Initial commit
This commit is contained in:
commit
880af3d578
|
@ -0,0 +1,5 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "container:../..">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1140"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Buildkite"
|
||||
BuildableName = "Buildkite"
|
||||
BlueprintName = "Buildkite"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "BuildkiteTests"
|
||||
BuildableName = "BuildkiteTests"
|
||||
BlueprintName = "BuildkiteTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "BuildkiteIntegrationTests"
|
||||
BuildableName = "BuildkiteIntegrationTests"
|
||||
BlueprintName = "BuildkiteIntegrationTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "BuildkiteTests"
|
||||
BuildableName = "BuildkiteTests"
|
||||
BlueprintName = "BuildkiteTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "BuildkiteIntegrationTests"
|
||||
BuildableName = "BuildkiteIntegrationTests"
|
||||
BlueprintName = "BuildkiteIntegrationTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Buildkite"
|
||||
BuildableName = "Buildkite"
|
||||
BlueprintName = "Buildkite"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,29 @@
|
|||
// swift-tools-version:5.2
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Example",
|
||||
platforms: [
|
||||
.iOS(.v13),
|
||||
.macOS(.v10_15)
|
||||
],
|
||||
products: [
|
||||
// Products define the executables and libraries produced by a package, and make them visible to other packages.
|
||||
.executable(name: "Example",
|
||||
targets: ["Example"])
|
||||
],
|
||||
dependencies: [
|
||||
// Dependencies declare other packages that this package depends on.
|
||||
// .package(url: /* package url */, from: "1.0.0"),
|
||||
.package(path: "../"),
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
|
||||
.target(
|
||||
name: "Example",
|
||||
dependencies: ["Buildkite"]),
|
||||
]
|
||||
)
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// main.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/5/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Buildkite
|
||||
|
||||
let client = Buildkite()
|
||||
client.token = "..."
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
client.sendPublisher(Build.Resources.ListAll())
|
||||
.map(\.content)
|
||||
.sink(receiveCompletion: { result in
|
||||
if case let .failure(error) = result {
|
||||
print(error)
|
||||
exit(1)
|
||||
}
|
||||
}) { agents in
|
||||
print(agents)
|
||||
exit(0)
|
||||
}.store(in: &cancellables)
|
||||
|
||||
RunLoop.main.run()
|
|
@ -0,0 +1,32 @@
|
|||
// swift-tools-version:5.2
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Buildkite",
|
||||
platforms: [
|
||||
.iOS(.v10),
|
||||
.macOS(.v10_12)
|
||||
],
|
||||
products: [
|
||||
// Products define the executables and libraries produced by a package, and make them visible to other packages.
|
||||
.library(
|
||||
name: "Buildkite",
|
||||
targets: ["Buildkite"])
|
||||
],
|
||||
dependencies: [
|
||||
// Dependencies declare other packages that this package depends on.
|
||||
// .package(url: /* package url */, from: "1.0.0"),
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
|
||||
.target(
|
||||
name: "Buildkite",
|
||||
dependencies: []),
|
||||
.testTarget(
|
||||
name: "BuildkiteTests",
|
||||
dependencies: ["Buildkite"]),
|
||||
]
|
||||
)
|
|
@ -0,0 +1,171 @@
|
|||
//
|
||||
// Buildkite.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
public final class Buildkite {
|
||||
let encoder: JSONEncoder = {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.dateEncodingStrategy = .custom(Formatters.encodeISO8601)
|
||||
encoder.keyEncodingStrategy = .convertToSnakeCase
|
||||
return encoder
|
||||
}()
|
||||
|
||||
let decoder: JSONDecoder = {
|
||||
let decoder = JSONDecoder()
|
||||
decoder.dateDecodingStrategy = .custom(Formatters.decodeISO8601)
|
||||
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||
return decoder
|
||||
}()
|
||||
|
||||
var configuration: Configuration
|
||||
var transport: Transport
|
||||
|
||||
public var token: String? {
|
||||
get {
|
||||
configuration.token
|
||||
}
|
||||
set {
|
||||
configuration.token = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public init(configuration: Configuration = .default, transport: Transport = URLSession.shared) {
|
||||
self.configuration = configuration
|
||||
self.transport = transport
|
||||
}
|
||||
|
||||
public func send<R: Resource & HasResponseBody>(_ resource: R, completion: @escaping (Result<Response<R.Content>, Error>) -> Void) {
|
||||
let request = URLRequest(resource, configuration: configuration)
|
||||
transport.send(request: request, completion: handleContentfulResponse(completion: completion))
|
||||
}
|
||||
|
||||
public func send<R: Resource & HasRequestBody & HasResponseBody>(_ resource: R, completion: @escaping (Result<Response<R.Content>, Error>) -> Void) {
|
||||
let request: URLRequest
|
||||
do {
|
||||
request = try URLRequest(resource, configuration: configuration, encoder: encoder)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
transport.send(request: request, completion: handleContentfulResponse(completion: completion))
|
||||
}
|
||||
|
||||
public func send<R: Resource>(_ resource: R, completion: @escaping (Result<Response<Void>, Error>) -> Void) {
|
||||
let request = URLRequest(resource, configuration: configuration)
|
||||
transport.send(request: request, completion: handleEmptyResponse(completion: completion))
|
||||
}
|
||||
|
||||
public func send<R: Resource & HasRequestBody>(_ resource: R, completion: @escaping (Result<Response<Void>, Error>) -> Void) {
|
||||
let request: URLRequest
|
||||
do {
|
||||
request = try URLRequest(resource, configuration: configuration, encoder: encoder)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
transport.send(request: request, completion: handleEmptyResponse(completion: completion))
|
||||
}
|
||||
|
||||
private func handleContentfulResponse<Content: Decodable>(completion: @escaping (Result<Response<Content>, Error>) -> Void) -> (Result<(data: Data, response: URLResponse), Error>) -> Void { { [weak self] result in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
let content: Content
|
||||
let response: URLResponse
|
||||
do {
|
||||
let data: Data
|
||||
(data, response) = try result.get()
|
||||
try self.checkResponseForIssues(response)
|
||||
content = try self.decoder.decode(Content.self, from: data)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
completion(.success(Response(content: content, response: response)))
|
||||
}
|
||||
}
|
||||
|
||||
private func handleEmptyResponse(completion: @escaping (Result<Response<Void>, Error>) -> Void) -> (Result<(data: Data, response: URLResponse), Error>) -> Void { { [weak self] result in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
var response: URLResponse
|
||||
do {
|
||||
(_, response) = try result.get()
|
||||
try self.checkResponseForIssues(response)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
completion(.success(Response(content: (), response: response)))
|
||||
}
|
||||
}
|
||||
|
||||
private func checkResponseForIssues(_ response: URLResponse) throws {
|
||||
guard let response = response as? HTTPURLResponse,
|
||||
let statusCode = StatusCode(rawValue: response.statusCode) else {
|
||||
throw ResponseError.missingResponse
|
||||
}
|
||||
if !statusCode.isSuccess {
|
||||
throw statusCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
|
||||
@available(iOS 13.0, macOS 10.15, *)
|
||||
extension Buildkite {
|
||||
public func sendPublisher<R: Resource & HasResponseBody>(_ resource: R) -> AnyPublisher<Response<R.Content>, Error> {
|
||||
transport.sendPublisher(request: URLRequest(resource, configuration: configuration))
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response)
|
||||
let content = try self.decoder.decode(R.Content.self, from: $0.data)
|
||||
return Response(content: content, response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
public func sendPublisher<R: Resource & HasRequestBody & HasResponseBody>(_ resource: R) -> AnyPublisher<Response<R.Content>, Error> {
|
||||
Result { try URLRequest(resource, configuration: configuration, encoder: encoder) }
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response)
|
||||
let content = try self.decoder.decode(R.Content.self, from: $0.data)
|
||||
return Response(content: content, response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
public func sendPublisher<R: Resource>(_ resource: R) -> AnyPublisher<Response<Void>, Error> {
|
||||
transport.sendPublisher(request: URLRequest(resource, configuration: configuration))
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response)
|
||||
return Response(content: (), response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func sendPublisher<R: Resource & HasRequestBody>(_ resource: R) -> AnyPublisher<Response<Void>, Error> {
|
||||
Result { try URLRequest(resource, configuration: configuration, encoder: encoder) }
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response)
|
||||
return Response(content: (), response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// AccessToken.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/3/20.
|
||||
// Copyright © 2020 Fangamer. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct AccessToken: Codable, Equatable {
|
||||
public var uuid: UUID
|
||||
public var scopes: [String]
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Agent.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/3/20.
|
||||
// Copyright © 2020 Fangamer. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Agent: Codable, Equatable {
|
||||
public var id: UUID
|
||||
public var url: URL
|
||||
public var webUrl: URL
|
||||
public var name: String
|
||||
public var connectionState: String
|
||||
public var hostname: String
|
||||
public var ipAddress: String
|
||||
public var userAgent: String
|
||||
public var version: String
|
||||
public var creator: User?
|
||||
public var createdAt: Date
|
||||
public var job: Job?
|
||||
public var lastJobFinishedAt: Date?
|
||||
public var priority: Int?
|
||||
public var metaData: [String]
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Annotation.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/3/20.
|
||||
// Copyright © 2020 Fangamer. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Annotation: Codable, Equatable {
|
||||
public enum Context: String, Codable {
|
||||
case success
|
||||
case info
|
||||
case warning
|
||||
case error
|
||||
}
|
||||
|
||||
public var id: UUID
|
||||
public var context: String
|
||||
public var style: Context
|
||||
public var bodyHtml: String
|
||||
public var createdAt: Date
|
||||
public var updatedAt: Date
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Artifact.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/3/20.
|
||||
// Copyright © 2020 Fangamer. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Artifact: Codable, Equatable {
|
||||
public enum State: String, Codable, Equatable {
|
||||
case new
|
||||
case error
|
||||
case finished
|
||||
case deleted
|
||||
}
|
||||
|
||||
public var id: UUID
|
||||
public var jobId: UUID
|
||||
public var url: URL
|
||||
public var downloadUrl: URL
|
||||
public var state: State
|
||||
public var path: String
|
||||
public var dirname: String
|
||||
public var filename: String
|
||||
public var mimeType: String
|
||||
public var fileSize: Int
|
||||
public var sha1sum: String
|
||||
|
||||
public struct URLs: Codable {
|
||||
public var url: URL
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Build.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/3/20.
|
||||
// Copyright © 2020 Fangamer. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Build: Codable, Equatable {
|
||||
public var id: UUID
|
||||
public var url: URL
|
||||
public var webUrl: URL
|
||||
public var number: Int
|
||||
public var state: String
|
||||
public var blocked: Bool
|
||||
public var message: String?
|
||||
public var commit: String
|
||||
public var branch: String
|
||||
public var env: [String: String]?
|
||||
public var source: String
|
||||
public var creator: User?
|
||||
public var jobs: [Job]
|
||||
public var createdAt: Date
|
||||
public var scheduledAt: Date
|
||||
public var startedAt: Date?
|
||||
public var finishedAt: Date?
|
||||
public var metaData: [String: String]
|
||||
public var pullRequest: [String: String?]?
|
||||
public var pipeline: Pipeline
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// Emoji.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/3/20.
|
||||
// Copyright © 2020 Fangamer. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Emoji: Codable, Equatable {
|
||||
public var name: String
|
||||
public var url: URL
|
||||
public var aliases: [String] = []
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// Job.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/3/20.
|
||||
// Copyright © 2020 Fangamer. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Job: Codable, Equatable {
|
||||
public struct Agent: Codable, Equatable {
|
||||
public var id: UUID
|
||||
public var url: URL
|
||||
public var name: String
|
||||
}
|
||||
|
||||
public var id: UUID
|
||||
public var type: String
|
||||
public var name: String?
|
||||
public var stepKey: String?
|
||||
public var agentQueryRules: [String]
|
||||
public var state: String?
|
||||
public var buildUrl: URL?
|
||||
public var webUrl: URL?
|
||||
public var logUrl: URL?
|
||||
public var rawLogUrl: URL?
|
||||
public var artifactsUrl: URL?
|
||||
public var command: String?
|
||||
public var softFailed: Bool
|
||||
public var exitStatus: Int?
|
||||
public var artifactPaths: String?
|
||||
public var agent: Agent?
|
||||
public var createdAt: Date
|
||||
public var scheduledAt: Date
|
||||
public var runnableAt: Date?
|
||||
public var startedAt: Date?
|
||||
public var finishedAt: Date?
|
||||
public var retried: Bool
|
||||
public var retriedInJobId: UUID?
|
||||
public var retriesCount: Int?
|
||||
public var parallelGroupIndex: Int?
|
||||
public var parallelGroupTotal: Int?
|
||||
|
||||
public struct Unblocked: Codable, Equatable {
|
||||
public var id: UUID
|
||||
public var type: String
|
||||
public var label: String
|
||||
public var state: String
|
||||
public var webUrl: URL?
|
||||
public var unblockedBy: User
|
||||
public var unblockedAt: Date
|
||||
public var unblockable: Bool
|
||||
public var unblockUrl: URL
|
||||
}
|
||||
|
||||
public struct LogOutput: Codable {
|
||||
public var url: URL
|
||||
public var content: String
|
||||
public var size: Int
|
||||
public var headerTimes: [Int]
|
||||
}
|
||||
|
||||
public struct EnvironmentVariables: Codable, Equatable {
|
||||
public var env: [String: String]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Organization.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/3/20.
|
||||
// Copyright © 2020 Fangamer. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Organization: Codable, Equatable {
|
||||
public var id: UUID
|
||||
public var url: URL
|
||||
public var webUrl: URL
|
||||
public var name: String
|
||||
public var slug: String
|
||||
public var pipelinesUrl: URL
|
||||
public var agentsUrl: URL
|
||||
public var emojisUrl: URL
|
||||
public var createdAt: URL
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
//
|
||||
// Pipeline.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/3/20.
|
||||
// Copyright © 2020 Fangamer. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Pipeline: Codable, Equatable {
|
||||
public var id: UUID
|
||||
public var url: URL
|
||||
public var webUrl: URL
|
||||
public var name: String
|
||||
public var slug: String
|
||||
public var repository: String
|
||||
public var branchConfiguration: String?
|
||||
public var defaultBranch: String?
|
||||
public var provider: Provider
|
||||
public var skipQueuedBranchBuilds: Bool
|
||||
public var skipQueuedBranchBuildsFilter: String?
|
||||
public var cancelRunningBranchBuilds: Bool
|
||||
public var cancelRunningBranchBuildsFilter: String?
|
||||
public var buildsUrl: URL
|
||||
public var badgeUrl: URL
|
||||
public var createdAt: Date
|
||||
public var scheduledBuildsCount: Int
|
||||
public var runningBuildsCount: Int
|
||||
public var scheduledJobsCount: Int
|
||||
public var runningJobsCount: Int
|
||||
public var waitingJobsCount: Int
|
||||
public var visibility: String
|
||||
public var steps: [Step]
|
||||
public var env: [String: EnvVar?]?
|
||||
|
||||
public struct Provider: Codable, Equatable {
|
||||
public var id: String
|
||||
public var webhookUrl: URL
|
||||
public var settings: Settings
|
||||
}
|
||||
}
|
||||
|
||||
extension Pipeline.Provider {
|
||||
public struct Settings: Codable, Equatable {
|
||||
public var repository: String?
|
||||
/// Whether to create builds for commits that are part of a Pull Request.
|
||||
public var buildPullRequests: Bool?
|
||||
/// Whether to limit the creation of builds to specific branches or patterns.
|
||||
public var pullRequestBranchFilterEnabled: Bool?
|
||||
/// The branch filtering pattern. Only pull requests on branches matching this pattern will cause builds to be created.
|
||||
public var pullRequestBranchFilterConfiguration: String?
|
||||
/// Whether to skip creating a new build for a pull request if an existing build for the commit and branch already exists.
|
||||
public var skipPullRequestBuildsForExistingCommits: Bool?
|
||||
/// Whether to create builds when tags are pushed.
|
||||
public var buildTags: Bool?
|
||||
/// Whether to update the status of commits in Bitbucket or GitHub.
|
||||
public var publishCommitStatus: Bool?
|
||||
/// Whether to create a separate status for each job in a build, allowing you to see the status of each job directly in Bitbucket or GitHub.
|
||||
public var publishCommitStatusPerStep: Bool?
|
||||
/// What type of event to trigger builds on. Code will create builds when code is pushed to GitHub. Deployment will create builds when a deployment is created with the GitHub Deployments API. Fork will create builds when the GitHub repository is forked. None will not create any builds based on GitHub activity.
|
||||
public var triggerMode: String?
|
||||
/// Whether filter conditions are being used for this step.
|
||||
public var filterEnabled: Bool?
|
||||
/// The conditions under which this step will run. See the Using Conditionals guide for more information.
|
||||
public var filterCondition: String?
|
||||
/// Whether to create builds for pull requests from third-party forks.
|
||||
public var buildPullRequestForks: Bool?
|
||||
/// Prefix branch names for third-party fork builds to ensure they don't trigger branch conditions. For example, the master branch from some-user will become some-user:master.
|
||||
public var prefixPullRequestForkBranchNames: Bool?
|
||||
/// Whether to create a separate status for pull request builds, allowing you to require a passing pull request build in your required status checks in GitHub.
|
||||
public var separatePullRequestStatuses: Bool?
|
||||
/// The status to use for blocked builds. Pending can be used with required status checks to prevent merging pull requests with blocked builds.
|
||||
public var publishBlockedAsPending: Bool?
|
||||
}
|
||||
}
|
||||
|
||||
extension Pipeline {
|
||||
public enum Step: Codable, Equatable {
|
||||
case script(Command)
|
||||
case waiter(Wait)
|
||||
case manual(Block)
|
||||
case trigger(Trigger)
|
||||
|
||||
private enum Unassociated: String, Codable {
|
||||
case script
|
||||
case waiter
|
||||
case manual
|
||||
case trigger
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let type = try container.decode(Unassociated.self, forKey: .type)
|
||||
switch type {
|
||||
case .script:
|
||||
self = .script(try Command(from: decoder))
|
||||
case .waiter:
|
||||
self = .waiter(try Wait(from: decoder))
|
||||
case .manual:
|
||||
self = .manual(try Block(from: decoder))
|
||||
case .trigger:
|
||||
self = .trigger(try Trigger(from: decoder))
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
switch self {
|
||||
case .script(let step):
|
||||
try step.encode(to: encoder)
|
||||
case .waiter(let step):
|
||||
try step.encode(to: encoder)
|
||||
case .manual(let step):
|
||||
try step.encode(to: encoder)
|
||||
case .trigger(let step):
|
||||
try step.encode(to: encoder)
|
||||
}
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case type
|
||||
}
|
||||
|
||||
public struct Command: Codable, Equatable {
|
||||
public let type = "script"
|
||||
public var name: String
|
||||
public var command: String?
|
||||
public var label: String?
|
||||
public var artifactPaths: String?
|
||||
public var branchConfiguration: String?
|
||||
public var env: [String: EnvVar?]
|
||||
public var timeoutInMinutes: Int?
|
||||
public var agentQueryRules: [String]
|
||||
public var async: Bool?
|
||||
public var concurrency: Int?
|
||||
public var parallelism: Int?
|
||||
}
|
||||
|
||||
public struct Wait: Codable, Equatable {
|
||||
public let type = "waiter"
|
||||
public var label: String?
|
||||
public var continueAfterFailure: Bool?
|
||||
}
|
||||
|
||||
public struct Block: Codable, Equatable {
|
||||
public let type = "manual"
|
||||
public var label: String?
|
||||
}
|
||||
|
||||
public struct Trigger: Codable, Equatable {
|
||||
public let type = "trigger"
|
||||
public var triggerProjectSlug: String
|
||||
public var label: String?
|
||||
public var triggerCommit: String?
|
||||
public var triggerBranch: String?
|
||||
public var triggerAsync: Bool?
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public enum EnvVar: Codable, Equatable {
|
||||
case bool(Bool)
|
||||
case number(Double)
|
||||
case string(String)
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
|
||||
do {
|
||||
let bool = try container.decode(Bool.self)
|
||||
self = .bool(bool)
|
||||
} catch DecodingError.typeMismatch {
|
||||
do {
|
||||
let number = try container.decode(Double.self)
|
||||
self = .number(number)
|
||||
} catch DecodingError.typeMismatch {
|
||||
let string = try container.decode(String.self)
|
||||
self = .string(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
switch self {
|
||||
case .bool(let bool):
|
||||
try container.encode(bool)
|
||||
case .number(let number):
|
||||
try container.encode(number)
|
||||
case .string(let string):
|
||||
try container.encode(string)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// User.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/3/20.
|
||||
// Copyright © 2020 Fangamer. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct User: Codable, Equatable {
|
||||
public var id: UUID
|
||||
public var name: String
|
||||
public var email: String
|
||||
public var avatarUrl: URL
|
||||
public var createdAt: Date
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// APIVersion.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct APIVersion {
|
||||
public static let v2: APIVersion = "v2"
|
||||
|
||||
let id: String
|
||||
|
||||
init(_ version: String) {
|
||||
id = version
|
||||
}
|
||||
}
|
||||
|
||||
extension APIVersion: ExpressibleByStringLiteral {
|
||||
public init(stringLiteral value: StringLiteralType) {
|
||||
self.init(value)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// Configuration.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Configuration {
|
||||
public let baseURL = URL(string: "https://api.buildkite.com")!
|
||||
public var version: APIVersion
|
||||
|
||||
public static var `default`: Configuration {
|
||||
.init(version: .v2)
|
||||
}
|
||||
|
||||
public init(version: APIVersion) {
|
||||
self.version = version
|
||||
}
|
||||
|
||||
func url(for path: String) -> URL {
|
||||
baseURL
|
||||
.appendingPathComponent(version.id)
|
||||
.appendingPathComponent(path)
|
||||
}
|
||||
|
||||
var token: String?
|
||||
|
||||
func authorizeIfNeeded(_ request: inout URLRequest) {
|
||||
if let token = token {
|
||||
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// Constants.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/23/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum Formatters {
|
||||
static let iso8601WithFractionalSeconds: ISO8601DateFormatter = {
|
||||
let formatter: ISO8601DateFormatter
|
||||
if #available(iOS 11.0, macOS 10.13, *) {
|
||||
formatter = ISO8601DateFormatter()
|
||||
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||
} else {
|
||||
formatter = Formatters.iso8601WithoutFractionalSeconds
|
||||
}
|
||||
return formatter
|
||||
}()
|
||||
|
||||
static let iso8601WithoutFractionalSeconds: ISO8601DateFormatter = {
|
||||
let formatter = ISO8601DateFormatter()
|
||||
formatter.formatOptions = [.withInternetDateTime]
|
||||
return formatter
|
||||
}()
|
||||
|
||||
static func dateIfPossible(fromISO8601 string: String) -> Date? {
|
||||
if let date = iso8601WithFractionalSeconds.date(from: string) {
|
||||
return date
|
||||
} else if let date = iso8601WithoutFractionalSeconds.date(from: string) {
|
||||
return date
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
static func encodeISO8601(date: Date, encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
let dateString = iso8601WithoutFractionalSeconds.string(from: date)
|
||||
try container.encode(dateString)
|
||||
}
|
||||
|
||||
static func decodeISO8601(decoder: Decoder) throws -> Date {
|
||||
let container = try decoder.singleValueContainer()
|
||||
let dateString = try container.decode(String.self)
|
||||
guard let date = dateIfPossible(fromISO8601: dateString) else {
|
||||
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: container.codingPath, debugDescription: "Expected date string to be ISO8601-formatted."))
|
||||
}
|
||||
return date
|
||||
}
|
||||
}
|
||||
|
||||
class OptionalFractionalSecondsDateFormatter: DateFormatter {
|
||||
static let withoutSeconds: DateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.calendar = Calendar(identifier: .iso8601)
|
||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
formatter.timeZone = TimeZone(identifier: "UTC")
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXX"
|
||||
return formatter
|
||||
}()
|
||||
|
||||
func setup() {
|
||||
calendar = Calendar(identifier: .iso8601)
|
||||
locale = Locale(identifier: "en_US_POSIX")
|
||||
timeZone = TimeZone(identifier: "UTC")
|
||||
dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX" // handle up to 6 decimal places, although iOS currently only preserves 2 digits of precision
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
setup()
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
setup()
|
||||
}
|
||||
|
||||
override func date(from string: String) -> Date? {
|
||||
if let result = super.date(from: string) {
|
||||
return result
|
||||
}
|
||||
return OptionalFractionalSecondsDateFormatter.withoutSeconds.date(from: string)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// Resource.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol HasRequestBody {
|
||||
associatedtype Body: Encodable
|
||||
var body: Body { get }
|
||||
}
|
||||
|
||||
public protocol HasResponseBody {
|
||||
associatedtype Content: Decodable
|
||||
}
|
||||
|
||||
public protocol Resource {
|
||||
var path: String { get }
|
||||
func transformRequest(_ request: inout URLRequest)
|
||||
}
|
||||
|
||||
extension Resource {
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
extension URLRequest {
|
||||
init<R: Resource & HasRequestBody>(_ resource: R, configuration: Configuration, encoder: JSONEncoder) throws {
|
||||
self.init(resource, configuration: configuration)
|
||||
httpBody = try encoder.encode(resource.body)
|
||||
}
|
||||
|
||||
init<R: Resource>(_ resource: R, configuration: Configuration) {
|
||||
let url = configuration.url(for: resource.path)
|
||||
var request = URLRequest(url: url)
|
||||
configuration.authorizeIfNeeded(&request)
|
||||
resource.transformRequest(&request)
|
||||
self = request
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Response.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ResponseError: Error {
|
||||
case missingResponse
|
||||
case unexpectedlyNoContent
|
||||
}
|
||||
|
||||
public struct Response<T> {
|
||||
public let content: T
|
||||
public let response: URLResponse
|
||||
|
||||
init(content: T, response: URLResponse) {
|
||||
self.content = content
|
||||
self.response = response
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// StatusCode.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum StatusCode: Int, Error {
|
||||
/// The request was successfully processed by Buildkite.
|
||||
case ok = 200
|
||||
|
||||
/// The request has been fulfilled and a new resource has been created.
|
||||
case created = 201
|
||||
|
||||
/// The request has been accepted, but not yet processed.
|
||||
case accepted = 202
|
||||
|
||||
/// The response to the request can be found under a different URL in the Location header and can be retrieved using a GET method on that resource.
|
||||
case seeOther = 303
|
||||
|
||||
/// The request was not understood by the server, generally due to bad syntax or because the Content-Type header was not correctly set to application/json.
|
||||
///
|
||||
/// This status is also returned when the request provides an invalid code parameter during the OAuth token exchange process.
|
||||
case badRequest = 400
|
||||
|
||||
/// The necessary authentication credentials are not present in the request or are incorrect.
|
||||
case unauthorized = 401
|
||||
|
||||
/// The requested shop is currently frozen. The shop owner needs to log in to the shop's admin and pay the outstanding balance to unfreeze the shop.
|
||||
case paymentRequired = 402
|
||||
|
||||
/// The server is refusing to respond to the request. This is generally because you have not requested the appropriate scope for this action.
|
||||
case forbidden = 403
|
||||
|
||||
/// The requested resource was not found but could be available again in the future.
|
||||
case notFound = 404
|
||||
|
||||
/// The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request.
|
||||
case notAcceptable = 406
|
||||
|
||||
/// The request body was well-formed but contains semantic errors. The response body will provide more details in the errors or error parameters.
|
||||
case unprocessableEntity = 422
|
||||
|
||||
/// The requested shop is currently locked. Shops are locked if they repeatedly exceed their API request limit, or if there is an issue with the account, such as a detected compromise or fraud risk.
|
||||
///
|
||||
/// Contact support if your shop is locked.
|
||||
case locked = 423
|
||||
|
||||
/// The request was not accepted because the application has exceeded the rate limit. See the API Call Limit documentation for a breakdown of Buildkite's rate-limiting mechanism.
|
||||
case tooManyRequests = 429
|
||||
|
||||
/// An internal error occurred in Buildkite. Please post to the API & Technology forum so that Buildkite staff can investigate.
|
||||
case internalServerError = 500
|
||||
|
||||
/// The requested endpoint is not available on that particular shop, e.g. requesting access to a Plus-specific API on a non-Plus shop. This response may also indicate that this endpoint is reserved for future use.
|
||||
case notImplemented = 501
|
||||
|
||||
/// The server is currently unavailable. Check the status page for reported service outages.
|
||||
case serviceUnavailable = 503
|
||||
|
||||
/// The request could not complete in time. Try breaking it down in multiple smaller requests.
|
||||
case gatewayTimeout = 504
|
||||
|
||||
var isSuccess: Bool {
|
||||
self == .ok
|
||||
|| self == .created
|
||||
|| self == .accepted
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Transport.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
#endif
|
||||
|
||||
public protocol Transport {
|
||||
typealias Output = (data: Data, response: URLResponse)
|
||||
|
||||
func send(request: URLRequest, completion: @escaping (Result<Output, Error>) -> Void)
|
||||
|
||||
#if canImport(Combine)
|
||||
@available(iOS 13.0, macOS 10.15, *)
|
||||
func sendPublisher(request: URLRequest) -> AnyPublisher<Output, Error>
|
||||
#endif
|
||||
}
|
||||
|
||||
extension URLSession: Transport {
|
||||
public func send(request: URLRequest, completion: @escaping (Result<Output, Error>) -> Void) {
|
||||
let task = dataTask(with: request) { data, response, error in
|
||||
if let error = error {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
guard let data = data, let response = response else {
|
||||
completion(.failure(ResponseError.missingResponse))
|
||||
return
|
||||
}
|
||||
|
||||
completion(.success((data: data, response: response)))
|
||||
}
|
||||
task.resume()
|
||||
}
|
||||
|
||||
#if canImport(Combine)
|
||||
@available(iOS 13.0, macOS 10.15, *)
|
||||
public func sendPublisher(request: URLRequest) -> AnyPublisher<Output, Error> {
|
||||
dataTaskPublisher(for: request)
|
||||
.mapError { $0 as Error }
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// AccessTokens.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 4/21/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension AccessToken {
|
||||
public enum Resources {}
|
||||
}
|
||||
|
||||
extension AccessToken.Resources {
|
||||
/// Get the current token
|
||||
///
|
||||
/// Returns details about the API Access Token that was used to authenticate the request.
|
||||
public struct Get: Resource, HasResponseBody {
|
||||
public typealias Content = AccessToken
|
||||
public let path = "access-token"
|
||||
|
||||
public init() {}
|
||||
}
|
||||
|
||||
/// Revoke the current token
|
||||
///
|
||||
/// Once revoked, the token can no longer be used for further requests.
|
||||
public struct Revoke: Resource {
|
||||
public typealias Content = Void
|
||||
public let path = "access-token"
|
||||
|
||||
public init() {}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "DELETE"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// Agents.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 4/21/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Agent {
|
||||
public enum Resources { }
|
||||
}
|
||||
|
||||
extension Agent.Resources {
|
||||
/// List agents
|
||||
///
|
||||
/// Returns a paginated list of an organization’s agents.
|
||||
public struct List: Resource, HasResponseBody {
|
||||
public typealias Content = [Agent]
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/agents"
|
||||
}
|
||||
|
||||
public init(organization: String) {
|
||||
self.organization = organization
|
||||
}
|
||||
}
|
||||
|
||||
public struct Get: Resource, HasResponseBody {
|
||||
public typealias Content = Agent
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// agent ID
|
||||
public var agentId: UUID
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/agents/\(agentId)"
|
||||
}
|
||||
|
||||
public init(organization: String, agentId: UUID) {
|
||||
self.organization = organization
|
||||
self.agentId = agentId
|
||||
}
|
||||
}
|
||||
|
||||
/// Stop an agent
|
||||
///
|
||||
/// Instruct an agent to stop accepting new build jobs and shut itself down.
|
||||
public struct Stop: Resource {
|
||||
public typealias Content = Void
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// agent ID
|
||||
public var agentId: UUID
|
||||
public var force: Bool?
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/agents/\(agentId)/stop"
|
||||
}
|
||||
|
||||
public init(organization: String, agentId: UUID, force: Bool? = nil) {
|
||||
self.organization = organization
|
||||
self.agentId = agentId
|
||||
self.force = force
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "PUT"
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
var queryItems: [URLQueryItem] = []
|
||||
queryItems.appendIfNeeded(force, forKey: "force")
|
||||
components.queryItems = queryItems
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// Annotations.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 4/21/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Annotation {
|
||||
public enum Resources { }
|
||||
}
|
||||
|
||||
extension Annotation.Resources {
|
||||
/// List annotations for a build
|
||||
///
|
||||
/// Returns a paginated list of a build’s annotations.
|
||||
public struct List: Resource, HasResponseBody {
|
||||
public typealias Content = [Annotation]
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
public var build: Int
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/annotations"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
//
|
||||
// Artifacts.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 4/21/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Artifact {
|
||||
enum Resources { }
|
||||
}
|
||||
|
||||
extension Artifact.Resources {
|
||||
/// List artifacts for a build
|
||||
///
|
||||
/// Returns a paginated list of a build’s artifacts across all of its jobs.
|
||||
struct ListByBuild: Resource, HasResponseBody {
|
||||
typealias Content = [Artifact]
|
||||
/// organization slug
|
||||
var organization: String
|
||||
/// pipeline slug
|
||||
var pipeline: String
|
||||
/// build number
|
||||
var build: Int
|
||||
|
||||
var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/artifacts"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
}
|
||||
}
|
||||
|
||||
/// List artifacts for a job
|
||||
///
|
||||
/// Returns a paginated list of a job’s artifacts.
|
||||
struct ListByJob: Resource, HasResponseBody {
|
||||
typealias Content = [Artifact]
|
||||
/// organization slug
|
||||
var organization: String
|
||||
/// pipeline slug
|
||||
var pipeline: String
|
||||
/// build number
|
||||
var build: Int
|
||||
/// job ID
|
||||
var jobId: UUID
|
||||
|
||||
var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, jobId: UUID) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
self.jobId = jobId
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an artifact
|
||||
struct Get: Resource, HasResponseBody {
|
||||
typealias Content = Artifact
|
||||
/// organization slug
|
||||
var organization: String
|
||||
/// pipeline slug
|
||||
var pipeline: String
|
||||
/// build number
|
||||
var build: Int
|
||||
/// job ID
|
||||
var jobId: UUID
|
||||
/// artifact ID
|
||||
var artifactId: UUID
|
||||
|
||||
var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts/\(artifactId)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, jobId: UUID, artifactId: UUID) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
self.jobId = jobId
|
||||
self.artifactId = artifactId
|
||||
}
|
||||
}
|
||||
|
||||
/// Download an artifact
|
||||
///
|
||||
///
|
||||
struct Download: Resource {
|
||||
typealias Content = Artifact.URLs
|
||||
/// organization slug
|
||||
var organization: String
|
||||
/// pipeline slug
|
||||
var pipeline: String
|
||||
/// build number
|
||||
var build: Int
|
||||
/// job ID
|
||||
var jobId: UUID
|
||||
/// artifact ID
|
||||
var artifactId: UUID
|
||||
|
||||
var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts/\(artifactId)/download"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, jobId: UUID, artifactId: UUID) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
self.jobId = jobId
|
||||
self.artifactId = artifactId
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete an artifact
|
||||
///
|
||||
///
|
||||
struct Delete: Resource {
|
||||
typealias Content = Void
|
||||
/// organization slug
|
||||
var organization: String
|
||||
/// pipeline slug
|
||||
var pipeline: String
|
||||
/// build number
|
||||
var build: Int
|
||||
/// job ID
|
||||
var jobId: UUID
|
||||
/// artifact ID
|
||||
var artifactId: UUID
|
||||
|
||||
var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts/\(artifactId)"
|
||||
}
|
||||
|
||||
func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "DELETE"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, jobId: UUID, artifactId: UUID) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
self.jobId = jobId
|
||||
self.artifactId = artifactId
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,306 @@
|
|||
//
|
||||
// Builds.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 4/21/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Build {
|
||||
public enum Resources { }
|
||||
}
|
||||
|
||||
extension Build.Resources {
|
||||
/// List all builds
|
||||
///
|
||||
/// Returns a paginated list of all builds across all the user’s organizations and pipelines. If using token-based authentication
|
||||
/// the list of builds will be for the authorized organizations only. Builds are listed in the order they were created (newest first).
|
||||
public struct ListAll: Resource, HasResponseBody {
|
||||
public typealias Content = [Build]
|
||||
public let path = "builds"
|
||||
|
||||
public var options: QueryOptions?
|
||||
|
||||
public init(options: Build.Resources.QueryOptions? = nil) {
|
||||
self.options = options
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = options {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
}
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
||||
/// List builds for an organization
|
||||
///
|
||||
/// Returns a paginated list of an organization’s builds across all of an organization’s pipelines. Builds are listed in the order
|
||||
/// they were created (newest first).
|
||||
public struct ListForOrganization: Resource, HasResponseBody {
|
||||
public typealias Content = [Build]
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
|
||||
public var options: QueryOptions?
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/builds"
|
||||
}
|
||||
|
||||
public init(organization: String, options: Build.Resources.QueryOptions? = nil) {
|
||||
self.organization = organization
|
||||
self.options = options
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = options {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
}
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
||||
/// List builds for a pipeline
|
||||
///
|
||||
/// Returns a paginated list of a pipeline’s builds. Builds are listed in the order they were created (newest first).
|
||||
public struct ListForPipeline: Resource, HasResponseBody {
|
||||
public typealias Content = [Build]
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
|
||||
public var options: QueryOptions?
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, options: Build.Resources.QueryOptions? = nil) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.options = options
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = options {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
}
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a build
|
||||
public struct Get: Resource, HasResponseBody {
|
||||
public typealias Content = Build
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
public var build: Int
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a build
|
||||
public struct Create: Resource, HasRequestBody, HasResponseBody {
|
||||
public typealias Content = Build
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
/// body of the request
|
||||
public var body: Body
|
||||
|
||||
public struct Body: Codable {
|
||||
public struct Author: Codable {
|
||||
public var name: String
|
||||
public var email: String
|
||||
|
||||
public init(name: String, email: String) {
|
||||
self.name = name
|
||||
self.email = email
|
||||
}
|
||||
}
|
||||
|
||||
/// Ref, SHA or tag to be built.
|
||||
public var commit: String
|
||||
/// Branch the commit belongs to. This allows you to take advantage of your pipeline and step-level branch filtering rules.
|
||||
public var branch: String
|
||||
|
||||
/// A hash with a "name" and "email" key to show who created this build.
|
||||
public var author: Author?
|
||||
/// Force the agent to remove any existing build directory and perform a fresh checkout.
|
||||
public var cleanCheckout: Bool?
|
||||
/// Environment variables to be made available to the build.
|
||||
public var env: [String: String]?
|
||||
/// Run the build regardless of the pipeline’s branch filtering rules. Step branch filtering rules will still apply.
|
||||
public var ignorePipelineBranchFilters: Bool?
|
||||
/// Message for the build.
|
||||
public var message: String?
|
||||
/// A hash of meta-data to make available to the build.
|
||||
public var metaData: [String: String]?
|
||||
/// For a pull request build, the base branch of the pull request.
|
||||
public var pullRequestBaseBranch: String?
|
||||
/// For a pull request build, the pull request number.
|
||||
public var pullRequestId: Int?
|
||||
/// For a pull request build, the git repository of the pull request.
|
||||
public var pullRequestRepository: String?
|
||||
|
||||
public init(commit: String, branch: String, author: Build.Resources.Create.Body.Author? = nil, cleanCheckout: Bool? = nil, env: [String : String]? = nil, ignorePipelineBranchFilters: Bool? = nil, message: String? = nil, metaData: [String : String]? = nil, pullRequestBaseBranch: String? = nil, pullRequestId: Int? = nil, pullRequestRepository: String? = nil) {
|
||||
self.commit = commit
|
||||
self.branch = branch
|
||||
self.author = author
|
||||
self.cleanCheckout = cleanCheckout
|
||||
self.env = env
|
||||
self.ignorePipelineBranchFilters = ignorePipelineBranchFilters
|
||||
self.message = message
|
||||
self.metaData = metaData
|
||||
self.pullRequestBaseBranch = pullRequestBaseBranch
|
||||
self.pullRequestId = pullRequestId
|
||||
self.pullRequestRepository = pullRequestRepository
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, body: Body) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.body = body
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "POST"
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancel a build
|
||||
///
|
||||
/// Cancels the build if it's state is either scheduled or running.
|
||||
public struct Cancel: Resource, HasResponseBody {
|
||||
public typealias Content = Build
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
public var build: Int
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/cancel"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "PUT"
|
||||
}
|
||||
}
|
||||
|
||||
/// Rebuild a build
|
||||
///
|
||||
/// Returns the newly created build.
|
||||
public struct Rebuild: Resource, HasResponseBody {
|
||||
public typealias Content = Build
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
public var build: Int
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/rebuild"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "PUT"
|
||||
}
|
||||
}
|
||||
|
||||
public struct QueryOptions {
|
||||
internal init(branches: [String] = [], commit: String? = nil, createdFrom: Date? = nil, createdTo: Date? = nil, creator: UUID? = nil, finishedFrom: Date? = nil, includeRetriedJobs: Bool? = nil, metadata: [String : String] = [:], state: String? = nil) {
|
||||
self.branches = branches
|
||||
self.commit = commit
|
||||
self.createdFrom = createdFrom
|
||||
self.createdTo = createdTo
|
||||
self.creator = creator
|
||||
self.finishedFrom = finishedFrom
|
||||
self.includeRetriedJobs = includeRetriedJobs
|
||||
self.metadata = metadata
|
||||
self.state = state
|
||||
}
|
||||
|
||||
/// Filters the results by the given branch or branches.
|
||||
public var branches: [String] = []
|
||||
/// Filters the results by the commit (only works for full sha, not for shortened ones).
|
||||
public var commit: String?
|
||||
/// Filters the results by builds created on or after the given time (in ISO 8601 format)
|
||||
public var createdFrom: Date?
|
||||
/// Filters the results by builds created before the given time (in ISO 8601 format)
|
||||
public var createdTo: Date?
|
||||
/// Filters the results by the user who created the build
|
||||
public var creator: UUID?
|
||||
/// Filters the results by builds finished on or after the given time (in ISO 8601 format)
|
||||
public var finishedFrom: Date?
|
||||
/// Include all retried job executions in each build’s jobs list. Without this parameter, you'll see only the most recently run job for each step.
|
||||
public var includeRetriedJobs: Bool?
|
||||
/// Filters the results by the given meta_data.
|
||||
public var metadata: [String: String] = [:]
|
||||
/// Filters the results by the given build state. The finished state is a shortcut to automatically search for builds with passed, failed, blocked, canceled states.
|
||||
public var state: String?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Array where Element == URLQueryItem {
|
||||
init(options: Build.Resources.QueryOptions) {
|
||||
self.init()
|
||||
append(options.branches, forKey: "branch")
|
||||
appendIfNeeded(options.commit, forKey: "commit")
|
||||
appendIfNeeded(options.createdFrom, forKey: "created_from")
|
||||
appendIfNeeded(options.createdTo, forKey: "created_to")
|
||||
appendIfNeeded(options.creator, forKey: "creator")
|
||||
appendIfNeeded(options.finishedFrom, forKey: "finished_from")
|
||||
appendIfNeeded(options.includeRetriedJobs, forKey: "include_retried_jobs")
|
||||
append(options.metadata, forKey: "meta_data")
|
||||
appendIfNeeded(options.state, forKey: "state")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// Emojis.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 4/21/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Emoji {
|
||||
public enum Resources { }
|
||||
}
|
||||
|
||||
extension Emoji.Resources {
|
||||
/// List emojis
|
||||
///
|
||||
/// Returns a list of all the emojis for a given organization, including custom emojis and aliases. This list is not paginated.
|
||||
public struct List: Resource, HasResponseBody {
|
||||
public typealias Content = [Emoji]
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/emojis"
|
||||
}
|
||||
|
||||
public init(organization: String) {
|
||||
self.organization = organization
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
//
|
||||
// Jobs.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 4/21/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Job {
|
||||
public enum Resources { }
|
||||
}
|
||||
|
||||
extension Job.Resources {
|
||||
/// Retry a job
|
||||
///
|
||||
/// Retries a `failed` or `timed_out` job.
|
||||
public struct Retry: Resource, HasResponseBody {
|
||||
public typealias Content = Job
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
public var build: Int
|
||||
/// job ID
|
||||
public var job: UUID
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/retry"
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "PUT"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
self.job = job
|
||||
}
|
||||
}
|
||||
|
||||
/// Unblock a job
|
||||
///
|
||||
/// Unblocks a build’s "Block pipeline" job. The job’s `unblockable` property indicates whether it is able to be unblocked, and the `unblock_url` property points to this endpoint.
|
||||
public struct Unblock: Resource, HasRequestBody, HasResponseBody {
|
||||
public typealias Content = Job
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
public var build: Int
|
||||
/// job ID
|
||||
public var job: UUID
|
||||
/// body of the request
|
||||
public var body: Body
|
||||
|
||||
public struct Body: Codable {
|
||||
public var unblocker: UUID?
|
||||
public var fields: [String: String]
|
||||
|
||||
public init(unblocker: UUID? = nil, fields: [String : String] = [:]) {
|
||||
self.unblocker = unblocker
|
||||
self.fields = fields
|
||||
}
|
||||
}
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/unblock"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID, body: Job.Resources.Unblock.Body) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
self.job = job
|
||||
self.body = body
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "PUT"
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a job’s log output
|
||||
public struct LogOutput: Resource {
|
||||
typealias Content = Job.LogOutput
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
public var build: Int
|
||||
/// job ID
|
||||
public var job: UUID
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/log"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
self.job = job
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete a job’s log output
|
||||
public struct DeleteLogOutput: Resource {
|
||||
public typealias Content = Void
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
public var build: Int
|
||||
/// job ID
|
||||
public var job: UUID
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/log"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
self.job = job
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "DELETE"
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a job's environment variables
|
||||
public struct EnvironmentVariables: Resource, HasResponseBody {
|
||||
public typealias Content = Job.EnvironmentVariables
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
public var build: Int
|
||||
/// job ID
|
||||
public var job: UUID
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/env"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
self.job = job
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Organizations.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 4/21/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Organization {
|
||||
public enum Resources { }
|
||||
}
|
||||
|
||||
extension Organization.Resources {
|
||||
/// List organizations
|
||||
///
|
||||
/// Returns a paginated list of the user’s organizations.
|
||||
public struct List: Resource, HasResponseBody {
|
||||
public typealias Content = [Organization]
|
||||
public let path = "organizations"
|
||||
|
||||
public init() {}
|
||||
}
|
||||
|
||||
/// Get an organization
|
||||
public struct Get: Resource, HasResponseBody {
|
||||
public typealias Content = Organization
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)"
|
||||
}
|
||||
|
||||
public init(organization: String) {
|
||||
self.organization = organization
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
//
|
||||
// Pipelines.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 4/21/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Pipeline {
|
||||
public enum Resources { }
|
||||
}
|
||||
|
||||
extension Pipeline.Resources {
|
||||
/// List pipelines
|
||||
///
|
||||
/// Returns a paginated list of an organization’s pipelines.
|
||||
public struct List: Resource, HasResponseBody {
|
||||
public typealias Content = [Pipeline]
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a pipeline
|
||||
public struct Get: Resource, HasResponseBody {
|
||||
public typealias Content = Pipeline
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a pipeline
|
||||
public struct Create: Resource, HasRequestBody, HasResponseBody {
|
||||
public typealias Content = Pipeline
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
|
||||
public var body: Body
|
||||
|
||||
public struct Body: Codable {
|
||||
/// The name of the pipeline.
|
||||
public var name: String
|
||||
/// The repository URL.
|
||||
public var repository: URL
|
||||
/// An array of the build pipeline steps.
|
||||
public var steps: [Pipeline.Step]
|
||||
|
||||
/// A branch filter pattern to limit which pushed branches trigger builds on this pipeline.
|
||||
public var branchConfiguration: String?
|
||||
/// Cancel intermediate builds. When a new build is created on a branch, any previous builds that are running on the same branch will be automatically canceled.
|
||||
public var cancelRunningBranchBuilds: Bool?
|
||||
/// A branch filter pattern to limit which branches intermediate build cancelling applies to.
|
||||
public var cancelRunningBranchBuildsFilter: String?
|
||||
/// The name of the branch to prefill when new builds are created or triggered in Buildkite. It is also used to filter the builds and metrics shown on the Pipelines page.
|
||||
public var defaultBranch: String?
|
||||
/// The pipeline description.
|
||||
public var description: String?
|
||||
/// The pipeline environment variables.
|
||||
public var env: [String: String]?
|
||||
/// The source provider settings. See the Provider Settings section for accepted properties.
|
||||
public var providerSettings: Pipeline.Provider.Settings?
|
||||
/// Skip intermediate builds. When a new build is created on a branch, any previous builds that haven't yet started on the same branch will be automatically marked as skipped.
|
||||
public var skipQueuedBranchBuilds: Bool?
|
||||
/// A branch filter pattern to limit which branches intermediate build skipping applies to.
|
||||
public var skipQueuedBranchBuildsFilter: String?
|
||||
/// An array of team UUIDs to add this pipeline to. You can find your team’s UUID either via the GraphQL API, or on the settings page for a team. This property is only available if your organization has enabled Teams.
|
||||
public var teamUUIDs: [UUID]?
|
||||
|
||||
public init(name: String, repository: URL, steps: [Pipeline.Step], branchConfiguration: String? = nil, cancelRunningBranchBuilds: Bool? = nil, cancelRunningBranchBuildsFilter: String? = nil, defaultBranch: String? = nil, description: String? = nil, env: [String : String]? = nil, providerSettings: Pipeline.Provider.Settings? = nil, skipQueuedBranchBuilds: Bool? = nil, skipQueuedBranchBuildsFilter: String? = nil, teamUUIDs: [UUID]? = nil) {
|
||||
self.name = name
|
||||
self.repository = repository
|
||||
self.steps = steps
|
||||
self.branchConfiguration = branchConfiguration
|
||||
self.cancelRunningBranchBuilds = cancelRunningBranchBuilds
|
||||
self.cancelRunningBranchBuildsFilter = cancelRunningBranchBuildsFilter
|
||||
self.defaultBranch = defaultBranch
|
||||
self.description = description
|
||||
self.env = env
|
||||
self.providerSettings = providerSettings
|
||||
self.skipQueuedBranchBuilds = skipQueuedBranchBuilds
|
||||
self.skipQueuedBranchBuildsFilter = skipQueuedBranchBuildsFilter
|
||||
self.teamUUIDs = teamUUIDs
|
||||
}
|
||||
}
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines"
|
||||
}
|
||||
|
||||
public init(organization: String, body: Pipeline.Resources.Create.Body) {
|
||||
self.organization = organization
|
||||
self.body = body
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "POST"
|
||||
}
|
||||
}
|
||||
|
||||
/// Update a pipeline
|
||||
///
|
||||
/// Updates one or more properties of an existing pipeline
|
||||
public struct Update: Resource, HasRequestBody, HasResponseBody {
|
||||
public typealias Content = Pipeline
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
|
||||
public var body: Body
|
||||
|
||||
public struct Body: Codable {
|
||||
/// A branch filter pattern to limit which pushed branches trigger builds on this pipeline.
|
||||
public var branchConfiguration: String?
|
||||
/// Cancel intermediate builds. When a new build is created on a branch, any previous builds that are running on the same branch will be automatically canceled.
|
||||
public var cancelRunningBranchBuilds: Bool?
|
||||
/// A branch filter pattern to limit which branches intermediate build cancelling applies to.
|
||||
public var cancelRunningBranchBuildsFilter: String?
|
||||
/// The name of the branch to prefill when new builds are created or triggered in Buildkite.
|
||||
public var defaultBranch: String?
|
||||
/// The pipeline description.
|
||||
public var description: String?
|
||||
/// The pipeline environment variables.
|
||||
public var env: [String: String]?
|
||||
/// The name of the pipeline.
|
||||
public var name: String?
|
||||
/// The source provider settings. See the Provider Settings section for accepted properties.
|
||||
public var providerSettings: Pipeline.Provider.Settings?
|
||||
/// The repository URL.
|
||||
public var repository: URL?
|
||||
/// An array of the build pipeline steps.
|
||||
public var steps: [Pipeline.Step]?
|
||||
/// Skip intermediate builds. When a new build is created on a branch, any previous builds that haven't yet started on the same branch will be automatically marked as skipped.
|
||||
public var skipQueuedBranchBuilds: Bool?
|
||||
/// A branch filter pattern to limit which branches intermediate build skipping applies to.
|
||||
public var skipQueuedBranchBuildsFilter: String?
|
||||
/// Whether the pipeline is visible to everyone, including users outside this organization.
|
||||
public var visibility: String?
|
||||
|
||||
public init(branchConfiguration: String? = nil, cancelRunningBranchBuilds: Bool? = nil, cancelRunningBranchBuildsFilter: String? = nil, defaultBranch: String? = nil, description: String? = nil, env: [String : String]? = nil, name: String? = nil, providerSettings: Pipeline.Provider.Settings? = nil, repository: URL? = nil, steps: [Pipeline.Step]? = nil, skipQueuedBranchBuilds: Bool? = nil, skipQueuedBranchBuildsFilter: String? = nil, visibility: String? = nil) {
|
||||
self.branchConfiguration = branchConfiguration
|
||||
self.cancelRunningBranchBuilds = cancelRunningBranchBuilds
|
||||
self.cancelRunningBranchBuildsFilter = cancelRunningBranchBuildsFilter
|
||||
self.defaultBranch = defaultBranch
|
||||
self.description = description
|
||||
self.env = env
|
||||
self.name = name
|
||||
self.providerSettings = providerSettings
|
||||
self.repository = repository
|
||||
self.steps = steps
|
||||
self.skipQueuedBranchBuilds = skipQueuedBranchBuilds
|
||||
self.skipQueuedBranchBuildsFilter = skipQueuedBranchBuildsFilter
|
||||
self.visibility = visibility
|
||||
}
|
||||
}
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, body: Pipeline.Resources.Update.Body) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.body = body
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete a pipeline
|
||||
public struct Delete: Resource {
|
||||
public typealias Content = Void
|
||||
/// organization slug
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Users.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 4/21/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension User {
|
||||
public enum Resources { }
|
||||
}
|
||||
|
||||
extension User.Resources {
|
||||
public struct Me: Resource, HasResponseBody {
|
||||
public typealias Content = User
|
||||
public let path = "user"
|
||||
|
||||
public init() {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// URL+Buildkite.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/5/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Array where Element == URLQueryItem {
|
||||
mutating func appendIfNeeded<S: LosslessStringConvertible>(_ value: S?, forKey key: String) {
|
||||
guard let value = value else {
|
||||
return
|
||||
}
|
||||
append(URLQueryItem(name: key, value: String(value)))
|
||||
}
|
||||
|
||||
enum ArrayFormat {
|
||||
case indices
|
||||
case brackets
|
||||
|
||||
func format(for index: Int) -> String {
|
||||
switch self {
|
||||
case .indices:
|
||||
return "[\(index)]"
|
||||
case .brackets:
|
||||
return "[]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutating func append(_ items: [String], forKey key: String, arrayFormat: ArrayFormat = .brackets) {
|
||||
append(contentsOf: items
|
||||
.enumerated()
|
||||
.map {
|
||||
URLQueryItem(name: "\(key)\(arrayFormat.format(for: $0.offset))",
|
||||
value: $0.element)
|
||||
})
|
||||
}
|
||||
|
||||
mutating func append(_ items: [String: String], forKey key: String) {
|
||||
append(contentsOf: items
|
||||
.map {
|
||||
URLQueryItem(name: "\(key)[\($0.key)]",
|
||||
value: $0.value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
extension Date: LosslessStringConvertible {
|
||||
public init?(_ description: String) {
|
||||
guard let date = Formatters.dateIfPossible(fromISO8601: description) else {
|
||||
return nil
|
||||
}
|
||||
self = date
|
||||
}
|
||||
}
|
||||
|
||||
extension UUID: LosslessStringConvertible {
|
||||
public init?(_ description: String) {
|
||||
guard let id = UUID(uuidString: description) else {
|
||||
return nil
|
||||
}
|
||||
self = id
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
//
|
||||
// BuildkiteTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
#endif
|
||||
|
||||
class BuildkiteTests: XCTestCase {
|
||||
private struct TestData {
|
||||
enum Case {
|
||||
case success
|
||||
case successNoContent
|
||||
case badResponse
|
||||
case unsuccessfulResponse
|
||||
case noData
|
||||
}
|
||||
|
||||
var configuration = Configuration.default
|
||||
var client: Buildkite
|
||||
var resources = MockResources()
|
||||
|
||||
init(testCase: Case = .success) throws {
|
||||
let responses: [(Data, URLResponse)]
|
||||
|
||||
switch testCase {
|
||||
case .success:
|
||||
responses = [try MockData.mockingSuccess(with: resources.content, url: configuration.baseURL)]
|
||||
case .successNoContent:
|
||||
responses = [MockData.mockingSuccessNoContent(url: configuration.baseURL)]
|
||||
case .badResponse:
|
||||
responses = [MockData.mockingIncompatibleResponse(for: configuration.baseURL)]
|
||||
case .unsuccessfulResponse:
|
||||
responses = [MockData.mockingUnsuccessfulResponse(for: configuration.baseURL)]
|
||||
case .noData:
|
||||
responses = []
|
||||
}
|
||||
|
||||
client = Buildkite(configuration: configuration,
|
||||
transport: MockTransport(responses: responses))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Closure-based Requests
|
||||
|
||||
extension BuildkiteTests {
|
||||
func testClosureBasedRequest() throws {
|
||||
let testData = try TestData(testCase: .success)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
testData.client.send(testData.resources.contentResource) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(testData.resources.content, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testClosureBasedRequestNoContent() throws {
|
||||
let testData = try TestData(testCase: .successNoContent)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
testData.client.send(testData.resources.noContentResource) { _ in
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testClosureBasedRequestInvalidResponse() throws {
|
||||
let testData = try TestData(testCase: .badResponse)
|
||||
let expectation = XCTestExpectation()
|
||||
testData.client.send(testData.resources.contentResource) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
XCTFail("Expected to have failed with an error, but closure fulfilled normally")
|
||||
} catch {
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testClosureBasedRequestUnsuccessfulResponse() throws {
|
||||
let testData = try TestData(testCase: .unsuccessfulResponse)
|
||||
let expectation = XCTestExpectation()
|
||||
testData.client.send(testData.resources.contentResource) { result in
|
||||
defer {
|
||||
expectation.fulfill()
|
||||
}
|
||||
guard let _ = try? result.get() else {
|
||||
return
|
||||
}
|
||||
XCTFail("Expected to have failed with an error, but closure fulfilled normally")
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testFailureFromTransport() throws {
|
||||
let testData = try TestData(testCase: .noData)
|
||||
let expectation = XCTestExpectation()
|
||||
testData.client.send(testData.resources.contentResource) { result in
|
||||
defer {
|
||||
expectation.fulfill()
|
||||
}
|
||||
guard let _ = try? result.get() else {
|
||||
return
|
||||
}
|
||||
XCTFail("Expected to have failed with an error, but closure fulfilled normally")
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Combine-based Requests
|
||||
|
||||
#if canImport(Combine)
|
||||
@available(iOS 13.0, macOS 10.15, *)
|
||||
extension BuildkiteTests {
|
||||
func testPublisherBasedRequest() throws {
|
||||
let testData = try TestData(testCase: .success)
|
||||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
testData.client.sendPublisher(testData.resources.contentResource)
|
||||
.sink(receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: { XCTAssertEqual(testData.resources.content, $0.content) })
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testPublisherBasedRequestNoContent() throws {
|
||||
let testData = try TestData(testCase: .success)
|
||||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
testData.client.sendPublisher(testData.resources.noContentResource)
|
||||
.sink(receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}, receiveValue: { _ in })
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testPublisherBasedRequestInvalidResponse() throws {
|
||||
let testData = try TestData(testCase: .badResponse)
|
||||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
testData.client.sendPublisher(testData.resources.contentResource)
|
||||
.sink(receiveCompletion: {
|
||||
if case .finished = $0 {
|
||||
XCTFail("Expected to have failed with an error, but publisher fulfilled normally")
|
||||
}
|
||||
expectation.fulfill()
|
||||
}, receiveValue: { _ in })
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testPublisherBasedRequestUnsuccessfulResponse() throws {
|
||||
let testData = try TestData(testCase: .unsuccessfulResponse)
|
||||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
testData.client.sendPublisher(testData.resources.contentResource)
|
||||
.sink(receiveCompletion: {
|
||||
if case .finished = $0 {
|
||||
XCTFail("Expected to have failed with an error, but publisher fulfilled normally")
|
||||
}
|
||||
expectation.fulfill()
|
||||
}, receiveValue: { _ in })
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// StatusCodeTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/23/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
class StatusCodeTests: XCTestCase {
|
||||
func testFlag() {
|
||||
XCTAssertTrue(StatusCode.ok.isSuccess)
|
||||
XCTAssertTrue(StatusCode.created.isSuccess)
|
||||
XCTAssertTrue(StatusCode.accepted.isSuccess)
|
||||
XCTAssertFalse(StatusCode.paymentRequired.isSuccess)
|
||||
XCTAssertFalse(StatusCode.unauthorized.isSuccess)
|
||||
XCTAssertFalse(StatusCode.notFound.isSuccess)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
//
|
||||
// TransportTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
#endif
|
||||
|
||||
class TransportTests: XCTestCase {
|
||||
private func createSession(testCase: MockURLProtocol.Case = .success) -> URLSession {
|
||||
switch testCase {
|
||||
case .success:
|
||||
MockURLProtocol.requestHandler = MockData.mockingSuccessNoContent
|
||||
case .error:
|
||||
MockURLProtocol.requestHandler = MockData.mockingError
|
||||
}
|
||||
let config = URLSessionConfiguration.ephemeral
|
||||
config.protocolClasses = [MockURLProtocol.self]
|
||||
return URLSession(configuration: config)
|
||||
}
|
||||
|
||||
private class MockURLProtocol: URLProtocol {
|
||||
enum Case {
|
||||
case success
|
||||
case error
|
||||
}
|
||||
|
||||
typealias RequestHandler = (URLRequest) throws -> (Data, URLResponse)
|
||||
static var requestHandler: RequestHandler?
|
||||
|
||||
override class func canInit(with request: URLRequest) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
|
||||
return request
|
||||
}
|
||||
|
||||
override func startLoading() {
|
||||
guard let handler = MockURLProtocol.requestHandler else {
|
||||
return
|
||||
}
|
||||
do {
|
||||
let (data, response) = try handler(request)
|
||||
client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
|
||||
client?.urlProtocol(self, didLoad: data)
|
||||
client?.urlProtocolDidFinishLoading(self)
|
||||
} catch {
|
||||
client?.urlProtocol(self, didFailWithError: error)
|
||||
}
|
||||
}
|
||||
|
||||
override func stopLoading() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Closure-based Requests
|
||||
|
||||
extension TransportTests {
|
||||
func testURLSessionSendClosureBasedRequest() {
|
||||
let request = URLRequest(url: URL())
|
||||
let expectation = XCTestExpectation()
|
||||
createSession().send(request: request) {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testURLSessionSendClosureBasedRequestFailure() {
|
||||
let request = URLRequest(url: URL())
|
||||
let expectation = XCTestExpectation()
|
||||
createSession(testCase: .error).send(request: request) {
|
||||
if case .success(_) = $0 {
|
||||
XCTFail("Expected to have failed with an error, but closure fulfilled normally")
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Combine-based Requests
|
||||
|
||||
#if canImport(Combine)
|
||||
@available(iOS 13.0, macOS 10.15, *)
|
||||
extension TransportTests {
|
||||
func testURLSessionSendPublisherBasedRequest() {
|
||||
let request = URLRequest(url: URL())
|
||||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
createSession()
|
||||
.sendPublisher(request: request)
|
||||
.sink(receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}, receiveValue: { _ in })
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testURLSessionSendPublisherBasedRequestFailure() {
|
||||
let request = URLRequest(url: URL())
|
||||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
createSession(testCase: .error)
|
||||
.sendPublisher(request: request)
|
||||
.sink(receiveCompletion: {
|
||||
if case .finished = $0 {
|
||||
XCTFail("Expected to have failed with an error, but publisher fulfilled normally")
|
||||
}
|
||||
expectation.fulfill()
|
||||
}, receiveValue: { _ in })
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// AccessTokensTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
class AccessTokensTests: XCTestCase {
|
||||
func testAccessTokenGet() throws {
|
||||
let expected = AccessToken(uuid: UUID(), scopes: [])
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(AccessToken.Resources.Get()) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testAccessTokenDelete() throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(AccessToken.Resources.Revoke()) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// AgentsTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
extension Agent {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
url: URL(),
|
||||
webUrl: URL(),
|
||||
name: "jeffrey",
|
||||
connectionState: "connected",
|
||||
hostname: "jeffrey",
|
||||
ipAddress: "192.168.1.1",
|
||||
userAgent: "buildkite/host",
|
||||
version: "3.20.0",
|
||||
creator: User(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
job: Job(),
|
||||
lastJobFinishedAt: nil,
|
||||
priority: nil,
|
||||
metaData: [])
|
||||
}
|
||||
}
|
||||
|
||||
class AgentsTests: XCTestCase {
|
||||
func testAgentsList() throws {
|
||||
let expected = [Agent(), Agent()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Agent.Resources.List(organization: "buildkite")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testAgentsGet() throws {
|
||||
let expected = Agent()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Agent.Resources.Get(organization: "buildkite", agentId: UUID())) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testAgentsStop() throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Agent.Resources.Stop(organization: "buildkite", agentId: UUID(), force: true)) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// AnnotationsTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
extension Annotation {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
context: "message",
|
||||
style: .info,
|
||||
bodyHtml: "<div></div>",
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
updatedAt: Date(timeIntervalSince1970: 1001))
|
||||
}
|
||||
}
|
||||
|
||||
class AnnotationsTests: XCTestCase {
|
||||
func testAnnotationsList() throws {
|
||||
let expected = [Annotation(), Annotation()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Annotation.Resources.List(organization: "buildkite", pipeline: "my-pipeline", build: 1)) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
//
|
||||
// ArtifactsTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
extension Artifact {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
jobId: UUID(),
|
||||
url: URL(),
|
||||
downloadUrl: URL(),
|
||||
state: .new,
|
||||
path: "",
|
||||
dirname: "",
|
||||
filename: "",
|
||||
mimeType: "",
|
||||
fileSize: 0,
|
||||
sha1sum: "")
|
||||
}
|
||||
}
|
||||
|
||||
class ArtifactsTests: XCTestCase {
|
||||
func testArtifactsListByBuild() throws {
|
||||
let expected = [Artifact(), Artifact()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Artifact.Resources.ListByBuild(organization: "buildkite", pipeline: "my-pipeline", build: 1)) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testArtifactsListByJob() throws {
|
||||
let expected = [Artifact(), Artifact()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Artifact.Resources.ListByJob(organization: "buildkite", pipeline: "my-pipeline", build: 1, jobId: UUID())) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testArtifactsGet() throws {
|
||||
let expected = Artifact()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Artifact.Resources.Get(organization: "buildkite", pipeline: "my-pipeline", build: 1, jobId: UUID(), artifactId: UUID())) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testArtifactsDownload() throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Artifact.Resources.Download(organization: "buildkite", pipeline: "my-pipeline", build: 1, jobId: UUID(), artifactId: UUID())) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testArtifactsDelete() throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Artifact.Resources.Delete(organization: "buildkite", pipeline: "my-pipeline", build: 1, jobId: UUID(), artifactId: UUID())) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
//
|
||||
// BuildsTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
extension Build {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
url: URL(),
|
||||
webUrl: URL(),
|
||||
number: 1,
|
||||
state: "passed",
|
||||
blocked: false,
|
||||
message: "a commit",
|
||||
commit: "HEAD",
|
||||
branch: "master",
|
||||
env: [:],
|
||||
source: "webhook",
|
||||
creator: User(),
|
||||
jobs: [],
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
scheduledAt: Date(timeIntervalSince1970: 1000),
|
||||
startedAt: Date(timeIntervalSince1970: 1000),
|
||||
finishedAt: Date(timeIntervalSince1970: 1001),
|
||||
metaData: [:],
|
||||
pullRequest: [:],
|
||||
pipeline: Pipeline())
|
||||
}
|
||||
}
|
||||
|
||||
class BuildsTests: XCTestCase {
|
||||
func testBuildsListAllDefaultQuery() throws {
|
||||
let expected = [Build(), Build()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Build.Resources.ListAll()) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testBuildsListAllSpecializedQuery() throws {
|
||||
let expected = [Build(), Build()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let resource = Build.Resources.ListAll(options: Build.Resources.QueryOptions(branches: ["master"],
|
||||
commit: "HEAD",
|
||||
createdFrom: Date(timeIntervalSince1970: 1000),
|
||||
createdTo: Date(timeIntervalSince1970: 1000),
|
||||
creator: UUID(),
|
||||
finishedFrom: Date(timeIntervalSince1970: 1000),
|
||||
includeRetriedJobs: true,
|
||||
metadata: ["buildkite": "is cool"],
|
||||
state: "passed"))
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(resource) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testBuildsListForOrganization() throws {
|
||||
let expected = [Build(), Build()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Build.Resources.ListForOrganization(organization: "buildkite")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testBuildsListForPipeline() throws {
|
||||
let expected = [Build(), Build()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Build.Resources.ListForPipeline(organization: "buildkite", pipeline: "my-pipeline")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testBuildsGet() throws {
|
||||
let expected = Build()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Build.Resources.Get(organization: "buildkite", pipeline: "my-pipeline", build: 1)) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testBuildsCreate() throws {
|
||||
let expected = Build()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
let body = Build.Resources.Create.Body(commit: "HEAD",
|
||||
branch: "master",
|
||||
author: nil,
|
||||
cleanCheckout: nil,
|
||||
env: nil,
|
||||
ignorePipelineBranchFilters: nil,
|
||||
message: nil,
|
||||
metaData: nil,
|
||||
pullRequestBaseBranch: nil,
|
||||
pullRequestId: nil,
|
||||
pullRequestRepository: nil)
|
||||
|
||||
context.client.send(Build.Resources.Create(organization: "buildkite", pipeline: "my-pipeline", body: body)) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testBuildsCancel() throws {
|
||||
let expected = Build()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Build.Resources.Cancel(organization: "buildkite", pipeline: "my-pipeline", build: 1)) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testBuildsRebuild() throws {
|
||||
let expected = Build()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Build.Resources.Rebuild(organization: "buildkite", pipeline: "my-pipeline", build: 1)) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// EmojisTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
extension Emoji {
|
||||
init() {
|
||||
self.init(name: "jeff",
|
||||
url: URL())
|
||||
}
|
||||
}
|
||||
|
||||
class EmojisTests: XCTestCase {
|
||||
func testEmojisList() throws {
|
||||
let expected = [Emoji(), Emoji()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Emoji.Resources.List(organization: "buildkite")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
//
|
||||
// JobsTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
extension Job {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
type: "script",
|
||||
name: "📦",
|
||||
stepKey: "package",
|
||||
agentQueryRules: [],
|
||||
state: "finished",
|
||||
buildUrl: URL(),
|
||||
webUrl: URL(),
|
||||
logUrl: URL(),
|
||||
rawLogUrl: URL(),
|
||||
artifactsUrl: URL(),
|
||||
command: "echo 1",
|
||||
softFailed: false,
|
||||
exitStatus: 0,
|
||||
artifactPaths: "",
|
||||
agent: nil,
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
scheduledAt: Date(timeIntervalSince1970: 1000),
|
||||
runnableAt: nil,
|
||||
startedAt: nil,
|
||||
finishedAt: nil,
|
||||
retried: false,
|
||||
retriedInJobId: UUID(),
|
||||
retriesCount: 0,
|
||||
parallelGroupIndex: nil,
|
||||
parallelGroupTotal: nil)
|
||||
}
|
||||
}
|
||||
|
||||
class JobsTests: XCTestCase {
|
||||
func testJobsRetry() throws {
|
||||
let expected = Job()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Job.Resources.Retry(organization: "buildkite", pipeline: "my-pipeline", build: 1, job: UUID())) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testJobsUnblock() throws {
|
||||
let expected = Job()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let body = Job.Resources.Unblock.Body()
|
||||
let resource = Job.Resources.Unblock(organization: "buildkite", pipeline: "my-pipeline", build: 1, job: UUID(), body: body)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(resource) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testJobsLogOutput() throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Job.Resources.LogOutput(organization: "buildkite", pipeline: "my-pipeline", build: 1, job: UUID())) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testJobsDeleteLogOutput() throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Job.Resources.DeleteLogOutput(organization: "buildkite", pipeline: "my-pipeline", build: 1, job: UUID())) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testJobsEnvironmentVariables() throws {
|
||||
let expected = Job.EnvironmentVariables(env: [:])
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Job.Resources.EnvironmentVariables(organization: "buildkite", pipeline: "my-pipeline", build: 1, job: UUID())) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// OrganizationsTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
extension Organization {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
url: URL(),
|
||||
webUrl: URL(),
|
||||
name: "Buildkite",
|
||||
slug: "buildkite",
|
||||
pipelinesUrl: URL(),
|
||||
agentsUrl: URL(),
|
||||
emojisUrl: URL(),
|
||||
createdAt: URL())
|
||||
}
|
||||
}
|
||||
|
||||
class OrganizationsTests: XCTestCase {
|
||||
func testOrganizationsList() throws {
|
||||
let expected = [Organization()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Organization.Resources.List()) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testOrganizationsGet() throws {
|
||||
let expected = Organization()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Organization.Resources.Get(organization: "buildkite")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
//
|
||||
// PipelinesTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
extension Pipeline {
|
||||
init(steps: [Step] = []) {
|
||||
self.init(id: UUID(),
|
||||
url: URL(),
|
||||
webUrl: URL(),
|
||||
name: "My Pipeline",
|
||||
slug: "my-pipeline",
|
||||
repository: "git@github.com:buildkite/agent.git",
|
||||
branchConfiguration: nil,
|
||||
defaultBranch: "master",
|
||||
provider: Provider(id: "github",
|
||||
webhookUrl: URL(),
|
||||
settings: Provider.Settings(repository: nil,
|
||||
buildPullRequests: nil,
|
||||
pullRequestBranchFilterEnabled: nil,
|
||||
pullRequestBranchFilterConfiguration: nil,
|
||||
skipPullRequestBuildsForExistingCommits: nil,
|
||||
buildTags: nil,
|
||||
publishCommitStatus: nil,
|
||||
publishCommitStatusPerStep: nil,
|
||||
triggerMode: nil,
|
||||
filterEnabled: nil,
|
||||
filterCondition: nil,
|
||||
buildPullRequestForks: nil,
|
||||
prefixPullRequestForkBranchNames: nil,
|
||||
separatePullRequestStatuses: nil,
|
||||
publishBlockedAsPending: nil)),
|
||||
skipQueuedBranchBuilds: false,
|
||||
skipQueuedBranchBuildsFilter: nil,
|
||||
cancelRunningBranchBuilds: false,
|
||||
cancelRunningBranchBuildsFilter: nil,
|
||||
buildsUrl: URL(),
|
||||
badgeUrl: URL(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
scheduledBuildsCount: 0,
|
||||
runningBuildsCount: 0,
|
||||
scheduledJobsCount: 0,
|
||||
runningJobsCount: 0,
|
||||
waitingJobsCount: 0,
|
||||
visibility: "private",
|
||||
steps: steps,
|
||||
env: [:])
|
||||
}
|
||||
}
|
||||
|
||||
class PipelinesTests: XCTestCase {
|
||||
func testPipelinesList() throws {
|
||||
let expected = [Pipeline(), Pipeline()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Pipeline.Resources.List(organization: "buildkite", pipeline: "my-pipeline")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testPipelinesGet() throws {
|
||||
let expected = Pipeline()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Pipeline.Resources.Get(organization: "buildkite", pipeline: "my-pipeline")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testPipelinesCreate() throws {
|
||||
let steps: [Pipeline.Step] = [
|
||||
.script(Pipeline.Step.Command(name: "📦",
|
||||
command: "echo true",
|
||||
label: "📦",
|
||||
artifactPaths: "*",
|
||||
branchConfiguration: nil,
|
||||
env: [:],
|
||||
timeoutInMinutes: nil,
|
||||
agentQueryRules: [],
|
||||
async: nil,
|
||||
concurrency: nil,
|
||||
parallelism: nil)),
|
||||
.waiter(Pipeline.Step.Wait(label: "wait",
|
||||
continueAfterFailure: true)),
|
||||
.manual(Pipeline.Step.Block(label: "manual")),
|
||||
.trigger(Pipeline.Step.Trigger(triggerProjectSlug: "my-other-pipeline",
|
||||
label: "trigger",
|
||||
triggerCommit: nil,
|
||||
triggerBranch: nil,
|
||||
triggerAsync: nil))
|
||||
]
|
||||
let expected = Pipeline(steps: steps)
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let resource = Pipeline.Resources.Create(organization: "buildkite",
|
||||
body: Pipeline.Resources.Create.Body(name: "My Pipeline",
|
||||
repository: URL(),
|
||||
steps: steps,
|
||||
branchConfiguration: nil,
|
||||
cancelRunningBranchBuilds: nil,
|
||||
cancelRunningBranchBuildsFilter: nil,
|
||||
defaultBranch: nil,
|
||||
description: nil,
|
||||
env: nil,
|
||||
providerSettings: nil,
|
||||
skipQueuedBranchBuilds: nil,
|
||||
skipQueuedBranchBuildsFilter: nil,
|
||||
teamUUIDs: nil))
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
context.client.send(resource) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testPipelinesUpdate() throws {
|
||||
let expected = Pipeline()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let resource = Pipeline.Resources.Update(organization: "buildkite",
|
||||
pipeline: "my-pipeline",
|
||||
body: Pipeline.Resources.Update.Body(branchConfiguration: nil,
|
||||
cancelRunningBranchBuilds: nil,
|
||||
cancelRunningBranchBuildsFilter: nil,
|
||||
defaultBranch: nil,
|
||||
description: nil,
|
||||
env: nil,
|
||||
name: nil,
|
||||
providerSettings: nil,
|
||||
repository: nil,
|
||||
steps: nil,
|
||||
skipQueuedBranchBuilds: nil,
|
||||
skipQueuedBranchBuildsFilter: nil,
|
||||
visibility: nil))
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
context.client.send(resource) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testPipelinesDelete() throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Pipeline.Resources.Delete(organization: "buildkite", pipeline: "my-pipeline")) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// UsersTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buildkite
|
||||
|
||||
extension User {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
name: "Jeff",
|
||||
email: "jeff@buildkite.com",
|
||||
avatarUrl: URL(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000))
|
||||
}
|
||||
}
|
||||
|
||||
class UsersTests: XCTestCase {
|
||||
func testUserMe() throws {
|
||||
let expected = User()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(User.Resources.Me()) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// MockContext.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/4/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Buildkite
|
||||
|
||||
struct MockContext {
|
||||
var client: Buildkite
|
||||
var resources = MockResources()
|
||||
|
||||
init() {
|
||||
let configuration = Configuration.default
|
||||
self.init(configuration: configuration, responses: [
|
||||
MockData.mockingSuccessNoContent(url: configuration.baseURL)
|
||||
])
|
||||
}
|
||||
|
||||
init<Content: Codable>(content: Content) throws {
|
||||
let configuration = Configuration.default
|
||||
try self.init(configuration: configuration, responses: [
|
||||
MockData.mockingSuccess(with: content, url: configuration.baseURL)
|
||||
])
|
||||
}
|
||||
|
||||
private init(configuration: Configuration, responses: [(Data, URLResponse)]) {
|
||||
let transport = MockTransport(responses: responses)
|
||||
client = Buildkite(configuration: configuration,
|
||||
transport: transport)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// MockData.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
struct MockResources {
|
||||
struct HasContent: Resource, HasResponseBody {
|
||||
struct Content: Codable, Equatable {
|
||||
var name: String
|
||||
var age: Int
|
||||
}
|
||||
let path = "mock"
|
||||
}
|
||||
|
||||
var contentResource = HasContent()
|
||||
var content = HasContent.Content(name: "Jeff", age: 35)
|
||||
|
||||
struct NoContent: Resource {
|
||||
typealias Content = Void
|
||||
let path = "mock"
|
||||
}
|
||||
|
||||
var noContentResource = NoContent()
|
||||
}
|
||||
|
||||
enum MockData {
|
||||
static let encoder: JSONEncoder = {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.dateEncodingStrategy = .iso8601
|
||||
encoder.keyEncodingStrategy = .convertToSnakeCase
|
||||
return encoder
|
||||
}()
|
||||
}
|
||||
|
||||
extension MockData {
|
||||
static func mockingSuccess<Content: Codable>(with content: Content, url: URL) throws -> (Data, URLResponse) {
|
||||
let data = try encoder.encode(content)
|
||||
return (data, urlResponse(for: url, status: .ok))
|
||||
}
|
||||
|
||||
static func mockingSuccessNoContent(url: URL) -> (Data, URLResponse) {
|
||||
return (Data(), urlResponse(for: url, status: .ok))
|
||||
}
|
||||
|
||||
static func mockingIncompatibleResponse(for url: URL) -> (Data, URLResponse) {
|
||||
return (Data(), urlResponse(for: url, rawStatus: -128))
|
||||
}
|
||||
|
||||
static func mockingUnsuccessfulResponse(for url: URL) -> (Data, URLResponse) {
|
||||
return (Data(), urlResponse(for: url, status: .notFound))
|
||||
}
|
||||
|
||||
static func mockingSuccessNoContent(for request: URLRequest) throws -> (Data, URLResponse) {
|
||||
mockingSuccessNoContent(url: request.url!)
|
||||
}
|
||||
|
||||
static func mockingError(for request: URLRequest) throws -> (Data, URLResponse) {
|
||||
throw URLError(.notConnectedToInternet)
|
||||
}
|
||||
|
||||
private static func urlResponse(for url: URL, status: StatusCode) -> URLResponse {
|
||||
urlResponse(for: url, rawStatus: status.rawValue)
|
||||
}
|
||||
|
||||
private static func urlResponse(for url: URL, rawStatus status: Int) -> URLResponse {
|
||||
HTTPURLResponse(url: url,
|
||||
statusCode: status,
|
||||
httpVersion: "HTTP/1.1",
|
||||
headerFields: [:])!
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Response Mocks
|
||||
|
||||
extension MockData {
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// MockTransport.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/22/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
#endif
|
||||
|
||||
final class MockTransport {
|
||||
enum Error: Swift.Error {
|
||||
case tooManyRequests
|
||||
}
|
||||
|
||||
var history: [URLRequest] = []
|
||||
var responses: [Transport.Output]
|
||||
|
||||
init(responses: [Transport.Output]) {
|
||||
self.responses = responses
|
||||
}
|
||||
}
|
||||
|
||||
extension MockTransport: Transport {
|
||||
func send(request: URLRequest, completion: @escaping (Result<Output, Swift.Error>) -> Void) {
|
||||
history.append(request)
|
||||
guard !responses.isEmpty else {
|
||||
completion(.failure(MockTransport.Error.tooManyRequests))
|
||||
return
|
||||
}
|
||||
completion(.success(responses.removeFirst()))
|
||||
}
|
||||
|
||||
#if canImport(Combine)
|
||||
@available(iOS 13.0, macOS 10.15, *)
|
||||
func sendPublisher(request: URLRequest) -> AnyPublisher<Output, Swift.Error> {
|
||||
history.append(request)
|
||||
return Future { [weak self] promise in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
guard !self.responses.isEmpty else {
|
||||
promise(.failure(MockTransport.Error.tooManyRequests))
|
||||
return
|
||||
}
|
||||
promise(.success(self.responses.removeFirst()))
|
||||
}.eraseToAnyPublisher()
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// URL+Buildkite.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/5/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension URL {
|
||||
init() {
|
||||
self.init(string: "https://www.buildkite.com")!
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// Extensions.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/24/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
enum Constants {
|
||||
fileprivate static let asyncTestTimeout = 1.0
|
||||
}
|
||||
|
||||
extension XCTestCase {
|
||||
func wait(for expectations: [XCTestExpectation]) {
|
||||
wait(for: expectations, timeout: Constants.asyncTestTimeout)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
#if !canImport(ObjectiveC)
|
||||
import XCTest
|
||||
|
||||
extension AccessTokensTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__AccessTokensTests = [
|
||||
("testAccessTokenDelete", testAccessTokenDelete),
|
||||
("testAccessTokenGet", testAccessTokenGet),
|
||||
]
|
||||
}
|
||||
|
||||
extension AgentsTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__AgentsTests = [
|
||||
("testAgentsGet", testAgentsGet),
|
||||
("testAgentsList", testAgentsList),
|
||||
("testAgentsStop", testAgentsStop),
|
||||
]
|
||||
}
|
||||
|
||||
extension AnnotationsTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__AnnotationsTests = [
|
||||
("testAnnotationsList", testAnnotationsList),
|
||||
]
|
||||
}
|
||||
|
||||
extension ArtifactsTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__ArtifactsTests = [
|
||||
("testArtifactsDelete", testArtifactsDelete),
|
||||
("testArtifactsDownload", testArtifactsDownload),
|
||||
("testArtifactsGet", testArtifactsGet),
|
||||
("testArtifactsListByBuild", testArtifactsListByBuild),
|
||||
("testArtifactsListByJob", testArtifactsListByJob),
|
||||
]
|
||||
}
|
||||
|
||||
extension BuildkiteTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__BuildkiteTests = [
|
||||
("testClosureBasedRequest", testClosureBasedRequest),
|
||||
("testClosureBasedRequestInvalidResponse", testClosureBasedRequestInvalidResponse),
|
||||
("testClosureBasedRequestNoContent", testClosureBasedRequestNoContent),
|
||||
("testClosureBasedRequestUnsuccessfulResponse", testClosureBasedRequestUnsuccessfulResponse),
|
||||
("testFailureFromTransport", testFailureFromTransport),
|
||||
("testPublisherBasedRequest", testPublisherBasedRequest),
|
||||
("testPublisherBasedRequestInvalidResponse", testPublisherBasedRequestInvalidResponse),
|
||||
("testPublisherBasedRequestNoContent", testPublisherBasedRequestNoContent),
|
||||
("testPublisherBasedRequestUnsuccessfulResponse", testPublisherBasedRequestUnsuccessfulResponse),
|
||||
]
|
||||
}
|
||||
|
||||
extension BuildsTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__BuildsTests = [
|
||||
("testBuildsCancel", testBuildsCancel),
|
||||
("testBuildsCreate", testBuildsCreate),
|
||||
("testBuildsGet", testBuildsGet),
|
||||
("testBuildsListAllDefaultQuery", testBuildsListAllDefaultQuery),
|
||||
("testBuildsListAllSpecializedQuery", testBuildsListAllSpecializedQuery),
|
||||
("testBuildsListForOrganization", testBuildsListForOrganization),
|
||||
("testBuildsListForPipeline", testBuildsListForPipeline),
|
||||
("testBuildsRebuild", testBuildsRebuild),
|
||||
]
|
||||
}
|
||||
|
||||
extension EmojisTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__EmojisTests = [
|
||||
("testEmojisList", testEmojisList),
|
||||
]
|
||||
}
|
||||
|
||||
extension JobsTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__JobsTests = [
|
||||
("testJobsDeleteLogOutput", testJobsDeleteLogOutput),
|
||||
("testJobsEnvironmentVariables", testJobsEnvironmentVariables),
|
||||
("testJobsLogOutput", testJobsLogOutput),
|
||||
("testJobsRetry", testJobsRetry),
|
||||
("testJobsUnblock", testJobsUnblock),
|
||||
]
|
||||
}
|
||||
|
||||
extension OrganizationsTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__OrganizationsTests = [
|
||||
("testOrganizationsGet", testOrganizationsGet),
|
||||
("testOrganizationsList", testOrganizationsList),
|
||||
]
|
||||
}
|
||||
|
||||
extension PipelinesTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__PipelinesTests = [
|
||||
("testPipelinesCreate", testPipelinesCreate),
|
||||
("testPipelinesDelete", testPipelinesDelete),
|
||||
("testPipelinesGet", testPipelinesGet),
|
||||
("testPipelinesList", testPipelinesList),
|
||||
("testPipelinesUpdate", testPipelinesUpdate),
|
||||
]
|
||||
}
|
||||
|
||||
extension StatusCodeTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__StatusCodeTests = [
|
||||
("testFlag", testFlag),
|
||||
]
|
||||
}
|
||||
|
||||
extension TransportTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__TransportTests = [
|
||||
("testURLSessionSendClosureBasedRequest", testURLSessionSendClosureBasedRequest),
|
||||
("testURLSessionSendClosureBasedRequestFailure", testURLSessionSendClosureBasedRequestFailure),
|
||||
("testURLSessionSendPublisherBasedRequest", testURLSessionSendPublisherBasedRequest),
|
||||
("testURLSessionSendPublisherBasedRequestFailure", testURLSessionSendPublisherBasedRequestFailure),
|
||||
]
|
||||
}
|
||||
|
||||
extension UsersTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__UsersTests = [
|
||||
("testUserMe", testUserMe),
|
||||
]
|
||||
}
|
||||
|
||||
public func __allTests() -> [XCTestCaseEntry] {
|
||||
return [
|
||||
testCase(AccessTokensTests.__allTests__AccessTokensTests),
|
||||
testCase(AgentsTests.__allTests__AgentsTests),
|
||||
testCase(AnnotationsTests.__allTests__AnnotationsTests),
|
||||
testCase(ArtifactsTests.__allTests__ArtifactsTests),
|
||||
testCase(BuildkiteTests.__allTests__BuildkiteTests),
|
||||
testCase(BuildsTests.__allTests__BuildsTests),
|
||||
testCase(EmojisTests.__allTests__EmojisTests),
|
||||
testCase(JobsTests.__allTests__JobsTests),
|
||||
testCase(OrganizationsTests.__allTests__OrganizationsTests),
|
||||
testCase(PipelinesTests.__allTests__PipelinesTests),
|
||||
testCase(StatusCodeTests.__allTests__StatusCodeTests),
|
||||
testCase(TransportTests.__allTests__TransportTests),
|
||||
testCase(UsersTests.__allTests__UsersTests),
|
||||
]
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
import XCTest
|
||||
|
||||
import BuildkiteTests
|
||||
|
||||
var tests = [XCTestCaseEntry]()
|
||||
tests += BuildkiteTests.__allTests()
|
||||
|
||||
XCTMain(tests)
|
Loading…
Reference in New Issue