/ .github / workflows / nix.yml
nix.yml
  1  name: Nix
  2  
  3  on:
  4    push:
  5      branches: [main]
  6    pull_request:
  7  
  8  permissions:
  9    contents: read
 10    pull-requests: write
 11  
 12  concurrency:
 13    group: nix-${{ github.ref }}
 14    cancel-in-progress: true
 15  
 16  jobs:
 17    nix:
 18      strategy:
 19        matrix:
 20          os: [ubuntu-latest, macos-latest]
 21      runs-on: ${{ matrix.os }}
 22      timeout-minutes: 30
 23      steps:
 24        - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
 25        - uses: ./.github/actions/nix-setup
 26          with:
 27            cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }}
 28  
 29        - name: Resolve head SHA
 30          if: github.event_name == 'pull_request'
 31          id: sha
 32          shell: bash
 33          run: |
 34            FULL="${{ github.event.pull_request.head.sha || github.sha }}"
 35            echo "full=$FULL" >> "$GITHUB_OUTPUT"
 36            echo "short=${FULL:0:7}" >> "$GITHUB_OUTPUT"
 37  
 38        - name: Check flake
 39          id: flake
 40          if: runner.os == 'Linux'
 41          continue-on-error: true
 42          run: nix flake check --print-build-logs
 43  
 44        - name: Build package
 45          id: build
 46          if: runner.os == 'Linux'
 47          continue-on-error: true
 48          run: nix build --print-build-logs
 49  
 50        # When the real Nix build fails, run a targeted diagnostic to see if
 51        # the failure is specifically a stale npm lockfile hash in one of the
 52        # known npm subpackages (tui / web).  This avoids surfacing a generic
 53        # "build failed" message when the fix is a single known command.
 54        - name: Diagnose npm lockfile hashes
 55          id: hash_check
 56          if: (steps.flake.outcome == 'failure' || steps.build.outcome == 'failure') && runner.os == 'Linux'
 57          continue-on-error: true
 58          env:
 59            LINK_SHA: ${{ steps.sha.outputs.full }}
 60          run: nix run .#fix-lockfiles -- --check
 61  
 62        # If fix-lockfiles itself crashes (infrastructure blip, cache throttle,
 63        # etc.) it won't set stale=true/false.  Treat that as a distinct failure
 64        # mode rather than silently ignoring it.
 65        - name: Fail if hash check crashed without reporting
 66          if: steps.hash_check.outcome == 'failure' && steps.hash_check.outputs.stale != 'true' && steps.hash_check.outputs.stale != 'false'
 67          run: |
 68            echo "::error::fix-lockfiles exited without reporting stale status — likely an infrastructure or script failure"
 69            exit 1
 70  
 71        - name: Post sticky PR comment (stale hashes)
 72          if: steps.hash_check.outputs.stale == 'true' && github.event_name == 'pull_request'
 73          uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728  # v2.9.1
 74          with:
 75            header: nix-lockfile-check
 76            message: |
 77              ### ⚠️ npm lockfile hash out of date
 78  
 79              Checked against commit [`${{ steps.sha.outputs.short }}`](${{ github.server_url }}/${{ github.repository }}/commit/${{ steps.sha.outputs.full }}) (PR head at check time).
 80  
 81              The `hash = "sha256-..."` line in these nix files no longer matches the committed `package-lock.json`:
 82  
 83              ${{ steps.hash_check.outputs.report }}
 84  
 85              #### Apply the fix
 86  
 87              - [ ] **Apply lockfile fix** — tick to push a commit with the correct hashes to this PR branch
 88              - Or [run the Nix Lockfile Fix workflow](${{ github.server_url }}/${{ github.repository }}/actions/workflows/nix-lockfile-fix.yml) manually (pass PR `#${{ github.event.pull_request.number }}`)
 89              - Or locally: `nix run .#fix-lockfiles` and commit the diff
 90  
 91        # Clear the sticky comment when either the build passed outright (no
 92        # hash check needed) or the hash check explicitly returned stale=false
 93        # (build failed for a non-hash reason).
 94        - name: Clear sticky PR comment (resolved)
 95          if: |
 96            github.event_name == 'pull_request' &&
 97            runner.os == 'Linux' &&
 98            (steps.hash_check.outputs.stale == 'false' ||
 99             (steps.flake.outcome == 'success' && steps.build.outcome == 'success'))
100          uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728  # v2.9.1
101          with:
102            header: nix-lockfile-check
103            delete: true
104  
105        - name: Final fail if build or flake failed
106          if: steps.flake.outcome == 'failure' || steps.build.outcome == 'failure'
107          run: |
108            if [ "${{ steps.hash_check.outputs.stale }}" == "true" ]; then
109              echo "::error::Nix build failed due to stale npm lockfile hash. Run: nix run .#fix-lockfiles"
110            else
111              echo "::error::Nix build/flake check failed. See logs above."
112            fi
113            exit 1
114  
115        - name: Evaluate flake (macOS)
116          if: runner.os == 'macOS'
117          run: nix flake show --json > /dev/null