name: Eval on: pull_request_target: types: [opened, ready_for_review, synchronize, reopened] push: # Keep this synced with ci/request-reviews/dev-branches.txt branches: - master - staging - release-* - staging-* - haskell-updates - python-updates permissions: {} jobs: get-merge-commit: uses: ./.github/workflows/get-merge-commit.yml attrs: name: Attributes runs-on: ubuntu-24.04 needs: get-merge-commit if: needs.get-merge-commit.outputs.mergedSha outputs: targetSha: ${{ steps.targetSha.outputs.targetSha }} systems: ${{ steps.systems.outputs.systems }} steps: - name: Check out the PR at the test merge commit uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ needs.get-merge-commit.outputs.mergedSha }} fetch-depth: 2 path: nixpkgs - name: Determine target commit if: github.event_name == 'pull_request_target' id: targetSha run: | targetSha=$(git -C nixpkgs rev-parse HEAD^1) echo "targetSha=$targetSha" >> "$GITHUB_OUTPUT" - name: Install Nix uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 with: extra_nix_config: sandbox = true - name: Evaluate the list of all attributes and get the systems matrix id: systems run: | nix-build nixpkgs/ci -A eval.attrpathsSuperset echo "systems=$(> "$GITHUB_OUTPUT" - name: Upload the list of all attributes uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: name: paths path: result/* eval-aliases: name: Eval nixpkgs with aliases enabled runs-on: ubuntu-24.04 needs: [ get-merge-commit ] steps: - name: Check out the PR at the test merge commit uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ needs.get-merge-commit.outputs.mergedSha }} path: nixpkgs - name: Install Nix uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 with: extra_nix_config: sandbox = true - name: Query nixpkgs with aliases enabled to check for basic syntax errors run: | time nix-env -I ./nixpkgs -f ./nixpkgs -qa '*' --option restrict-eval true --option allow-import-from-derivation false >/dev/null outpaths: name: Outpaths runs-on: ubuntu-24.04 needs: [ attrs, get-merge-commit ] strategy: fail-fast: false matrix: system: ${{ fromJSON(needs.attrs.outputs.systems) }} steps: - name: Enable swap run: | sudo fallocate -l 10G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile - name: Download the list of all attributes uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: paths path: paths - name: Check out the PR at the test merge commit uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ needs.get-merge-commit.outputs.mergedSha }} path: nixpkgs - name: Install Nix uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 with: extra_nix_config: sandbox = true - name: Evaluate the ${{ matrix.system }} output paths for all derivation attributes env: MATRIX_SYSTEM: ${{ matrix.system }} run: | nix-build nixpkgs/ci -A eval.singleSystem \ --argstr evalSystem "$MATRIX_SYSTEM" \ --arg attrpathFile ./paths/paths.json \ --arg chunkSize 10000 # If it uses too much memory, slightly decrease chunkSize - name: Upload the output paths and eval stats uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: name: intermediate-${{ matrix.system }} path: result/* process: name: Process runs-on: ubuntu-24.04 needs: [ outpaths, attrs, get-merge-commit ] outputs: targetRunId: ${{ steps.targetRunId.outputs.targetRunId }} steps: - name: Download output paths and eval stats for all systems uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: pattern: intermediate-* path: intermediate - name: Check out the PR at the test merge commit uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ needs.get-merge-commit.outputs.mergedSha }} fetch-depth: 2 path: nixpkgs - name: Install Nix uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 with: extra_nix_config: sandbox = true - name: Combine all output paths and eval stats run: | nix-build nixpkgs/ci -A eval.combine \ --arg resultsDir ./intermediate \ -o prResult - name: Upload the combined results uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: name: result path: prResult/* - name: Get target run id if: needs.attrs.outputs.targetSha id: targetRunId run: | # Get the latest eval.yml workflow run for the PR's target commit if ! run=$(gh api --method GET /repos/"$REPOSITORY"/actions/workflows/eval.yml/runs \ -f head_sha="$TARGET_SHA" -f event=push \ --jq '.workflow_runs | sort_by(.run_started_at) | .[-1]') \ || [[ -z "$run" ]]; then echo "Could not find an eval.yml workflow run for $TARGET_SHA, cannot make comparison" exit 1 fi echo "Comparing against $(jq .html_url <<< "$run")" runId=$(jq .id <<< "$run") conclusion=$(jq -r .conclusion <<< "$run") while [[ "$conclusion" == null || "$conclusion" == "" ]]; do echo "Workflow not done, waiting 10 seconds before checking again" sleep 10 conclusion=$(gh api /repos/"$REPOSITORY"/actions/runs/"$runId" --jq '.conclusion') done if [[ "$conclusion" != "success" ]]; then echo "Workflow was not successful (conclusion: $conclusion), cannot make comparison" exit 1 fi echo "targetRunId=$runId" >> "$GITHUB_OUTPUT" env: REPOSITORY: ${{ github.repository }} TARGET_SHA: ${{ needs.attrs.outputs.targetSha }} GH_TOKEN: ${{ github.token }} - uses: actions/download-artifact@v4 if: steps.targetRunId.outputs.targetRunId with: name: result path: targetResult github-token: ${{ github.token }} run-id: ${{ steps.targetRunId.outputs.targetRunId }} - name: Compare against the target branch if: steps.targetRunId.outputs.targetRunId run: | git -C nixpkgs worktree add ../target ${{ needs.attrs.outputs.targetSha }} git -C nixpkgs diff --name-only ${{ needs.attrs.outputs.targetSha }} \ | jq --raw-input --slurp 'split("\n")[:-1]' > touched-files.json # Use the target branch to get accurate maintainer info nix-build target/ci -A eval.compare \ --arg beforeResultDir ./targetResult \ --arg afterResultDir ./prResult \ --arg touchedFilesJson ./touched-files.json \ -o comparison cat comparison/step-summary.md >> "$GITHUB_STEP_SUMMARY" - name: Upload the combined results if: steps.targetRunId.outputs.targetRunId uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: name: comparison path: comparison/* # Separate job to have a very tightly scoped PR write token tag: name: Tag runs-on: ubuntu-24.04 needs: [ attrs, process ] if: needs.process.outputs.targetRunId permissions: pull-requests: write statuses: write steps: # See ./codeowners-v2.yml, reuse the same App because we need the same permissions # Can't use the token received from permissions above, because it can't get enough permissions - uses: actions/create-github-app-token@21cfef2b496dd8ef5b904c159339626a10ad380e # v1.11.6 id: app-token with: app-id: ${{ vars.OWNER_APP_ID }} private-key: ${{ secrets.OWNER_APP_PRIVATE_KEY }} - name: Download process result uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: comparison path: comparison - name: Install Nix uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 # Important: This workflow job runs with extra permissions, # so we need to make sure to not run untrusted code from PRs - name: Check out Nixpkgs at the base commit uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ needs.attrs.outputs.targetSha }} path: base sparse-checkout: ci - name: Build the requestReviews derivation run: nix-build base/ci -A requestReviews - name: Labelling pull request run: | # Get all currently set rebuild labels gh api \ /repos/"$REPOSITORY"/issues/"$NUMBER"/labels \ --jq '.[].name | select(startswith("10.rebuild"))' \ | sort > before # And the labels that should be there jq -r '.labels[]' comparison/changed-paths.json \ | sort > after # Remove the ones not needed anymore while read -r toRemove; do echo "Removing label $toRemove" gh api \ --method DELETE \ /repos/"$REPOSITORY"/issues/"$NUMBER"/labels/"$toRemove" done < <(comm -23 before after) # And add the ones that aren't set already while read -r toAdd; do echo "Adding label $toAdd" gh api \ --method POST \ /repos/"$REPOSITORY"/issues/"$NUMBER"/labels \ -f "labels[]=$toAdd" done < <(comm -13 before after) env: GH_TOKEN: ${{ github.token }} REPOSITORY: ${{ github.repository }} NUMBER: ${{ github.event.number }} - name: Add eval summary to commit statuses if: ${{ github.event_name == 'pull_request_target' }} run: | description=$(jq -r ' "Package: added " + (.attrdiff.added | length | tostring) + ", removed " + (.attrdiff.removed | length | tostring) + ", changed " + (.attrdiff.changed | length | tostring) + ", Rebuild: linux " + (.rebuildCountByKernel.linux | tostring) + ", darwin " + (.rebuildCountByKernel.darwin | tostring) '