Support for the /meta endpoint
This commit is contained in:
parent
587811d65e
commit
eeeb1ae194
|
@ -1,6 +1,8 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Example/.build
|
||||
/.vscode
|
||||
/Examples/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
Package.resolved
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"fileScopedDeclarationPrivacy": {
|
||||
"accessLevel": "private"
|
||||
},
|
||||
"indentation": {
|
||||
"spaces": 4
|
||||
},
|
||||
"indentConditionalCompilationBlocks": false,
|
||||
"indentSwitchCaseLabels": false,
|
||||
"lineBreakAroundMultilineExpressionChainComponents": true,
|
||||
"lineBreakBeforeControlFlowKeywords": false,
|
||||
"lineBreakBeforeEachArgument": true,
|
||||
"lineBreakBeforeEachGenericRequirement": false,
|
||||
"lineLength": 120,
|
||||
"maximumBlankLines": 1,
|
||||
"prioritizeKeepingFunctionOutputTogether": true,
|
||||
"respectsExistingLineBreaks": true,
|
||||
"rules": {
|
||||
"AllPublicDeclarationsHaveDocumentation": false,
|
||||
"AlwaysUseLowerCamelCase": true,
|
||||
"AmbiguousTrailingClosureOverload": true,
|
||||
"BeginDocumentationCommentWithOneLineSummary": false,
|
||||
"DoNotUseSemicolons": true,
|
||||
"DontRepeatTypeInStaticProperties": true,
|
||||
"FileScopedDeclarationPrivacy": true,
|
||||
"FullyIndirectEnum": true,
|
||||
"GroupNumericLiterals": true,
|
||||
"IdentifiersMustBeASCII": true,
|
||||
"NeverForceUnwrap": false,
|
||||
"NeverUseForceTry": false,
|
||||
"NeverUseImplicitlyUnwrappedOptionals": false,
|
||||
"NoAccessLevelOnExtensionDeclaration": true,
|
||||
"NoBlockComments": true,
|
||||
"NoCasesWithOnlyFallthrough": true,
|
||||
"NoEmptyTrailingClosureParentheses": true,
|
||||
"NoLabelsInCasePatterns": true,
|
||||
"NoLeadingUnderscores": false,
|
||||
"NoParensAroundConditions": true,
|
||||
"NoVoidReturnOnFunctionSignature": true,
|
||||
"OneCasePerLine": true,
|
||||
"OneVariableDeclarationPerLine": true,
|
||||
"OnlyOneTrailingClosureArgument": true,
|
||||
"OrderedImports": true,
|
||||
"ReturnVoidInsteadOfEmptyTuple": true,
|
||||
"UseEarlyExits": true,
|
||||
"UseLetInEveryBoundCaseVariable": true,
|
||||
"UseShorthandTypeNames": true,
|
||||
"UseSingleLinePropertyGetter": true,
|
||||
"UseSynthesizedInitializer": true,
|
||||
"UseTripleSlashForDocumentationComments": true,
|
||||
"UseWhereClausesInForLoops": true,
|
||||
"ValidateDocumentationComments": true
|
||||
},
|
||||
"tabWidth": 8,
|
||||
"version": 1
|
||||
}
|
|
@ -2,6 +2,6 @@
|
|||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "container:../..">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// main.swift
|
||||
// graphql
|
||||
//
|
||||
// Created by Aaron Sky on 5/5/20.
|
||||
//
|
||||
|
||||
#if compiler(>=5.5.2) && canImport(_Concurrency)
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Buildkite
|
||||
|
||||
struct MyPipeline: Codable {
|
||||
var organization: Organization?
|
||||
|
||||
struct Organization: Codable {
|
||||
var pipelines: Pipelines
|
||||
|
||||
struct Pipelines: Codable {
|
||||
var edges: [PipelineEdge]
|
||||
|
||||
struct PipelineEdge: Codable {
|
||||
var node: Pipeline
|
||||
|
||||
struct Pipeline: Codable {
|
||||
var name: String
|
||||
var uuid: UUID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
|
||||
@main struct GraphQLExample {
|
||||
static func main() async {
|
||||
let client = BuildkiteClient()
|
||||
client.token = "..."
|
||||
|
||||
let query = """
|
||||
query MyPipelines($first: Int!) {
|
||||
organization(slug: "buildkite") {
|
||||
pipelines(first: $first) {
|
||||
edges {
|
||||
node {
|
||||
name
|
||||
uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
do {
|
||||
let pipelines = try await client.sendQuery(GraphQL<MyPipeline>(
|
||||
rawQuery: query,
|
||||
variables: ["first": 30]
|
||||
))
|
||||
print(pipelines)
|
||||
} catch {
|
||||
print(error)
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,62 +0,0 @@
|
|||
//
|
||||
// main.swift
|
||||
// graphql
|
||||
//
|
||||
// Created by Aaron Sky on 5/5/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Buildkite
|
||||
|
||||
let client = BuildkiteClient()
|
||||
client.token = "..."
|
||||
|
||||
let query = """
|
||||
query MyPipelines($first: Int!) {
|
||||
organization(slug: "buildkite") {
|
||||
pipelines(first: $first) {
|
||||
edges {
|
||||
node {
|
||||
name
|
||||
uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
struct MyPipeline: Codable {
|
||||
var organization: Organization?
|
||||
|
||||
struct Organization: Codable {
|
||||
var pipelines: Pipelines
|
||||
|
||||
struct Pipelines: Codable {
|
||||
var edges: [PipelineEdge]
|
||||
|
||||
struct PipelineEdge: Codable {
|
||||
var node: Pipeline
|
||||
|
||||
struct Pipeline: Codable {
|
||||
var name: String
|
||||
var uuid: UUID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client.sendQuery(GraphQL<MyPipeline>(rawQuery: query, variables: ["first": 30])) { result in
|
||||
do {
|
||||
let pipelines = try result.get()
|
||||
print(pipelines)
|
||||
exit(0)
|
||||
} catch {
|
||||
print(error)
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
RunLoop.main.run()
|
|
@ -0,0 +1,30 @@
|
|||
SWIFT_FORMAT_BIN := swift format
|
||||
GIT_REPO_TOPLEVEL := $(shell git rev-parse --show-toplevel)
|
||||
SWIFT_FORMAT_CONFIG_FILE := $(GIT_REPO_TOPLEVEL)/.swift-format.json
|
||||
|
||||
format:
|
||||
$(SWIFT_FORMAT_BIN) \
|
||||
--configuration $(SWIFT_FORMAT_CONFIG_FILE) \
|
||||
--ignore-unparsable-files \
|
||||
--in-place \
|
||||
--recursive \
|
||||
$(GIT_REPO_TOPLEVEL)/Package.swift $(GIT_REPO_TOPLEVEL)/Sources $(GIT_REPO_TOPLEVEL)/Tests
|
||||
|
||||
lint:
|
||||
$(SWIFT_FORMAT_BIN) lint \
|
||||
--configuration $(SWIFT_FORMAT_CONFIG_FILE) \
|
||||
--ignore-unparsable-files \
|
||||
--recursive \
|
||||
$(GIT_REPO_TOPLEVEL)/Package.swift $(GIT_REPO_TOPLEVEL)/Sources $(GIT_REPO_TOPLEVEL)/Tests
|
||||
|
||||
test:
|
||||
swift test --parallel --enable-code-coverage
|
||||
|
||||
coverage: test
|
||||
xcrun llvm-cov export \
|
||||
-format=lcov \
|
||||
-instr-profile=.build/arm64-apple-macosx/debug/codecov/default.profdata \
|
||||
.build/arm64-apple-macosx/debug/BuildkitePackageTests.xctest/Contents/MacOS/BuildkitePackageTests \
|
||||
> lcov.info
|
||||
|
||||
.PHONY: format lint test coverage
|
|
@ -8,12 +8,13 @@ let package = Package(
|
|||
.iOS(.v10),
|
||||
.macOS(.v10_12),
|
||||
.tvOS(.v10),
|
||||
.watchOS(.v3)
|
||||
.watchOS(.v3),
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "Buildkite",
|
||||
targets: ["Buildkite"])
|
||||
targets: ["Buildkite"]
|
||||
)
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
|
@ -34,6 +35,13 @@ let package = Package(
|
|||
.testTarget(
|
||||
name: "BuildkiteTests",
|
||||
dependencies: ["Buildkite"]
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
#if swift(>=5.6)
|
||||
// Add the documentation compiler plugin if possible
|
||||
package.dependencies.append(
|
||||
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0")
|
||||
)
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,7 @@ The entire publicly documented REST API surface is supported by this package.
|
|||
- ``Build/Resources``
|
||||
- ``Emoji/Resources``
|
||||
- ``Job/Resources``
|
||||
- ``Meta/Resources``
|
||||
- ``Organization/Resources``
|
||||
- ``Pipeline/Resources``
|
||||
- ``Team/Resources``
|
||||
|
@ -50,6 +51,7 @@ The entire publicly documented REST API surface is supported by this package.
|
|||
- ``Build``
|
||||
- ``Emoji``
|
||||
- ``Job``
|
||||
- ``Meta``
|
||||
- ``Organization``
|
||||
- ``Pipeline``
|
||||
- ``Team``
|
||||
|
|
|
@ -47,12 +47,17 @@ public final class BuildkiteClient {
|
|||
/// - Parameters:
|
||||
/// - configuration: Configures supported API versions and the access token. Uses the latest supported API versions by default. See ``token`` for setting the client access token if using the default configuration.
|
||||
/// - transport: Transport layer used for API communication. Uses the shared URLSession by default.
|
||||
public init(configuration: Configuration = .default, transport: Transport = URLSession.shared) {
|
||||
public init(
|
||||
configuration: Configuration = .default,
|
||||
transport: Transport = URLSession.shared
|
||||
) {
|
||||
self.configuration = configuration
|
||||
self.transport = transport
|
||||
}
|
||||
|
||||
private func handleContentfulResponse<Content: Decodable>(completion: @escaping (Result<Response<Content>, Error>) -> Void) -> Transport.Completion {
|
||||
private func handleContentfulResponse<Content: Decodable>(
|
||||
completion: @escaping (Result<Response<Content>, Error>) -> Void
|
||||
) -> Transport.Completion {
|
||||
return { [weak self] result in
|
||||
guard let self = self else {
|
||||
return
|
||||
|
@ -72,7 +77,9 @@ public final class BuildkiteClient {
|
|||
}
|
||||
}
|
||||
|
||||
private func handleEmptyResponse(completion: @escaping (Result<Response<Void>, Error>) -> Void) -> Transport.Completion {
|
||||
private func handleEmptyResponse(
|
||||
completion: @escaping (Result<Response<Void>, Error>) -> Void
|
||||
) -> Transport.Completion {
|
||||
return { [weak self] result in
|
||||
guard let self = self else {
|
||||
return
|
||||
|
@ -91,14 +98,16 @@ public final class BuildkiteClient {
|
|||
|
||||
private func checkResponseForIssues(_ response: URLResponse, data: Data? = nil) throws {
|
||||
guard let httpResponse = response as? HTTPURLResponse,
|
||||
let statusCode = StatusCode(rawValue: httpResponse.statusCode) else {
|
||||
throw ResponseError.incompatibleResponse(response)
|
||||
}
|
||||
let statusCode = StatusCode(rawValue: httpResponse.statusCode)
|
||||
else {
|
||||
throw ResponseError.incompatibleResponse(response)
|
||||
}
|
||||
if !statusCode.isSuccess {
|
||||
guard let data = data,
|
||||
let errorIntermediary = try? decoder.decode(BuildkiteError.Intermediary.self, from: data) else {
|
||||
throw statusCode
|
||||
}
|
||||
let errorIntermediary = try? decoder.decode(BuildkiteError.Intermediary.self, from: data)
|
||||
else {
|
||||
throw statusCode
|
||||
}
|
||||
throw BuildkiteError(statusCode: statusCode, intermediary: errorIntermediary)
|
||||
}
|
||||
}
|
||||
|
@ -106,12 +115,13 @@ public final class BuildkiteClient {
|
|||
|
||||
// MARK: - Closure API
|
||||
|
||||
public extension BuildkiteClient {
|
||||
extension BuildkiteClient {
|
||||
/// Performs the given resource asynchronously, then calls a handler upon completion.
|
||||
/// - Parameters:
|
||||
/// - resource:A resource.
|
||||
/// - completion:The completion handler to call when the operation has completed. This handler is called on whatever queue the transport layer is implemented to use. You should generally assume this is happening on a global background queue, such as the case when using the shared URLSession.
|
||||
func send<R>(_ resource: R, completion: @escaping (Result<Response<R.Content>, Error>) -> Void) where R: Resource, R.Content: Decodable {
|
||||
public func send<R>(_ resource: R, completion: @escaping (Result<Response<R.Content>, Error>) -> Void)
|
||||
where R: Resource, R.Content: Decodable {
|
||||
do {
|
||||
let request = try URLRequest(resource, configuration: configuration)
|
||||
transport.send(request: request, completion: handleContentfulResponse(completion: completion))
|
||||
|
@ -125,7 +135,11 @@ public extension BuildkiteClient {
|
|||
/// - resource:A resource.
|
||||
/// - pageOptions: Page options to perform pagination.
|
||||
/// - completion:The completion handler to call when the operation has completed. This handler is called on whatever queue the transport layer is implemented to use. You should generally assume this is happening on a global background queue, such as the case when using the shared URLSession.
|
||||
func send<R>(_ resource: R, pageOptions: PageOptions? = nil, completion: @escaping (Result<Response<R.Content>, Error>) -> Void) where R: PaginatedResource {
|
||||
public func send<R>(
|
||||
_ resource: R,
|
||||
pageOptions: PageOptions? = nil,
|
||||
completion: @escaping (Result<Response<R.Content>, Error>) -> Void
|
||||
) where R: PaginatedResource {
|
||||
do {
|
||||
let request = try URLRequest(resource, configuration: configuration, pageOptions: pageOptions)
|
||||
transport.send(request: request, completion: handleContentfulResponse(completion: completion))
|
||||
|
@ -138,7 +152,8 @@ public extension BuildkiteClient {
|
|||
/// - Parameters:
|
||||
/// - resource:A resource.
|
||||
/// - completion:The completion handler to call when the operation has completed. This handler is called on whatever queue the transport layer is implemented to use. You should generally assume this is happening on a global background queue, such as the case when using the shared URLSession.
|
||||
func send<R>(_ resource: R, completion: @escaping (Result<Response<R.Content>, Error>) -> Void) where R: Resource, R.Body: Encodable, R.Content: Decodable {
|
||||
public func send<R>(_ resource: R, completion: @escaping (Result<Response<R.Content>, Error>) -> Void)
|
||||
where R: Resource, R.Body: Encodable, R.Content: Decodable {
|
||||
do {
|
||||
let request = try URLRequest(resource, configuration: configuration, encoder: encoder)
|
||||
transport.send(request: request, completion: handleContentfulResponse(completion: completion))
|
||||
|
@ -152,9 +167,18 @@ public extension BuildkiteClient {
|
|||
/// - resource:A resource.
|
||||
/// - pageOptions: Page options to perform pagination.
|
||||
/// - completion:The completion handler to call when the operation has completed. This handler is called on whatever queue the transport layer is implemented to use. You should generally assume this is happening on a global background queue, such as the case when using the shared URLSession.
|
||||
func send<R>(_ resource: R, pageOptions: PageOptions? = nil, completion: @escaping (Result<Response<R.Content>, Error>) -> Void) where R: PaginatedResource, R.Body: Encodable {
|
||||
public func send<R>(
|
||||
_ resource: R,
|
||||
pageOptions: PageOptions? = nil,
|
||||
completion: @escaping (Result<Response<R.Content>, Error>) -> Void
|
||||
) where R: PaginatedResource, R.Body: Encodable {
|
||||
do {
|
||||
let request = try URLRequest(resource, configuration: configuration, encoder: encoder, pageOptions: pageOptions)
|
||||
let request = try URLRequest(
|
||||
resource,
|
||||
configuration: configuration,
|
||||
encoder: encoder,
|
||||
pageOptions: pageOptions
|
||||
)
|
||||
transport.send(request: request, completion: handleContentfulResponse(completion: completion))
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
|
@ -165,7 +189,8 @@ public extension BuildkiteClient {
|
|||
/// - Parameters:
|
||||
/// - resource:A resource.
|
||||
/// - completion:The completion handler to call when the operation has completed. This handler is called on whatever queue the transport layer is implemented to use. You should generally assume this is happening on a global background queue, such as the case when using the shared URLSession.
|
||||
func send<R>(_ resource: R, completion: @escaping (Result<Response<R.Content>, Error>) -> Void) where R: Resource, R.Content == Void {
|
||||
public func send<R>(_ resource: R, completion: @escaping (Result<Response<R.Content>, Error>) -> Void)
|
||||
where R: Resource, R.Content == Void {
|
||||
do {
|
||||
let request = try URLRequest(resource, configuration: configuration)
|
||||
transport.send(request: request, completion: handleEmptyResponse(completion: completion))
|
||||
|
@ -178,7 +203,8 @@ public extension BuildkiteClient {
|
|||
/// - Parameters:
|
||||
/// - resource:A resource.
|
||||
/// - completion:The completion handler to call when the operation has completed. This handler is called on whatever queue the transport layer is implemented to use. You should generally assume this is happening on a global background queue, such as the case when using the shared URLSession.
|
||||
func send<R>(_ resource: R, completion: @escaping (Result<Response<R.Content>, Error>) -> Void) where R: Resource, R.Body: Encodable, R.Content == Void {
|
||||
public func send<R>(_ resource: R, completion: @escaping (Result<Response<R.Content>, Error>) -> Void)
|
||||
where R: Resource, R.Body: Encodable, R.Content == Void {
|
||||
do {
|
||||
let request = try URLRequest(resource, configuration: configuration, encoder: encoder)
|
||||
transport.send(request: request, completion: handleEmptyResponse(completion: completion))
|
||||
|
@ -191,7 +217,7 @@ public extension BuildkiteClient {
|
|||
/// - Parameters:
|
||||
/// - resource:A resource.
|
||||
/// - completion:The completion handler to call when the operation has completed. This handler is called on whatever queue the transport layer is implemented to use. You should generally assume this is happening on a global background queue, such as the case when using the shared URLSession.
|
||||
func sendQuery<T>(_ resource: GraphQL<T>, completion: @escaping (Result<T, Error>) -> Void) {
|
||||
public func sendQuery<T>(_ resource: GraphQL<T>, completion: @escaping (Result<T, Error>) -> Void) {
|
||||
send(resource) { result in
|
||||
do {
|
||||
switch (try result.get()).content {
|
||||
|
@ -213,20 +239,21 @@ public extension BuildkiteClient {
|
|||
import Combine
|
||||
|
||||
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
|
||||
public extension BuildkiteClient {
|
||||
extension BuildkiteClient {
|
||||
/// Performs the given resource and publishes the response asynchronously.
|
||||
/// - Parameter resource: A resource.
|
||||
/// - Returns: The publisher publishes the response when the operation completes, or terminates if the operation fails with an error.
|
||||
func sendPublisher<R>(_ resource: R) -> AnyPublisher<Response<R.Content>, Error> where R: Resource, R.Content: Decodable {
|
||||
public func sendPublisher<R>(_ resource: R) -> AnyPublisher<Response<R.Content>, Error>
|
||||
where R: Resource, R.Content: Decodable {
|
||||
Result { try URLRequest(resource, configuration: configuration) }
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response, data: $0.data)
|
||||
let content = try self.decoder.decode(R.Content.self, from: $0.data)
|
||||
return Response(content: content, response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response, data: $0.data)
|
||||
let content = try self.decoder.decode(R.Content.self, from: $0.data)
|
||||
return Response(content: content, response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
/// Performs the given resource and publishes the response asynchronously.
|
||||
|
@ -234,31 +261,35 @@ public extension BuildkiteClient {
|
|||
/// - resource: A resource.
|
||||
/// - pageOptions: Page options to perform pagination.
|
||||
/// - Returns: The publisher publishes the response when the operation completes, or terminates if the operation fails with an error.
|
||||
func sendPublisher<R>(_ resource: R, pageOptions: PageOptions? = nil) -> AnyPublisher<Response<R.Content>, Error> where R: PaginatedResource {
|
||||
public func sendPublisher<R>(
|
||||
_ resource: R,
|
||||
pageOptions: PageOptions? = nil
|
||||
) -> AnyPublisher<Response<R.Content>, Error> where R: PaginatedResource {
|
||||
Result { try URLRequest(resource, configuration: configuration, pageOptions: pageOptions) }
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response, data: $0.data)
|
||||
let content = try self.decoder.decode(R.Content.self, from: $0.data)
|
||||
return Response(content: content, response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response, data: $0.data)
|
||||
let content = try self.decoder.decode(R.Content.self, from: $0.data)
|
||||
return Response(content: content, response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
/// Performs the given resource and publishes the response asynchronously.
|
||||
/// - Parameter resource: A resource.
|
||||
/// - Returns: The publisher publishes the response when the operation completes, or terminates if the operation fails with an error.
|
||||
func sendPublisher<R>(_ resource: R) -> AnyPublisher<Response<R.Content>, Error> where R: Resource, R.Body: Encodable, R.Content: Decodable {
|
||||
public func sendPublisher<R>(_ resource: R) -> AnyPublisher<Response<R.Content>, Error>
|
||||
where R: Resource, R.Body: Encodable, R.Content: Decodable {
|
||||
Result { try URLRequest(resource, configuration: configuration, encoder: encoder) }
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response, data: $0.data)
|
||||
let content = try self.decoder.decode(R.Content.self, from: $0.data)
|
||||
return Response(content: content, response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response, data: $0.data)
|
||||
let content = try self.decoder.decode(R.Content.self, from: $0.data)
|
||||
return Response(content: content, response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
/// Performs the given resource and publishes the response asynchronously.
|
||||
|
@ -266,50 +297,55 @@ public extension BuildkiteClient {
|
|||
/// - resource: A resource.
|
||||
/// - pageOptions: Page options to perform pagination.
|
||||
/// - Returns: The publisher publishes the response when the operation completes, or terminates if the operation fails with an error.
|
||||
func sendPublisher<R>(_ resource: R, pageOptions: PageOptions? = nil) -> AnyPublisher<Response<R.Content>, Error> where R: PaginatedResource, R.Body: Encodable {
|
||||
public func sendPublisher<R>(
|
||||
_ resource: R,
|
||||
pageOptions: PageOptions? = nil
|
||||
) -> AnyPublisher<Response<R.Content>, Error> where R: PaginatedResource, R.Body: Encodable {
|
||||
Result { try URLRequest(resource, configuration: configuration, encoder: encoder, pageOptions: pageOptions) }
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response, data: $0.data)
|
||||
let content = try self.decoder.decode(R.Content.self, from: $0.data)
|
||||
return Response(content: content, response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response, data: $0.data)
|
||||
let content = try self.decoder.decode(R.Content.self, from: $0.data)
|
||||
return Response(content: content, response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
/// Performs the given resource and publishes the response asynchronously.
|
||||
/// - Parameter resource: A resource.
|
||||
/// - Returns: The publisher publishes the response when the operation completes, or terminates if the operation fails with an error.
|
||||
func sendPublisher<R>(_ resource: R) -> AnyPublisher<Response<R.Content>, Error> where R: Resource, R.Content == Void {
|
||||
public func sendPublisher<R>(_ resource: R) -> AnyPublisher<Response<R.Content>, Error>
|
||||
where R: Resource, R.Content == Void {
|
||||
Result { try URLRequest(resource, configuration: configuration) }
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response)
|
||||
return Response(content: (), response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response)
|
||||
return Response(content: (), response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
/// Performs the given resource and publishes the response asynchronously.
|
||||
/// - Parameter resource: A resource.
|
||||
/// - Returns: The publisher publishes the response when the operation completes, or terminates if the operation fails with an error.
|
||||
func sendPublisher<R>(_ resource: R) -> AnyPublisher<Response<R.Content>, Error> where R: Resource, R.Body: Encodable, R.Content == Void {
|
||||
public func sendPublisher<R>(_ resource: R) -> AnyPublisher<Response<R.Content>, Error>
|
||||
where R: Resource, R.Body: Encodable, R.Content == Void {
|
||||
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()
|
||||
.publisher
|
||||
.flatMap(transport.sendPublisher)
|
||||
.tryMap {
|
||||
try self.checkResponseForIssues($0.response)
|
||||
return Response(content: (), response: $0.response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
/// Performs the given GraphQL query or mutation and publishes the content asynchronously.
|
||||
/// - Parameter resource: A resource.
|
||||
/// - Returns: The publisher publishes the content when the operation completes, or terminates if the operation fails with an error.
|
||||
func sendQueryPublisher<T>(_ resource: GraphQL<T>) -> AnyPublisher<T, Error> {
|
||||
public func sendQueryPublisher<T>(_ resource: GraphQL<T>) -> AnyPublisher<T, Error> {
|
||||
sendPublisher(resource)
|
||||
.map(\.content)
|
||||
.tryMap { try $0.get() }
|
||||
|
@ -323,11 +359,11 @@ public extension BuildkiteClient {
|
|||
// MARK: - Async/Await API
|
||||
|
||||
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
|
||||
public extension BuildkiteClient {
|
||||
extension BuildkiteClient {
|
||||
/// Performs the given resource asynchronously.
|
||||
/// - Parameter resource: A resource.
|
||||
/// - Returns: A response containing the content of the response body, as well as other information about the HTTP operation.
|
||||
func send<R>(_ resource: R) async throws -> Response<R.Content> where R: Resource, R.Content: Decodable {
|
||||
public func send<R>(_ resource: R) async throws -> Response<R.Content> where R: Resource, R.Content: Decodable {
|
||||
let request = try URLRequest(resource, configuration: configuration)
|
||||
let (data, response) = try await transport.send(request: request)
|
||||
try checkResponseForIssues(response, data: data)
|
||||
|
@ -340,7 +376,8 @@ public extension BuildkiteClient {
|
|||
/// - resource: A resource.
|
||||
/// - pageOptions: Page options to perform pagination.
|
||||
/// - Returns: A response containing the content of the response body, as well as other information about the HTTP operation.
|
||||
func send<R>(_ resource: R, pageOptions: PageOptions? = nil) async throws -> Response<R.Content> where R: PaginatedResource {
|
||||
public func send<R>(_ resource: R, pageOptions: PageOptions? = nil) async throws -> Response<R.Content>
|
||||
where R: PaginatedResource {
|
||||
let request = try URLRequest(resource, configuration: configuration, pageOptions: pageOptions)
|
||||
let (data, response) = try await transport.send(request: request)
|
||||
try checkResponseForIssues(response, data: data)
|
||||
|
@ -351,7 +388,8 @@ public extension BuildkiteClient {
|
|||
/// Performs the given resource asynchronously.
|
||||
/// - Parameter resource: A resource.
|
||||
/// - Returns: A response containing the content of the response body, as well as other information about the HTTP operation.
|
||||
func send<R>(_ resource: R) async throws -> Response<R.Content> where R: Resource, R.Body: Encodable, R.Content: Decodable {
|
||||
public func send<R>(_ resource: R) async throws -> Response<R.Content>
|
||||
where R: Resource, R.Body: Encodable, R.Content: Decodable {
|
||||
let request = try URLRequest(resource, configuration: configuration, encoder: encoder)
|
||||
let (data, response) = try await transport.send(request: request)
|
||||
try checkResponseForIssues(response, data: data)
|
||||
|
@ -364,7 +402,8 @@ public extension BuildkiteClient {
|
|||
/// - resource: A resource.
|
||||
/// - pageOptions: Page options to perform pagination.
|
||||
/// - Returns: A response containing the content of the response body, as well as other information about the HTTP operation.
|
||||
func send<R>(_ resource: R, pageOptions: PageOptions? = nil) async throws -> Response<R.Content> where R: PaginatedResource, R.Body: Encodable {
|
||||
public func send<R>(_ resource: R, pageOptions: PageOptions? = nil) async throws -> Response<R.Content>
|
||||
where R: PaginatedResource, R.Body: Encodable {
|
||||
let request = try URLRequest(resource, configuration: configuration, encoder: encoder, pageOptions: pageOptions)
|
||||
|
||||
let (data, response) = try await transport.send(request: request)
|
||||
|
@ -376,7 +415,7 @@ public extension BuildkiteClient {
|
|||
/// Performs the given resource asynchronously.
|
||||
/// - Parameter resource: A resource.
|
||||
/// - Returns: A response containing the content of the response body, as well as other information about the HTTP operation.
|
||||
func send<R>(_ resource: R) async throws -> Response<R.Content> where R: Resource, R.Content == Void {
|
||||
public func send<R>(_ resource: R) async throws -> Response<R.Content> where R: Resource, R.Content == Void {
|
||||
let request = try URLRequest(resource, configuration: configuration)
|
||||
let (data, response) = try await transport.send(request: request)
|
||||
try checkResponseForIssues(response, data: data)
|
||||
|
@ -386,7 +425,8 @@ public extension BuildkiteClient {
|
|||
/// Performs the given resource asynchronously.
|
||||
/// - Parameter resource: A resource.
|
||||
/// - Returns: A response containing information about the HTTP operation, and no content.
|
||||
func send<R>(_ resource: R) async throws -> Response<R.Content> where R: Resource, R.Body: Encodable, R.Content == Void {
|
||||
public func send<R>(_ resource: R) async throws -> Response<R.Content>
|
||||
where R: Resource, R.Body: Encodable, R.Content == Void {
|
||||
let request = try URLRequest(resource, configuration: configuration, encoder: encoder)
|
||||
let (data, response) = try await transport.send(request: request)
|
||||
try checkResponseForIssues(response, data: data)
|
||||
|
@ -397,7 +437,7 @@ public extension BuildkiteClient {
|
|||
/// - Parameter resource: A resource.
|
||||
/// - Returns: Content of the resolved GraphQL operation.
|
||||
/// - Throws: An error either of type ``BuildkiteError`` or ``GraphQL/Errors``.
|
||||
func sendQuery<T>(_ resource: GraphQL<T>) async throws -> T {
|
||||
public func sendQuery<T>(_ resource: GraphQL<T>) async throws -> T {
|
||||
let response = try await send(resource)
|
||||
return try response.content.get()
|
||||
}
|
||||
|
|
|
@ -25,7 +25,9 @@ public enum Job: Codable, Equatable {
|
|||
case trigger
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
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 {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// Meta.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/29/22.
|
||||
// Copyright © 2022 Aaron Sky. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
public struct Meta: Codable, Equatable {
|
||||
/// A list of IP addresses in CIDR notation that Buildkite uses to
|
||||
/// send outbound traffic such as webhooks and commit statuses.
|
||||
/// These are subject to change from time to time.
|
||||
///
|
||||
/// Buildkite recommends checking for new addresses daily, and
|
||||
/// will try to advertise new addresses for at least 7 days
|
||||
/// before they are used.
|
||||
public var webhookIPRanges: [String]
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
// This corresponds to the key "webhook_ips" from the Buildkite payload.
|
||||
case webhookIPRanges = "webhookIps"
|
||||
}
|
||||
}
|
|
@ -93,7 +93,9 @@ extension Pipeline {
|
|||
case trigger
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
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 {
|
||||
|
|
|
@ -26,7 +26,10 @@ public struct APIVersion: Equatable {
|
|||
public let baseURL: URL
|
||||
public let version: String
|
||||
|
||||
init(baseURL: URL, version: String) {
|
||||
init(
|
||||
baseURL: URL,
|
||||
version: String
|
||||
) {
|
||||
self.baseURL = baseURL
|
||||
self.version = version
|
||||
}
|
||||
|
|
|
@ -18,11 +18,16 @@ public struct Configuration {
|
|||
public var graphQLVersion: APIVersion
|
||||
|
||||
public static var `default`: Configuration {
|
||||
.init(version: APIVersion.REST.v2,
|
||||
graphQLVersion: APIVersion.GraphQL.v1)
|
||||
.init(
|
||||
version: APIVersion.REST.v2,
|
||||
graphQLVersion: APIVersion.GraphQL.v1
|
||||
)
|
||||
}
|
||||
|
||||
public init(version: APIVersion = APIVersion.REST.v2, graphQLVersion: APIVersion = APIVersion.GraphQL.v1) {
|
||||
public init(
|
||||
version: APIVersion = APIVersion.REST.v2,
|
||||
graphQLVersion: APIVersion = APIVersion.GraphQL.v1
|
||||
) {
|
||||
self.version = version
|
||||
self.graphQLVersion = graphQLVersion
|
||||
}
|
||||
|
|
|
@ -49,7 +49,12 @@ enum Formatters {
|
|||
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."))
|
||||
throw DecodingError.dataCorrupted(
|
||||
DecodingError.Context(
|
||||
codingPath: container.codingPath,
|
||||
debugDescription: "Expected date string to be ISO8601-formatted."
|
||||
)
|
||||
)
|
||||
}
|
||||
return date
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ public enum JSONValue {
|
|||
indirect case object([String: JSONValue])
|
||||
}
|
||||
|
||||
public extension JSONValue {
|
||||
subscript(dynamicMember key: JSONValue) -> JSONValue? {
|
||||
extension JSONValue {
|
||||
public subscript(dynamicMember key: JSONValue) -> JSONValue? {
|
||||
self[key]
|
||||
}
|
||||
|
||||
subscript(_ key: JSONValue) -> JSONValue? {
|
||||
public subscript(_ key: JSONValue) -> JSONValue? {
|
||||
if case let .number(key) = key {
|
||||
return self[Int(key)]
|
||||
} else if case let .string(key) = key {
|
||||
|
@ -38,14 +38,14 @@ public extension JSONValue {
|
|||
return nil
|
||||
}
|
||||
|
||||
subscript(_ index: Int) -> JSONValue? {
|
||||
public subscript(_ index: Int) -> JSONValue? {
|
||||
guard case let .array(array) = self else {
|
||||
return nil
|
||||
}
|
||||
return array[index]
|
||||
}
|
||||
|
||||
subscript(_ key: String) -> JSONValue? {
|
||||
public subscript(_ key: String) -> JSONValue? {
|
||||
guard case let .object(object) = self else {
|
||||
return nil
|
||||
}
|
||||
|
@ -76,7 +76,9 @@ extension JSONValue: Encodable {
|
|||
}
|
||||
|
||||
extension JSONValue: Decodable {
|
||||
public init(from decoder: Decoder) throws {
|
||||
public init(
|
||||
from decoder: Decoder
|
||||
) throws {
|
||||
let singleValueContainer = try decoder.singleValueContainer()
|
||||
|
||||
if singleValueContainer.decodeNil() {
|
||||
|
@ -94,49 +96,64 @@ extension JSONValue: Decodable {
|
|||
} else {
|
||||
throw DecodingError.dataCorruptedError(
|
||||
in: singleValueContainer,
|
||||
debugDescription: "invalid JSON structure or the input was not JSON")
|
||||
debugDescription: "invalid JSON structure or the input was not JSON"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONValue: ExpressibleByNilLiteral {
|
||||
public init(nilLiteral: Void) {
|
||||
public init(
|
||||
nilLiteral: Void
|
||||
) {
|
||||
self = .null
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONValue: ExpressibleByBooleanLiteral {
|
||||
public init(booleanLiteral value: BooleanLiteralType) {
|
||||
public init(
|
||||
booleanLiteral value: BooleanLiteralType
|
||||
) {
|
||||
self = .bool(value)
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONValue: ExpressibleByIntegerLiteral {
|
||||
public init(integerLiteral value: IntegerLiteralType) {
|
||||
public init(
|
||||
integerLiteral value: IntegerLiteralType
|
||||
) {
|
||||
self = .number(Double(value))
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONValue: ExpressibleByFloatLiteral {
|
||||
public init(floatLiteral value: FloatLiteralType) {
|
||||
public init(
|
||||
floatLiteral value: FloatLiteralType
|
||||
) {
|
||||
self = .number(value)
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONValue: ExpressibleByStringLiteral {
|
||||
public init(stringLiteral value: StringLiteralType) {
|
||||
public init(
|
||||
stringLiteral value: StringLiteralType
|
||||
) {
|
||||
self = .string(value)
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONValue: ExpressibleByArrayLiteral {
|
||||
public init(arrayLiteral elements: JSONValue...) {
|
||||
public init(
|
||||
arrayLiteral elements: JSONValue...
|
||||
) {
|
||||
self = .array(elements)
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONValue: ExpressibleByDictionaryLiteral {
|
||||
public init(dictionaryLiteral elements: (String, JSONValue)...) {
|
||||
public init(
|
||||
dictionaryLiteral elements: (String, JSONValue)...
|
||||
) {
|
||||
self = .object(Dictionary(uniqueKeysWithValues: elements))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,16 @@ public struct Page {
|
|||
public var firstPage: Int?
|
||||
public var lastPage: Int?
|
||||
|
||||
init?(for header: String) {
|
||||
init?(
|
||||
for header: String
|
||||
) {
|
||||
guard !header.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
for link in header.split(separator: ",") {
|
||||
let segments = link
|
||||
let segments =
|
||||
link
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
.split(separator: ";")
|
||||
guard
|
||||
|
@ -36,8 +39,9 @@ public struct Page {
|
|||
let url = URLComponents(string: String(urlString.dropFirst().dropLast())),
|
||||
|
||||
let pageString = url.queryItems?.first(where: { $0.name == "page" })?.value,
|
||||
let page = Int(pageString) else {
|
||||
continue
|
||||
let page = Int(pageString)
|
||||
else {
|
||||
continue
|
||||
}
|
||||
|
||||
for segment in segments.dropFirst() {
|
||||
|
@ -62,7 +66,10 @@ public struct PageOptions {
|
|||
public var page: Int
|
||||
public var perPage: Int
|
||||
|
||||
public init(page: Int, perPage: Int) {
|
||||
public init(
|
||||
page: Int,
|
||||
perPage: Int
|
||||
) {
|
||||
self.page = page
|
||||
self.perPage = perPage
|
||||
}
|
||||
|
@ -71,8 +78,9 @@ public struct PageOptions {
|
|||
extension URLRequest {
|
||||
mutating func appendPageOptions(_ options: PageOptions) {
|
||||
guard let url = self.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true)
|
||||
else {
|
||||
return
|
||||
}
|
||||
var queryItems = components.queryItems ?? []
|
||||
queryItems.append(pageOptions: options)
|
||||
|
@ -81,8 +89,8 @@ extension URLRequest {
|
|||
}
|
||||
}
|
||||
|
||||
private extension Array where Element == URLQueryItem {
|
||||
mutating func append(pageOptions: PageOptions) {
|
||||
extension Array where Element == URLQueryItem {
|
||||
fileprivate mutating func append(pageOptions: PageOptions) {
|
||||
append(URLQueryItem(name: "page", value: String(pageOptions.page)))
|
||||
append(URLQueryItem(name: "per_page", value: String(pageOptions.perPage)))
|
||||
}
|
||||
|
|
|
@ -43,11 +43,16 @@ extension Resource where Body == Void {
|
|||
public protocol PaginatedResource: Resource where Content: Decodable {}
|
||||
|
||||
extension URLRequest {
|
||||
init<R: Resource>(_ resource: R, configuration: Configuration) throws {
|
||||
init<R: Resource>(
|
||||
_ resource: R,
|
||||
configuration: Configuration
|
||||
) throws {
|
||||
let version = resource.version
|
||||
guard version == configuration.version
|
||||
|| version == configuration.graphQLVersion else {
|
||||
throw ResourceError.incompatibleVersion(version)
|
||||
guard
|
||||
version == configuration.version
|
||||
|| version == configuration.graphQLVersion
|
||||
else {
|
||||
throw ResourceError.incompatibleVersion(version)
|
||||
}
|
||||
|
||||
let url = version.url(for: resource.path)
|
||||
|
@ -58,19 +63,32 @@ extension URLRequest {
|
|||
self = request
|
||||
}
|
||||
|
||||
init<R: Resource>(_ resource: R, configuration: Configuration, encoder: JSONEncoder) throws where R.Body: Encodable {
|
||||
init<R: Resource>(
|
||||
_ resource: R,
|
||||
configuration: Configuration,
|
||||
encoder: JSONEncoder
|
||||
) throws where R.Body: Encodable {
|
||||
try self.init(resource, configuration: configuration)
|
||||
httpBody = try encoder.encode(resource.body)
|
||||
}
|
||||
|
||||
init<R: Resource & PaginatedResource>(_ resource: R, configuration: Configuration, pageOptions: PageOptions? = nil) throws {
|
||||
init<R: Resource & PaginatedResource>(
|
||||
_ resource: R,
|
||||
configuration: Configuration,
|
||||
pageOptions: PageOptions? = nil
|
||||
) throws {
|
||||
try self.init(resource, configuration: configuration)
|
||||
if let options = pageOptions {
|
||||
appendPageOptions(options)
|
||||
}
|
||||
}
|
||||
|
||||
init<R: Resource & PaginatedResource>(_ resource: R, configuration: Configuration, encoder: JSONEncoder, pageOptions: PageOptions? = nil) throws where R.Body: Encodable {
|
||||
init<R: Resource & PaginatedResource>(
|
||||
_ resource: R,
|
||||
configuration: Configuration,
|
||||
encoder: JSONEncoder,
|
||||
pageOptions: PageOptions? = nil
|
||||
) throws where R.Body: Encodable {
|
||||
try self.init(resource, configuration: configuration, encoder: encoder)
|
||||
if let options = pageOptions {
|
||||
appendPageOptions(options)
|
||||
|
|
|
@ -17,7 +17,10 @@ public struct Response<T> {
|
|||
public let response: URLResponse
|
||||
public let page: Page?
|
||||
|
||||
init(content: T, response: URLResponse) {
|
||||
init(
|
||||
content: T,
|
||||
response: URLResponse
|
||||
) {
|
||||
self.content = content
|
||||
self.response = response
|
||||
if let response = response as? HTTPURLResponse, let link = response.allHeaderFields["Link"] as? String {
|
||||
|
@ -37,7 +40,10 @@ public struct BuildkiteError: Error {
|
|||
public var message: String
|
||||
public var errors: [String]
|
||||
|
||||
init(statusCode: StatusCode, intermediary: Intermediary) {
|
||||
init(
|
||||
statusCode: StatusCode,
|
||||
intermediary: Intermediary
|
||||
) {
|
||||
self.statusCode = statusCode
|
||||
self.message = intermediary.message ?? ""
|
||||
self.errors = intermediary.errors ?? []
|
||||
|
|
|
@ -26,15 +26,15 @@ public protocol Transport {
|
|||
|
||||
func send(request: URLRequest, completion: @escaping Completion)
|
||||
|
||||
#if canImport(Combine)
|
||||
#if canImport(Combine)
|
||||
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
|
||||
func sendPublisher(request: URLRequest) -> AnyPublisher<Output, Error>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if compiler(>=5.5.2) && canImport(_Concurrency)
|
||||
#if compiler(>=5.5.2) && canImport(_Concurrency)
|
||||
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
|
||||
func send(request: URLRequest) async throws -> Output
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
extension URLSession: Transport {
|
||||
|
@ -53,31 +53,30 @@ extension URLSession: Transport {
|
|||
task.resume()
|
||||
}
|
||||
|
||||
#if canImport(Combine)
|
||||
#if canImport(Combine)
|
||||
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
|
||||
public func sendPublisher(request: URLRequest) -> AnyPublisher<Output, Error> {
|
||||
dataTaskPublisher(for: request)
|
||||
.mapError { $0 as Error }
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if compiler(>=5.5.2) && canImport(_Concurrency)
|
||||
#if compiler(>=5.5.2) && canImport(_Concurrency)
|
||||
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
|
||||
public func send(request: URLRequest) async throws -> Output {
|
||||
if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) {
|
||||
return try await data(for: request)
|
||||
} else {
|
||||
guard #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) else {
|
||||
return try await withCheckedThrowingContinuation { continuation in
|
||||
let task = dataTask(with: request) { data, response, error in
|
||||
if let error = error {
|
||||
continuation.resume(throwing: error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
guard let data = data,
|
||||
let response = response else {
|
||||
continuation.resume(throwing: TransportError.noResponse)
|
||||
let response = response
|
||||
else {
|
||||
continuation.resume(throwing: TransportError.noResponse)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -86,6 +85,7 @@ extension URLSession: Transport {
|
|||
task.resume()
|
||||
}
|
||||
}
|
||||
return try await data(for: request)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -40,25 +40,36 @@ extension Array where Element == URLQueryItem {
|
|||
} else if items.count == 1 {
|
||||
appendIfNeeded(items.first, forKey: key)
|
||||
} else {
|
||||
append(contentsOf: items
|
||||
.enumerated()
|
||||
.map {
|
||||
URLQueryItem(name: "\(key)\(arrayFormat.format(for: $0.offset))",
|
||||
value: $0.element)
|
||||
})
|
||||
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)
|
||||
})
|
||||
append(
|
||||
contentsOf: items.map {
|
||||
URLQueryItem(
|
||||
name: "\(key)[\($0.key)]",
|
||||
value: $0.value
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension Date: LosslessStringConvertible {
|
||||
public init?(_ description: String) {
|
||||
public init?(
|
||||
_ description: String
|
||||
) {
|
||||
guard let date = Formatters.dateIfPossible(fromISO8601: description) else {
|
||||
return nil
|
||||
}
|
||||
|
@ -67,7 +78,9 @@ extension Date: LosslessStringConvertible {
|
|||
}
|
||||
|
||||
extension UUID: LosslessStringConvertible {
|
||||
public init?(_ description: String) {
|
||||
public init?(
|
||||
_ description: String
|
||||
) {
|
||||
guard let id = UUID(uuidString: description) else {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -37,14 +37,17 @@ extension Agent.Resources {
|
|||
"organizations/\(organization)/agents"
|
||||
}
|
||||
|
||||
public init(organization: String) {
|
||||
public init(
|
||||
organization: String
|
||||
) {
|
||||
self.organization = organization
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true)
|
||||
else {
|
||||
return
|
||||
}
|
||||
var queryItems: [URLQueryItem] = []
|
||||
queryItems.appendIfNeeded(name, forKey: "name")
|
||||
|
@ -67,7 +70,10 @@ extension Agent.Resources {
|
|||
"organizations/\(organization)/agents/\(agentId)"
|
||||
}
|
||||
|
||||
public init(organization: String, agentId: UUID) {
|
||||
public init(
|
||||
organization: String,
|
||||
agentId: UUID
|
||||
) {
|
||||
self.organization = organization
|
||||
self.agentId = agentId
|
||||
}
|
||||
|
@ -88,7 +94,9 @@ extension Agent.Resources {
|
|||
/// If the agent is currently processing a job, the job and the build will be canceled.
|
||||
public var force: Bool?
|
||||
|
||||
public init(force: Bool? = nil) {
|
||||
public init(
|
||||
force: Bool? = nil
|
||||
) {
|
||||
self.force = force
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +105,11 @@ extension Agent.Resources {
|
|||
"organizations/\(organization)/agents/\(agentId)/stop"
|
||||
}
|
||||
|
||||
public init(organization: String, agentId: UUID, force: Bool? = nil) {
|
||||
public init(
|
||||
organization: String,
|
||||
agentId: UUID,
|
||||
force: Bool? = nil
|
||||
) {
|
||||
self.organization = organization
|
||||
self.agentId = agentId
|
||||
self.body = Body(force: force)
|
||||
|
|
|
@ -33,7 +33,11 @@ extension Annotation.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/annotations"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
|
|
@ -33,7 +33,11 @@ extension Artifact.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/artifacts"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -58,7 +62,12 @@ extension Artifact.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, jobId: UUID) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
jobId: UUID
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -84,7 +93,13 @@ extension Artifact.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts/\(artifactId)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, jobId: UUID, artifactId: UUID) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
jobId: UUID,
|
||||
artifactId: UUID
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -113,7 +128,13 @@ extension Artifact.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts/\(artifactId)/download"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, jobId: UUID, artifactId: UUID) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
jobId: UUID,
|
||||
artifactId: UUID
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -141,7 +162,13 @@ extension Artifact.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts/\(artifactId)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, jobId: UUID, artifactId: UUID) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
jobId: UUID,
|
||||
artifactId: UUID
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -174,13 +201,25 @@ extension Resource where Self == Artifact.Resources.Get {
|
|||
}
|
||||
|
||||
extension Resource where Self == Artifact.Resources.Download {
|
||||
public static func downloadArtifact(_ id: UUID, in organization: String, pipeline: String, build: Int, job: UUID) -> Self {
|
||||
public static func downloadArtifact(
|
||||
_ id: UUID,
|
||||
in organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
job: UUID
|
||||
) -> Self {
|
||||
Self(organization: organization, pipeline: pipeline, build: build, jobId: job, artifactId: id)
|
||||
}
|
||||
}
|
||||
|
||||
extension Resource where Self == Artifact.Resources.Delete {
|
||||
public static func deleteArtifact(_ id: UUID, in organization: String, pipeline: String, build: Int, job: UUID) -> Self {
|
||||
public static func deleteArtifact(
|
||||
_ id: UUID,
|
||||
in organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
job: UUID
|
||||
) -> Self {
|
||||
Self(organization: organization, pipeline: pipeline, build: build, jobId: job, artifactId: id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,14 +27,17 @@ extension Build.Resources {
|
|||
|
||||
public var queryOptions: QueryOptions?
|
||||
|
||||
public init(queryOptions: Build.Resources.QueryOptions? = nil) {
|
||||
public init(
|
||||
queryOptions: Build.Resources.QueryOptions? = nil
|
||||
) {
|
||||
self.queryOptions = queryOptions
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true)
|
||||
else {
|
||||
return
|
||||
}
|
||||
var queryItems: [URLQueryItem] = []
|
||||
if let options = queryOptions {
|
||||
|
@ -60,15 +63,19 @@ extension Build.Resources {
|
|||
"organizations/\(organization)/builds"
|
||||
}
|
||||
|
||||
public init(organization: String, queryOptions: Build.Resources.QueryOptions? = nil) {
|
||||
public init(
|
||||
organization: String,
|
||||
queryOptions: Build.Resources.QueryOptions? = nil
|
||||
) {
|
||||
self.organization = organization
|
||||
self.queryOptions = queryOptions
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true)
|
||||
else {
|
||||
return
|
||||
}
|
||||
var queryItems: [URLQueryItem] = []
|
||||
if let options = queryOptions {
|
||||
|
@ -95,7 +102,11 @@ extension Build.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, queryOptions: Build.Resources.QueryOptions? = nil) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
queryOptions: Build.Resources.QueryOptions? = nil
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.queryOptions = queryOptions
|
||||
|
@ -103,8 +114,9 @@ extension Build.Resources {
|
|||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true)
|
||||
else {
|
||||
return
|
||||
}
|
||||
var queryItems: [URLQueryItem] = []
|
||||
if let options = queryOptions {
|
||||
|
@ -129,7 +141,11 @@ extension Build.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -151,7 +167,10 @@ extension Build.Resources {
|
|||
public var name: String
|
||||
public var email: String
|
||||
|
||||
public init(name: String, email: String) {
|
||||
public init(
|
||||
name: String,
|
||||
email: String
|
||||
) {
|
||||
self.name = name
|
||||
self.email = email
|
||||
}
|
||||
|
@ -181,7 +200,19 @@ extension Build.Resources {
|
|||
/// For a pull request build, the git repository of the pull request.
|
||||
public var pullRequestRepository: String?
|
||||
|
||||
public init(commit: String, branch: String, author: 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) {
|
||||
public init(
|
||||
commit: String,
|
||||
branch: String,
|
||||
author: 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
|
||||
|
@ -201,7 +232,11 @@ extension Build.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, body: Body) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
body: Body
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.body = body
|
||||
|
@ -228,7 +263,11 @@ extension Build.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/cancel"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -255,7 +294,11 @@ extension Build.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/rebuild"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -286,7 +329,17 @@ extension Build.Resources {
|
|||
/// 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: [Build.State]
|
||||
|
||||
public 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: [Build.State] = []) {
|
||||
public 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: [Build.State] = []
|
||||
) {
|
||||
self.branches = branches
|
||||
self.commit = commit
|
||||
self.createdFrom = createdFrom
|
||||
|
@ -300,8 +353,10 @@ extension Build.Resources {
|
|||
}
|
||||
}
|
||||
|
||||
private extension Array where Element == URLQueryItem {
|
||||
init(queryOptions: Build.Resources.QueryOptions) {
|
||||
extension Array where Element == URLQueryItem {
|
||||
fileprivate init(
|
||||
queryOptions: Build.Resources.QueryOptions
|
||||
) {
|
||||
self.init()
|
||||
append(queryOptions.branches, forKey: "branch")
|
||||
appendIfNeeded(queryOptions.commit, forKey: "commit")
|
||||
|
@ -322,13 +377,18 @@ extension Resource where Self == Build.Resources.ListAll {
|
|||
}
|
||||
|
||||
extension Resource where Self == Build.Resources.ListForOrganization {
|
||||
public static func builds(inOrganization organization: String, options: Build.Resources.QueryOptions? = nil) -> Self {
|
||||
public static func builds(inOrganization organization: String, options: Build.Resources.QueryOptions? = nil) -> Self
|
||||
{
|
||||
Self(organization: organization, queryOptions: options)
|
||||
}
|
||||
}
|
||||
|
||||
extension Resource where Self == Build.Resources.ListForPipeline {
|
||||
public static func builds(forPipeline pipeline: String, in organization: String, options: Build.Resources.QueryOptions? = nil) -> Self {
|
||||
public static func builds(
|
||||
forPipeline pipeline: String,
|
||||
in organization: String,
|
||||
options: Build.Resources.QueryOptions? = nil
|
||||
) -> Self {
|
||||
Self(organization: organization, pipeline: pipeline, queryOptions: options)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,9 @@ extension Emoji.Resources {
|
|||
"organizations/\(organization)/emojis"
|
||||
}
|
||||
|
||||
public init(organization: String) {
|
||||
public init(
|
||||
organization: String
|
||||
) {
|
||||
self.organization = organization
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,11 +21,15 @@ public struct Followable<R: Resource>: Codable, Equatable, Resource {
|
|||
|
||||
private var url: URL
|
||||
|
||||
init(url: URL) {
|
||||
init(
|
||||
url: URL
|
||||
) {
|
||||
self.url = url
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
public init(
|
||||
from decoder: Decoder
|
||||
) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
let url = try container.decode(URL.self)
|
||||
self.init(url: url)
|
||||
|
|
|
@ -27,7 +27,9 @@ public struct GraphQL<T: Decodable>: Resource {
|
|||
case data(T)
|
||||
case errors(Errors)
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
public init(
|
||||
from decoder: Decoder
|
||||
) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
if let errors = try container.decodeIfPresent([Error].self, forKey: .errors) {
|
||||
let type = try container.decodeIfPresent(String.self, forKey: .type)
|
||||
|
@ -38,7 +40,8 @@ public struct GraphQL<T: Decodable>: Resource {
|
|||
throw DecodingError.dataCorrupted(
|
||||
DecodingError.Context(
|
||||
codingPath: decoder.codingPath,
|
||||
debugDescription: "The GraphQL response does not contain either errors or data. One is required. If errors are present, they will be considered instead of any data that may have also been sent."
|
||||
debugDescription:
|
||||
"The GraphQL response does not contain either errors or data. One is required. If errors are present, they will be considered instead of any data that may have also been sent."
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -68,7 +71,10 @@ public struct GraphQL<T: Decodable>: Resource {
|
|||
|
||||
public let path = ""
|
||||
|
||||
public init(rawQuery query: String, variables: [String: JSONValue] = [:]) {
|
||||
public init(
|
||||
rawQuery query: String,
|
||||
variables: [String: JSONValue] = [:]
|
||||
) {
|
||||
self.body = Body(query: query, variables: .object(variables))
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,12 @@ extension Job.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/retry"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
job: UUID
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -67,7 +72,10 @@ extension Job.Resources {
|
|||
public var unblocker: UUID?
|
||||
public var fields: [String: String]
|
||||
|
||||
public init(unblocker: UUID? = nil, fields: [String: String] = [:]) {
|
||||
public init(
|
||||
unblocker: UUID? = nil,
|
||||
fields: [String: String] = [:]
|
||||
) {
|
||||
self.unblocker = unblocker
|
||||
self.fields = fields
|
||||
}
|
||||
|
@ -77,7 +85,13 @@ extension Job.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/unblock"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID, body: Body) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
job: UUID,
|
||||
body: Body
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -106,7 +120,12 @@ extension Job.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/log"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
job: UUID
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -129,7 +148,12 @@ extension Job.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/log"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
job: UUID
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -157,7 +181,12 @@ extension Job.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/env"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
job: UUID
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -189,7 +218,13 @@ extension Job.Resources.LogOutput {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(job)/log.\(format)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, job: UUID, format: Format) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
job: UUID,
|
||||
format: Format
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
|
@ -206,7 +241,13 @@ extension Resource where Self == Job.Resources.Retry {
|
|||
}
|
||||
|
||||
extension Resource where Self == Job.Resources.Unblock {
|
||||
public static func unblockJob(_ job: UUID, in organization: String, pipeline: String, build: Int, with body: Self.Body) -> Self {
|
||||
public static func unblockJob(
|
||||
_ job: UUID,
|
||||
in organization: String,
|
||||
pipeline: String,
|
||||
build: Int,
|
||||
with body: Self.Body
|
||||
) -> Self {
|
||||
Self(organization: organization, pipeline: pipeline, build: build, job: job, body: body)
|
||||
}
|
||||
}
|
||||
|
@ -224,13 +265,24 @@ extension Resource where Self == Job.Resources.DeleteLogOutput {
|
|||
}
|
||||
|
||||
extension Resource where Self == Job.Resources.EnvironmentVariables {
|
||||
public static func environmentVariables(for job: UUID, in organization: String, pipeline: String, build: Int) -> Self {
|
||||
public static func environmentVariables(
|
||||
for job: UUID,
|
||||
in organization: String,
|
||||
pipeline: String,
|
||||
build: Int
|
||||
) -> Self {
|
||||
Self(organization: organization, pipeline: pipeline, build: build, job: job)
|
||||
}
|
||||
}
|
||||
|
||||
extension Resource where Self == Job.Resources.LogOutput.Alternative {
|
||||
public static func logOutput(_ format: Job.Resources.LogOutput.Alternative.Format, for job: UUID, in organization: String, pipeline: String, build: Int) -> Self {
|
||||
public static func logOutput(
|
||||
_ format: Job.Resources.LogOutput.Alternative.Format,
|
||||
for job: UUID,
|
||||
in organization: String,
|
||||
pipeline: String,
|
||||
build: Int
|
||||
) -> Self {
|
||||
Self(organization: organization, pipeline: pipeline, build: build, job: job, format: format)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// Metas.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/29/22.
|
||||
// Copyright © 2022 Aaron Sky. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
extension Meta {
|
||||
/// Resources for requesting meta information about Buildkite.
|
||||
public enum Resources {}
|
||||
}
|
||||
|
||||
extension Meta.Resources {
|
||||
/// Get an object with properties describing Buildkite
|
||||
///
|
||||
/// Returns meta information about Buildkite.
|
||||
public struct Get: Resource {
|
||||
public typealias Content = Meta
|
||||
public let path = "meta"
|
||||
|
||||
public init() {}
|
||||
}
|
||||
}
|
||||
|
||||
extension Resource where Self == Meta.Resources.Get {
|
||||
/// Get an object with properties describing Buildkite
|
||||
///
|
||||
/// Returns meta information about Buildkite.
|
||||
public static var meta: Self {
|
||||
Self()
|
||||
}
|
||||
}
|
|
@ -38,7 +38,9 @@ extension Organization.Resources {
|
|||
"organizations/\(organization)"
|
||||
}
|
||||
|
||||
public init(organization: String) {
|
||||
public init(
|
||||
organization: String
|
||||
) {
|
||||
self.organization = organization
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,9 @@ extension Pipeline.Resources {
|
|||
"organizations/\(organization)/pipelines"
|
||||
}
|
||||
|
||||
public init(organization: String) {
|
||||
public init(
|
||||
organization: String
|
||||
) {
|
||||
self.organization = organization
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +49,10 @@ extension Pipeline.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
}
|
||||
|
@ -88,7 +93,20 @@ extension Pipeline.Resources {
|
|||
/// 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, configuration: String, branchConfiguration: String? = nil, cancelRunningBranchBuilds: Bool? = nil, cancelRunningBranchBuildsFilter: String? = nil, defaultBranch: String? = nil, description: String? = nil, providerSettings: Pipeline.Provider.Settings? = nil, skipQueuedBranchBuilds: Bool? = nil, skipQueuedBranchBuildsFilter: String? = nil, teamUUIDs: [UUID]? = nil) {
|
||||
public init(
|
||||
name: String,
|
||||
repository: URL,
|
||||
configuration: String,
|
||||
branchConfiguration: String? = nil,
|
||||
cancelRunningBranchBuilds: Bool? = nil,
|
||||
cancelRunningBranchBuildsFilter: String? = nil,
|
||||
defaultBranch: String? = nil,
|
||||
description: String? = nil,
|
||||
providerSettings: Pipeline.Provider.Settings? = nil,
|
||||
skipQueuedBranchBuilds: Bool? = nil,
|
||||
skipQueuedBranchBuildsFilter: String? = nil,
|
||||
teamUUIDs: [UUID]? = nil
|
||||
) {
|
||||
self.name = name
|
||||
self.repository = repository
|
||||
self.configuration = configuration
|
||||
|
@ -108,7 +126,10 @@ extension Pipeline.Resources {
|
|||
"organizations/\(organization)/pipelines"
|
||||
}
|
||||
|
||||
public init(organization: String, body: Body) {
|
||||
public init(
|
||||
organization: String,
|
||||
body: Body
|
||||
) {
|
||||
self.organization = organization
|
||||
self.body = body
|
||||
}
|
||||
|
@ -155,7 +176,21 @@ extension Pipeline.Resources {
|
|||
/// 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) {
|
||||
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
|
||||
|
@ -176,7 +211,10 @@ extension Pipeline.Resources {
|
|||
"organizations/\(organization)/pipelines"
|
||||
}
|
||||
|
||||
public init(organization: String, body: Body) {
|
||||
public init(
|
||||
organization: String,
|
||||
body: Body
|
||||
) {
|
||||
self.organization = organization
|
||||
self.body = body
|
||||
}
|
||||
|
@ -226,7 +264,21 @@ extension Pipeline.Resources {
|
|||
/// 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) {
|
||||
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
|
||||
|
@ -247,7 +299,11 @@ extension Pipeline.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, body: Body) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String,
|
||||
body: Body
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.body = body
|
||||
|
@ -266,7 +322,10 @@ extension Pipeline.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/archive"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
}
|
||||
|
@ -288,7 +347,10 @@ extension Pipeline.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/unarchive"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
}
|
||||
|
@ -309,7 +371,10 @@ extension Pipeline.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
}
|
||||
|
@ -326,7 +391,10 @@ extension Pipeline.Resources {
|
|||
"organizations/\(organization)/pipelines/\(pipeline)/webhook"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String) {
|
||||
public init(
|
||||
organization: String,
|
||||
pipeline: String
|
||||
) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
}
|
||||
|
|
|
@ -30,15 +30,19 @@ extension Team.Resources {
|
|||
"organizations/\(organization)/teams"
|
||||
}
|
||||
|
||||
public init(organization: String, userId: UUID? = nil) {
|
||||
public init(
|
||||
organization: String,
|
||||
userId: UUID? = nil
|
||||
) {
|
||||
self.organization = organization
|
||||
self.userId = userId
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true)
|
||||
else {
|
||||
return
|
||||
}
|
||||
var queryItems: [URLQueryItem] = []
|
||||
queryItems.appendIfNeeded(userId, forKey: "user_id")
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -33,24 +34,37 @@ class BuildkiteClientTests: XCTestCase {
|
|||
var client: BuildkiteClient
|
||||
var resources = MockResources()
|
||||
|
||||
init(testCase: Case = .success) throws {
|
||||
init(
|
||||
testCase: Case = .success
|
||||
) throws {
|
||||
let responses: [(Data, URLResponse)]
|
||||
|
||||
switch testCase {
|
||||
case .success:
|
||||
responses = [try MockData.mockingSuccess(with: resources.content, url: configuration.version.baseURL)]
|
||||
case .successPaginated:
|
||||
responses = [try MockData.mockingSuccess(with: resources.paginatedContent, url: configuration.version.baseURL)]
|
||||
responses = [
|
||||
try MockData.mockingSuccess(with: resources.paginatedContent, url: configuration.version.baseURL)
|
||||
]
|
||||
case .successNoContent:
|
||||
responses = [MockData.mockingSuccessNoContent(url: configuration.version.baseURL)]
|
||||
case .successHasBody:
|
||||
responses = [MockData.mockingSuccessNoContent(url: configuration.version.baseURL)]
|
||||
case .successHasBodyAndContent:
|
||||
responses = [try MockData.mockingSuccess(with: resources.bodyAndContent, url: configuration.version.baseURL)]
|
||||
responses = [
|
||||
try MockData.mockingSuccess(with: resources.bodyAndContent, url: configuration.version.baseURL)
|
||||
]
|
||||
case .successHasBodyPaginated:
|
||||
responses = [try MockData.mockingSuccess(with: resources.bodyAndPaginatedContent, url: configuration.version.baseURL)]
|
||||
responses = [
|
||||
try MockData.mockingSuccess(
|
||||
with: resources.bodyAndPaginatedContent,
|
||||
url: configuration.version.baseURL
|
||||
)
|
||||
]
|
||||
case .successGraphQL:
|
||||
responses = [try MockData.mockingSuccess(with: resources.graphQLIntermediary, url: configuration.version.baseURL)]
|
||||
responses = [
|
||||
try MockData.mockingSuccess(with: resources.graphQLIntermediary, url: configuration.version.baseURL)
|
||||
]
|
||||
case .badResponse:
|
||||
responses = [MockData.mockingIncompatibleResponse(for: configuration.version.baseURL)]
|
||||
case .unsuccessfulResponse:
|
||||
|
@ -59,8 +73,10 @@ class BuildkiteClientTests: XCTestCase {
|
|||
responses = []
|
||||
}
|
||||
|
||||
client = BuildkiteClient(configuration: configuration,
|
||||
transport: MockTransport(responses: responses))
|
||||
client = BuildkiteClient(
|
||||
configuration: configuration,
|
||||
transport: MockTransport(responses: responses)
|
||||
)
|
||||
client.token = "a valid token, i guess"
|
||||
XCTAssertEqual(client.token, client.configuration.token)
|
||||
}
|
||||
|
@ -108,7 +124,10 @@ extension BuildkiteClientTests {
|
|||
let testData = try TestData(testCase: .success)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
testData.client.send(testData.resources.paginatedContentResource, pageOptions: PageOptions(page: 1, perPage: 30)) { result in
|
||||
testData.client.send(
|
||||
testData.resources.paginatedContentResource,
|
||||
pageOptions: PageOptions(page: 1, perPage: 30)
|
||||
) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(testData.resources.paginatedContent, response.content)
|
||||
|
@ -161,7 +180,10 @@ extension BuildkiteClientTests {
|
|||
let testData = try TestData(testCase: .successHasBodyPaginated)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
testData.client.send(testData.resources.bodyAndPaginatedResource, pageOptions: PageOptions(page: 1, perPage: 30)) { result in
|
||||
testData.client.send(
|
||||
testData.resources.bodyAndPaginatedResource,
|
||||
pageOptions: PageOptions(page: 1, perPage: 30)
|
||||
) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(testData.resources.bodyAndPaginatedContent, response.content)
|
||||
|
@ -246,13 +268,15 @@ extension BuildkiteClientTests {
|
|||
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) })
|
||||
.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])
|
||||
}
|
||||
|
@ -261,17 +285,20 @@ extension BuildkiteClientTests {
|
|||
let testData = try TestData(testCase: .success)
|
||||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
testData.client.sendPublisher(testData.resources.paginatedContentResource, pageOptions: PageOptions(page: 1, perPage: 30))
|
||||
.sink(receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
testData.client
|
||||
.sendPublisher(testData.resources.paginatedContentResource, pageOptions: PageOptions(page: 1, perPage: 30))
|
||||
.sink(
|
||||
receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: {
|
||||
XCTAssertEqual(testData.resources.paginatedContent, $0.content)
|
||||
XCTAssertNotNil($0.page)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: {
|
||||
XCTAssertEqual(testData.resources.paginatedContent, $0.content)
|
||||
XCTAssertNotNil($0.page)
|
||||
})
|
||||
)
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
@ -281,12 +308,15 @@ extension BuildkiteClientTests {
|
|||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
testData.client.sendPublisher(testData.resources.noContentNoBodyResource)
|
||||
.sink(receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}, receiveValue: { _ in })
|
||||
.sink(
|
||||
receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: { _ in }
|
||||
)
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
@ -296,12 +326,15 @@ extension BuildkiteClientTests {
|
|||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
testData.client.sendPublisher(testData.resources.bodyResource)
|
||||
.sink(receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}, receiveValue: { _ in })
|
||||
.sink(
|
||||
receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: { _ in }
|
||||
)
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
@ -311,15 +344,17 @@ extension BuildkiteClientTests {
|
|||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
testData.client.sendPublisher(testData.resources.bodyAndContentResource)
|
||||
.sink(receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
.sink(
|
||||
receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: {
|
||||
XCTAssertEqual(testData.resources.bodyAndContent, $0.content)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: {
|
||||
XCTAssertEqual(testData.resources.bodyAndContent, $0.content)
|
||||
})
|
||||
)
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
@ -328,17 +363,20 @@ extension BuildkiteClientTests {
|
|||
let testData = try TestData(testCase: .successHasBodyPaginated)
|
||||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
testData.client.sendPublisher(testData.resources.bodyAndPaginatedResource, pageOptions: PageOptions(page: 1, perPage: 30))
|
||||
.sink(receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
testData.client
|
||||
.sendPublisher(testData.resources.bodyAndPaginatedResource, pageOptions: PageOptions(page: 1, perPage: 30))
|
||||
.sink(
|
||||
receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: {
|
||||
XCTAssertEqual(testData.resources.bodyAndPaginatedContent, $0.content)
|
||||
XCTAssertNotNil($0.page)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: {
|
||||
XCTAssertEqual(testData.resources.bodyAndPaginatedContent, $0.content)
|
||||
XCTAssertNotNil($0.page)
|
||||
})
|
||||
)
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
@ -348,14 +386,17 @@ extension BuildkiteClientTests {
|
|||
let expectation = XCTestExpectation()
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
testData.client.sendQueryPublisher(testData.resources.graphQLResource)
|
||||
.sink(receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
.sink(
|
||||
receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: {
|
||||
XCTAssertEqual(testData.resources.graphQLContent, $0)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}, receiveValue: {
|
||||
XCTAssertEqual(testData.resources.graphQLContent, $0)
|
||||
})
|
||||
)
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
@ -365,12 +406,15 @@ extension BuildkiteClientTests {
|
|||
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 })
|
||||
.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])
|
||||
}
|
||||
|
@ -380,12 +424,15 @@ extension BuildkiteClientTests {
|
|||
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 })
|
||||
.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])
|
||||
}
|
||||
|
@ -405,8 +452,10 @@ extension BuildkiteClientTests {
|
|||
|
||||
func testAsyncBasedRequestWithPagination() async throws {
|
||||
let testData = try TestData(testCase: .success)
|
||||
let response = try await testData.client.send(testData.resources.paginatedContentResource,
|
||||
pageOptions: PageOptions(page: 1, perPage: 30))
|
||||
let response = try await testData.client.send(
|
||||
testData.resources.paginatedContentResource,
|
||||
pageOptions: PageOptions(page: 1, perPage: 30)
|
||||
)
|
||||
XCTAssertEqual(testData.resources.paginatedContent, response.content)
|
||||
XCTAssertNotNil(response.page)
|
||||
}
|
||||
|
@ -429,8 +478,10 @@ extension BuildkiteClientTests {
|
|||
|
||||
func testAsyncBasedRequestHasBodyWithPagination() async throws {
|
||||
let testData = try TestData(testCase: .successHasBodyPaginated)
|
||||
let response = try await testData.client.send(testData.resources.bodyAndPaginatedResource,
|
||||
pageOptions: PageOptions(page: 1, perPage: 30))
|
||||
let response = try await testData.client.send(
|
||||
testData.resources.bodyAndPaginatedResource,
|
||||
pageOptions: PageOptions(page: 1, perPage: 30)
|
||||
)
|
||||
XCTAssertEqual(testData.resources.bodyAndPaginatedContent, response.content)
|
||||
XCTAssertNotNil(response.page)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -19,40 +20,40 @@ import FoundationNetworking
|
|||
final class JSONValueTests: XCTestCase {
|
||||
func testDecodeArray() throws {
|
||||
let json = """
|
||||
{ "fooKey": [true, 1] }
|
||||
"""
|
||||
{ "fooKey": [true, 1] }
|
||||
"""
|
||||
let expected = JSONValue.object(["fooKey": .array([.bool(true), .number(1)])])
|
||||
try decodingTest(json, expected)
|
||||
}
|
||||
|
||||
func testDecodeBool() throws {
|
||||
let json = """
|
||||
{ "fooKey": true }
|
||||
"""
|
||||
{ "fooKey": true }
|
||||
"""
|
||||
let expected = JSONValue.object(["fooKey": .bool(true)])
|
||||
try decodingTest(json, expected)
|
||||
}
|
||||
|
||||
func testDecodeDouble() throws {
|
||||
let json = """
|
||||
{ "fooKey": 1.2345 }
|
||||
"""
|
||||
{ "fooKey": 1.2345 }
|
||||
"""
|
||||
let expected = JSONValue.object(["fooKey": .number(1.2345)])
|
||||
try decodingTest(json, expected)
|
||||
}
|
||||
|
||||
func testDecodeNull() throws {
|
||||
let json = """
|
||||
{ "fooKey": null }
|
||||
"""
|
||||
{ "fooKey": null }
|
||||
"""
|
||||
let expected = JSONValue.object(["fooKey": .null])
|
||||
try decodingTest(json, expected)
|
||||
}
|
||||
|
||||
func testDecodeString() throws {
|
||||
let json = """
|
||||
{ "fooKey": "fooVal" }
|
||||
"""
|
||||
{ "fooKey": "fooVal" }
|
||||
"""
|
||||
let expected = JSONValue.object(["fooKey": .string("fooVal")])
|
||||
let data = try XCTUnwrap(json.data(using: .utf8))
|
||||
let actual = try JSONDecoder().decode(JSONValue.self, from: data)
|
||||
|
@ -94,16 +95,15 @@ final class JSONValueTests: XCTestCase {
|
|||
123,
|
||||
[
|
||||
"abc": false,
|
||||
"qqq": [:]
|
||||
]
|
||||
"qqq": [:],
|
||||
],
|
||||
|
||||
]
|
||||
,
|
||||
],
|
||||
"qux": [
|
||||
"1": nil,
|
||||
"2": "2",
|
||||
"3": 33333333.0
|
||||
]
|
||||
"3": 33333333.0,
|
||||
],
|
||||
])
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
// Copyright © 2020 Aaron Sky. All rights reserved.
|
||||
//
|
||||
|
||||
@testable import Buildkite
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
@ -68,24 +69,26 @@ 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)
|
||||
createSession()
|
||||
.send(request: request) {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
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")
|
||||
createSession(testCase: .error)
|
||||
.send(request: request) {
|
||||
if case .success(_) = $0 {
|
||||
XCTFail("Expected to have failed with an error, but closure fulfilled normally")
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
||||
|
@ -103,14 +106,17 @@ extension TransportTests {
|
|||
var cancellables: Set<AnyCancellable> = []
|
||||
createSession()
|
||||
.sendPublisher(request: request)
|
||||
.sink(receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}, receiveValue: { _ in })
|
||||
.sink(
|
||||
receiveCompletion: {
|
||||
if case let .failure(error) = $0 {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
},
|
||||
receiveValue: { _ in }
|
||||
)
|
||||
.store(in: &cancellables)
|
||||
wait(for: [expectation])
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testURLSessionSendPublisherBasedRequestFailure() {
|
||||
|
@ -119,14 +125,17 @@ extension TransportTests {
|
|||
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 })
|
||||
.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])
|
||||
wait(for: [expectation])
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -15,37 +16,17 @@ import FoundationNetworking
|
|||
#endif
|
||||
|
||||
class AccessTokensTests: XCTestCase {
|
||||
func testAccessTokenGet() throws {
|
||||
func testAccessTokenGet() async throws {
|
||||
let expected = AccessToken(uuid: UUID(), scopes: [])
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.getAccessToken)
|
||||
|
||||
context.client.send(.getAccessToken) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testAccessTokenDelete() throws {
|
||||
func testAccessTokenDelete() async throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(.revokeAccessToken) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
_ = try await context.client.send(.revokeAccessToken)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -16,99 +17,76 @@ import FoundationNetworking
|
|||
|
||||
extension Agent {
|
||||
init() {
|
||||
let job = Job.script(Job.Command(id: UUID(),
|
||||
name: "📦",
|
||||
state: "passed",
|
||||
command: nil,
|
||||
stepKey: nil,
|
||||
buildUrl: URL(),
|
||||
webUrl: URL(),
|
||||
logUrl: Followable(),
|
||||
rawLogUrl: Followable(),
|
||||
artifactsUrl: URL(),
|
||||
softFailed: false,
|
||||
exitStatus: 0,
|
||||
artifactPaths: nil,
|
||||
agentQueryRules: [],
|
||||
agent: nil,
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
scheduledAt: Date(timeIntervalSince1970: 1000),
|
||||
runnableAt: nil,
|
||||
startedAt: nil,
|
||||
finishedAt: nil,
|
||||
retried: false,
|
||||
retriedInJobId: nil,
|
||||
retriesCount: nil,
|
||||
parallelGroupIndex: nil,
|
||||
parallelGroupTotal: nil))
|
||||
let job = Job.script(
|
||||
Job.Command(
|
||||
id: UUID(),
|
||||
name: "📦",
|
||||
state: "passed",
|
||||
command: nil,
|
||||
stepKey: nil,
|
||||
buildUrl: URL(),
|
||||
webUrl: URL(),
|
||||
logUrl: Followable(),
|
||||
rawLogUrl: Followable(),
|
||||
artifactsUrl: URL(),
|
||||
softFailed: false,
|
||||
exitStatus: 0,
|
||||
artifactPaths: nil,
|
||||
agentQueryRules: [],
|
||||
agent: nil,
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
scheduledAt: Date(timeIntervalSince1970: 1000),
|
||||
runnableAt: nil,
|
||||
startedAt: nil,
|
||||
finishedAt: nil,
|
||||
retried: false,
|
||||
retriedInJobId: nil,
|
||||
retriesCount: nil,
|
||||
parallelGroupIndex: nil,
|
||||
parallelGroupTotal: nil
|
||||
)
|
||||
)
|
||||
|
||||
self.init(id: UUID(),
|
||||
url: Followable(),
|
||||
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: [])
|
||||
self.init(
|
||||
id: UUID(),
|
||||
url: Followable(),
|
||||
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 {
|
||||
func testAgentsList() async throws {
|
||||
let expected = [Agent(), Agent()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.agents(in: "buildkite"))
|
||||
|
||||
context.client.send(.agents(in: "buildkite")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testAgentsGet() throws {
|
||||
func testAgentsGet() async throws {
|
||||
let expected = Agent()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
context.client.send(.agent(UUID(), in: "buildkite")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
let response = try await context.client.send(.agent(UUID(), in: "buildkite"))
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testAgentsStop() throws {
|
||||
func testAgentsStop() async throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(.stopAgent(UUID(), in: "buildkite", force: true)) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
_ = try await context.client.send(.stopAgent(UUID(), in: "buildkite", force: true))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -16,31 +17,24 @@ import FoundationNetworking
|
|||
|
||||
extension Annotation {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
context: "message",
|
||||
style: .info,
|
||||
bodyHtml: "<div></div>",
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
updatedAt: Date(timeIntervalSince1970: 1001))
|
||||
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 {
|
||||
func testAnnotationsList() async throws {
|
||||
let expected = [Annotation(), Annotation()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.annotations(in: "buildkite", pipeline: "my-pipeline", build: 1))
|
||||
|
||||
context.client.send(.annotations(in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -16,106 +17,70 @@ import FoundationNetworking
|
|||
|
||||
extension Artifact {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
jobId: UUID(),
|
||||
url: Followable(),
|
||||
downloadUrl: Followable(),
|
||||
state: .new,
|
||||
path: "",
|
||||
dirname: "",
|
||||
filename: "",
|
||||
mimeType: "",
|
||||
fileSize: 0,
|
||||
sha1sum: "")
|
||||
self.init(
|
||||
id: UUID(),
|
||||
jobId: UUID(),
|
||||
url: Followable(),
|
||||
downloadUrl: Followable(),
|
||||
state: .new,
|
||||
path: "",
|
||||
dirname: "",
|
||||
filename: "",
|
||||
mimeType: "",
|
||||
fileSize: 0,
|
||||
sha1sum: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ArtifactsTests: XCTestCase {
|
||||
func testArtifactsListByBuild() throws {
|
||||
func testArtifactsListByBuild() async throws {
|
||||
let expected = [Artifact(), Artifact()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.artifacts(byBuild: 1, in: "buildkite", pipeline: "my-pipeline"))
|
||||
|
||||
context.client.send(.artifacts(byBuild: 1, in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testArtifactsListByJob() throws {
|
||||
func testArtifactsListByJob() async throws {
|
||||
let expected = [Artifact(), Artifact()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.artifacts(byJob: UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1)
|
||||
)
|
||||
|
||||
context.client.send(.artifacts(byJob: UUID(), in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testArtifactsGet() throws {
|
||||
func testArtifactsGet() async throws {
|
||||
let expected = Artifact()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.artifact(UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1, job: UUID())
|
||||
)
|
||||
|
||||
context.client.send(.artifact(UUID(), in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testArtifactsDownload() throws {
|
||||
func testArtifactsDownload() async throws {
|
||||
let expected = Artifact.URLs(url: URL())
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.downloadArtifact(UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1, job: UUID())
|
||||
)
|
||||
|
||||
context.client.send(.downloadArtifact(UUID(), in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testArtifactsDelete() throws {
|
||||
func testArtifactsDelete() async throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(.deleteArtifact(UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1, job: UUID())) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
_ = try await context.client.send(
|
||||
.deleteArtifact(UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1, job: UUID())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -16,189 +17,135 @@ import FoundationNetworking
|
|||
|
||||
extension Build {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
url: Followable(),
|
||||
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())
|
||||
self.init(
|
||||
id: UUID(),
|
||||
url: Followable(),
|
||||
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 {
|
||||
func testBuildsListAllDefaultQuery() async throws {
|
||||
let expected = [Build(), Build()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.builds())
|
||||
|
||||
context.client.send(.builds()) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testBuildsListAllSpecializedQuery() throws {
|
||||
func testBuildsListAllSpecializedQuery() async throws {
|
||||
let expected = [Build(), Build()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.builds(
|
||||
options: .init(
|
||||
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, .blocked, .failed]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
context.client.send(.builds(options: .init(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, .blocked, .failed]))) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testBuildsListForOrganization() throws {
|
||||
func testBuildsListForOrganization() async throws {
|
||||
let expected = [Build(), Build()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.builds(inOrganization: "buildkite", options: .init()))
|
||||
|
||||
context.client.send(.builds(inOrganization: "buildkite", options: .init())) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testBuildsListForPipeline() throws {
|
||||
func testBuildsListForPipeline() async throws {
|
||||
let expected = [Build(), Build()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.builds(forPipeline: "my-pipeline", in: "buildkite", options: .init())
|
||||
)
|
||||
|
||||
context.client.send(.builds(forPipeline: "my-pipeline", in: "buildkite", options: .init())) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testBuildsGet() throws {
|
||||
func testBuildsGet() async throws {
|
||||
let expected = Build()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.build(1, in: "buildkite", pipeline: "my-pipeline"))
|
||||
|
||||
context.client.send(.build(1, in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testBuildsCreate() throws {
|
||||
func testBuildsCreate() async throws {
|
||||
let expected = Build()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.createBuild(
|
||||
in: "buildkite",
|
||||
pipeline: "my-pipeline",
|
||||
with: .init(
|
||||
commit: "HEAD",
|
||||
branch: "master",
|
||||
author: Build.Resources.Create.Body.Author(name: "", email: ""),
|
||||
cleanCheckout: nil,
|
||||
env: nil,
|
||||
ignorePipelineBranchFilters: nil,
|
||||
message: nil,
|
||||
metaData: nil,
|
||||
pullRequestBaseBranch: nil,
|
||||
pullRequestId: nil,
|
||||
pullRequestRepository: nil
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
context.client.send(.createBuild(in: "buildkite", pipeline: "my-pipeline", with: .init(commit: "HEAD",
|
||||
branch: "master",
|
||||
author: Build.Resources.Create.Body.Author(name: "", email: ""),
|
||||
cleanCheckout: nil,
|
||||
env: nil,
|
||||
ignorePipelineBranchFilters: nil,
|
||||
message: nil,
|
||||
metaData: nil,
|
||||
pullRequestBaseBranch: nil,
|
||||
pullRequestId: nil,
|
||||
pullRequestRepository: nil))) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testBuildsCancel() throws {
|
||||
func testBuildsCancel() async throws {
|
||||
let expected = Build()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.cancelBuild(1, in: "buildkite", pipeline: "my-pipeline"))
|
||||
|
||||
context.client.send(.cancelBuild(1, in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testBuildsRebuild() throws {
|
||||
func testBuildsRebuild() async throws {
|
||||
let expected = Build()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.rebuild(1, in: "buildkite", pipeline: "my-pipeline"))
|
||||
|
||||
context.client.send(.rebuild(1, in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -16,27 +17,20 @@ import FoundationNetworking
|
|||
|
||||
extension Emoji {
|
||||
init() {
|
||||
self.init(name: "jeff",
|
||||
url: URL())
|
||||
self.init(
|
||||
name: "jeff",
|
||||
url: URL()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class EmojisTests: XCTestCase {
|
||||
func testEmojisList() throws {
|
||||
func testEmojisList() async throws {
|
||||
let expected = [Emoji(), Emoji()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.emojis(in: "buildkite"))
|
||||
|
||||
context.client.send(.emojis(in: "buildkite")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -21,29 +22,13 @@ extension Followable {
|
|||
}
|
||||
|
||||
class FollowableTests: XCTestCase {
|
||||
func testFollowable() throws {
|
||||
func testFollowable() async throws {
|
||||
let expected = Organization()
|
||||
let context = try MockContext(content: Organization(), expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let organizationResponse = try await context.client.send(.organization("buildkite"))
|
||||
let followableResponse = try await context.client.send(organizationResponse.content.url)
|
||||
|
||||
context.client.send(.organization("buildkite")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
context.client.send(response.content.url) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, followableResponse.content)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -15,91 +16,88 @@ import FoundationNetworking
|
|||
#endif
|
||||
|
||||
class GraphQLTests: XCTestCase {
|
||||
func testGraphQLSuccess() throws {
|
||||
func testGraphQLSuccess() async throws {
|
||||
let expected: JSONValue = ["jeff": [1, 2, 3], "horses": false]
|
||||
let content: JSONValue = ["data": expected]
|
||||
let context = try MockContext(content: content)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.sendQuery(
|
||||
GraphQL<JSONValue>(rawQuery: "query MyQuery{jeff,horses}", variables: [:])
|
||||
)
|
||||
|
||||
context.client.sendQuery(GraphQL<JSONValue>(rawQuery: "query MyQuery{jeff,horses}", variables: [:])) { result in
|
||||
do {
|
||||
let content = try result.get()
|
||||
XCTAssertEqual(expected, content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response)
|
||||
}
|
||||
|
||||
func testGraphQLErrors() throws {
|
||||
let expected: GraphQL<JSONValue>.Errors = .init(errors: [
|
||||
.init(message: "Field 'id' doesn't exist on type 'Query'",
|
||||
locations: [.init(line: 2, column: 3)],
|
||||
path: ["query SimpleQuery", "id"],
|
||||
extensions: [
|
||||
"code": "undefinedField",
|
||||
"typeName": "Query",
|
||||
"fieldName": "id"
|
||||
])
|
||||
], type: nil)
|
||||
func testGraphQLErrors() async throws {
|
||||
let expected: GraphQL<JSONValue>.Errors = .init(
|
||||
errors: [
|
||||
.init(
|
||||
message: "Field 'id' doesn't exist on type 'Query'",
|
||||
locations: [.init(line: 2, column: 3)],
|
||||
path: ["query SimpleQuery", "id"],
|
||||
extensions: [
|
||||
"code": "undefinedField",
|
||||
"typeName": "Query",
|
||||
"fieldName": "id",
|
||||
]
|
||||
)
|
||||
],
|
||||
type: nil
|
||||
)
|
||||
|
||||
let content: JSONValue = [
|
||||
"errors": .array(expected.errors.map { error in
|
||||
let messageJSON: JSONValue = .string(error.message)
|
||||
let locationsJSON: JSONValue
|
||||
if let locations = error.locations {
|
||||
locationsJSON = .array(locations.map { .object(["line": .number(Double($0.line)), "column": .number(Double($0.column))]) })
|
||||
} else {
|
||||
locationsJSON = .null
|
||||
}
|
||||
let pathJSON: JSONValue
|
||||
if let path = error.path {
|
||||
pathJSON = .array(path.map { .string($0) })
|
||||
} else {
|
||||
pathJSON = .null
|
||||
}
|
||||
let extensionsJSON = error.extensions ?? .null
|
||||
"errors": .array(
|
||||
expected.errors.map { error in
|
||||
let messageJSON: JSONValue = .string(error.message)
|
||||
let locationsJSON: JSONValue
|
||||
if let locations = error.locations {
|
||||
locationsJSON = .array(
|
||||
locations.map {
|
||||
.object(["line": .number(Double($0.line)), "column": .number(Double($0.column))])
|
||||
}
|
||||
)
|
||||
} else {
|
||||
locationsJSON = .null
|
||||
}
|
||||
let pathJSON: JSONValue
|
||||
if let path = error.path {
|
||||
pathJSON = .array(path.map { .string($0) })
|
||||
} else {
|
||||
pathJSON = .null
|
||||
}
|
||||
let extensionsJSON = error.extensions ?? .null
|
||||
|
||||
return [
|
||||
"message": messageJSON,
|
||||
"locations": locationsJSON,
|
||||
"path": pathJSON,
|
||||
"extensions": extensionsJSON
|
||||
]
|
||||
})
|
||||
return [
|
||||
"message": messageJSON,
|
||||
"locations": locationsJSON,
|
||||
"path": pathJSON,
|
||||
"extensions": extensionsJSON,
|
||||
]
|
||||
}
|
||||
)
|
||||
]
|
||||
let context = try MockContext(content: content)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.sendQuery(GraphQL<JSONValue>(rawQuery: "query MyQuery{jeff,horses}", variables: [:])) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
XCTFail("Expected to have failed with an error, but closure fulfilled normally")
|
||||
} catch let error as GraphQL<JSONValue>.Errors {
|
||||
XCTAssertEqual(expected, error)
|
||||
} catch {
|
||||
XCTFail("Expected to have failed with an error, but closure failed with unexpected error type")
|
||||
}
|
||||
expectation.fulfill()
|
||||
do {
|
||||
_ = try await context.client.sendQuery(
|
||||
GraphQL<JSONValue>(rawQuery: "query MyQuery{jeff,horses}", variables: [:])
|
||||
)
|
||||
XCTFail("Expected to have failed with an error, but closure fulfilled normally")
|
||||
} catch let error as GraphQL<JSONValue>.Errors {
|
||||
XCTAssertEqual(expected, error)
|
||||
} catch {
|
||||
XCTFail("Expected to have failed with an error, but closure failed with unexpected error type")
|
||||
}
|
||||
wait(for: [expectation])
|
||||
}
|
||||
|
||||
func testGraphQLIncompatibleResponse() throws {
|
||||
func testGraphQLIncompatibleResponse() async throws {
|
||||
let content: JSONValue = [:]
|
||||
let context = try MockContext(content: content)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.sendQuery(GraphQL<JSONValue>(rawQuery: "", variables: [:])) {
|
||||
try? XCTAssertThrowsError($0.get(), "Expected to have failed with an error, but closure fulfilled normally")
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
do {
|
||||
_ = try await context.client.sendQuery(GraphQL<JSONValue>(rawQuery: "", variables: [:]))
|
||||
XCTFail("Expected to have failed with an error, but closure fulfilled normally")
|
||||
} catch {}
|
||||
}
|
||||
|
||||
func testGraphQLContentGet() throws {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -15,172 +16,127 @@ import FoundationNetworking
|
|||
#endif
|
||||
|
||||
class JobsTests: XCTestCase {
|
||||
func testJobsRetryWaiter() throws {
|
||||
func testJobsRetryWaiter() async throws {
|
||||
let expected: Job = .waiter(Job.Wait(id: UUID()))
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.retryJob(UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1)
|
||||
)
|
||||
|
||||
context.client.send(.retryJob(UUID(), in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testJobsRetryTrigger() throws {
|
||||
let expected: Job = .trigger(Job.Trigger(name: nil,
|
||||
state: nil,
|
||||
buildUrl: URL(),
|
||||
webUrl: URL(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
scheduledAt: nil,
|
||||
finishedAt: nil,
|
||||
runnableAt: nil,
|
||||
triggeredBuild: Job.Trigger.TriggeredBuild(id: UUID(),
|
||||
number: 0,
|
||||
url: URL(),
|
||||
webUrl: URL())))
|
||||
func testJobsRetryTrigger() async throws {
|
||||
let expected: Job = .trigger(
|
||||
Job.Trigger(
|
||||
name: nil,
|
||||
state: nil,
|
||||
buildUrl: URL(),
|
||||
webUrl: URL(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
scheduledAt: nil,
|
||||
finishedAt: nil,
|
||||
runnableAt: nil,
|
||||
triggeredBuild: Job.Trigger.TriggeredBuild(
|
||||
id: UUID(),
|
||||
number: 0,
|
||||
url: URL(),
|
||||
webUrl: URL()
|
||||
)
|
||||
)
|
||||
)
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.retryJob(UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1)
|
||||
)
|
||||
|
||||
context.client.send(.retryJob(UUID(), in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testJobsUnblock() throws {
|
||||
let expected: Job = .manual(Job.Block(id: UUID(),
|
||||
label: "",
|
||||
state: "",
|
||||
webUrl: nil,
|
||||
unblockedBy: User(),
|
||||
unblockedAt: Date(timeIntervalSince1970: 1000),
|
||||
unblockable: true,
|
||||
unblockUrl: URL()))
|
||||
func testJobsUnblock() async throws {
|
||||
let expected: Job = .manual(
|
||||
Job.Block(
|
||||
id: UUID(),
|
||||
label: "",
|
||||
state: "",
|
||||
webUrl: nil,
|
||||
unblockedBy: User(),
|
||||
unblockedAt: Date(timeIntervalSince1970: 1000),
|
||||
unblockable: true,
|
||||
unblockUrl: URL()
|
||||
)
|
||||
)
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.unblockJob(UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1, with: .init())
|
||||
)
|
||||
|
||||
context.client.send(.unblockJob(UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1, with: .init())) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testJobsLogOutput() throws {
|
||||
func testJobsLogOutput() async throws {
|
||||
let expected = Job.LogOutput()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.logOutput(for: UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1)
|
||||
)
|
||||
|
||||
context.client.send(.logOutput(for: UUID(), in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testJobsLogOutputAlternativePlainText() throws {
|
||||
func testJobsLogOutputAlternativePlainText() async throws {
|
||||
let expected = "hello friends"
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.logOutput(.plainText, for: UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1)
|
||||
)
|
||||
|
||||
context.client.send(.logOutput(.plainText, for: UUID(), in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testJobsLogOutputAlternativeHTML() throws {
|
||||
func testJobsLogOutputAlternativeHTML() async throws {
|
||||
let expected = "hello friends"
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.logOutput(.html, for: UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1)
|
||||
)
|
||||
|
||||
context.client.send(.logOutput(.html, for: UUID(), in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testJobsDeleteLogOutput() throws {
|
||||
func testJobsDeleteLogOutput() async throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(.deleteLogOutput(for: UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1)) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
_ = try await context.client.send(
|
||||
.deleteLogOutput(for: UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1)
|
||||
)
|
||||
}
|
||||
|
||||
func testJobsEnvironmentVariables() throws {
|
||||
func testJobsEnvironmentVariables() async throws {
|
||||
let expected = Job.EnvironmentVariables(env: [:])
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(
|
||||
.environmentVariables(for: UUID(), in: "buildkite", pipeline: "my-pipeline", build: 1)
|
||||
)
|
||||
|
||||
context.client.send(.environmentVariables(for: UUID(), in: "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])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
}
|
||||
|
||||
extension Job.LogOutput {
|
||||
init() {
|
||||
self.init(url: Followable(),
|
||||
content: "hello friends",
|
||||
size: 13,
|
||||
headerTimes: [])
|
||||
self.init(
|
||||
url: Followable(),
|
||||
content: "hello friends",
|
||||
size: 13,
|
||||
headerTimes: []
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// MetasTests.swift
|
||||
// Buildkite
|
||||
//
|
||||
// Created by Aaron Sky on 5/29/22.
|
||||
// Copyright © 2022 Aaron Sky. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
class MetasTests: XCTestCase {
|
||||
func testMetaGet() async throws {
|
||||
let expected = Meta(webhookIPRanges: ["1.1.1.1/32"])
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let response = try await context.client.send(.meta)
|
||||
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -16,52 +17,36 @@ import FoundationNetworking
|
|||
|
||||
extension Organization {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
url: Followable(),
|
||||
webUrl: URL(),
|
||||
name: "Buildkite",
|
||||
slug: "buildkite",
|
||||
pipelinesUrl: Followable(),
|
||||
agentsUrl: Followable(),
|
||||
emojisUrl: Followable(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000))
|
||||
self.init(
|
||||
id: UUID(),
|
||||
url: Followable(),
|
||||
webUrl: URL(),
|
||||
name: "Buildkite",
|
||||
slug: "buildkite",
|
||||
pipelinesUrl: Followable(),
|
||||
agentsUrl: Followable(),
|
||||
emojisUrl: Followable(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class OrganizationsTests: XCTestCase {
|
||||
func testOrganizationsList() throws {
|
||||
func testOrganizationsList() async throws {
|
||||
let expected = [Organization()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.organizations)
|
||||
|
||||
context.client.send(.organizations) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testOrganizationsGet() throws {
|
||||
func testOrganizationsGet() async throws {
|
||||
let expected = Organization()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.organization("buildkite"))
|
||||
|
||||
context.client.send(.organization("buildkite")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -15,207 +16,194 @@ import FoundationNetworking
|
|||
#endif
|
||||
|
||||
extension Pipeline {
|
||||
init(steps: [Step] = []) {
|
||||
self.init(id: UUID(),
|
||||
url: Followable(),
|
||||
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: Followable(),
|
||||
badgeUrl: URL(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
scheduledBuildsCount: 0,
|
||||
runningBuildsCount: 0,
|
||||
scheduledJobsCount: 0,
|
||||
runningJobsCount: 0,
|
||||
waitingJobsCount: 0,
|
||||
visibility: "private",
|
||||
steps: steps,
|
||||
env: [:])
|
||||
init(
|
||||
steps: [Step] = []
|
||||
) {
|
||||
self.init(
|
||||
id: UUID(),
|
||||
url: Followable(),
|
||||
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: Followable(),
|
||||
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 {
|
||||
func testPipelinesList() async throws {
|
||||
let expected = [Pipeline(), Pipeline()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.pipelines(in: "buildkite"))
|
||||
|
||||
context.client.send(.pipelines(in: "buildkite")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testPipelinesGet() throws {
|
||||
func testPipelinesGet() async throws {
|
||||
let expected = Pipeline()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.pipeline("buildkite", in: "organization"))
|
||||
|
||||
context.client.send(.pipeline("buildkite", in: "organization")) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
|
||||
func testPipelinesCreate() throws {
|
||||
func testPipelinesCreate() async throws {
|
||||
let steps: [Pipeline.Step] = [
|
||||
.script(Pipeline.Step.Command(name: "📦",
|
||||
command: "echo true",
|
||||
label: "📦",
|
||||
env: [:],
|
||||
agentQueryRules: []))
|
||||
.script(
|
||||
Pipeline.Step.Command(
|
||||
name: "📦",
|
||||
command: "echo true",
|
||||
label: "📦",
|
||||
env: [:],
|
||||
agentQueryRules: []
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
let expected = Pipeline(steps: steps)
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
context.client.send(.createPipeline(.init(name: "My Pipeline",
|
||||
repository: URL(),
|
||||
configuration: "steps:\n\t- label: \"📦\"\n\t command: \"echo true\""),
|
||||
in: "buildkite")) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
_ = try await context.client.send(
|
||||
.createPipeline(
|
||||
.init(
|
||||
name: "My Pipeline",
|
||||
repository: URL(),
|
||||
configuration: "steps:\n\t- label: \"📦\"\n\t command: \"echo true\""
|
||||
),
|
||||
in: "buildkite"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func testPipelinesCreateVisualSteps() throws {
|
||||
func testPipelinesCreateVisualSteps() async 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)),
|
||||
.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))
|
||||
.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 expectation = XCTestExpectation()
|
||||
context.client.send(.createVisualStepsPipeline(.init(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),
|
||||
in: "buildkite")) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
_ = try await context.client.send(
|
||||
.createVisualStepsPipeline(
|
||||
.init(
|
||||
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
|
||||
),
|
||||
in: "buildkite"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func testPipelinesUpdate() throws {
|
||||
func testPipelinesUpdate() async throws {
|
||||
let expected = Pipeline()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
context.client.send(.updatePipeline("my-pipeline",
|
||||
in: "buildkite",
|
||||
with: .init(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))) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
_ = try await context.client.send(
|
||||
.updatePipeline(
|
||||
"my-pipeline",
|
||||
in: "buildkite",
|
||||
with: .init(
|
||||
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
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func testPipelinesDelete() throws {
|
||||
func testPipelinesDelete() async throws {
|
||||
let context = MockContext()
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(.deletePipeline("my-pipeline", in: "buildkite")) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
_ = try await context.client.send(.deletePipeline("my-pipeline", in: "buildkite"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,41 +8,35 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
private extension Team {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
name: "",
|
||||
slug: "",
|
||||
description: "",
|
||||
privacy: .visible,
|
||||
default: true,
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
createdBy: User())
|
||||
extension Team {
|
||||
fileprivate init() {
|
||||
self.init(
|
||||
id: UUID(),
|
||||
name: "",
|
||||
slug: "",
|
||||
description: "",
|
||||
privacy: .visible,
|
||||
default: true,
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
createdBy: User()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TeamsTests: XCTestCase {
|
||||
func testTeamsList() throws {
|
||||
func testTeamsList() async throws {
|
||||
let expected = [Team(), Team()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.teams(in: "buildkite", byUser: UUID()))
|
||||
|
||||
context.client.send(.teams(in: "buildkite", byUser: UUID())) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -16,30 +17,23 @@ import FoundationNetworking
|
|||
|
||||
extension User {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
name: "Jeff",
|
||||
email: "jeff@buildkite.com",
|
||||
avatarUrl: URL(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000))
|
||||
self.init(
|
||||
id: UUID(),
|
||||
name: "Jeff",
|
||||
email: "jeff@buildkite.com",
|
||||
avatarUrl: URL(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class UsersTests: XCTestCase {
|
||||
func testUserMe() throws {
|
||||
func testUserMe() async throws {
|
||||
let expected = User()
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let response = try await context.client.send(.me)
|
||||
|
||||
context.client.send(.me) { result in
|
||||
do {
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
wait(for: [expectation])
|
||||
XCTAssertEqual(expected, response.content)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
// Copyright © 2020 Aaron Sky. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Buildkite
|
||||
import Foundation
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
|
@ -19,21 +19,34 @@ struct MockContext {
|
|||
|
||||
init() {
|
||||
let configuration = Configuration.default
|
||||
self.init(configuration: configuration, responses: [
|
||||
MockData.mockingSuccessNoContent(url: configuration.version.baseURL)
|
||||
])
|
||||
self.init(
|
||||
configuration: configuration,
|
||||
responses: [
|
||||
MockData.mockingSuccessNoContent(url: configuration.version.baseURL)
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
init<Content: Codable>(content: Content...) throws {
|
||||
init<Content: Codable>(
|
||||
content: Content...
|
||||
) throws {
|
||||
let configuration = Configuration.default
|
||||
try self.init(configuration: configuration, responses: content.map {
|
||||
try MockData.mockingSuccess(with: $0, url: configuration.version.baseURL)
|
||||
})
|
||||
try self.init(
|
||||
configuration: configuration,
|
||||
responses: content.map {
|
||||
try MockData.mockingSuccess(with: $0, url: configuration.version.baseURL)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private init(configuration: Configuration, responses: [(Data, URLResponse)]) {
|
||||
private init(
|
||||
configuration: Configuration,
|
||||
responses: [(Data, URLResponse)]
|
||||
) {
|
||||
let transport = MockTransport(responses: responses)
|
||||
client = BuildkiteClient(configuration: configuration,
|
||||
transport: transport)
|
||||
client = BuildkiteClient(
|
||||
configuration: configuration,
|
||||
transport: transport
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@testable import Buildkite
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
|
@ -143,9 +144,14 @@ extension MockData {
|
|||
}
|
||||
|
||||
private static func urlResponse(for url: URL, rawStatus status: Int) -> URLResponse {
|
||||
HTTPURLResponse(url: url,
|
||||
statusCode: status,
|
||||
httpVersion: "HTTP/1.1",
|
||||
headerFields: ["Link": #"<https://api.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds?api_key=f8582f070276d764ce3dd4c6d57be92574dccf86&page=3>; rel="prev",<https://api.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds?api_key=f8582f070276d764ce3dd4c6d57be92574dccf86&page=5>; rel="next",<https://api.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds?api_key=f8582f070276d764ce3dd4c6d57be92574dccf86&page=1>; rel="first", <https://api.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds?api_key=f8582f070276d764ce3dd4c6d57be92574dccf86&page=10>; rel="last""#])!
|
||||
HTTPURLResponse(
|
||||
url: url,
|
||||
statusCode: status,
|
||||
httpVersion: "HTTP/1.1",
|
||||
headerFields: [
|
||||
"Link":
|
||||
#"<https://api.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds?api_key=f8582f070276d764ce3dd4c6d57be92574dccf86&page=3>; rel="prev",<https://api.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds?api_key=f8582f070276d764ce3dd4c6d57be92574dccf86&page=5>; rel="next",<https://api.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds?api_key=f8582f070276d764ce3dd4c6d57be92574dccf86&page=1>; rel="first", <https://api.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds?api_key=f8582f070276d764ce3dd4c6d57be92574dccf86&page=10>; rel="last""#
|
||||
]
|
||||
)!
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
// Copyright © 2020 Aaron Sky. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Buildkite
|
||||
import Foundation
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
|
@ -25,7 +25,9 @@ final class MockTransport {
|
|||
var history: [URLRequest] = []
|
||||
var responses: [Transport.Output]
|
||||
|
||||
init(responses: [Transport.Output]) {
|
||||
init(
|
||||
responses: [Transport.Output]
|
||||
) {
|
||||
self.responses = responses
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +42,7 @@ extension MockTransport: Transport {
|
|||
completion(.success(responses.removeFirst()))
|
||||
}
|
||||
|
||||
#if canImport(Combine)
|
||||
#if canImport(Combine)
|
||||
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
|
||||
func sendPublisher(request: URLRequest) -> AnyPublisher<Output, Swift.Error> {
|
||||
history.append(request)
|
||||
|
@ -53,11 +55,12 @@ extension MockTransport: Transport {
|
|||
return
|
||||
}
|
||||
promise(.success(self.responses.removeFirst()))
|
||||
}.eraseToAnyPublisher()
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if compiler(>=5.5.2) && canImport(_Concurrency)
|
||||
#if compiler(>=5.5.2) && canImport(_Concurrency)
|
||||
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
|
||||
func send(request: URLRequest) async throws -> Output {
|
||||
history.append(request)
|
||||
|
@ -66,5 +69,5 @@ extension MockTransport: Transport {
|
|||
}
|
||||
return responses.removeFirst()
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue