Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add repo topics #197

Merged
merged 3 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions OctoKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@
721F73E929889A040064B11A /* latest_release.json in Resources */ = {isa = PBXBuildFile; fileRef = 721F73E829889A040064B11A /* latest_release.json */; };
721F73EA29889A040064B11A /* latest_release.json in Resources */ = {isa = PBXBuildFile; fileRef = 721F73E829889A040064B11A /* latest_release.json */; };
721F73EB29889A040064B11A /* latest_release.json in Resources */ = {isa = PBXBuildFile; fileRef = 721F73E829889A040064B11A /* latest_release.json */; };
849DF07A2D029AF400A202DF /* topics.json in Resources */ = {isa = PBXBuildFile; fileRef = 849DF0792D029AF400A202DF /* topics.json */; };
849DF07B2D029AF400A202DF /* topics.json in Resources */ = {isa = PBXBuildFile; fileRef = 849DF0792D029AF400A202DF /* topics.json */; };
849DF07C2D029AF400A202DF /* topics.json in Resources */ = {isa = PBXBuildFile; fileRef = 849DF0792D029AF400A202DF /* topics.json */; };
84B89D012C814DBC00273C68 /* Organization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B89D002C814DBC00273C68 /* Organization.swift */; };
84B89D032C814DE400273C68 /* forked_repo.json in Resources */ = {isa = PBXBuildFile; fileRef = 84B89D022C814DE400273C68 /* forked_repo.json */; };
84B89D042C814DED00273C68 /* forked_repo.json in Resources */ = {isa = PBXBuildFile; fileRef = 84B89D022C814DE400273C68 /* forked_repo.json */; };
Expand Down Expand Up @@ -340,6 +343,7 @@
665D5D5E24A639D70045E3B4 /* statuses.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = statuses.json; path = Fixtures/statuses.json; sourceTree = "<group>"; };
665D5D5F24A639D70045E3B4 /* status.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = status.json; path = Fixtures/status.json; sourceTree = "<group>"; };
721F73E829889A040064B11A /* latest_release.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = latest_release.json; path = Fixtures/latest_release.json; sourceTree = "<group>"; };
849DF0792D029AF400A202DF /* topics.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = topics.json; path = Fixtures/topics.json; sourceTree = "<group>"; };
84B89D002C814DBC00273C68 /* Organization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Organization.swift; sourceTree = "<group>"; };
84B89D022C814DE400273C68 /* forked_repo.json */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text.json; name = forked_repo.json; path = Fixtures/forked_repo.json; sourceTree = "<group>"; };
9D9ADDDE23EEFD4A000AC34D /* ReviewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -488,6 +492,7 @@
23EA619C25EAE31A001B0964 /* reactions.json */,
23EA619F25EAE31A001B0964 /* releases.json */,
23EA619E25EAE31A001B0964 /* reviews.json */,
849DF0792D029AF400A202DF /* topics.json */,
);
name = Fixtures;
sourceTree = "<group>";
Expand Down Expand Up @@ -831,6 +836,7 @@
234F4BDD1BDDE44600A58EF7 /* public_key.json in Resources */,
5090ED7223E483820062C763 /* issue_comment.json in Resources */,
DABBDE501C8C0C20008F57CD /* issue.json in Resources */,
849DF07B2D029AF400A202DF /* topics.json in Resources */,
234F4BDE1BDDE44600A58EF7 /* repo.json in Resources */,
23EA61B425EAE31A001B0964 /* pull_requests.json in Resources */,
234F4BE11BDDE44600A58EF7 /* user_repos.json in Resources */,
Expand Down Expand Up @@ -880,6 +886,7 @@
23F643461C7AEF63000427B3 /* public_key.json in Resources */,
502C70FC23E8535900384775 /* issue_comment.json in Resources */,
DABBDE511C8C0C20008F57CD /* issue.json in Resources */,
849DF07C2D029AF400A202DF /* topics.json in Resources */,
23F643481C7AEF66000427B3 /* repo.json in Resources */,
23EA61B525EAE31A001B0964 /* pull_requests.json in Resources */,
23F6434E1C7AEF6F000427B3 /* user_repos.json in Resources */,
Expand Down Expand Up @@ -921,6 +928,7 @@
23F643471C7AEF63000427B3 /* public_key.json in Resources */,
502C70FD23E8535A00384775 /* issue_comment.json in Resources */,
DABBDE521C8C0C20008F57CD /* issue.json in Resources */,
849DF07A2D029AF400A202DF /* topics.json in Resources */,
23F643491C7AEF67000427B3 /* repo.json in Resources */,
23EA61B625EAE31A001B0964 /* pull_requests.json in Resources */,
23F6434F1C7AEF70000427B3 /* user_repos.json in Resources */,
Expand Down
48 changes: 48 additions & 0 deletions OctoKit/Repositories.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@ public struct SymlinkContent: Codable {
}
}

