From af7fa1d35bba80b87b905b03ea98f144ae1770d1 Mon Sep 17 00:00:00 2001 From: Jeroen Wesbeek Date: Wed, 4 Dec 2024 17:27:19 +0100 Subject: [PATCH 1/2] - Extend PullRequest to read and create pull request review comments (regular comments as well as comments to specific commits / line numbers) - Add support for fetching requested reviewers (users and teams) for a Pull Request - Fix lint warnings --- OctoKit/Issue.swift | 54 +-- OctoKit/PullRequest.swift | 316 ++++++++++++++++-- OctoKit/Team.swift | 83 +++++ .../Fixtures/pull_request_comment.json | 56 ++++ .../Fixtures/pull_request_comments.json | 58 ++++ ...sts_files.json => pull_request_files.json} | 0 .../pull_request_requested_reviewers.json | 41 +++ Tests/OctoKitTests/PullRequestTests.swift | 178 +++++++++- 8 files changed, 730 insertions(+), 56 deletions(-) create mode 100644 OctoKit/Team.swift create mode 100644 Tests/OctoKitTests/Fixtures/pull_request_comment.json create mode 100644 Tests/OctoKitTests/Fixtures/pull_request_comments.json rename Tests/OctoKitTests/Fixtures/{pull_requests_files.json => pull_request_files.json} (100%) create mode 100644 Tests/OctoKitTests/Fixtures/pull_request_requested_reviewers.json diff --git a/OctoKit/Issue.swift b/OctoKit/Issue.swift index ffb4dfe3..0d7fa0b6 100644 --- a/OctoKit/Issue.swift +++ b/OctoKit/Issue.swift @@ -104,21 +104,23 @@ open class Issue: Codable { } } -public struct Comment: Codable { - public let id: Int - public let url: URL - public let htmlURL: URL - public let body: String - public let user: User - public let createdAt: Date - public let updatedAt: Date - public let reactions: Reactions? +public extension Issue { + struct Comment: Codable { + public let id: Int + public let url: URL + public let htmlURL: URL + public let body: String + public let user: User + public let createdAt: Date + public let updatedAt: Date + public let reactions: Reactions? - enum CodingKeys: String, CodingKey { - case id, url, body, user, reactions - case htmlURL = "html_url" - case createdAt = "created_at" - case updatedAt = "updated_at" + enum CodingKeys: String, CodingKey { + case id, url, body, user, reactions + case htmlURL = "html_url" + case createdAt = "created_at" + case updatedAt = "updated_at" + } } } @@ -382,11 +384,11 @@ public extension Octokit { repository: String, number: Int, body: String, - completion: @escaping (_ response: Result) -> Void) -> URLSessionDataTaskProtocol? { + completion: @escaping (_ response: Result) -> Void) -> URLSessionDataTaskProtocol? { let router = IssueRouter.commentIssue(configuration, owner, repository, number, body) let decoder = JSONDecoder() decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) - return router.post(session, decoder: decoder, expectedResultType: Comment.self) { issue, error in + return router.post(session, decoder: decoder, expectedResultType: Issue.Comment.self) { issue, error in if let error = error { completion(.failure(error)) } else { @@ -406,11 +408,11 @@ public extension Octokit { /// - body: The contents of the comment. /// - completion: Callback for the comment that is created. @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) - func commentIssue(owner: String, repository: String, number: Int, body: String) async throws -> Comment { + func commentIssue(owner: String, repository: String, number: Int, body: String) async throws -> Issue.Comment { let router = IssueRouter.commentIssue(configuration, owner, repository, number, body) let decoder = JSONDecoder() decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) - return try await router.post(session, decoder: decoder, expectedResultType: Comment.self) + return try await router.post(session, decoder: decoder, expectedResultType: Issue.Comment.self) } #endif @@ -428,9 +430,9 @@ public extension Octokit { number: Int, page: String = "1", perPage: String = "100", - completion: @escaping (_ response: Result<[Comment], Error>) -> Void) -> URLSessionDataTaskProtocol? { + completion: @escaping (_ response: Result<[Issue.Comment], Error>) -> Void) -> URLSessionDataTaskProtocol? { let router = IssueRouter.readIssueComments(configuration, owner, repository, number, page, perPage) - return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [Comment].self) { comments, error in + return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [Issue.Comment].self) { comments, error in if let error = error { completion(.failure(error)) } else { @@ -455,9 +457,9 @@ public extension Octokit { repository: String, number: Int, page: String = "1", - perPage: String = "100") async throws -> [Comment] { + perPage: String = "100") async throws -> [Issue.Comment] { let router = IssueRouter.readIssueComments(configuration, owner, repository, number, page, perPage) - return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [Comment].self) + return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [Issue.Comment].self) } #endif @@ -473,11 +475,11 @@ public extension Octokit { repository: String, number: Int, body: String, - completion: @escaping (_ response: Result) -> Void) -> URLSessionDataTaskProtocol? { + completion: @escaping (_ response: Result) -> Void) -> URLSessionDataTaskProtocol? { let router = IssueRouter.patchIssueComment(configuration, owner, repository, number, body) let decoder = JSONDecoder() decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) - return router.post(session, decoder: decoder, expectedResultType: Comment.self) { issue, error in + return router.post(session, decoder: decoder, expectedResultType: Issue.Comment.self) { issue, error in if let error = error { completion(.failure(error)) } else { @@ -497,11 +499,11 @@ public extension Octokit { /// - body: The contents of the comment. /// - completion: Callback for the comment that is created. @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) - func patchIssueComment(owner: String, repository: String, number: Int, body: String) async throws -> Comment { + func patchIssueComment(owner: String, repository: String, number: Int, body: String) async throws -> Issue.Comment { let router = IssueRouter.patchIssueComment(configuration, owner, repository, number, body) let decoder = JSONDecoder() decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) - return try await router.post(session, decoder: decoder, expectedResultType: Comment.self) + return try await router.post(session, decoder: decoder, expectedResultType: Issue.Comment.self) } #endif } diff --git a/OctoKit/PullRequest.swift b/OctoKit/PullRequest.swift index 85584fd5..5dcd71ea 100644 --- a/OctoKit/PullRequest.swift +++ b/OctoKit/PullRequest.swift @@ -180,6 +180,58 @@ extension PullRequest.File { } } +public extension PullRequest { + struct Comment: Codable { + public let id: Int + public let url: URL + public let htmlURL: URL + public let body: String + public let user: User + public let createdAt: Date + public let updatedAt: Date + public let reactions: Reactions? + + /// The SHA of the commit this comment is associated with. + public private(set) var commitId: String? + /// The line of the blob in the pull request diff that the comment applies to. For a multi-line comment, the last line of the range that your comment applies to. + public private(set) var line: Int? + /// The first line in the pull request diff that the multi-line comment applies to. + public private(set) var startLine: Int? + /// The starting side of the diff that the comment applies to. + public private(set) var side: Side? + /// The level at which the comment is targeted. + public private(set) var subjectType: SubjectType? + /// The ID of the review comment this comment replied to. + public private(set) var inReplyToId: Int? + + enum CodingKeys: String, CodingKey { + case id, url, body, user, reactions + case htmlURL = "html_url" + case createdAt = "created_at" + case updatedAt = "updated_at" + + case line, side + case commitId = "commit_id" + case startLine = "start_line" + case inReplyToId = "in_reply_to_id" + } + } +} + +public extension PullRequest.Comment { + enum Side: String, Codable { + case left = "LEFT" + case right = "RIGHT" + case side + } +} + +public extension PullRequest.Comment { + enum SubjectType: String, Codable { + case line, file + } +} + // MARK: Request public extension Octokit { @@ -213,10 +265,8 @@ public extension Octokit { return router.post(session, decoder: decoder, expectedResultType: PullRequest.self) { pullRequest, error in if let error = error { completion(.failure(error)) - } else { - if let pullRequest = pullRequest { - completion(.success(pullRequest)) - } + } else if let pullRequest { + completion(.success(pullRequest)) } } } @@ -268,10 +318,8 @@ public extension Octokit { return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: PullRequest.self) { pullRequest, error in if let error = error { completion(.failure(error)) - } else { - if let pullRequest = pullRequest { - completion(.success(pullRequest)) - } + } else if let pullRequest { + completion(.success(pullRequest)) } } } @@ -319,10 +367,8 @@ public extension Octokit { return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [PullRequest].self) { pullRequests, error in if let error = error { completion(.failure(error)) - } else { - if let pullRequests = pullRequests { - completion(.success(pullRequests)) - } + } else if let pullRequests { + completion(.success(pullRequests)) } } } @@ -381,10 +427,8 @@ public extension Octokit { return router.post(session, decoder: decoder, expectedResultType: PullRequest.self) { pullRequest, error in if let error = error { completion(.failure(error)) - } else { - if let pullRequest = pullRequest { - completion(.success(pullRequest)) - } + } else if let pullRequest { + completion(.success(pullRequest)) } } } @@ -416,7 +460,6 @@ public extension Octokit { decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) return try await router.post(session, decoder: decoder, expectedResultType: PullRequest.self) } - #endif func listPullRequestsFiles(owner: String, @@ -429,10 +472,8 @@ public extension Octokit { return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [PullRequest.File].self) { files, error in if let error = error { completion(.failure(error)) - } else { - if let files = files { - completion(.success(files)) - } + } else if let files { + completion(.success(files)) } } } @@ -448,6 +489,196 @@ public extension Octokit { return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [PullRequest.File].self) } #endif + + /// Fetches all review comments for a pull request. + /// - Parameters: + /// - owner: The user or organization that owns the repository. + /// - repository: The name of the repository. + /// - number: The number of the pull request. + /// - page: Current page for comments pagination. `1` by default. + /// - perPage: Number of comments per page. `100` by default. + /// - completion: Callback for the outcome of the fetch. + @discardableResult + func readPullRequestReviewComments(owner: String, + repository: String, + number: Int, + page: Int = 1, + perPage: Int = 100, + completion: @escaping (_ response: Result<[PullRequest.Comment], Error>) -> Void) -> URLSessionDataTaskProtocol? { + let router = PullRequestRouter.readPullRequestReviewComments(configuration, owner, repository, number, page, perPage) + return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [PullRequest.Comment].self) { comments, error in + if let error = error { + completion(.failure(error)) + } else if let comments { + completion(.success(comments)) + } + } + } + + #if compiler(>=5.5.2) && canImport(_Concurrency) + /// Fetches all review comments for a pull request. + /// - Parameters: + /// - owner: The user or organization that owns the repository. + /// - repository: The name of the repository. + /// - number: The number of the pull request. + /// - page: Current page for comments pagination. `1` by default. + /// - perPage: Number of comments per page. `100` by default. + @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) + func readPullRequestReviewComments(owner: String, + repository: String, + number: Int, + page: Int = 1, + perPage: Int = 100) async throws -> [PullRequest.Comment] { + let router = PullRequestRouter.readPullRequestReviewComments(configuration, owner, repository, number, page, perPage) + return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [PullRequest.Comment].self) + } + #endif + + /// Posts a review comment on a pull request using the given body. + /// - Parameters: + /// - owner: The user or organization that owns the repository. + /// - repository: The name of the repository. + /// - number: The number of the pull request. + /// - commitId: The SHA of the commit needing a comment. + /// - path: The relative path to the file that necessitates a comment. + /// - line: The line of the blob in the pull request diff that the comment applies to. + /// - body: The text of the review comment. + /// - completion: Callback for the comment that is created. + @discardableResult + func createPullRequestReviewComment(owner: String, + repository: String, + number: Int, + commitId: String, + path: String, + line: Int, + body: String, + completion: @escaping (_ response: Result) -> Void) -> URLSessionDataTaskProtocol? { + let router = PullRequestRouter.createPullRequestReviewComment(configuration, owner, repository, number, commitId, path, line, body) + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) + return router.post(session, decoder: decoder, expectedResultType: PullRequest.Comment.self) { issue, error in + if let error = error { + completion(.failure(error)) + } else if let issue { + completion(.success(issue)) + } + } + } + + #if compiler(>=5.5.2) && canImport(_Concurrency) + /// Posts a review comment on a pull request using the given body. + /// - Parameters: + /// - owner: The user or organization that owns the repository. + /// - repository: The name of the repository. + /// - number: The number of the pull request. + /// - commitId: The SHA of the commit needing a comment. + /// - path: The relative path to the file that necessitates a comment. + /// - line: The line of the blob in the pull request diff that the comment applies to. + /// - body: The contents of the comment. + @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) + func createPullRequestReviewComment(owner: String, + repository: String, + number: Int, + commitId: String, + path: String, + line: Int, + body: String) async throws -> PullRequest.Comment { + let router = PullRequestRouter.createPullRequestReviewComment(configuration, owner, repository, number, commitId, path, line, body) + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(Time.rfc3339DateFormatter) + return try await router.post(session, decoder: decoder, expectedResultType: PullRequest.Comment.self) + } + #endif + + /// Posts a review comment on a pull request using the given body. + /// - Parameters: + /// - owner: The user or organization that owns the repository. + /// - repository: The name of the repository. + /// - number: The number of the pull request. + /// - body: The text of the review comment. + /// - completion: Callback for the comment that is created. + @discardableResult + func createPullRequestReviewComment(owner: String, + repository: String, + number: Int, + body: String, + completion: @escaping (_ response: Result) -> Void) -> URLSessionDataTaskProtocol? { + /// To add a regular comment to a pull request timeline, the Issue Comment API should be used. + /// See: https://docs.github.com/en/rest/pulls/comments?apiVersion=2022-11-28#create-a-review-comment-for-a-pull-request + commentIssue(owner: owner, + repository: repository, + number: number, body: body, + completion: completion) + } + + #if compiler(>=5.5.2) && canImport(_Concurrency) + /// Posts a review comment on a pull request using the given body. + /// - Parameters: + /// - owner: The user or organization that owns the repository. + /// - repository: The name of the repository. + /// - number: The number of the pull request. + /// - body: The contents of the comment. + @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) + func createPullRequestReviewComment(owner: String, + repository: String, + number: Int, + body: String) async throws -> Issue.Comment { + /// To add a regular comment to a pull request timeline, the Issue Comment API should be used. + /// See: https://docs.github.com/en/rest/pulls/comments?apiVersion=2022-11-28#create-a-review-comment-for-a-pull-request + try await commentIssue(owner: owner, repository: repository, number: number, body: body) + } + #endif + + /// Fetches all reviewers for a pull request. + /// - Parameters: + /// - owner: The user or organization that owns the repository. + /// - repository: The name of the repository. + /// - number: The number of the pull request. + /// - page: Current page for comments pagination. `1` by default. + /// - perPage: Number of comments per page. `100` by default. + /// - completion: Callback for the outcome of the fetch. + @discardableResult + func readPullRequestRequestedReviewers(owner: String, + repository: String, + number: Int, + page: Int = 1, + perPage: Int = 100, + completion: @escaping (_ response: Result) -> Void) -> URLSessionDataTaskProtocol? { + let router = PullRequestRouter.readPullRequestRequestedReviewers(configuration, owner, repository, number, page, perPage) + return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: PullRequest.RequestedReviewers.self) { requestedReviewers, error in + if let error = error { + completion(.failure(error)) + } else if let requestedReviewers { + completion(.success(requestedReviewers)) + } + } + } + + #if compiler(>=5.5.2) && canImport(_Concurrency) + /// Fetches all reviewers for a pull request. + /// - Parameters: + /// - owner: The user or organization that owns the repository. + /// - repository: The name of the repository. + /// - number: The number of the pull request. + /// - page: Current page for comments pagination. `1` by default. + /// - perPage: Number of comments per page. `100` by default. + @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) + func readPullRequestRequestedReviewers(owner: String, + repository: String, + number: Int, + page: Int = 1, + perPage: Int = 100) async throws -> PullRequest.RequestedReviewers { + let router = PullRequestRouter.readPullRequestRequestedReviewers(configuration, owner, repository, number, page, perPage) + return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: PullRequest.RequestedReviewers.self) + } + #endif +} + +public extension PullRequest { + struct RequestedReviewers: Codable { + public private(set) var users = [User]() + public private(set) var teams = [Team]() + } } // MARK: Router @@ -458,14 +689,20 @@ enum PullRequestRouter: JSONPostRouter { case createPullRequest(Configuration, String, String, String, String, String?, String, String?, Bool?, Bool?) case patchPullRequest(Configuration, String, String, String, String, String, Openness, String?, Bool?) case listPullRequestsFiles(Configuration, String, String, Int, Int?, Int?) + case readPullRequestReviewComments(Configuration, String, String, Int, Int?, Int?) + case createPullRequestReviewComment(Configuration, String, String, Int, String, String, Int, String) + case readPullRequestRequestedReviewers(Configuration, String, String, Int, Int?, Int?) var method: HTTPMethod { switch self { - case .createPullRequest: + case .createPullRequest, + .createPullRequestReviewComment: return .POST case .readPullRequest, .readPullRequests, - .listPullRequestsFiles: + .listPullRequestsFiles, + .readPullRequestReviewComments, + .readPullRequestRequestedReviewers: return .GET case .patchPullRequest: return .PATCH @@ -474,7 +711,9 @@ enum PullRequestRouter: JSONPostRouter { var encoding: HTTPEncoding { switch self { - case .patchPullRequest, .createPullRequest: + case .patchPullRequest, + .createPullRequest, + .createPullRequestReviewComment: return .json default: return .url @@ -488,6 +727,9 @@ enum PullRequestRouter: JSONPostRouter { case let .patchPullRequest(config, _, _, _, _, _, _, _, _): return config case let .createPullRequest(config, _, _, _, _, _, _, _, _, _): return config case let .listPullRequestsFiles(config, _, _, _, _, _): return config + case let .readPullRequestReviewComments(config, _, _, _, _, _): return config + case let .createPullRequestReviewComment(config, _, _, _, _, _, _, _): return config + case let .readPullRequestRequestedReviewers(config, _, _, _, _, _): return config } } @@ -552,15 +794,24 @@ enum PullRequestRouter: JSONPostRouter { parameters["draft"] = draft } return parameters - case let .listPullRequestsFiles(_, _, _, _, perPage, page): + case let .listPullRequestsFiles(_, _, _, _, perPage, page), + let .readPullRequestReviewComments(_, _, _, _, page, perPage), + let .readPullRequestRequestedReviewers(_, _, _, _, page, perPage): var parameters: [String: Any] = [:] - if let perPage = perPage { + if let perPage { parameters["per_page"] = perPage } - if let page = page { + if let page { parameters["page"] = page } return parameters + case let .createPullRequestReviewComment(_, _, _, _, commitId, path, line, body): + return [ + "body": body, + "commit_id": commitId, + "path": path, + "line": line + ] } } @@ -575,7 +826,16 @@ enum PullRequestRouter: JSONPostRouter { case let .createPullRequest(_, owner, repository, _, _, _, _, _, _, _): return "repos/\(owner)/\(repository)/pulls" case let .listPullRequestsFiles(_, owner, repository, number, _, _): - return "/repos/\(owner)/\(repository)/pulls/\(number)/files" + return "repos/\(owner)/\(repository)/pulls/\(number)/files" + case let .readPullRequestReviewComments(_, owner, repository, number, _, _): + /// See: https://docs.github.com/en/rest/pulls/comments?apiVersion=2022-11-28#list-review-comments-on-a-pull-request + return "repos/\(owner)/\(repository)/pulls/\(number)/comments" + case let .createPullRequestReviewComment(_, owner, repository, number, _, _, _, _): + /// See: https://docs.github.com/en/rest/pulls/comments?apiVersion=2022-11-28#create-a-review-comment-for-a-pull-request + return "repos/\(owner)/\(repository)/pulls/\(number)/comments" + case let .readPullRequestRequestedReviewers(_, owner, repository, number, _, _): + /// See: https://docs.github.com/en/rest/pulls/review-requests?apiVersion=2022-11-28#get-all-requested-reviewers-for-a-pull-request + return "repos/\(owner)/\(repository)/pulls/\(number)/requested_reviewers" } } } diff --git a/OctoKit/Team.swift b/OctoKit/Team.swift new file mode 100644 index 00000000..9b09125c --- /dev/null +++ b/OctoKit/Team.swift @@ -0,0 +1,83 @@ +// +// Team.swift +// OctoKit +// +// Created by Jeroen Wesbeek on 04/12/2024. +// + +import Foundation +import RequestKit +#if canImport(FoundationNetworking) +import FoundationNetworking +#endif + +// MARK: model + +open class Team: Codable { + open internal(set) var id: Int + open var nodeID: String + open var name: String + open var slug: String + open var description: String? + open var privacy: Privacy? + open var notificationSetting: NotificationSetting? + open var url: String? + open var htmlURL: String? + open var membersURL: String? + open var repositoriesURL: String? + + public init(id: Int = -1, + nodeID: String, + name: String, + slug: String, + description: String, + privacy: Privacy? = nil, + notificationSetting: NotificationSetting? = nil, + url: String? = nil, + htmlURL: String? = nil, + membersURL: String? = nil, + repositoriesURL: String? = nil) { + self.id = id + self.nodeID = nodeID + self.name = name + self.slug = slug + self.description = description + self.privacy = privacy + self.notificationSetting = notificationSetting + self.url = url + self.htmlURL = htmlURL + self.membersURL = membersURL + self.repositoriesURL = repositoriesURL + } + + enum CodingKeys: String, CodingKey { + case id, name, slug, description, privacy, url + case nodeID = "node_id" + case htmlURL = "html_url" + case membersURL = "members_url" + case repositoriesURL = "repositories_url" + } +} + +public extension Team { + /// The level of privacy of a team. + enum Privacy: String, Codable { + /// Only visible to organization owners and members of this team. + case secret + /// Visible to all members of this organization. + case closed + } +} + +public extension Team { + enum Permission: String, Codable { + case pull, push, triage, maintain, admin + } +} + +public extension Team { + enum NotificationSetting: String, Codable { + case enabled = "notifications_enabled" + case disabled = "notifications_disabled" + } +} diff --git a/Tests/OctoKitTests/Fixtures/pull_request_comment.json b/Tests/OctoKitTests/Fixtures/pull_request_comment.json new file mode 100644 index 00000000..2d390f67 --- /dev/null +++ b/Tests/OctoKitTests/Fixtures/pull_request_comment.json @@ -0,0 +1,56 @@ +{ + "url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1", + "pull_request_review_id": 42, + "id": 10, + "node_id": "MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDEw", + "diff_hunk": "@@ -16,33 +16,40 @@ public class Connection : IConnection...", + "path": "file1.txt", + "position": 1, + "original_position": 4, + "commit_id": "6dcb09b5b57875f334f61aebed695e2e4193db5e", + "original_commit_id": "9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840", + "in_reply_to_id": 8, + "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 + }, + "body": "Great stuff!", + "created_at": "2011-04-14T16:00:49Z", + "updated_at": "2011-04-14T16:00:49Z", + "html_url": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1", + "pull_request_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1", + "author_association": "NONE", + "_links": { + "self": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1" + }, + "html": { + "href": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1" + }, + "pull_request": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1" + } + }, + "start_line": 1, + "original_start_line": 1, + "start_side": "RIGHT", + "line": 2, + "original_line": 2, + "side": "RIGHT" +} diff --git a/Tests/OctoKitTests/Fixtures/pull_request_comments.json b/Tests/OctoKitTests/Fixtures/pull_request_comments.json new file mode 100644 index 00000000..231a17eb --- /dev/null +++ b/Tests/OctoKitTests/Fixtures/pull_request_comments.json @@ -0,0 +1,58 @@ +[ + { + "url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1", + "pull_request_review_id": 42, + "id": 10, + "node_id": "MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDEw", + "diff_hunk": "@@ -16,33 +16,40 @@ public class Connection : IConnection...", + "path": "file1.txt", + "position": 1, + "original_position": 4, + "commit_id": "6dcb09b5b57875f334f61aebed695e2e4193db5e", + "original_commit_id": "9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840", + "in_reply_to_id": 8, + "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 + }, + "body": "Great stuff!", + "created_at": "2011-04-14T16:00:49Z", + "updated_at": "2011-04-14T16:00:49Z", + "html_url": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1", + "pull_request_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1", + "author_association": "NONE", + "_links": { + "self": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1" + }, + "html": { + "href": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1" + }, + "pull_request": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1" + } + }, + "start_line": 1, + "original_start_line": 1, + "start_side": "RIGHT", + "line": 2, + "original_line": 2, + "side": "RIGHT" + } +] diff --git a/Tests/OctoKitTests/Fixtures/pull_requests_files.json b/Tests/OctoKitTests/Fixtures/pull_request_files.json similarity index 100% rename from Tests/OctoKitTests/Fixtures/pull_requests_files.json rename to Tests/OctoKitTests/Fixtures/pull_request_files.json diff --git a/Tests/OctoKitTests/Fixtures/pull_request_requested_reviewers.json b/Tests/OctoKitTests/Fixtures/pull_request_requested_reviewers.json new file mode 100644 index 00000000..780f0555 --- /dev/null +++ b/Tests/OctoKitTests/Fixtures/pull_request_requested_reviewers.json @@ -0,0 +1,41 @@ +{ + "users": [ + { + "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 + } + ], + "teams": [ + { + "id": 1, + "node_id": "MDQ6VGVhbTE=", + "url": "https://api.github.com/teams/1", + "html_url": "https://github.com/orgs/github/teams/justice-league", + "name": "Justice League", + "slug": "justice-league", + "description": "A great team.", + "privacy": "closed", + "notification_setting": "notifications_enabled", + "permission": "admin", + "members_url": "https://api.github.com/teams/1/members{/member}", + "repositories_url": "https://api.github.com/teams/1/repos", + "parent": null + } + ] +} diff --git a/Tests/OctoKitTests/PullRequestTests.swift b/Tests/OctoKitTests/PullRequestTests.swift index acac3f14..56fb8b29 100644 --- a/Tests/OctoKitTests/PullRequestTests.swift +++ b/Tests/OctoKitTests/PullRequestTests.swift @@ -370,7 +370,7 @@ class PullRequestTests: XCTestCase { func testListPullRequestsFiles() { let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/octocat/Hello-World/pulls/1347/files", expectedHTTPMethod: "GET", - jsonFile: "pull_requests_files", + jsonFile: "pull_request_files", statusCode: 200) let task = Octokit(session: session) @@ -405,7 +405,7 @@ class PullRequestTests: XCTestCase { func testListPullRequestsFilesAsync() async throws { let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/octocat/Hello-World/pulls/1347/files", expectedHTTPMethod: "GET", - jsonFile: "pull_requests_files", + jsonFile: "pull_request_files", statusCode: 200) let files = try await Octokit(session: session) @@ -429,4 +429,178 @@ class PullRequestTests: XCTestCase { XCTAssertTrue(session.wasCalled) } #endif + + func testReadPullRequestReviewComments() { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/octokat/Hello-World/pulls/1347/comments?", + expectedHTTPMethod: "GET", + jsonFile: "pull_request_comments", + statusCode: 200) + let task = Octokit(session: session).readPullRequestReviewComments(owner: "octokat", + repository: "Hello-World", + number: 1347) { response in + switch response { + case let .success(comments): + XCTAssertEqual(comments.count, 1) + let comment = comments.first + XCTAssertNotNil(comment) + XCTAssertEqual(comment?.body, "Great stuff!") + 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 testReadPullRequestReviewCommentsAsync() async throws { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/octokat/Hello-World/pulls/1347/comments?", + expectedHTTPMethod: "GET", + jsonFile: "pull_request_comments", + statusCode: 200) + let comments = try await Octokit(session: session).readPullRequestReviewComments(owner: "octokat", + repository: "Hello-World", + number: 1347) + XCTAssertEqual(comments.count, 1) + let comment = try XCTUnwrap(comments.first) + XCTAssertNotNil(comment) + XCTAssertEqual(comment.body, "Great stuff!") + XCTAssertTrue(session.wasCalled) + } + #endif + + func testCreatePullRequestReviewComment() { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/octokat/Hello-World/pulls/1347/comments", + expectedHTTPMethod: "POST", + jsonFile: "pull_request_comment", + statusCode: 200) + let task = Octokit(session: session).createPullRequestReviewComment(owner: "octokat", + repository: "Hello-World", + number: 1347, + commitId: "6dcb09b5b57875f334f61aebed695e2e4193db5e", + path: "file1.txt", + line: 2, + body: "Great stuff!") { response in + switch response { + case let .success(comment): + XCTAssertEqual(comment.body, "Great stuff!") + XCTAssertEqual(comment.commitId, "6dcb09b5b57875f334f61aebed695e2e4193db5e") + XCTAssertEqual(comment.line, 2) + XCTAssertEqual(comment.startLine, 1) + XCTAssertEqual(comment.side, .right) + XCTAssertNil(comment.subjectType) + XCTAssertEqual(comment.inReplyToId, 8) + 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 testCreatePullRequestReviewCommentAsync() async throws { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/octokat/Hello-World/pulls/1347/comments", + expectedHTTPMethod: "POST", + jsonFile: "pull_request_comment", + statusCode: 200) + let comment = try await Octokit(session: session).createPullRequestReviewComment(owner: "octokat", + repository: "Hello-World", + number: 1347, + commitId: "6dcb09b5b57875f334f61aebed695e2e4193db5e", + path: "file1.txt", + line: 2, + body: "Great stuff!") + XCTAssertEqual(comment.body, "Great stuff!") + XCTAssertEqual(comment.commitId, "6dcb09b5b57875f334f61aebed695e2e4193db5e") + XCTAssertEqual(comment.line, 2) + XCTAssertEqual(comment.startLine, 1) + XCTAssertEqual(comment.side, .right) + XCTAssertNil(comment.subjectType) + XCTAssertEqual(comment.inReplyToId, 8) + XCTAssertTrue(session.wasCalled) + } + #endif + + func testCreatePullRequestRegularComment() { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/octokat/Hello-World/issues/1347/comments", + expectedHTTPMethod: "POST", + jsonFile: "pull_request_comment", + statusCode: 200) + let task = Octokit(session: session).createPullRequestReviewComment(owner: "octokat", + repository: "Hello-World", + number: 1347, + body: "Great stuff!") { response in + switch response { + case let .success(comment): + XCTAssertEqual(comment.body, "Great stuff!") + 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 testCreatePullRequestRegularCommentAsync() async throws { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/octokat/Hello-World/issues/1347/comments", + expectedHTTPMethod: "POST", + jsonFile: "pull_request_comment", + statusCode: 200) + let comment = try await Octokit(session: session).createPullRequestReviewComment(owner: "octokat", + repository: "Hello-World", + number: 1347, + body: "Great stuff!") + XCTAssertEqual(comment.body, "Great stuff!") + XCTAssertTrue(session.wasCalled) + } + #endif + + func testReadPullRequestRequestedReviewers() { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/octokat/Hello-World/pulls/1347/requested_reviewers?", + expectedHTTPMethod: "GET", + jsonFile: "pull_request_requested_reviewers", + statusCode: 200) + let task = Octokit(session: session).readPullRequestRequestedReviewers(owner: "octokat", + repository: "Hello-World", + number: 1347) { response in + switch response { + case let .success(requestedReviewers): + XCTAssertEqual(requestedReviewers.users.count, 1) + XCTAssertEqual(requestedReviewers.users.first?.login, "octocat") + XCTAssertEqual(requestedReviewers.teams.count, 1) + XCTAssertEqual(requestedReviewers.teams.first?.name, "Justice League") + 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 testReadPullRequestRequestedReviewersAsync() async throws { + let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/repos/octokat/Hello-World/pulls/1347/requested_reviewers?", + expectedHTTPMethod: "GET", + jsonFile: "pull_request_requested_reviewers", + statusCode: 200) + let requestedReviewers = try await Octokit(session: session).readPullRequestRequestedReviewers(owner: "octokat", + repository: "Hello-World", + number: 1347) + XCTAssertEqual(requestedReviewers.users.count, 1) + let user = try XCTUnwrap(requestedReviewers.users.first) + XCTAssertEqual(user.login, "octocat") + XCTAssertEqual(requestedReviewers.teams.count, 1) + let team = try XCTUnwrap(requestedReviewers.teams.first) + XCTAssertEqual(team.name, "Justice League") + XCTAssertTrue(session.wasCalled) + } + #endif } From e7106a0502da3d60751eef22912143df9f40559b Mon Sep 17 00:00:00 2001 From: Jeroen Wesbeek Date: Fri, 6 Dec 2024 11:14:40 +0100 Subject: [PATCH 2/2] Team.swift was missing in the xcodeproj --- OctoKit.xcodeproj/project.pbxproj | 70 ++++++++++++++++++------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/OctoKit.xcodeproj/project.pbxproj b/OctoKit.xcodeproj/project.pbxproj index db59f7ac..f32e63cf 100644 --- a/OctoKit.xcodeproj/project.pbxproj +++ b/OctoKit.xcodeproj/project.pbxproj @@ -255,6 +255,10 @@ E7EE59DA1BE10DA60012E3D2 /* StarsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7EE59D91BE10DA60012E3D2 /* StarsTests.swift */; }; E7EE59DC1BE119110012E3D2 /* Follow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7EE59DB1BE119110012E3D2 /* Follow.swift */; }; E7EE59DE1BE11C2A0012E3D2 /* FollowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7EE59DD1BE11C2A0012E3D2 /* FollowTests.swift */; }; + F330CBC72D0305CC001D2BA9 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = F330CBC62D0305CC001D2BA9 /* Team.swift */; }; + F330CBC82D0305CC001D2BA9 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = F330CBC62D0305CC001D2BA9 /* Team.swift */; }; + F330CBC92D0305CC001D2BA9 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = F330CBC62D0305CC001D2BA9 /* Team.swift */; }; + F330CBCA2D0305CC001D2BA9 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = F330CBC62D0305CC001D2BA9 /* Team.swift */; }; F8711EA21BFCAE9F005DDACA /* Time.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8711EA11BFCAE9F005DDACA /* Time.swift */; }; /* End PBXBuildFile section */ @@ -370,6 +374,7 @@ E7EE59D91BE10DA60012E3D2 /* StarsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarsTests.swift; sourceTree = ""; }; E7EE59DB1BE119110012E3D2 /* Follow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Follow.swift; sourceTree = ""; }; E7EE59DD1BE11C2A0012E3D2 /* FollowTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FollowTests.swift; sourceTree = ""; }; + F330CBC62D0305CC001D2BA9 /* Team.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Team.swift; sourceTree = ""; }; F8711EA11BFCAE9F005DDACA /* Time.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Time.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -436,27 +441,27 @@ 234F4BAA1BDDE31A00A58EF7 /* OctoKitTests */ = { isa = PBXGroup; children = ( - 234F4BD71BDDE40400A58EF7 /* Fixtures */, + 234F4BAD1BDDE31A00A58EF7 /* Info.plist */, 234F4BC91BDDE3F900A58EF7 /* ConfigurationTests.swift */, E7EE59DD1BE11C2A0012E3D2 /* FollowTests.swift */, 515337F022529C380024544D /* GistTests.swift */, E7EDEA6B1C871D01006BAAF2 /* IssueTests.swift */, D4D28F6B2299D87300F8E92A /* LabelTests.swift */, 234F4BCB1BDDE3F900A58EF7 /* OctokitSwiftTests.swift */, - 234F4BCC1BDDE3F900A58EF7 /* PublicKeyTests.swift */, - 234F4BCD1BDDE3F900A58EF7 /* RepositoryTests.swift */, - E7EE59D91BE10DA60012E3D2 /* StarsTests.swift */, - 234F4BCE1BDDE3F900A58EF7 /* TestHelper.swift */, - 234F4BCF1BDDE3F900A58EF7 /* UserTests.swift */, 23A0521E1CA924950068BFF7 /* OctoKitURLTestSession.swift */, - 234F4BAD1BDDE31A00A58EF7 /* Info.plist */, - BF8C76EB002802C14A08F63E /* PullRequestTests.swift */, - 5090ED7523E48EE60062C763 /* ReleasesTests.swift */, - 9D9ADDDE23EEFD4A000AC34D /* ReviewTests.swift */, D1EAE84C25038A910023806C /* PlanTests.swift */, 23EA618125EAE2FA001B0964 /* PreviewHeaderTests.swift */, + 234F4BCC1BDDE3F900A58EF7 /* PublicKeyTests.swift */, + BF8C76EB002802C14A08F63E /* PullRequestTests.swift */, 23EA618325EAE2FA001B0964 /* ReactionsTests.swift */, + 5090ED7523E48EE60062C763 /* ReleasesTests.swift */, + 234F4BCD1BDDE3F900A58EF7 /* RepositoryTests.swift */, + 9D9ADDDE23EEFD4A000AC34D /* ReviewTests.swift */, + E7EE59D91BE10DA60012E3D2 /* StarsTests.swift */, 23EA618225EAE2FA001B0964 /* StatusesTests.swift */, + 234F4BCE1BDDE3F900A58EF7 /* TestHelper.swift */, + 234F4BCF1BDDE3F900A58EF7 /* UserTests.swift */, + 234F4BD71BDDE40400A58EF7 /* Fixtures */, ); name = OctoKitTests; path = Tests/OctoKitTests; @@ -465,34 +470,34 @@ 234F4BD71BDDE40400A58EF7 /* Fixtures */ = { isa = PBXGroup; children = ( - 721F73E829889A040064B11A /* latest_release.json */, - 03CCD2512453A9AA007D5CB3 /* users.json */, + C1B2EE912A0C0090001CF2FA /* created_pull_request.json */, 84B89D022C814DE400273C68 /* forked_repo.json */, 515337F92252A0410024544D /* gist.json */, 515337F522529E7B0024544D /* gists.json */, 5090ED7123E483820062C763 /* issue_comment.json */, + 23EA619B25EAE31A001B0964 /* issue_comments.json */, DABBDE4F1C8C0C20008F57CD /* issue.json */, 515337A8224FC3760024544D /* issue2.json */, E7EDEA6D1C871D0E006BAAF2 /* issues.json */, D4D28F732299DCE700F8E92A /* label.json */, D4D28F6F2299DBE600F8E92A /* labels.json */, + 721F73E829889A040064B11A /* latest_release.json */, + 23EA619D25EAE31A001B0964 /* plan.json */, 5090ED7723E48FBC0062C763 /* post_release.json */, 234F4BD81BDDE44600A58EF7 /* public_key.json */, - 234F4BD91BDDE44600A58EF7 /* repo.json */, - 665D5D5F24A639D70045E3B4 /* status.json */, - 665D5D5E24A639D70045E3B4 /* statuses.json */, - 234F4BDA1BDDE44600A58EF7 /* user_me.json */, - 234F4BDB1BDDE44600A58EF7 /* user_mietzmithut.json */, - 234F4BDC1BDDE44600A58EF7 /* user_repos.json */, - 23EA619B25EAE31A001B0964 /* issue_comments.json */, - 23EA619D25EAE31A001B0964 /* plan.json */, 23EA61A025EAE31A001B0964 /* pull_request.json */, 23EA61A125EAE31A001B0964 /* pull_requests.json */, - C1B2EE912A0C0090001CF2FA /* created_pull_request.json */, 23EA619C25EAE31A001B0964 /* reactions.json */, 23EA619F25EAE31A001B0964 /* releases.json */, + 234F4BD91BDDE44600A58EF7 /* repo.json */, 23EA619E25EAE31A001B0964 /* reviews.json */, + 665D5D5F24A639D70045E3B4 /* status.json */, + 665D5D5E24A639D70045E3B4 /* statuses.json */, 849DF0792D029AF400A202DF /* topics.json */, + 234F4BDA1BDDE44600A58EF7 /* user_me.json */, + 234F4BDB1BDDE44600A58EF7 /* user_mietzmithut.json */, + 234F4BDC1BDDE44600A58EF7 /* user_repos.json */, + 03CCD2512453A9AA007D5CB3 /* users.json */, ); name = Fixtures; sourceTree = ""; @@ -501,7 +506,6 @@ isa = PBXGroup; children = ( 239BE7CD1B8C47A100D2CE22 /* OctoKit.h */, - 84B89D002C814DBC00273C68 /* Organization.swift */, 23B267851BDDD756003887E3 /* Configuration.swift */, 515337C3225179FB0024544D /* File.swift */, E7EE59DB1BE119110012E3D2 /* Follow.swift */, @@ -510,22 +514,24 @@ DAEFC58F1C83D85100CF3785 /* Label.swift */, DAEFC5941C83EF0D00CF3785 /* Milestone.swift */, 23B267861BDDD756003887E3 /* Octokit.swift */, + 84B89D002C814DBC00273C68 /* Organization.swift */, + BF8C72B985869B84F46B4E9D /* Parameters.swift */, + D1EAE8472503886C0023806C /* Plan.swift */, + D1EAE8612503D33B0023806C /* PreviewHeader.swift */, 23B267871BDDD756003887E3 /* PublicKey.swift */, + BF8C73E0EF3CEEBDEA68DD5E /* PullRequest.swift */, + D1EAE86A2503D9280023806C /* Reactions.swift */, 5090ED7323E48AA80062C763 /* Releases.swift */, 23B267881BDDD756003887E3 /* Repositories.swift */, - 23B267891BDDD756003887E3 /* User.swift */, + 9D9ADDE023EEFDE0000AC34D /* Review.swift */, E7EE59D71BDFEFB30012E3D2 /* Stars.swift */, 665D5D5924A639960045E3B4 /* Statuses.swift */, + D4D28F772299E9F200F8E92A /* String+PercentEncoding.swift */, + F330CBC62D0305CC001D2BA9 /* Team.swift */, F8711EA11BFCAE9F005DDACA /* Time.swift */, 237F91E31E5AEC82005FAA6B /* URL+URLParameters.swift */, + 23B267891BDDD756003887E3 /* User.swift */, 239BE7CB1B8C47A100D2CE22 /* Supporting Files */, - BF8C73E0EF3CEEBDEA68DD5E /* PullRequest.swift */, - BF8C72B985869B84F46B4E9D /* Parameters.swift */, - 9D9ADDE023EEFDE0000AC34D /* Review.swift */, - D4D28F772299E9F200F8E92A /* String+PercentEncoding.swift */, - D1EAE8612503D33B0023806C /* PreviewHeader.swift */, - D1EAE86A2503D9280023806C /* Reactions.swift */, - D1EAE8472503886C0023806C /* Plan.swift */, ); path = OctoKit; sourceTree = ""; @@ -1003,6 +1009,7 @@ 84B89D012C814DBC00273C68 /* Organization.swift in Sources */, 515337C4225179FB0024544D /* File.swift in Sources */, 515337C2225166600024544D /* Gist.swift in Sources */, + F330CBC92D0305CC001D2BA9 /* Team.swift in Sources */, 23B2678C1BDDD756003887E3 /* PublicKey.swift in Sources */, 23B2678E1BDDD756003887E3 /* User.swift in Sources */, 237F91E41E5AEC82005FAA6B /* URL+URLParameters.swift in Sources */, @@ -1034,6 +1041,7 @@ 84B89D0A2C81587100273C68 /* Organization.swift in Sources */, 23CAF2B71C7AB6EB005011C4 /* Time.swift in Sources */, 23CAF2B41C7AB6D4005011C4 /* Stars.swift in Sources */, + F330CBCA2D0305CC001D2BA9 /* Team.swift in Sources */, 23CAF2AB1C7AB6C9005011C4 /* PublicKey.swift in Sources */, D1EAE86C2503D9280023806C /* Reactions.swift in Sources */, 237F91E51E5AEC87005FAA6B /* URL+URLParameters.swift in Sources */, @@ -1091,6 +1099,7 @@ 84B89D0B2C81587100273C68 /* Organization.swift in Sources */, 23CAF2B81C7AB6EB005011C4 /* Time.swift in Sources */, 23CAF2B51C7AB6D5005011C4 /* Stars.swift in Sources */, + F330CBC72D0305CC001D2BA9 /* Team.swift in Sources */, 23CAF2AC1C7AB6CA005011C4 /* PublicKey.swift in Sources */, D1EAE86D2503D9280023806C /* Reactions.swift in Sources */, 237F91E61E5AEC88005FAA6B /* URL+URLParameters.swift in Sources */, @@ -1148,6 +1157,7 @@ 84B89D0C2C81587200273C68 /* Organization.swift in Sources */, 23CAF2B91C7AB6EC005011C4 /* Time.swift in Sources */, 23CAF2B61C7AB6D5005011C4 /* Stars.swift in Sources */, + F330CBC82D0305CC001D2BA9 /* Team.swift in Sources */, 23CAF2AD1C7AB6CA005011C4 /* PublicKey.swift in Sources */, D1EAE86E2503D9280023806C /* Reactions.swift in Sources */, 237F91E71E5AEC89005FAA6B /* URL+URLParameters.swift in Sources */,