Skip to content

Commit

Permalink
Add gist fork_of decoding and requests to fetch user's starred gists (
Browse files Browse the repository at this point in the history
#201)

* add title,forkOf fields to gist, and starred gists request

* actually, dont need the title, using filenames

* fix tests

* fix lint errors

---------

Co-authored-by: Andrew McKnight <[email protected]>
  • Loading branch information
armcknight and Andrew McKnight authored Feb 11, 2025
1 parent 7b15f74 commit c477602
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 8 deletions.
59 changes: 52 additions & 7 deletions OctoKit/Gist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ open class Gist: Codable {
open var comments: Int?
open var user: User?
open var owner: User?
open var forkOf: Gist?

public init(id: String? = nil,
url: URL? = nil,
Expand All @@ -39,7 +40,8 @@ open class Gist: Codable {
description: String? = nil,
comments: Int? = nil,
user: User? = nil,
owner: User? = nil) {
owner: User? = nil,
forkOf: Gist? = nil) {
self.id = id
self.url = url
self.forksURL = forksURL
Expand All @@ -56,6 +58,7 @@ open class Gist: Codable {
self.comments = comments
self.user = user
self.owner = owner
self.forkOf = forkOf
}

enum CodingKeys: String, CodingKey {
Expand All @@ -75,6 +78,7 @@ open class Gist: Codable {
case comments
case user
case owner
case forkOf = "fork_of"
}
}

Expand Down Expand Up @@ -116,6 +120,41 @@ public extension Octokit {
}
#endif

/**
Fetches the starred gists of the authenticated user
- parameter page: Current page for gist pagination. `1` by default.
- parameter perPage: Number of gists per page. `100` by default.
- parameter completion: Callback for the outcome of the fetch.
*/
@discardableResult
func myStarredGists(page: String = "1",
perPage: String = "100",
completion: @escaping (_ response: Result<[Gist], Error>) -> Void) -> URLSessionDataTaskProtocol? {
let router = GistRouter.readAuthenticatedStarredGists(configuration, page, perPage)
return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [Gist].self) { gists, error in
if let error = error {
completion(.failure(error))
} else {
if let gists = gists {
completion(.success(gists))
}
}
}
}

#if compiler(>=5.5.2) && canImport(_Concurrency)
/**
Fetches the starred gists of the authenticated user
- parameter page: Current page for gist pagination. `1` by default.
- parameter perPage: Number of gists per page. `100` by default.
*/
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
func myStarredGists(page: String = "1", perPage: String = "100") async throws -> [Gist] {
let router = GistRouter.readAuthenticatedStarredGists(configuration, page, perPage)
return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [Gist].self)
}
#endif

/**
Fetches the gists of the specified user
- parameter owner: The username who owns the gists.
Expand Down Expand Up @@ -155,7 +194,7 @@ public extension Octokit {
#endif

/**
Fetches an gist
Fetches a gist
- parameter id: The id of the gist.
- parameter completion: Callback for the outcome of the fetch.
*/
Expand All @@ -175,7 +214,7 @@ public extension Octokit {

#if compiler(>=5.5.2) && canImport(_Concurrency)
/**
Fetches an gist
Fetches a gist
- parameter id: The id of the gist.
*/
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
Expand All @@ -186,7 +225,7 @@ public extension Octokit {
#endif

/**
Creates an gist with a single file.
Creates a gist with a single file.
- parameter description: The description of the gist.
- parameter filename: The name of the file in the gist.
- parameter fileContent: The content of the file in the gist.
Expand Down Expand Up @@ -215,7 +254,7 @@ public extension Octokit {

#if compiler(>=5.5.2) && canImport(_Concurrency)
/**
Creates an gist with a single file.
Creates a gist with a single file.
- parameter description: The description of the gist.
- parameter filename: The name of the file in the gist.
- parameter fileContent: The content of the file in the gist.
Expand All @@ -231,7 +270,7 @@ public extension Octokit {
#endif

/**
Edits an gist with a single file.
Edits a gist with a single file.
- parameter id: The of the gist to update.
- parameter description: The description of the gist.
- parameter filename: The name of the file in the gist.
Expand Down Expand Up @@ -260,7 +299,7 @@ public extension Octokit {

#if compiler(>=5.5.2) && canImport(_Concurrency)
/**
Edits an gist with a single file.
Edits a gist with a single file.
- parameter id: The of the gist to update.
- parameter description: The description of the gist.
- parameter filename: The name of the file in the gist.
Expand All @@ -280,6 +319,7 @@ public extension Octokit {

enum GistRouter: JSONPostRouter {
case readAuthenticatedGists(Configuration, String, String)
case readAuthenticatedStarredGists(Configuration, String, String)
case readGists(Configuration, String, String, String)
case readGist(Configuration, String)
case postGistFile(Configuration, String, String, String, Bool)
Expand All @@ -306,6 +346,7 @@ enum GistRouter: JSONPostRouter {
var configuration: Configuration {
switch self {
case let .readAuthenticatedGists(config, _, _): return config
case let .readAuthenticatedStarredGists(config, _, _): return config
case let .readGists(config, _, _, _): return config
case let .readGist(config, _): return config
case let .postGistFile(config, _, _, _, _): return config
Expand All @@ -317,6 +358,8 @@ enum GistRouter: JSONPostRouter {
switch self {
case let .readAuthenticatedGists(_, page, perPage):
return ["per_page": perPage, "page": page]
case let .readAuthenticatedStarredGists(_, page, perPage):
return ["per_page": perPage, "page": page]
case let .readGists(_, _, page, perPage):
return ["per_page": perPage, "page": page]
case .readGist:
Expand Down Expand Up @@ -347,6 +390,8 @@ enum GistRouter: JSONPostRouter {
switch self {
case .readAuthenticatedGists:
return "gists"
case .readAuthenticatedStarredGists:
return "gists/starred"
case let .readGists(_, owner, _, _):
return "users/\(owner)/gists"
case let .readGist(_, id):
Expand Down
43 changes: 42 additions & 1 deletion Tests/OctoKitTests/Fixtures/gist.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,47 @@
"type" : "application\/x-ruby"
}
},
"fork_of": {
"url": "https://api.github.com/gists/f87cbd23c4bc9ad7b04a9f80cf532fc3",
"forks_url": "https://api.github.com/gists/f87cbd23c4bc9ad7b04a9f80cf532fc3/forks",
"commits_url": "https://api.github.com/gists/f87cbd23c4bc9ad7b04a9f80cf532fc3/commits",
"id": "f87cbd23c4bc9ad7b04a9f80cf532fc3",
"node_id": "G_kwDOADF1_doAIGY4N2NiZDIzYzRiYzlhZDdiMDRhOWY4MGNmNTMyZmMz",
"git_pull_url": "https://gist.github.com/f87cbd23c4bc9ad7b04a9f80cf532fc3.git",
"git_push_url": "https://gist.github.com/f87cbd23c4bc9ad7b04a9f80cf532fc3.git",
"html_url": "https://gist.github.com/armcknight/f87cbd23c4bc9ad7b04a9f80cf532fc3",
"files": {

},
"public": true,
"created_at": "2023-07-24T19:09:01Z",
"updated_at": "2023-07-24T19:09:02Z",
"description": "Hello World Examples",
"comments": 0,
"user": null,
"comments_url": "https://api.github.com/gists/f87cbd23c4bc9ad7b04a9f80cf532fc3/comments",
"owner": {
"login": "armcknight",
"id": 3241469,
"node_id": "MDQ6VXNlcjMyNDE0Njk=",
"avatar_url": "https://avatars.githubusercontent.com/u/3241469?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/armcknight",
"html_url": "https://github.com/armcknight",
"followers_url": "https://api.github.com/users/armcknight/followers",
"following_url": "https://api.github.com/users/armcknight/following{/other_user}",
"gists_url": "https://api.github.com/users/armcknight/gists{/gist_id}",
"starred_url": "https://api.github.com/users/armcknight/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/armcknight/subscriptions",
"organizations_url": "https://api.github.com/users/armcknight/orgs",
"repos_url": "https://api.github.com/users/armcknight/repos",
"events_url": "https://api.github.com/users/armcknight/events{/privacy}",
"received_events_url": "https://api.github.com/users/armcknight/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
}
},
"forks" : [
{
"created_at" : "2011-04-14T16:00:49Z",
Expand Down Expand Up @@ -133,4 +174,4 @@
"updated_at" : "2011-06-20T11:34:15Z",
"url" : "https:\/\/api.github.com\/gists\/aa5a315d61ae9438b18d",
"user" : null
}
}
49 changes: 49 additions & 0 deletions Tests/OctoKitTests/Fixtures/starred_gists.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[
{
"comments" : 0,
"comments_url" : "https:\/\/api.github.com\/gists\/aa5a315d61ae9438b18d\/comments\/",
"commits_url" : "https:\/\/api.github.com\/gists\/aa5a315d61ae9438b18d\/commits",
"created_at" : "2010-04-14T02:15:15Z",
"description" : "Hello World Starred Examples",
"files" : {
"hello_world.rb" : {
"filename" : "hello_world.rb",
"language" : "Ruby",
"raw_url" : "https:\/\/gist.githubusercontent.com\/octocat\/6cad326836d38bd3a7ae\/raw\/db9c55113504e46fa076e7df3a04ce592e2e86d8\/hello_world.rb",
"size" : 167,
"type" : "application\/x-ruby"
}
},
"forks_url" : "https:\/\/api.github.com\/gists\/aa5a315d61ae9438b18d\/forks",
"git_pull_url" : "https:\/\/gist.github.com\/aa5a315d61ae9438b18d.git",
"git_push_url" : "https:\/\/gist.github.com\/aa5a315d61ae9438b18d.git",
"html_url" : "https:\/\/gist.github.com\/aa5a315d61ae9438b18d",
"id" : "aa5a315d61ae9438b18d",
"node_id" : "MDQ6R2lzdGFhNWEzMTVkNjFhZTk0MzhiMThk",
"owner" : {
"avatar_url" : "https:\/\/github.com\/images\/error\/octocat_happy.gif",
"events_url" : "https:\/\/api.github.com\/users\/octocat\/events{\/privacy}",
"followers_url" : "https:\/\/api.github.com\/users\/octocat\/followers",
"following_url" : "https:\/\/api.github.com\/users\/octocat\/following{\/other_user}",
"gists_url" : "https:\/\/api.github.com\/users\/octocat\/gists{\/gist_id}",
"gravatar_id" : "",
"html_url" : "https:\/\/github.com\/octocat",
"id" : 1,
"login" : "octocat",
"node_id" : "MDQ6VXNlcjE=",
"organizations_url" : "https:\/\/api.github.com\/users\/octocat\/orgs",
"received_events_url" : "https:\/\/api.github.com\/users\/octocat\/received_events",
"repos_url" : "https:\/\/api.github.com\/users\/octocat\/repos",
"site_admin" : false,
"starred_url" : "https:\/\/api.github.com\/users\/octocat\/starred{\/owner}{\/repo}",
"subscriptions_url" : "https:\/\/api.github.com\/users\/octocat\/subscriptions",
"type" : "User",
"url" : "https:\/\/api.github.com\/users\/octocat"
},
"public" : true,
"truncated" : false,
"updated_at" : "2011-06-20T11:34:15Z",
"url" : "https:\/\/api.github.com\/gists\/aa5a315d61ae9438b18d",
"user" : null
}
]
45 changes: 45 additions & 0 deletions Tests/OctoKitTests/GistTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,46 @@ class GistTests: XCTestCase {
}
#endif

func testGetMyStarredGists() {
let config = TokenConfiguration("user:12345")
let headers = Helper.makeAuthHeader(username: "user", password: "12345")

let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/gists/starred?page=1&per_page=100",
expectedHTTPMethod: "GET",
expectedHTTPHeaders: headers,
jsonFile: "starred_gists",
statusCode: 200)
let task = Octokit(config, session: session).myStarredGists { response in
switch response {
case let .success(gists):
XCTAssertEqual(gists.count, 1)
XCTAssertEqual(gists[0].description, "Hello World Starred Examples")
case let .failure(error):
XCTAssertNil(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 testGetMyStarredGistsAsync() async throws {
let config = TokenConfiguration("user:12345")
let headers = Helper.makeAuthHeader(username: "user", password: "12345")

let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/gists/starred?page=1&per_page=100",
expectedHTTPMethod: "GET",
expectedHTTPHeaders: headers,
jsonFile: "starred_gists",
statusCode: 200)
let gists = try await Octokit(config, session: session).myStarredGists()
XCTAssertEqual(gists.count, 1)
XCTAssertEqual(gists[0].description, "Hello World Starred Examples")
XCTAssertTrue(session.wasCalled)
}
#endif

func testGetGists() {
let config = TokenConfiguration("user:12345")
let headers = Helper.makeAuthHeader(username: "user", password: "12345")
Expand Down Expand Up @@ -88,6 +128,11 @@ class GistTests: XCTestCase {
switch response {
case let .success(gist):
XCTAssertEqual(gist.id, "aa5a315d61ae9438b18d")
guard let forkID = gist.forkOf?.id else {
XCTFail("Didn't properly decode fork parent gist")
return
}
XCTAssertEqual(forkID, "f87cbd23c4bc9ad7b04a9f80cf532fc3")
case .failure:
XCTFail("should not get an error")
}
Expand Down

0 comments on commit c477602

Please sign in to comment.