Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 54 additions & 3 deletions api/v1alpha2/taskpipeline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,40 @@ const (
TaskPipelineConditionSucceeded = "Succeeded"
)

// PipelineStagePhaseSkipped means the stage's conditions were not met, so the
// stage created no Tasks. It appears only in PipelineStageStatus.
const PipelineStagePhaseSkipped TaskPhase = "Skipped"

// PipelineConditionOperator compares a rendered condition input against a set of values.
// +kubebuilder:validation:Enum=In;NotIn
type PipelineConditionOperator string

const (
// PipelineConditionOperatorIn is met when the input equals one of the values.
PipelineConditionOperatorIn PipelineConditionOperator = "In"
// PipelineConditionOperatorNotIn is met when the input equals none of the values.
PipelineConditionOperatorNotIn PipelineConditionOperator = "NotIn"
)

// PipelineStageCondition gates a stage on a value rendered from earlier stages.
type PipelineStageCondition struct {
// Input is a Go template rendered with .Params and .Stages, the results of
// completed earlier stages. Leading and trailing whitespace is trimmed from the
// rendered value before it is compared.
// +kubebuilder:validation:MinLength=1
Input string `json:"input"`

// Operator compares the rendered input against values.
Operator PipelineConditionOperator `json:"operator"`

// Values is the set the rendered input is compared against. Comparison is
// exact and case-sensitive.
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=32
// +listType=atomic
Values []string `json:"values"`
}

