Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions .github/workflows/nix-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: "Update Nix flake"

# Checks whether `flake.nix` lags behind the latest GitHub release. If it does,
# prefetches the new release's per-platform SRI hashes, rewrites `flake.nix`,
# and opens a PR.
#
# This runs on a schedule instead of `release: published` because prek's releases
# are created with `secrets.GITHUB_TOKEN` (see .github/workflows/release.yml),
# and GitHub does not start new workflow runs from events created by
# GITHUB_TOKEN — so a `release: published` trigger would never fire. A daily
# lag-check is fully decoupled from how releases are created and needs no PAT.
# Run manually any time via workflow_dispatch.

on:
schedule:
- cron: "17 6 * * *"
workflow_dispatch:

permissions:
contents: write
pull-requests: write

concurrency:
group: nix-flake-release
cancel-in-progress: true

jobs:
update-flake:
name: Bump flake version + hashes if lagging
runs-on: ubuntu-latest
if: github.repository == 'j178/prek'
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Install Nix
uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6

- name: Check for lag and rewrite flake.nix
env:
# system|asset-substring — one per line. The substring must uniquely
# match the release asset filename for that system (including the
# .tar.gz suffix so it does not match the sibling .sha256 files).
ASSET_MAP: |
x86_64-linux|x86_64-unknown-linux-gnu.tar.gz
aarch64-linux|aarch64-unknown-linux-gnu.tar.gz
x86_64-darwin|x86_64-apple-darwin.tar.gz
aarch64-darwin|aarch64-apple-darwin.tar.gz
run: |
set -euo pipefail
# Latest release tag from the GitHub API (strip leading 'v').
tag=$(curl -fsSL -H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/latest" \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"])')
latest="${tag#v}"
# Version currently pinned in flake.nix.
current=$(python3 -c 'import re; s=open("flake.nix").read(); m=re.search(r"version = \"([^\"]*)\";", s); print(m.group(1))')
echo "flake.nix version: $current | latest release: $latest (tag $tag)"
if [ "$current" = "$latest" ]; then
echo "flake.nix is up to date; nothing to do."
echo "LAGGING=no" >> "$GITHUB_ENV"
exit 0
fi
echo "LAGGING=yes" >> "$GITHUB_ENV"
echo "VERSION=$latest" >> "$GITHUB_ENV"
export TAG="$tag"
python3 <<'PYEOF'
import json, os, re, subprocess, urllib.request
tag = os.environ["TAG"]
version = tag.lstrip("v")
repo = os.environ["GITHUB_REPOSITORY"]
with urllib.request.urlopen(
f"https://api.github.com/repos/{repo}/releases/latest") as r:
release = json.load(r)
# Drop sibling checksum files (.sha256) so a tarball substring does
# not also match its "<tarball>.sha256" companion (cargo-dist etc.).
names = {a["name"] for a in release["assets"]
if not a["name"].endswith(".sha256")}
asset_map = {}
for line in os.environ["ASSET_MAP"].splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
sys_, sub = line.split("|", 1)
asset_map[sys_.strip()] = sub.strip()
src = open("flake.nix").read()
src, n = re.subn(r'version = "[^"]*";', f'version = "{version}";', src, count=1)
if n != 1:
raise SystemExit('could not find version = "..." in flake.nix')
for sys_, sub in asset_map.items():
match = next((n for n in names if sub in n), None)
if not match:
raise SystemExit(f"no asset for {sys_} ({sub}) in {tag}; have: {sorted(names)}")
url = f"https://github.com/{repo}/releases/download/{tag}/{match}"
out = json.loads(subprocess.check_output(
["nix", "store", "prefetch-file", "--json", "--hash-type", "sha256", url]))
sri = out["hash"]
pat = re.compile(r'("' + re.escape(sys_) + r'" = \{[^}]*\})', re.S)
def repl(m):
b = m.group(1)
b = re.sub(r'file = "[^"]*";', f'file = "{match}";', b, count=1)
b = re.sub(r'sha256 = "[^"]*";', f'sha256 = "{sri}";', b, count=1)
return b
src, n = pat.subn(repl, src, count=1)
if n != 1:
raise SystemExit(f"could not find assets block for {sys_} in flake.nix")
open("flake.nix", "w").write(src)
print(f"bumped flake.nix to {version}: {list(asset_map)}")
PYEOF

