Skip to content

Commit

Permalink
Merge pull request nerdishbynature#80 from robmathers/label-endpoints
Browse files Browse the repository at this point in the history
Add methods to get and create labels
  • Loading branch information
pietbrauer authored May 26, 2019
2 parents 29fd7f4 + 0273467 commit 018bad3
Show file tree
Hide file tree
Showing 6 changed files with 348 additions and 0 deletions.
34 changes: 34 additions & 0 deletions OctoKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,19 @@
BF8C7BE0F4071324EBDCA204 /* PullRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8C73E0EF3CEEBDEA68DD5E /* PullRequest.swift */; };
BF8C7DEE90DD25CBCA4AEE71 /* Parameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8C72B985869B84F46B4E9D /* Parameters.swift */; };
BF8C7FFFDDAFA560EBEC35EE /* PullRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8C73E0EF3CEEBDEA68DD5E /* PullRequest.swift */; };
D4D28F6C2299D87300F8E92A /* LabelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D28F6B2299D87300F8E92A /* LabelTests.swift */; };
D4D28F6D2299D87A00F8E92A /* LabelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D28F6B2299D87300F8E92A /* LabelTests.swift */; };
D4D28F6E2299D87A00F8E92A /* LabelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D28F6B2299D87300F8E92A /* LabelTests.swift */; };
D4D28F702299DBE600F8E92A /* labels.json in Resources */ = {isa = PBXBuildFile; fileRef = D4D28F6F2299DBE600F8E92A /* labels.json */; };
D4D28F712299DBE600F8E92A /* labels.json in Resources */ = {isa = PBXBuildFile; fileRef = D4D28F6F2299DBE600F8E92A /* labels.json */; };
D4D28F722299DBE600F8E92A /* labels.json in Resources */ = {isa = PBXBuildFile; fileRef = D4D28F6F2299DBE600F8E92A /* labels.json */; };
D4D28F742299DCE700F8E92A /* label.json in Resources */ = {isa = PBXBuildFile; fileRef = D4D28F732299DCE700F8E92A /* label.json */; };
D4D28F752299DCE700F8E92A /* label.json in Resources */ = {isa = PBXBuildFile; fileRef = D4D28F732299DCE700F8E92A /* label.json */; };
D4D28F762299DCE700F8E92A /* label.json in Resources */ = {isa = PBXBuildFile; fileRef = D4D28F732299DCE700F8E92A /* label.json */; };
D4D28F782299E9F200F8E92A /* String+PercentEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D28F772299E9F200F8E92A /* String+PercentEncoding.swift */; };
D4D28FA0229A02A900F8E92A /* String+PercentEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D28F772299E9F200F8E92A /* String+PercentEncoding.swift */; };
D4D28FA1229A02A900F8E92A /* String+PercentEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D28F772299E9F200F8E92A /* String+PercentEncoding.swift */; };
D4D28FA2229A02AA00F8E92A /* String+PercentEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D28F772299E9F200F8E92A /* String+PercentEncoding.swift */; };
DABBDE501C8C0C20008F57CD /* issue.json in Resources */ = {isa = PBXBuildFile; fileRef = DABBDE4F1C8C0C20008F57CD /* issue.json */; };
DABBDE511C8C0C20008F57CD /* issue.json in Resources */ = {isa = PBXBuildFile; fileRef = DABBDE4F1C8C0C20008F57CD /* issue.json */; };
DABBDE521C8C0C20008F57CD /* issue.json in Resources */ = {isa = PBXBuildFile; fileRef = DABBDE4F1C8C0C20008F57CD /* issue.json */; };
Expand Down Expand Up @@ -269,6 +282,10 @@
BF8C76EB002802C14A08F63E /* PullRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PullRequestTests.swift; sourceTree = "<group>"; };
BF8C77314F563A710F11E2F6 /* pull_request.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = pull_request.json; sourceTree = "<group>"; };
BF8C79B71035B425F7748392 /* pull_requests.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = pull_requests.json; sourceTree = "<group>"; };
D4D28F6B2299D87300F8E92A /* LabelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelTests.swift; sourceTree = "<group>"; };
D4D28F6F2299DBE600F8E92A /* labels.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = labels.json; path = Fixtures/labels.json; sourceTree = "<group>"; };
D4D28F732299DCE700F8E92A /* label.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = label.json; path = Fixtures/label.json; sourceTree = "<group>"; };
D4D28F772299E9F200F8E92A /* String+PercentEncoding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+PercentEncoding.swift"; sourceTree = "<group>"; };
DABBDE4F1C8C0C20008F57CD /* issue.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = issue.json; path = Fixtures/issue.json; sourceTree = "<group>"; };
DAEFC58F1C83D85100CF3785 /* Label.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; };
DAEFC5941C83EF0D00CF3785 /* Milestone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Milestone.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -351,6 +368,7 @@
E7EE59DD1BE11C2A0012E3D2 /* FollowTests.swift */,
515337F022529C380024544D /* GistTests.swift */,
E7EDEA6B1C871D01006BAAF2 /* IssueTests.swift */,
D4D28F6B2299D87300F8E92A /* LabelTests.swift */,
234F4BCB1BDDE3F900A58EF7 /* OctokitSwiftTests.swift */,
234F4BCC1BDDE3F900A58EF7 /* PublicKeyTests.swift */,
234F4BCD1BDDE3F900A58EF7 /* RepositoryTests.swift */,
Expand All @@ -373,6 +391,8 @@
DABBDE4F1C8C0C20008F57CD /* issue.json */,
515337A8224FC3760024544D /* issue2.json */,
E7EDEA6D1C871D0E006BAAF2 /* issues.json */,
D4D28F732299DCE700F8E92A /* label.json */,
D4D28F6F2299DBE600F8E92A /* labels.json */,
234F4BD81BDDE44600A58EF7 /* public_key.json */,
234F4BD91BDDE44600A58EF7 /* repo.json */,
234F4BDA1BDDE44600A58EF7 /* user_me.json */,
Expand Down Expand Up @@ -406,6 +426,7 @@
239BE7CB1B8C47A100D2CE22 /* Supporting Files */,
BF8C73E0EF3CEEBDEA68DD5E /* PullRequest.swift */,
BF8C72B985869B84F46B4E9D /* Parameters.swift */,
D4D28F772299E9F200F8E92A /* String+PercentEncoding.swift */,
);
path = OctoKit;
sourceTree = "<group>";
Expand Down Expand Up @@ -698,6 +719,7 @@
files = (
E7EE59E01BE139FD0012E3D2 /* users.json in Resources */,
515337A9224FC3760024544D /* issue2.json in Resources */,
D4D28F742299DCE700F8E92A /* label.json in Resources */,
234F4BDF1BDDE44600A58EF7 /* user_me.json in Resources */,
234F4BDD1BDDE44600A58EF7 /* public_key.json in Resources */,
DABBDE501C8C0C20008F57CD /* issue.json in Resources */,
Expand All @@ -706,6 +728,7 @@
234F4BE01BDDE44600A58EF7 /* user_mietzmithut.json in Resources */,
515337F622529E7B0024544D /* gists.json in Resources */,
515337FA2252A0410024544D /* gist.json in Resources */,
D4D28F702299DBE600F8E92A /* labels.json in Resources */,
E7EDEA6E1C871D0E006BAAF2 /* issues.json in Resources */,
BF8C78845606511558E7B929 /* pull_requests.json in Resources */,
BF8C7B976A0652C486FAF736 /* pull_request.json in Resources */,
Expand All @@ -732,6 +755,7 @@
files = (
23F643501C7AEF72000427B3 /* users.json in Resources */,
515337AA224FC3760024544D /* issue2.json in Resources */,
D4D28F752299DCE700F8E92A /* label.json in Resources */,
23F6434A1C7AEF69000427B3 /* user_me.json in Resources */,
23F643461C7AEF63000427B3 /* public_key.json in Resources */,
DABBDE511C8C0C20008F57CD /* issue.json in Resources */,
Expand All @@ -740,6 +764,7 @@
23F6434C1C7AEF6C000427B3 /* user_mietzmithut.json in Resources */,
515337F722529E7B0024544D /* gists.json in Resources */,
515337FB2252A0410024544D /* gist.json in Resources */,
D4D28F712299DBE600F8E92A /* labels.json in Resources */,
E7EDEA741C871FA8006BAAF2 /* issues.json in Resources */,
BF8C7923F427B3CFC6833337 /* pull_requests.json in Resources */,
BF8C7A686709462323C702D8 /* pull_request.json in Resources */,
Expand All @@ -759,6 +784,7 @@
files = (
23F643511C7AEF73000427B3 /* users.json in Resources */,
515337AB224FC3760024544D /* issue2.json in Resources */,
D4D28F762299DCE700F8E92A /* label.json in Resources */,
23F6434B1C7AEF6A000427B3 /* user_me.json in Resources */,
23F643471C7AEF63000427B3 /* public_key.json in Resources */,
DABBDE521C8C0C20008F57CD /* issue.json in Resources */,
Expand All @@ -767,6 +793,7 @@
23F6434D1C7AEF6D000427B3 /* user_mietzmithut.json in Resources */,
515337F822529E7B0024544D /* gists.json in Resources */,
515337FC2252A0410024544D /* gist.json in Resources */,
D4D28F722299DBE600F8E92A /* labels.json in Resources */,
E7EDEA751C871FA9006BAAF2 /* issues.json in Resources */,
BF8C711C2C6B42F9F323FCFE /* pull_requests.json in Resources */,
BF8C716EB8D5CA2CBBA745CB /* pull_request.json in Resources */,
Expand All @@ -788,6 +815,7 @@
buildActionMask = 2147483647;
files = (
234F4BD61BDDE3F900A58EF7 /* UserTests.swift in Sources */,
D4D28F6C2299D87300F8E92A /* LabelTests.swift in Sources */,
234F4BD31BDDE3F900A58EF7 /* PublicKeyTests.swift in Sources */,
E7EDEA6C1C871D01006BAAF2 /* IssueTests.swift in Sources */,
234F4BD41BDDE3F900A58EF7 /* RepositoryTests.swift in Sources */,
Expand All @@ -808,6 +836,7 @@
files = (
E7EE59DC1BE119110012E3D2 /* Follow.swift in Sources */,
23B2678A1BDDD756003887E3 /* Configuration.swift in Sources */,
D4D28F782299E9F200F8E92A /* String+PercentEncoding.swift in Sources */,
E7EE59D81BDFEFB30012E3D2 /* Stars.swift in Sources */,
23B2678D1BDDD756003887E3 /* Repositories.swift in Sources */,
F8711EA21BFCAE9F005DDACA /* Time.swift in Sources */,
Expand All @@ -831,6 +860,7 @@
files = (
23CAF2A51C7AB6C2005011C4 /* Follow.swift in Sources */,
23CAF2AE1C7AB6CD005011C4 /* Repositories.swift in Sources */,
D4D28FA0229A02A900F8E92A /* String+PercentEncoding.swift in Sources */,
23CAF2B11C7AB6D1005011C4 /* User.swift in Sources */,
23CAF2A21C7AB6BE005011C4 /* Configuration.swift in Sources */,
23CAF2B71C7AB6EB005011C4 /* Time.swift in Sources */,
Expand All @@ -853,6 +883,7 @@
buildActionMask = 2147483647;
files = (
23CAF2BC1C7AB6FC005011C4 /* FollowTests.swift in Sources */,
D4D28F6D2299D87A00F8E92A /* LabelTests.swift in Sources */,
23CAF2C41C7AB708005011C4 /* StarsTests.swift in Sources */,
E7EDEA721C871F94006BAAF2 /* IssueTests.swift in Sources */,
23CAF2C61C7AB70B005011C4 /* TestHelper.swift in Sources */,
Expand All @@ -873,6 +904,7 @@
files = (
23CAF2A61C7AB6C2005011C4 /* Follow.swift in Sources */,
23CAF2AF1C7AB6CD005011C4 /* Repositories.swift in Sources */,
D4D28FA1229A02A900F8E92A /* String+PercentEncoding.swift in Sources */,
23CAF2B21C7AB6D1005011C4 /* User.swift in Sources */,
23CAF2A31C7AB6BF005011C4 /* Configuration.swift in Sources */,
23CAF2B81C7AB6EB005011C4 /* Time.swift in Sources */,
Expand All @@ -895,6 +927,7 @@
buildActionMask = 2147483647;
files = (
23CAF2BD1C7AB6FC005011C4 /* FollowTests.swift in Sources */,
D4D28F6E2299D87A00F8E92A /* LabelTests.swift in Sources */,
23CAF2C51C7AB709005011C4 /* StarsTests.swift in Sources */,
E7EDEA731C871F95006BAAF2 /* IssueTests.swift in Sources */,
23CAF2C71C7AB70C005011C4 /* TestHelper.swift in Sources */,
Expand All @@ -915,6 +948,7 @@
files = (
23CAF2A71C7AB6C3005011C4 /* Follow.swift in Sources */,
23CAF2B01C7AB6CE005011C4 /* Repositories.swift in Sources */,
D4D28FA2229A02AA00F8E92A /* String+PercentEncoding.swift in Sources */,
23CAF2B31C7AB6D2005011C4 /* User.swift in Sources */,
23CAF2A41C7AB6BF005011C4 /* Configuration.swift in Sources */,
23CAF2B91C7AB6EC005011C4 /* Time.swift in Sources */,
Expand Down
127 changes: 127 additions & 0 deletions OctoKit/Label.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,134 @@
import Foundation
import RequestKit

open class Label: Codable {
open var url: URL?
open var name: String?
open var color: String?
}

// MARK: request

public extension Octokit {
/**
Fetches a single label 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 name: The name of the label.
- parameter completion: Callback for the outcome of the fetch.
*/
@discardableResult
func label(_ session: RequestKitURLSession = URLSession.shared, owner: String, repository: String, name: String, completion: @escaping (_ response: Response<Label>) -> Void) -> URLSessionDataTaskProtocol? {
let router = LabelRouter.readLabel(configuration, owner, repository, name)
return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: Label.self) { label, error in
if let error = error {
completion(Response.failure(error))
} else {
if let label = label {
completion(Response.success(label))
}
}
}
}

/**
Fetches all labels 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 page: Current page for label pagination. `1` by default.
- parameter perPage: Number of labels per page. `100` by default.
- parameter completion: Callback for the outcome of the fetch.
*/
@discardableResult
func labels(_ session: RequestKitURLSession = URLSession.shared, owner: String, repository: String, page: String = "1", perPage: String = "100", completion: @escaping (_ response: Response<[Label]>) -> Void) -> URLSessionDataTaskProtocol? {
let router = LabelRouter.readLabels(configuration, owner, repository, page, perPage)
return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: [Label].self) { labels, error in
if let error = error {
completion(Response.failure(error))
} else {
if let labels = labels {
completion(Response.success(labels))
}
}
}
}

/**
Create a label 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 name: The name of the label.
- parameter color: The color of the label, in hexadecimal without the leading `#`.
- parameter completion: Callback for the outcome of the request.
*/
@discardableResult
func postLabel(_ session: RequestKitURLSession = URLSession.shared, owner: String, repository: String, name: String, color: String, completion: @escaping (_ response: Response<Label>) -> Void) -> URLSessionDataTaskProtocol? {
let router = LabelRouter.createLabel(configuration, owner, repository, name, color)
return router.post(session, expectedResultType: Label.self) { label, error in
if let error = error {
completion(Response.failure(error))
} else {
if let label = label {
completion(Response.success(label))
}
}
}
}
}

enum LabelRouter: JSONPostRouter {
case readLabel(Configuration, String, String, String)
case readLabels(Configuration, String, String, String, String)
case createLabel(Configuration, String, String, String, String)

var method: HTTPMethod {
switch self {
case .createLabel:
return .POST
default:
return .GET
}
}

var encoding: HTTPEncoding {
switch self {
case .createLabel:
return .json
default:
return .url
}
}

var configuration: Configuration {
switch self {
case .readLabel(let config, _, _, _): return config
case .readLabels(let config, _, _, _, _): return config
case .createLabel(let config, _, _, _, _): return config
}
}

var params: [String : Any] {
switch self {
case .readLabel: return [:]
case .readLabels(_, _, _, let page, let perPage):
return ["per_page": perPage, "page": page]
case .createLabel(_, _, _, let name, let color):
return ["name": name, "color": color]
}
}

var path: String {
switch self {
case .readLabel(_, let owner, let repository, let name):
let name = name.stringByAddingPercentEncodingForRFC3986() ?? name
return "/repos/\(owner)/\(repository)/labels/\(name)"
case .readLabels(_, let owner, let repository, _, _):
return "/repos/\(owner)/\(repository)/labels"
case .createLabel(_, let owner, let repository, _, _):
return "/repos/\(owner)/\(repository)/labels"
}
}
}
14 changes: 14 additions & 0 deletions OctoKit/String+PercentEncoding.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Foundation

extension String {
/// Percent-encodes a string to be URL-safe
///
/// See https://useyourloaf.com/blog/how-to-percent-encode-a-url-string/ for more info
/// - returns: An optional string, with percent encoding to match RFC3986
func stringByAddingPercentEncodingForRFC3986() -> String? {
let unreserved = "-._~/?"
var allowed = CharacterSet.alphanumerics
allowed.insert(charactersIn: unreserved)
return addingPercentEncoding(withAllowedCharacters: allowed)
}
}
8 changes: 8 additions & 0 deletions Tests/OctoKitTests/Fixtures/label.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"id": 107942188,
"node_id": "MDU6TGFiZWwxMDc5NDIxODg=",
"url": "https://api.github.com/repos/octocat/hello-worId/labels/bug",
"name": "bug",
"color": "fc2929",
"default": true
}
58 changes: 58 additions & 0 deletions Tests/OctoKitTests/Fixtures/labels.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
[
{
"id": 107942188,
"node_id": "MDU6TGFiZWwxMDc5NDIxODg=",
"url": "https://api.github.com/repos/octocat/hello-worId/labels/bug",
"name": "bug",
"color": "fc2929",
"default": true
},
{
"id": 107942189,
"node_id": "MDU6TGFiZWwxMDc5NDIxODk=",
"url": "https://api.github.com/repos/octocat/hello-worId/labels/duplicate",
"name": "duplicate",
"color": "cccccc",
"default": true
},
{
"id": 107942190,
"node_id": "MDU6TGFiZWwxMDc5NDIxOTA=",
"url": "https://api.github.com/repos/octocat/hello-worId/labels/enhancement",
"name": "enhancement",
"color": "84b6eb",
"default": true
},
{
"id": 107942191,
"node_id": "MDU6TGFiZWwxMDc5NDIxOTE=",
"url": "https://api.github.com/repos/octocat/hello-worId/labels/help%20wanted",
"name": "help wanted",
"color": "159818",
"default": true
},
{
"id": 107942192,
"node_id": "MDU6TGFiZWwxMDc5NDIxOTI=",
"url": "https://api.github.com/repos/octocat/hello-worId/labels/invalid",
"name": "invalid",
"color": "e6e6e6",
"default": true
},
{
"id": 107942193,
"node_id": "MDU6TGFiZWwxMDc5NDIxOTM=",
"url": "https://api.github.com/repos/octocat/hello-worId/labels/question",
"name": "question",
"color": "cc317c",
"default": true
},
{
"id": 107942194,
"node_id": "MDU6TGFiZWwxMDc5NDIxOTQ=",
"url": "https://api.github.com/repos/octocat/hello-worId/labels/wontfix",
"name": "wontfix",
"color": "ffffff",
"default": true
}
]
Loading

0 comments on commit 018bad3

Please sign in to comment.