Add Control Flow Logic for CI Steps
Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.
Problem Statement
Today, rules are evaluated when the pipeline is created. In other words, they are not dynamic or evaluated at run-time. Our users would like pipelines to evaluate objects such as artifact or dotenv, which are created during pipeline execution which result in a more accurate and efficient pipelines
Proposed Solution
Providing a run-time evaluation at execution time
User Stories
⚠️ WIP proposal
1. Step Output-Based Conditional Execution
As a developer I want to conditionally run security scans based on dependency analysis results So that I only scan when new vulnerabilities are possible
run:
- name: analyze_dependencies
step: ...
- name: security_scan
step: ...
if: ${{ steps.analyze_dependencies.outputs.has_new_deps }}
security_scan runs only if analyze_dependencies output true
In addition a string comparison should be possible such in a case where you want to run a step only on a merge request event
if: ${{ vars.CI_PIPELINE_SOURCE == "merge_request_event" }}
2. Fail a pipeline in case an artifact was not created
run:
- name: fetch_artifact
step: ...
inputs:
artifact: [url]
token: [api key]
continue_on_err: true
- name: respond_to_download_failure
script: # do something interesting: exit 1, build a new artifact.txt, etc
if: ${{ !contains(steps.fetch_artifact.outputs.fetched, "artifact.txt") }}
In addition, I would expect users to want to use the existing rules condition such as change: and exists:
e.g.
3. Conditional step execution based on file exists
steps:
- name: check_migrations
- name: run_migrations
if: ${{ file_exists("artifact.txt") }}
Additional details
- The
ifis directly on the step - Logical AND is supported in expressions, so a list of
rulesis unnecessary. For example,if: ${{ vars.BYPASS_SEC_SCAN != "true" && steps.analyze_dependencies.outputs.has_new_deps }} -
existscould be a function in the expression language.
Design Decisions
-
No
ruleskeyword: Avoids confusion with job-level rules that have incompatible features -
Expression-based: Single
iffield supports complex logic via&&,||,!operators -
Step-scoped: No
changesorpathssupport since steps don't operate in git context -
Function library: Built-in functions like
file_exists(),contains()for common operations