- name: Open PR
if: env.LAGGING == 'yes'
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
commit-message: "chore(nix): bump flake to v${{ env.VERSION }}"
title: "chore(nix): bump flake to v${{ env.VERSION }}"
branch: chore/nix-flake-v${{ env.VERSION }}
base: master
body: |
Auto-generated by the `Update Nix flake` workflow (daily lag-check).
The latest GitHub release is v${{ env.VERSION }} but `flake.nix` was
pinned to an older version. This PR bumps `version` and refreshes
the per-platform SRI hashes by prefetching the new release assets.

Note: PRs opened by `GITHUB_TOKEN` do not trigger downstream
workflow runs (e.g. CI), so this PR will show no checks. The diff
is a 5-line hash bump with no source changes — safe to merge as-is.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ site/
# NPM packages
npm-artifacts/
npm/.output/

# Nix build result symlinks
/result
/result-*
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,22 @@ nix-env -iA nixos.prek
nix profile install nixpkgs#prek
```

For the latest release (Nixpkgs may lag behind), use the flake in this repo:

```bash
# Run without installing
nix run github:j178/prek

# Install into your profile
nix profile install github:j178/prek
```

The flake tracks `master` and is auto-bumped to the latest release by a
daily [workflow](.github/workflows/nix-release.yml), so `github:j178/prek`
always serves the current release. (Release tags are cut before the bump
lands, so `github:j178/prek/vX.Y.Z` is not a valid pin — use the nixpkgs
package or a specific commit SHA if you need reproducibility.)

<!-- --8<-- [end: nix-install] -->

</details>
Expand Down
27 changes: 27 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

94 changes: 94 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
description = "Better pre-commit, re-engineered in Rust";

inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";

outputs = { self, nixpkgs }: let
version = "0.4.5";

# ponytail: only the 4 standard Nix systems are exposed; upstream also ships
# musl/arm/armv7/riscv64/s390x tarballs but those map to no stdenv system.
# .github/workflows/nix-release.yml runs a daily lag-check: when the latest
# GitHub release outpaces `version` here, it prefetches new SRI hashes and
# opens a PR — no manual editing required. (Scheduled rather than
# release-triggered because releases are created with GITHUB_TOKEN, which
# does not start new workflow runs.) To expose more systems, add entries
# here and a matching line to the workflow's ASSET_MAP.
assets = {
"x86_64-linux" = {
file = "prek-x86_64-unknown-linux-gnu.tar.gz";
sha256 = "sha256-3IbhjlMlFt1inuYhq3a8TEdhBSIZsn468eR8v5pxonA=";
};
"aarch64-linux" = {
file = "prek-aarch64-unknown-linux-gnu.tar.gz";
sha256 = "sha256-akFDf9aGQd556qw9bdZmf6OFEsk6c/ZhombeKxJVexs=";
};
"x86_64-darwin" = {
file = "prek-x86_64-apple-darwin.tar.gz";
sha256 = "sha256-sK/Iu+pp1hu/5JEAOU35nu0VqcRnWwbJk2QX5lqoixY=";
};
"aarch64-darwin" = {
file = "prek-aarch64-apple-darwin.tar.gz";
sha256 = "sha256-7Ukgdi8OPbBxY8Q3r2IqHUkF4a1wU2kqSVVRuc6SVJ8=";
};
};

systems = builtins.attrNames assets;
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);

prekFor = system: let
pkgs = nixpkgs.legacyPackages.${system};
asset = assets.${system};
in pkgs.stdenv.mkDerivation {
pname = "prek";
inherit version;

src = pkgs.fetchurl {
url = "https://github.com/j178/prek/releases/download/v${version}/${asset.file}";
sha256 = asset.sha256;
};

sourceRoot = ".";

nativeBuildInputs = pkgs.lib.optionals pkgs.stdenv.isLinux [ pkgs.autoPatchelfHook ];
buildInputs = pkgs.lib.optionals pkgs.stdenv.isLinux [ pkgs.stdenv.cc.cc.lib ];

dontConfigure = true;
dontBuild = true;

installPhase = ''
runHook preInstall
mkdir -p "$out/bin"
cp prek-*/prek "$out/bin/prek"
chmod +x "$out/bin/prek"
runHook postInstall
'';

meta = with pkgs.lib; {
description = "Better pre-commit, re-engineered in Rust";
homepage = "https://github.com/j178/prek";
downloadPage = "https://github.com/j178/prek/releases";
license = licenses.mit;
mainProgram = "prek";
platforms = systems;
sourceProvenance = [ sourceTypes.binaryNativeCode ];
};
};
in {
packages = forAllSystems (system: rec {
prek = prekFor system;
default = prek;
});

apps = forAllSystems (system: {
prek = {
type = "app";
program = "${prekFor system}/bin/prek";
};
default = {
type = "app";
program = "${prekFor system}/bin/prek";
};
});
};
}
Loading