diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..9f55b2c --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +3.0 diff --git a/Cartfile b/Cartfile index 172426c..d1915c3 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1 @@ -github "nerdishbynature/RequestKit" ~>1.1 +github "nerdishbynature/RequestKit" ~>2.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index 92cd484..490733e 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "nerdishbynature/RequestKit" "1.1.0" +github "nerdishbynature/RequestKit" "2.0.0" diff --git a/TanukiKit.podspec b/TanukiKit.podspec index 757a5f7..a19819e 100644 --- a/TanukiKit.podspec +++ b/TanukiKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "TanukiKit" - s.version = "0.3.1" + s.version = "0.4.0" s.summary = "A Swift API Client for GitLab CE/EE" s.description = <<-DESC You are looking at the A Swift API Client for GitLabe CE/EE. @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/nerdishbynature/tanukikit.git", :tag => s.version.to_s } s.social_media_url = "https://twitter.com/pietbrauer" s.module_name = "TanukiKit" - s.dependency "NBNRequestKit", "~> 1.1" + s.dependency "NBNRequestKit", "~> 2.0" s.requires_arc = true s.source_files = "TanukiKit/*.swift" s.ios.deployment_target = '8.0' diff --git a/TanukiKit.xcodeproj/project.pbxproj b/TanukiKit.xcodeproj/project.pbxproj index 322bb54..225b594 100644 --- a/TanukiKit.xcodeproj/project.pbxproj +++ b/TanukiKit.xcodeproj/project.pbxproj @@ -713,8 +713,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -744,7 +746,7 @@ PRODUCT_NAME = TanukiKit; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -764,8 +766,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -787,7 +791,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.nerdishbynature.TanukiKit; PRODUCT_NAME = TanukiKit; SDKROOT = iphoneos; - SWIFT_VERSION = 2.3; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -799,6 +804,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -819,6 +825,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -831,7 +838,6 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -848,7 +854,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.nerdishbynature.TanukiKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -865,7 +871,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.nerdishbynature.TanukiKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -873,6 +879,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -895,6 +902,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -917,6 +925,7 @@ 23A4CE211C7C6BF700261CFB /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -938,6 +947,7 @@ 23A4CE221C7C6BF700261CFB /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -993,7 +1003,7 @@ 23A4CE461C7C6C5600261CFB /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1016,7 +1026,7 @@ 23A4CE471C7C6C5600261CFB /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; diff --git a/TanukiKit/Configuration.swift b/TanukiKit/Configuration.swift index 09f8ee6..5241b95 100644 --- a/TanukiKit/Configuration.swift +++ b/TanukiKit/Configuration.swift @@ -48,21 +48,29 @@ public struct OAuthConfiguration: Configuration { self.redirectURI = redirectURI } - public func authenticate() -> NSURL? { - return OAuthRouter.Authorize(self, redirectURI).URLRequest?.URL + public func authenticate() -> URL? { + return OAuthRouter.authorize(self, redirectURI).URLRequest?.url } - public func authorize(session: RequestKitURLSession = NSURLSession.sharedSession(), code: String, completion: (config: TokenConfiguration) -> Void) { - let request = OAuthRouter.AccessToken(self, code, redirectURI).URLRequest + public func authorize(session: RequestKitURLSession = URLSession.shared, code: String, completion: @escaping (_ config: TokenConfiguration) -> Void) { + let request = OAuthRouter.accessToken(self, code, redirectURI).URLRequest if let request = request { - let task = session.dataTaskWithRequest(request) { data, response, err in - if let response = response as? NSHTTPURLResponse { + let task = session.dataTask(with: request) { data, response, err in + if let response = response as? HTTPURLResponse { if response.statusCode != 200 { return } else { - if let data = data, json = try? NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments), accessToken = json["access_token"] as? String { - let config = TokenConfiguration(accessToken, url: self.apiEndpoint) - completion(config: config) + guard let data = data else { + return + } + do { + let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] + if let json = json, let accessToken = json["access_token"] as? String { + let config = TokenConfiguration(accessToken, url: self.apiEndpoint) + completion(config) + } + } catch { + return } } } @@ -71,72 +79,71 @@ public struct OAuthConfiguration: Configuration { } } - public func handleOpenURL(session: RequestKitURLSession = NSURLSession.sharedSession(), url: NSURL, completion: (config: TokenConfiguration) -> Void) { - let absoluteString: String? = url.absoluteString - if let code = absoluteString?.componentsSeparatedByString("=").last { - authorize(session, code: code) { (config) in - completion(config: config) + public func handleOpenURL(_ session: RequestKitURLSession = URLSession.shared, url: URL, completion: @escaping (_ config: TokenConfiguration) -> Void) { + if let code = url.absoluteString.components(separatedBy: "=").last { + authorize(session: session, code: code) { (config) in + completion(config) } } } } enum OAuthRouter: Router { - case Authorize(OAuthConfiguration, String) - case AccessToken(OAuthConfiguration, String, String) + case authorize(OAuthConfiguration, String) + case accessToken(OAuthConfiguration, String, String) var configuration: Configuration { switch self { - case .Authorize(let config, _): return config - case .AccessToken(let config, _, _): return config + case .authorize(let config, _): return config + case .accessToken(let config, _, _): return config } } var method: HTTPMethod { switch self { - case .Authorize: + case .authorize: return .GET - case .AccessToken: + case .accessToken: return .POST } } var encoding: HTTPEncoding { switch self { - case .Authorize: - return .URL - case .AccessToken: - return .FORM + case .authorize: + return .url + case .accessToken: + return .form } } var path: String { switch self { - case .Authorize: + case .authorize: return "oauth/authorize" - case .AccessToken: + case .accessToken: return "oauth/token" } } - var params: [String: AnyObject] { + var params: [String: Any] { switch self { - case .Authorize(let config, let redirectURI): - return ["client_id": config.token, "response_type": "code", "redirect_uri": redirectURI] - case .AccessToken(let config, let code, let rediredtURI): - return ["client_id": config.token, "client_secret": config.secret, "code": code, "grant_type": "authorization_code", "redirect_uri": rediredtURI] + case .authorize(let config, let redirectURI): + return ["client_id": config.token as AnyObject, "response_type": "code" as AnyObject, "redirect_uri": redirectURI as AnyObject] + case .accessToken(let config, let code, let rediredtURI): + return ["client_id": config.token as AnyObject, "client_secret": config.secret as AnyObject, "code": code as AnyObject, "grant_type": "authorization_code" as AnyObject, "redirect_uri": rediredtURI as AnyObject] } } - var URLRequest: NSURLRequest? { + var URLRequest: Foundation.URLRequest? { switch self { - case .Authorize(let config, _): - let url = NSURL(string: path, relativeToURL: NSURL(string: config.webEndpoint)) - let components = NSURLComponents(URL: url!, resolvingAgainstBaseURL: true) + case .authorize(let config, _): + let url = URL(string: path, relativeTo: URL(string: config.webEndpoint)!) + let components = URLComponents(url: url!, resolvingAgainstBaseURL: true) return request(components!, parameters: params) - case .AccessToken(let config, _, _): - let url = NSURL(string: path, relativeToURL: NSURL(string: config.webEndpoint)) - let components = NSURLComponents(URL: url!, resolvingAgainstBaseURL: true) + case .accessToken(let config, _, _): + let url = URL(string: path, relativeTo: URL(string: config.webEndpoint)!) + let components = URLComponents(url: url!, resolvingAgainstBaseURL: true) return request(components!, parameters: params) } } diff --git a/TanukiKit/Keys.swift b/TanukiKit/Keys.swift index 9239564..00e203e 100644 --- a/TanukiKit/Keys.swift +++ b/TanukiKit/Keys.swift @@ -4,14 +4,14 @@ import RequestKit // MARK: request public extension TanukiKit { - public func postPublicKey(session: RequestKitURLSession = NSURLSession.sharedSession(), publicKey: String, title: String, completion: (response:Response) -> Void) { - let router = PublicKeyRouter.PostPublicKey(publicKey, title, configuration) - router.loadJSON(session, expectedResultType: [String: AnyObject].self) { json, error in + public func postPublicKey(_ session: RequestKitURLSession = URLSession.shared, publicKey: String, title: String, completion: @escaping (_ response:Response) -> Void) -> URLSessionDataTaskProtocol? { + let router = PublicKeyRouter.postPublicKey(publicKey, title, configuration) + return router.loadJSON(session, expectedResultType: [String: AnyObject].self) { json, error in if let error = error { - completion(response: Response.Failure(error)) + completion(Response.failure(error)) } else { if let _ = json { - completion(response: Response.Success(publicKey)) + completion(Response.success(publicKey)) } } } @@ -19,39 +19,39 @@ public extension TanukiKit { } enum PublicKeyRouter: Router { - case PostPublicKey(String, String, Configuration) + case postPublicKey(String, String, Configuration) var configuration: Configuration { switch self { - case .PostPublicKey(_, _, let config): return config + case .postPublicKey(_, _, let config): return config } } var method: HTTPMethod { switch self { - case .PostPublicKey: + case .postPublicKey: return .POST } } var encoding: HTTPEncoding { switch self { - case .PostPublicKey: - return .FORM + case .postPublicKey: + return .form } } var path: String { switch self { - case .PostPublicKey: + case .postPublicKey: return "user/keys" } } - var params: [String: AnyObject] { + var params: [String: Any] { switch self { - case .PostPublicKey(let publicKey, let title, _): - return ["title": title, "key": publicKey] + case .postPublicKey(let publicKey, let title, _): + return ["title": title as AnyObject, "key": publicKey as AnyObject] } } } diff --git a/TanukiKit/Repositories.swift b/TanukiKit/Repositories.swift index 9fac5f9..e2f207c 100644 --- a/TanukiKit/Repositories.swift +++ b/TanukiKit/Repositories.swift @@ -1,15 +1,15 @@ import Foundation import RequestKit -@objc public class Repository: NSObject { - public let id: Int - public let owner: User - public var name: String? - public var fullName: String? - public var isPrivate: Bool - public var repositoryDescription: String? - public var sshURL: String? - public var cloneURL: String? +@objc open class Repository: NSObject { + open let id: Int + open let owner: User + open var name: String? + open var fullName: String? + open var isPrivate: Bool + open var repositoryDescription: String? + open var sshURL: String? + open var cloneURL: String? public init(_ json: [String: AnyObject]) { owner = User(json["owner"] as? [String: AnyObject] ?? [:]) @@ -36,16 +36,16 @@ public extension TanukiKit { - parameter perPage: Number of repositories per page. `100` by default. - parameter completion: Callback for the outcome of the fetch. */ - public func repositories(session: RequestKitURLSession = NSURLSession.sharedSession(), page: String = "1", perPage: String = "100", completion: (response: Response<[Repository]>) -> Void) { - let router = RepositoryRouter.ReadAuthenticatedRepositories(configuration, page, perPage) - router.loadJSON(session, expectedResultType: [[String: AnyObject]].self) { json, error in + public func repositories(_ session: RequestKitURLSession = URLSession.shared, page: String = "1", perPage: String = "100", completion: @escaping (_ response: Response<[Repository]>) -> Void) -> URLSessionDataTaskProtocol? { + let router = RepositoryRouter.readAuthenticatedRepositories(configuration, page, perPage) + return router.loadJSON(session, expectedResultType: [[String: AnyObject]].self) { json, error in if let error = error { - completion(response: Response.Failure(error)) + completion(Response.failure(error)) } if let json = json { let repos = json.map { Repository($0) } - completion(response: Response.Success(repos)) + completion(Response.success(repos)) } } } @@ -54,11 +54,11 @@ public extension TanukiKit { // MARK: Router enum RepositoryRouter: Router { - case ReadAuthenticatedRepositories(Configuration, String, String) + case readAuthenticatedRepositories(Configuration, String, String) var configuration: Configuration { switch self { - case .ReadAuthenticatedRepositories(let config, _, _): return config + case .readAuthenticatedRepositories(let config, _, _): return config } } @@ -67,19 +67,19 @@ enum RepositoryRouter: Router { } var encoding: HTTPEncoding { - return .URL + return .url } - var params: [String: AnyObject] { + var params: [String: Any] { switch self { - case .ReadAuthenticatedRepositories(_, let page, let perPage): - return ["per_page": perPage, "page": page] + case .readAuthenticatedRepositories(_, let page, let perPage): + return ["per_page": perPage as AnyObject, "page": page as AnyObject] } } var path: String { switch self { - case .ReadAuthenticatedRepositories: + case .readAuthenticatedRepositories: return "/projects" } } diff --git a/TanukiKit/Time.swift b/TanukiKit/Time.swift index 5c8567a..11ec075 100644 --- a/TanukiKit/Time.swift +++ b/TanukiKit/Time.swift @@ -8,11 +8,11 @@ struct Time { - [https://developer.apple.com/library/mac/qa/qa1480/_index.html](https://developer.apple.com/library/mac/qa/qa1480/_index.html) - [https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html) */ - private static var rfc3339DateFormatter: NSDateFormatter = { - let formatter = NSDateFormatter() + private static var rfc3339DateFormatter: DateFormatter = { + let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" - formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") - formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0) + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) return formatter }() @@ -21,8 +21,8 @@ struct Time { - parameter string: The string representation of the date - returns: An `NSDate` with a successful parse, otherwise `nil` */ - static func rfc3339Date(string: String?) -> NSDate? { + static func rfc3339Date(string: String?) -> Date? { guard let string = string else { return nil } - return Time.rfc3339DateFormatter.dateFromString(string) + return Time.rfc3339DateFormatter.date(from: string) } -} \ No newline at end of file +} diff --git a/TanukiKit/User.swift b/TanukiKit/User.swift index a2a747b..545f992 100644 --- a/TanukiKit/User.swift +++ b/TanukiKit/User.swift @@ -2,63 +2,63 @@ import Foundation import RequestKit // MARK: model -@objc public class User: NSObject { - public var name: String? - public var login: String? - public let id: Int - public var state: String? - public var avatarURL: NSURL? - public var webURL: NSURL? - public var createdAt: NSDate? - public var isAdmin: Bool? - public var bio: String? - public var location: String? - public var skype: String? - public var linkedin: String? - public var twitter: String? - public var websiteURL: NSURL? - public var lastSignInAt: NSDate? - public var confirmedAt: NSDate? - public var email: String? - public var themeId: Int? - public var colorSchemeId: Int? - public var projectsLimit: Int? - public var currentSignInAt: NSDate? - public var canCreateGroup: Bool? - public var canCreateProject: Bool? - public var twoFactorEnabled: Bool? - public var external: Bool? - public var privateToken: String? +@objc open class User: NSObject { + open let id: Int + open var login: String? + open var state: String? + open var avatarURL: URL? + open var webURL: URL? + open var createdAt: Date? + open var isAdmin: Bool? + open var bio: String? + open var name: String? + open var location: String? + open var skype: String? + open var linkedin: String? + open var twitter: String? + open var websiteURL: URL? + open var lastSignInAt: Date? + open var confirmedAt: Date? + open var email: String? + open var themeId: Int? + open var colorSchemeId: Int? + open var projectsLimit: Int? + open var currentSignInAt: Date? + open var canCreateGroup: Bool? + open var canCreateProject: Bool? + open var twoFactorEnabled: Bool? + open var external: Bool? + open var privateToken: String? - public init(_ json: [String: AnyObject]) { + public init(_ json: [String: Any]) { if let id = json["id"] as? Int { name = json["name"] as? String login = json["username"] as? String self.id = id state = json["state"] as? String - if let urlString = json["avatar_url"] as? String, url = NSURL(string: urlString) { + if let urlString = json["avatar_url"] as? String, let url = URL(string: urlString) { avatarURL = url } - if let urlString = json["web_url"] as? String, url = NSURL(string: urlString) { + if let urlString = json["web_url"] as? String, let url = URL(string: urlString) { webURL = url } - createdAt = Time.rfc3339Date(json["created_at"] as? String) + createdAt = Time.rfc3339Date(string: json["created_at"] as? String) isAdmin = json["is_admin"] as? Bool bio = json["bio"] as? String location = json["location"] as? String skype = json["skype"] as? String linkedin = json["linkedin"] as? String twitter = json["twitter"] as? String - if let urlString = json["website_url"] as? String, url = NSURL(string: urlString) { + if let urlString = json["website_url"] as? String, let url = URL(string: urlString) { websiteURL = url } - lastSignInAt = Time.rfc3339Date(json["last_sign_in_at"] as? String) - confirmedAt = Time.rfc3339Date(json["confirmed_at"] as? String) + lastSignInAt = Time.rfc3339Date(string: json["last_sign_in_at"] as? String) + confirmedAt = Time.rfc3339Date(string: json["confirmed_at"] as? String) email = json["email"] as? String themeId = json["theme_id"] as? Int colorSchemeId = json["color_scheme_id"] as? Int projectsLimit = json["projects_limit"] as? Int - currentSignInAt = Time.rfc3339Date(json["current_sign_in_at"] as? String) + currentSignInAt = Time.rfc3339Date(string: json["current_sign_in_at"] as? String) canCreateGroup = json["can_create_group"] as? Bool canCreateProject = json["can_create_project"] as? Bool twoFactorEnabled = json["two_factor_enabled"] as? Bool @@ -78,15 +78,15 @@ public extension TanukiKit { Fetches the currently logged in user - parameter completion: Callback for the outcome of the fetch. */ - public func me(session: RequestKitURLSession = NSURLSession.sharedSession(), completion: (response: Response) -> Void) { - let router = UserRouter.ReadAuthenticatedUser(self.configuration) - router.loadJSON(session, expectedResultType: [String: AnyObject].self) { json, error in + public func me(_ session: RequestKitURLSession = URLSession.shared, completion: @escaping (_ response: Response) -> Void) -> URLSessionDataTaskProtocol? { + let router = UserRouter.readAuthenticatedUser(self.configuration) + return router.loadJSON(session, expectedResultType: [String: Any].self) { json, error in if let error = error { - completion(response: Response.Failure(error)) + completion(Response.failure(error)) } else { if let json = json { let parsedUser = User(json) - completion(response: Response.Success(parsedUser)) + completion(Response.success(parsedUser)) } } } @@ -96,11 +96,11 @@ public extension TanukiKit { // MARK: Router enum UserRouter: Router { - case ReadAuthenticatedUser(Configuration) + case readAuthenticatedUser(Configuration) var configuration: Configuration { switch self { - case .ReadAuthenticatedUser(let config): return config + case .readAuthenticatedUser(let config): return config } } @@ -109,17 +109,17 @@ enum UserRouter: Router { } var encoding: HTTPEncoding { - return .URL + return .url } var path: String { switch self { - case .ReadAuthenticatedUser: + case .readAuthenticatedUser: return "user" } } - var params: [String: AnyObject] { + var params: [String: Any] { return [:] } } diff --git a/TanukiKitTests/ConfigurationTests.swift b/TanukiKitTests/ConfigurationTests.swift index 0ea407c..beb169b 100644 --- a/TanukiKitTests/ConfigurationTests.swift +++ b/TanukiKitTests/ConfigurationTests.swift @@ -42,7 +42,7 @@ class ConfigurationTests: XCTestCase { let config = OAuthConfiguration(token: "12345", secret: "6789", redirectURI: "https://oauth.example.com/gitlab_oauth") let json = "{\"access_token\": \"017ec60f4a182\", \"token_type\": \"bearer\"}" let session = TanukiKitURLTestSession(expectedURL: "https://gitlab.com/oauth/token", expectedHTTPMethod: "POST", response: json, statusCode: 200) - let url = NSURL(string: "https://oauth.example.com/gitlab_oauth?code=dhfjgh23493")! + let url = URL(string: "https://oauth.example.com/gitlab_oauth?code=dhfjgh23493")! var token: TokenConfiguration? config.handleOpenURL(session, url: url) { resultingConfig in token = resultingConfig diff --git a/TanukiKitTests/KeysTests.swift b/TanukiKitTests/KeysTests.swift index df2f8f3..bd7f2bb 100644 --- a/TanukiKitTests/KeysTests.swift +++ b/TanukiKitTests/KeysTests.swift @@ -5,11 +5,11 @@ class PublicKeyTests: XCTestCase { func testPostPublicKey() { let config = PrivateTokenConfiguration("12345") let session = TanukiKitURLTestSession(expectedURL: "https://gitlab.com/api/v3/user/keys", expectedHTTPMethod: "POST", jsonFile: "public_key", statusCode: 201) - TanukiKit(config).postPublicKey(session, publicKey: "test-key", title: "test title") { response in + _ = TanukiKit(config).postPublicKey(session, publicKey: "test-key", title: "test title") { response in switch response { - case .Success(let publicKey): + case .success(let publicKey): XCTAssertEqual(publicKey, "test-key") - case .Failure: + case .failure: XCTAssert(false, "should not get an error") } } @@ -19,11 +19,11 @@ class PublicKeyTests: XCTestCase { func testFailToPostPublicKey() { let config = PrivateTokenConfiguration("12345") let session = TanukiKitURLTestSession(expectedURL: "https://gitlab.com/api/v3/user/keys", expectedHTTPMethod: "POST", jsonFile: "public_key", statusCode: 403) - TanukiKit(config).postPublicKey(session, publicKey: "test-key", title: "test title") { response in + _ = TanukiKit(config).postPublicKey(session, publicKey: "test-key", title: "test title") { response in switch response { - case .Success: + case .success: XCTAssert(false, "should not get a public key") - case .Failure(let error): + case .failure(let error): XCTAssertEqual((error as NSError).code, 403) XCTAssertEqual((error as NSError).domain, TanukiKitErrorDomain) } diff --git a/TanukiKitTests/TanukiKitTestURLSession.swift b/TanukiKitTests/TanukiKitTestURLSession.swift index 6466815..317ca9d 100644 --- a/TanukiKitTests/TanukiKitTestURLSession.swift +++ b/TanukiKitTests/TanukiKitTestURLSession.swift @@ -2,7 +2,7 @@ import RequestKit import XCTest class MockURLSessionDataTask: URLSessionDataTaskProtocol { - private (set) var resumeWasCalled = false + fileprivate (set) var resumeWasCalled = false func resume() { resumeWasCalled = true @@ -34,21 +34,21 @@ class TanukiKitURLTestSession: RequestKitURLSession { self.statusCode = statusCode } - func dataTaskWithRequest(request: NSURLRequest, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> URLSessionDataTaskProtocol { - XCTAssertEqual(request.URL?.absoluteString, expectedURL) - XCTAssertEqual(request.HTTPMethod, expectedHTTPMethod) - let data = responseString?.dataUsingEncoding(NSUTF8StringEncoding) - let response = NSHTTPURLResponse(URL: request.URL!, statusCode: statusCode, HTTPVersion: "http/1.1", headerFields: ["Content-Type": "application/json"]) + func dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol { + XCTAssertEqual(request.url?.absoluteString, expectedURL) + XCTAssertEqual(request.httpMethod, expectedHTTPMethod) + let data = responseString?.data(using: String.Encoding.utf8) + let response = HTTPURLResponse(url: request.url!, statusCode: statusCode, httpVersion: "http/1.1", headerFields: ["Content-Type": "application/json"]) completionHandler(data, response, nil) wasCalled = true return MockURLSessionDataTask() } - func uploadTaskWithRequest(request: NSURLRequest, fromData bodyData: NSData?, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> URLSessionDataTaskProtocol { - XCTAssertEqual(request.URL?.absoluteString, expectedURL) - XCTAssertEqual(request.HTTPMethod, expectedHTTPMethod) - let data = responseString?.dataUsingEncoding(NSUTF8StringEncoding) - let response = NSHTTPURLResponse(URL: request.URL!, statusCode: statusCode, HTTPVersion: "http/1.1", headerFields: ["Content-Type": "application/json"]) + func uploadTask(with request: URLRequest, fromData bodyData: Data?, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol { + XCTAssertEqual(request.url?.absoluteString, expectedURL) + XCTAssertEqual(request.httpMethod, expectedHTTPMethod) + let data = responseString?.data(using: String.Encoding.utf8) + let response = HTTPURLResponse(url: request.url!, statusCode: statusCode, httpVersion: "http/1.1", headerFields: ["Content-Type": "application/json"]) completionHandler(data, response, nil) wasCalled = true return MockURLSessionDataTask() diff --git a/TanukiKitTests/TestHelper.swift b/TanukiKitTests/TestHelper.swift index baaa6b3..ce3e631 100644 --- a/TanukiKitTests/TestHelper.swift +++ b/TanukiKitTests/TestHelper.swift @@ -1,29 +1,29 @@ import Foundation internal class TestHelper { - internal class func stringFromFile(name: String) -> String? { - let bundle = NSBundle(forClass: self) - let path = bundle.pathForResource(name, ofType: "json") + internal class func stringFromFile(_ name: String) -> String? { + let bundle = Bundle(for: self) + let path = bundle.path(forResource: name, ofType: "json") if let path = path { - let string = try? String(contentsOfFile: path, encoding: NSUTF8StringEncoding) + let string = try? String(contentsOfFile: path, encoding: String.Encoding.utf8) return string } return nil } - internal class func parseDate(date: String?) -> NSDate? { - let dateFormatter = NSDateFormatter() + internal class func parseDate(date: String?) -> Date? { + let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" - dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") - let dateOutput = dateFormatter.dateFromString(date!) + dateFormatter.locale = Locale(identifier: "en_US_POSIX") + let dateOutput = dateFormatter.date(from: date!) return dateOutput } - internal class func JSONFromFile(name: String) -> AnyObject { - let bundle = NSBundle(forClass: self) - let path = bundle.pathForResource(name, ofType: "json")! - let data = NSData(contentsOfFile: path)! - let dict: AnyObject? = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) + internal class func JSONFromFile(name: String) -> Any { + let bundle = Bundle(for: self) + let path = bundle.url(forResource: name, withExtension: "json")! + let data = try! Data(contentsOf: path) + let dict: Any? = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) return dict! } } diff --git a/TanukiKitTests/UserTests.swift b/TanukiKitTests/UserTests.swift index 6c4c721..339f338 100644 --- a/TanukiKitTests/UserTests.swift +++ b/TanukiKitTests/UserTests.swift @@ -8,11 +8,11 @@ class UserTests: XCTestCase { func testGetUserCOM() { let session = TanukiKitURLTestSession(expectedURL: "https://gitlab.com/api/v3/user?access_token=12345", expectedHTTPMethod: "GET", jsonFile: "User", statusCode: 200) let config = TokenConfiguration("12345") - TanukiKit(config).me(session) { response in + _ = TanukiKit(config).me(session) { response in switch response { - case .Success(let user): + case .success(let user): XCTAssertEqual(user.login, "testmctestface") - case .Failure(let error): + case .failure(let error): XCTAssert(false, "❌ Should not retrieve an error –> (\(error))") } } @@ -22,11 +22,11 @@ class UserTests: XCTestCase { func testGetUserEECE() { let session = TanukiKitURLTestSession(expectedURL: "https://code.tiferrei.com/api/v3/user?private_token=12345", expectedHTTPMethod: "GET", jsonFile: "User", statusCode: 200) let config = PrivateTokenConfiguration("12345", url: "https://code.tiferrei.com/api/v3/") - TanukiKit(config).me(session) { response in + _ = TanukiKit(config).me(session) { response in switch response { - case .Success(let user): + case .success(let user): XCTAssertEqual(user.login, "testmctestface") - case .Failure(let error): + case .failure(let error): XCTAssert(false, "❌ Should not retrieve an error –> \(error)") } } @@ -36,14 +36,14 @@ class UserTests: XCTestCase { func testFailToGetUser() { let json = "{\"message\":\"401 Unauthorized\"}" let session = TanukiKitURLTestSession(expectedURL: "https://gitlab.com/api/v3/user", expectedHTTPMethod: "GET", response: json, statusCode: 401) - TanukiKit().me(session) { response in + _ = TanukiKit().me(session) { response in switch response { - case .Success: + case .success: XCTAssert(false, "❌ Should not retrieve user.") - case .Failure(let error as NSError): + case .failure(let error as NSError): XCTAssertEqual(error.code, 401) XCTAssertEqual(error.domain, TanukiKitErrorDomain) - case .Failure: + case .failure: XCTAssertTrue(false) } } @@ -53,27 +53,27 @@ class UserTests: XCTestCase { // MARK: Model Tests func testUserParsing() { - let subject = User(TestHelper.JSONFromFile("User") as! [String: AnyObject]) + let subject = User(TestHelper.JSONFromFile(name: "User") as! [String: AnyObject]) XCTAssertEqual(subject.name, "Test McTestface") XCTAssertEqual(subject.login, "testmctestface") XCTAssertEqual(subject.id, 7) - XCTAssertEqual(subject.avatarURL, NSURL(string: "https://code.tiferrei.com/uploads/user/avatar/7/avatar.png")) - XCTAssertEqual(subject.webURL, NSURL(string: "https://code.tiferrei.com/u/testmctestface")) - XCTAssertEqual(subject.createdAt, TestHelper.parseDate("2016-05-03T15:05:46.391Z")) + XCTAssertEqual(subject.avatarURL, URL(string: "https://code.tiferrei.com/uploads/user/avatar/7/avatar.png")) + XCTAssertEqual(subject.webURL, URL(string: "https://code.tiferrei.com/u/testmctestface")) + XCTAssertEqual(subject.createdAt, TestHelper.parseDate(date: "2016-05-03T15:05:46.391Z")) XCTAssertEqual(subject.isAdmin, false) XCTAssertEqual(subject.bio, "I'm a simple test user that Tiago created to test the GitLab API.") XCTAssertEqual(subject.location, "World Wide Web") XCTAssertEqual(subject.skype, "testMcTestface") XCTAssertEqual(subject.linkedin, "testMcTestface") XCTAssertEqual(subject.twitter, "@testMcTestface") - XCTAssertEqual(subject.websiteURL, NSURL(string: "https://testmctestface.example.com")) - XCTAssertEqual(subject.lastSignInAt, TestHelper.parseDate("2016-05-03T15:06:21.305Z")) - XCTAssertEqual(subject.confirmedAt, TestHelper.parseDate("2016-05-03T15:05:46.183Z")) + XCTAssertEqual(subject.websiteURL, URL(string: "https://testmctestface.example.com")) + XCTAssertEqual(subject.lastSignInAt, TestHelper.parseDate(date: "2016-05-03T15:06:21.305Z")) + XCTAssertEqual(subject.confirmedAt, TestHelper.parseDate(date: "2016-05-03T15:05:46.183Z")) XCTAssertEqual(subject.email, "EMAIL") XCTAssertEqual(subject.themeId, 2) XCTAssertEqual(subject.colorSchemeId, 1) XCTAssertEqual(subject.projectsLimit, 10) - XCTAssertEqual(subject.currentSignInAt, TestHelper.parseDate("2016-06-26T15:29:16.606Z")) + XCTAssertEqual(subject.currentSignInAt, TestHelper.parseDate(date: "2016-06-26T15:29:16.606Z")) XCTAssertEqual(subject.canCreateGroup, false) XCTAssertEqual(subject.canCreateProject, true) XCTAssertEqual(subject.twoFactorEnabled, false)