buildkite-swift/Sources/Buildkite/Models/Job.swift

444 lines
14 KiB
Swift

//
// Job.swift
// Buildkite
//
// Created by Aaron Sky on 5/3/20.
// Copyright © 2020 Aaron Sky. All rights reserved.
//
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
/// Information about a job created as part of a build.
public enum Job: Codable, Equatable, Hashable, Sendable {
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
}
/// Command job.
public struct Command: Codable, Equatable, Hashable, Identifiable, Sendable {
/// Type of the job. Always `"script"`.
public var type = "script"
/// ID of the job.
public var id: UUID
/// ID of the job to be used with the GraphQL API.
public var graphqlId: String
/// Name of the job.
public var name: String?
/// Job state.
public var state: String?
/// Command(s) the job will run.
public var command: String?
/// A key to reference the job by using the [buildkite-agent step command](https://buildkite.com/docs/agent/v3/cli-step).
public var stepKey: String?
/// Build URL.
public var buildURL: URL
/// Human-readable URL of this job in the Buildkite dashboard.
public var webURL: URL
/// Followable URL to the job's log output.
public var logURL: Followable<Job.Resources.LogOutput>
/// Followable URL to the job's raw log output.
public var rawLogURL: Followable<Job.Resources.LogOutput.Alternative>
/// Artifacts URL.
public var artifactsURL: URL
/// Whether or not the job can "soft fail".
public var softFailed: Bool
/// The exit code the job's command concluded with.
public var exitStatus: Int?
/// Artifact paths to files that will be automatically uploaded as artifacts.
public var artifactPaths: String?
/// A list of [agent tag](https://buildkite.com/docs/agent/v3/cli-start#setting-tags)
/// keys to values to [target specific agents](https://buildkite.com/docs/agent/v3/cli-start#agent-targeting)
/// that this job was configured to target.
public var agentQueryRules: [String]
/// The agent this job has been assigned to, if any.
public var agent: AgentRef?
/// When the job was created.
public var createdAt: Date
/// When the job was scheduled.
public var scheduledAt: Date?
/// When the job became runnable.
public var runnableAt: Date?
/// When the job was started.
public var startedAt: Date?
/// When the job finished.
public var finishedAt: Date?
/// Whether or not the job has been retried.
public var retried: Bool
/// The ID of the job it was retried into, if any.
public var retriedInJobId: UUID?
/// The number of times this job has been retried.
public var retriesCount: Int?
/// The index out of parallel executions of this job.
public var parallelGroupIndex: Int?
/// Total number of parallel executions of this job.
public var parallelGroupTotal: Int?
public init(
id: UUID,
graphqlId: String,
name: String? = nil,
state: String? = nil,
command: String? = nil,
stepKey: String? = nil,
buildURL: URL,
webURL: URL,
logURL: Followable<Job.Resources.LogOutput>,
rawLogURL: Followable<Job.Resources.LogOutput.Alternative>,
artifactsURL: URL,
softFailed: Bool,
exitStatus: Int? = nil,
artifactPaths: String? = nil,
agentQueryRules: [String],
agent: AgentRef? = nil,
createdAt: Date,
scheduledAt: Date? = nil,
runnableAt: Date? = nil,
startedAt: Date? = nil,
finishedAt: Date? = nil,
retried: Bool,
retriedInJobId: UUID? = nil,
retriesCount: Int? = nil,
parallelGroupIndex: Int? = nil,
parallelGroupTotal: Int? = nil
) {
self.id = id
self.graphqlId = graphqlId
self.name = name
self.state = state
self.command = command
self.stepKey = stepKey
self.buildURL = buildURL
self.webURL = webURL
self.logURL = logURL
self.rawLogURL = rawLogURL
self.artifactsURL = artifactsURL
self.softFailed = softFailed
self.exitStatus = exitStatus
self.artifactPaths = artifactPaths
self.agentQueryRules = agentQueryRules
self.agent = agent
self.createdAt = createdAt
self.scheduledAt = scheduledAt
self.runnableAt = runnableAt
self.startedAt = startedAt
self.finishedAt = finishedAt
self.retried = retried
self.retriedInJobId = retriedInJobId
self.retriesCount = retriesCount
self.parallelGroupIndex = parallelGroupIndex
self.parallelGroupTotal = parallelGroupTotal
}
/// Reference to an agent.
public struct AgentRef: Codable, Equatable, Hashable, Sendable {
/// ID of the agent.
public var id: UUID
/// Name of the agent.
public var name: String
/// Followable URL to the specific agent.
public var url: Followable<Agent.Resources.Get>
public init(
id: UUID,
name: String,
url: Followable<Agent.Resources.Get>
) {
self.id = id
self.name = name
self.url = url
}
}
private enum CodingKeys: String, CodingKey {
case type
case id
case graphqlId = "graphql_id"
case name
case state
case command
case stepKey = "step_key"
case buildURL = "build_url"
case webURL = "web_url"
case logURL = "log_url"
case rawLogURL = "raw_log_url"
case artifactsURL = "artifacts_url"
case softFailed = "soft_failed"
case exitStatus = "exit_status"
case artifactPaths = "artifact_paths"
case agentQueryRules = "agent_query_rules"
case agent
case createdAt = "created_at"
case scheduledAt = "scheduled_at"
case runnableAt = "runnable_at"
case startedAt = "started_at"
case finishedAt = "finished_at"
case retried
case retriedInJobId = "retried_in_job_id"
case retriesCount = "retries_count"
case parallelGroupIndex = "parallel_group_index"
case parallelGroupTotal = "parallel_group_total"
}
}
/// Wait job.
public struct Wait: Codable, Equatable, Hashable, Identifiable, Sendable {
/// Type of the job. Always `"waiter"`.
public var type = "waiter"
/// ID of the job.
public var id: UUID
/// ID of the job to be used with the GraphQL API.
public var graphqlId: String
public init(
id: UUID,
graphqlId: String
) {
self.id = id
self.graphqlId = graphqlId
}
private enum CodingKeys: String, CodingKey {
case type
case id
case graphqlId = "graphql_id"
}
}
/// Block job.
public struct Block: Codable, Equatable, Hashable, Identifiable, Sendable {
/// Type of the job. Always `"manual"`.
public var type = "manual"
/// ID of the job.
public var id: UUID
/// ID of the job to be used with the GraphQL API.
public var graphqlId: String
/// Label for the job.
public var label: String
/// Job state.
public var state: String
/// Human-readable URL of this job in the Buildkite dashboard.
public var webURL: URL?
/// User who unblocked this job, if any.
public var unblockedBy: User?
/// When this job was unblocked.
public var unblockedAt: Date?
/// Whether or not this job can be unblocked.
public var unblockable: Bool
/// Human-readable URL to unblock this job.
public var unblockURL: URL
public init(
id: UUID,
graphqlId: String,
label: String,
state: String,
webURL: URL? = nil,
unblockedBy: User? = nil,
unblockedAt: Date? = nil,
unblockable: Bool,
unblockURL: URL
) {
self.id = id
self.graphqlId = graphqlId
self.label = label
self.state = state
self.webURL = webURL
self.unblockedBy = unblockedBy
self.unblockedAt = unblockedAt
self.unblockable = unblockable
self.unblockURL = unblockURL
}
private enum CodingKeys: String, CodingKey {
case type
case id
case graphqlId = "graphql_id"
case label
case state
case webURL = "web_url"
case unblockedBy = "unblocked_by"
case unblockedAt = "unblocked_at"
case unblockable
case unblockURL = "unblock_url"
}
}
/// Trigger job.
public struct Trigger: Codable, Equatable, Hashable, Sendable {
/// Type of the job. Always `"trigger"`.
public var type = "trigger"
/// Name of the job.
public var name: String?
/// Job state.
public var state: String?
/// Build URL.
public var buildURL: URL
/// Human-readable URL of this job in the Buildkite dashboard.
public var webURL: URL
/// When the job was created.
public var createdAt: Date
/// When the job was scheduled.
public var scheduledAt: Date?
/// When the job finished.
public var finishedAt: Date?
/// When the build became runnable.
public var runnableAt: Date?
/// Build that was triggered by this job.
public var triggeredBuild: TriggeredBuild?
public init(
name: String? = nil,
state: String? = nil,
buildURL: URL,
webURL: URL,
createdAt: Date,
scheduledAt: Date? = nil,
finishedAt: Date? = nil,
runnableAt: Date? = nil,
triggeredBuild: TriggeredBuild? = nil
) {
self.name = name
self.state = state
self.buildURL = buildURL
self.webURL = webURL
self.createdAt = createdAt
self.scheduledAt = scheduledAt
self.finishedAt = finishedAt
self.runnableAt = runnableAt
self.triggeredBuild = triggeredBuild
}
/// Build triggered by this job.
public struct TriggeredBuild: Codable, Equatable, Hashable, Identifiable, Sendable {
/// ID of the triggered build.
public var id: UUID
/// Build number.
public var number: Int
/// Build URL.
public var url: URL
/// Human-readable URL to this build in the Buildkite dashboard.
public var webURL: URL
public init(
id: UUID,
number: Int,
url: URL,
webURL: URL
) {
self.id = id
self.number = number
self.url = url
self.webURL = webURL
}
private enum CodingKeys: String, CodingKey {
case id
case number
case url
case webURL = "web_url"
}
}
private enum CodingKeys: String, CodingKey {
case type
case name
case state
case buildURL = "build_url"
case webURL = "web_url"
case createdAt = "created_at"
case scheduledAt = "scheduled_at"
case finishedAt = "finished_at"
case runnableAt = "runnable_at"
case triggeredBuild = "triggered_build"
}
}
/// Log output from a job.
public struct LogOutput: Codable, Equatable, Hashable, Sendable {
/// Followable URL to this specific job's log output.
public var url: Followable<Job.Resources.LogOutput>
/// Log content.
public var content: String
/// Size of the logs in bytes.
public var size: Int
/// Header timestamps.
public var headerTimes: [Int]
public init(
url: Followable<Job.Resources.LogOutput>,
content: String,
size: Int,
headerTimes: [Int]
) {
self.url = url
self.content = content
self.size = size
self.headerTimes = headerTimes
}
private enum CodingKeys: String, CodingKey {
case url
case content
case size
case headerTimes = "header_times"
}
}
/// Environment variables for a job.
public struct EnvironmentVariables: Codable, Equatable, Hashable, Sendable {
public var env: [String: String]
public init(
env: [String: String]
) {
self.env = env
}
}
}