From 89308730ab05f4c9963a2d78e3e3604c1aea8630 Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Mon, 20 Jul 2026 08:04:44 +1000 Subject: [PATCH] Add scripts/bump-nixpkgs-release.sh flake.nix's nixpkgs.url/home-manager.url can't source a version string from variables.nix -- flake input resolution requires a plain string literal, confirmed empirically (nix flake metadata errors with "expected a string or a path but got a thunk" otherwise). This script is the one-command alternative: bump both release branches in flake.nix via targeted substitution (never a blind repo-wide replace, so it can't collide with stateVersion strings elsewhere), with an upstream branch existence check before writing, plus an optional --tooling flag for codex-maintenance.sh's separately-pinned nixpkgs-fmt/statix fetch. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01La55Nsss8jZ7ZuzUV9mfot --- scripts/bump-nixpkgs-release.sh | 133 ++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100755 scripts/bump-nixpkgs-release.sh diff --git a/scripts/bump-nixpkgs-release.sh b/scripts/bump-nixpkgs-release.sh new file mode 100755 index 0000000..cefa85c --- /dev/null +++ b/scripts/bump-nixpkgs-release.sh @@ -0,0 +1,133 @@ +#!/usr/bin/env bash +# Bumps the NixOS release branch this flake tracks — flake.nix's +# `nixpkgs.url` and `home-manager.url` — in one place, via targeted +# substitution of just those two lines. Deliberately does NOT touch any +# `system.stateVersion` anywhere in the repo: per NixOS's own docs, that +# value must stay fixed at whatever it was on a host's first install (it +# pins on-disk data-format defaults, not "which nixpkgs release am I on"), +# so it's never something a channel bump should follow. +# +# scripts/codex-maintenance.sh's own `nixos-25.11` pin (used only to fetch +# nixpkgs-fmt/statix — see CLAUDE.md) is a separate, independently-versioned +# reference on purpose: it doesn't have to track the flake's own nixpkgs +# input, since the tooling just needs to build, not match. Bump it with +# --tooling if you want it moved too; the default run leaves it alone. +set -euo pipefail + +repo_root="$(cd "$(dirname "$0")/.." && pwd)" +flake_nix="${repo_root}/flake.nix" +maintenance_sh="${repo_root}/scripts/codex-maintenance.sh" +claude_md="${repo_root}/CLAUDE.md" + +usage() { + cat < [--tooling ] + + New NixOS release for flake.nix's nixpkgs.url and + home-manager.url, e.g. 26.11 + --tooling Also bump scripts/codex-maintenance.sh's separate + nixpkgs-fmt/statix pin (and its mention in + CLAUDE.md) to this release. Independent of the + first argument — pass the same value if you want + both in sync, a different one if you don't. + +Examples: + $0 26.11 + $0 26.11 --tooling 26.11 +EOF +} + +release_re='^[0-9]{2}\.(05|11)$' + +if [[ $# -eq 0 || "$1" == "-h" || "$1" == "--help" ]]; then + usage + exit 0 +fi + +new_release="$1" +shift + +tooling_release="" +while [[ $# -gt 0 ]]; do + case "$1" in + --tooling) + tooling_release="${2:?--tooling requires a release argument}" + shift 2 + ;; + *) + echo "Unknown argument: $1" >&2 + usage >&2 + exit 1 + ;; + esac +done + +check_release_format() { + local release="$1" + if [[ ! "$release" =~ $release_re ]]; then + echo "ERROR: '$release' doesn't look like a NixOS release (expected e.g. 26.11)" >&2 + exit 1 + fi +} + +check_branch_exists() { + local repo_url="$1" branch="$2" + echo "Checking '$branch' exists on $repo_url..." + if ! git ls-remote --exit-code --heads "$repo_url" "$branch" >/dev/null; then + echo "ERROR: branch '$branch' not found on $repo_url. Typo, or not cut yet?" >&2 + exit 1 + fi +} + +check_release_format "$new_release" + +current_release="$(grep -oE 'nixos-[0-9]{2}\.[0-9]{2}' "$flake_nix" | head -1 | sed 's/^nixos-//')" +if [[ -z "$current_release" ]]; then + echo "ERROR: couldn't find flake.nix's current nixpkgs release" >&2 + exit 1 +fi + +if [[ "$current_release" == "$new_release" ]]; then + echo "flake.nix is already on $new_release." +else + echo "Bumping flake.nix's nixpkgs/home-manager release: $current_release -> $new_release" + check_branch_exists "https://github.com/NixOS/nixpkgs.git" "nixos-$new_release" + check_branch_exists "https://github.com/nix-community/home-manager.git" "release-$new_release" + + sed -i \ + -e "s|github:NixOS/nixpkgs/nixos-${current_release}|github:NixOS/nixpkgs/nixos-${new_release}|" \ + -e "s|github:nix-community/home-manager/release-${current_release}|github:nix-community/home-manager/release-${new_release}|" \ + "$flake_nix" + + echo "Updated:" + grep -n "nixos-${new_release}\|release-${new_release}" "$flake_nix" +fi + +if [[ -n "$tooling_release" ]]; then + check_release_format "$tooling_release" + + current_tooling_release="$(grep -oE 'nixos-[0-9]{2}\.[0-9]{2}' "$maintenance_sh" | head -1 | sed 's/^nixos-//')" + + if [[ "$current_tooling_release" == "$tooling_release" ]]; then + echo "codex-maintenance.sh's tooling pin is already on $tooling_release." + else + echo "Bumping codex-maintenance.sh's nixpkgs-fmt/statix pin: $current_tooling_release -> $tooling_release" + check_branch_exists "https://github.com/NixOS/nixpkgs.git" "nixos-$tooling_release" + + sed -i "s|github:NixOS/nixpkgs/nixos-${current_tooling_release}|github:NixOS/nixpkgs/nixos-${tooling_release}|g" \ + "$maintenance_sh" + sed -i "s|nixos-${current_tooling_release}|nixos-${tooling_release}|g" \ + "$claude_md" + + echo "Updated:" + grep -n "nixos-${tooling_release}" "$maintenance_sh" "$claude_md" + fi +fi + +echo +echo "flake.lock still points at the old input revisions until refreshed. Either:" +echo " nix flake update nixpkgs home-manager # just these two inputs" +echo " nix flake update # everything — see docs/flake-lock-automation.md" +echo +echo "Then run 'bash scripts/codex-maintenance.sh dry-run' before committing —" +echo "a channel bump can shift option defaults across every host."