From 491651e13bfcfd0a9228cdd364f866c4bf678ba7 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sun, 31 Mar 2019 18:19:50 -0500 Subject: [PATCH 1/6] Added initial support for Github Gists. --- OctoKit.xcodeproj/project.pbxproj | 22 +++ OctoKit/File.swift | 23 ++++ OctoKit/Gist.swift | 214 ++++++++++++++++++++++++++++++ 3 files changed, 259 insertions(+) create mode 100644 OctoKit/File.swift create mode 100644 OctoKit/Gist.swift diff --git a/OctoKit.xcodeproj/project.pbxproj b/OctoKit.xcodeproj/project.pbxproj index 9b53ebe0..f4ca72c1 100644 --- a/OctoKit.xcodeproj/project.pbxproj +++ b/OctoKit.xcodeproj/project.pbxproj @@ -96,6 +96,14 @@ 23F6434F1C7AEF70000427B3 /* user_repos.json in Resources */ = {isa = PBXBuildFile; fileRef = 234F4BDC1BDDE44600A58EF7 /* user_repos.json */; }; 23F643501C7AEF72000427B3 /* users.json in Resources */ = {isa = PBXBuildFile; fileRef = E7EE59DF1BE139FD0012E3D2 /* users.json */; }; 23F643511C7AEF73000427B3 /* users.json in Resources */ = {isa = PBXBuildFile; fileRef = E7EE59DF1BE139FD0012E3D2 /* users.json */; }; + 515337C2225166600024544D /* Gist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C1225166600024544D /* Gist.swift */; }; + 515337C4225179FB0024544D /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C3225179FB0024544D /* File.swift */; }; + 515337C5225179FB0024544D /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C3225179FB0024544D /* File.swift */; }; + 515337C6225179FB0024544D /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C3225179FB0024544D /* File.swift */; }; + 515337C7225179FB0024544D /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C3225179FB0024544D /* File.swift */; }; + 515337C822517A060024544D /* Gist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C1225166600024544D /* Gist.swift */; }; + 515337C922517A070024544D /* Gist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C1225166600024544D /* Gist.swift */; }; + 515337CA22517A0B0024544D /* Gist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C1225166600024544D /* Gist.swift */; }; BF8C711C2C6B42F9F323FCFE /* pull_requests.json in Resources */ = {isa = PBXBuildFile; fileRef = BF8C79B71035B425F7748392 /* pull_requests.json */; }; BF8C716EB8D5CA2CBBA745CB /* pull_request.json in Resources */ = {isa = PBXBuildFile; fileRef = BF8C77314F563A710F11E2F6 /* pull_request.json */; }; BF8C719220F02AC04EF3D137 /* PullRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8C76EB002802C14A08F63E /* PullRequestTests.swift */; }; @@ -238,6 +246,8 @@ 23CAF29A1C7AB619005011C4 /* OctoKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OctoKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 23F6433C1C7AEEB6000427B3 /* Nocilla.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nocilla.framework; path = Carthage/Build/tvOS/Nocilla.framework; sourceTree = ""; }; 23F643421C7AEF2F000427B3 /* Nocilla.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nocilla.framework; path = Carthage/Build/Mac/Nocilla.framework; sourceTree = ""; }; + 515337C1225166600024544D /* Gist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gist.swift; sourceTree = ""; }; + 515337C3225179FB0024544D /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; }; BF8C72B985869B84F46B4E9D /* Parameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parameters.swift; sourceTree = ""; }; BF8C73E0EF3CEEBDEA68DD5E /* PullRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PullRequest.swift; sourceTree = ""; }; BF8C76EB002802C14A08F63E /* PullRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PullRequestTests.swift; sourceTree = ""; }; @@ -360,7 +370,9 @@ children = ( 239BE7CD1B8C47A100D2CE22 /* OctoKit.h */, 23B267851BDDD756003887E3 /* Configuration.swift */, + 515337C3225179FB0024544D /* File.swift */, E7EE59DB1BE119110012E3D2 /* Follow.swift */, + 515337C1225166600024544D /* Gist.swift */, E7EDEA691C871CEB006BAAF2 /* Issue.swift */, DAEFC58F1C83D85100CF3785 /* Label.swift */, DAEFC5941C83EF0D00CF3785 /* Milestone.swift */, @@ -409,6 +421,7 @@ B975D5A3F8B0384EFB0C5863 /* Frameworks */, ); sourceTree = ""; + usesTabs = 0; }; F01C6F351A6429CC0072FA44 /* Products */ = { isa = PBXGroup; @@ -638,6 +651,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -767,6 +781,8 @@ E7EE59D81BDFEFB30012E3D2 /* Stars.swift in Sources */, 23B2678D1BDDD756003887E3 /* Repositories.swift in Sources */, F8711EA21BFCAE9F005DDACA /* Time.swift in Sources */, + 515337C4225179FB0024544D /* File.swift in Sources */, + 515337C2225166600024544D /* Gist.swift in Sources */, 23B2678C1BDDD756003887E3 /* PublicKey.swift in Sources */, 23B2678E1BDDD756003887E3 /* User.swift in Sources */, 237F91E41E5AEC82005FAA6B /* URL+URLParameters.swift in Sources */, @@ -793,7 +809,9 @@ 237F91E51E5AEC87005FAA6B /* URL+URLParameters.swift in Sources */, DAEFC5961C83EF0D00CF3785 /* Milestone.swift in Sources */, 23CAF2A81C7AB6C6005011C4 /* Octokit.swift in Sources */, + 515337C5225179FB0024544D /* File.swift in Sources */, E7EDEA6F1C871F81006BAAF2 /* Issue.swift in Sources */, + 515337C822517A060024544D /* Gist.swift in Sources */, DAEFC5911C83D85100CF3785 /* Label.swift in Sources */, BF8C797115D9BB2DE41E59E6 /* PullRequest.swift in Sources */, BF8C7DEE90DD25CBCA4AEE71 /* Parameters.swift in Sources */, @@ -832,7 +850,9 @@ 237F91E61E5AEC88005FAA6B /* URL+URLParameters.swift in Sources */, DAEFC5971C83EF0D00CF3785 /* Milestone.swift in Sources */, 23CAF2A91C7AB6C6005011C4 /* Octokit.swift in Sources */, + 515337C6225179FB0024544D /* File.swift in Sources */, E7EDEA701C871F81006BAAF2 /* Issue.swift in Sources */, + 515337C922517A070024544D /* Gist.swift in Sources */, DAEFC5921C83D85100CF3785 /* Label.swift in Sources */, BF8C7FFFDDAFA560EBEC35EE /* PullRequest.swift in Sources */, BF8C7A3F2B4817EF3AD1B315 /* Parameters.swift in Sources */, @@ -871,7 +891,9 @@ 237F91E71E5AEC89005FAA6B /* URL+URLParameters.swift in Sources */, DAEFC5981C83EF0D00CF3785 /* Milestone.swift in Sources */, 23CAF2AA1C7AB6C7005011C4 /* Octokit.swift in Sources */, + 515337C7225179FB0024544D /* File.swift in Sources */, E7EDEA711C871F82006BAAF2 /* Issue.swift in Sources */, + 515337CA22517A0B0024544D /* Gist.swift in Sources */, DAEFC5931C83D85100CF3785 /* Label.swift in Sources */, BF8C7808F0A0A71D0110AD43 /* PullRequest.swift in Sources */, BF8C7AB9EBD2E18007A8B77D /* Parameters.swift in Sources */, diff --git a/OctoKit/File.swift b/OctoKit/File.swift new file mode 100644 index 00000000..280b451c --- /dev/null +++ b/OctoKit/File.swift @@ -0,0 +1,23 @@ + +import Foundation + +public typealias FileDict = [String: File] +public typealias Files = [FileDict] + +open class File: Codable { + open private(set) var id: Int = -1 + open var rawURL: URL? + open var filename: String? + open var type: String? + open var language: String? + open var size: Int? + + enum CodingKeys: String, CodingKey { + case rawURL = "raw_url" + case filename + case type + case language + case size + } + +} diff --git a/OctoKit/Gist.swift b/OctoKit/Gist.swift new file mode 100644 index 00000000..dacac9ab --- /dev/null +++ b/OctoKit/Gist.swift @@ -0,0 +1,214 @@ +import Foundation +import RequestKit + +// MARK: model + +open class Gist: Codable { + open private(set) var id: Int = -1 + open var url: URL? + open var forksURL: URL? + open var commitsURL: URL? + open var gitPushURL: URL? + open var gitPullURL: URL? + open var commentsURL: URL? + open var htmlURL: URL? + open var files: Files + open var publicGist: Bool? + open var createdAt: Date? + open var updatedAt: Date? + open var description: String? + open var comments: Int? + open var user: User? + open var owner: User? + + enum CodingKeys: String, CodingKey { + case id + case url + case forksURL = "forks_url" + case commitsURL = "commits_url" + case gitPushURL = "git_pull_url" + case gitPullURL = "git_push_url" + case commentsURL = "comments_url" + case htmlURL = "html_url" + case files + case publicGist = "public" + case createdAt = "created_at" + case updatedAt = "updated_at" + case description + case comments + case user + case owner + } +} + +// MARK: request + +public extension Octokit { + + /** + Fetches the gists of the specified user + - parameter session: RequestKitURLSession, defaults to URLSession.sharedSession() + - parameter owner: The username who owns the gists. + - 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 gists(_ session: RequestKitURLSession = URLSession.shared, owner: String, page: String = "1", perPage: String = "100", completion: @escaping (_ response: Response<[Gist]>) -> Void) -> URLSessionDataTaskProtocol? { + let router = GistRouter.readGists(configuration, owner, page, perPage) + return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [Gist].self) { gists, error in + if let error = error { + completion(Response.failure(error)) + } else { + if let gists = gists { + completion(Response.success(gists)) + } + } + } + } + + /** + Fetches an gist in a repository + - parameter session: RequestKitURLSession, defaults to URLSession.sharedSession() + - parameter id: The id of the gist. + - parameter completion: Callback for the outcome of the fetch. + */ + @discardableResult + func gist(_ session: RequestKitURLSession = URLSession.shared, id: Int, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { + let router = GistRouter.readGist(configuration, id) + return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: Gist.self) { gist, error in + if let error = error { + completion(Response.failure(error)) + } else { + if let gist = gist { + completion(Response.success(gist)) + } + } + } + } + + /** + Creates an gist with a single file. + - parameter session: RequestKitURLSession, defaults to URLSession.sharedSession() + - 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. + - parameter completion: Callback for the issue that is created. + */ + @discardableResult + func postGistFile(_ session: RequestKitURLSession = URLSession.shared, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { + let router = GistRouter.postGistFile(configuration, description, filename, fileContent) + return router.post(session, expectedResultType: Issue.self) { issue, error in + if let error = error { + completion(Response.failure(error)) + } else { + if let issue = issue { + completion(Response.success(issue)) + } + } + } + } + + /** + Edits an issue in a repository. + - parameter session: RequestKitURLSession, defaults to URLSession.sharedSession() + - parameter owner: The user or organization that owns the repository. + - parameter repository: The name of the repository. + - parameter number: The number of the issue. + - parameter title: The title of the issue. + - parameter body: The body text of the issue in GitHub-flavored Markdown format. + - parameter assignee: The name of the user to assign the issue to. This parameter is ignored if the user lacks push access to the repository. + - parameter state: Whether the issue is open or closed. + - parameter completion: Callback for the issue that is created. + */ + @discardableResult + func patchIssue(_ session: RequestKitURLSession = URLSession.shared, id: String, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { + let router = GistRouter.patchGistFile(configuration, id, description, filename, fileContent) + return router.post(session, expectedResultType: Gist.self) { gist, error in + if let error = error { + completion(Response.failure(error)) + } else { + if let gist = gist { + completion(Response.success(gist)) + } + } + } + } +} + +// MARK: Router + +enum GistRouter: JSONPostRouter { + case readGists(Configuration, String, String, String) + case readGist(Configuration, Int) + case postGistFile(Configuration, String, String, String) + case patchGistFile(Configuration, String, String, String, String) + + var method: HTTPMethod { + switch self { + case .postGistFile, .patchGistFile: + return .POST + default: + return .GET + } + } + + var encoding: HTTPEncoding { + switch self { + case .postGistFile, .patchGistFile: + return .json + default: + return .url + } + } + + var configuration: Configuration { + switch self { + case .readGists(let config, _, _, _): return config + case .readGist(let config, _): return config + case .postGistFile(let config, _, _, _): return config + case .patchGistFile(let config, _, _, _, _): return config + } + } + + var params: [String: Any] { + switch self { + case .readGists(_, _, let page, let perPage): + return ["per_page": perPage, "page": page] + case .readGist: + return [:] + case .postGistFile(_, let description, let filename, let fileContent): + var params = [String: Any]() + params["description"] = description + var file = [String: Any]() + file["content"] = fileContent + var files = [String: Any]() + files[filename] = file + params["files"] = files + return params + case .patchGistFile(_, _, let description, let filename, let fileContent): + var params = [String: Any]() + params["description"] = description + var file = [String: Any]() + file["content"] = fileContent + var files = [String: Any]() + files[filename] = file + params["files"] = files + return params + } + } + + var path: String { + switch self { + case .readGists(_, let owner, _, _): + return "users/\(owner)/gists" + case .readGist(_, let id): + return "gists/\(id)" + case .postGistFile(_, _, _, _): + return "gists" + case .patchGistFile(_, let id, _, _, _): + return "gists/\(id)" + } + } + +} From 0aa2df4f82b4bd1895e9dbb6588ea800338a76f3 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Mon, 1 Apr 2019 14:25:42 -0500 Subject: [PATCH 2/6] Added decoder for posts. --- OctoKit/Gist.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OctoKit/Gist.swift b/OctoKit/Gist.swift index dacac9ab..abc07f1b 100644 --- a/OctoKit/Gist.swift +++ b/OctoKit/Gist.swift @@ -98,7 +98,9 @@ public extension Octokit { @discardableResult func postGistFile(_ session: RequestKitURLSession = URLSession.shared, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { let router = GistRouter.postGistFile(configuration, description, filename, fileContent) - return router.post(session, expectedResultType: Issue.self) { issue, error in + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) + return router.post(session, decoder: decoder, expectedResultType: Issue.self) { issue, error in if let error = error { completion(Response.failure(error)) } else { @@ -124,7 +126,9 @@ public extension Octokit { @discardableResult func patchIssue(_ session: RequestKitURLSession = URLSession.shared, id: String, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { let router = GistRouter.patchGistFile(configuration, id, description, filename, fileContent) - return router.post(session, expectedResultType: Gist.self) { gist, error in + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) + return router.post(session, decoder: decoder, expectedResultType: Gist.self) { gist, error in if let error = error { completion(Response.failure(error)) } else { From 44d99d498cf43007e40f89f73b32f59f5ffb3b13 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Mon, 1 Apr 2019 15:07:50 -0500 Subject: [PATCH 3/6] Added Gist tests and fixed some bugs they found. --- OctoKit.xcodeproj/project.pbxproj | 32 +++++- OctoKit/File.swift | 3 +- OctoKit/Gist.swift | 43 ++++++-- Tests/OctoKitTests/Fixtures/gist.json | 136 +++++++++++++++++++++++++ Tests/OctoKitTests/Fixtures/gists.json | 49 +++++++++ Tests/OctoKitTests/GistTests.swift | 103 +++++++++++++++++++ 6 files changed, 352 insertions(+), 14 deletions(-) create mode 100644 Tests/OctoKitTests/Fixtures/gist.json create mode 100644 Tests/OctoKitTests/Fixtures/gists.json create mode 100644 Tests/OctoKitTests/GistTests.swift diff --git a/OctoKit.xcodeproj/project.pbxproj b/OctoKit.xcodeproj/project.pbxproj index bb3f9b51..dfe70b47 100644 --- a/OctoKit.xcodeproj/project.pbxproj +++ b/OctoKit.xcodeproj/project.pbxproj @@ -96,6 +96,9 @@ 23F6434F1C7AEF70000427B3 /* user_repos.json in Resources */ = {isa = PBXBuildFile; fileRef = 234F4BDC1BDDE44600A58EF7 /* user_repos.json */; }; 23F643501C7AEF72000427B3 /* users.json in Resources */ = {isa = PBXBuildFile; fileRef = E7EE59DF1BE139FD0012E3D2 /* users.json */; }; 23F643511C7AEF73000427B3 /* users.json in Resources */ = {isa = PBXBuildFile; fileRef = E7EE59DF1BE139FD0012E3D2 /* users.json */; }; + 515337A9224FC3760024544D /* issue2.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337A8224FC3760024544D /* issue2.json */; }; + 515337AA224FC3760024544D /* issue2.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337A8224FC3760024544D /* issue2.json */; }; + 515337AB224FC3760024544D /* issue2.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337A8224FC3760024544D /* issue2.json */; }; 515337C2225166600024544D /* Gist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C1225166600024544D /* Gist.swift */; }; 515337C4225179FB0024544D /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C3225179FB0024544D /* File.swift */; }; 515337C5225179FB0024544D /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C3225179FB0024544D /* File.swift */; }; @@ -104,9 +107,15 @@ 515337C822517A060024544D /* Gist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C1225166600024544D /* Gist.swift */; }; 515337C922517A070024544D /* Gist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C1225166600024544D /* Gist.swift */; }; 515337CA22517A0B0024544D /* Gist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337C1225166600024544D /* Gist.swift */; }; - 515337A9224FC3760024544D /* issue2.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337A8224FC3760024544D /* issue2.json */; }; - 515337AA224FC3760024544D /* issue2.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337A8224FC3760024544D /* issue2.json */; }; - 515337AB224FC3760024544D /* issue2.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337A8224FC3760024544D /* issue2.json */; }; + 515337F222529D590024544D /* GistTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337F022529C380024544D /* GistTests.swift */; }; + 515337F322529D5A0024544D /* GistTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337F022529C380024544D /* GistTests.swift */; }; + 515337F422529D5C0024544D /* GistTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515337F022529C380024544D /* GistTests.swift */; }; + 515337F622529E7B0024544D /* gists.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337F522529E7B0024544D /* gists.json */; }; + 515337F722529E7B0024544D /* gists.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337F522529E7B0024544D /* gists.json */; }; + 515337F822529E7B0024544D /* gists.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337F522529E7B0024544D /* gists.json */; }; + 515337FA2252A0410024544D /* gist.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337F92252A0410024544D /* gist.json */; }; + 515337FB2252A0410024544D /* gist.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337F92252A0410024544D /* gist.json */; }; + 515337FC2252A0410024544D /* gist.json in Resources */ = {isa = PBXBuildFile; fileRef = 515337F92252A0410024544D /* gist.json */; }; BF8C711C2C6B42F9F323FCFE /* pull_requests.json in Resources */ = {isa = PBXBuildFile; fileRef = BF8C79B71035B425F7748392 /* pull_requests.json */; }; BF8C716EB8D5CA2CBBA745CB /* pull_request.json in Resources */ = {isa = PBXBuildFile; fileRef = BF8C77314F563A710F11E2F6 /* pull_request.json */; }; BF8C719220F02AC04EF3D137 /* PullRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8C76EB002802C14A08F63E /* PullRequestTests.swift */; }; @@ -249,9 +258,12 @@ 23CAF29A1C7AB619005011C4 /* OctoKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OctoKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 23F6433C1C7AEEB6000427B3 /* Nocilla.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nocilla.framework; path = Carthage/Build/tvOS/Nocilla.framework; sourceTree = ""; }; 23F643421C7AEF2F000427B3 /* Nocilla.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nocilla.framework; path = Carthage/Build/Mac/Nocilla.framework; sourceTree = ""; }; + 515337A8224FC3760024544D /* issue2.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = issue2.json; path = Fixtures/issue2.json; sourceTree = ""; }; 515337C1225166600024544D /* Gist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gist.swift; sourceTree = ""; }; 515337C3225179FB0024544D /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; }; - 515337A8224FC3760024544D /* issue2.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = issue2.json; path = Fixtures/issue2.json; sourceTree = ""; }; + 515337F022529C380024544D /* GistTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GistTests.swift; sourceTree = ""; }; + 515337F522529E7B0024544D /* gists.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = gists.json; path = Fixtures/gists.json; sourceTree = ""; }; + 515337F92252A0410024544D /* gist.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = gist.json; path = Fixtures/gist.json; sourceTree = ""; }; BF8C72B985869B84F46B4E9D /* Parameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parameters.swift; sourceTree = ""; }; BF8C73E0EF3CEEBDEA68DD5E /* PullRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PullRequest.swift; sourceTree = ""; }; BF8C76EB002802C14A08F63E /* PullRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PullRequestTests.swift; sourceTree = ""; }; @@ -337,6 +349,7 @@ 234F4BD71BDDE40400A58EF7 /* Fixtures */, 234F4BC91BDDE3F900A58EF7 /* ConfigurationTests.swift */, E7EE59DD1BE11C2A0012E3D2 /* FollowTests.swift */, + 515337F022529C380024544D /* GistTests.swift */, E7EDEA6B1C871D01006BAAF2 /* IssueTests.swift */, 234F4BCB1BDDE3F900A58EF7 /* OctokitSwiftTests.swift */, 234F4BCC1BDDE3F900A58EF7 /* PublicKeyTests.swift */, @@ -355,6 +368,8 @@ 234F4BD71BDDE40400A58EF7 /* Fixtures */ = { isa = PBXGroup; children = ( + 515337F92252A0410024544D /* gist.json */, + 515337F522529E7B0024544D /* gists.json */, DABBDE4F1C8C0C20008F57CD /* issue.json */, 515337A8224FC3760024544D /* issue2.json */, E7EDEA6D1C871D0E006BAAF2 /* issues.json */, @@ -689,6 +704,8 @@ 234F4BDE1BDDE44600A58EF7 /* repo.json in Resources */, 234F4BE11BDDE44600A58EF7 /* user_repos.json in Resources */, 234F4BE01BDDE44600A58EF7 /* user_mietzmithut.json in Resources */, + 515337F622529E7B0024544D /* gists.json in Resources */, + 515337FA2252A0410024544D /* gist.json in Resources */, E7EDEA6E1C871D0E006BAAF2 /* issues.json in Resources */, BF8C78845606511558E7B929 /* pull_requests.json in Resources */, BF8C7B976A0652C486FAF736 /* pull_request.json in Resources */, @@ -721,6 +738,8 @@ 23F643481C7AEF66000427B3 /* repo.json in Resources */, 23F6434E1C7AEF6F000427B3 /* user_repos.json in Resources */, 23F6434C1C7AEF6C000427B3 /* user_mietzmithut.json in Resources */, + 515337F722529E7B0024544D /* gists.json in Resources */, + 515337FB2252A0410024544D /* gist.json in Resources */, E7EDEA741C871FA8006BAAF2 /* issues.json in Resources */, BF8C7923F427B3CFC6833337 /* pull_requests.json in Resources */, BF8C7A686709462323C702D8 /* pull_request.json in Resources */, @@ -746,6 +765,8 @@ 23F643491C7AEF67000427B3 /* repo.json in Resources */, 23F6434F1C7AEF70000427B3 /* user_repos.json in Resources */, 23F6434D1C7AEF6D000427B3 /* user_mietzmithut.json in Resources */, + 515337F822529E7B0024544D /* gists.json in Resources */, + 515337FC2252A0410024544D /* gist.json in Resources */, E7EDEA751C871FA9006BAAF2 /* issues.json in Resources */, BF8C711C2C6B42F9F323FCFE /* pull_requests.json in Resources */, BF8C716EB8D5CA2CBBA745CB /* pull_request.json in Resources */, @@ -774,6 +795,7 @@ 234F4BD51BDDE3F900A58EF7 /* TestHelper.swift in Sources */, 23A0521F1CA924950068BFF7 /* OctoKitURLTestSession.swift in Sources */, 234F4BD01BDDE3F900A58EF7 /* ConfigurationTests.swift in Sources */, + 515337F222529D590024544D /* GistTests.swift in Sources */, 234F4BD21BDDE3F900A58EF7 /* OctokitSwiftTests.swift in Sources */, E7EE59DA1BE10DA60012E3D2 /* StarsTests.swift in Sources */, BF8C719220F02AC04EF3D137 /* PullRequestTests.swift in Sources */, @@ -838,6 +860,7 @@ 23CAF2C01C7AB702005011C4 /* PublicKeyTests.swift in Sources */, 23A052201CA924950068BFF7 /* OctoKitURLTestSession.swift in Sources */, 23CAF2CA1C7AB711005011C4 /* UserTests.swift in Sources */, + 515337F322529D5A0024544D /* GistTests.swift in Sources */, 23CAF2C21C7AB705005011C4 /* RepositoryTests.swift in Sources */, 23CAF2BA1C7AB6F1005011C4 /* ConfigurationTests.swift in Sources */, BF8C725A44F262E5305385CC /* PullRequestTests.swift in Sources */, @@ -879,6 +902,7 @@ 23CAF2C11C7AB702005011C4 /* PublicKeyTests.swift in Sources */, 23A052211CA924950068BFF7 /* OctoKitURLTestSession.swift in Sources */, 23CAF2CB1C7AB712005011C4 /* UserTests.swift in Sources */, + 515337F422529D5C0024544D /* GistTests.swift in Sources */, 23CAF2C31C7AB706005011C4 /* RepositoryTests.swift in Sources */, 23CAF2BB1C7AB6F1005011C4 /* ConfigurationTests.swift in Sources */, BF8C732A1D13EFA1DE994A6B /* PullRequestTests.swift in Sources */, diff --git a/OctoKit/File.swift b/OctoKit/File.swift index 280b451c..ccd5e092 100644 --- a/OctoKit/File.swift +++ b/OctoKit/File.swift @@ -1,8 +1,7 @@ import Foundation -public typealias FileDict = [String: File] -public typealias Files = [FileDict] +public typealias Files = [String: File] open class File: Codable { open private(set) var id: Int = -1 diff --git a/OctoKit/Gist.swift b/OctoKit/Gist.swift index abc07f1b..f2160ebb 100644 --- a/OctoKit/Gist.swift +++ b/OctoKit/Gist.swift @@ -4,7 +4,7 @@ import RequestKit // MARK: model open class Gist: Codable { - open private(set) var id: Int = -1 + open private(set) var id: String? open var url: URL? open var forksURL: URL? open var commitsURL: URL? @@ -45,6 +45,27 @@ open class Gist: Codable { public extension Octokit { + /** + Fetches the gists of the authenticated user + - parameter session: RequestKitURLSession, defaults to URLSession.sharedSession() + - 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 myGists(_ session: RequestKitURLSession = URLSession.shared, page: String = "1", perPage: String = "100", completion: @escaping (_ response: Response<[Gist]>) -> Void) -> URLSessionDataTaskProtocol? { + let router = GistRouter.readAuthenticatedGists(configuration, page, perPage) + return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [Gist].self) { gists, error in + if let error = error { + completion(Response.failure(error)) + } else { + if let gists = gists { + completion(Response.success(gists)) + } + } + } + } + /** Fetches the gists of the specified user - parameter session: RequestKitURLSession, defaults to URLSession.sharedSession() @@ -74,7 +95,7 @@ public extension Octokit { - parameter completion: Callback for the outcome of the fetch. */ @discardableResult - func gist(_ session: RequestKitURLSession = URLSession.shared, id: Int, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { + func gist(_ session: RequestKitURLSession = URLSession.shared, id: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { let router = GistRouter.readGist(configuration, id) return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: Gist.self) { gist, error in if let error = error { @@ -96,16 +117,16 @@ public extension Octokit { - parameter completion: Callback for the issue that is created. */ @discardableResult - func postGistFile(_ session: RequestKitURLSession = URLSession.shared, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { + func postGistFile(_ session: RequestKitURLSession = URLSession.shared, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { let router = GistRouter.postGistFile(configuration, description, filename, fileContent) let decoder = JSONDecoder() decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) - return router.post(session, decoder: decoder, expectedResultType: Issue.self) { issue, error in + return router.post(session, decoder: decoder, expectedResultType: Gist.self) { gist, error in if let error = error { completion(Response.failure(error)) } else { - if let issue = issue { - completion(Response.success(issue)) + if let gist = gist { + completion(Response.success(gist)) } } } @@ -124,7 +145,7 @@ public extension Octokit { - parameter completion: Callback for the issue that is created. */ @discardableResult - func patchIssue(_ session: RequestKitURLSession = URLSession.shared, id: String, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { + func patchGistFile(_ session: RequestKitURLSession = URLSession.shared, id: String, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { let router = GistRouter.patchGistFile(configuration, id, description, filename, fileContent) let decoder = JSONDecoder() decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) @@ -143,8 +164,9 @@ public extension Octokit { // MARK: Router enum GistRouter: JSONPostRouter { + case readAuthenticatedGists(Configuration, String, String) case readGists(Configuration, String, String, String) - case readGist(Configuration, Int) + case readGist(Configuration, String) case postGistFile(Configuration, String, String, String) case patchGistFile(Configuration, String, String, String, String) @@ -168,6 +190,7 @@ enum GistRouter: JSONPostRouter { var configuration: Configuration { switch self { + case .readAuthenticatedGists(let config, _, _): return config case .readGists(let config, _, _, _): return config case .readGist(let config, _): return config case .postGistFile(let config, _, _, _): return config @@ -177,6 +200,8 @@ enum GistRouter: JSONPostRouter { var params: [String: Any] { switch self { + case .readAuthenticatedGists(_, let page, let perPage): + return ["per_page": perPage, "page": page] case .readGists(_, _, let page, let perPage): return ["per_page": perPage, "page": page] case .readGist: @@ -204,6 +229,8 @@ enum GistRouter: JSONPostRouter { var path: String { switch self { + case .readAuthenticatedGists(_, _, _): + return "/gists" case .readGists(_, let owner, _, _): return "users/\(owner)/gists" case .readGist(_, let id): diff --git a/Tests/OctoKitTests/Fixtures/gist.json b/Tests/OctoKitTests/Fixtures/gist.json new file mode 100644 index 00000000..5fff71ee --- /dev/null +++ b/Tests/OctoKitTests/Fixtures/gist.json @@ -0,0 +1,136 @@ +{ + "url": "https://api.github.com/gists/aa5a315d61ae9438b18d", + "forks_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/forks", + "commits_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/commits", + "id": "aa5a315d61ae9438b18d", + "node_id": "MDQ6R2lzdGFhNWEzMTVkNjFhZTk0MzhiMThk", + "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", + "files": { + "hello_world.rb": { + "filename": "hello_world.rb", + "type": "application/x-ruby", + "language": "Ruby", + "raw_url": "https://gist.githubusercontent.com/octocat/6cad326836d38bd3a7ae/raw/db9c55113504e46fa076e7df3a04ce592e2e86d8/hello_world.rb", + "size": 167, + "truncated": false, + "content": "class HelloWorld\n def initialize(name)\n @name = name.capitalize\n end\n def sayHi\n puts \"Hello !\"\n end\nend\n\nhello = HelloWorld.new(\"World\")\nhello.sayHi" + }, + "hello_world.py": { + "filename": "hello_world.py", + "type": "application/x-python", + "language": "Python", + "raw_url": "https://gist.githubusercontent.com/octocat/e29f3839074953e1cc2934867fa5f2d2/raw/99c1bf3a345505c2e6195198d5f8c36267de570b/hello_world.py", + "size": 199, + "truncated": false, + "content": "class HelloWorld:\n\n def __init__(self, name):\n self.name = name.capitalize()\n \n def sayHi(self):\n print \"Hello \" + self.name + \"!\"\n\nhello = HelloWorld(\"world\")\nhello.sayHi()" + }, + "hello_world_ruby.txt": { + "filename": "hello_world_ruby.txt", + "type": "text/plain", + "language": "Text", + "raw_url": "https://gist.githubusercontent.com/octocat/e29f3839074953e1cc2934867fa5f2d2/raw/9e4544db60e01a261aac098592b11333704e9082/hello_world_ruby.txt", + "size": 46, + "truncated": false, + "content": "Run `ruby hello_world.rb` to print Hello World" + }, + "hello_world_python.txt": { + "filename": "hello_world_python.txt", + "type": "text/plain", + "language": "Text", + "raw_url": "https://gist.githubusercontent.com/octocat/e29f3839074953e1cc2934867fa5f2d2/raw/076b4b78c10c9b7e1e0b73ffb99631bfc948de3b/hello_world_python.txt", + "size": 48, + "truncated": false, + "content": "Run `python hello_world.py` to print Hello World" + } + }, + "public": true, + "created_at": "2010-04-14T02:15:15Z", + "updated_at": "2011-06-20T11:34:15Z", + "description": "Hello World Examples", + "comments": 0, + "user": null, + "comments_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/comments/", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "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}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "truncated": false, + "forks": [ + { + "user": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "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}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "url": "https://api.github.com/gists/dee9c42e4998ce2ea439", + "id": "dee9c42e4998ce2ea439", + "created_at": "2011-04-14T16:00:49Z", + "updated_at": "2011-04-14T16:00:49Z" + } + ], + "history": [ + { + "url": "https://api.github.com/gists/aa5a315d61ae9438b18d/57a7f021a713b1c5a6a199b54cc514735d2d462f", + "version": "57a7f021a713b1c5a6a199b54cc514735d2d462f", + "user": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "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}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "change_status": { + "deletions": 0, + "additions": 180, + "total": 180 + }, + "committed_at": "2010-04-14T02:15:15Z" + } + ] +} diff --git a/Tests/OctoKitTests/Fixtures/gists.json b/Tests/OctoKitTests/Fixtures/gists.json new file mode 100644 index 00000000..d28aa0a8 --- /dev/null +++ b/Tests/OctoKitTests/Fixtures/gists.json @@ -0,0 +1,49 @@ +[ + { + "url": "https://api.github.com/gists/aa5a315d61ae9438b18d", + "forks_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/forks", + "commits_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/commits", + "id": "aa5a315d61ae9438b18d", + "node_id": "MDQ6R2lzdGFhNWEzMTVkNjFhZTk0MzhiMThk", + "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", + "files": { + "hello_world.rb": { + "filename": "hello_world.rb", + "type": "application/x-ruby", + "language": "Ruby", + "raw_url": "https://gist.githubusercontent.com/octocat/6cad326836d38bd3a7ae/raw/db9c55113504e46fa076e7df3a04ce592e2e86d8/hello_world.rb", + "size": 167 + } + }, + "public": true, + "created_at": "2010-04-14T02:15:15Z", + "updated_at": "2011-06-20T11:34:15Z", + "description": "Hello World Examples", + "comments": 0, + "user": null, + "comments_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/comments/", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "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}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "truncated": false + } +] diff --git a/Tests/OctoKitTests/GistTests.swift b/Tests/OctoKitTests/GistTests.swift new file mode 100644 index 00000000..6b394804 --- /dev/null +++ b/Tests/OctoKitTests/GistTests.swift @@ -0,0 +1,103 @@ + +import Foundation +import XCTest +import OctoKit + +class GistTests: XCTestCase { + + static var allTests = [ + ("testGetMyGists", testGetGists), + ("testGetGists", testGetGists), + ("testGetGist", testGetGist), + ("testPostGist", testPostGist), + ("testPatchGist", testPatchGist), + ("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests) + ] + + // MARK: Actual Request tests + + func testGetMyGists() { + let config = TokenConfiguration("12345") + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/gists?access_token=12345&page=1&per_page=100", expectedHTTPMethod: "GET", jsonFile: "gists", statusCode: 200) + let task = Octokit(config).myGists(session) { response in + switch response { + case .success(let gists): + XCTAssertEqual(gists.count, 1) + case .failure(let error): + XCTAssertNil(error) + } + } + XCTAssertNotNil(task) + XCTAssertTrue(session.wasCalled) + } + + func testGetGists() { + let config = TokenConfiguration("12345") + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/users/vincode-io/gists?access_token=12345&page=1&per_page=100", expectedHTTPMethod: "GET", jsonFile: "gists", statusCode: 200) + let task = Octokit(config).gists(session, owner: "vincode-io") { response in + switch response { + case .success(let gists): + XCTAssertEqual(gists.count, 1) + case .failure(let error): + XCTAssertNil(error) + } + } + XCTAssertNotNil(task) + XCTAssertTrue(session.wasCalled) + } + + func testGetGist() { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/gists/aa5a315d61ae9438b18d", expectedHTTPMethod: "GET", jsonFile: "gist", statusCode: 200) + let task = Octokit().gist(session, id: "aa5a315d61ae9438b18d") { response in + switch response { + case .success(let gist): + XCTAssertEqual(gist.id, "aa5a315d61ae9438b18d") + case .failure: + XCTAssert(false, "should not get an error") + } + } + XCTAssertNotNil(task) + XCTAssertTrue(session.wasCalled) + } + + func testPostGist() { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/gists", expectedHTTPMethod: "POST", jsonFile: "gist", statusCode: 200) + let task = Octokit().postGistFile(session, description: "Test Post", filename: "Hello-World.swift", fileContent: "Sample Program") { response in + switch response { + case .success(let gist): + XCTAssertEqual(gist.id, "aa5a315d61ae9438b18d") + case .failure: + XCTAssert(false, "should not get an error") + } + } + XCTAssertNotNil(task) + XCTAssertTrue(session.wasCalled) + } + + func testPatchGist() { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/gists/aa5a315d61ae9438b18d", expectedHTTPMethod: "POST", jsonFile: "gist", statusCode: 200) + let task = Octokit().patchGistFile(session, id: "aa5a315d61ae9438b18d", description: "Test Post", filename: "Hello-World.swift", fileContent: "Sample Program") { response in + switch response { + case .success(let gist): + XCTAssertEqual(gist.id, "aa5a315d61ae9438b18d") + case .failure: + XCTAssert(false, "should not get an error") + } + } + XCTAssertNotNil(task) + XCTAssertTrue(session.wasCalled) + } + + func testLinuxTestSuiteIncludesAllTests() { + #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) + let thisClass = type(of: self) + let linuxCount = thisClass.allTests.count + #if os(iOS) + let darwinCount = thisClass.defaultTestSuite.tests.count + #else + let darwinCount = thisClass.defaultTestSuite.tests.count + #endif + XCTAssertEqual(linuxCount, darwinCount, "\(darwinCount - linuxCount) tests are missing from allTests") + #endif + } +} From 68ece0b9261af2c39ef9e2035ba8cd0476af2d8f Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Mon, 1 Apr 2019 15:14:19 -0500 Subject: [PATCH 4/6] Fixed my sloppy documentation. --- OctoKit/Gist.swift | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/OctoKit/Gist.swift b/OctoKit/Gist.swift index f2160ebb..c7206770 100644 --- a/OctoKit/Gist.swift +++ b/OctoKit/Gist.swift @@ -89,7 +89,7 @@ public extension Octokit { } /** - Fetches an gist in a repository + Fetches an gist - parameter session: RequestKitURLSession, defaults to URLSession.sharedSession() - parameter id: The id of the gist. - parameter completion: Callback for the outcome of the fetch. @@ -114,7 +114,7 @@ public extension Octokit { - 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. - - parameter completion: Callback for the issue that is created. + - parameter completion: Callback for the gist that is created. */ @discardableResult func postGistFile(_ session: RequestKitURLSession = URLSession.shared, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { @@ -133,16 +133,13 @@ public extension Octokit { } /** - Edits an issue in a repository. + Edits an gist with a single file. - parameter session: RequestKitURLSession, defaults to URLSession.sharedSession() - - parameter owner: The user or organization that owns the repository. - - parameter repository: The name of the repository. - - parameter number: The number of the issue. - - parameter title: The title of the issue. - - parameter body: The body text of the issue in GitHub-flavored Markdown format. - - parameter assignee: The name of the user to assign the issue to. This parameter is ignored if the user lacks push access to the repository. - - parameter state: Whether the issue is open or closed. - - parameter completion: Callback for the issue that is created. + - 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. + - parameter fileContent: The content of the file in the gist. + - parameter completion: Callback for the gist that is created. */ @discardableResult func patchGistFile(_ session: RequestKitURLSession = URLSession.shared, id: String, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { From 00ea4b4cdd3aa629131e70948f55886af539b2d5 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Mon, 1 Apr 2019 17:14:09 -0500 Subject: [PATCH 5/6] Added publicAccess to the Gist post function. --- OctoKit/Gist.swift | 15 ++++++++------- Tests/OctoKitTests/GistTests.swift | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/OctoKit/Gist.swift b/OctoKit/Gist.swift index c7206770..fdacaf3e 100644 --- a/OctoKit/Gist.swift +++ b/OctoKit/Gist.swift @@ -117,8 +117,8 @@ public extension Octokit { - parameter completion: Callback for the gist that is created. */ @discardableResult - func postGistFile(_ session: RequestKitURLSession = URLSession.shared, description: String, filename: String, fileContent: String, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { - let router = GistRouter.postGistFile(configuration, description, filename, fileContent) + func postGistFile(_ session: RequestKitURLSession = URLSession.shared, description: String, filename: String, fileContent: String, publicAccess: Bool, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { + let router = GistRouter.postGistFile(configuration, description, filename, fileContent, publicAccess) let decoder = JSONDecoder() decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) return router.post(session, decoder: decoder, expectedResultType: Gist.self) { gist, error in @@ -164,7 +164,7 @@ enum GistRouter: JSONPostRouter { case readAuthenticatedGists(Configuration, String, String) case readGists(Configuration, String, String, String) case readGist(Configuration, String) - case postGistFile(Configuration, String, String, String) + case postGistFile(Configuration, String, String, String, Bool) case patchGistFile(Configuration, String, String, String, String) var method: HTTPMethod { @@ -190,7 +190,7 @@ enum GistRouter: JSONPostRouter { case .readAuthenticatedGists(let config, _, _): return config case .readGists(let config, _, _, _): return config case .readGist(let config, _): return config - case .postGistFile(let config, _, _, _): return config + case .postGistFile(let config, _, _, _, _): return config case .patchGistFile(let config, _, _, _, _): return config } } @@ -203,8 +203,9 @@ enum GistRouter: JSONPostRouter { return ["per_page": perPage, "page": page] case .readGist: return [:] - case .postGistFile(_, let description, let filename, let fileContent): + case .postGistFile(_, let description, let filename, let fileContent, let publicAccess): var params = [String: Any]() + params["public"] = publicAccess params["description"] = description var file = [String: Any]() file["content"] = fileContent @@ -227,12 +228,12 @@ enum GistRouter: JSONPostRouter { var path: String { switch self { case .readAuthenticatedGists(_, _, _): - return "/gists" + return "gists" case .readGists(_, let owner, _, _): return "users/\(owner)/gists" case .readGist(_, let id): return "gists/\(id)" - case .postGistFile(_, _, _, _): + case .postGistFile(_, _, _, _, _): return "gists" case .patchGistFile(_, let id, _, _, _): return "gists/\(id)" diff --git a/Tests/OctoKitTests/GistTests.swift b/Tests/OctoKitTests/GistTests.swift index 6b394804..05b50448 100644 --- a/Tests/OctoKitTests/GistTests.swift +++ b/Tests/OctoKitTests/GistTests.swift @@ -62,7 +62,7 @@ class GistTests: XCTestCase { func testPostGist() { let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/gists", expectedHTTPMethod: "POST", jsonFile: "gist", statusCode: 200) - let task = Octokit().postGistFile(session, description: "Test Post", filename: "Hello-World.swift", fileContent: "Sample Program") { response in + let task = Octokit().postGistFile(session, description: "Test Post", filename: "Hello-World.swift", fileContent: "Sample Program", publicAccess: true) { response in switch response { case .success(let gist): XCTAssertEqual(gist.id, "aa5a315d61ae9438b18d") From bdc02b0574bdc2de14517e380fcc6b197d9ac31a Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 2 Apr 2019 05:56:55 -0500 Subject: [PATCH 6/6] Added missing parameter comment. --- OctoKit/Gist.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/OctoKit/Gist.swift b/OctoKit/Gist.swift index fdacaf3e..920d35dd 100644 --- a/OctoKit/Gist.swift +++ b/OctoKit/Gist.swift @@ -114,6 +114,7 @@ public extension Octokit { - 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. + - parameter publicAccess: The public/private visability of the gist. - parameter completion: Callback for the gist that is created. */ @discardableResult