Skip to content

Commit

Permalink
Add support for fetching requested reviewers (users and teams) for a …
Browse files Browse the repository at this point in the history
…Pull Request.
  • Loading branch information
4np committed Dec 4, 2024
1 parent 8a3f2f1 commit bb224ee
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 30 deletions.
104 changes: 74 additions & 30 deletions OctoKit/PullRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -265,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))
}
}
}
Expand Down Expand Up @@ -320,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))
}
}
}
Expand Down Expand Up @@ -371,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))
}
}
}
Expand Down Expand Up @@ -433,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))
}
}
}
Expand Down Expand Up @@ -481,10 +473,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))
}
}
}
Expand Down Expand Up @@ -520,10 +510,8 @@ public extension Octokit {
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 = comments {
completion(.success(comments))
}
} else if let comments {
completion(.success(comments))
}
}
}
Expand Down Expand Up @@ -572,10 +560,8 @@ public extension Octokit {
return router.post(session, decoder: decoder, expectedResultType: PullRequest.Comment.self) { issue, error in
if let error = error {
completion(.failure(error))
} else {
if let issue = issue {
completion(.success(issue))
}
} else if let issue {
completion(.success(issue))
}
}
}
Expand Down Expand Up @@ -643,6 +629,57 @@ public extension Octokit {
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<PullRequest.RequestedReviewers, Error>) -> 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
Expand All @@ -655,6 +692,7 @@ enum PullRequestRouter: JSONPostRouter {
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 {
Expand All @@ -664,7 +702,8 @@ enum PullRequestRouter: JSONPostRouter {
case .readPullRequest,
.readPullRequests,
.listPullRequestsFiles,
.readPullRequestReviewComments:
.readPullRequestReviewComments,
.readPullRequestRequestedReviewers:
return .GET
case .patchPullRequest:
return .PATCH
Expand All @@ -691,6 +730,7 @@ enum PullRequestRouter: JSONPostRouter {
case let .listPullRequestsFiles(config, _, _, _, _, _): return config
case let .readPullRequestReviewComments(config, _, _, _, _, _): return config
case let .createPullRequestReviewComment(config, _, _, _, _, _, _, _): return config
case let .readPullRequestRequestedReviewers(config, _, _, _, _, _): return config
}
}

Expand Down Expand Up @@ -756,7 +796,8 @@ enum PullRequestRouter: JSONPostRouter {
}
return parameters
case let .listPullRequestsFiles(_, _, _, _, perPage, page),
let .readPullRequestReviewComments(_, _, _, _, page, perPage):
let .readPullRequestReviewComments(_, _, _, _, page, perPage),
let .readPullRequestRequestedReviewers(_, _, _, _, page, perPage):
var parameters: [String: Any] = [:]
if let perPage {
parameters["per_page"] = perPage
Expand Down Expand Up @@ -793,6 +834,9 @@ enum PullRequestRouter: JSONPostRouter {
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"
}
}
}
83 changes: 83 additions & 0 deletions OctoKit/Team.swift
Original file line number Diff line number Diff line change
@@ -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"
}
}
41 changes: 41 additions & 0 deletions Tests/OctoKitTests/Fixtures/pull_request_requested_reviewers.json
Original file line number Diff line number Diff line change
@@ -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
}
]
}
44 changes: 44 additions & 0 deletions Tests/OctoKitTests/PullRequestTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -567,4 +567,48 @@ class PullRequestTests: XCTestCase {
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
}

0 comments on commit bb224ee

Please sign in to comment.