ci: add publish-arm64 flake app for local parity (emmett#44)
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
Introduce a shared publish-arm64 flake app (archetype oci-image-skopeo) that builds the arm64 docker-archive via Nix and skopeo-copies it to the Gitea OCI registry as :<ver>-arm64, mirroring to :latest-arm64. Both .woodpecker.yaml and `nix run .#publish-arm64` invoke the same app so CI and local cannot drift. - dry-run by default; PUBLISH=1 to actually push (safe to run locally) - token via $REGISTRY_TOKEN, fallback pass infra/gitea/personal_access_token_packages_rw - token never printed; no set -x on token-bearing paths - rename CI secret env CI_REGISTRY_TOKEN -> REGISTRY_TOKEN - thin .woodpecker.yaml: one PUBLISH=1 nix run line - --help/--dry-run honored; meta.description set
This commit is contained in:
+6
-26
@@ -24,7 +24,8 @@ steps:
|
||||
environment:
|
||||
GITEA_CLONE_TOKEN:
|
||||
from_secret: gitea_clone_token
|
||||
CI_REGISTRY_TOKEN:
|
||||
# Single token env var shared by CI + local parity (emmett#44).
|
||||
REGISTRY_TOKEN:
|
||||
from_secret: registry_token
|
||||
backend_options:
|
||||
kubernetes:
|
||||
@@ -43,28 +44,7 @@ steps:
|
||||
EOF
|
||||
- if [ -n "$GITEA_CLONE_TOKEN" ]; then echo "machine git.oleks.space login oleks password $GITEA_CLONE_TOKEN" >~/.netrc && chmod 600 ~/.netrc; fi
|
||||
|
||||
# Resolve the upstream Angie version and build the image stream script.
|
||||
- VERSION="$(nix eval --raw .#angieVersion)"
|
||||
- echo "Building angie $VERSION"
|
||||
- STREAM="$(nix build .#default --print-out-paths --no-link)"
|
||||
|
||||
# skopeo's containers/image library writes intermediate files under
|
||||
# /var/tmp (not TMPDIR), and the nix-ci image doesn't seed that path.
|
||||
- mkdir -p /var/tmp && chmod 1777 /var/tmp
|
||||
|
||||
# Auth + push to Gitea OCI registry under both <ver>-arm64 and latest-arm64.
|
||||
- mkdir -p ~/.config/containers
|
||||
- |
|
||||
printf '{"auths":{"git.oleks.space":{"auth":"%s"}}}\n' \
|
||||
"$(printf 'oleks:%s' "$CI_REGISTRY_TOKEN" | base64 -w0)" \
|
||||
> ~/.config/containers/auth.json
|
||||
- |
|
||||
nix run nixpkgs#skopeo -- copy --insecure-policy \
|
||||
--authfile ~/.config/containers/auth.json \
|
||||
docker-archive:<("$STREAM") \
|
||||
docker://git.oleks.space/oleks/angie:$VERSION-arm64
|
||||
- |
|
||||
nix run nixpkgs#skopeo -- copy --insecure-policy \
|
||||
--authfile ~/.config/containers/auth.json \
|
||||
docker://git.oleks.space/oleks/angie:$VERSION-arm64 \
|
||||
docker://git.oleks.space/oleks/angie:latest-arm64
|
||||
# Thin front door: CI and `nix run .#publish-arm64` on emmett run the
|
||||
# exact same shared app (emmett#44, archetype oci-image-skopeo). The app
|
||||
# is dry-run by default; PUBLISH=1 makes it actually push.
|
||||
- PUBLISH=1 nix run .#publish-arm64
|
||||
|
||||
@@ -8,14 +8,31 @@ registry.
|
||||
## Output
|
||||
|
||||
| Tag | Pushed when |
|
||||
|---|---|
|
||||
| --- | --- |
|
||||
| `git.oleks.space/oleks/angie:<version>-arm64` | every successful CI run |
|
||||
| `git.oleks.space/oleks/angie:latest-arm64` | every successful CI run |
|
||||
|
||||
The version string comes from `pkgs.angie.version` in nixpkgs unstable; bump
|
||||
the flake input to roll it forward.
|
||||
|
||||
## Build locally
|
||||
## Build / publish locally
|
||||
|
||||
CI and local runs share one entrypoint (emmett#44, archetype oci-image-skopeo):
|
||||
|
||||
```bash
|
||||
# dry-run: build the arm64 image and print the refs it would push (no registry contact)
|
||||
nix run .#publish-arm64
|
||||
|
||||
# actually push :<version>-arm64 and mirror to :latest-arm64
|
||||
PUBLISH=1 nix run .#publish-arm64
|
||||
```
|
||||
|
||||
The registry token is read from `$REGISTRY_TOKEN`, falling back to
|
||||
`pass infra/gitea/personal_access_token_packages_rw`. The token is never
|
||||
printed. `.woodpecker.yaml` runs the exact same app with `PUBLISH=1`, so CI
|
||||
and local cannot drift.
|
||||
|
||||
Just the raw build (no push):
|
||||
|
||||
```bash
|
||||
nix build .#default
|
||||
|
||||
@@ -78,11 +78,127 @@
|
||||
WorkingDir = "/etc/angie";
|
||||
};
|
||||
};
|
||||
# Shared build+publish logic for the arm64 OCI leg. This script IS the
|
||||
# parity code (emmett#44, archetype: oci-image-skopeo): both
|
||||
# `.woodpecker.yaml` and a local `nix run .#publish-arm64` invoke the
|
||||
# exact same entrypoint, so CI and local cannot drift.
|
||||
#
|
||||
# Safety: DRY-RUN by default. It builds the image stream and prints the
|
||||
# refs it WOULD push, but performs no registry contact unless PUBLISH=1
|
||||
# is set. The token is never printed and this script never runs under
|
||||
# `set -x` (which would leak the auth header).
|
||||
publish-arm64 = pkgs.writeShellApplication {
|
||||
name = "publish-arm64";
|
||||
runtimeInputs = with pkgs; [
|
||||
skopeo
|
||||
coreutils
|
||||
gnused
|
||||
gitMinimal
|
||||
];
|
||||
# `pass` is optional (only the local fallback path needs it) and may
|
||||
# live outside this closure, so it is resolved from PATH at runtime.
|
||||
text = ''
|
||||
set -euo pipefail
|
||||
|
||||
# --- usage -------------------------------------------------------
|
||||
if [ "''${1:-}" = "--help" ] || [ "''${1:-}" = "-h" ]; then
|
||||
printf '%s\n' \
|
||||
"publish-arm64 — build the angie arm64 OCI image and (optionally) push it." \
|
||||
"" \
|
||||
"Builds the arm64 docker-archive via Nix and uses skopeo to copy it to" \
|
||||
"the Gitea OCI registry as :<ver>-arm64, then mirrors that digest to" \
|
||||
":latest-arm64." \
|
||||
"" \
|
||||
"DRY-RUN by default: prints the refs it would push and exits without" \
|
||||
"contacting the registry. Set PUBLISH=1 to actually push." \
|
||||
"" \
|
||||
"Env:" \
|
||||
" PUBLISH=1 actually push (default: dry-run)" \
|
||||
" VERSION=<ver> override the tag (default: angie.version)" \
|
||||
" REGISTRY_TOKEN=<tok> registry RW token; if empty, falls back to" \
|
||||
" pass infra/gitea/personal_access_token_packages_rw" \
|
||||
"" \
|
||||
"Flags:" \
|
||||
" --help, -h this help" \
|
||||
" --dry-run force dry-run even if PUBLISH=1"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
DRY_RUN=0
|
||||
if [ "''${PUBLISH:-0}" != "1" ]; then DRY_RUN=1; fi
|
||||
if [ "''${1:-}" = "--dry-run" ]; then DRY_RUN=1; fi
|
||||
|
||||
REGISTRY="git.oleks.space"
|
||||
IMAGE="oleks/angie"
|
||||
|
||||
# --- version / tag (identical for CI + local) --------------------
|
||||
VERSION="''${VERSION:-$(nix eval --raw .#angieVersion)}"
|
||||
echo "angie version: $VERSION"
|
||||
echo "target refs: docker://$REGISTRY/$IMAGE:$VERSION-arm64"
|
||||
echo " docker://$REGISTRY/$IMAGE:latest-arm64"
|
||||
|
||||
# --- build (cluster-independent) ---------------------------------
|
||||
echo "building arm64 image stream..."
|
||||
STREAM="$(nix build .#default --print-out-paths --no-link)"
|
||||
|
||||
if [ "$DRY_RUN" = "1" ]; then
|
||||
echo "DRY-RUN: built $STREAM"
|
||||
echo "DRY-RUN: would skopeo-copy docker-archive -> docker://$REGISTRY/$IMAGE:$VERSION-arm64"
|
||||
echo "DRY-RUN: would mirror :$VERSION-arm64 -> :latest-arm64"
|
||||
echo "DRY-RUN: set PUBLISH=1 to actually push."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- token resolution (never printed) ----------------------------
|
||||
TOKEN="''${REGISTRY_TOKEN:-}"
|
||||
if [ -z "$TOKEN" ]; then
|
||||
if command -v pass >/dev/null 2>&1; then
|
||||
TOKEN="$(pass infra/gitea/personal_access_token_packages_rw)"
|
||||
fi
|
||||
fi
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo "ERROR: no registry token. Set REGISTRY_TOKEN or store it at" >&2
|
||||
echo " pass infra/gitea/personal_access_token_packages_rw" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# skopeo's containers/image library stages under /var/tmp (not TMPDIR).
|
||||
mkdir -p /var/tmp && chmod 1777 /var/tmp || true
|
||||
|
||||
AUTHFILE="$(mktemp -d)/auth.json"
|
||||
# shellcheck disable=SC2064
|
||||
trap "rm -rf '$(dirname "$AUTHFILE")'" EXIT
|
||||
printf '{"auths":{"%s":{"auth":"%s"}}}\n' \
|
||||
"$REGISTRY" "$(printf 'oleks:%s' "$TOKEN" | base64 -w0)" \
|
||||
> "$AUTHFILE"
|
||||
|
||||
echo "pushing :$VERSION-arm64 ..."
|
||||
skopeo copy --insecure-policy --authfile "$AUTHFILE" \
|
||||
docker-archive:<("$STREAM") \
|
||||
"docker://$REGISTRY/$IMAGE:$VERSION-arm64"
|
||||
|
||||
echo "mirroring :$VERSION-arm64 -> :latest-arm64 ..."
|
||||
skopeo copy --insecure-policy --authfile "$AUTHFILE" \
|
||||
"docker://$REGISTRY/$IMAGE:$VERSION-arm64" \
|
||||
"docker://$REGISTRY/$IMAGE:latest-arm64"
|
||||
|
||||
echo "done."
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
packages.${system} = {
|
||||
default = image;
|
||||
};
|
||||
|
||||
apps.${system} = {
|
||||
publish-arm64 = {
|
||||
type = "app";
|
||||
program = "${publish-arm64}/bin/publish-arm64";
|
||||
meta.description = "Build and publish the angie arm64 OCI image to git.oleks.space (dry-run by default; PUBLISH=1 to push).";
|
||||
};
|
||||
};
|
||||
|
||||
# Plain string — read by CI via `nix eval --raw .#angieVersion`.
|
||||
angieVersion = angie.version;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user