Skip to content

Run it in Gitea or Forgejo Actions

Goal: every push to your default branch keeps a release pull request up to date, merging it tags the commit that landed, and the tag creates the release.

Gitea Actions and Forgejo Actions run GitHub Actions' workflow syntax, so this is the GitHub Actions guide with four differences: where the workflows live, the name of the token variable, a manifest line for a self-hosted forge, and a runner you register yourself.

The workflows below are the ones TestReleasingInTheForgesOwnCI in test/integration commits and runs, against Gitea 1.24.7 with act_runner 0.6.1 and Forgejo 11.0.16 with forgejo-runner 13.2.0, installing colophon v0.19.2. The test registers the runner, lets the workflows propose, tag and release, and only merges the pull request itself, as a person would. Forge support has the rest of what has been proven where.

1. Switch Actions on and register a runner

Actions must be enabled on the instance and on the repository (Settings, then Units, on the repository). A runner does the work: act_runner for Gitea, forgejo-runner for Forgejo. Register it with a token from the repository's Actions settings, or from the forge's admin command:

gitea actions generate-runner-token     # on Forgejo: forgejo actions generate-runner-token

The workflows use runs-on: ubuntu-latest, and the actions they use need Node, so give the runner a label that maps it to an image with Node in it, such as ubuntu-latest:docker://node:20-bookworm.

2. Provide a token

Create an access token for an account that can push to the repository, with these scopes:

  • write:repository, to push the release branch and the tag, and to create the release;
  • write:issue, to open the pull request and attach its labels;
  • read:organization, because listing labels also reads the owner's organisation labels, and without it the release pull request loses all of its labels.

Store it as a repository secret named COLOPHON_TOKEN. The workflows hand it to colophon as GITEA_TOKEN, the variable colophon reads on both forges. The tag the publish job pushes with it is what starts the tag workflow in the runs above. If tags are protected, the token's owner must be allowed to create them.

3. Name the forge, if it is self-hosted

colophon knows codeberg.org by its host. Any other Gitea or Forgejo instance needs one line in .colophon.yaml:

forge: gitea

gitea covers Forgejo too: they share the API colophon uses.

4. Add the workflows

Gitea reads .gitea/workflows/, Forgejo .forgejo/workflows/.

# release.yml
name: release

on:
  push:
    branches: [main]

concurrency:
  group: colophon-${{ github.ref }}
  cancel-in-progress: false

env:
  COLOPHON_VERSION: v0.19.2

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.COLOPHON_TOKEN }}
      - uses: actions/setup-go@v5
        with:
          go-version: stable
      - run: go install gitlab.com/phpboyscout/colophon/cmd/colophon@${COLOPHON_VERSION}
      - run: colophon --ci publish --tag-only --target main --author-name colophon --author-email [email protected]
        env:
          GITEA_TOKEN: ${{ secrets.COLOPHON_TOKEN }}

  propose:
    needs: publish
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.COLOPHON_TOKEN }}
      - uses: actions/setup-go@v5
        with:
          go-version: stable
      - run: go install gitlab.com/phpboyscout/colophon/cmd/colophon@${COLOPHON_VERSION}
      - run: colophon --ci propose --target main --author-name colophon --author-email [email protected]
        env:
          GITEA_TOKEN: ${{ secrets.COLOPHON_TOKEN }}
# tag.yml
name: tag

on:
  push:
    tags: ['v*']

env:
  COLOPHON_VERSION: v0.19.2

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.COLOPHON_TOKEN }}
      - uses: actions/setup-go@v5
        with:
          go-version: stable
      - run: go install gitlab.com/phpboyscout/colophon/cmd/colophon@${COLOPHON_VERSION}
      # build and upload your assets here, then pass --assets and --asset-base
      - run: colophon --ci release --tag "${GITHUB_REF_NAME}" --target main
        env:
          GITEA_TOKEN: ${{ secrets.COLOPHON_TOKEN }}

The reasons for each part (two jobs with propose after publish, the concurrency group, the pinned version, --ci) are the same as on GitHub, and the GitHub Actions guide gives them. --tag-only with a tag workflow is the shape for a release that carries assets; a release without any can drop both and let publish create it.

actions/checkout and actions/setup-go resolved through each forge's default action source in the runs above. An instance that changes [actions] DEFAULT_ACTIONS_URL needs both reachable from there.

5. Merge the release pull request

Merge it however the repository merges. colophon resolves the commit that landed against the target branch, rather than trusting the pull request's head.

If it fails

symptom cause
the workflows never start Actions is off on the instance or the repository, or no runner carries the ubuntu-latest label
a job waits and never runs the runner's label maps to an image it cannot pull, or the runner is offline
this checkout is shallow (depth-limited clone) fetch-depth: 0 is missing from a checkout
the release pull request has no labels the token lacks read:organization
UNIQUE constraint failed: release.repo_id, release.tag_name when a release is created a race in Gitea between recording a just-pushed tag and creating its release, seen from publish without --tag-only (forge-gitea#8); re-run the job