// PipelineMatrix defines an ordered set of values used to create stage Tasks.
type PipelineMatrix struct {
// Items contains the values exposed under .Matrix for each Task. Each item
Expand All @@ -37,8 +71,8 @@ type PipelineMatrix struct {
}

// PipelineTaskTemplate defines Tasks created for a pipeline stage.
// Prompt and branch support Go text/template expressions. The current matrix
// values are available as .Matrix. Results from completed stages are available
// Prompt and branch support Go text/template expressions. The pipeline's params
// are available as .Params, and the current matrix values as .Matrix. Results from completed stages are available
// as .Stages, keyed by stage name. Each value lists that stage's Task results
// in index order, with Name, Matrix, Results, and Outputs fields.
//
Expand Down Expand Up @@ -80,26 +114,43 @@ type PipelineStage struct {
// Matrix expands the stage into parallel Tasks.
// +optional
Matrix *PipelineMatrix `json:"matrix,omitempty"`

// Conditions must all be met for the stage to run. They are evaluated when
// the stage would otherwise start. A stage whose conditions are not met is
// Skipped: it creates no Tasks, and later stages proceed as if it succeeded.
// +optional
// +kubebuilder:validation:MaxItems=8
// +listType=atomic
Conditions []PipelineStageCondition `json:"conditions,omitempty"`
}

// TaskPipelineSpec defines an ordered sequence of stages.
//
// +kubebuilder:validation:XValidation:rule="self.stages.all(stage, self.stages.exists_one(candidate, candidate.name == stage.name))",message="stage names must be unique"
// +kubebuilder:validation:XValidation:rule="self.stages == oldSelf.stages",message="TaskPipeline stages are immutable after creation"
// +kubebuilder:validation:XValidation:rule="has(self.params) == has(oldSelf.params) && (!has(self.params) || self.params == oldSelf.params)",message="TaskPipeline params are immutable after creation"
type TaskPipelineSpec struct {
// Stages execute in order. Tasks within a matrix stage execute in parallel.
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=64
// +listType=atomic
Stages []PipelineStage `json:"stages"`

// Params are string values exposed to stage prompt, branch, and condition
// templates as .Params. A TaskSpawner with pipelineTemplate sets them from
// the work item's template variables.
// +optional
// +kubebuilder:validation:MaxProperties=64
Params map[string]string `json:"params,omitempty"`
}

// PipelineStageStatus summarizes the Tasks created for one pipeline stage.
type PipelineStageStatus struct {
// Name identifies the pipeline stage.
Name string `json:"name"`

// Phase uses the Task phase vocabulary to summarize this stage's Tasks.
// Phase uses the Task phase vocabulary to summarize this stage's Tasks,
// plus Skipped when the stage's conditions were not met.
// +optional
Phase TaskPhase `json:"phase,omitempty"`

Expand Down
36 changes: 30 additions & 6 deletions api/v1alpha2/taskspawner_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1201,20 +1201,44 @@ type TaskTemplate struct {
UpstreamRepo string `json:"upstreamRepo,omitempty"`
}

// TaskSpawnerPipelineTemplate defines the TaskPipeline created for each work item.
//
// +kubebuilder:validation:XValidation:rule="self.stages.all(stage, self.stages.exists_one(candidate, candidate.name == stage.name))",message="stage names must be unique"
type TaskSpawnerPipelineTemplate struct {
// Stages are copied into each created TaskPipeline. The work item's
// template variables are set as the TaskPipeline's params, so stage
// prompt, branch, and condition templates read them as .Params, for
// example .Params.Body.
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=64
// +listType=atomic
Stages []PipelineStage `json:"stages"`
}

// TaskSpawnerSpec defines the desired state of TaskSpawner.
// +kubebuilder:validation:XValidation:rule="!(has(self.when.githubIssues) || has(self.when.githubPullRequests) || has(self.when.githubWebhook) || has(self.when.linearWebhook)) || has(self.taskTemplate.workspaceRef) || (has(self.taskTemplate.worker) && has(self.taskTemplate.worker.workspaceRef)) || has(self.taskTemplate.workerPoolRef)",message="a workspace source is required when using githubIssues, githubPullRequests, githubWebhook, or linearWebhook source (set taskTemplate.workspaceRef, taskTemplate.worker.workspaceRef, or taskTemplate.workerPoolRef — a pool satisfies this because it carries its own workspace)"
// +kubebuilder:validation:XValidation:rule="has(self.taskTemplate.workerPoolRef) || (has(self.taskTemplate.worker) && (has(self.taskTemplate.worker.credentials) || has(self.credentials))) || (has(self.taskTemplate.type) && (has(self.taskTemplate.credentials) || has(self.credentials)))",message="inline task templates require taskTemplate credentials or spec.credentials"
// +kubebuilder:validation:XValidation:rule="!has(self.credentials) || (!has(self.taskTemplate.workerPoolRef) && !has(self.taskTemplate.credentials) && (!has(self.taskTemplate.worker) || !has(self.taskTemplate.worker.credentials)))",message="spec.credentials is mutually exclusive with taskTemplate credentials and workerPoolRef"
// +kubebuilder:validation:XValidation:rule="!has(self.taskTemplate) || !(has(self.when.githubIssues) || has(self.when.githubPullRequests) || has(self.when.githubWebhook) || has(self.when.linearWebhook)) || has(self.taskTemplate.workspaceRef) || (has(self.taskTemplate.worker) && has(self.taskTemplate.worker.workspaceRef)) || has(self.taskTemplate.workerPoolRef)",message="a workspace source is required when using githubIssues, githubPullRequests, githubWebhook, or linearWebhook source (set taskTemplate.workspaceRef, taskTemplate.worker.workspaceRef, or taskTemplate.workerPoolRef — a pool satisfies this because it carries its own workspace)"
// +kubebuilder:validation:XValidation:rule="!has(self.taskTemplate) || has(self.taskTemplate.workerPoolRef) || (has(self.taskTemplate.worker) && (has(self.taskTemplate.worker.credentials) || has(self.credentials))) || (has(self.taskTemplate.type) && (has(self.taskTemplate.credentials) || has(self.credentials)))",message="inline task templates require taskTemplate credentials or spec.credentials"
// +kubebuilder:validation:XValidation:rule="!has(self.credentials) || !has(self.taskTemplate) || (!has(self.taskTemplate.workerPoolRef) && !has(self.taskTemplate.credentials) && (!has(self.taskTemplate.worker) || !has(self.taskTemplate.worker.credentials)))",message="spec.credentials is mutually exclusive with taskTemplate credentials and workerPoolRef"
// +kubebuilder:validation:XValidation:rule="has(self.taskTemplate) != has(self.pipelineTemplate)",message="exactly one of taskTemplate or pipelineTemplate is required"
// +kubebuilder:validation:XValidation:rule="!has(self.pipelineTemplate) || (has(self.when.slack) && !has(self.when.githubIssues) && !has(self.when.githubPullRequests) && !has(self.when.cron) && !has(self.when.jira) && !has(self.when.githubWebhook) && !has(self.when.linearWebhook) && !has(self.when.webhook))",message="pipelineTemplate is supported only with the slack source"
// +kubebuilder:validation:XValidation:rule="!has(self.pipelineTemplate) || !has(self.credentials)",message="spec.credentials is not supported with pipelineTemplate"
type TaskSpawnerSpec struct {
// When defines the conditions that trigger task spawning.
// +kubebuilder:validation:Required
When When `json:"when"`

// TaskTemplate defines the template for spawned Tasks. Inline worker and
// legacy type templates may use TaskSpawner.spec.credentials instead of
// credentials nested in the template.
// +kubebuilder:validation:Required
TaskTemplate TaskTemplate `json:"taskTemplate"`
// credentials nested in the template. Exactly one of taskTemplate or
// pipelineTemplate is required.
// +optional
TaskTemplate TaskTemplate `json:"taskTemplate,omitzero"`

// PipelineTemplate creates a TaskPipeline for each work item instead of a
// single Task. Supported only with the slack source, and mutually exclusive
// with taskTemplate and spec.credentials.
// +optional
PipelineTemplate *TaskSpawnerPipelineTemplate `json:"pipelineTemplate,omitempty"`

// Credentials lists named credentials available to generated Tasks. The
// spawner selects one credential at random and copies it to the generated
Expand Down
61 changes: 61 additions & 0 deletions api/v1alpha2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading