Actions CI
- Forgejo Actions | User guide
- Forgejo Actions | Quick start guide
- Forgejo Actions | Basic concepts
- Forgejo Actions | Advanced features
- Forgejo Actions | Using Actions
- Forgejo Actions | Security
- Forgejo Actions | Security of Pull Requests
- Forgejo Actions | Security OpenID Connect
- Forgejo Actions | GitHub Actions
- Forgejo Actions | Reference
- Forgejo Actions | Troubleshooting
Forgejo Actions | User guide
Forgejo Actions is a Continuous Integration system built into Forgejo. It lets you automatically build, lint, test, deploy or publish your software.
Quick start
If you want a quick way to get started with an example, check out the quick start guide.
Workflows
Forgejo Actions workflows are defined using .yaml files in the .forgejo/workflows directory of the repository. The workflow file describes the events that should trigger the workflow, and which jobs need to be executed.
NOTE: in the absence of a
.forgejo/workflowsdirectory, workflows will be looked up in the.github/workflowsdirectory, if it exists.
For more information about how to write workflow files, check out the basic concepts. There is also a guide to the more advanced features.
Runners
Workflows are not executed by the Forgejo instance itself. Instead, they are handed out to runners, which perform the workflow and report back with the results.
In order for a workflow to run, an appropriate runner needs to be available to the repository. You can view the available runners in the repository settings, under Actions > Runners.
If the instance does not provide runners, or if you wish to use your own runners, check out the Forgejo Runner installation guide to see how to set up and connect your own runner.
Troubleshooting
Learn the basics of troubleshooting a failed workflow or action.
Security
Sensitive security-related issues should be reported to security@forgejo.org using encryption.
A security audit of the runner was conducted late 2024 (see the penetration test report for more information). All issues found on that occasion were fixed in 2025.
About GitHub Actions
If you are familiar with GitHub Actions, you'll likely recognize many things in Forgejo Actions. Forgejo Actions is designed to be familiar to users of GitHub Actions, but it is not designed to be compatible.
If you wish to migrate a workflow from GitHub Actions to Forgejo Actions, some minimal tweaking will most likely be necessary.
For a more detailed description of the differences between GitHub Actions and Forgejo Actions, check out the GitHub Actions differences page.
Alternative CI options
Forgejo Actions is a CI system built into Forgejo. There are also other CI systems available, which may be more suitable for certain use-cases. A list of these is available in the forgejo-contrib repository.
Forgejo Actions | Quick start guide
This guide explains how to set up a simple Forgejo Actions workflow. The basic concepts are all mentioned here, and links to further information are provided.
Setting up Actions
To get started we will have to do some setup:
-
First, verify that Actions is enabled for your repository. Visit your repository settings, and go to Units > Overview. Make sure the Actions checkbox is ticked. If it is not visible, your instance administrator has disabled Forgejo Actions.
-
Next, see if there is a runner available for the repository. Visit the repository settings, and go to Actions > Runners. If there are no runners listed, follow the Forgejo Runner installation guide to set up a runner, and return here when you're finished.
Adding the workflow
Now we are ready to write a workflow file and add it to our repository:
- Create a file
.forgejo/workflows/demo.yaml, and add the following code:
on: [push]
jobs:
test:
runs-on: docker
steps:
- run: echo All good!
This file describes a workflow. The workflow will trigger on a push event. The workflow contains one job, called test. This job will run on a runner with the label docker. If your runner (from step 2) has a different label, you should specify it here. The test job has one step, which is to simply run the command echo All good!.
Save the file and push it to the main branch of the repository.
- Go to the
Actionstab of the repository. You should see yourdemo.ymlworkflow listed on the left. Because you pushed to a branch, the workflow has been triggered, and you can view the results of the run on the right.If you click on the run you'll get a more detailed view with the output from the runner:
If the run does not start and you get a warning that no matching runner is online, you have most likely forgotten to change the runs-on field in the workflow. Find the label for the runner you want to use in step 2, and edit your workflow file.
Congratulations! You've just run your first workflow. Now you can expand your workflow to do all sorts of things, from building your code to sending it to a remote server. For most tasks you'll want to get the code into the workflow, so we'll cover that in the next section.
Using an action to check out your code
An action is a reusable procedure for doing something in your CI workflow. In many ways, actions are similar to functions. To get the content of your repository into a workflow, we will be using the actions/checkout action. An action is simply a repository with some special files in it. For more information about how to use them and how to make your own, check out the actions guide.
- Add the following lines to the
demo.yamlfile, below- run: echo All good!:
- uses: actions/checkout@v6
- run: ls -la
Here we are adding two steps. The first step uses the action actions/checkout, specifically v6. We are not passing any parameters, as we just want to check out this repository. The second step simply runs the command ls -la to show us the content of the working directory.
Commit these changes and push them to the main branch of the repository.
- Go to the actions tab and view the output the most recent run. You should see the two new steps.
Forgejo Actions | Basic concepts
This page explains the basic concepts you'll encounter when using Forgejo Actions.
All Forgejo Actions workflows are defined in workflow files. These are .yaml files stored in the .forgejo/workflows directory of a repository. Below is an example of a simple workflow file:
Basic syntax
on: [push]
jobs:
print-content:
runs-on: docker
steps:
- name: checkout code
uses: actions/checkout@v6
- name: list directory contents
run: ls -la
The on key specifies which events the workflow should trigger on. In this case it triggers on any push operation. You can narrow this down to specific branches, or trigger on other events like issues or pull requests.
The jobs key contains the jobs that are part of this workflow. A job is one unit of work that will be handed out to a runner. A workflow may contain multiple jobs. By default, these will run independently from one another.
This workflow contains one job, called print-content. The runs-on key specifies the label of the runner the workflow will run on. This job will only run on runners with the docker label.
A job consists of one or more steps. The steps are executed in order. If one step fails, the job will clean up and no further steps will be run.
The first step, checkout code, uses an action to check out the contents of the repository into the working directory. Actions are reusable procedures for doing something in your CI workflow. Read more about actions.
The second step, list directory contents, runs the provided command in the shell of the job. In this case it lists the contents of the working directory.
That concludes the basic syntax of a workflow file. For a complete definition of the syntax of a workflow file, see the workflow reference.
Expressions
In a workflow file you may use expressions. These look like ${{ ... }}. Expressions are evaluated by the runner when executing a workflow. In certain fields of the workflow file, like if: , the ${{ }} is implicit and can be stripped.
NOTE: Implicit type conversions with booleans may be difficult to figure out when assigned to actions inputs or output values. It is easier for debugging to use explicit strings (e.g. 'yes' or 'no') instead of true/false or 'true'/'false'.
Check out the expression example
Variables
You can use variables to read information from the workflow context. There are many different variables available. For example, the expression ${{ forgejo.ref_name }} would be substituted with the name of the branch the workflow is running for.
For a complete list of the values available in the workflow context, see the workflow reference.
Literals
You may use the following types of literals in expressions:
- boolean: true or false
- null: null
- number: any number format supported by JSON
- string: enclosed in single quotes
Logical operators
You may use the following logical operators in expressions:
| Operator | Description |
|---|---|
( ) |
Logical grouping |
[ ] |
Index |
. |
Property de-reference |
! |
Not |
< |
Less than |
<= |
Less than or equal |
> |
Greater than |
>= |
Greater than or equal |
== |
Equal |
!= |
Not equal |
&& |
And |
|| |
Or |
NOTE: String comparisons are case insensitive.
Conditionals
You may use these functions in if: conditionals on jobs and steps.
success(). returns true when none of the previous jobs/steps have failed or been cancelled.always(). causes the job/step to always execute, and returns true, even when cancelled. If you want to run a job/step regardless of its success or failure, use the recommended alternative:'!cancelled()'(the expression must be enclosed by quotes to not be interpreted as YAML tag).failure(). returns true when any previous step/job has failed.
Functions
You may use these functions in expressions:
contains( search, item ). Returnstrueifsearchcontainsitem. Ifsearchis an array, this function returnstrueif theitemis an element in the array. Ifsearchis a string, this function returnstrueif theitemis a substring ofsearch. This function is not case sensitive. Casts values to a string when comparing.startsWith( searchString, searchValue ). ReturnstruewhensearchStringstarts withsearchValue. This function is not case sensitive. Casts values to a string.endsWith( searchString, searchValue ). ReturnstrueifsearchStringends withsearchValue. This function is not case sensitive. Casts values to a string.format( string, replaceValue0, replaceValue1, ..., replaceValueN). Replaces values in thestring, with the variablereplaceValueN. Variables in thestringare specified using the{N}syntax, whereNis an integer. You must specify at least onereplaceValueandstring. Escape curly braces using double braces.join( array, optionalSeparator ). The value forarraycan be an array or a string. All values inarrayare concatenated into a string. If you provideoptionalSeparator, it is inserted between the concatenated values. Otherwise, the default separator,is used. Casts values to a string.toJSON(value). Returns a pretty-print JSON representation ofvalue.fromJSON(value). Returns a JSON object or JSON data type forvalue. You can use this function to provide a JSON object as an evaluated expression or to convert environment variables from a string.hashFiles(pattern[, ...]). Returns a hash (e.g.39b35c59b92fdb3024d09a4f2f960d123ba59c3d531569f5195b65fbf0a40161) based on the concatenated content of all the files matching the patterns given in argument. Returns an empty string if the files are not found. It is a JavaScript function executed in the container running the action and requires Node.js to be installed.
Some of these functions cast values to strings in order to compare them. The following conversions are used:
| Input type | Output result |
|---|---|
null |
'' (empty string) |
| booleans | 'true' or 'false' |
| numbers | decimal format, exponential for large numbers |
| arrays | arrays are never converted to strings |
| objects | objects are never converted to strings |
Secrets
A repository, a user or an organization can hold secrets, a set of key/value pairs that are stored encrypted in the Forgejo database and revealed to the workflows as ${{ secrets.KEY }}. They can be defined from the web interface:
- in
/org/{org}/settings/actions/secretsto be available in all the repositories that belong to the organization - in
/user/settings/actions/secretsto be available in all the repositories that belong to the logged in user - in
/{owner}/{repo}/settings/actions/secretsto be available to theworkflowsof a single repository
Once the secret is added, its value cannot be changed or displayed.
Custom variables
A repository, a user or an organization can hold variables, a set of key/value pairs that are stored in the Forgejo database and available to the workflows as ${{ vars.KEY }}. They can be defined from the web interface:
- in
/org/{org}/settings/actions/variablesto be available in all the repositories that belong to the organization - in
/user/settings/actions/variablesto be available in all the repositories that belong to the logged in user - in
/{owner}/{repo}/settings/actions/variablesto be available to theworkflowsof a single repository
After a variable is added, its value can be modified.
Name constraints
The following rules apply to variable names:
- Variable names can only contain alphanumeric characters (
[a-z],[A-Z],[0-9]) or underscores (_). Spaces are not allowed. - Variable names must not start with the
FORGEJO_,GITHUB_orGITEA_prefix. - Variable names must not start with a number.
- Variable names are case-insensitive.
- Variable names must be unique at the level they are created at.
- Variable names must not be
CI.
Precedence
A variable found in the settings of the owner of a repository (organization or user) has precedence over the same variable found in a repository.
Automatic token
At the start of each workflow, a unique authentication token is automatically created and destroyed when it completes. It can be used to read the repositories associated with the workflow, even when they are private. It is available:
- in the environment of each step as
FORGEJO_TOKEN - as
forgejo.token - as
env.FORGEJO_TOKEN - as
secrets.FORGEJO_TOKEN
To help with reusing actions and workflows originally developed for GitHub Actions, they are also available under the following names:
GITHUB_TOKEN==FORGEJO_TOKENgithub.token==forgejo.tokenenv.GITHUB_TOKEN==env.FORGEJO_TOKENsecrets.GITHUB_TOKEN==secrets.FORGEJO_TOKEN
This token can only be used for interactions with the repository of the project and any attempt to use it on other repositories, even for creating an issue, will return a 404 error.
This token also has write permission to the repository and can be used to push commits or use API endpoints such as creating a label or merge a pull request.
In order to avoid infinite recursion, no workflow will be triggered as a side effect of a change authored with this token. For instance, if a branch is pushed to the repository and there exists a workflow that is triggered on push events, it will not fire.
A workflow triggered by a pull_request or pull_request_target event from a forked repository is an exception: in that case the token does not have write permissions to the repository. The pull request could contain an untested or malicious workflow.
NOTE: In the case of a
pull_request_targetthe risk is mitigated and the automatic token may be given write permissions in future versions of Forgejo.
Actions
An action is a reusable procedure for accomplishing something in your CI workflow.
Using actions
To use an action, specify the uses: key in a step like this:
- name: Checkout the repository
uses: actions/checkout@v6
with:
ref: 'main'
The uses key contains the name of the repository the action is stored in. You can specify it in shorthand like above, in which case it will be prefixed with the DEFAULT_ACTIONS_URL. You can also specify the full url: uses: https://codeberg.org/username/yourcustomaction.
The with key contains parameters to be passed to the action. Which parameters are available depends on which action you are using. You can find in the documentation of the action you are using.
Creating actions
An action is a repository that contains the equivalent of a function in any programming language. It comes in two flavors, depending on the file found at the root of the repository:
- action.yml: describes the inputs and outputs of the action and the implementation. See this example.
- Dockerfile: if no
action.ymlfile is found, it is used to create an image withdocker buildand run a container from it to carry out the action. See this example and the workflow that uses it. Note that files written outside of the workspace will be lost when the step using such an action terminates.
Just as any other program or function, an action has pre-requisites to successfully be installed and run. When looking at reusing an existing action, this is an important consideration. For instance setup-go depends on NodeJS during installation.
To read more about creating your own actions, see the actions guide.
Forgejo Actions | Advanced features
This page covers the more advanced features of Forgejo Actions.
pre-commit hook
A pre-commit hook is provided to assist in
validating Forgejo Actions files in your projects.
See pre-commit.com for detailed instructions on how
to set it up, as well as more details on how it works, and then add this to
your .pre-commit-config.yaml file:
repos:
- repo: https://code.forgejo.org/forgejo/runner
rev: v11.1.1
hooks:
- id: forgejo-runner-validate
Artifacts
Artifacts let you persist data after a job has completed. An artifact is a file or collection of files produced during a workflow run.
This has two main uses:
- Storing non-permanent data after a workflow finishes, like test results.
- Storing data generated in one job, so another job later in the same workflow can use it.
Artifacts expire after a delay of 90 days by default, but this may be changed by the instance admin.
The artifacts created by a workflow can be downloaded from the web interface that shows the the details of the jobs for a workflow.
Check out the example based on the upload-artifact action and the download-artifact action.
NOTE: The name of an artifact is limited to 255 characters.
NOTE: It is not currently possible to access artifacts from other workflow runs within forgejo #8004.
NOTE: When using upload and download actions you must use v3 or patched v4 as demonstrated here.
Uploading to a package registry
Forgejo offers built-in package registries. You can use these to publish packages for various package managers, or just generic build output.
Cache
You can use the Cache to reuse commonly used files from previous workflow runs, like package downloads or intermediary build results.
Some Actions will automatically use the cache. For
instance the setup-go action will do that by default to save downloading and compiling packages found in go.mod.
It is also possible to explicitly control what is cached (and when)
by using the actions/cache action.
Caching makes no guarantees that a cache will be populated, even when two
jobs are run in sequence. If you want to reliably exchange information
between jobs, see artifacts.
See also the set of examples.
NOTE: actions/cache will use
zstdif present when compressing files to be sent to the cache. It is faster than the default compression. A container which does not havezstdinstalled will not be able to decompress the cache and will continue without. In general it is recommended to ensure that if you're usingzstdin one place in your project, you use it everywhere.
NOTE: if the runner is not configured to provide a cache, actions/cache will fail with the following error:
Cache action is only supported on GHES version >= 3.5.
Caching with Podman
Since version 5, when used with Pasta, which is the default, Podman copies the IP of the primary interface of the host into containers. Therefore, it is not possible to connect to the host using the host's primary IP address, which is the method used by actions/cache. It manifests in errors like ::warning::Failed to restore: getCacheEntry failed: connect ECONNREFUSED 192.168.124.60:41275.
There are multiple options to deal with it.
One option is to configure Podman not to use the host's primary IP address for containers; see the article Podman 5.0 breaking changes in detail, section "Pasta default for rootless networking".
Another option is to change the Forgejo Runner configuration to use the "magic" host name host.containers.internal:
cache:
proxy_port: 4000
actions_cache_url_override: 'http://host.containers.internal:4000'
However, that is only an option if a particular Forgejo Runner instance only uses Podman as a back-end and not, for example, Podman and LXC, because all back-ends would receive http://host.containers.internal:4000 as cache URL.
Services
Services like databases can be started from container images and are then available to all steps in a particular job:
job:
my-job:
runs-on: docker
services:
pgsql:
image: postgres:15
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
...
A container with the specified image: is run before the job starts and is terminated when it completes. The job can address the service using its name, in this case pgsql.
The IP address of pgsql is on the same network as the container running the steps and there is no need for port binding. The postgres:15 image exposes the PostgreSQL port 5432 and a client will be able to connect as shown in this example.
NOTE: services are only supported with the
dockerbackend, not with thelxcbackend.
NOTE: services require
[container].networkto be empty so that a new network can be temporarily created to connect the container running the workflow with the services.
See the reference for the list of supported options. There are also a number of examples that illustrate the configuration and usage of services.
Forgejo Actions | Using Actions
Actions are reusable pieces of code that you can use in your CI workflows.
Using Actions
For example, to check out the contents of the repository you can use the actions/checkout action. To use it, add the following step to a job in your workflow:
- name: Check out the repository
uses: https://data.forgejo.org/actions/checkout@v6
This specifies that this step uses the action https://data.forgejo.org/actions/checkout, version v6.
You can also specify an action like uses: actions/checkout@v6. In this case the runner will prefix it with the DEFAULT_ACTIONS_URL and proceed like normal. The DEFAULT_ACTIONS_URL is https://data.forgejo.org/ by default, but it can be changed by the instance administrator. For this reason it is strongly recommended to use fully qualified URLs. In this guide we will use the shorter notation for brevity.
You can also load an action from a local directory instead of a remote repository. This is called a local action.
Action inputs
An Action can have parameters, called inputs. You can usually read which inputs an action has in its README. To specify the inputs for an action, you can use the with key like so:
- name: Check out the repository
uses: actions/checkout@v6
with:
ref: my-feature-branch
path: some/subdirectory
show-progress: true
Action dependencies
Since Actions are simply scripts run in your CI workflow, they usually have dependencies. For example, the actions/checkout action depends on NodeJS. If it is not present the action will fail. When using non-standard container images it is important to check that the required dependencies are present. If they are not you can try these fixes:
- Find a container image that does have the dependencies pre-installed.
- Install the dependencies during the workflow, by using a package manager.
- Find an alternative action that doesn't have the dependencies.
Local actions
If an action's uses statement starts with ./ it will be loaded from the specified local directory, instead of being cloned from a remote repository. The layout and content of the actions directory will be exactly the same as with a remote action.
The action is taken from a local directory, from the perspective of the runner. This means you will typically need to have a checkout action before being able to use a local action.
Creating your own actions
It is fairly simple to create your own actions. An action is really just a directory with an action.yml in it. There are three types of actions, node, docker and composite.
These types of actions are both explained further below.
Tip: When first developing an action, it is useful to load it as a local action for testing.
action.yml
The action.yml file contains all the metadata for the action. It decides the name, description, inputs, outputs and how to run the action.
Take a look at this simple example:
name: 'Example Action'
author: 'Me, I wrote it'
description: |
A simple action that just takes some input and writes it to a file.
inputs:
message:
description: 'The message to be stored'
default: 'default message'
outputs:
time:
description: 'The time when the action was run'
runs: ...
The content of the runs key determines what type of action it is.
node actions
Node actions are executed using NodeJS. NodeJS will not automatically be installed, so if it is not present in the container image the action will fail.
Node actions have the following information in the runs key:
runs:
using: 'node20'
main: 'index.js'
The main key determines the entry point for execution.
For more information about writing node actions, check the GitHub documentation. Keep in mind that certain details differ between GitHub and Forgejo.
docker actions
Docker actions are executed using a container engine. They can only be used on runners that provide one, like Docker or Podman.
Docker actions have the following information in the runs key:
runs:
using: 'docker'
image: 'Containerfile'
args:
- ${{ inputs.message }} # This also needs to be defined in the inputs section above.
The image key points at the Containerfile that should be used to build the image that will be run. The Containerfile contains the configuration for the base image, as well as an entrypoint. Arguments can be passed with the args key.
For more information about writing Docker actions, check the GitHub documentation. Keep in mind that certain details differ between GitHub and Forgejo.
composite actions
Composite actions are simply a series of steps from a normal workflow, packaged as an action for easier reuse.
Composite actions have the following information in the runs key:
runs:
using: 'composite'
steps:
- name: Print message
run: echo "$MESSAGE"
shell: bash
env:
MESSAGE: ${{ inputs.message }} # This also needs to be defined in the inputs section above.
- name: Some other step
...
Composite actions can use other actions just like normal workflows. You can also write scripts, commit them to the action repository, and then use them in the action by calling them with a run key.
Forgejo Actions | Security
Forgejo Actions is a very flexible CI/CD system. It lets you write workflows that execute arbitrary code, with contents of potentially private repositories. This brings some security risks. This page details the security design of the Actions system, and any considerations you should be aware of.
Security Design
Forgejo Actions consists of two main parts: The Forgejo server, which contains the repository and hands out workflow runs; and the Forgejo Runner, which receives workflow runs and executes them. One server may have many different runner attached, which are registered to different users or organizations.
Runner selection
When a workflow is triggered, the Forgejo instance will try to find a runner to run the workflow. The runner will be selected from a pool of runners that consists of the following groups:
- Runners registered to the Forgejo instance by the instance administrators
- Runners registered to the user account or organization account that the repository belongs to
- Runners registered to the specific repository
Your workflow will never be executed by a runner that does not belong to one of these groups.
Pull requests from forks
When a repository is publicly available on a Forgejo instance with open registration, any user can open a pull request that includes code to be executed by Forgejo Actions. Checkout the section dedicated to trust management for more information.
Automatic token
When a workflow is started, a unique authentication token is automatically created. It can be used to read the repositories associated with the workflow, even when they are private. This token is automatically destroyed when the workflow finishes.
This token can only be used for interactions with the repository it was created for, and any attempt to use it on other repositories will return a 404 error.
Pull requests
Workflows triggered by the pull_request event are an exception. The token generated for these runs does not have write permissions for the repository, since a pull request is not verified and could contain an untested or malicious workflow.
pull_request_target
As an alternative to pull_request there is pull_request_target. Workflows with this event will run in the context of the base of the Pull Request, instead of the incoming commits. This means that the changes proposed in the PR are not available in the workflow. You cannot use this event to perform workflows that would check the incoming changes.
Because no untrusted code is available to the runner in this context, the restrictions on the token are lifted. That means you can use this event type to write to the repository, for example to change labels or place comments.
Runner
The Forgejo Runner attempts to isolate different workflow runs from each other as much as possible. How this is achieved depends on the kind of runner it is.
Docker, Podman and LXC runners
In the case of a runner which uses OCI (Docker, Podman) or LXC containers, a new container will be created for each workflows. The containers provide isolation from the host system and other containers.
However, if the container environment is misconfigured it may be possible for a workflow to escape its confinement and perform potentially malicious actions. This may compromise the runner, which means that any future workflows sent to this runner may also be compromised.
Host runners
Host runners have no real isolation. When a workflow finishes the appropriate folders are cleaned up, so any workflows that stay within the intended bounds shouldn't have any effect on each other.
It is trivial to 'escape' on a host runner, and all sorts of malicious things can be done.
Secrets
Secrets can be used to store passwords or tokens for use in a workflow. They are stored encrypted in the Forgejo database, and sent out to workflows when they are needed. More information.
Forgejo Runner attempts to automatically redact secrets from the logs.
Security considerations
When using Actions, keep in mind the following considerations:
Runner
- Container runners are generally safe, but they may be compromised if misconfigured.
- Never trust a host runner if it is shared with other users.
- The safest option is to host your own runner, and use it only for your trusted repositories.
Secrets
- Use the secrets feature to store API tokens and passwords for use in workflows.
- Do not print secrets to output, as these may be publicly visible.
Forgejo Actions | Security of Pull Requests
A pull request may contain code that changes what is run by Forgejo
Actions, for instance if it modifies a file in the
.forgejo/workflows directory. When such a pull request originates
from a fork of a public repository on a Forgejo instance with open
registration, the author may be a malicious user. For this reason the
workflows of such pull requests need to be approved before they are run.
Users with elevated permissions on a repository can approve or deny workflows runs using the pull request conversation page.
Trust management
Trust is either granted or denied to the author of a pull request.
When using the Approve once button, all pending workflows will be
allowed to run. However future workflows will need another manual
approval (for instance if a new commit is pushed to the same pull request).
Using the Approve always button will trust the author of the pull request to always
run workflows on this repository.
It is possible to revoke that trust at any time.
The page displaying the run of each blocked workflow shows a link to the trust management area of the pull request.
Which users need approval?
The users who only have read access to the repository need approval before workflows triggered by a pull request they authored can be run.
The users who have elevated permissions on the repository do not need approval, even if they author a pull request from a forked repository. That includes:
- Collaborators with write access
- Team members with write permissions on the
Actionsunit Ownersof the repository- Instance admins
What pull requests need approval?
- from a fork of the repository
- created using the
AGitworkflow
Which user can grant approval?
Trust management is available to users who are either:
- Collaborators with write access
- Team members with write permissions on the
Actionsunit Ownersof the repository- Instance admins
Which workflow files are used?
When a trusted user submits a pull request, workflows found in the
pull request content are used (except for the ones using the
pull_request_target event), taking into account any changes done to
these files as part of that pull request.
If the pull request is not from a trusted user and a workflow is triggered by a trusted user, the workflows found in the target branch of the pull request will be used instead of those found in the pull request.
A concrete use case is to allow the repository owner to set a label on a pull request from an untrusted user without having to verify if the pull request contains a malicious workflow.
Trust expiration
When a permanently trusted user has not submitted a pull request for over three months, the trust they may have been granted on a given repository will be automatically revoked.
Blocked users
When a user is blocked, the trust they were granted on all repositories owned by the user doing the blocking will be revoked.
All workflow runs created on their behalf on those repositories will be canceled.
Forgejo Actions | Security OpenID Connect
Forgejo Actions allows for workflows to request OpenID Connect compatible JWT ID tokens from Forgejo to exchange with external systems for credentials once a trust relationship between the external service and Forgejo is established.
These trust relationships can be configured in platforms such as AWS, GCP, and Azure, to make assertions on metadata in Forgejo ID tokens and exchange them for granularly scoped and short-lived access tokens.
Benefits
- Eliminates the needs for secrets stored in Forgejo for compatible external systems
- Access tokens generated by external systems are short-lived and expire automatically
- Allows for granular control over authentication and authorization in external systems via assertions on metadata in the Forgejo ID tokens
High level flow
- A workflow run makes a request to Forgejo to generate an OIDC (OpenID Connect) ID token.
- Forgejo generates and returns an OIDC ID token that contains metadata about the run, repo, actor, and other information.
- The returned OIDC ID token can be exchanged with external platforms for short-lived credentials in these systems.
- The external platform will make a request to Forgejo for required metadata and keys to validate the received token.
- Forgejo responds to these requests with OIDC metadata, including where to find signing keys.
- The external platform uses this metadata, the keys, and a configured trust relationship to validate access and provide short-lived credentials if these validations pass.
- The workflow run receives these short-lived credentials, and can now use them to access the external platform.
Prerequisites
A trust relationship must be established in a compatible external system to allow for exchanging an ID token for short-lived credentials.
Setup instructions for some compatible external systems are as follows:
NOTE: Improperly configured trust relationships can allow for unintended access to third party systems. The
sub,iss, andaudclaims should be validated in the trust relationship at the minimum. Trust relationships should be configured to be as strict and narrowly scoped as is possible for your usecase.
Token structure
JWT tokens are comprised of three main components:
- A header which contains information about the signing algorithm and key used for signing the token
- A body or payload which contains
- A signature of the other two sections based on the signing algorithm used
These sections are Base64 URL encoded and joined by . to form the JWT.
Examples of what the decoded sections look like follow below.
Header
{
"alg": "RS256",
"kid": "iSrBtRq6EaN6605cSatQEnafFF82rOfm_22_d_V6ehQ",
"typ": "JWT"
}
Body
{
"actor": "user1",
"aud": "exampleAudience",
"event_name": "push",
"exp": 1767217099,
"iat": 1767213499,
"iss": "https://example.com/api/actions",
"nbf": 1767213499,
"ref": "refs/heads/master",
"ref_protected": "false",
"ref_type": "branch",
"repository": "user1/testing",
"repository_owner": "user1",
"run_attempt": "1",
"run_id": "43",
"run_number": "43",
"sha": "76cb2978acb72029ac23277a6192eea1707c6a2c",
"sub": "repo:user1/testing:ref:refs/heads/master",
"workflow": "test.yml",
"workflow_ref": "user1/testing/.forgejo/workflows/test.yml@refs/heads/master"
}
Signature
The format of the signature will depend on the algorithm used for signing the JWT ID token.
Reference
Requesting an ID token
OpenID connect must be enabled in workflow files at either the workflow or individual job level to be able to generate ID tokens from action runs.
When enabled, ACTIONS_ID_TOKEN_REQUEST_TOKEN and ACTIONS_ID_TOKEN_REQUEST_URL will be injected into the runners environment. A token can then be generated by running:
curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=exampleCustomAudience"
where the audience is an optional query param can be customized to match the value of the aud claim expected by the trust relationship in the external platform.
When unspecified, the aud value will default to the Forgejo instance's URL with the repository owner as a suffix.
For example, https://example.com/user1.
Subject format
When the event that triggered the workflow is a pull_request the subject format is:
repo:[repository]:pull_request
where [repository] is the owner and repository name (e.g., forgejo/docs).
For all other events that trigger workflows, the subject format is:
repo:[repository]:ref:[ref]
where [ref] is the fully formed git reference (i.e. starting with refs/) associated with the event that triggered the workflow, if any (e.g. refs/heads/main)
Standard claims
The Forgejo ID token contains a number of well-known standard (also known as registered) claims as defined by RFC 7519.
| Claim | Summary | Description |
|---|---|---|
aud |
Audience | The intended audience of the ID token. This can be configured using the audience URL param when requesting a token, and defaults to [forgejo instance URL]/[repository owner]. |
iss |
Issuer | The issuer of the ID token. This will be in the format: [forgejo instance URL]/api/actions. For example, https://example.com/api/actions. |
sub |
Subject | The subject claim for the token. See subject format for more details. |
iat |
Issued at | The time that the token was issued. |
exp |
Expires at | The expiry time of the token. |
nbf |
Not before | The time after which this token is valid. |
Custom claims
The Forgejo ID token contains a number of custom claims that contain Forgejo specific information.
| Claim | Summary | Description |
|---|---|---|
actor |
Triggering actor | The name of the user that triggered the workflow. |
base_ref |
Base reference | The name of the base branch of the pull request (e.g. main). Only defined when a workflow runs because of a pull_request or pull_request_target event. |
event_name |
Event name | The name of the event that triggered the workflow (e.g. push). |
ref |
Reference | The fully formed git reference (i.e. starting with refs/) associated with the event that triggered the workflow, if any (e.g. refs/heads/main). |
ref_protected |
Is reference protected | true if branch protections are configured for the ref that triggered the workflow run. |
ref_type |
Reference type | The type of the ref (branch or tag for example). |
repository |
Repository | The owner and repository name (e.g. forgejo/docs). |
repository_owner |
Repository owner | The repository owner's name (e.g. forgejo) |
run_attempt |
Run attempt | Attempt number for this run, beginning at 1 and incrementing when the job is re-run. |
run_id |
Run identifier | A unique id for the current workflow run in the Forgejo instance. |
run_number |
Run number | A unique id for the current workflow run in the repository of the workflow. |
sha |
Git SHA | The commit SHA that triggered the workflow. The value of this commit SHA depends on the event that triggered the workflow. |
workflow |
Workflow name | The name of the workflow that triggered the run. |
workflow_ref |
Workflow ref | Ref path to the workflow, for example, owner/example-respository/.forgejo/workflows/test-workflow.yaml@refs/heads/main |
Forgejo Actions | GitHub Actions
If you are familiar with GitHub Actions, you'll likely recognize many things in Forgejo Actions. Forgejo Actions is designed to be familiar to users of GitHub Actions, but it is not designed to be compatible.
Familiarity instead of compatibility
Forgejo Actions is built on top of several existing technologies that were built to emulate GitHub Actions. For this reason, Forgejo Actions will seem very similar to GitHub Actions. Many features are (nearly) identical: workflows defined by YAML files in the repository, a swarm of runners executing actions inside docker containers, the ability to reuse workflows with Actions.
However, GitHub has different constraints when designing GitHub Actions. Because of this, they are able to add some features that are not a great fit for Forgejo Actions. On the other hand, Forgejo Actions has some features that GitHub Actions doesn't have, like running workflows in LXC containers.
Overall, many features from GitHub Actions translate one-to-one to Forgejo Actions. It is mostly the small differences that mean we can't claim to be 100% compatible. These small things are also usually the most difficult and least useful for our users to implement. And, since GitHub continues development on GitHub Actions, keeping up with all the changes would be impractical.
For all of these reasons, Forgejo Actions strives for familiarity instead of compatibility. We want users of GitHub actions to feel familiar using Forgejo Actions, even if there are some small changes here and there. Workflows should work with some minimal changes.
If there is a feature you are missing, you are welcome to discuss it, but keep in mind this philosophy.
Known list of differences
This list may be incomplete. If you find a notable difference, you can edit this page.
- The default environment is very different. Most Forgejo Runners use a Debian bookworm image with just node.js by default, while GitHub uses a larger
ubuntuimage. - Some keys in the
githubcontext are missing. - Certain subkeys on the
jobkey in workflow files are ignored, likepermissions, andcontinue-on-error. - Enabling OIDC ID token generation uses the
enable-openid-connectkey in the workflow file instead ofpermissions: id-token: write
Forgejo Actions | Reference
This page contains the complete reference for Forgejo Actions workflow files. For a more information on what the different parts of these files mean and how to use the syntax, check the basic concepts.
Jump to the context reference.
Workflow Syntax
The syntax and semantics of the YAML file describing a workflow are partially explained here. If something is not documented here, the GitHub Actions documentation may be helpful. However, GitHub Actions and Forgejo Actions are not the same and things might not work right away.
Each chapter documents the function of one key in a workflow YAML file. Keys like <job_id> are placeholders for user-specified names.
defaults
Set some defaults for all jobs in the workflow.
These global defaults can be overridden with the per-job defaults block, which in turn can be overridden by the corresponding option in each step.
defaults:
run:
shell: bash
working-directory: ./scripts
defaults.run.shell
Sets the default jobs.<job_id>.steps[*].shell for all jobs.
Can also be overridden per job: jobs.<job_id>.defaults.run.shell
defaults.run.working-directory
Sets the default jobs.<job_id>.steps[*].working-directory for all jobs.
Can also be overridden per job: jobs.<job_id>.defaults.run.working-directory
name
An optional name for the workflow. This name is displayed in the actions tab. If omitted, the name of the workflow file will be used.
on
Workflows will be triggered on certain events with the following:
on:
<event-name>:
<event-parameter>:
...
e.g. to run a workflow when branch main is pushed
on:
push:
branches:
- main
on.push
Trigger the workflow when a commit or a tag is pushed.
If the branches event parameter is present, it will only be triggered if the commit is pushed to one of the branches in the list.
If the paths event parameter is present, it will only be triggered if the pushed commit modifies one of the path in the list.
If both branches and paths are present, the workflow will only be triggered if both match.
on:
push:
branches:
- 'mai*'
paths:
- '**/test.yml'
Check out the push branches example.
on:
push:
tags:
- 'v1.*'
Check out the push tags example.
NOTE: combining
tagswithpathsorbranchesis not intended.
on.issues
Trigger the workflow when an event happens on an issue, as specified with the types event parameter. It defaults to [opened, edited] if not specified.
openedthe issue was created.reopenedthe closed issue was reopened.closedthe issue was closed or merged.labeleda label was added.unlabeleda label was removed.assignedan assignee was added.unassignedan assignee was removed.editedthe title or body (description) of the issue were modified.
on:
issues:
types: [opened, edited]
on.issue_comment
Trigger the workflow when an event related to a comment happens on an issue or a pull request, as specified with the types event parameter. This event is different The types event parameter defaults to [created, edited, deleted] if not specified.
on:
issue_comment:
types:
- created
- edited
- deleted
[!caution] Caution The event is only generated if the workflow exists on the default branch and the associated SHA is the tip of the default branch. It will not use a workflow found in a pull request.
on.pull_request
Trigger the workflow when an event happens on a pull request, as specified with the types event parameter. It defaults to [opened, synchronize, reopened] if not specified.
openedthe pull request was created.reopenedthe closed pull request was reopened.closedthe pull request was closed or merged.labeleda label was added.unlabeleda label was removed.synchronizethe commits associated with the pull request were modified.assignedan assignee was added.unassignedan assignee was removed.editedthe title or body (description) of the pull request were modified.
on:
pull_request:
types: [opened, synchronize, reopened]
If the head of a pull request is from a forked repository, the secrets are not available and the automatic token only has read permissions.
on.pull_request_target
Trigger the workflow when an event happens on a pull request, and execute the workflow in the context of the target branch of the pull request. Specifically, it is similar to the on.pull_request event with the following exceptions:
- secrets stored in the base repository are available in the
secretscontext, (e.g.${{ secrets.KEY }}). ACTIONS_ID_TOKEN_REQUEST_URLandACTIONS_ID_TOKEN_REQUEST_TOKENwill be available in the environment ifenable-openid-connectis set totrueat the workflow or job level.- the automatic token has write permission to the repository.
- the workflow runs in the context of the default branch of the base repository, meaning that:
- changes to the workflow in the pull request will be ignored
- the actions/checkout action will checkout the default branch instead of the content of the pull request
It is strongly recommended that workflows using on.pull_request_target do not interact with the untrusted code from the pull request, as it can be difficult to anticipate the security risks and side-effects. Although the workflow code itself is executed from the safe source of the target branch, its interactions with the untrusted code could compromise security. A known, non-exhaustive list of risks includes:
- All action steps are executed with the
FORGEJO_TOKENandGITHUB_TOKENenvironment variables; interacting with untrusted code in the pull request may leak these tokens. - Workflows with
enable-openid-connectset totrueat the workflow or job level will have theACTIONS_ID_TOKEN_REQUEST_URLandACTIONS_ID_TOKEN_REQUEST_TOKENvariables set; interacting with untrusted code in the pull request may leak these variables and request OIDC ID tokens. - The
actions/checkoutaction will persist the security token unless configured withpersist-credentials: false; untrusted code in the pull request may retrieve the token from disk and lead to it being leaked. - Secrets that are used in action steps, for example as command-line parameters or environment variables, may be available to environment inspection by untrusted code leading to the risk of secret compromise.
- An
actions/cachestep introduces an opportunity for executed untrusted code in a pull request to poison cache contents which may later be used in a workflow that is executed with higher-level permissions, such as access to more secrets.
The safest configuration is to not checkout the code of the pull request at all.
on.release
Trigger the workflow when an event happens on release, as
specified with the types event parameter.
publishedthe release was created.editedthe body, title or comments of the release were modified.deletedthe release was deleted.
on:
release:
types: [published, edited, deleted]
on.schedule
The schedule event allows you to trigger a workflow at a scheduled time. When a workflow with a schedule event is present in the default branch, Forgejo will add a task to run it at the designated time. The scheduled workflows on other branches or pull requests are ignored.
The scheduled time is specified using the POSIX cron syntax. See also the crontab(5) manual page for a more information and some examples.
on:
schedule:
- cron: '30 5,17 * * *'
By default, schedules are interpreted as UTC. The workflow in the example would be run each day at 05:30 and 17:30 UTC.
Optionally, a different time zone can be specified by supplying an ID of an IANA time zone:
on:
schedule:
- cron: '30 5,17 * * *'
timezone: Europe/Berlin
This workflow would run each day year-round at 05:30 (04:30 UTC from November through March; 03:30 UTC from April through October) and 17:30 (16:30 UTC or 15:30 UTC) in Berlin's local time.
CAUTION: It is recommended not to schedule workflows during the time of day when daylight saving time changes occur. Workflows that are scheduled to run when the clock jumps forward are skipped. When the clock moves backward, workflows run twice.
Forgejo behaves differently than GitHub during daylight saving time changes for historical reasons. Forgejo supported specifying time zones before GitHub did, although using a different syntax, and chose a different approach for dealing with DST changes.
on.workflow_call
The workflow_call event allows you to call a workflow from another workflow.
For example if the following workflow is found in .forgejo/workflows/reusable.yml:
on:
workflow_call:
jobs:
callee:
runs-on: docker
steps:
- run: echo OK
it can be called from another workflow as follows:
on:
push:
jobs:
caller:
uses: ./.forgejo/workflows/reusable.yml
on.workflow_call.inputs
Inputs for a workflow_call are declared in the inputs sub-key, where each sub-key itself is an input. Each of those inputs may have a type:
booleannumberstring
Additionally, every input can be made required, given a human-readable description, and a default value.
on:
workflow_call:
inputs:
boolean:
description: 'Boolean'
required: false
type: boolean
number:
description: 'Number'
default: '100'
type: number
string:
description: 'String'
required: true
type: string
Inputs then can be used inside the jobs with the inputs context:
jobs:
test:
runs-on: docker
steps:
- run: echo ${{ inputs.number }}
Inputs are provided to a workflow_call by using jobs.<job_id>.with.
on.workflow_call.outputs
Outputs for a workflow_call are declared in the outputs sub-key:
outputs:
name_of_the_output:
value: value_of_the_output
A concrete example looks like this:
on:
workflow_call:
outputs:
output1:
value: ${{ jobs.callee.outputs.job-output }}
jobs:
callee:
runs-on: docker
outputs:
job-output: ${{ steps.stepwithoutput.outputs.myvalue }}
steps:
- id: stepwithoutput
run: |
echo "myvalue=outputvalue1" >> $FORGEJO_OUTPUT
on.workflow_dispatch
The workflow_dispatch events allows for manual triggering a workflow by either using the Forgejo UI, or the API with the POST /repos/{owner}/{repo}/actions/workflows/{workflowname}/dispatches endpoint. This event allows for inputs to be defined, which will get rendered in the Forgejo UI or read from the body of the API request.
Inputs are declared in the inputs sub-key, where each sub-key itself is an input. Each of those inputs need to have a type. These types can be:
choice: A dropdown where the available options are defined as a list of strings withoptionsboolean: A checkbox with the values oftrueorfalsenumberstring
Additionally, every input can be made required, given a human-readable description, and a default value.
on:
workflow_dispatch:
inputs:
logLevel:
description: 'Log Level'
required: true
default: 'warning'
type: choice
options:
- info
- warning
- debug
boolean:
description: 'Boolean'
required: false
type: boolean
number:
description: 'Number'
default: '100'
type: number
string:
description: 'String'
required: true
type: string
Inputs then can be used inside the jobs with the inputs context:
jobs:
test:
runs-on: docker
steps:
- run: echo ${{ inputs.logLevel }}
enable-email-notifications
Send an email notification when a workflow run fails.
enable-email-notifications: true
The email notification is sent to the user who triggered the workflow run (for example, the author of a pull request, the user who pushed a commit), unless they disabled email notifications in their settings.
If a workflow run is not associated with a user like a scheduled workflow run, the notification will be sent to:
- The user who owns the repository unless they disabled email notifications in their settings.
- The organization that owns the repository unless there is no contact email in its settings.
NOTE: This setting has no effect on the actions webhooks.
enable-openid-connect
Allow all jobs in the workflow to generate OIDC compliant ID tokens.
enable-openid-connect: true
Enabling this setting adds ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN which can be used to generate an ID token.
See the Security OpenID Connect documentation for more information.
NOTE: This setting is disabled for
pull_requestevents from forked repositories.
env
Set environment variables that are available in the workflow in the env context and as regular environment variables.
env:
KEY1: value1
KEY2: value2
- The expression
${{ env.KEY1 }}will be evaluated tovalue1 - The environment variable
KEY1will be set tovalue1
concurrency
The concurrency settings control the concurrent executions of a workflow when triggered by multiple distinct events.
If no concurrency settings are provided, Forgejo will automatically manage the concurrency of a workflow that is executed by the on.push and on.pull_request (synchronize) events in the following manner: whenever a new event triggers a new workflow invocation, any other invocations of the same workflow will be canceled automatically.
Some common usages of concurrency include:
- If you're performing checks, such as automated tests in a software project, then it can be desirable to ignore older changes and focus on checking the most recent changes. The default behavior, omitting
concurrencyfrom your workflow, is usually fine. - If you're performing releases of artifacts from a branch, then you may want to ensure each event's workflow is completed without being superseded by a later event.
concurrency.cancel-in-progresscan be set tofalseto aid this case, andconcurrency.groupcan be omitted. - If you're performing deployments, then using
concurrency.groupcan be important so that only a single deployment occurs at one time.concurrency.cancel-in-progressis typically set tofalseto avoid canceling an in-progress deployment.
Multiple jobs within a workflow are not affected by the concurrency setting. jobs.<job_id>.needs can be used to introduce ordering between different jobs, which can prevent them from running concurrently if desired.
concurrency.group
An optional concurrency group for the workflow. A concurrency group is a string that is defined by the workflow. When a concurrency group is present, Forgejo will make a best-effort to ensure that only a single workflow with the same concurrency group is executed at one time. The contexts forgejo/forge/github, inputs, and vars can be referenced. Concurrency groups are case insensitive.
When multiple workflows are triggered from events with a concurrency group, the concurrency.cancel-in-progress setting determines how only a single workflow will execute; either cancelling previous workflow runs, or queuing behind them.
For example:
on: [push]
concurrency:
group: deploy-${{ forgejo.ref }}
jobs:
# ...
In this example, the concurrency group will evaluate to a string like deploy-refs/heads/main. Only a single workflow with this concurrency group will execute at once, even if multiple pushes occur to the main branch.
Forgejo makes a best-effort to ensure that only a single workflow with the same concurrency group is executed at one time by dispatching tasks to runners only when Forgejo believes no other runner is executing the workflow. However, in exceptional circumstances this cannot be guaranteed.
concurrency.cancel-in-progress
cancel-in-progress is a boolean setting indicating whether to cancel the execution of other workflows when new events trigger new workflows. Variables from the contexts forgejo/forge/github, inputs, and vars can be referenced.
If the concurrency.group setting is not provided, then cancel-in-progress behaves as follows:
- If omitted, it will default to
trueforon.pushandon.pull_request(synchronize) events. - If evaluated to
true, then any previous invocation of the same workflow with the same branch will be canceled, allowing the newest event to be processed as soon as possible. - If evaluated to
false, then no concurrency management will occur. Multiple invocations of the workflow may run simultaneously, as long as the available runner instances have capacity to execute the workflows.
Example:
on: [push]
concurrency:
cancel-in-progress: false
If the concurrency.group setting is provided, then cancel-in-progress behaves as follows:
- If omitted, it will default to
trueforon.pushandon.pull_request(synchronize) events. - If evaluated to
true, then any previous invocation of any workflow in the repository with the same concurrency group will be canceled, allowing the newest event to be processed as soon as possible. - If evaluated to
false, then any previous invocation of any workflow in the repository with the same concurrency group will be executed before the newer invocation, allowing each workflow to complete in sequence. Note that exact sequential ordering is not guaranteed; while typically workflows that were triggered earlier will be executed earlier, there are some edge-cases where this does not occur. For example, a workflow may be "re-run" through the UI even if later workflows have already been queued or completed.
Example:
on: [push]
concurrency:
group: deploy-${{ forgejo.ref }}
cancel-in-progress: true
As the value of cancel-in-progress can be evaluated with an expression, it can be used to make workflows sequential conditionally; for example, the below configuration would cancel most workflows on a push, but allow multiple simultaneous workflows on main:
on: [push]
concurrency:
cancel-in-progress: ${{ forgejo.ref_name != 'main' }}
jobs:
# ...
jobs
The list of jobs in the workflow. The key to each job is a job_id and its content defines the sequential steps to be run.
Each job runs in a different container and shares nothing with other jobs.
All jobs run in parallel, unless they depend on each other as specified with jobs.<job_id>.needs.
jobs.<job_id>
Specifies the id for the job. This is used in some places to uniquely identify the job.
jobs.<job_id>.runs-on
Specifies the kind of machine that is needed to run the job. For instance docker in the following workflow
---
jobs:
test:
runs-on: docker
means that the job will only be sent to a runner which has declared the docker label.
You may have labels to differentiate between:
- Different running environments (Docker, Podman, LXC, host, etc.)
- Different default images (ubuntu-latest, alpine-latest, etc.)
- Different architectures (arm, x86_64, etc.)
- Specific hardware installed on the runner (nvidia-gpu, big-ram, etc.)
The actual machine provided by the runner entirely depends on how the runner was registered (see the Forgejo Actions administrator guide for more information).
The list of available labels for a given repository can be seen in the /{owner}/{repo}/settings/actions/runners page.
If your job specifies a label for which no runner is online, the job cannot be executed and your pipeline will halt until a runner with a matching label comes online. You will be able to see this in the Actions tab of your repository.
runs-on is typically a required field. However, if a job defines jobs.<job_id>.uses in order to reference a reusable workflow, then it is optional. See jobs.<job_id>.uses for more information on this behaviour.
jobs.<job_id>.if
When specified, the job is only run if the expression evaluates to true.
For instance:
---
jobs:
build:
if: forgejo.ref == 'refs/heads/main'
steps:
- run: echo only run on main branch
jobs.<job_id>.needs
Can be used to introduce ordering between different jobs by listing their respective <job_id>. All jobs listed here must complete successfully before this job is considered for execution.
needs can either be a single string, naming a single job as pre-requisite, or an array for specifying multiple jobs to run before this one.
For instance:
---
jobs:
lint:
steps:
- run: echo linting the code
build:
needs:
- lint
steps:
- run: echo only run after linting
jobs.<job_id>.timeout-minutes
Set the number of minutes this job can be performed before it is canceled.
jobs:
test:
runs-on: docker
timeout-minutes: 1
steps:
- run: sleep 2m
- run: echo will never run
jobs.<job_id>.outputs
The jobs.<job_id>.outputs object is a key/value map of the output of the
corresponding job, defined by writing to $FORGEJO_OUTPUT. For instance:
on: [push]
jobs:
job1:
runs-on: docker
outputs:
job1output: ${{ steps.step1.outputs.value }}
steps:
- id: step1
run: |
set -x
echo "value=value1" >> $FORGEJO_OUTPUT
This output can then be used in jobs that run after it completes (i.e. that need it in the sense of jobs.<job_id>.needs). For instance:
job2:
needs: [job1]
runs-on: docker
steps:
- run: |
set -x
test "${{ needs.job1.outputs.job1output }}" = "value1"
jobs.<job_id>.uses
Specifies the reusable workflow to call with a workflow_call event. uses can be specified in one of three supported formats:
./.forgejo/workflows/reusable.yml-- refers to a workflow file within the same repository as the current workflow is defined.some-org/some-repo/.forgejo/workflows/reusable.yml@main-- refers to a workflow file within a different repository (some-org/some-repo), at a specified path and Git reference (main). The target repository must be a public repository.https://example.com/some-org/some-repo/.forgejo/workflows/reusable.yml@main-- refers to a workflow file hosted on a different Forgejo or GitHub instance. The target repository must be a public reposistory.
It is recommended that jobs.<job_id>.runs-on is omitted when using uses, as this will allow Forgejo to perform workflow expansion. Workflow expansion results in the target workflow's jobs appearing in the UI as separate jobs. This provides an easier to understand experience for accessing the logs of each job, and permits the jobs to run on separate runners with their own runs-on fields. A workflow file hosted on a different Forgejo or GitHub instance is not supported by workflow expansion, and will automatically disable it.
uses is typically accompanied by jobs.<job_id>.with and jobs.<job_id>.secrets to provide information into the reusable workflow. See on.workflow_call for more information on defining a workflow call.
jobs.<job_id>.with
A dictionary mapping the inputs of the workflow_call event to concrete values. See on.workflow_call.inputs for more information on how the inputs are declared in reusable workflow.
jobs.<job_id>.secrets
Controls the secrets provided to the reusable workflow being called. It can either be secrets: inherit in which case the reusable workflow will have access to the same secrets as the caller. Or it can be a dictionary mapping a selection of secrets. For instance in the following, the reusable workflow will get keep_it_private as the result of evaluating the expression ${{ secrets.secret }}:
on:
push:
jobs:
caller:
runs-on: docker
uses: ./.forgejo/workflows/reusable.yml
secrets:
secret: keep_it_private
jobs.<job_id>.name
The name of the job. If not set, the name of the job defaults to <job_id>.
The expressions it contains will be interpolated. For instance if the variable SOME is set to THING, in the following:
jobs:
test:
name: jobname-${{ vars.SOME }}
The name of the job will be jobname-THING.
jobs.<job_id>.enable-openid-connect
Allow this job to generate OIDC compliant ID tokens.
on:
push:
jobs:
caller:
uses: ./.forgejo/workflows/reusable.yml
enable-openid-connect: true
See also enable-openid-connect.
NOTE: This setting takes precedence over the workflow level setting.
NOTE: This setting is disabled for
pull_requestevents from forked repositories.
jobs.<job_id>.strategy.matrix
If present, it will generate a matrix from the content of the object and create one job per cell in the matrix instead of a single job.
For instance:
jobs:
test:
runs-on: self-hosted
strategy:
matrix:
variant: ['bookworm', 'bullseye']
node: ['18', '20']
steps:
- uses: https://code.forgejo.org/actions/setup-node@v4
with:
node-version: '${{ matrix.node }}'
Will create four jobs where:
matrix.variant= "bookworm" &matrix.node= "18"matrix.variant= "bookworm" &matrix.node= "20"matrix.variant= "bullseye" &matrix.node= "18"matrix.variant= "bullseye" &matrix.node= "20"
They each run independently and can use the matrix context to access these values, like in the node-version key in the snippet.
The strategy.matrix option can calculate the jobs to be created, typically by using the fromJSON evaluation function. The following snippet contains the same four job matrix defined above, but the matrix options can be defined by the matrix-generator job. The test job needs the matrix-generator job so that it is executed first and defines the job matrix:
jobs:
matrix-generator:
runs-on: docker
outputs:
variants: ${{ steps.generate_matrix.outputs.variants }}
nodes: ${{ steps.generate_matrix.outputs.nodes }}
steps:
- id: generate_matrix
run: |
echo 'variants=["bookworm", "bullseye"]' >> $GITHUB_OUTPUT
echo 'nodes=["18", "20"]' >> $GITHUB_OUTPUT
test:
needs: matrix-generator
runs-on: docker
strategy:
matrix:
variant: ${{ fromJSON(needs.matrix-generator.outputs.variants) }}
node: ${{ fromJSON(needs.matrix-generator.outputs.nodes) }}
container:
image: debian:${{ matrix.obj.variant }}
steps:
- uses: https://code.forgejo.org/actions/setup-node@v4
with:
node-version: '${{ matrix.node }}'
NOTE: if
jobs.<job_id>.nameis set, care must be taken that it evaluates to a unique name for each job created from the matrix, e.g.name-${{ matrix.variant }}-${{ matrix.node}}in the above example.
jobs.<job_id>.container.image
-
Docker or Podman: If the default image is unsuitable, a job can specify an alternate container image with
container:, as shown in this example. For instance the following will ensure the job is run using Alpine 3.20.CAUTION: When starting a container, Forgejo Runner does the equivalent of
docker run <image>. That means that container images, once downloaded, are never updated.Note: Many
Actionsrequire node to run. Using a custom container image that does not contain node may cause these actions to break.runs-on: docker container: image: alpine:3.20It is generally recommended to pin image versions instead of relying on tags, for example,
debian:docker://node@sha256:sha256:91447bc57243b852a21e0ff3553f531f0d4b66257a564b106c79d9e00f3aa14einstead ofdebian:docker://node:lts. That is a prerequisite for reproducible jobs. -
LXC: If the default template and release specified by the runner are unsuitable, a job can specify an alternate template and release as follows.
runs-on: lxc container: image: debian:bookworm
jobs.<job_id>.container.env
Set environment variables in the container.
NOTE: ignored if
jobs.<job_id>.runs-onis an LXC container.
jobs.<job_id>.container.credentials
If the image's container registry requires authentication to pull the image, username and password will be used.
The credentials are the same values that you would provide to the docker login command. For instance:
runs-on: docker
container:
image: alpine:3.20
credentials:
username: 'root'
password: 'admin1234'
NOTE: ignored if
jobs.<job_id>.runs-onis an LXC container.
jobs.<job_id>.container.volumes
Set the volumes for the container to use, as if provided with the --volume argument of the docker run command.
NOTE: the
--volumeoption is restricted to a list of volumes configured in the runner executing the task. See the Forgejo Runner installation guide for more information.
NOTE: ignored if
jobs.<job_id>.runs-onis an LXC container.
jobs.<job_id>.container.options
A string of the following additional options, as documented docker run.
--volume--tmpfs--hostname(except for Forgejo Runner 6.0.x and 6.1.x)--memory(requires runner 11.2.0 or greater)
NOTE: the
--volumeoption is restricted to a list of volumes configured in the runner executing the task. See the Forgejo Actions administrator guide for more information.
NOTE: the value of
--memorycannot be higher than the value set in the runner configuration file in[container].options, if any.
NOTE: ignored if
jobs.<job_id>.runs-onis an LXC container.
jobs.<job_id>.services
The map of services to run before the job starts and terminate when it completes. The key determines the name of the host where the service runs. For instance:
services:
pgsql:
image: postgres:15
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
steps:
- run: PGPASSWORD=postgres psql -h pgsql -U postgres -c '\dt' test
jobs.<job_id>.services.<service_name>.cmd
A list of command and arguments, equivalent to [COMMAND] [ARG...].
jobs.<job_id>.services.<service_name>.credentials
jobs.<job_id>.services.<service_name>.credentials.username
The username to authenticate with the registry where the image is located.
jobs.<job_id>.services.<service_name>.credentials.password
The password or access token to authenticate with the registry where the image is located.
jobs.<job_id>.services.<service_name>.env
Key/value pairs injected in the environment when running the container, equivalent to --env.
jobs.<job_id>.services.<service_name>.image
The location of the container image to run.
jobs.<job_id>.services.<service_name>.options
A string of the following additional options, as documented docker run.
--volume--tmpfs--hostname--memory(requires runner 11.2.0 or greater)--health-cmd--health-interval--health-retries--health-timeout--health-start-period--no-healthcheck
NOTE: the
--volumeoption is restricted to a list of volumes configured in the runner executing the task. See the Forgejo Runner installation guide for more information.
NOTE: the value of
--memorycannot be higher than the value set in the runner configuration file in[container].options, if any.
jobs.<job_id>.services.<service_name>.volumes
Set the volumes for the container to use, as if provided with the --volume argument of the docker run command.
NOTE: the option is restricted to a list of volumes configured in the runner executing the task. See the Forgejo Runner installation guide for more information.
jobs.<job_id>.steps
An array of steps executed sequentially on the host specified by runs-on.
jobs.<job_id>.steps.if
The steps are run if the expression evaluates to true.
For instance:
jobs:
my-job:
steps:
- name: some-step
# This step runs when the event that triggerend the workflow was the opening of a pull request
if: ${{ forgejo.event_name == 'pull_request' && forgejo.event.action == 'opened' }}
- name: another-step
# This step runs when the event that triggered the workflow was the closing of a pull request
if: ${{ forgejo.event_name == 'pull_request' && forgejo.event.action == 'closed' }}
jobs.<job_id>.defaults
Set the defaults for this job. These override the global defaults of the workflow.
jobs.<job_id>.defaults.run.working-directory
Set the default working directory to use for each step.
jobs:
test:
runs-on: docker
defaults:
run:
working-directory: ./app/
steps:
- run: echo SUCCESS
jobs.<job_id>.defaults.run.shell
Set the default shell to use for each step.
jobs:
test:
runs-on: docker
defaults:
run:
shell: sh
steps:
- run: echo SUCCESS
See jobs.<job_id>.steps[*].shell for more information on the shell values and their semantics.
jobs.<job_id>.steps[*].run
A shell script to run in the environment specified with
jobs.<job_id>.runs-on. It runs as root using the default shell unless
specified otherwise with jobs.<job_id>.steps[*].shell. For instance:
jobs:
test:
runs-on: docker
container:
image: alpine:latest
steps:
- run: |
grep Alpine /etc/os-release
echo SUCCESS
jobs.<job_id>.steps[*].working-directory
The working directory from which the script specified with jobs.<job_id>.step[*].run will run. For instance:
- run: test $(pwd) = /tmp
working-directory: /tmp
jobs.<job_id>.steps[*].shell
The interpreter used to run the script specified with jobs.<job_id>.step[*].run. If the interpreter is not specified, it defaults to bash or sh if bash is not available.
NOTE: The fallback to
shifbashis not available requires a version of Forgejo Runner >= v8.0.0.
The value is a command line where the literal string {0} is replaced with the path to a (temporary) file, containing the content of jobs.<job_id>.steps[*].run. For example dash -e {0} would become dash -e /tmp/xxx.
jobs:
test:
runs-on: docker
container:
image: debian:bookworm
steps:
- shell: dash -e {0}
run: echo using dash here
Some commonly used interpreters have abbreviated aliases that are expanded into command lines as follows:
bash=>bash --noprofile --norc -e -o pipefail {0}sh=>sh -e {0}node=>node {0}python=>python {0}
jobs.<job_id>.steps[*].id
A unique identifier for the step. You will only need this if you want to refer to inputs or outputs from this step, for example using the steps.<step_id>.outputs context.
jobs.<job_id>.steps[*].if
The step is run if the expression evaluates to true.
Check out the workflows in example-if and example-if-fail.
jobs.<job_id>.steps[*].uses
Specifies the repository from which the Action will be cloned or a directory where it can be found.
-
Remote actions A relative
Actionsuch asuses: actions/checkout@v6will clone the repository at the URL composed by prepending theDEFAULT_ACTIONS_URL(https://data.forgejo.orgby default, see note below). It is the equivalent of providing the fully qualified URLuses: https://data.forgejo.org/actions/checkout@v6. In other words the following:on: [push] jobs: test: runs-on: docker steps: - uses: actions/checkout@v6is the same as:
on: [push] jobs: test: runs-on: docker steps: - uses: https://data.forgejo.org/actions/checkout@v6NOTE: When possible it is strongly recommended to choose fully qualified URLs to avoid ambiguities. During installation, the instance administrator may change the
DEFAULT_ACTIONS_URL. This can cause your workflow to break if the actions you want to use are not available on the specified instance.The string after the
@specifies the version of the action. There are various ways of specifying a version:steps: # Using the commit SHA of a specific commit. - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # Using the full name of a tag. - uses: actions/checkout@v6.0.2 # Using part of the name of a tag to match the newest version of that tag. - uses: actions/checkout@v6 # Using the name of a branch - uses: actions/checkout@mainBecause it is possible to compromise tags, it is recommended to use commit SHAs for security reasons.
-
Remote container actions An OCI container can be used as an action. You may specify a container action with
uses: docker://[host]/[container]:[tag].For example, the YAML
uses: docker://code.forgejo.org/actions/some-action:latestwould get the
latestversion of thesome-actioncontainer by useractionsfromcode.forgejo.org. -
Local actions An action that begins with a
./will be loaded from a directory instead of being cloned from a repository. The structure of the directory is otherwise the same as if it was located in a remote repository.NOTE: the most common mistake when using an action included in the repository under test is to forget to checkout the repository with
uses: actions/checkout@v6.
jobs.<job_id>.steps[*].with
A dictionary mapping the inputs of the action to concrete values. The action.yml defines and documents the inputs.
on: [push]
jobs:
ls:
runs-on: docker
steps:
- uses: ./.forgejo/local-action
with:
input-two: 'two'
jobs.<job_id>.steps[*].with.args
For actions that are implemented with a Dockerfile, the args key is used to override the CMD passed to the ENTRYPOINT of the container. If not specified the CMD from the Dockerfile will be used.
jobs.<job_id>.steps[*].with.entrypoint
For actions that are implemented with a Dockerfile, the entrypoint key is used to overrides the ENTRYPOINT in the Dockerfile. It must be the path to the executable file to run.
jobs.<job_id>.steps[*].env
Set environment variables like it's top-level variant env, but only for the current step.
jobs.<job_id>.steps[*].continue-on-error
It set to true on a step, the step won't cause the job to fail if it fails. Following steps will still run, and if they succeed the job will be marked successful.
steps:
- run: echo "failing step" && false
continue-on-error: true
- run: echo "this step runs and job is successful"
When a step with continue-on-error fails, its steps.<step_id>.outcome will be failure, but its steps.<step_id>.conclusion will be success.
jobs.<job_id>.steps[*].timeout-minutes
Set the number of minutes this step can be performed before it is canceled.
steps:
- run: sleep 301
timeout-minutes: 5
- run: echo "this will not get run"
Contexts
A context is an object that contains information relevant to a workflow run. For instance the secrets context contains the secrets defined in the repository. Each of the following context is defined as a top-level variable when evaluating expressions. For instance ${{ secrets.MYSECRET }} will be replaced by the value of MYSECRET.
| Context name | Description |
|---|---|
| secrets | secrets available in the repository |
| vars | variables available in the repository |
| env | environment variables defined in the workflow |
| forgejo or forge | information about the workflow being run |
| matrix | information about the current row of the matrix |
| steps | information about the steps that have been run |
| needs | information about the jobs that have been run |
| inputs | the input parameters given to an action |
| runner | information about the runner and operating system |
To help with reusing actions and workflows originally developed for GitHub Actions, the github context is defined to be the same as the forgejo context.
Availability
Some contexts like secrets can only be accessed in certain places. Likewise, functions can be restricted to certain workflow keys. The following table lists which contexts and functions are available where.
| Workflow key | Accessible contexts | Accessible functions |
|---|---|---|
run-name |
forgejo, inputs, vars |
- |
concurrency |
forgejo, inputs, vars |
- |
env |
env, forgejo, inputs, secrets, vars |
- |
jobs.<job-id>.concurrency |
forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.container |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.container.credentials |
env, forgejo, inputs, secrets, vars |
- |
jobs.<job-id>.container.env.<env-id> |
env, forgejo, inputs, job, matrix, needs, runner, secrets, strategy, vars |
- |
jobs.<job-id>.container.image |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.container.options |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.container.volumes.[*] |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.continue-on-error |
forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.defaults.run |
env, forgejo, inputs , matrix, needs, strategy, vars |
- |
jobs.<job-id>.env |
forgejo, inputs, matrix, needs, secrets, strategy, vars |
- |
jobs.<job-id>.environment |
forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.environment.url |
env, forgejo, inputs, job, matrix, needs, runner, steps, strategy, vars |
- |
jobs.<job-id>.if |
env, forgejo, inputs, needs, secrets, vars |
always, cancelled, failure, success |
jobs.<job-id>.name |
forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.outputs.<output-id> |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
- |
jobs.<job-id>.runs-on |
forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.secrets.<secret_id> |
forgejo, inputs, matrix, needs, secrets, strategy, vars |
- |
jobs.<job-id>.services |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.services.<service-id> |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.services.<service-id>.cmd.[*] |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.services.<service-id>.credentials |
env, forgejo, inputs, secrets, vars |
- |
jobs.<job-id>.services.<service-id>.env.<env-id> |
env, forgejo, inputs, job, matrix, needs, runner, secrets, strategy, vars |
- |
jobs.<job-id>.services.<service-id>.image |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.services.<service-id>.options |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.services.<service-id>.ports.[*] |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.services.<service-id>.volumes.[*] |
env, forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.steps[*].continue-on-error |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
hashFiles |
jobs.<job-id>.steps[*].env |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
hashFiles |
jobs.<job-id>.steps[*].if |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
always, cancelled, failure, success, hashFiles |
jobs.<job-id>.steps[*].name |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
hashFiles |
jobs.<job-id>.steps[*].run |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
hashFiles |
jobs.<job-id>.steps[*].timeout-minutes |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
hashFiles |
jobs.<job-id>.steps[*].uses |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
hashFiles |
jobs.<job-id>.steps[*].with |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
hashFiles |
jobs.<job-id>.steps[*].working-directory |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
hashFiles |
jobs.<job-id>.strategy |
forgejo, inputs, needs, vars |
- |
jobs.<job-id>.strategy.fail-fast |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
hashFiles |
jobs.<job-id>.strategy.max-parallel |
env, forgejo, inputs, job, matrix, needs, runner, secrets, steps, strategy, vars |
hashFiles |
jobs.<job-id>.timeout-minutes |
forgejo, inputs, matrix, needs, strategy, vars |
- |
jobs.<job-id>.with.<with-id> |
forgejo, inputs, matrix, needs, strategy, vars |
- |
on.workflow_call.inputs.<input-id>.default |
forgejo, vars [^1] |
- |
on.workflow_call.outputs.<output-id>.value |
forgejo, inputs, jobs, vars |
- |
When you are manipulating a particular context like env, you cannot reference context variables defined within the same workflow key. Therefore, the following example will not work:
on:
push:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Invalid context reference
run: |
echo "$IS_PUSH"
env:
EVENT: '${{ forgejo.event_name}}'
IS_PUSH: "${{ env.EVENT == 'push' }}" # false because env.EVENT is undefined
[^1]: While GitHub Actions permits accessing inputs in on.workflow_call.inputs.<input-id>.default, it is always empty. Therefore, Forgejo Runner does not make it available.
secrets
A map of the repository secrets. It is empty if the event that triggered the workflow is pull_request and the head is from a fork of the repository.
Example: ${{ secrets.MYSECRETS }}
vars
A map of the repository variables.
Example: ${{ vars.MYVARIABLE }}
env
A map of the environment variables defined in the workflow.
Example: ${{ env.SOMETHING }}
In addition, the variables listed in the following table are injected into the environment of the shell executing a particular step. However, they are not included in env and can therefore not be referenced when defining a workflow.
| Name | Description |
|---|---|
| CI | Always set to true. |
| FORGEJO_ACTION | The numerical id of the current step. |
| FORGEJO_ACTION_PATH | When evaluated while running a composite action (i.e. using: "composite", the path where an action files are located. |
| FORGEJO_ACTION_REPOSITORY | For a step executing an action, this is the owner and repository name of the action (e.g. actions/checkout). |
| FORGEJO_ACTIONS | Always set to true when the Forgejo Runner is running the workflow. |
| FORGEJO_ACTOR | The name of the user that triggered the workflow. |
| FORGEJO_API_URL | The API endpoint of the Forgejo instance running the workflow (e.g. https://code.forgejo.org/api/v1). |
| FORGEJO_BASE_REF | The name of the base branch of the pull request (e.g. main). Only defined when a workflow runs because of a pull_request or pull_request_target event. |
| FORGEJO_HEAD_REF | The name of the head branch of the pull request (e.g. my-feature). Only defined when a workflow runs because of a pull_request or pull_request_target event. |
| FORGEJO_ENV | The path on the runner to the file that sets variables from workflow commands. This file is unique to the current step and changes for each step in a job. |
| FORGEJO_EVENT_NAME | The name of the event that triggered the workflow (e.g. push). |
| FORGEJO_EVENT_PATH | The path to the file on the Forgejo Runner that contains the full event webhook payload. |
| FORGEJO_HEAD_REF | The name of the head branch of the pull request (e.g. my-feature). Only defined when a workflow runs because of a pull_request or pull_request_target event. |
| FORGEJO_JOB | The job_id of the current job. |
| FORGEJO_OUTPUT | The path on the runner to the file that sets the current step's outputs. This file is unique to the current step. |
| FORGEJO_PATH | The path on the runner to the file that sets the PATH environment variable. This file is unique to the current step. |
| FORGEJO_REF | The fully formed git reference (i.e. starting with refs/) associated with the event that triggered the workflow, if any (e.g. refs/heads/main). |
| FORGEJO_REF_NAME | The short git reference name of the branch or tag associated with the workflow, if any (e.g. main). |
| FORGEJO_REPOSITORY | The owner and repository name (e.g. forgejo/docs). |
| FORGEJO_REPOSITORY_OWNER | The repository owner's name (e.g. forgejo) |
| FORGEJO_RUN_ATTEMPT | Attempt number for this run, beginning at 1 and incrementing when the job is re-run. |
| FORGEJO_RUN_NUMBER | A unique id for the current workflow run in the repository of the workflow. |
| FORGEJO_RUN_ID | A unique id for the current workflow run in the Forgejo instance. |
| FORGEJO_SERVER_URL | The URL of the Forgejo instance running the workflow (e.g. https://code.forgejo.org) |
| FORGEJO_SHA | The commit SHA that triggered the workflow. The value of this commit SHA depends on the event that triggered the workflow. |
| FORGEJO_TOKEN | The unique authentication token automatically created for duration of the workflow. |
| FORGEJO_WORKSPACE | The default working directory on the runner for steps, and the default location of the repository when using the checkout action. |
| FORGEJO_WORKFLOW_REF | Ref path to the workflow, for example, owner/example-respository/.forgejo/workflows/test-workflow.yaml@refs/heads/main |
To help with reusing actions and workflows originally developed for GitHub Actions, each FORGEJO_* variable is also available as a GITHUB_* variable with the same suffix (e.g. GITHUB_REPOSITORY is the same as FORGEJO_REPOSITORY).
NOTE: the
FORGEJO_*variables require Forgejo Runner v7.0.0 or above. With earlier versions only theGITHUB_*variables were defined.
github
To help with reusing actions and workflows originally developed for GitHub Actions, the github context is defined to be the same as the forgejo context.
forgejo
The following are identical to the matching environment variable
(e.g. forgejo.base_ref is the same as env.FORGEJO_BASE_REF):
NOTE: the
forgecontext is the same as theforgejocontext.
| Name | Description |
|---|---|
| action | The numerical id of the current step. |
| action_path | When evaluated while running a composite action (i.e. using: "composite", the path where an action files are located. |
| action_repository | For a step executing an action, this is the owner and repository name of the action (e.g. actions/checkout). |
| actor | The name of the user that triggered the workflow. |
| api_url | The API endpoint of the Forgejo instance running the workflow (e.g. https://code.forgejo.org/api/v1). |
| base_ref | The name of the base branch of the pull request (e.g. main). Only defined when a workflow runs because of a pull_request or pull_request_target event. |
| event | JSON object containing event details of how the workflow was triggered; details vary depending on the event. |
| event_name | The name of the event that triggered the workflow (e.g. push). |
| event_path | The path to the file on the Forgejo Runner that contains the full event webhook payload. |
| head_ref | The name of the head branch of the pull request (e.g. my-feature). Only defined when a workflow runs because of a pull_request or pull_request_target event. |
| job | The job_id of the current job. |
| output | The path on the runner to the file that sets the current step's outputs. This file is unique to the current step. |
| path | The path on the runner to the file that sets the PATH environment variable. This file is unique to the current step. |
| ref | The fully formed git reference (i.e. starting with refs/) associated with the event that triggered the workflow, if any (e.g. refs/heads/main). |
| ref_name | The short git reference name of the branch or tag associated with the workflow, if any (e.g. main). |
| repository | The owner and repository name (e.g. forgejo/docs). |
| repository_owner | The repository owner's name (e.g. forgejo) |
| run_id | A unique id for the current workflow run in the Forgejo instance. |
| run_number | A unique id for the current workflow run in the repository of the workflow. |
| run_attempt | Attempt number for this run, beginning at 1 and incrementing when the job is re-run. |
| server_url | The URL of the Forgejo instance running the workflow (e.g. https://code.forgejo.org) |
| sha | The commit SHA that triggered the workflow. The value of this commit SHA depends on the event that triggered the workflow. |
| token | The unique authentication token automatically created for duration of the workflow. |
| workspace | The default working directory on the runner for steps, and the default location of the repository when using the checkout action. |
| workflow_ref | Ref path to the workflow, for example, owner/example-respository/.forgejo/workflows/test-workflow.yaml@refs/heads/main |
Example: ${{ forgejo.SHA }}
In addition, the forgejo context contains the forgejo.event object
which is set to the payload associated with the event
(forgejo.event_name) that triggered the workflow.
To find out what this payload is made of, insert a job at the beginning of the workflow to display the entire context in the web UI. For instance:
debug:
runs-on: docker
steps:
- name: event
run: |
cat <<'EOF'
${{ toJSON(forgejo) }}
EOF
will show something similar to the following when a label is updated in a pull request:
{
"event": {
"action": "label_updated",
"commit_id": "",
"label": {
"color": "795548",
"description": "Issue or pull request related to testing",
"exclusive": false,
"id": 23,
"is_archived": false,
"name": "Kind/Testing",
"url": "https://code.forgejo.org/api/v1/repos/forgejo/runner/labels/23"
},
"number": 948,
"pull_request": {
...
"workflow": "cascade",
"run_attempt": "1",
"run_id": "117195",
"run_number": "9384",
"actor": "earl-warren",
"repository": "forgejo/runner",
"event_name": "pull_request_target",
"sha": "09adcc47d250567412c2fc2083ed7dcf61a7b953",
"ref": "refs/heads/main",
"ref_name": "main",
"ref_type": "branch",
"head_ref": "wip-cascade",
"base_ref": "main",
"token": "***",
"workspace": "/workspace/forgejo/runner",
...
NOTE: although the automatic token is masked (see
***in the example above), it is not advisable to display this on a publicly readable instance.
matrix
An object that exists in the context of a job where jobs.<job_id>.strategy.matrix is defined . For instance:
jobs:
actions:
runs-on: self-hosted
strategy:
matrix:
info:
- version: v1.22
branch: next
Example: ${{ matrix.info.version }}
steps
The steps context contains information about the steps in the current job that have
an id specified (jobs.<job_id>.step[*].id) and have already run.
The steps.<step_id>.outputs object is a key/value map of the output of the
corresponding step, defined by writing to $FORGEJO_OUTPUT. For instance:
- id: mystep
run: echo 'check=good' >> $FORGEJO_OUTPUT
- run: test ${{ steps.mystep.outputs.check }} = good
Values that contain newlines can be set as follows:
- id: mystep
run: |
cat >> $FORGEJO_OUTPUT <<EOF
thekey<<STRING
value line 1
value line 2
STRING
EOF
needs
The needs context contains information about the jobs in the current workflow that have
already run before the current job (i.e. that need it in the sense of jobs.<job_id>.needs).
inputs
The inputs context maps keys (strings) to values (also strings) when running an action. They are provided as jobs.<job_id>.step[*].with
in a step where jobs.<job_id>.step[*].uses specifies an action.
For example, an action defined with the following action.yaml:
inputs:
message-input:
description: 'The message to print'
runs:
using: 'composite'
steps:
- run: echo ${{ inputs.message-input }}
would have an input message-input which could be used by a workflow.yaml like this:
steps:
- uses: my-action
with:
message-input: 'message to print'
runner
The runner context contains information about the runner that is executing the current job.
Example: ${{ runner.os }}
The context variables are also available as environment variables in each step. However, they are not included in env (see env context).
| Name | Environment Variable | Description |
|---|---|---|
runner.os |
RUNNER_OS |
The operating system of the runner; either Linux, Windows, macOS, or undefined. |
runner.arch |
RUNNER_ARCH |
The CPU architecture of the runner; either X86, X64, ARM, ARM64, or undefined. |
runner.temp |
RUNNER_TEMP |
This is a temporary directory provided by the runner. |
runner.tool_cache |
RUNNER_TOOL_CACHE |
This is a directory where tools can be installed. Defaults to /opt/hostedtoolcache. Despite the name, this directory is not cached across builds anymore but the variable is kept for compatibility reasons. If you want to enable the toolcache for actions that supports it, mount a volume to /opt/hostedtoolcache. |
For compatibility with GitHub Actions, runner.os and runner.arch only contain values defined by GitHub Actions. On platforms not supported by GitHub Actions, they contain undefined. If Microsoft ever expands GitHub Actions' platform support, Forgejo Runner will replace undefined with the value used by GitHub Actions.
Environment variables
Forgejo defines some environment variables that are available on each step. Please see the env context and the runner context for a list of the environment variables.
Forgejo Actions | Troubleshooting
When a workflow or an action fails to run as expected, the following steps may help to figure out where to look for errors.
Schema validation
As of Forgejo Runner v8.0.0 and above both workflows and actions are validated against a schema and will fail to run if they do not pass. Errors will be displayed:
- When browsing a workflow from the web interface (available in Forgejo v13.0.0 and above).
- In the list of actions, when hovering on the warning sign next to a workflow that fails schema validation (available in Forgejo v13.0.0 and above).
- In the logs of a workflow run, in the
Set up jobstep for an action used by the workflow (available in all Forgejo versions). - In the logs of a workflow run, in the
Complete jobstep for an action used by an action (two levels of indirection) used by a workflow (available in all Forgejo versions).
It is also possible to verify that the workflows and/or actions found in a repository successfully pass schema validation using the Forgejo Runner CLI (e.g. forgejo-runner validate --repository https://example.com/my/repo) (available in the Forgejo Runner v9.0.0 and above).
A pre-commit hook is also provided to help automate this, see Advanced features for more details.
Forgejo Runner logs
If the logs of the action displayed in the web UI are incomplete, it is worth looking into the logs of the Forgejo Runner itself.
Common Workflow Issues
Keep in mind the following caveats in case you have problems with your workflow:
Non-Standard Git Credentials in the workflow
Usually, actions/checkout creates git credentials for your workflow "on the fly" and inserts them into the git config (Example: http.https://codeberg.org/.extraheader=AUTHORIZATION: basic ***).
For Standard use cases, this is what you'll probably want. However, if you need to interact with different repositories in your workflow (e.g. your private repositories, usually with renovate or similar tools), you may want to use different credentials like an API key with specific scope.
It might be possible that your custom git credentials are set correctly, but the "auto-generated" key from the git config is still preferred, leading to failures when interacting with other repositories.
To fix this, set persist-credentials to false in your checkout action's configuration:
- uses: https://code.forgejo.org/actions/checkout@v6
with:
persist-credentials: false