Release management

Release numbering

The Forgejo release numbers are composed of the Gitea release number followed by a dash and a serial number. For instance:

  • Gitea v1.20.0 will be Forgejo v1.20.0-0, v1.20.0-1, etc

The Gitea release candidates are suffixed with -rcN which is handled as a special case for packaging: although X.Y.Z is lexicographically lower than X.Y.Z-rc1 is is considered greater. The Forgejo serial number must therefore be inserted before the -rcN suffix to preserve the expected version ordering.

  • Gitea v1.20.0-rc0 will be Forgejo v1.20.0-0-rc0, v1.20.0-1-rc0
  • Gitea v1.20.0-rc1 will be Forgejo v1.20.0-2-rc1, v1.20.0-3-rc1, v1.20.0-4-rc1
  • Gitea v1.20.0 will be Forgejo v1.20.0-5, v1.20.0-6, v1.20.0-7
  • etc.

Because Forgejo depends on Gitea, it must retain the same release numbering scheme to be compatible with libraries and tools that depend on it. For instance, the tea CLI or the Gitea SDK will behave differently depending on the server version they connect to. If Forgejo had a different numbering scheme, it would no longer be compatible with the Gitea ecosystem.

From a Semantic Versioning standpoint, all Forgejo releases are pre-releases because they are suffixed with a dash. They are syntactically correct but do not comply with the Semantic Versioning recommendations. Gitea is not compliant either and Forgejo inherits this problem.

Release process

The TL;DR: to publish a vX.Y.Z-N release is to:

Semantic version

  • Update the FORGEJO_VERSION variable in the Makefile

Create a milestone and a check list

  • Create a Forgejo vX.X.Z-N milestone set to the date of the release
  • Create an issue named [RELEASE] Forgejo vX.Y.Z-N with a description that includes a list of what needs to be done for the release with links to follow the progress
  • Set the milestone of this issue to Forgejo vX.X.Z-N
  • Close the milestone when the release is complete

Cherry pick the latest commits from Gitea

The vX.Y/forgejo branch is populated as part of the rebase on top of Gitea. The release happens in between rebase and it is worth checking if the matching Gitea branch, release/vX.Y contains commits that should be included in the release.

  • cherry-pick -x the commits
  • push the vX.Y/forgejo branch including the commits
  • verify that the tests pass

Release Notes

  • Add an entry in

Forgejo release building and testing

When Forgejo is released, artefacts (packages, binaries, etc.) are first published by the CI/CD pipelines in the organization, to be downloaded and verified to work.

It will trigger a build workflow that:

If the build fails, the logs of the workflow can be found in for debugging. Once the build is successful, it must be copied to

It will trigger a publish workflow that:

To verify the container images, the setup-forgejo integration tests can be used. Push a branch with the location of the release under test to run a collection of test workflows.

Reach out to packagers and users to manually verify the release works as expected.

Forgejo release publication

It will trigger a workflow to:

Forgejo runner publication

The release is built on, which is a mirror of

The release is published on, which is a mirror of It is behind a VPN and its role is to copy and sign release artifacts.

If the publishing the release needs debug, it can be done manually:

It can also be done from the CLI with forgejo-runner exec and providing the secrets from the command line.

Securing the release token and cryptographic keys

For both the Forgejo runner and Forgejo itself, copying and signing the release artifacts (container images and binaries) happen on a Forgejo isntance running behind a VPN to safeguard the token that has write access to the Forgejo repository as well as the cryptographic key used to sign the releases.

Website update

DNS update

  • Update the TXT record that starts with forgejo_versions= to be forgejo_versions=vX.Y.Z-N

Standard toot

The following toot can be re-used to announce a minor release at For more significant releases it is best to consider a dedicated and non-standard toot.

#Forgejo vX.Y.Z-N was just released! This is a minor patch. Check out the release notes and download it at If you experience any issues with this release, please report to

Release signing keys management

A GPG master key with no expiration date is created and shared with members of the Owners team via encrypted email. A subkey with a one year expiration date is created and stored in the secrets repository, to be used by the CI pipeline. The public master key is stored in the secrets repository and published where relevant.

Master key creation

  • gpg —expert —full-generate-key
  • key type: ECC and ECC option with Curve 25519 as curve
  • no expiration
  • id: Forgejo Releases
  • gpg —export-secret-keys —armor EB114F5E6C0DC2BCDD183550A4B61A2DC5923710 and send via encrypted email to Owners
  • gpg —export —armor EB114F5E6C0DC2BCDD183550A4B61A2DC5923710 >
  • commit to the secret repository

Subkey creation and renewal

  • gpg —expert —edit-key EB114F5E6C0DC2BCDD183550A4B61A2DC5923710
  • addkey
  • key type: ECC (signature only)
  • key validity: one year
  • create an issue to schedule the renewal


  • gpg —export —armor F7CBF02094E7665E17ED6C44E381BF3E50D53707 >
  • gpg —export-secret-keys —armor F7CBF02094E7665E17ED6C44E381BF3E50D53707 > 2023-release-team-gpg
  • commit to the secrets repository
  • renewal issue

CI configuration

In the Woodpecker CI configuration the following secrets must be set:

  • releaseteamgpg is the secret GPG key used to sign the releases
  • releaseteamuser is the user name to authenticate with the Forgejo API and publish the releases
  • releaseteamtoken is the token to authenticate releaseteamuser with the Forgejo API and publish the releases
  • domain is

Users, organizations and repositories

Shared user: release-team

The release-team user publishes and signs all releases. The associated email is

The public GPG key used to sign the releases is EB114F5E6C0DC2BCDD183550A4B61A2DC5923710 Forgejo Releases <>

Shared user: forgejo-ci

The forgejo-ci user is dedicated to and provides it with OAuth2 credentials it uses to run.

Shared user: forgejo-experimental-ci

The forgejo-experimental-ci user is dedicated to provide the application tokens used by Woodpecker CI repositories to build releases and publish them to It does not (and must not) have permission to publish releases at

Integration and experimental organization

The organization is dedicated to integration testing. Its purpose is to ensure all artefacts can effectively be published and retrieved by the CI/CD pipelines.

The organization is dedicated to publishing experimental Forgejo releases. They are copied from the organization.

The forgejo-experimental-ci user as well as all Forgejo contributors working on the CI/CD pipeline should be owners of both organizations.

The repository is coupled with a Woodpecker CI repository configured with the credentials provided by the user. It runs the pipelines found in releases/woodpecker-build/*.yml which builds and publishes an unsigned release in

Experimental and release repositories

The private repository is coupled with a Woodpecker CI repository configured with the credentials provided by the user. It runs the pipelines found in releases/woodpecker-publish/*.yml which signs and copies a release from into

The private repository is coupled with a Woodpecker CI repository configured with the credentials provided by the user. It runs the pipelines found in releases/woodpecker-publish/*.yml which signs and copies a release from into