ci/parse: init

The nix-parse workflow can now be run locally the same way as in CI.

To do this, the CI's workflow was slightly adjusted. Instead of testing
only the changed files, we're now testing all files in the repository.

This is possible in two ways:

1. By calling nix-instantiate once with all files as arguments. This
will be rather fast, but only the first error is shown before it errors
out.
2. By calling nix-instantiate once for each file. This will be much
slower, but has the advantage that we see all errors at once.

To avoid running the long variant every time, we first do a quick check
with the fast version. If that fails, we run the slower one to report
the errors. This gives us the best of both.

Changed files
+48 -19
.github
workflows
ci
+2 -19
.github/workflows/nix-parse-v2.yml
··· 15 15 needs: get-merge-commit 16 16 if: "needs.get-merge-commit.outputs.mergedSha && !contains(github.event.pull_request.title, '[skip treewide]')" 17 17 steps: 18 - - name: Get list of changed files from PR 19 - env: 20 - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 - run: | 22 - gh api \ 23 - repos/${{ github.repository }}/pulls/${{github.event.number}}/files --paginate \ 24 - | jq --raw-output '.[] | select(.status != "removed" and (.filename | endswith(".nix"))) | .filename' \ 25 - > "$HOME/changed_files" 26 - if [[ -s "$HOME/changed_files" ]]; then 27 - echo "CHANGED_FILES=$HOME/changed_files" > "$GITHUB_ENV" 28 - fi 29 - 30 18 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 31 19 with: 32 20 ref: ${{ needs.get-merge-commit.outputs.mergedSha }} ··· 37 25 extra_nix_config: sandbox = true 38 26 nix_path: nixpkgs=channel:nixpkgs-unstable 39 27 40 - - name: Parse all changed or added nix files 28 + - name: Parse all nix files 41 29 run: | 42 - ret=0 43 - while IFS= read -r file; do 44 - out="$(nix-instantiate --parse "$file")" || { echo "$out" && ret=1; } 45 - done < "$HOME/changed_files" 46 - exit "$ret" 47 - if: ${{ env.CHANGED_FILES && env.CHANGED_FILES != '' }} 30 + nix-build ci -A parse
+3
ci/default.nix
··· 76 76 manual-nixos = (import ../nixos/release.nix { }).manual.${system} or null; 77 77 manual-nixpkgs = (import ../pkgs/top-level/release.nix { }).manual; 78 78 manual-nixpkgs-tests = (import ../pkgs/top-level/release.nix { }).manual.tests; 79 + parse = pkgs.lib.recurseIntoAttrs { 80 + latest = pkgs.callPackage ./parse.nix { nix = pkgs.nixVersions.latest; }; 81 + }; 79 82 shell = import ../shell.nix { inherit nixpkgs system; }; 80 83 }
+43
ci/parse.nix
··· 1 + { 2 + lib, 3 + nix, 4 + runCommand, 5 + }: 6 + let 7 + nixpkgs = 8 + with lib.fileset; 9 + toSource { 10 + root = ../.; 11 + fileset = (fileFilter (file: file.hasExt "nix") ../.); 12 + }; 13 + in 14 + runCommand "nix-parse-${nix.name}" 15 + { 16 + nativeBuildInputs = [ 17 + nix 18 + ]; 19 + } 20 + '' 21 + export NIX_STORE_DIR=$TMPDIR/store 22 + export NIX_STATE_DIR=$TMPDIR/state 23 + 24 + cd "${nixpkgs}" 25 + 26 + # Passes all files to nix-instantiate at once. 27 + # Much faster, but will only show first error. 28 + parse-all() { 29 + find . -type f -iname '*.nix' | xargs -P $(nproc) nix-instantiate --parse >/dev/null 2>/dev/null 30 + } 31 + 32 + # Passes each file separately to nix-instantiate with -n1. 33 + # Much slower, but will show all errors. 34 + parse-each() { 35 + find . -type f -iname '*.nix' | xargs -n1 -P $(nproc) nix-instantiate --parse >/dev/null 36 + } 37 + 38 + if ! parse-all; then 39 + parse-each 40 + fi 41 + 42 + touch $out 43 + ''