Skip to content

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 if is directly on the step
  • Logical AND is supported in expressions, so a list of rules is unnecessary. For example, if: ${{ vars.BYPASS_SEC_SCAN != "true" && steps.analyze_dependencies.outputs.has_new_deps }}
  • exists could be a function in the expression language.

Design Decisions

  • No rules keyword: Avoids confusion with job-level rules that have incompatible features
  • Expression-based: Single if field supports complex logic via &&, ||, ! operators
  • Step-scoped: No changes or paths support since steps don't operate in git context
  • Function library: Built-in functions like file_exists(), contains() for common operations
Edited by 🤖 GitLab Bot 🤖