Basic pagination support
This commit is contained in:
parent
fa81cfdf2c
commit
1b2c7472fa
|
@ -34,20 +34,6 @@
|
|||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "BuildkiteIntegrationTests"
|
||||
BuildableName = "BuildkiteIntegrationTests"
|
||||
BlueprintName = "BuildkiteIntegrationTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
|
@ -67,16 +53,6 @@
|
|||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "BuildkiteIntegrationTests"
|
||||
BuildableName = "BuildkiteIntegrationTests"
|
||||
BlueprintName = "BuildkiteIntegrationTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
|
|
|
@ -12,7 +12,7 @@ import Buildkite
|
|||
let client = Buildkite()
|
||||
client.token = "..."
|
||||
var cancellables: Set<AnyCancellable> = []
|
||||
client.sendPublisher(Build.Resources.ListAll())
|
||||
client.sendPublisher(Build.Resources.Get(organization: "wayfair", pipeline: "merge-train-ci", build: 162))
|
||||
.map(\.content)
|
||||
.sink(receiveCompletion: { result in
|
||||
if case let .failure(error) = result {
|
||||
|
|
|
@ -32,7 +32,7 @@ public struct Artifact: Codable, Equatable {
|
|||
public var fileSize: Int
|
||||
public var sha1sum: String
|
||||
|
||||
public struct URLs: Codable {
|
||||
public struct URLs: Codable, Equatable {
|
||||
public var url: URL
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,29 +12,72 @@ import Foundation
|
|||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
public struct Job: Codable, Equatable {
|
||||
public struct Agent: Codable, Equatable {
|
||||
public var id: UUID
|
||||
public var url: URL
|
||||
public var name: String
|
||||
public enum Job: Codable, Equatable {
|
||||
case script(Command)
|
||||
case waiter(Wait)
|
||||
case manual(Block)
|
||||
case trigger(Trigger)
|
||||
|
||||
private enum Unassociated: String, Codable {
|
||||
case script
|
||||
case waiter
|
||||
case manual
|
||||
case trigger
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let type = try container.decode(Unassociated.self, forKey: .type)
|
||||
switch type {
|
||||
case .script:
|
||||
self = .script(try Command(from: decoder))
|
||||
case .waiter:
|
||||
self = .waiter(try Wait(from: decoder))
|
||||
case .manual:
|
||||
self = .manual(try Block(from: decoder))
|
||||
case .trigger:
|
||||
self = .trigger(try Trigger(from: decoder))
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
switch self {
|
||||
case .script(let step):
|
||||
try step.encode(to: encoder)
|
||||
case .waiter(let step):
|
||||
try step.encode(to: encoder)
|
||||
case .manual(let step):
|
||||
try step.encode(to: encoder)
|
||||
case .trigger(let step):
|
||||
try step.encode(to: encoder)
|
||||
}
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case type
|
||||
}
|
||||
|
||||
public struct Command: Codable, Equatable {
|
||||
public struct AgentRef: Codable, Equatable {
|
||||
public var id: UUID
|
||||
public var type: String
|
||||
public var name: String?
|
||||
public var stepKey: String?
|
||||
public var agentQueryRules: [String]
|
||||
public var state: String?
|
||||
public var buildUrl: URL?
|
||||
public var webUrl: URL?
|
||||
public var logUrl: URL?
|
||||
public var rawLogUrl: URL?
|
||||
public var artifactsUrl: URL?
|
||||
public var name: String
|
||||
public var url: URL
|
||||
}
|
||||
public let type = "script"
|
||||
public var id: UUID
|
||||
public var name: String
|
||||
public var command: String?
|
||||
public var stepKey: String?
|
||||
public var buildUrl: URL
|
||||
public var webUrl: URL
|
||||
public var logUrl: URL
|
||||
public var rawLogUrl: URL
|
||||
public var artifactsUrl: URL
|
||||
public var softFailed: Bool
|
||||
public var exitStatus: Int?
|
||||
public var exitStatus: Int
|
||||
public var artifactPaths: String?
|
||||
public var agent: Agent?
|
||||
public var agentQueryRules: [String]
|
||||
public var agent: AgentRef?
|
||||
public var createdAt: Date
|
||||
public var scheduledAt: Date
|
||||
public var runnableAt: Date?
|
||||
|
@ -45,10 +88,16 @@ public struct Job: Codable, Equatable {
|
|||
public var retriesCount: Int?
|
||||
public var parallelGroupIndex: Int?
|
||||
public var parallelGroupTotal: Int?
|
||||
}
|
||||
|
||||
public struct Unblocked: Codable, Equatable {
|
||||
public struct Wait: Codable, Equatable {
|
||||
public let type = "waiter"
|
||||
public var id: UUID
|
||||
}
|
||||
|
||||
public struct Block: Codable, Equatable {
|
||||
public let type = "manual"
|
||||
public var id: UUID
|
||||
public var type: String
|
||||
public var label: String
|
||||
public var state: String
|
||||
public var webUrl: URL?
|
||||
|
@ -58,6 +107,26 @@ public struct Job: Codable, Equatable {
|
|||
public var unblockUrl: URL
|
||||
}
|
||||
|
||||
public struct Trigger: Codable, Equatable {
|
||||
public let type = "trigger"
|
||||
public var name: String
|
||||
public var state: String
|
||||
public var buildUrl: URL
|
||||
public var webUrl: URL
|
||||
public var createdAt: Date
|
||||
public var scheduledAt: Date
|
||||
public var finishedAt: Date?
|
||||
public var runnableAt: Date?
|
||||
public var triggeredBuild: TriggeredBuild
|
||||
|
||||
public struct TriggeredBuild: Codable, Equatable {
|
||||
public var id: UUID
|
||||
public var number: Int
|
||||
public var url: URL
|
||||
public var webUrl: URL
|
||||
}
|
||||
}
|
||||
|
||||
public struct LogOutput: Codable {
|
||||
public var url: URL
|
||||
public var content: String
|
||||
|
|
|
@ -159,7 +159,6 @@ extension Pipeline {
|
|||
public var triggerBranch: String?
|
||||
public var triggerAsync: Bool?
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Constants.swift
|
||||
// Formatters.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 3/23/20.
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// Pagination.swift
|
||||
//
|
||||
//
|
||||
// Created by Aaron Sky on 5/5/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
public struct Page {
|
||||
var nextPage: Int?
|
||||
var previousPage: Int?
|
||||
var firstPage: Int?
|
||||
var lastPage: Int?
|
||||
|
||||
init?(for header: String) {
|
||||
guard !header.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
for link in header.split(separator: ",") {
|
||||
let segments = link
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
.split(separator: ";")
|
||||
guard
|
||||
segments.count <= 2,
|
||||
|
||||
let urlString = segments.first,
|
||||
urlString.hasPrefix("<") && urlString.hasSuffix(">"),
|
||||
|
||||
let url = URLComponents(string: String(urlString.dropFirst().dropLast())),
|
||||
|
||||
let pageString = url.queryItems?.first(where: { $0.name == "page" })?.value,
|
||||
let page = Int(pageString) else {
|
||||
continue
|
||||
}
|
||||
|
||||
for segment in segments.dropFirst() {
|
||||
switch segment.trimmingCharacters(in: .whitespacesAndNewlines) {
|
||||
case "rel=\"next\"":
|
||||
nextPage = page
|
||||
case "rel=\"prev\"":
|
||||
previousPage = page
|
||||
case "rel=\"first\"":
|
||||
firstPage = page
|
||||
case "rel=\"last\"":
|
||||
lastPage = page
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct PageOptions {
|
||||
public var page: Int
|
||||
public var perPage: Int
|
||||
|
||||
public init(page: Int, perPage: Int) {
|
||||
self.page = page
|
||||
self.perPage = perPage
|
||||
}
|
||||
}
|
||||
|
||||
extension Array where Element == URLQueryItem {
|
||||
init(options: PageOptions) {
|
||||
self.init()
|
||||
append(URLQueryItem(name: "page", value: String(options.page)))
|
||||
append(URLQueryItem(name: "per_page", value: String(options.perPage)))
|
||||
}
|
||||
}
|
||||
|
|
@ -32,11 +32,6 @@ extension Resource {
|
|||
}
|
||||
|
||||
extension URLRequest {
|
||||
init<R: Resource & HasRequestBody>(_ resource: R, configuration: Configuration, encoder: JSONEncoder) throws {
|
||||
self.init(resource, configuration: configuration)
|
||||
httpBody = try encoder.encode(resource.body)
|
||||
}
|
||||
|
||||
init<R: Resource>(_ resource: R, configuration: Configuration) {
|
||||
let url = configuration.url(for: resource.path)
|
||||
var request = URLRequest(url: url)
|
||||
|
@ -44,4 +39,9 @@ extension URLRequest {
|
|||
resource.transformRequest(&request)
|
||||
self = request
|
||||
}
|
||||
|
||||
init<R: Resource & HasRequestBody>(_ resource: R, configuration: Configuration, encoder: JSONEncoder) throws {
|
||||
self.init(resource, configuration: configuration)
|
||||
httpBody = try encoder.encode(resource.body)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,15 @@ enum ResponseError: Error {
|
|||
public struct Response<T> {
|
||||
public let content: T
|
||||
public let response: URLResponse
|
||||
public let page: Page?
|
||||
|
||||
init(content: T, response: URLResponse) {
|
||||
self.content = content
|
||||
self.response = response
|
||||
if let response = response as? HTTPURLResponse, let link = response.allHeaderFields["Link"] as? String {
|
||||
page = Page(for: link)
|
||||
} else {
|
||||
page = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ extension Agent.Resources {
|
|||
/// organization slug
|
||||
public var organization: String
|
||||
|
||||
public var pageOptions: PageOptions?
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/agents"
|
||||
}
|
||||
|
@ -31,6 +33,17 @@ extension Agent.Resources {
|
|||
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
|
||||
}
|
||||
if let options = pageOptions {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
}
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
||||
public struct Get: Resource, HasResponseBody {
|
||||
|
|
|
@ -28,6 +28,8 @@ extension Annotation.Resources {
|
|||
/// build number
|
||||
public var build: Int
|
||||
|
||||
public var pageOptions: PageOptions?
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/annotations"
|
||||
}
|
||||
|
@ -37,5 +39,16 @@ extension Annotation.Resources {
|
|||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = pageOptions {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
}
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,23 +12,25 @@ import FoundationNetworking
|
|||
#endif
|
||||
|
||||
extension Artifact {
|
||||
enum Resources { }
|
||||
public enum Resources { }
|
||||
}
|
||||
|
||||
extension Artifact.Resources {
|
||||
/// List artifacts for a build
|
||||
///
|
||||
/// Returns a paginated list of a build’s artifacts across all of its jobs.
|
||||
struct ListByBuild: Resource, HasResponseBody {
|
||||
typealias Content = [Artifact]
|
||||
public struct ListByBuild: Resource, HasResponseBody {
|
||||
public typealias Content = [Artifact]
|
||||
/// organization slug
|
||||
var organization: String
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
var pipeline: String
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
var build: Int
|
||||
public var build: Int
|
||||
|
||||
var path: String {
|
||||
public var pageOptions: PageOptions?
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/artifacts"
|
||||
}
|
||||
|
||||
|
@ -37,23 +39,36 @@ extension Artifact.Resources {
|
|||
self.pipeline = pipeline
|
||||
self.build = build
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = pageOptions {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
}
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
||||
/// List artifacts for a job
|
||||
///
|
||||
/// Returns a paginated list of a job’s artifacts.
|
||||
struct ListByJob: Resource, HasResponseBody {
|
||||
typealias Content = [Artifact]
|
||||
public struct ListByJob: Resource, HasResponseBody {
|
||||
public typealias Content = [Artifact]
|
||||
/// organization slug
|
||||
var organization: String
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
var pipeline: String
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
var build: Int
|
||||
public var build: Int
|
||||
/// job ID
|
||||
var jobId: UUID
|
||||
public var jobId: UUID
|
||||
|
||||
var path: String {
|
||||
public var pageOptions: PageOptions?
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts"
|
||||
}
|
||||
|
||||
|
@ -63,23 +78,34 @@ extension Artifact.Resources {
|
|||
self.build = build
|
||||
self.jobId = jobId
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = pageOptions {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
}
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an artifact
|
||||
struct Get: Resource, HasResponseBody {
|
||||
typealias Content = Artifact
|
||||
public struct Get: Resource, HasResponseBody {
|
||||
public typealias Content = Artifact
|
||||
/// organization slug
|
||||
var organization: String
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
var pipeline: String
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
var build: Int
|
||||
public var build: Int
|
||||
/// job ID
|
||||
var jobId: UUID
|
||||
public var jobId: UUID
|
||||
/// artifact ID
|
||||
var artifactId: UUID
|
||||
public var artifactId: UUID
|
||||
|
||||
var path: String {
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts/\(artifactId)"
|
||||
}
|
||||
|
||||
|
@ -95,20 +121,20 @@ extension Artifact.Resources {
|
|||
/// Download an artifact
|
||||
///
|
||||
///
|
||||
struct Download: Resource {
|
||||
typealias Content = Artifact.URLs
|
||||
public struct Download: Resource, HasResponseBody {
|
||||
public typealias Content = Artifact.URLs
|
||||
/// organization slug
|
||||
var organization: String
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
var pipeline: String
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
var build: Int
|
||||
public var build: Int
|
||||
/// job ID
|
||||
var jobId: UUID
|
||||
public var jobId: UUID
|
||||
/// artifact ID
|
||||
var artifactId: UUID
|
||||
public var artifactId: UUID
|
||||
|
||||
var path: String {
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts/\(artifactId)/download"
|
||||
}
|
||||
|
||||
|
@ -124,27 +150,23 @@ extension Artifact.Resources {
|
|||
/// Delete an artifact
|
||||
///
|
||||
///
|
||||
struct Delete: Resource {
|
||||
typealias Content = Void
|
||||
public struct Delete: Resource {
|
||||
public typealias Content = Void
|
||||
/// organization slug
|
||||
var organization: String
|
||||
public var organization: String
|
||||
/// pipeline slug
|
||||
var pipeline: String
|
||||
public var pipeline: String
|
||||
/// build number
|
||||
var build: Int
|
||||
public var build: Int
|
||||
/// job ID
|
||||
var jobId: UUID
|
||||
public var jobId: UUID
|
||||
/// artifact ID
|
||||
var artifactId: UUID
|
||||
public var artifactId: UUID
|
||||
|
||||
var path: String {
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds/\(build)/jobs/\(jobId)/artifacts/\(artifactId)"
|
||||
}
|
||||
|
||||
func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "DELETE"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, build: Int, jobId: UUID, artifactId: UUID) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
|
@ -152,5 +174,9 @@ extension Artifact.Resources {
|
|||
self.jobId = jobId
|
||||
self.artifactId = artifactId
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
request.httpMethod = "DELETE"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,13 @@ extension Build.Resources {
|
|||
public typealias Content = [Build]
|
||||
public let path = "builds"
|
||||
|
||||
public var options: QueryOptions?
|
||||
public var queryOptions: QueryOptions?
|
||||
|
||||
public init(options: Build.Resources.QueryOptions? = nil) {
|
||||
self.options = options
|
||||
public var pageOptions: PageOptions?
|
||||
|
||||
public init(queryOptions: Build.Resources.QueryOptions? = nil, pageOptions: PageOptions? = nil) {
|
||||
self.queryOptions = queryOptions
|
||||
self.pageOptions = pageOptions
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
|
@ -35,9 +38,14 @@ extension Build.Resources {
|
|||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = options {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
var queryItems: [URLQueryItem] = []
|
||||
if let options = queryOptions {
|
||||
queryItems.append(contentsOf: [URLQueryItem](options: options))
|
||||
}
|
||||
if let options = pageOptions {
|
||||
queryItems.append(contentsOf: [URLQueryItem](options: options))
|
||||
}
|
||||
components.queryItems = queryItems
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
@ -51,15 +59,18 @@ extension Build.Resources {
|
|||
/// organization slug
|
||||
public var organization: String
|
||||
|
||||
public var options: QueryOptions?
|
||||
public var queryOptions: QueryOptions?
|
||||
|
||||
public var pageOptions: PageOptions?
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/builds"
|
||||
}
|
||||
|
||||
public init(organization: String, options: Build.Resources.QueryOptions? = nil) {
|
||||
public init(organization: String, queryOptions: Build.Resources.QueryOptions? = nil, pageOptions: PageOptions? = nil) {
|
||||
self.organization = organization
|
||||
self.options = options
|
||||
self.queryOptions = queryOptions
|
||||
self.pageOptions = pageOptions
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
|
@ -67,9 +78,14 @@ extension Build.Resources {
|
|||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = options {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
var queryItems: [URLQueryItem] = []
|
||||
if let options = queryOptions {
|
||||
queryItems.append(contentsOf: [URLQueryItem](options: options))
|
||||
}
|
||||
if let options = pageOptions {
|
||||
queryItems.append(contentsOf: [URLQueryItem](options: options))
|
||||
}
|
||||
components.queryItems = queryItems
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
@ -84,16 +100,19 @@ extension Build.Resources {
|
|||
/// pipeline slug
|
||||
public var pipeline: String
|
||||
|
||||
public var options: QueryOptions?
|
||||
public var queryOptions: QueryOptions?
|
||||
|
||||
public var pageOptions: PageOptions?
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines/\(pipeline)/builds"
|
||||
}
|
||||
|
||||
public init(organization: String, pipeline: String, options: Build.Resources.QueryOptions? = nil) {
|
||||
public init(organization: String, pipeline: String, queryOptions: Build.Resources.QueryOptions? = nil, pageOptions: PageOptions? = nil) {
|
||||
self.organization = organization
|
||||
self.pipeline = pipeline
|
||||
self.options = options
|
||||
self.queryOptions = queryOptions
|
||||
self.pageOptions = pageOptions
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
|
@ -101,9 +120,14 @@ extension Build.Resources {
|
|||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = options {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
var queryItems: [URLQueryItem] = []
|
||||
if let options = queryOptions {
|
||||
queryItems.append(contentsOf: [URLQueryItem](options: options))
|
||||
}
|
||||
if let options = pageOptions {
|
||||
queryItems.append(contentsOf: [URLQueryItem](options: options))
|
||||
}
|
||||
components.queryItems = queryItems
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
@ -260,18 +284,6 @@ extension Build.Resources {
|
|||
}
|
||||
|
||||
public struct QueryOptions {
|
||||
internal init(branches: [String] = [], commit: String? = nil, createdFrom: Date? = nil, createdTo: Date? = nil, creator: UUID? = nil, finishedFrom: Date? = nil, includeRetriedJobs: Bool? = nil, metadata: [String : String] = [:], state: String? = nil) {
|
||||
self.branches = branches
|
||||
self.commit = commit
|
||||
self.createdFrom = createdFrom
|
||||
self.createdTo = createdTo
|
||||
self.creator = creator
|
||||
self.finishedFrom = finishedFrom
|
||||
self.includeRetriedJobs = includeRetriedJobs
|
||||
self.metadata = metadata
|
||||
self.state = state
|
||||
}
|
||||
|
||||
/// Filters the results by the given branch or branches.
|
||||
public var branches: [String] = []
|
||||
/// Filters the results by the commit (only works for full sha, not for shortened ones).
|
||||
|
@ -290,6 +302,18 @@ extension Build.Resources {
|
|||
public var metadata: [String: String] = [:]
|
||||
/// Filters the results by the given build state. The finished state is a shortcut to automatically search for builds with passed, failed, blocked, canceled states.
|
||||
public var state: String?
|
||||
|
||||
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: String? = nil) {
|
||||
self.branches = branches
|
||||
self.commit = commit
|
||||
self.createdFrom = createdFrom
|
||||
self.createdTo = createdTo
|
||||
self.creator = creator
|
||||
self.finishedFrom = finishedFrom
|
||||
self.includeRetriedJobs = includeRetriedJobs
|
||||
self.metadata = metadata
|
||||
self.state = state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,22 @@ extension Organization.Resources {
|
|||
public typealias Content = [Organization]
|
||||
public let path = "organizations"
|
||||
|
||||
public init() {}
|
||||
public var pageOptions: PageOptions?
|
||||
|
||||
public init(pageOptions: PageOptions? = nil) {
|
||||
self.pageOptions = pageOptions
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = pageOptions {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
}
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an organization
|
||||
|
|
|
@ -24,12 +24,26 @@ extension Pipeline.Resources {
|
|||
/// organization slug
|
||||
public var organization: String
|
||||
|
||||
public var pageOptions: PageOptions?
|
||||
|
||||
public var path: String {
|
||||
"organizations/\(organization)/pipelines"
|
||||
}
|
||||
|
||||
public init(organization: String) {
|
||||
public init(organization: String, pageOptions: PageOptions? = nil) {
|
||||
self.organization = organization
|
||||
self.pageOptions = pageOptions
|
||||
}
|
||||
|
||||
public func transformRequest(_ request: inout URLRequest) {
|
||||
guard let url = request.url,
|
||||
var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
||||
return
|
||||
}
|
||||
if let options = pageOptions {
|
||||
components.queryItems = [URLQueryItem](options: options)
|
||||
}
|
||||
request.url = components.url
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,30 @@ extension Agent {
|
|||
version: "3.20.0",
|
||||
creator: User(),
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
job: Job(),
|
||||
job: Job.script(Job.Command(id: UUID(),
|
||||
name: "📦",
|
||||
command: nil,
|
||||
stepKey: nil,
|
||||
buildUrl: URL(),
|
||||
webUrl: URL(),
|
||||
logUrl: URL(),
|
||||
rawLogUrl: URL(),
|
||||
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) ),
|
||||
lastJobFinishedAt: nil,
|
||||
priority: nil,
|
||||
metaData: [])
|
||||
|
|
|
@ -85,13 +85,15 @@ class ArtifactsTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testArtifactsDownload() throws {
|
||||
let context = MockContext()
|
||||
let expected = Artifact.URLs(url: URL())
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
||||
context.client.send(Artifact.Resources.Download(organization: "buildkite", pipeline: "my-pipeline", build: 1, jobId: UUID(), artifactId: UUID())) { result in
|
||||
do {
|
||||
_ = try result.get()
|
||||
let response = try result.get()
|
||||
XCTAssertEqual(expected, response.content)
|
||||
} catch {
|
||||
XCTFail(error.localizedDescription)
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ class BuildsTests: XCTestCase {
|
|||
let expected = [Build(), Build()]
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let resource = Build.Resources.ListAll(options: Build.Resources.QueryOptions(branches: ["master"],
|
||||
let resource = Build.Resources.ListAll(queryOptions: Build.Resources.QueryOptions(branches: ["master"],
|
||||
commit: "HEAD",
|
||||
createdFrom: Date(timeIntervalSince1970: 1000),
|
||||
createdTo: Date(timeIntervalSince1970: 1000),
|
||||
|
|
|
@ -13,40 +13,9 @@ import XCTest
|
|||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
extension Job {
|
||||
init() {
|
||||
self.init(id: UUID(),
|
||||
type: "script",
|
||||
name: "📦",
|
||||
stepKey: "package",
|
||||
agentQueryRules: [],
|
||||
state: "finished",
|
||||
buildUrl: URL(),
|
||||
webUrl: URL(),
|
||||
logUrl: URL(),
|
||||
rawLogUrl: URL(),
|
||||
artifactsUrl: URL(),
|
||||
command: "echo 1",
|
||||
softFailed: false,
|
||||
exitStatus: 0,
|
||||
artifactPaths: "",
|
||||
agent: nil,
|
||||
createdAt: Date(timeIntervalSince1970: 1000),
|
||||
scheduledAt: Date(timeIntervalSince1970: 1000),
|
||||
runnableAt: nil,
|
||||
startedAt: nil,
|
||||
finishedAt: nil,
|
||||
retried: false,
|
||||
retriedInJobId: UUID(),
|
||||
retriesCount: 0,
|
||||
parallelGroupIndex: nil,
|
||||
parallelGroupTotal: nil)
|
||||
}
|
||||
}
|
||||
|
||||
class JobsTests: XCTestCase {
|
||||
func testJobsRetry() throws {
|
||||
let expected = Job()
|
||||
let expected = Job.waiter(Job.Wait(id: UUID()))
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
|
@ -64,7 +33,7 @@ class JobsTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testJobsUnblock() throws {
|
||||
let expected = Job()
|
||||
let expected = Job.waiter(Job.Wait(id: UUID()))
|
||||
let context = try MockContext(content: expected)
|
||||
|
||||
let body = Job.Resources.Unblock.Body()
|
||||
|
|
Loading…
Reference in New Issue