Skip to content
Crow CI
Codeberg

Workflow syntax

The Workflow section defines a list of steps to build, test and deploy. Steps are executed serially in the order in which they are defined. If a step returns a non-zero exit code, the workflow and therefore the entire workflow terminates and returns an error status.

Exemplary step definition:

steps:
- name: backend
image: <image>
commands:
- <command 1>
- <command 2>
- name: frontend
image: <image>
commands: |
<command 1>

Besides steps:, various other top-level commands are understood which allow controlling the pipeline execution flow.

A common use case is to disable partial cloning, to allow for a possible git push in a follow-up step (which does not work with a partial clone).

clone:
- name: clone
image: codeberg.org/crow-plugins/clone
settings:
partial: false

See the default configuration of the clone plugin to check for possible options to change.

The name field allows to set a custom name for a pipeline. By default, the workflow name is derived from the YAML file name (e.g., build.yamlbuild).

For matrix pipelines, a NAME (case-insensitive) key can be provided for each matrix entry:

matrix:
include:
- NAME: name1
VAR1: value1
- NAME: name2
VAR1: value2

Both name and NAME support variable substitution (e.g., ${ENVIRONMENT}). If a matrix NAME is set, it takes priority over other options. Otherwise, the top-level name is used. If neither is set, the file name is used.

Multiple workflows can be set up for a repository. Those will run independent of each other by default. To introduce a dependency among these, the depends_on keyword can be used with the workflow name (usually the name of the YAML file).

Labels can be set for workflows. These are used by agents to filter their execution. An agent will pick up and run a workflow when every label assigned to it matches the agents labels.

Every workflow has the repo=your-user/your-repo-name label set. If the platform attribute of a workflow has been set, a label like platform=your-os/your-arch is set as well.

Labels can be set in a map:

labels:
location: europe # only agents with `location=europe` or `location=*` will be used
weather: sun
hostname: '' # this label will be ignored as it is empty
steps:
- name: build
image: <image>
commands:
- go build
- go test

Matrix builds allow separate workflows for each combination in the matrix, simplifying building and testing a single commit against multiple configurations.

For more details check the dedicated documentation on matrix builds.

Steps can be given “privileged” capabilities. Doing so is a security risk and should only be used in private environments, and even there only as the last resort.

The environment variable CROW_PLUGINS_PRIVILEGED controls which plugin images are allowed to run in privileged mode. The way images are matched is controlled by CROW_PLUGINS_PRIVILEGED_MATCH_TYPE (default: semver).

  • semver (default):
    • <image>:6 matches all plugin versions with major version 6 (e.g., <image>:6.1.2).
    • <image>:6.3 matches all plugin versions with major version 6 and minor version 3 (e.g., <image>:6.3.5).
    • <image>:6.3.1 matches only the specific version 6.3.1.
  • semver-range: Uses semver constraint syntax for more flexible version matching:
    • <image>:>=6 matches any version 6.0.0 or higher.
    • <image>:<7.0 matches any version less than 7.0.0.
    • <image>:>=6.0.0,<7.0.0 matches any version from 6.0.0 (inclusive) to 7.0.0 (exclusive).
    • <image>:~6.3 equivalent to <image>:>=6.3.0,<6.4.0 (allows patch-level changes).
    • <image>:^6.3 equivalent to <image>:>=6.3.0,<7.0.0 (allows minor-level changes).
  • regex: Each entry in CROW_PLUGINS_PRIVILEGED is treated as a regular expression and matched against the full image name (including tag).
  • exact: Only exact string matches are allowed.
Terminal window
export CROW_PLUGINS_PRIVILEGED="codeberg.org/crow-plugins/docker-buildx:1,plugins/gcr:7.2"
export CROW_PLUGINS_PRIVILEGED_MATCH_TYPE=semver
  • This will allow any crow-plugins/docker-buildx image with a major version 1 tag, and any plugins/gcr image with a 7.2.x tag, to run in privileged mode.
Terminal window
export CROW_PLUGINS_PRIVILEGED="codeberg.org/crow-plugins/docker-buildx:1\\..*"
export CROW_PLUGINS_PRIVILEGED_MATCH_TYPE=regex
  • This will allow any crow-plugins/docker-buildx image with a tag starting with 1.
