Nightly Build / build (push) Successful in 9m28s
The previous commit tried to fix the mtime invalidation with `git restore-mtime`. It does not work on this box, in the worst way: the packaged version (2022.12) drives `git whatchanged`, which git 2.53 refuses to run without --i-still-use-this — and the tool swallows that failure and exits 0 having updated nothing. Verified on the runner: "0 commits evaluated, 675 files missing, 0 files updated", while the job happily went on to rebuild everything. Fix the cause instead of the symptom. Both building workflows now sync a tree that survives between runs and build there. `git checkout` only rewrites files whose content actually changed, so mtimes are correct as a consequence rather than as a reconstruction — and no external tool is involved. Gitea serves this repo from the same machine the runner runs on, so the sync reads the bare repo directly: no network, no token. Two properties this buys that restore-mtime did not: - The absolute source path is pinned. The runner derives its workspace path from the job definition, so editing a workflow moved it and invalidated every workspace crate by itself — the previous commit paid that cost without knowing it. - It cannot fail towards staleness. Checking out an older commit stamps those files newer, which costs an extra rebuild; restore-mtime moved mtimes backwards, which could have let cargo reuse artifacts built from newer code. Each workflow gets its own tree, for the same reason they already have their own CARGO_TARGET_DIR: they track different branches, and one shared tree would rewrite half the files on every switch.
161 lines
6.7 KiB
YAML
161 lines
6.7 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- release
|
|
pull_request:
|
|
branches:
|
|
- release
|
|
|
|
jobs:
|
|
# ── PR check: verify the version is not already built ───────────────────────
|
|
verify-version:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: linux-amd64
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Verify version is new
|
|
run: ./ci/verify-version.sh --builds-dir /var/www/builds.skaldagent.net
|
|
|
|
# ── Push/merge: build, package, and deploy the release ──────────────────────
|
|
release:
|
|
if: github.event_name == 'push'
|
|
runs-on: linux-amd64
|
|
|
|
outputs:
|
|
version: ${{ steps.extract-version.outputs.version }}
|
|
|
|
env:
|
|
# Deliberately NOT the nightly's target dir. No CARGO_INCREMENTAL here —
|
|
# a release binary is the one people install, so it gets the fully
|
|
# optimised non-incremental build — and that flag is part of cargo's
|
|
# profile fingerprint. Sharing one cache between a workflow that sets it
|
|
# and one that doesn't would make each run invalidate the other's
|
|
# workspace crates, which is exactly the cost this whole change removes.
|
|
CARGO_TARGET_DIR: /home/dguiducci/.cache/skald-ci/target-release
|
|
# The persistent build tree. Separate from the nightly's for the same
|
|
# reason as the target dir: this one tracks `release`, that one tracks
|
|
# `main`, and a shared tree would rewrite half the files on every switch —
|
|
# reintroducing precisely the mtime churn the arrangement removes.
|
|
SRC: /home/dguiducci/.cache/skald-ci/src-release
|
|
|
|
steps:
|
|
# Deliberately not actions/checkout — see the long note in nightly.yml.
|
|
# Short version: the runner deletes its workspace after every job, so a
|
|
# fresh clone stamps every source file "now" and cargo, which decides
|
|
# freshness by mtime, rebuilt all 20 workspace crates on every run
|
|
# whatever the commit touched. A tree that survives makes `git checkout`
|
|
# rewrite only the files that actually changed.
|
|
- name: Sync the persistent build tree
|
|
run: |
|
|
set -eu
|
|
# Gitea serves this repo from the same machine the runner runs on, so
|
|
# the tree syncs straight off the bare repo: no network, no token.
|
|
ORIGIN=/home/dguiducci/skald/gitea/data/git/repositories/dguiducci/skald-circle.git
|
|
if [ ! -d "$SRC/.git" ]; then
|
|
mkdir -p "$(dirname "$SRC")"
|
|
git clone --no-checkout "$ORIGIN" "$SRC"
|
|
fi
|
|
cd "$SRC"
|
|
git remote set-url origin "$ORIGIN"
|
|
git fetch --prune --force origin
|
|
git checkout -f --detach "$GITHUB_SHA"
|
|
# Clear leftovers from the previous run (dist/ above all) so a stale
|
|
# tarball can never be published as this version.
|
|
git clean -ffdxq
|
|
echo "[sync] $(git log --oneline -1)"
|
|
|
|
- name: Extract version from Cargo.toml
|
|
id: extract-version
|
|
run: |
|
|
cd "$SRC"
|
|
VER="v$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')"
|
|
echo "version=$VER" >> "$GITHUB_OUTPUT"
|
|
echo "[release] Building version $VER"
|
|
|
|
# Also run verify-version on push to catch any race (belt-and-suspenders)
|
|
- name: Verify version is new
|
|
run: |
|
|
cd "$SRC"
|
|
./ci/verify-version.sh --builds-dir /var/www/builds.skaldagent.net
|
|
|
|
- name: Build native (linux/amd64)
|
|
run: |
|
|
cd "$SRC"
|
|
RUSTFLAGS="-A warnings" cargo build --release --no-default-features
|
|
RUSTFLAGS="-A warnings" cargo build --release --no-default-features -p skald-setup
|
|
|
|
- name: Cross-compile (linux/arm64)
|
|
env:
|
|
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
|
|
AR_aarch64_unknown_linux_gnu: aarch64-linux-gnu-ar
|
|
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
|
|
run: |
|
|
cd "$SRC"
|
|
RUSTFLAGS="-A warnings" cargo build --release --no-default-features --target aarch64-unknown-linux-gnu
|
|
RUSTFLAGS="-A warnings" cargo build --release --no-default-features -p skald-setup --target aarch64-unknown-linux-gnu
|
|
|
|
- name: Package amd64
|
|
run: |
|
|
cd "$SRC"
|
|
./ci/package.sh \
|
|
--version "${{ steps.extract-version.outputs.version }}" \
|
|
--os linux \
|
|
--arch amd64 \
|
|
--target-dir "$CARGO_TARGET_DIR/release" \
|
|
--output dist/
|
|
|
|
- name: Package arm64
|
|
run: |
|
|
cd "$SRC"
|
|
./ci/package.sh \
|
|
--version "${{ steps.extract-version.outputs.version }}" \
|
|
--os linux \
|
|
--arch arm64 \
|
|
--target-dir "$CARGO_TARGET_DIR/aarch64-unknown-linux-gnu/release" \
|
|
--output dist/
|
|
|
|
- name: Deploy to builds.skaldagent.net
|
|
run: |
|
|
cd "$SRC"
|
|
VERSION="${{ steps.extract-version.outputs.version }}"
|
|
TARGET="/var/www/builds.skaldagent.net/releases/${VERSION}"
|
|
mkdir -p "$TARGET"
|
|
# Publish each tarball atomically (temp name + rename) so a client can
|
|
# never fetch a half-written file.
|
|
for f in dist/*.tar.gz; do
|
|
name="$(basename "$f")"
|
|
cp "$f" "$TARGET/.$name.tmp"
|
|
mv -f "$TARGET/.$name.tmp" "$TARGET/$name"
|
|
done
|
|
echo "[release] Deployed $VERSION:"
|
|
ls -lh "$TARGET/"
|
|
|
|
- name: Update latest version pointer
|
|
run: |
|
|
VERSION="${{ steps.extract-version.outputs.version }}"
|
|
DEST=/var/www/builds.skaldagent.net/releases
|
|
# Flip LATEST atomically — install.sh/update.sh read it to decide
|
|
# whether to upgrade, so it must never be observed empty or partial.
|
|
printf '%s\n' "$VERSION" > "$DEST/.LATEST.tmp"
|
|
mv -f "$DEST/.LATEST.tmp" "$DEST/LATEST"
|
|
echo "[release] Updated releases/LATEST → $VERSION"
|
|
|
|
- name: Publish the release installer
|
|
run: |
|
|
cd "$SRC"
|
|
# install.sh is served straight from the web root
|
|
# (curl -fsSL https://builds.skaldagent.net/install.sh | bash), so
|
|
# without this it stays whatever was copied there by hand and drifts
|
|
# from the repo — a fix to the installer would reach every existing box
|
|
# through update.sh but never a new one. Published here rather than on
|
|
# every push so the served installer always matches a real release.
|
|
ROOT=/var/www/builds.skaldagent.net
|
|
cp install.sh "$ROOT/.install.sh.tmp"
|
|
chmod 644 "$ROOT/.install.sh.tmp"
|
|
mv -f "$ROOT/.install.sh.tmp" "$ROOT/install.sh"
|
|
echo "[release] Published install.sh"
|