Cross-Forge CI

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

GloriousFlywheel