Terminal window
export CROW_PLUGINS_PRIVILEGED="codeberg.org/crow-plugins/docker-buildx:1.0.0"
export CROW_PLUGINS_PRIVILEGED_MATCH_TYPE=exact
  • This will only allow the exact image codeberg.org/crow-plugins/docker-buildx:1.0.0 to run in privileged mode.
Terminal window
export CROW_PLUGINS_PRIVILEGED="codeberg.org/crow-plugins/docker-buildx:>=1.0.0,<2.0.0"
export CROW_PLUGINS_PRIVILEGED_MATCH_TYPE=semver-range
  • This will allow any crow-plugins/docker-buildx image with a version from 1.0.0 (inclusive) to 2.0.0 (exclusive) to run in privileged mode.

Workflows that should run even if dependent workflows failed.

runs_on: [success, failure]

See the “Execution control” page for more details.

Service containers can be used to asynchronously run databases or cache containers during the execution of a workflow.

For more details check the services docs.

The implicit clone step, which can be configured through the clone keyword, can be skipped entirely.

skip_clone: true

Variables are global workflow definitions which can be reused across the workflow definition.

Advanced YAML features such as anchors and aliases are supported.

For more details and examples see the advanced usage documentation.

The when: defines the events when a workflow is triggered. If at least one of the conditions in the when block evaluates to true, the step is executed, otherwise it is skipped. A condition is evaluated to true if all sub-conditions are true.

when:
- event: pull_request
- event: push
branch: ${CI_REPO_DEFAULT_BRANCH}

The above example would trigger the workflow

  • on pull_request events
  • on push events to the default branch of the repository

For more information about the specific filter combinations, take a look at the step-specific when filters.

The workspace defines the shared volume and working directory which is shared by all workflow steps. The default workspace base is /crow and the path is extended with the repository URL (src/{url-without-schema}). A full example would be /crow/src/github.com/octocat/hello-world.

The base attribute defines a shared base volume available to all steps. This ensures that source code, dependencies and other dynamic assets are persisted and shared between steps.

workspace:
base: /go
path: src/github.com/octocat/hello-world

The path attribute defines the working directory of the build. The value of path must be relative and is combined with the base path.

The commands of every step are executed serially as if they would be entered into a terminal.

steps:
- name: backend
image: <image>
commands:
- go build
- go test

Behind the scenes, the commands are converted into a shell script, which is then executed as the container entrypoint (docker run --entrypoint=build.sh golang):

#!/bin/sh
set -e
go build
go test

Sometimes (e.g. to avoid issues with escaping quotes and double-colons) it can be easier to specify all commands as a block instead of a list in YAML:

steps:
- name: backend
image: <image>
commands: |
go build
go test

Normally, workflow steps are executed serially in the order in which they are defined. As soon as depends_on is set for one or more steps, a directed acyclic graph (DAG) will be created and all steps of the workflow will be executed in parallel. Only the steps that have a dependency set to another step via depends_on are executed serially:

steps:
- name: build # will be executed immediately
image: <image>
commands:
- go build
- name: deploy
image: <image>
settings:
repo: foo/bar
depends_on: [build, test] # deploy will be executed after 'build' and 'test' finished
- name: test # will be executed immediately as no dependencies are set
image: <image>
commands:
- go test

The detach options can be used to run steps in the background until a workflow has finished. It is similar to services: and hence explained in more detail in the “services” documentation.

The directory options allows setting a subdirectory inside the container in which the commands will be executed.

The container entrypoint.

The default entrypoint is

Terminal window
"/bin/sh", "-c", "echo $CI_SCRIPT | base64 -d | /bin/sh -e"

An alternative to the above which allows defining custom parameters is to use a custom shell via the env var CI_SCRIPT (Base64-encoded).

Pass arbitrary environment variables to individual steps.

steps:
- name: backend
image: <image>
environment:
XY: true
commands: |
go build
go test

For more details, check the dedicated “environment variables” documentation.

Allow steps to fail without causing the whole workflow and the subsequent pipeline to fail (e.g., a step executing a linting check).

If an error is encountered while executing the step, the step will be reported as “failed” but the next steps of the workflow will continue to execute.

steps:
- name: backend
image: <image>
commands:
- go build
- go test
failure: ignore

The container image to use for the step.

steps:
- name: build
image: <image>
services:
- name: database
image: mysql

Additional volumes can be mounted to individual steps.

