Skip to content
Snippets Groups Projects
Commit cc430d3f authored by Timo Furrer's avatar Timo Furrer
Browse files

Merge branch 'trigger-in-pipeline' into 'main'

Support running pipeline templates directly in child pipeline with `trigger_in_child_pipeline` input

See merge request components/opentofu!190
parents 3f22d1f6 cc000b48
No related branches found
No related tags found
No related merge requests found
......@@ -44,6 +44,17 @@ include:
opentofu_version: <OPENTOFU_VERSION>
stages: [validate, build, deploy]
# ... or in a child pipeline:
include:
- component: $CI_SERVER_FQDN/components/opentofu/validate-plan-apply@<VERSION>
inputs:
# The version must currently be specified explicitly as an input,
# to find the correctly associated images. # This can be removed
# once https://gitlab.com/gitlab-org/gitlab/-/issues/438275 is solved.
version: <VERSION> # component version
opentofu_version: <OPENTOFU_VERSION>
trigger_in_child_pipeline: true
```
A concrete example may look like this:
......@@ -158,6 +169,10 @@ but no destructive actions.
- [`validate-plan-apply`](templates/validate-plan-apply.yml)
- [`validate-plan-destroy`](templates/validate-plan-destroy.yml)
These templates support the `trigger_in_child_pipeline` input which will
include the component but run all its job in a child pipeline. This may be useful in cases
where you want to run dedicated child pipeline for each of your environments.
### Job Templates
Instead of including the `full-pipeline` or another opinionated template,
......
......@@ -46,6 +46,17 @@ include:
opentofu_version: <OPENTOFU_VERSION>
stages: [validate, build, deploy]
# ... or in a child pipeline:
include:
- component: $CI_SERVER_FQDN/components/opentofu/validate-plan-apply@<VERSION>
inputs:
# The version must currently be specified explicitly as an input,
# to find the correctly associated images. # This can be removed
# once https://gitlab.com/gitlab-org/gitlab/-/issues/438275 is solved.
version: <VERSION> # component version
opentofu_version: <OPENTOFU_VERSION>
trigger_in_child_pipeline: true
```
A concrete example may look like this:
......@@ -160,6 +171,10 @@ but no destructive actions.
- [`validate-plan-apply`](templates/validate-plan-apply.yml)
- [`validate-plan-destroy`](templates/validate-plan-destroy.yml)
These templates support the `trigger_in_child_pipeline` input which will
include the component but run all its job in a child pipeline. This may be useful in cases
where you want to run dedicated child pipeline for each of your environments.
### Job Templates
Instead of including the `full-pipeline` or another opinionated template,
......
......@@ -159,11 +159,25 @@ spec:
default: false
type: boolean
description: 'Whether to mark the job with a warning if the plan contains a diff.'
trigger_in_child_pipeline:
default: false
type: boolean
description: 'Whether to run all the jobs in a child pipeline.'
child_pipeline_name:
default: opentofu
type: string
description: 'If `trigger_in_child_pipeline` is `true` then this defines the name of the child pipeline bridge job.'
child_pipeline_stage:
default: opentofu
type: string
description: 'If `trigger_in_child_pipeline` is `true` then this defines the stage of the child pipeline bridge job.'
---
include:
- local: '/templates/fmt.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]fmt'
stage: $[[ inputs.stage_validate ]]
......@@ -177,6 +191,8 @@ include:
needs: []
rules: $[[ inputs.fmt_rules ]]
- local: '/templates/validate.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]validate'
stage: $[[ inputs.stage_validate ]]
......@@ -191,6 +207,11 @@ include:
var_file: $[[ inputs.var_file ]]
rules: $[[ inputs.validate_rules ]]
- local: '/templates/test.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "true"'
when: never
- exists:
- $[[ inputs.root_dir ]]/**/*.tftest.hcl
inputs:
as: '$[[ inputs.job_name_prefix ]]test'
stage: $[[ inputs.stage_test ]]
......@@ -205,10 +226,9 @@ include:
var_file: $[[ inputs.var_file ]]
needs: []
rules: $[[ inputs.test_rules ]]
rules:
- exists:
- $[[ inputs.root_dir ]]/**/*.tftest.hcl
- local: '/templates/plan.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]plan'
stage: $[[ inputs.stage_build ]]
......@@ -226,6 +246,8 @@ include:
rules: $[[ inputs.plan_rules ]]
warning_on_non_empty_plan: $[[ inputs.warning_on_non_empty_plan ]]
- local: '/templates/apply.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]apply'
stage: $[[ inputs.stage_deploy ]]
......@@ -241,6 +263,8 @@ include:
var_file: $[[ inputs.var_file ]]
rules: $[[ inputs.apply_rules ]]
- local: '/templates/destroy.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]destroy'
stage: $[[ inputs.stage_cleanup ]]
......@@ -255,6 +279,8 @@ include:
var_file: $[[ inputs.var_file ]]
rules: $[[ inputs.destroy_rules ]]
- local: '/templates/delete-state.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]delete-state'
stage: $[[ inputs.stage_cleanup ]]
......@@ -267,3 +293,58 @@ include:
# https://gitlab.com/gitlab-org/gitlab/-/issues/440468
'$[[ inputs.job_name_prefix ]]delete-state':
needs: ['$[[ inputs.job_name_prefix ]]destroy']
# NOTE: the following configuration is only used if `trigger_in_child_pipeline` is enabled.
stages:
- $[[ inputs.stage_validate ]]
- $[[ inputs.stage_build ]]
- $[[ inputs.stage_deploy ]]
- $[[ inputs.stage_cleanup ]]
- $[[ inputs.child_pipeline_stage ]]
'.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:true':
stage: $[[ inputs.child_pipeline_stage ]]
'.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:false':
# NOTE: this is a hack for the bridge job below to have a valid stage even if it isn't used.
# The thing is that the stage needs to be defined even if the job is "ruled" out and not created.
# The .pre stage always exists.
stage: .pre
'$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]':
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "true"'
extends: '.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:$[[ inputs.trigger_in_child_pipeline ]]'
trigger:
include:
- local: /templates/validate-plan-apply.yml
inputs:
stage_validate: $[[ inputs.stage_validate ]]
stage_build: $[[ inputs.stage_build ]]
stage_deploy: $[[ inputs.stage_deploy ]]
stage_cleanup: $[[ inputs.stage_cleanup ]]
version: $[[ inputs.version ]]
base_os: $[[ inputs.base_os ]]
opentofu_version: $[[ inputs.opentofu_version ]]
image_registry_base: $[[ inputs.image_registry_base ]]
image_name: $[[ inputs.image_name]]
image_digest: $[[ inputs.image_digest]]
job_name_prefix: $[[ inputs.job_name_prefix]]
root_dir: $[[ inputs.root_dir]]
state_name: $[[ inputs.state_name]]
plan_name: $[[ inputs.plan_name ]]
plan_artifacts_access: $[[ inputs.plan_artifacts_access ]]
var_file: $[[ inputs.var_file ]]
fmt_rules: $[[ inputs.fmt_rules ]]
validate_rules: $[[ inputs.validate_rules ]]
plan_rules: $[[ inputs.plan_rules ]]
apply_rules: $[[ inputs.apply_rules ]]
destroy_rules: $[[ inputs.destroy_rules ]]
delete_state_rules: $[[ inputs.delete_state_rules ]]
warning_on_non_empty_plan: $[[ inputs.warning_on_non_empty_plan ]]
trigger_in_child_pipeline: false
forward:
yaml_variables: true
pipeline_variables: true
strategy: depend
......@@ -126,11 +126,25 @@ spec:
default: false
type: boolean
description: 'Whether to mark the job with a warning if the plan contains a diff.'
trigger_in_child_pipeline:
default: false
type: boolean
description: 'Whether to run all the jobs in a child pipeline.'
child_pipeline_name:
default: opentofu
type: string
description: 'If `trigger_in_child_pipeline` is `true` then this defines the name of the child pipeline bridge job.'
child_pipeline_stage:
default: opentofu
type: string
description: 'If `trigger_in_child_pipeline` is `true` then this defines the stage of the child pipeline bridge job.'
---
include:
- local: '/templates/fmt.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]fmt'
stage: $[[ inputs.stage_validate ]]
......@@ -144,6 +158,8 @@ include:
needs: []
rules: $[[ inputs.fmt_rules ]]
- local: '/templates/validate.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]validate'
stage: $[[ inputs.stage_validate ]]
......@@ -159,6 +175,8 @@ include:
rules: $[[ inputs.validate_rules ]]
cache_policy: pull-push
- local: '/templates/plan.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]plan'
stage: $[[ inputs.stage_build ]]
......@@ -177,6 +195,8 @@ include:
cache_policy: pull
warning_on_non_empty_plan: $[[ inputs.warning_on_non_empty_plan ]]
- local: '/templates/apply.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]apply'
stage: $[[ inputs.stage_deploy ]]
......@@ -192,3 +212,54 @@ include:
var_file: $[[ inputs.var_file ]]
rules: $[[ inputs.apply_rules ]]
cache_policy: pull
# NOTE: the following configuration is only used if `trigger_in_child_pipeline` is enabled.
stages:
- $[[ inputs.stage_validate ]]
- $[[ inputs.stage_build ]]
- $[[ inputs.stage_deploy ]]
- $[[ inputs.child_pipeline_stage ]]
'.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:true':
stage: $[[ inputs.child_pipeline_stage ]]
'.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:false':
# NOTE: this is a hack for the bridge job below to have a valid stage even if it isn't used.
# The thing is that the stage needs to be defined even if the job is "ruled" out and not created.
# The .pre stage always exists.
stage: .pre
'$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]':
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "true"'
extends: '.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:$[[ inputs.trigger_in_child_pipeline ]]'
trigger:
include:
- local: /templates/validate-plan-apply.yml
inputs:
stage_validate: $[[ inputs.stage_validate ]]
stage_build: $[[ inputs.stage_build ]]
stage_deploy: $[[ inputs.stage_deploy ]]
version: $[[ inputs.version ]]
base_os: $[[ inputs.base_os ]]
opentofu_version: $[[ inputs.opentofu_version ]]
image_registry_base: $[[ inputs.image_registry_base ]]
image_name: $[[ inputs.image_name]]
image_digest: $[[ inputs.image_digest]]
job_name_prefix: $[[ inputs.job_name_prefix]]
root_dir: $[[ inputs.root_dir]]
state_name: $[[ inputs.state_name]]
plan_name: $[[ inputs.plan_name ]]
plan_artifacts_access: $[[ inputs.plan_artifacts_access ]]
var_file: $[[ inputs.var_file ]]
fmt_rules: $[[ inputs.fmt_rules ]]
validate_rules: $[[ inputs.validate_rules ]]
plan_rules: $[[ inputs.plan_rules ]]
apply_rules: $[[ inputs.apply_rules ]]
warning_on_non_empty_plan: $[[ inputs.warning_on_non_empty_plan ]]
trigger_in_child_pipeline: false
forward:
yaml_variables: true
pipeline_variables: true
strategy: depend
......@@ -132,11 +132,25 @@ spec:
default: false
type: boolean
description: 'Whether to mark the job with a warning if the plan contains a diff.'
trigger_in_child_pipeline:
default: false
type: boolean
description: 'Whether to run all the jobs in a child pipeline.'
child_pipeline_name:
default: opentofu
type: string
description: 'If `trigger_in_child_pipeline` is `true` then this defines the name of the child pipeline bridge job.'
child_pipeline_stage:
default: opentofu
type: string
description: 'If `trigger_in_child_pipeline` is `true` then this defines the stage of the child pipeline bridge job.'
---
include:
- local: '/templates/fmt.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]fmt'
stage: $[[ inputs.stage_validate ]]
......@@ -150,6 +164,8 @@ include:
needs: []
rules: $[[ inputs.fmt_rules ]]
- local: '/templates/validate.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]validate'
stage: $[[ inputs.stage_validate ]]
......@@ -165,6 +181,8 @@ include:
rules: $[[ inputs.validate_rules ]]
cache_policy: pull-push
- local: '/templates/plan.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]plan'
stage: $[[ inputs.stage_build ]]
......@@ -184,6 +202,8 @@ include:
cache_policy: pull
warning_on_non_empty_plan: $[[ inputs.warning_on_non_empty_plan ]]
- local: '/templates/destroy.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]destroy'
stage: $[[ inputs.stage_cleanup ]]
......@@ -201,6 +221,8 @@ include:
rules: $[[ inputs.destroy_rules ]]
cache_policy: pull
- local: '/templates/delete-state.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]delete-state'
stage: $[[ inputs.stage_cleanup ]]
......@@ -213,3 +235,55 @@ include:
# https://gitlab.com/gitlab-org/gitlab/-/issues/440468
'$[[ inputs.job_name_prefix ]]delete-state':
needs: ['$[[ inputs.job_name_prefix ]]destroy']
# NOTE: the following configuration is only used if `trigger_in_child_pipeline` is enabled.
stages:
- $[[ inputs.stage_validate ]]
- $[[ inputs.stage_build ]]
- $[[ inputs.stage_cleanup ]]
- $[[ inputs.child_pipeline_stage ]]
'.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:true':
stage: $[[ inputs.child_pipeline_stage ]]
'.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:false':
# NOTE: this is a hack for the bridge job below to have a valid stage even if it isn't used.
# The thing is that the stage needs to be defined even if the job is "ruled" out and not created.
# The .pre stage always exists.
stage: .pre
'$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]':
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "true"'
extends: '.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:$[[ inputs.trigger_in_child_pipeline ]]'
trigger:
include:
- local: /templates/validate-plan-destroy.yml
inputs:
stage_validate: $[[ inputs.stage_validate ]]
stage_build: $[[ inputs.stage_build ]]
stage_cleanup: $[[ inputs.stage_cleanup ]]
version: $[[ inputs.version ]]
base_os: $[[ inputs.base_os ]]
opentofu_version: $[[ inputs.opentofu_version ]]
image_registry_base: $[[ inputs.image_registry_base ]]
image_name: $[[ inputs.image_name]]
image_digest: $[[ inputs.image_digest]]
job_name_prefix: $[[ inputs.job_name_prefix]]
root_dir: $[[ inputs.root_dir]]
state_name: $[[ inputs.state_name]]
plan_name: $[[ inputs.plan_name ]]
plan_artifacts_access: $[[ inputs.plan_artifacts_access ]]
var_file: $[[ inputs.var_file ]]
fmt_rules: $[[ inputs.fmt_rules ]]
validate_rules: $[[ inputs.validate_rules ]]
plan_rules: $[[ inputs.plan_rules ]]
destroy_rules: $[[ inputs.destroy_rules ]]
delete_state_rules: $[[ inputs.delete_state_rules ]]
warning_on_non_empty_plan: $[[ inputs.warning_on_non_empty_plan ]]
trigger_in_child_pipeline: false
forward:
yaml_variables: true
pipeline_variables: true
strategy: depend
......@@ -110,11 +110,25 @@ spec:
default: false
type: boolean
description: 'Whether to mark the job with a warning if the plan contains a diff.'
trigger_in_child_pipeline:
default: false
type: boolean
description: 'Whether to run all the jobs in a child pipeline.'
child_pipeline_name:
default: opentofu
type: string
description: 'If `trigger_in_child_pipeline` is `true` then this defines the name of the child pipeline bridge job.'
child_pipeline_stage:
default: opentofu
type: string
description: 'If `trigger_in_child_pipeline` is `true` then this defines the stage of the child pipeline bridge job.'
---
include:
- local: '/templates/fmt.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]fmt'
stage: $[[ inputs.stage_validate ]]
......@@ -128,6 +142,8 @@ include:
needs: []
rules: $[[ inputs.fmt_rules ]]
- local: '/templates/validate.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]validate'
stage: $[[ inputs.stage_validate ]]
......@@ -143,6 +159,8 @@ include:
rules: $[[ inputs.validate_rules ]]
cache_policy: pull-push
- local: '/templates/plan.yml'
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "false"'
inputs:
as: '$[[ inputs.job_name_prefix ]]plan'
stage: $[[ inputs.stage_build ]]
......@@ -160,3 +178,51 @@ include:
rules: $[[ inputs.plan_rules ]]
cache_policy: pull
warning_on_non_empty_plan: $[[ inputs.warning_on_non_empty_plan ]]
# NOTE: the following configuration is only used if `trigger_in_child_pipeline` is enabled.
stages:
- $[[ inputs.stage_validate ]]
- $[[ inputs.stage_build ]]
- $[[ inputs.child_pipeline_stage ]]
'.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:true':
stage: $[[ inputs.child_pipeline_stage ]]
'.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:false':
# NOTE: this is a hack for the bridge job below to have a valid stage even if it isn't used.
# The thing is that the stage needs to be defined even if the job is "ruled" out and not created.
# The .pre stage always exists.
stage: .pre
'$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]':
rules:
- if: '"$[[ inputs.trigger_in_child_pipeline ]]" == "true"'
extends: '.$[[ inputs.job_name_prefix ]]$[[ inputs.child_pipeline_name ]]:bridge_job_stage:$[[ inputs.trigger_in_child_pipeline ]]'
trigger:
include:
- local: /templates/validate-plan.yml
inputs:
stage_validate: $[[ inputs.stage_validate ]]
stage_build: $[[ inputs.stage_build ]]
version: $[[ inputs.version ]]
base_os: $[[ inputs.base_os ]]
opentofu_version: $[[ inputs.opentofu_version ]]
image_registry_base: $[[ inputs.image_registry_base ]]
image_name: $[[ inputs.image_name]]
image_digest: $[[ inputs.image_digest]]
job_name_prefix: $[[ inputs.job_name_prefix]]
root_dir: $[[ inputs.root_dir]]
state_name: $[[ inputs.state_name]]
plan_name: $[[ inputs.plan_name ]]
artifacts_access: $[[ inputs.artifacts_access ]]
var_file: $[[ inputs.var_file ]]
fmt_rules: $[[ inputs.fmt_rules ]]
validate_rules: $[[ inputs.validate_rules ]]
plan_rules: $[[ inputs.plan_rules ]]
warning_on_non_empty_plan: $[[ inputs.warning_on_non_empty_plan ]]
trigger_in_child_pipeline: false
forward:
yaml_variables: true
pipeline_variables: true
strategy: depend
include:
- component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/validate-plan-apply@$CI_COMMIT_SHA
inputs:
image_registry_base: $GITLAB_OPENTOFU_IMAGE_BASE
version: $CI_COMMIT_SHA
base_os: $GITLAB_OPENTOFU_BASE_IMAGE_OS
opentofu_version: $OPENTOFU_VERSION
root_dir: $TEST_TF_ROOT
state_name: $TEST_TF_STATE_NAME
fmt_rules: [{when: on_success}]
validate_rules: [{when: on_success}]
plan_rules: [{when: on_success}]
apply_rules: [{when: on_success}]
trigger_in_child_pipeline: true
child_pipeline_name: test-pipeline
child_pipeline_stage: test
# For CI Terraform state cleanup
- component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/delete-state@$CI_COMMIT_SHA
inputs:
stage: cleanup
state_name: $TEST_TF_STATE_NAME
rules: [{when: always}]
stages: [test, cleanup]
......@@ -17,6 +17,7 @@ component:
- Destroy
- VarFile
- WarningOnNonEmptyPlan
- TriggerInChildPipeline
GITLAB_OPENTOFU_BASE_IMAGE_OS:
- alpine
- debian
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment