Step bundles now support the run_if condition. This allows you to skip or execute an entire group of Steps based on a single condition, cleaning up your workflow configuration.
Problem this solves
Previously, to conditionally run a group of related steps, you had to add the same run_if conditions to every individual step within a step bundle. This created repetitive YAML configuration and made workflows harder to read and maintain, especially for bundles with three or more Steps that always needed to run together.
How it works
In the above screenshot, you can see the “When to run” section under the “Configuration” tab on the right-hand side. Here’s where you can enter conditions that need to be met before the bundle executes.
Needless to say, you can also use the YAML-based way to achieve this. When you apply run_if directly to step bundle calls in your workflow, the condition is evaluated before the bundle executes. If it evaluates to false, the entire bundle and all its steps are skipped.
The run_if syntax works the same as it does for individual steps.
Examples
- Skip deployment bundles for draft PRs:
workflows:
deploy:
steps:
- bundle::build-and-test: {}
- bundle::deploy-to-staging:
run_if: '{{ not (envcontain "BITRISE_GIT_MESSAGE" "[draft]") }}'
- bundle::notify-slack:
run_if: '{{ not .IsBuildFailed }}'
In the above example,
-
the bundle
deploy-to-stagingwould run only if the PR is not a draft PR. -
Similarly, the bundle
notify-slackwould run only if it is a successful build.
- Environment-specific bundles:
workflows:
ci:
steps:
- bundle::setup-dependencies: {}
- bundle::run-unit-tests: {}
- bundle::integration-tests:
run_if: '{{ enveq "BITRISE_GIT_BRANCH" "main" }}'
In the above example, the bundle integration-tests would run only if branch of the build is the main branch.
- Save and restore the SPM cache depending on whether it is a Tuist build
workflows:
primary:
steps:
- bundle::restore-spm-cache:
run_if: '{{ not (enveq "IS_TUIST" "true") }}'
- bundle::save-spm-cache:
run_if: '{{ and (not (enveq "IS_TUIST" "true")) (enveq "PR_NUMBER" "") }}'
In the above example,
-
The bundle
restore-spm-cachewould run only if the environment variable IS_TUIST is not true. -
The bundle
save-spm-cachewould run only if the environment variable IS_TUIST is not true AND it is not a PR. (PR_NUMBER is empty)
- Run certain steps only in CI environment
workflows:
test:
steps:
- bundle::setup_repo: {}
# run tests ...
step_bundles:
setup_repo:
run_if: '{{.IsCI}}'
steps:
- git-clone:
inputs:
- clone_depth: '1'
- script:
title: Setup repository
# ...
In the above example, a test workflow is used, which runs a setup_repo Step Bundle. This bundle clones the repository and performs additional setup Steps on it. Now the setup_repo bundle should only run in a CI environment, not locally, so the setup_repo has a run_if: .IsCI condition on the Step Bundle definition.
Specifying a run_if in the definition vs instance of the Step Bundle:
You can do both.
-
When the
run_ifis in the definition, then it serves as the defaultrun_iffor all instances. -
When the
run_ifis in the instance, it overrides the definition, and that single instance will have therun_if.
When to use which
If a Step Bundle is usually executed conditionally, it is better to define run_if on the definition, so that all instances will get the sensible default run_if. Like a repo clone and setup bundle usually only make sense in a CI environment.
Syntax
Use the same run_if syntax as individual steps. All the template expressions and custom template functions we implemented for steps are supported.
These are the custom template functions:
-
getenv -
enveq -
envcontain
Here is one example with each custom template function:
-
'{{ getenv "PR_NUMBER" | eq "" }}'→ true if PR number is empty -
'{{ enveq "PR_NUMBER" "" }}'→ (same as the previous) true if PR number is empty -
'{{ envcontain "BITRISE_GIT_MESSAGE" "[draft]" }}'→ true if git message contains[draft]
