Cross-Forge CI
GloriousFlywheel supports GitHub Actions as the primary runner-control surface and keeps GitLab CI as a compatibility path on the same Kubernetes substrate. This guide shows comparable job shapes side by side, but they are not equal maturity adapters.
Quick Comparison
| Feature | GitLab CI | GitHub Actions |
|---|---|---|
| Config file | .gitlab-ci.yml |
.github/workflows/*.yml |
| Runner selection | tags: [docker] |
runs-on: tinyland-docker |
| Scaling | Manager HPA compatibility | ARC scale sets |
| Scale-to-zero | Not currently proved | Primary path |
| Cache access | Runner env parity | Runner env parity |
| Reusable configs | CI/CD Components | Composite Actions |
| CLI tool | glab |
gh |
Equivalent Jobs
Simple Build
GitLab CI:
build:
tags: [docker]
script:
- make build
GitHub Actions:
jobs:
build:
runs-on: tinyland-docker
steps:
- uses: actions/checkout@v6
- run: make build
Nix Build with Cache
GitLab CI:
build:
tags: [nix]
script:
- test -n "$NIX_CONFIG"
- nix build .#default
GitHub Actions:
jobs:
build:
runs-on: tinyland-nix
steps:
- uses: actions/checkout@v6
- uses: tinyland-inc/GloriousFlywheel/.github/actions/nix-job@main
env:
ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN || '' }}
with:
attic-public-key: ${{ vars.ATTIC_PUBLIC_KEY || '' }}
command: nix build .#default
push-cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && secrets.ATTIC_TOKEN != '' && 'true' || 'false' }}
The GitHub pattern is intentionally bootstrap-first: nix-job installs or
verifies the Nix toolchain before applying GloriousFlywheel cache/runtime
hints. Attic and Bazel remain acceleration layers, not publication surfaces.
Trusted cache writes are a separate policy decision; public-read attachment
only requires the Attic public key and substituter trust.
The example keeps pull requests read-only and only publishes Nix results on
trusted default-branch pushes when ATTIC_TOKEN is present. Broad proof
workflow writes are still separately guarded; do not treat this as RBE,
CAS/action-cache, or backend-authority evidence.
Docker Image Build
GitLab CI:
build-image:
tags: [dind]
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
GitHub Actions:
jobs:
build-image:
runs-on: tinyland-dind
steps:
- uses: actions/checkout@v6
- run: |
docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
docker push ghcr.io/${{ github.repository }}:${{ github.sha }}
CLI Commands
Pipeline / Workflow Status
# GitLab
glab ci status
glab ci view
# GitHub
gh run list
gh run view <run-id>
Create Merge Request / Pull Request
# GitLab
glab mr create --fill --squash-before-merge
# GitHub
gh pr create --fill
View CI Logs
# GitLab
glab ci trace
# GitHub
gh run view <run-id> --log
When to Use Which Forge
| Scenario | Recommended Forge | Reason |
|---|---|---|
| Primary pooled runners | GitHub | ARC scale sets are the production control plane |
| IaC compatibility validation | GitLab | GitLab runner module remains a compatibility surface |
| Open source projects | GitHub | Community visibility and Actions marketplace |
| Nix builds | GitHub first | Both adapters can carry Attic config; ARC is proved |
| Bazel cache-backed CI | GitHub first | Shared Bazel remote cache is proved in ARC jobs |
| Forgejo/Codeberg experiments | Proof only | No production adapter or cache path exists yet |
GitLab runner pods now receive the same Attic and Bazel cache environment as the ARC runner classes, but GitLab does not currently match ARC’s queue-driven scale-to-zero behavior. Treat GitLab as compatibility infrastructure until a live GitLab proof exercises the same cache-first contract end to end.
Woodpecker/Codeberg is future adapter work. The current repo has Forgejo proof documentation, not a reusable Woodpecker runner stack, shared fleet, or verified Attic/Bazel cache path.
See Also
- GitHub App Adoption — install GloriousFlywheel on your org
- Self-Service Enrollment — GitLab runner enrollment
- GitHub Actions Runners — ARC runner details