GitHub, Gitea & Forgejo¶
Status: GitHub live-validated on hosted runners; Gitea and Forgejo render-supported, live runtime (OIDC, runner, DinD) unproven.
These three forges share one golden-tested Actions render backend, so setup is identical apart from the workflow path and the runner. StageFreight renders a native workflow and drives releases/PRs/commits over each forge's API.
Rendering¶
stagefreight ci render <forge> --write writes:
| Forge | Workflow file |
|---|---|
github |
.github/workflows/stagefreight.yml |
gitea |
.gitea/workflows/stagefreight.yml |
forgejo |
.forgejo/workflows/stagefreight.yml |
The pipeline model — render, tags, the five-job lifecycle — is in Getting Started.
Runners¶
- GitHub-hosted runners work as-is — no setup, and the only live-validated path.
- Self-hosted Actions runners (GitHub, Gitea, Forgejo) need a Docker daemon — and BuildKit for image builds — reachable from the job; a packaged deployment isn't published yet. The GitLab runner stacks are a reference for the required companions.
Build engine¶
The rendered workflow injects no dind service and no DOCKER_HOST: build-engine
provisioning is the runner's job. At runtime StageFreight detects the engine in order
BUILDKIT_HOST → DOCKER_HOST → local Docker socket, so a hosted runner uses its
auto-mounted socket and a self-hosted runner uses whatever buildkitd/dind the operator
exposes at the runner level. A workflow-level dind would shadow that operator engine, cannot
share TLS certs with a hosted job, leaks DOCKER_HOST into the runner's own host-side Docker
calls, and is not resolvable by name from a container job.
This is safe on ephemeral builders because the image never lives only in the daemon: the
build always exports an OCI layout under .stagefreight/, which travels perform → publish as
a job artifact. The cost on hosted runners is moving the full layout between jobs.
Generated workflow¶
Details a hand-edit or a renderer change must preserve:
- Phase handoff.
upload-artifactsetsinclude-hidden-files: true(v4.4.0+ drops dot-paths such as.stagefreight/by default) and stores files relative to their common ancestor, so the artifact carries no.stagefreight/prefix.download-artifacttherefore extracts withpath: .stagefreight; extracting to.flattens the handoff into the workspace root and the next phase cannot find the pipeline state. - Workspace.
SF_CI_WORKSPACEis$PWD, not${{ github.workspace }}— in a container job that expression is the host path, which does not exist inside the container. - Cross-run cache. Each phase job restores and saves
/stagefreight/cachewithactions/cache, keyedstagefreight-cache-<os>-<phase>-<hashFiles(lockfiles)>with a per-phase prefix restore key. The key is per phase because a GitHub cache key is write-once; a shared key races jobs.hashFilesignores absent lockfiles, so one glob list covers every language. BuildKit's image-layer cache lives in the builder and is not covered.
Credentials¶
Each forge's client uses its own access token; the repo auto-detects from GITHUB_REPOSITORY
(Actions) or CI_REPO (Woodpecker).
- GitHub — the built-in
GITHUB_TOKENworks by default; setGH_TOKENto a PAT for broader scope (e.g. pushing to another repo). The workflow requestscontents: writeon jobs that commit back. - Package registries — each registry's credential prefix renders as
<PREFIX>_TOKEN: ${{ secrets.<PREFIX>_TOKEN || <forge default> }}(likewise_USER), e.g.secrets.GHCR_TOKEN || secrets.GITHUB_TOKEN. The built-in token works with no setup; a repo secret of that name overrides it. A fork'sGITHUB_TOKENis often read-only by organization policy, and a403on package push means authenticated but unauthorized — add the<PREFIX>_TOKENsecret rather than changing config. - Multi-forge configs — when one
.stagefreight.ymlruns on several forges (e.g. a GitLab origin and a GitHub mirror), scope targets whose registry is only reachable or credentialed on some forges withwhen: { forges: [gitlab] }instead of deleting them. - Gitea —
GITEA_TOKEN: a Gitea access token with repository read/write scope; drives commits, PRs, releases, and tags over the/api/v1REST API. - Forgejo —
FORGEJO_TOKEN: a Forgejo access token with the same repository read/write scope (the client shares Gitea's/api/v1backend).