review #457084 #159
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: review | |
| run-name: "review #${{ inputs.pr }}${{ inputs.extra-args && format(' ({0})', inputs.extra-args) || '' }}" | |
| permissions: {} | |
| env: | |
| PR_NUMBER: ${{ inputs.pr }} | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| pr: | |
| description: "Pull Request Number" | |
| required: true | |
| type: string | |
| x86_64-linux: | |
| description: "Run on x86_64-linux" | |
| required: true | |
| type: boolean | |
| default: true | |
| aarch64-linux: | |
| description: "Run on aarch64-linux" | |
| required: true | |
| type: boolean | |
| default: true | |
| x86_64-darwin: | |
| description: "Run on x86_64-darwin" | |
| required: true | |
| type: choice | |
| default: yes_sandbox_relaxed | |
| options: | |
| - "no" | |
| - yes_sandbox_false | |
| - yes_sandbox_relaxed | |
| - yes_sandbox_true | |
| aarch64-darwin: | |
| description: "Run on aarch64-darwin" | |
| required: true | |
| type: choice | |
| default: yes_sandbox_relaxed | |
| options: | |
| - "no" | |
| - yes_sandbox_false | |
| - yes_sandbox_relaxed | |
| - yes_sandbox_true | |
| extra-args: | |
| description: "nixpkgs-review extra args" | |
| required: false | |
| type: string | |
| push-to-cache: | |
| description: "Push to cache" | |
| required: true | |
| type: boolean | |
| default: true | |
| upterm: | |
| description: "Start upterm session after nixpkgs-review" | |
| required: true | |
| type: boolean | |
| default: false | |
| post-result: | |
| description: "Post Result" | |
| required: true | |
| type: boolean | |
| default: true | |
| on-success: | |
| description: "What to do on review success" | |
| required: true | |
| type: choice | |
| default: nothing | |
| options: | |
| - nothing | |
| - mark_as_ready | |
| - approve | |
| - merge | |
| jobs: | |
| prepare: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| pr: ${{ steps.pr.outputs.pr }} | |
| head: ${{ steps.pr.outputs.head }} | |
| merge: ${{ steps.pr.outputs.merge }} | |
| author_id: ${{ steps.pr.outputs.author_id }} | |
| steps: | |
| - name: get pr | |
| id: pr | |
| run: | | |
| while true; do | |
| pr="$(gh api "/repos/NixOS/nixpkgs/pulls/$PR_NUMBER")" | |
| jq -e '.mergeable_state == "unknown" and (.merged | not)' <<< "$pr" > /dev/null || break | |
| echo "mergeable state not known yet, retrying..." | |
| sleep 2 | |
| done | |
| jq <<< "$pr" | |
| if [[ "$(jq '.merged or .mergeable' <<< "$pr")" != "true" ]]; then | |
| echo "::error::PR is not mergeable" | |
| exit 1 | |
| fi | |
| echo "pr=$pr" >> "$GITHUB_OUTPUT" | |
| echo "head=$(jq -r '.head.sha' <<< "$pr")" >> "$GITHUB_OUTPUT" | |
| echo "merge=$(jq -r '.merge_commit_sha' <<< "$pr")" >> "$GITHUB_OUTPUT" | |
| echo "author_id=$(jq -r '.user.id' <<< "$pr")" >> "$GITHUB_OUTPUT" | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| review: | |
| needs: [prepare] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| system: | |
| - x86_64-linux | |
| - aarch64-linux | |
| - x86_64-darwin | |
| - aarch64-darwin | |
| exclude: | |
| - system: ${{ !inputs.x86_64-linux && 'x86_64-linux' || '' }} | |
| - system: ${{ !inputs.aarch64-linux && 'aarch64-linux' || '' }} | |
| - system: ${{ inputs.x86_64-darwin == 'no' && 'x86_64-darwin' || '' }} | |
| - system: ${{ inputs.aarch64-darwin == 'no' && 'aarch64-darwin' || '' }} | |
| runs-on: >- | |
| ${{ (matrix.system == 'x86_64-linux' && 'ubuntu-latest') | |
| || (matrix.system == 'aarch64-linux' && 'ubuntu-24.04-arm') | |
| || (matrix.system == 'x86_64-darwin' && 'macos-latest') | |
| || (matrix.system == 'aarch64-darwin' && 'macos-latest') }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| sparse-checkout: | | |
| .github/actions | |
| flake.lock | |
| flake.nix | |
| - name: setup nix | |
| uses: ./.github/actions/setup-nix | |
| with: | |
| extra-nix-config: ${{ vars.EXTRA_NIX_CONFIG }} | |
| system: ${{ matrix.system }} | |
| sandbox: ${{ | |
| (matrix.system == 'x86_64-darwin' && inputs.x86_64-darwin == 'yes_sandbox_false' | |
| || matrix.system == 'aarch64-darwin' && inputs.aarch64-darwin == 'yes_sandbox_false') && 'false' | |
| || (matrix.system == 'x86_64-darwin' && inputs.x86_64-darwin == 'yes_sandbox_relaxed' | |
| || matrix.system == 'aarch64-darwin' && inputs.aarch64-darwin == 'yes_sandbox_relaxed') && 'relaxed' | |
| || 'true' }} | |
| - name: install packages | |
| run: | | |
| pkgs=(coreutils nixpkgs-review jq gnused) | |
| if [[ ${{ inputs.push-to-cache && vars.ATTIC_SERVER != '' && vars.ATTIC_CACHE != '' }} = true ]]; then | |
| pkgs+=(attic-client) | |
| elif [[ ${{ inputs.push-to-cache && vars.CACHIX_CACHE != '' }} = true ]]; then | |
| pkgs+=(cachix) | |
| fi | |
| nix profile add "${pkgs[@]/#/.#}" | |
| - name: clone nixpkgs | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: NixOS/nixpkgs | |
| path: nixpkgs | |
| persist-credentials: false | |
| - name: run nixpkgs-review ${{ inputs.extra-args }} | |
| run: | | |
| nixpkgs-review -- \ | |
| pr ${PR_NUMBER} \ | |
| --no-shell \ | |
| --no-exit-status \ | |
| --no-headers \ | |
| --print-result \ | |
| --build-args="-L" \ | |
| --pr-json="$PR_JSON" \ | |
| $EXTRA_ARGS | |
| working-directory: nixpkgs | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| EXTRA_ARGS: ${{ inputs.extra-args }} | |
| PR_JSON: ${{ needs.prepare.outputs.pr }} | |
| - name: push results to cache | |
| if: ${{ inputs.push-to-cache && ((vars.ATTIC_SERVER != '' && vars.ATTIC_CACHE != '') || vars.CACHIX_CACHE != '') }} | |
| run: | | |
| set -ex | |
| (realpath -qe ~/.cache/nixpkgs-review/pr-${PR_NUMBER}/results/* || true) > paths | |
| [[ -s paths ]] || exit 0 | |
| if [[ ${{ vars.ATTIC_SERVER != '' && vars.ATTIC_CACHE != '' }} = true ]]; then | |
| attic login default "$ATTIC_SERVER" "$ATTIC_TOKEN" | |
| if ! attic cache info "$ATTIC_CACHE"; then | |
| echo "::error::attic returned an error" | |
| exit 0 | |
| fi | |
| attic push --stdin "$ATTIC_CACHE" < paths | |
| info=$(curl -f -H "Authorization: Bearer ${ATTIC_TOKEN}" "${ATTIC_SERVER}_api/v1/cache-config/${ATTIC_CACHE}") | |
| substituter_endpoint=$(jq -r .substituter_endpoint <<< "$info") | |
| public_key=$(jq -r .public_key <<< "$info") | |
| is_public=$(jq -r .is_public <<< "$info") | |
| elif [[ ${{ vars.CACHIX_CACHE != '' }} = true ]]; then | |
| [[ -n "$CACHIX_SIGNING_KEY" ]] || unset CACHIX_SIGNING_KEY | |
| cachix push "$CACHIX_CACHE" < paths | |
| info=$(curl -f -H "Authorization: Bearer ${CACHIX_AUTH_TOKEN}" "https://app.cachix.org/api/v1/cache/${CACHIX_CACHE}") | |
| substituter_endpoint=$(jq -r .uri <<< "$info") | |
| public_key=$(jq -r '.publicSigningKeys[]' <<< "$info") | |
| is_public=$(jq -r .isPublic <<< "$info") | |
| fi | |
| [[ "$is_public" = true ]] || exit 0 | |
| echo "nix-store -r --add-root nixpkgs-pr-${PR_NUMBER}-${{ matrix.system }} \\" >> fetch_cmd | |
| echo " --option binary-caches 'https://cache.nixos.org/ $substituter_endpoint' \\" >> fetch_cmd | |
| echo " --option trusted-public-keys '" >> fetch_cmd | |
| echo " cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" >> fetch_cmd | |
| echo " $public_key" >> fetch_cmd | |
| echo -n " '" >> fetch_cmd | |
| for p in $(cat paths); do | |
| echo -e " \\" >> fetch_cmd | |
| echo -n " $p" >> fetch_cmd | |
| done | |
| env: | |
| ATTIC_SERVER: ${{ vars.ATTIC_SERVER }} | |
| ATTIC_CACHE: ${{ vars.ATTIC_CACHE }} | |
| ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }} | |
| CACHIX_CACHE: ${{ vars.CACHIX_CACHE }} | |
| CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} | |
| CACHIX_SIGNING_KEY: ${{ secrets.CACHIX_SIGNING_KEY }} | |
| - name: start upterm session | |
| if: ${{ inputs.upterm }} | |
| uses: owenthereal/action-upterm@v1 | |
| with: | |
| limit-access-to-actor: true | |
| - name: generate report | |
| id: report | |
| run: | | |
| touch fetch_cmd | |
| cat fetch_cmd | |
| dir=~/.cache/nixpkgs-review/pr-${PR_NUMBER} | |
| if [[ "$OS" != "Linux" ]]; then | |
| sandbox=$(nix config show sandbox) | |
| sed -i '/^###/s/$/ (sandbox = '"$sandbox"')/' "$dir/report.md" | |
| fi | |
| if ! [[ -s "$dir/report.md" ]]; then | |
| echo -e "\n---" >> "$dir/report.md" | |
| echo "### \`${{ matrix.system }}\`" >> "$dir/report.md" | |
| echo ":white_check_mark: *No rebuilds*" >> "$dir/report.md" | |
| fi | |
| cat $dir/report.md | |
| jq -c '.+{$md, $fetch_cmd}' $dir/report.json \ | |
| --rawfile md $dir/report.md \ | |
| --rawfile fetch_cmd fetch_cmd \ | |
| > report_${{ matrix.system }}.json | |
| env: | |
| OS: ${{ runner.os }} | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: report_${{ matrix.system }}.json | |
| path: report_${{ matrix.system }}.json | |
| if-no-files-found: error | |
| report: | |
| runs-on: ubuntu-latest | |
| needs: [prepare, review] | |
| outputs: | |
| success: ${{ steps.report.outputs.success }} | |
| steps: | |
| - uses: actions/download-artifact@v5 | |
| with: | |
| merge-multiple: true | |
| - name: generate report | |
| id: report | |
| run: | | |
| systems=(x86_64-linux aarch64-linux x86_64-darwin aarch64-darwin) | |
| for system in "${systems[@]}"; do | |
| [[ -s "report_${system}.json" ]] || continue | |
| jq -j '.md' "report_${system}.json" > "report_${system}.md" | |
| jq -j '.fetch_cmd' "report_${system}.json" > "fetch_cmd_${system}" | |
| done | |
| echo -e "## \`nixpkgs-review\` result\n" >> report.md | |
| echo -e "Generated using [\`nixpkgs-review-gha\`](https://github.com/Defelo/nixpkgs-review-gha)\n" >> report.md | |
| echo -e "Command: \`nixpkgs-review pr ${PR_NUMBER}${EXTRA_ARGS:+ $EXTRA_ARGS}\`" >> report.md | |
| echo -e "Commit: [\`$HEAD\`](https://github.com/NixOS/nixpkgs/commit/$HEAD) ([subsequent changes](https://github.com/NixOS/nixpkgs/compare/$HEAD..pull/$PR_NUMBER/head))" >> report.md | |
| echo -e "Merge: [\`$MERGE\`](https://github.com/NixOS/nixpkgs/commit/$MERGE)\n" >> report.md | |
| echo -e "Logs: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n" >> report.md | |
| for system in "${systems[@]}"; do | |
| [[ -s "fetch_cmd_${system}" ]] || continue | |
| echo -e "<li><details><summary><code>$system</code></summary>\n\n\`\`\`shell" >> cache.md | |
| cat "fetch_cmd_${system}" >> cache.md | |
| echo -e "\n\`\`\`\n</details></li>" >> cache.md | |
| done | |
| if [[ -s cache.md ]]; then | |
| echo -e "<details><summary>Download packages from cache:</summary><ul>" >> report.md | |
| cat cache.md >> report.md | |
| echo -e "</ul></details>\n" >> report.md | |
| fi | |
| for system in "${systems[@]}"; do | |
| [[ -s "report_${system}.md" ]] || continue | |
| cat "report_${system}.md" >> report.md | |
| done | |
| cat report.md | |
| echo success=$(jq -s 'all(.[].result[]; .failed==[])' report_*.json) >> "$GITHUB_OUTPUT" | |
| sed '1s|$| for [#'"$PR_NUMBER"'](https://github.com/NixOS/nixpkgs/pull/'"$PR_NUMBER"')|' report.md >> $GITHUB_STEP_SUMMARY | |
| env: | |
| HEAD: ${{ needs.prepare.outputs.head }} | |
| MERGE: ${{ needs.prepare.outputs.merge }} | |
| EXTRA_ARGS: ${{ inputs.extra-args }} | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: report.md | |
| path: report.md | |
| if-no-files-found: error | |
| post-result: | |
| runs-on: ubuntu-latest | |
| needs: [prepare, report] | |
| if: ${{ inputs.post-result || inputs.on-success != 'nothing' }} | |
| steps: | |
| - uses: actions/download-artifact@v5 | |
| with: | |
| name: report.md | |
| - name: post comment | |
| if: ${{ inputs.post-result }} | |
| run: | | |
| if [[ -n "$GH_TOKEN" ]]; then | |
| gh pr -R NixOS/nixpkgs comment ${PR_NUMBER} -F report.md | |
| fi | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
| - name: mark pull request as ready for review | |
| if: ${{ needs.report.outputs.success == 'true' && inputs.on-success == 'mark_as_ready' }} | |
| run: | | |
| if [[ -z "$GH_TOKEN" ]]; then | |
| echo "::error::Cannot mark the PR as ready for review because no GH_TOKEN has been configured." | |
| exit 1 | |
| fi | |
| gh pr -R NixOS/nixpkgs ready ${PR_NUMBER} | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
| - name: approve pull request | |
| if: ${{ needs.report.outputs.success == 'true' && (inputs.on-success == 'approve' || inputs.on-success == 'merge') }} | |
| run: | | |
| if [[ -z "$GH_TOKEN" ]]; then | |
| echo "::error::Cannot approve the PR because no GH_TOKEN has been configured." | |
| exit 1 | |
| fi | |
| user_id="$(gh api /user --jq .id)" | |
| if [[ "$user_id" != "$PR_AUTHOR_ID" ]]; then | |
| gh pr -R NixOS/nixpkgs review ${PR_NUMBER} --approve -b "Approved automatically following the successful run of \`nixpkgs-review\`." | |
| elif [[ "${{ inputs.on-success }}" = "approve" ]]; then | |
| echo "::error::You cannot approve your own pull request." | |
| exit 1 | |
| fi | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
| PR_AUTHOR_ID: ${{ needs.prepare.outputs.author_id }} | |
| - name: merge pull request | |
| if: ${{ needs.report.outputs.success == 'true' && inputs.on-success == 'merge' }} | |
| run: | | |
| if [[ -z "$GH_TOKEN" ]]; then | |
| echo "::error::Cannot merge the PR because no GH_TOKEN has been configured." | |
| exit 1 | |
| fi | |
| is_committer="$(gh api /repos/NixOS/nixpkgs --jq .permissions.push)" | |
| if [[ "$is_committer" = true ]]; then | |
| gh pr -R NixOS/nixpkgs merge ${PR_NUMBER} --merge --match-head-commit "$HEAD" | |
| else | |
| current_head="$(gh api "/repos/NixOS/nixpkgs/pulls/$PR_NUMBER" --jq .head.sha)" | |
| if [[ "$current_head" != "$HEAD" ]]; then | |
| echo "::error::Refusing to merge because the head branch was modified (expected $HEAD, got $current_head instead)" | |
| exit 1 | |
| fi | |
| gh pr -R NixOS/nixpkgs comment ${PR_NUMBER} -b "@NixOS/nixpkgs-merge-bot merge" | |
| fi | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
| HEAD: ${{ needs.prepare.outputs.head }} |