feat: add automatic n8n overlay updates
- overlays/mods/n8n.nix: add passthru.updateScript pointing to ./update.sh - overlays/mods/update.sh: self-contained updater that fetches the latest stable n8n-io/n8n release, recomputes both src and pnpmDeps hashes (src via nix-prefetch-url with --name workaround for the `@` in the tag, pnpmDeps via the lib.fakeHash mismatch trick) - .gitea/workflows/nix-update.yml: discover and run overlays/mods/*/update.sh after the pkgs/ loop; verify step skips overlay/* entries (covered by flake check) The test suite (tests/n8n-overlay-test.nix) forbids exporting a local n8n package, so the overlay cannot be exposed via pkgs/n8n/ — the workflow gets an explicit overlay-discovery block instead.
This commit is contained in:
@@ -352,6 +352,47 @@ jobs:
|
||||
done
|
||||
fi
|
||||
|
||||
# ── Update overlay modifications (overlays/mods/) ───────────────
|
||||
# Overlay updates live outside pkgs/ because the test suite
|
||||
# (tests/n8n-overlay-test.nix) forbids exporting the overlay target
|
||||
# as a local package. Each `overlays/mods/*/update.sh` or
|
||||
# `overlays/mods/update.sh` is a self-contained updater that handles
|
||||
# version discovery, hash recomputation, and commit on its own.
|
||||
if [ -z "${{ inputs.package }}" ]; then
|
||||
echo ""
|
||||
echo "🔍 Discovering overlay update scripts in overlays/mods/ ..."
|
||||
OVERLAY_SCRIPTS=$(find overlays/mods -maxdepth 2 -name "update.sh" 2>/dev/null | sort)
|
||||
|
||||
if [ -n "$OVERLAY_SCRIPTS" ]; then
|
||||
for script in $OVERLAY_SCRIPTS; do
|
||||
OVERLAY_NAME=$(basename "$(dirname "$script")")
|
||||
echo "::group::Updating overlay: $OVERLAY_NAME"
|
||||
BEFORE_HASH=$(git rev-parse HEAD)
|
||||
|
||||
# Overlay scripts are self-contained and use nix-shell shebangs
|
||||
# for their dependencies. They commit on their own.
|
||||
if bash "$script" 2>&1 | tee /tmp/update-overlay-${OVERLAY_NAME}.log; then
|
||||
if [ "$(git rev-parse HEAD)" != "$BEFORE_HASH" ]; then
|
||||
echo "✅ Updated overlay/$OVERLAY_NAME"
|
||||
UPDATES_FOUND=true
|
||||
if [ -n "$UPDATED_PACKAGES" ]; then
|
||||
UPDATED_PACKAGES="$UPDATED_PACKAGES, overlay/$OVERLAY_NAME"
|
||||
else
|
||||
UPDATED_PACKAGES="overlay/$OVERLAY_NAME"
|
||||
fi
|
||||
else
|
||||
echo "✓ overlay/$OVERLAY_NAME already up to date"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Update failed for overlay/$OVERLAY_NAME"
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
done
|
||||
else
|
||||
echo "ℹ️ No overlay update scripts found."
|
||||
fi
|
||||
fi
|
||||
|
||||
COMMIT_COUNT=$(git rev-list --count origin/master..HEAD)
|
||||
|
||||
if [ "$COMMIT_COUNT" -gt 0 ]; then
|
||||
@@ -382,6 +423,12 @@ jobs:
|
||||
SUCCESSFUL_PACKAGES=()
|
||||
|
||||
for pkg in "${PKGS[@]}"; do
|
||||
# Overlay updates (e.g. "overlay/n8n") have no top-level flake
|
||||
# attribute — `nix flake check` already verifies them above.
|
||||
if [[ "$pkg" == overlay/* ]]; then
|
||||
echo "⊘ Skipping per-package build for $pkg (verified via flake check)"
|
||||
continue
|
||||
fi
|
||||
echo "::group::Building $pkg"
|
||||
if nix build .#$pkg 2>&1 | tee /tmp/build-${pkg}.log; then
|
||||
echo "✅ Build successful for $pkg"
|
||||
|
||||
@@ -39,6 +39,11 @@ in
|
||||
fi
|
||||
'';
|
||||
|
||||
# Self-contained update script (./update.sh) — fetches latest stable
|
||||
# release from n8n-io/n8n, recomputes both src and pnpmDeps hashes.
|
||||
# The CI workflow in .gitea/workflows/nix-update.yml discovers and runs it.
|
||||
passthru = (previousAttrs.passthru or {}) // {updateScript = ./update.sh;};
|
||||
|
||||
meta =
|
||||
previousAttrs.meta
|
||||
// {
|
||||
|
||||
Executable
+153
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell --pure -i bash -p bash curl jq nix nix-prefetch cacert git
|
||||
set -euo pipefail
|
||||
|
||||
# Update the n8n overlay (overlays/mods/n8n.nix) to the latest stable GitHub
|
||||
# release of n8n-io/n8n.
|
||||
#
|
||||
# This is a self-contained updater (not nix-update), because the overlay file
|
||||
# is a `prev.n8n.overrideAttrs` form rather than a standalone derivation and
|
||||
# the test suite (tests/n8n-overlay-test.nix) explicitly forbids exporting a
|
||||
# local n8n package. The CI workflow discovers and runs this script directly.
|
||||
#
|
||||
# What it does, in order:
|
||||
# 1. Fetch latest stable (non-prerelease) tag from the GitHub API
|
||||
# 2. Strip the `n8n@` prefix → version
|
||||
# 3. Compare to the version pinned in overlays/mods/n8n.nix
|
||||
# 4. Compute new src hash (fetchFromGitHub tarball) via nix-prefetch-url
|
||||
# 5. Compute new pnpmDeps hash via the lib.fakeHash trick
|
||||
# 6. Commit
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
NIX_FILE="$SCRIPT_DIR/n8n.nix"
|
||||
|
||||
REPO="n8n-io/n8n"
|
||||
TAG_PREFIX="n8n@"
|
||||
|
||||
# ── 1. Latest stable release ───────────────────────────────────────────────
|
||||
echo "Fetching latest stable release of $REPO ..."
|
||||
LATEST_TAG=$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" \
|
||||
| jq -r 'select(.prerelease == false) | .tag_name')
|
||||
|
||||
if [[ -z "$LATEST_TAG" ]]; then
|
||||
echo "ERROR: No stable release found for $REPO" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION="${LATEST_TAG#${TAG_PREFIX}}"
|
||||
echo "Latest version: $VERSION"
|
||||
|
||||
# ── 2. Current version from the nix file ───────────────────────────────────
|
||||
CURRENT=$(awk '
|
||||
/^[[:space:]]*version = "/ {
|
||||
gsub(/^[[:space:]]*version = "/, "")
|
||||
gsub(/".*/, "")
|
||||
print
|
||||
exit
|
||||
}
|
||||
' "$NIX_FILE")
|
||||
echo "Current version: $CURRENT"
|
||||
|
||||
if [[ "$VERSION" == "$CURRENT" ]]; then
|
||||
echo "Already at latest version, nothing to do."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "==> Updating n8n $CURRENT -> $VERSION"
|
||||
|
||||
# ── 3. Bump version in the file ────────────────────────────────────────────
|
||||
sed -i "s|^\([[:space:]]*\)version = \"[^\"]*\";|\1version = \"$VERSION\";|" "$NIX_FILE"
|
||||
|
||||
# ── 4. Compute and apply src hash ──────────────────────────────────────────
|
||||
echo "==> Computing src hash ..."
|
||||
SRC_URL="https://github.com/$REPO/archive/refs/tags/${TAG_PREFIX}${VERSION}.tar.gz"
|
||||
# `--name n8n-source` works around the `@` in the upstream tag name
|
||||
# (nix-prefetch-url refuses filenames containing `@`).
|
||||
SRC_HASH=$(nix-prefetch-url --unpack --type sha256 --name n8n-source "$SRC_URL" 2>/dev/null)
|
||||
SRC_SRI=$(nix hash convert --hash-algo sha256 --to sri "$SRC_HASH")
|
||||
echo " src hash: $SRC_SRI"
|
||||
|
||||
# Replace the FIRST `hash = "sha256-...";` occurrence (the src block sits above pnpmDeps)
|
||||
awk -v sri="$SRC_SRI" '
|
||||
!src_done && /^[[:space:]]*hash = "sha256-/ {
|
||||
sub(/"sha256-[A-Za-z0-9+/=]+"/, "\"" sri "\"")
|
||||
src_done = 1
|
||||
}
|
||||
{ print }
|
||||
' "$NIX_FILE" > "$NIX_FILE.tmp" && mv "$NIX_FILE.tmp" "$NIX_FILE"
|
||||
|
||||
# ── 5. Compute pnpmDeps hash via lib.fakeHash ──────────────────────────────
|
||||
echo "==> Computing pnpmDeps hash (this may take a while) ..."
|
||||
|
||||
# 5a. Temporarily set the pnpmDeps hash to lib.fakeHash
|
||||
awk '
|
||||
!pnpm_started && /^[[:space:]]*pnpmDeps = / { pnpm_started = 1 }
|
||||
pnpm_started && !pnpm_done && /^[[:space:]]*hash = "sha256-/ {
|
||||
sub(/"sha256-[A-Za-z0-9+/=]+"/, "lib.fakeHash")
|
||||
pnpm_done = 1
|
||||
}
|
||||
{ print }
|
||||
' "$NIX_FILE" > "$NIX_FILE.tmp" && mv "$NIX_FILE.tmp" "$NIX_FILE"
|
||||
|
||||
# 5b. Evaluate n8nModified.pnpmDeps — fixed-output derivation with a wrong hash
|
||||
# will fail and print the correct hash in the "got:" line.
|
||||
SYSTEM=$(nix eval --impure --raw --expr 'builtins.currentSystem' 2>/dev/null || echo "x86_64-linux")
|
||||
NIX_EXPR="(let
|
||||
flake = builtins.getFlake (toString ./.);
|
||||
pkgs = flake.inputs.nixpkgs.legacyPackages.\${builtins.currentSystem};
|
||||
n8nModified = import ./overlays/mods/n8n.nix { prev = pkgs; };
|
||||
in n8nModified.pnpmDeps)"
|
||||
|
||||
BUILD_OUTPUT=$(nix build --impure --no-link --expr "$NIX_EXPR" 2>&1 || true)
|
||||
|
||||
# Hash mismatch errors list two sha256 values: the wrong "Expected"/"specified"
|
||||
# one (our lib.fakeHash = all A's) and the correct "Got"/"got" one. Different
|
||||
# nix versions capitalise the label differently, so we filter out the fakeHash
|
||||
# sentinel and take whatever real sha256 remains.
|
||||
PNPM_HASH=$(echo "$BUILD_OUTPUT" \
|
||||
| grep -oE 'sha256-[A-Za-z0-9+/=]+' \
|
||||
| grep -v 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' \
|
||||
| tail -1)
|
||||
|
||||
if [[ -z "$PNPM_HASH" ]]; then
|
||||
echo "ERROR: Failed to compute pnpmDeps hash. nix build output:" >&2
|
||||
echo "$BUILD_OUTPUT" >&2
|
||||
echo "Restoring original file..." >&2
|
||||
git checkout -- "$NIX_FILE" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " pnpmDeps hash: $PNPM_HASH"
|
||||
|
||||
# 5d. Replace lib.fakeHash with the real hash
|
||||
awk -v sri="$PNPM_HASH" '
|
||||
!pnpm_started && /^[[:space:]]*pnpmDeps = / { pnpm_started = 1 }
|
||||
pnpm_started && !pnpm_done && /^[[:space:]]*hash = / {
|
||||
sub(/lib\.fakeHash/, "\"" sri "\"")
|
||||
pnpm_done = 1
|
||||
}
|
||||
{ print }
|
||||
' "$NIX_FILE" > "$NIX_FILE.tmp" && mv "$NIX_FILE.tmp" "$NIX_FILE"
|
||||
|
||||
# ── 6. Verify the file parses and commit ───────────────────────────────────
|
||||
echo "==> Verifying nix evaluation ..."
|
||||
if ! nix eval --impure --expr "
|
||||
let
|
||||
flake = builtins.getFlake (toString ./.);
|
||||
pkgs = flake.inputs.nixpkgs.legacyPackages.\${builtins.currentSystem};
|
||||
in (import ./overlays/mods/n8n.nix { prev = pkgs; }).version
|
||||
" >/dev/null 2>&1; then
|
||||
echo "ERROR: nix evaluation failed after update; restoring original." >&2
|
||||
git checkout -- "$NIX_FILE" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NIXPKGS_ROOT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || true)
|
||||
if [[ -n "$NIXPKGS_ROOT" ]] && \
|
||||
[[ -n "$(git -C "$NIXPKGS_ROOT" status --porcelain "$NIX_FILE")" ]]; then
|
||||
git -C "$NIXPKGS_ROOT" add "$NIX_FILE"
|
||||
git -C "$NIXPKGS_ROOT" commit -m "n8n: $CURRENT -> $VERSION"
|
||||
echo "==> Committed"
|
||||
fi
|
||||
|
||||
echo "==> Done"
|
||||
Reference in New Issue
Block a user