For the docker backend, this option can be used to mount files or folders from the host machine into the respective containers.

For the kubernetes backend, an existing persistent volume claim (PVC) is used.

More details can be found in the volumes documentation.

Woodpecker supports defining a list of conditions for a step by using a when block. If at least one of the conditions in the when block evaluate to true, the step is executed, otherwise it is skipped. A condition is evaluated to true if all sub-conditions are true.

steps:
- name: backend
image: <image>
commands:
- go build
- go test
when:
- branch: main

To only run for pushes to main, the following would need to be set:

steps:
- name: backend
image: <image>
commands:
- go build
- go test
when:
- branch: main
event: push

A condition can also be a list:

steps:
- name: backend
image: <image>
commands:
- go build
- go test
when:
- branch: [main, dev]
event: push

Regex is also supported:

steps:
- name: backend
image: <image>
commands:
- go build
- go test
when:
- branch: prefix/*
event: push

The matching is done via bmatcuk/doublestar/. Please check its documentation for complex condition sets.

An example which includes both explicit exclude and include parts could be written as:

when:
- branch:
include: [main, release/*]
exclude: [release/1.0.0, release/1.1.*]
when:
- event: cron
cron: <cron name>

Execute a step only if the provided evaluate expression equals to true. Both built-in CI_ and custom variables can be used inside the expression.

Examples:

  • Run on pushes to the default branch for the repository owner/repo:

    when:
    - evaluate: 'CI_PIPELINE_EVENT == "push" && CI_REPO == "owner/repo" && CI_COMMIT_BRANCH == CI_REPO_DEFAULT_BRANCH'
  • Run on commits created by user user1:

    when:
    - evaluate: 'CI_COMMIT_AUTHOR == "user1"'
  • Skip all commits containing “please ignore me” in the commit message:

    when:
    - evaluate: 'not (CI_COMMIT_MESSAGE contains "please ignore me")'
  • Run on pull requests with the label deploy:

    when:
    - evaluate: 'CI_COMMIT_PULL_REQUEST_LABELS contains "deploy"'
  • Skip step only if SKIP=true, run otherwise or if undefined:

    when:
    - evaluate: 'SKIP != "true"'

A list of all available events:

  • push: triggered when a commit is pushed to a branch.
  • pull_request: triggered when a pull request is opened or a new commit is pushed to it.
  • pull_request_closed: triggered when a pull request is closed without being merged.
  • pull_request_merged: triggered when a pull request is merged.
  • pull_request_edited: triggered when a pull request is edited (the PR title or body).
  • tag: triggered when a tag is pushed.
  • release: triggered when a release, pre-release or draft is created. (Further filters can be applied using evaluate in combination with environment variables.)
  • deployment: triggered when a “deployment” is created in the repository. (There are two ways to trigger this event: from the Crow UI directly or from a forge which supports “deployment” events (e.g., GitHub))
  • cron: triggered when a cron job is executed. Requires a cron job to be configured in the dashboard.
  • manual: triggered when a user manually triggers a pipeline in UI or via CLI.

Event triggers can be combined. If this is used, all conditions need to evaluate to true. Example: Execute a step if the pipeline event is a push to a specified branch:

when:
- event: push
branch: main

Execute a step for multiple events:

when:
- event: [push, tag, deployment, manual]
# alternative syntax
# - event:
# - push
# - tag
# - deployment
# - manual

Execute a step for a single matrix permutation:

when:
- matrix:
GO_VERSION: 1.5
REDIS_VERSION: 2.8

Only execute a step when specific files were changed:

when:
- path: 'src/*'

Glob patterns are used to match the changed files.

For pipelines without file changes (empty commits or on events without file changes like tag), on_empty can be used to set whether the condition should be true (default) or false.

when:
- path:
include: ['.crow/*.yaml', '*.ini']
exclude: ['*.md', 'docs/**']
ignore_message: '[ALL]'
on_empty: true

Execute a step for a specific platform:

when:
- platform: linux/amd64

Execute a step for a specific platform using wildcards:

when:
- platform: ['linux/*', 'windows/amd64']

The ref filter is compared against the git reference of the workflow. Example: filter tags that start with v:

when:
- event: tag
ref: refs/tags/v*

Filter by repository:

when:
- repo: test/test

To execute steps on failure of previous pipelines, for example to send notifications for such, the status filter can be used:

when:
- status: [success, failure]