diff --git a/docs/publishing-gitea-local-fork.md b/docs/publishing-gitea-local-fork.md new file mode 100644 index 0000000..328d6cc --- /dev/null +++ b/docs/publishing-gitea-local-fork.md @@ -0,0 +1,174 @@ +# Publishing `gitea-local-fork` + +End-to-end flow for taking a change in Oleks's local gitea fork +(`/home/oleks/projects/gitea`, branch `oleks/main`) all the way to a +binary in the `attic-infra-cache-k3s-1` cache, ready for any consumer +to fetch instead of recompiling Go 1.26.3 locally. + +## Step-by-step + +### 1. Develop in the gitea fork + +```bash +cd ~/projects/gitea +# work on oleks/main (the fork integration tip) +git commit -m "..." +git push oleks oleks/main:main +``` + +Lands on `git.oleks.space/oleks/gitea` at `refs/heads/main`. + +This step alone does **not** trigger any CI on flake-hub — the binding +contract is the flake-hub pin commit in step 2. + +### 2. Bump the pin in flake-hub + +```bash +cd ~/projects/nix-customs/flake-hub +just gitea-update +``` + +Under the hood, `scripts/update-gitea-local-fork.sh`: + +1. **Wipes stale unstable tags** — `git push oleks :refs/tags/v*-unstable-*` + so `nix-update` sees only clean semver tags (`v1.26.0` etc.) when + constructing the new version. +2. **Bumps the pin** — + + ```bash + nix run nixpkgs#nix-update -- \ + --flake gitea-local-fork \ + --version=branch=main \ + --build + ``` + + Updates `rev`, `vendorHash`, `pnpmDeps` hash, and `version` (formatted + as `-unstable-`). +3. **Tags the gitea fork** at the new rev with `v` and pushes + the tag. **This is the load-bearing step:** the tag makes the rev + reachable forever, surviving any future rebase / force-push of + `oleks/main`. +4. **Commits + pushes flake-hub** — the bumped `packages/gitea-local-fork.nix` + lands on `git.oleks.space/oleks/flake-hub` `main`. + +### 3. Woodpecker picks up the flake-hub push + +Pipeline auto-triggers from `.woodpecker/amd64.yaml` and `.woodpecker/arm64.yaml` +running in parallel. Each workflow: + +1. Clones `oleks/flake-hub` using the `gitea_clone_token` secret. +2. Runs `ci/setup.sh` — configures `/etc/hosts` to pin `armer` + directly (bypassing Cloudflare upload-size limits via hairpin NAT) + and writes the trusted substituters / public keys to `/etc/nix/nix.conf`. +3. Runs `ci/build.py ` — for each package (including + `gitea-local-fork` on `x86_64-linux` and `aarch64-linux`): + + ```bash + nix build .#packages..gitea-local-fork --print-build-logs ... + attic push attic-infra-cache-k3s-1 + ``` + + Authenticates the push with `ATTIC_TOKEN` against + `https://nix-cache-upload.oleks.space`. + +### 4. Closure lives in attic + +After both arch workflows succeed, the closure is queryable from: + +- **Cache URL:** `https://nix-cache-custom.oleks.space/attic-infra-cache-k3s-1` +- **Public key:** `attic-infra-cache-k3s-1:qYSNK3DmttQXCFqn1t50qoWGtQNPRFWq9mgQjD05DeU=` + +### 5. Consume from cache + +Anyone (or any host) can pull the binary instead of building: + + +```bash +just gitea-run +# or, equivalently: +nix run \ + --extra-substituters "https://nix-cache-custom.oleks.space/attic-infra-cache-k3s-1" \ + --extra-trusted-public-keys "attic-infra-cache-k3s-1:qYSNK3DmttQXCFqn1t50qoWGtQNPRFWq9mgQjD05DeU=" \ + git+https://git.oleks.space/oleks/flake-hub#gitea-local-fork +``` + + +## Diagram + +```text +┌────────────────────────────────────────────────────────────────────────┐ +│ 1. ~/projects/gitea (branch oleks/main) │ +│ ─ git push oleks oleks/main:main ─► oleks/gitea refs/heads/main │ +└────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌────────────────────────────────────────────────────────────────────────┐ +│ 2. ~/projects/nix-customs/flake-hub │ +│ ─ just gitea-update │ +│ a. wipe v*-unstable-* tags on fork │ +│ b. nix-update → bump rev/hashes/version │ +│ c. tag fork at new rev: v ─► push │ +│ d. commit + push flake-hub origin/main │ +└────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌────────────────────────────────────────────────────────────────────────┐ +│ 3. ci.oleks.space pipeline auto-fires │ +│ amd64 + arm64 (parallel): │ +│ clone → ci/setup.sh → ci/build.py │ +│ ─ nix build .#packages..gitea-local-fork │ +│ ─ attic push attic-infra-cache-k3s-1 │ +└────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌────────────────────────────────────────────────────────────────────────┐ +│ 4. attic-infra-cache-k3s-1 │ +│ URL: https://nix-cache-custom.oleks.space/attic-infra-cache-k3s-1 │ +└────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌────────────────────────────────────────────────────────────────────────┐ +│ 5. Consumer: just gitea-run / nix run …#gitea-local-fork │ +│ ─ closure pulled from cache, no recompile │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +## Secrets + +Both are Woodpecker repo secrets on `oleks/flake-hub` (never in code): + +- `gitea_clone_token` — clone flake-hub source; netrc for `fetchgit` of + the fork. +- `attic_token` — authenticate `attic push` against + `nix-cache-upload.oleks.space`. + +## Why the dance with tags in step 2c + +The fork's `oleks/main` branch is rebaseable. `fetchgit` in the +derivation resolves by `rev`, so the rev must remain reachable from +*some* ref on the remote. Tags are immutable. The +`v` tag created at update time becomes the load-bearing +reference: even if `oleks/main` later gets force-pushed and the rev +falls off the branch, the tag keeps it alive (and Gitea won't GC it). + +## Failure points to watch + +- **Step 2c — tag push rejected.** Check `oleks` remote auth in your + shell; the pre-push hook also runs lint. +- **Step 3 build — first cold build ≈10–15 min/arch, later ≈1–2 min.** + Normal; Go 1.26.3 compiles from source. +- **Step 3 attic — push hangs or 413.** `ci/setup.sh` pins armer in + `/etc/hosts` to bypass the Cloudflare 100 MB upload cap; confirm the + pin survived. +- **Step 5 consume — cache miss, recompile locally.** Check the closure + landed (`attic info` or browse the cache URL) and that the public key + matches. + +## Reference + +- Derivation: `packages/gitea-local-fork.nix` +- Flake attr: `flake.nix` → `packages..gitea-local-fork` +- Update script: `scripts/update-gitea-local-fork.sh` *(untracked, local-only)* +- Pipelines: `.woodpecker/amd64.yaml`, `.woodpecker/arm64.yaml` +- Build driver: `ci/build.py` +- Justfile recipes: `just gitea-build`, `just gitea-update`, `just gitea-run`