1.11.9.1 across
Step Modifier
Run a step multiple times with different combinations of variable values.
across
is considered an experimental feature, and its syntax/semantics may change. To enable across
for your deployment, you must set the feature flag CONCOURSE_ENABLE_ACROSS_STEP
.
The across
step can be combined with the load_var
step, the set_pipeline
step, and instanced pipelines to maintain a dynamically sized group of related pipelines.
More fields are also available for variable interpolation with the across step. See Across Step & Dynamic Vars for details.
Outputs from steps ran within the across step are not available to steps outside of the across step.
Contains a list of across_var
schema.
across_var
schema
The name of the variable that will be added to the ".
" var source. This variable will only be accessible in the scope of the step - each iteration of the step gets its own scope.
If a variable of the same name already exists in the parent scope, a warning will be printed.
The list of values that the var will iterate over when running the substep. If multiple vars are configured, all combinations of values across all vars will run.
The list of values may also be interpolated. For instance, you may use the load_var
step to first load a list of value
schema into a local var, and then iterate across that dynamic list of values.
The following
will run the task foo/build.yml
for each package defined in foo/packages-to-build.json
with Go 1.15 and 1.16.
plan:
- get: foo
- load_var: packages
file: foo/packages-to-build.json
- across:
- var: package
values: ((.:packages))
- var: go_version
values: ['1.15', '1.16']
task: build
file: foo/build.yml
vars:
go_version: ((.:go_version))
package: ((.:package))
Supposing foo/packages-to-build.json
had the following content:
["./cmd/first", "./cmd/second", "./cmd/third"]
...then the task foo/build.yml
would be run with the following var combinations:
{package: "./cmd/first", go_version: "1.15"}
{package: "./cmd/first", go_version: "1.16"}
{package: "./cmd/second", go_version: "1.15"}
{package: "./cmd/second", go_version: "1.16"}
{package: "./cmd/third", go_version: "1.15"}
{package: "./cmd/third", go_version: "1.16"}
Default 1
. If set to all
, the substep will run with all combinations of the current var in parallel. If set to a number
schema, only that number of substeps may run in parallel.
If multiple vars are configured, the effective max_in_flight
is multiplicative. For instance:
plan:
- across:
- var: var1
values: [a, b, c]
max_in_flight: all
- var: var2
values: [1, 2]
- var: var3
values: [foo, bar]
max_in_flight: 2
Here, 6 substeps will run in parallel, since all 3 of var1
's values can run in parallel, and 2 of var3
's values can run in parallel.
Default false
. When enabled, the across
step will fail fast by returning as soon as any sub-step fails. This means that running steps will be interrupted and pending steps will no longer be scheduled.
jobs:
- name: job
plan:
- across:
- var: some-text
values: ["hello-world", "hello-concourse"]
task: running-((.:some-text))
config:
platform: linux
image_resource:
type: mock
source:
mirror_self: true
run:
path: echo
args: ["((.:some-text))"]
resources:
- name: ci
type: git
source:
uri: https://github.com/concourse/examples.git
jobs:
- name: job
plan:
- get: ci
- across:
- var: pipeline
values: ["hello-world", "time-triggered"]
do:
- task: running-((.:pipeline))
input_mapping:
((.:pipeline)): ci
output_mapping:
((.:pipeline)): newci
config:
platform: linux
image_resource:
type: mock
source:
mirror_self: true
inputs:
- name: ((.:pipeline))
outputs:
- name: ((.:pipeline))
run:
path: cat
args: ["((.:pipeline))/pipelines/((.:pipeline)).yml"]
- task: newci-((.:pipeline))
config:
platform: linux
image_resource:
type: mock
source:
mirror_self: true
inputs:
- name: newci
run:
path: cat
args: ["newci/pipelines/((.:pipeline)).yml"]
resources:
- name: ci
type: git
source:
uri: https://github.com/concourse/examples.git
jobs:
- name: job
plan:
- get: ci
- across:
- var: pipeline
values: ["hello-world", "time-triggered"]
set_pipeline: ((.:pipeline))
file: ci/pipelines/((.:pipeline)).yml
Use the do
step to across
over multiple steps.
jobs:
- name: job
plan:
- across:
- var: name
values: ["Kaladin", "Jasnah"]
do: # takes a list of steps
- task: saying-hello
config:
platform: linux
image_resource:
type: mock
source:
mirror_self: true
run:
path: echo
args: ["Hello ((.:name))!"]
- task: saying-bye
config:
platform: linux
image_resource:
type: mock
source:
mirror_self: true
run:
path: echo
args: ["Bye ((.:name))!"]
You can use the across
step to set a pipeline for each branch in a git repository.
plan:
- get: release-branches
trigger: true
- get: ci
- load_var: branches
file: release-branches/branches.json
- across:
- var: branch
values: ((.:branches))
set_pipeline: release
file: ci/pipelines/release.yml
instance_vars: {branch: ((.:branch.name))}
When a new branch is added, a new pipeline will be created. When a branch is deleted, the pipeline will be automatically archived as described in the set_pipeline
step.
For a more complete example, refer to Multi-Branch Workflows.
Limitations
The across
step does not work with the get
step or put
step. The names of resouces are not interpolated within across steps. Trying to do the following will not work.
- across:
- var: version
values: ["1.16", "1.17"]
do:
- get: go-((.:version))
# or this
- get: golang
resource: go-((.version))
The main reason this does not work is that Concourse determines the inputs for a job before the job starts. Concourse has no way of determining inputs for a job while it's in the middle of running.
Current pipeline valdiation logic will also block you from setting the pipeline at all since Concourse validates the relationship between all resources and jobs by looking at get and put steps.
The above example will return an error like this when trying to set the pipeline:
invalid jobs:
jobs.job.plan.do[0].across.get(go): unknown resource 'go-((.:version))'