public struct Topics: Codable {
public let names: [String]

private enum CodingKeys: String, CodingKey {
case names
}
}

public struct SubmoduleContent: Codable {
public let type: String
public let submoduleGitUrl: String
Expand Down Expand Up @@ -291,6 +299,40 @@ public extension Octokit {
}
#endif

/**
* Fetches the topics for the specified repository.
* - parameters:
* - owner: the user or org that owns the repository
* - name: the name of the repository
*/
@discardableResult
func repositoryTopics(owner: String, name: String, completion: @escaping (_ response: Result<Topics, Error>) -> Void) -> URLSessionDataTaskProtocol? {
let router = RepositoryRouter.getRepositoryTopics(configuration, owner: owner, name: name)
return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: Topics.self) { contentResponse, error in
if let error = error {
completion(.failure(error))
} else {
if let contentResponse = contentResponse {
completion(.success(contentResponse))
}
}
}
}

#if compiler(>=5.5.2) && canImport(_Concurrency)
/**
* Fetches the topics for the specified repository.
* - parameters:
* - owner: the user or org that owns the repository
* - name: the name of the repository
*/
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
func repositoryTopics(owner: String, name: String) async throws -> Topics {
let router = RepositoryRouter.getRepositoryTopics(configuration, owner: owner, name: name)
return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: Topics.self)
}
#endif

/**
Gets the contents of a file or directory in a repository.
[Github documentation](https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28)
Expand Down Expand Up @@ -342,13 +384,15 @@ enum RepositoryRouter: Router {
case readAuthenticatedRepositories(Configuration, String, String)
case readRepository(Configuration, String, String)
case getRepositoryContent(Configuration, String, String, String?, String?)
case getRepositoryTopics(Configuration, owner: String, name: String)

var configuration: Configuration {
switch self {
case let .readRepositories(config, _, _, _): return config
case let .readAuthenticatedRepositories(config, _, _): return config
case let .readRepository(config, _, _): return config
case let .getRepositoryContent(config, _, _, _, _): return config
case let .getRepositoryTopics(config, _, _): return config
}
}

Expand All @@ -373,6 +417,8 @@ enum RepositoryRouter: Router {
return ["ref": ref]
}
return [:]
case .getRepositoryTopics:
return [:]
}
}

Expand All @@ -388,6 +434,8 @@ enum RepositoryRouter: Router {
var path = "repos/\(owner)/\(repo)/contents"
if let searchPath = searchPath { path.append("/\(searchPath)") }
return path
case let .getRepositoryTopics(_, owner, name):
return "repos/\(owner)/\(name)/topics"
}
}
}
6 changes: 6 additions & 0 deletions Tests/OctoKitTests/Fixtures/topics.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"names": [
"swift",
"library"
]
}
26 changes: 26 additions & 0 deletions Tests/OctoKitTests/RepositoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,32 @@ class RepositoryTests: XCTestCase {
}
#endif

func testGetRepositoryTopics() {
let (owner, name) = ("mietzmithut", "Test")
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/mietzmithut/Test/topics", expectedHTTPMethod: "GET", jsonFile: "topics", statusCode: 200)
let task = Octokit(session: session).repositoryTopics(owner: owner, name: name) { response in
switch response {
case let .success(topics):
XCTAssertEqual(topics.names, ["swift", "library"])
case .failure:
XCTAssert(false, "should not get an error")
}
}
XCTAssertNotNil(task)
XCTAssertTrue(session.wasCalled)
}

#if compiler(>=5.5.2) && canImport(_Concurrency)
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
func testGetRepositoryTopicsAsync() async throws {
let (owner, name) = ("mietzmithut", "Test")
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/mietzmithut/Test/topics", expectedHTTPMethod: "GET", jsonFile: "topics", statusCode: 200)
let topics = try await Octokit(session: session).repositoryTopics(owner: owner, name: name)
XCTAssertEqual(topics.names, ["swift", "library"])
XCTAssertTrue(session.wasCalled)
}
#endif

func testfailureRepositoryContent() {
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/nerdishbynature/octokit.swift/contents/Package.swift",
expectedHTTPMethod: "GET",
Expand Down
Loading