ci: local-pipeline parity via stage/publish flake apps (cluster#192, emmett#44)

attic-closure archetype: no parity-lib builder exists for attic pushes, so
wrap the existing per-arch package build in ci/publish.py (woodpecker-peek
pattern) and expose `nix run .#{stage,publish}-amd64` + `.#publish`.

Two-halves rule: STAGE nix-builds every package in the arch list into the
local store (emmett-buildable); PUBLISH additionally attic-pushes each
closure. Local runs DRY-RUN unless --push/PUBLISH=1; CI sets PUBLISH=1.

The .woodpecker/{amd64,arm64}.yaml now call the same ci/publish.py so CI
and local runs can't drift. arm64 stays node-bound (no emmett cross path),
so it has no local-parity app. ci/build.py becomes a forwarding shim.
This commit is contained in:
Oleks
2026-06-02 09:22:39 +03:00
parent ef13a18b4c
commit 9d80f47625
5 changed files with 282 additions and 83 deletions
+93
View File
@@ -320,5 +320,98 @@
gcc15-fixes = import ./overlays/gcc15-fixes.nix;
hyprspace = hyprspaceOverlay;
};
# `nix run .#<app>` — local-parity entrypoints (emmett#44, cluster#192,
# attic-closure archetype). parity-lib has NO attic builder, so this is a
# thin wrap of ci/publish.py (the woodpecker-peek pattern), NOT a parity
# builder conversion. The app IS the shared code: .woodpecker/amd64.yaml
# runs the exact same `ci/publish.py x86_64-linux`, so CI and a local run
# cannot drift.
#
# TWO HALVES (emmett#44): STAGE `nix build`s every package in the arch's
# list into the local /nix store (cluster-independent, runs on emmett);
# PUBLISH additionally `attic push`es each closure to the cache that lives
# next to the cluster. Local runs DRY-RUN (stage + show the pushes) unless
# `--push`/PUBLISH=1.
#
# nix run .#stage-amd64 stage x86_64-linux closures, no publish
# nix run .#publish-amd64 same, then push if `--push` given
# nix run .#publish-amd64 -- --push actually push to attic
# nix run .#publish all locally-buildable arches (amd64)
#
# arm64 BLOCKER: aarch64-linux cannot be built on emmett (linux/amd64) and
# there is no cross path for these native packages, so the arm64 leg MUST
# run on an aarch64 node (.woodpecker/arm64.yaml). It is intentionally
# absent from the apps below.
apps = nixpkgs.lib.genAttrs buildSystems (
system:
let
pkgs = import nixpkgs { inherit system; };
mkApp =
{
name,
arch,
defaultPush ? false,
}:
let
prog = pkgs.writeShellApplication {
inherit name;
runtimeInputs = [
pkgs.python3
pkgs.git
pkgs.nix
];
text = ''
${pkgs.lib.optionalString defaultPush "export PUBLISH=\"\${PUBLISH:-1}\""}
exec python3 ci/publish.py ${arch} "$@"
'';
};
in
{
type = "app";
program = "${prog}/bin/${name}";
meta.description =
"flake-hub ${arch} stage closures then attic push "
+ "(dry-run unless --push/PUBLISH=1)";
};
in
{
# x86_64-linux: native on emmett.
stage-amd64 = mkApp {
name = "stage-amd64";
arch = "x86_64-linux";
};
publish-amd64 = mkApp {
name = "publish-amd64";
arch = "x86_64-linux";
};
# `publish` = every locally-buildable arch + the arm64 blocker note.
# On emmett that is amd64 only; arm64 is node-bound (see comment above).
publish = {
type = "app";
program =
let
p = pkgs.writeShellApplication {
name = "publish";
runtimeInputs = [
pkgs.python3
pkgs.git
pkgs.nix
];
text = ''
echo "publish: amd64 is the only emmett-buildable arch; arm64 is"
echo " node-bound (run on an aarch64 node via"
echo " .woodpecker/arm64.yaml)."
exec python3 ci/publish.py x86_64-linux "$@"
'';
};
in
"${p}/bin/publish";
meta.description =
"flake-hub publish all locally-buildable arches (amd64; arm64 node-bound)";
};
}
);
};
}