From 95b5ef97f34e6acccdec2dcc738e60dd043ab021 Mon Sep 17 00:00:00 2001 From: Fabricio Mera <55803899+fm7-1@users.noreply.github.com> Date: Fri, 1 Aug 2025 10:54:32 -0500 Subject: [PATCH 1/4] maintainers: add fm7-1 --- maintainers/maintainer-list.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index cf10b8a6e0f3a..63f6c639f4a59 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -8504,6 +8504,11 @@ githubId = 74379; name = "Florian Pester"; }; + fm7-1 = { + github = "fm7-1"; + githubId = 55803899; + name = "Fabricio Mera"; + }; fmhoeger = { email = "fmhoeger@mirsem.org"; name = "fmhoeger"; From 2311428669adbfae987112460f4fb6a90fc8aa91 Mon Sep 17 00:00:00 2001 From: Sebastian Estrella <2049686+sestrella@users.noreply.github.com> Date: Fri, 11 Jul 2025 23:45:25 -0500 Subject: [PATCH 2/4] fix: Fix `semantic-release` build Update semantic-release version / Testing on macos-latest Run tests on ubuntu-latest Test with normal Pyhon3 package Add more runners to semantic-release workflow Temporarily remove old workflows --- .github/workflows/backport.yml | 76 ------ .github/workflows/codeowners-v2.yml | 147 ----------- .github/workflows/dismissed-review.yml | 65 ----- .github/workflows/edited.yml | 58 ----- .github/workflows/eval.yml | 255 ------------------- .github/workflows/lint.yml | 105 -------- .github/workflows/periodic-merge-24h.yml | 46 ---- .github/workflows/periodic-merge-6h.yml | 43 ---- .github/workflows/periodic-merge.yml | 63 ----- .github/workflows/pr.yml | 149 ----------- .github/workflows/push.yml | 48 ---- .github/workflows/review-dismissed.yml | 17 -- .github/workflows/reviewers.yml | 144 ----------- .github/workflows/semantic-release.yml | 22 ++ pkgs/by-name/se/semantic-release/package.nix | 7 +- 15 files changed, 26 insertions(+), 1219 deletions(-) delete mode 100644 .github/workflows/backport.yml delete mode 100644 .github/workflows/codeowners-v2.yml delete mode 100644 .github/workflows/dismissed-review.yml delete mode 100644 .github/workflows/edited.yml delete mode 100644 .github/workflows/eval.yml delete mode 100644 .github/workflows/lint.yml delete mode 100644 .github/workflows/periodic-merge-24h.yml delete mode 100644 .github/workflows/periodic-merge-6h.yml delete mode 100644 .github/workflows/periodic-merge.yml delete mode 100644 .github/workflows/pr.yml delete mode 100644 .github/workflows/push.yml delete mode 100644 .github/workflows/review-dismissed.yml delete mode 100644 .github/workflows/reviewers.yml create mode 100644 .github/workflows/semantic-release.yml diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml deleted file mode 100644 index 709d8a6edd8f9..0000000000000 --- a/.github/workflows/backport.yml +++ /dev/null @@ -1,76 +0,0 @@ -# WARNING: -# When extending this action, be aware that $GITHUB_TOKEN allows write access to -# the GitHub repository. This means that it should not evaluate user input in a -# way that allows code injection. - -name: Backport - -on: - pull_request_target: - types: [closed, labeled] - -permissions: - contents: read - issues: write - pull-requests: write - -defaults: - run: - shell: bash - -jobs: - backport: - name: Backport Pull Request - if: vars.NIXPKGS_CI_APP_ID && github.event.pull_request.merged == true && (github.event.action != 'labeled' || startsWith(github.event.label.name, 'backport')) - runs-on: ubuntu-24.04-arm - steps: - # Use a GitHub App to create the PR so that CI gets triggered - # The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs - - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - id: app-token - with: - app-id: ${{ vars.NIXPKGS_CI_APP_ID }} - private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }} - permission-contents: write - permission-pull-requests: write - - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ github.event.pull_request.head.sha }} - token: ${{ steps.app-token.outputs.token }} - - - name: Log current API rate limits - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: gh api /rate_limit | jq - - - name: Create backport PRs - id: backport - uses: korthout/backport-action@0193454f0c5947491d348f33a275c119f30eb736 # v3.2.1 - with: - # Config README: https://github.com/korthout/backport-action#backport-action - copy_labels_pattern: 'severity:\ssecurity' - github_token: ${{ steps.app-token.outputs.token }} - pull_description: |- - Bot-based backport to `${target_branch}`, triggered by a label in #${pull_number}. - - * [ ] Before merging, ensure that this backport is [acceptable for the release](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#changes-acceptable-for-releases). - * Even as a non-committer, if you find that it is not acceptable, leave a comment. - - - name: Log current API rate limits - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: gh api /rate_limit | jq - - - name: "Add 'has: port to stable' label" - if: steps.backport.outputs.created_pull_numbers != '' - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - # Not using the app on purpose to avoid triggering another workflow run after adding this label. - script: | - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - labels: [ '8.has: port to stable' ] - }) diff --git a/.github/workflows/codeowners-v2.yml b/.github/workflows/codeowners-v2.yml deleted file mode 100644 index 97fcfc63bdd2c..0000000000000 --- a/.github/workflows/codeowners-v2.yml +++ /dev/null @@ -1,147 +0,0 @@ -# This workflow depends on two GitHub Apps with the following permissions: -# - For checking code owners: -# - Permissions: -# - Repository > Administration: read-only -# - Organization > Members: read-only -# - Install App on this repository, setting these variables: -# - OWNER_RO_APP_ID (variable) -# - OWNER_RO_APP_PRIVATE_KEY (secret) -# - For requesting code owners: -# - Permissions: -# - Repository > Administration: read-only -# - Organization > Members: read-only -# - Repository > Pull Requests: read-write -# - Install App on this repository, setting these variables: -# - OWNER_APP_ID (variable) -# - OWNER_APP_PRIVATE_KEY (secret) -# -# This split is done because checking code owners requires handling untrusted PR input, -# while requesting code owners requires PR write access, and those shouldn't be mixed. -# -# Note that the latter is also used for ./eval.yml requesting reviewers. - -name: Codeowners v2 - -on: - pull_request: - paths: - - .github/workflows/codeowners-v2.yml - pull_request_target: - types: [opened, ready_for_review, synchronize, reopened] - -concurrency: - group: codeowners-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} - cancel-in-progress: true - -permissions: {} - -defaults: - run: - shell: bash - -env: - OWNERS_FILE: ci/OWNERS - # Don't do anything on draft PRs - DRY_MODE: ${{ github.event.pull_request.draft && '1' || '' }} - -jobs: - # Check that code owners is valid - check: - name: Check - runs-on: ubuntu-24.04-arm - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - sparse-checkout: .github/actions - - name: Check if the PR can be merged and checkout the merge and target commits - uses: ./.github/actions/get-merge-commit - with: - merged-as-untrusted: true - target-as-trusted: true - - - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 - - - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 - with: - # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere. - name: nixpkgs-ci - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - - - name: Build codeowners validator - run: nix-build trusted/ci -A codeownersValidator - - - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - if: github.event_name == 'pull_request_target' && vars.OWNER_RO_APP_ID - id: app-token - with: - app-id: ${{ vars.OWNER_RO_APP_ID }} - private-key: ${{ secrets.OWNER_RO_APP_PRIVATE_KEY }} - permission-administration: read - permission-members: read - - - name: Log current API rate limits - if: steps.app-token.outputs.token - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: gh api /rate_limit | jq - - - name: Validate codeowners - if: steps.app-token.outputs.token - env: - OWNERS_FILE: untrusted/${{ env.OWNERS_FILE }} - GITHUB_ACCESS_TOKEN: ${{ steps.app-token.outputs.token }} - REPOSITORY_PATH: untrusted - OWNER_CHECKER_REPOSITORY: ${{ github.repository }} - # Set this to "notowned,avoid-shadowing" to check that all files are owned by somebody - EXPERIMENTAL_CHECKS: "avoid-shadowing" - run: result/bin/codeowners-validator - - - name: Log current API rate limits - if: steps.app-token.outputs.token - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: gh api /rate_limit | jq - - # Request reviews from code owners - request: - name: Request - runs-on: ubuntu-24.04-arm - steps: - - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 - - # Important: Because we use pull_request_target, this checks out the base branch of the PR, not the PR head. - # This is intentional, because we need to request the review of owners as declared in the base branch. - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - path: trusted - - - name: Build review request package - run: nix-build trusted/ci -A requestReviews - - - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - if: github.event_name == 'pull_request_target' && vars.OWNER_APP_ID - id: app-token - with: - app-id: ${{ vars.OWNER_APP_ID }} - private-key: ${{ secrets.OWNER_APP_PRIVATE_KEY }} - permission-administration: read - permission-members: read - permission-pull-requests: write - - - name: Log current API rate limits - if: steps.app-token.outputs.token - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: gh api /rate_limit | jq - - - name: Request reviews - if: steps.app-token.outputs.token - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: result/bin/request-code-owner-reviews.sh ${{ github.repository }} ${{ github.event.number }} "$OWNERS_FILE" - - - name: Log current API rate limits - if: steps.app-token.outputs.token - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: gh api /rate_limit | jq diff --git a/.github/workflows/dismissed-review.yml b/.github/workflows/dismissed-review.yml deleted file mode 100644 index e8ab48bda0755..0000000000000 --- a/.github/workflows/dismissed-review.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Dismissed review - -on: - workflow_run: - workflows: - - Review dismissed - types: [completed] - -concurrency: - group: dismissed-review-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} - cancel-in-progress: true - -permissions: - pull-requests: write - -defaults: - run: - shell: bash - -jobs: - # The `check-cherry-picks` workflow creates review comments which reviewers - # are encouraged to manually dismiss if they're not relevant. - # When a CI-generated review is dismissed, this job automatically minimizes - # it, preventing it from cluttering the PR. - minimize: - name: Minimize as resolved - runs-on: ubuntu-24.04-arm - steps: - - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - script: | - // PRs from forks don't have any PRs associated by default. - // Thus, we request the PR number with an API call *to* the fork's repo. - // Multiple pull requests can be open from the same head commit, either via - // different base branches or head branches. - const { head_repository, head_sha, repository } = context.payload.workflow_run - await Promise.all( - (await github.paginate(github.rest.repos.listPullRequestsAssociatedWithCommit, { - owner: head_repository.owner.login, - repo: head_repository.name, - commit_sha: head_sha - })) - .filter(pull_request => pull_request.base.repo.id == repository.id) - .map(async (pull_request) => - Promise.all( - (await github.paginate(github.rest.pulls.listReviews, { - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: pull_request.number - })).filter(review => - review.user.login == 'github-actions[bot]' && - review.state == 'DISMISSED' - ).map(review => github.graphql(` - mutation($node_id:ID!) { - minimizeComment(input: { - classifier: RESOLVED, - subjectId: $node_id - }) - { clientMutationId } - }`, - { node_id: review.node_id } - )) - ) - ) - ) diff --git a/.github/workflows/edited.yml b/.github/workflows/edited.yml deleted file mode 100644 index 49fccb5f48ba0..0000000000000 --- a/.github/workflows/edited.yml +++ /dev/null @@ -1,58 +0,0 @@ -# Some workflows depend on the base branch of the PR, but changing the base branch is not included in the default trigger events, which would be `opened`, `synchronize` or `reopened`. -# Instead it causes an `edited` event. -# Since `edited` is also triggered when PR title/body is changed, we use this wrapper workflow, to run the other workflows conditionally only. -# There are already feature requests for adding a `base_changed` event: -# - https://github.com/orgs/community/discussions/35058 -# - https://github.com/orgs/community/discussions/64119 -# -# Instead of adding this to each workflow's pull_request_target event, we trigger this in a separate workflow. -# This has the advantage, that we can actually skip running those jobs for simple edits like changing the title or description. -# The actual trigger happens by closing and re-opening the pull request, which triggers the default pull_request_target events. -# This is much simpler and reliable than other approaches. - -name: "Edited base branch" - -on: - pull_request_target: - types: [edited] - -concurrency: - group: edited-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} - cancel-in-progress: true - -permissions: {} - -defaults: - run: - shell: bash - -jobs: - base: - name: Trigger jobs - runs-on: ubuntu-24.04 - if: github.event.changes.base.ref.from && github.event.changes.base.ref.from != github.event.pull_request.base.ref - steps: - # Use a GitHub App to create the PR so that CI gets triggered - # The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs - # We only need Pull Requests: write here, but the app is also used for backports. - - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - id: app-token - with: - app-id: ${{ vars.NIXPKGS_CI_APP_ID }} - private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }} - permission-pull-requests: write - - - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - github-token: ${{ steps.app-token.outputs.token }} - script: | - function changeState(state) { - return github.rest.pulls.update({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.payload.pull_request.number, - state - }) - } - await changeState('closed') - await changeState('open') diff --git a/.github/workflows/eval.yml b/.github/workflows/eval.yml deleted file mode 100644 index 5999aedcb9382..0000000000000 --- a/.github/workflows/eval.yml +++ /dev/null @@ -1,255 +0,0 @@ -name: Eval - -on: - workflow_call: - inputs: - mergedSha: - required: true - type: string - targetSha: - type: string - systems: - required: true - type: string - secrets: - OWNER_APP_PRIVATE_KEY: - required: false - -permissions: {} - -defaults: - run: - shell: bash - -jobs: - eval: - runs-on: ubuntu-24.04-arm - strategy: - fail-fast: false - matrix: - system: ${{ fromJSON(inputs.systems) }} - name: ${{ matrix.system }} - outputs: - targetRunId: ${{ steps.targetRunId.outputs.targetRunId }} - steps: - - name: Enable swap - run: | - sudo fallocate -l 10G /swap - sudo chmod 600 /swap - sudo mkswap /swap - sudo swapon /swap - - - name: Check out the PR at the test merge commit - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ inputs.mergedSha }} - path: untrusted - - - name: Install Nix - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 - 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 untrusted/ci -A eval.singleSystem \ - --argstr evalSystem "$MATRIX_SYSTEM" \ - --arg chunkSize 10000 \ - --out-link merged - # If it uses too much memory, slightly decrease chunkSize - - - name: Upload the output paths and eval stats - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: merged-${{ matrix.system }} - path: merged/* - - - name: Log current API rate limits - env: - GH_TOKEN: ${{ github.token }} - run: gh api /rate_limit | jq - - - name: Get target run id - if: inputs.targetSha - id: targetRunId - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - env: - MATRIX_SYSTEM: ${{ matrix.system }} - TARGET_SHA: ${{ inputs.targetSha }} - with: - script: | - const system = process.env.MATRIX_SYSTEM - const targetSha = process.env.TARGET_SHA - - let run_id - try { - run_id = (await github.rest.actions.listWorkflowRuns({ - ...context.repo, - workflow_id: 'push.yml', - event: 'push', - head_sha: targetSha - })).data.workflow_runs[0].id - } catch { - throw new Error(`Could not find a push.yml workflow run for ${targetSha}.`) - } - - // Waiting 120 * 5 sec = 10 min. max. - // Eval takes max 5-6 minutes, normally. - for (let i = 0; i < 120; i++) { - const result = await github.rest.actions.listWorkflowRunArtifacts({ - ...context.repo, - run_id, - name: `merged-${system}` - }) - if (result.data.total_count > 0) { - core.setOutput('targetRunId', run_id) - return - } - await new Promise(resolve => setTimeout(resolve, 5000)) - } - // No artifact found at this stage. This usually means that Eval failed on the target branch. - // This should only happen when Eval is broken on the target branch and this PR fixes it. - // Continue without targetRunId to skip the remaining steps, but pass the job. - - - name: Log current API rate limits - env: - GH_TOKEN: ${{ github.token }} - run: gh api /rate_limit | jq - - - uses: actions/download-artifact@v4 - if: steps.targetRunId.outputs.targetRunId - with: - run-id: ${{ steps.targetRunId.outputs.targetRunId }} - name: merged-${{ matrix.system }} - path: target - github-token: ${{ github.token }} - merge-multiple: true - - - name: Compare outpaths against the target branch - if: steps.targetRunId.outputs.targetRunId - env: - MATRIX_SYSTEM: ${{ matrix.system }} - run: | - nix-build untrusted/ci -A eval.diff \ - --arg beforeDir ./target \ - --arg afterDir "$(readlink ./merged)" \ - --argstr evalSystem "$MATRIX_SYSTEM" \ - --out-link diff - - - name: Upload outpaths diff and stats - if: steps.targetRunId.outputs.targetRunId - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: diff-${{ matrix.system }} - path: diff/* - - compare: - runs-on: ubuntu-24.04-arm - needs: [eval] - if: needs.eval.outputs.targetRunId - permissions: - statuses: write - steps: - - name: Download output paths and eval stats for all systems - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - with: - pattern: diff-* - path: diff - merge-multiple: true - - - name: Check out the PR at the target commit - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ inputs.targetSha }} - path: trusted - - - name: Install Nix - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 - with: - extra_nix_config: sandbox = true - - - name: Combine all output paths and eval stats - run: | - nix-build trusted/ci -A eval.combine \ - --arg diffDir ./diff \ - --out-link combined - - - name: Compare against the target branch - env: - AUTHOR_ID: ${{ github.event.pull_request.user.id }} - run: | - git -C trusted fetch --depth 1 origin ${{ inputs.mergedSha }} - git -C trusted diff --name-only ${{ inputs.mergedSha }} \ - | jq --raw-input --slurp 'split("\n")[:-1]' > touched-files.json - - # Use the target branch to get accurate maintainer info - nix-build trusted/ci -A eval.compare \ - --arg combinedDir "$(realpath ./combined)" \ - --arg touchedFilesJson ./touched-files.json \ - --argstr githubAuthorId "$AUTHOR_ID" \ - --out-link comparison - - cat comparison/step-summary.md >> "$GITHUB_STEP_SUMMARY" - - - name: Upload the comparison results - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: comparison - path: comparison/* - - - name: Add eval summary to commit statuses - if: ${{ github.event_name == 'pull_request_target' }} - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - script: | - const { readFile } = require('node:fs/promises') - const changed = JSON.parse(await readFile('comparison/changed-paths.json', 'utf-8')) - const description = - 'Package: ' + [ - `added ${changed.attrdiff.added.length}`, - `removed ${changed.attrdiff.removed.length}`, - `changed ${changed.attrdiff.changed.length}` - ].join(', ') + - ' — Rebuild: ' + [ - `linux ${changed.rebuildCountByKernel.linux}`, - `darwin ${changed.rebuildCountByKernel.darwin}` - ].join(', ') - - const { serverUrl, repo, runId, payload } = context - const target_url = - `${serverUrl}/${repo.owner}/${repo.repo}/actions/runs/${runId}?pr=${payload.pull_request.number}` - - await github.rest.repos.createCommitStatus({ - ...repo, - sha: payload.pull_request.head.sha, - context: 'Eval Summary', - state: 'success', - description, - target_url - }) - - misc: - if: ${{ github.event_name != 'push' }} - runs-on: ubuntu-24.04-arm - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - sparse-checkout: .github/actions - - name: Check if the PR can be merged and checkout the merge commit - uses: ./.github/actions/get-merge-commit - with: - merged-as-untrusted: true - - - name: Install Nix - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 - with: - extra_nix_config: sandbox = true - - - name: Ensure flake outputs on all systems still evaluate - run: nix flake check --all-systems --no-build ./untrusted - - - name: Query nixpkgs with aliases enabled to check for basic syntax errors - run: | - time nix-env -I ./untrusted -f ./untrusted -qa '*' --option restrict-eval true --option allow-import-from-derivation false >/dev/null diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 0b2da1070d200..0000000000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,105 +0,0 @@ -name: Lint - -on: - workflow_call: - inputs: - mergedSha: - required: true - type: string - targetSha: - required: true - type: string - -permissions: {} - -defaults: - run: - shell: bash - -jobs: - treefmt: - runs-on: ubuntu-24.04-arm - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - sparse-checkout: .github/actions - - name: Check if the PR can be merged and checkout the merge commit - uses: ./.github/actions/get-merge-commit - with: - mergedSha: ${{ inputs.mergedSha }} - merged-as-untrusted: true - - - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 - with: - extra_nix_config: sandbox = true - - - name: Check that files are formatted - run: | - # Note that it's fine to run this on untrusted code because: - # - There's no secrets accessible here - # - The build is sandboxed - if ! nix-build untrusted/ci -A fmt.check; then - echo "Some files are not properly formatted" - echo "Please format them by going to the Nixpkgs root directory and running one of:" - echo " nix-shell --run treefmt" - echo " nix develop --command treefmt" - echo " nix fmt" - echo "Make sure your branch is up to date with master; rebase if not." - echo "If you're having trouble, please ping @NixOS/nix-formatting" - exit 1 - fi - - parse: - runs-on: ubuntu-24.04-arm - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - sparse-checkout: .github/actions - - name: Check if the PR can be merged and checkout the merge commit - uses: ./.github/actions/get-merge-commit - with: - mergedSha: ${{ inputs.mergedSha }} - merged-as-untrusted: true - - - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 - with: - extra_nix_config: sandbox = true - - - name: Parse all nix files - run: | - # Tests multiple versions at once, let's make sure all of them run, so keep-going. - nix-build untrusted/ci -A parse --keep-going - - nixpkgs-vet: - runs-on: ubuntu-24.04-arm - # This should take 1 minute at most, but let's be generous. The default of 6 hours is definitely too long. - timeout-minutes: 10 - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - sparse-checkout: .github/actions - - name: Check if the PR can be merged and checkout merged and target commits - uses: ./.github/actions/get-merge-commit - with: - mergedSha: ${{ inputs.mergedSha }} - merged-as-untrusted: true - targetSha: ${{ inputs.targetSha }} - target-as-trusted: true - - - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 - with: - extra_nix_config: sandbox = true - - - name: Running nixpkgs-vet - env: - # Force terminal colors to be enabled. The library that `nixpkgs-vet` uses respects https://bixense.com/clicolors/ - CLICOLOR_FORCE: 1 - run: | - if nix-build untrusted/ci -A nixpkgs-vet --arg base "./trusted" --arg head "./untrusted"; then - exit 0 - else - exitCode=$? - echo "To run locally: ./ci/nixpkgs-vet.sh $GITHUB_BASE_REF https://github.com/$GITHUB_REPOSITORY.git" - echo "If you're having trouble, ping @NixOS/nixpkgs-vet" - exit "$exitCode" - fi diff --git a/.github/workflows/periodic-merge-24h.yml b/.github/workflows/periodic-merge-24h.yml deleted file mode 100644 index 63e3dfd138872..0000000000000 --- a/.github/workflows/periodic-merge-24h.yml +++ /dev/null @@ -1,46 +0,0 @@ -# This action periodically merges base branches into staging branches. -# This is done to -# * prevent conflicts or rather resolve them early -# * make all potential breakage happen on the staging branch -# * and make sure that all major rebuilds happen before the staging -# branch get’s merged back into its base branch. - -name: "Periodic Merges (24h)" - -on: - schedule: - # * is a special character in YAML so you have to quote this string - # Merge every 24 hours - - cron: '0 0 * * *' - workflow_dispatch: - -permissions: {} - -defaults: - run: - shell: bash - -jobs: - periodic-merge: - if: github.repository_owner == 'NixOS' - strategy: - # don't fail fast, so that all pairs are tried - fail-fast: false - # certain branches need to be merged in order, like master->staging-next->staging - # and disabling parallelism ensures the order of the pairs below. - max-parallel: 1 - matrix: - pairs: - - from: release-25.05 - into: staging-next-25.05 - - from: staging-next-25.05 - into: staging-25.05 - - name: merge-base(master,staging) → haskell-updates - from: master staging - into: haskell-updates - uses: ./.github/workflows/periodic-merge.yml - with: - from: ${{ matrix.pairs.from }} - into: ${{ matrix.pairs.into }} - name: ${{ matrix.pairs.name || format('{0} → {1}', matrix.pairs.from, matrix.pairs.into) }} - secrets: inherit diff --git a/.github/workflows/periodic-merge-6h.yml b/.github/workflows/periodic-merge-6h.yml deleted file mode 100644 index 15a7da3db4e2e..0000000000000 --- a/.github/workflows/periodic-merge-6h.yml +++ /dev/null @@ -1,43 +0,0 @@ -# This action periodically merges base branches into staging branches. -# This is done to -# * prevent conflicts or rather resolve them early -# * make all potential breakage happen on the staging branch -# * and make sure that all major rebuilds happen before the staging -# branch get’s merged back into its base branch. - -name: "Periodic Merges (6h)" - -on: - schedule: - # * is a special character in YAML so you have to quote this string - # Merge every 6 hours - - cron: '0 */6 * * *' - workflow_dispatch: - -permissions: {} - -defaults: - run: - shell: bash - -jobs: - periodic-merge: - if: github.repository_owner == 'NixOS' - strategy: - # don't fail fast, so that all pairs are tried - fail-fast: false - # certain branches need to be merged in order, like master->staging-next->staging - # and disabling parallelism ensures the order of the pairs below. - max-parallel: 1 - matrix: - pairs: - - from: master - into: staging-next - - from: staging-next - into: staging - uses: ./.github/workflows/periodic-merge.yml - with: - from: ${{ matrix.pairs.from }} - into: ${{ matrix.pairs.into }} - name: ${{ format('{0} → {1}', matrix.pairs.from, matrix.pairs.into) }} - secrets: inherit diff --git a/.github/workflows/periodic-merge.yml b/.github/workflows/periodic-merge.yml deleted file mode 100644 index 046a0d2fb4dde..0000000000000 --- a/.github/workflows/periodic-merge.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: "Merge" - -on: - workflow_call: - inputs: - from: - description: Branch to merge into target branch. Can also be two branches separated by space to find the merge base between them. - required: true - type: string - into: - description: Target branch to merge into. - required: true - type: string - -defaults: - run: - shell: bash - -jobs: - merge: - runs-on: ubuntu-24.04-arm - steps: - # Use a GitHub App to create the PR so that CI gets triggered - # The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs - - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - id: app-token - with: - app-id: ${{ vars.NIXPKGS_CI_APP_ID }} - private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }} - permission-contents: write - permission-pull-requests: write - - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - - name: Find merge base between two branches - if: contains(inputs.from, ' ') - id: merge_base - env: - branches: ${{ inputs.from }} - run: | - # turn into bash array, split on space - read -ra branches <<< "$branches" - git fetch --shallow-since="1 month ago" origin "${branches[@]}" - merge_base="$(git merge-base "refs/remotes/origin/${branches[0]}" "refs/remotes/origin/${branches[1]}")" - echo "Found merge base: $merge_base" >&2 - echo "merge_base=$merge_base" >> "$GITHUB_OUTPUT" - - - name: ${{ inputs.from }} → ${{ inputs.into }} - uses: devmasx/merge-branch@854d3ac71ed1e9deb668e0074781b81fdd6e771f # 1.4.0 - with: - type: now - from_branch: ${{ steps.merge_base.outputs.merge_base || inputs.from }} - target_branch: ${{ inputs.into }} - github_token: ${{ steps.app-token.outputs.token }} - - - name: Comment on failure - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0 - if: ${{ failure() }} - with: - issue-number: 105153 - body: | - Periodic merge from `${{ inputs.from }}` into `${{ inputs.into }}` has [failed](https://github.com/NixOS/nixpkgs/actions/runs/${{ github.run_id }}). - token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml deleted file mode 100644 index d3a6d2a56a82b..0000000000000 --- a/.github/workflows/pr.yml +++ /dev/null @@ -1,149 +0,0 @@ -name: PR - -on: - pull_request: - paths: - - .github/workflows/build.yml - - .github/workflows/check.yml - - .github/workflows/eval.yml - - .github/workflows/lint.yml - - .github/workflows/pr.yml - - .github/workflows/labels.yml - - .github/workflows/reviewers.yml # needs eval results from the same event type - pull_request_target: - -concurrency: - group: pr-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} - cancel-in-progress: true - -permissions: {} - -jobs: - prepare: - runs-on: ubuntu-24.04-arm - outputs: - baseBranch: ${{ steps.branches.outputs.base }} - headBranch: ${{ steps.branches.outputs.head }} - mergedSha: ${{ steps.get-merge-commit.outputs.mergedSha }} - targetSha: ${{ steps.get-merge-commit.outputs.targetSha }} - systems: ${{ steps.systems.outputs.systems }} - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - sparse-checkout: | - .github/actions - ci/supportedBranches.js - ci/supportedSystems.json - - name: Check if the PR can be merged and get the test merge commit - uses: ./.github/actions/get-merge-commit - id: get-merge-commit - - - name: Load supported systems - id: systems - run: | - echo "systems=$(jq -c > "$GITHUB_OUTPUT" - - - name: Determine branch type - id: branches - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - script: | - const { classify } = require('./ci/supportedBranches.js') - const { base, head } = context.payload.pull_request - - const baseClassification = classify(base.ref) - core.setOutput('base', baseClassification) - core.info('base classification:', baseClassification) - - const headClassification = - (base.repo.full_name == head.repo.full_name) ? - classify(head.ref) : - // PRs from forks are always considered WIP. - { type: ['wip'] } - core.setOutput('head', headClassification) - core.info('head classification:', headClassification) - - check: - name: Check - needs: [prepare] - uses: ./.github/workflows/check.yml - permissions: - # cherry-picks - pull-requests: write - with: - baseBranch: ${{ needs.prepare.outputs.baseBranch }} - headBranch: ${{ needs.prepare.outputs.headBranch }} - - lint: - name: Lint - needs: [prepare] - uses: ./.github/workflows/lint.yml - with: - mergedSha: ${{ needs.prepare.outputs.mergedSha }} - targetSha: ${{ needs.prepare.outputs.targetSha }} - - eval: - name: Eval - needs: [prepare] - uses: ./.github/workflows/eval.yml - permissions: - # compare - statuses: write - secrets: - OWNER_APP_PRIVATE_KEY: ${{ secrets.OWNER_APP_PRIVATE_KEY }} - with: - mergedSha: ${{ needs.prepare.outputs.mergedSha }} - targetSha: ${{ needs.prepare.outputs.targetSha }} - systems: ${{ needs.prepare.outputs.systems }} - - labels: - name: Labels - needs: [prepare, eval] - uses: ./.github/workflows/labels.yml - permissions: - issues: write - pull-requests: write - secrets: - NIXPKGS_CI_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }} - with: - headBranch: ${{ needs.prepare.outputs.headBranch }} - - reviewers: - name: Reviewers - needs: [prepare, eval] - if: | - needs.prepare.outputs.targetSha && - !contains(fromJSON(needs.prepare.outputs.headBranch).type, 'development') - uses: ./.github/workflows/reviewers.yml - secrets: - OWNER_APP_PRIVATE_KEY: ${{ secrets.OWNER_APP_PRIVATE_KEY }} - - build: - name: Build - needs: [prepare] - uses: ./.github/workflows/build.yml - secrets: - CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} - with: - baseBranch: ${{ needs.prepare.outputs.baseBranch }} - mergedSha: ${{ needs.prepare.outputs.mergedSha }} - - # This job's only purpose is to serve as a target for the "Required Status Checks" branch ruleset. - # It "needs" all the jobs that should block merging a PR. - # If they pass, it is skipped — which counts as "success" for purposes of the branch ruleset. - # However, if any of them fail, this job will also fail — thus blocking the branch ruleset. - no-pr-failures: - # Modify this list to add or remove jobs from required status checks. - needs: - - check - - lint - - eval - - build - # WARNING: - # Do NOT change the name of this job, otherwise the rule will not catch it anymore. - # This would prevent all PRs from merging. - name: no PR failures - if: ${{ failure() }} - runs-on: ubuntu-24.04-arm - steps: - - run: exit 1 diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml deleted file mode 100644 index 407b77194f35f..0000000000000 --- a/.github/workflows/push.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Push - -on: - pull_request: - paths: - - .github/workflows/push.yml - # eval is tested via pr.yml - push: - # Keep this synced with ci/request-reviews/dev-branches.txt - branches: - - master - - staging - - release-* - - staging-* - - haskell-updates - - python-updates - -permissions: {} - -jobs: - prepare: - runs-on: ubuntu-24.04-arm - outputs: - systems: ${{ steps.systems.outputs.systems }} - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - sparse-checkout: | - ci/supportedSystems.json - - - name: Load supported systems - id: systems - run: | - echo "systems=$(jq -c > "$GITHUB_OUTPUT" - - eval: - name: Eval - needs: [prepare] - uses: ./.github/workflows/eval.yml - # Those are not actually used on push, but will throw an error if not set. - permissions: - # compare - issues: write - pull-requests: write - statuses: write - with: - mergedSha: ${{ github.sha }} - systems: ${{ needs.prepare.outputs.systems }} diff --git a/.github/workflows/review-dismissed.yml b/.github/workflows/review-dismissed.yml deleted file mode 100644 index 988b4a47df14b..0000000000000 --- a/.github/workflows/review-dismissed.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Review dismissed - -on: - pull_request_review: - types: [dismissed] - -permissions: {} - -defaults: - run: - shell: bash - -jobs: - trigger: - runs-on: ubuntu-24.04-arm - steps: - - run: echo This is a no-op only used as a trigger for workflow_run. diff --git a/.github/workflows/reviewers.yml b/.github/workflows/reviewers.yml deleted file mode 100644 index 1d518133cf6d2..0000000000000 --- a/.github/workflows/reviewers.yml +++ /dev/null @@ -1,144 +0,0 @@ -# This workflow will request reviews from the maintainers of each package -# listed in the PR's most recent eval comparison artifact. - -name: Reviewers - -on: - pull_request: - paths: - - .github/workflows/reviewers.yml - pull_request_target: - types: [ready_for_review] - workflow_call: - secrets: - OWNER_APP_PRIVATE_KEY: - required: true - -concurrency: - group: reviewers-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} - cancel-in-progress: true - -permissions: {} - -defaults: - run: - shell: bash - -jobs: - request: - runs-on: ubuntu-24.04-arm - steps: - - name: Check out the PR at the base commit - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - path: trusted - sparse-checkout: ci - - - name: Install Nix - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 - with: - extra_nix_config: sandbox = true - - - name: Build the requestReviews derivation - run: nix-build trusted/ci -A requestReviews - - # 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@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - if: github.event_name == 'pull_request_target' && vars.OWNER_APP_ID - id: app-token - with: - app-id: ${{ vars.OWNER_APP_ID }} - private-key: ${{ secrets.OWNER_APP_PRIVATE_KEY }} - permission-administration: read - permission-members: read - permission-pull-requests: write - - - name: Log current API rate limits (github.token) - env: - GH_TOKEN: ${{ github.token }} - run: gh api /rate_limit | jq - - # In the regular case, this workflow is called via workflow_call from the eval workflow directly. - # In the more special case, when a PR is undrafted an eval run will have started already. - - name: Wait for comparison to be done - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - id: eval - with: - script: | - const run_id = (await github.rest.actions.listWorkflowRuns({ - owner: context.repo.owner, - repo: context.repo.repo, - workflow_id: 'pr.yml', - event: context.eventName, - head_sha: context.payload.pull_request.head.sha - })).data.workflow_runs[0].id - - core.setOutput('run-id', run_id) - - // Waiting 120 * 5 sec = 10 min. max. - // The extreme case is an Eval run that just started when the PR is undrafted. - // Eval takes max 5-6 minutes, normally. - for (let i = 0; i < 120; i++) { - const result = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id, - name: 'comparison' - }) - if (result.data.total_count > 0) return - await new Promise(resolve => setTimeout(resolve, 5000)) - } - throw new Error("No comparison artifact found.") - - - name: Log current API rate limits (github.token) - env: - GH_TOKEN: ${{ github.token }} - run: gh api /rate_limit | jq - - - name: Download the comparison results - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - with: - run-id: ${{ steps.eval.outputs.run-id }} - github-token: ${{ github.token }} - pattern: comparison - path: comparison - merge-multiple: true - - - name: Log current API rate limits (app-token) - if: ${{ steps.app-token.outputs.token }} - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: gh api /rate_limit | jq - - - name: Log current API rate limits (github.token) - env: - GH_TOKEN: ${{ github.token }} - run: gh api /rate_limit | jq - - - name: Requesting maintainer reviews - if: ${{ steps.app-token.outputs.token }} - env: - GH_TOKEN: ${{ github.token }} - REPOSITORY: ${{ github.repository }} - NUMBER: ${{ github.event.number }} - AUTHOR: ${{ github.event.pull_request.user.login }} - # Don't request reviewers on draft PRs - DRY_MODE: ${{ github.event.pull_request.draft && '1' || '' }} - run: | - # maintainers.json contains GitHub IDs. Look up handles to request reviews from. - # There appears to be no API to request reviews based on GitHub IDs - jq -r 'keys[]' comparison/maintainers.json \ - | while read -r id; do gh api /user/"$id" --jq .login; done \ - | GH_TOKEN=${{ steps.app-token.outputs.token }} result/bin/request-reviewers.sh "$REPOSITORY" "$NUMBER" "$AUTHOR" - - - name: Log current API rate limits (app-token) - if: ${{ steps.app-token.outputs.token }} - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: gh api /rate_limit | jq - - - name: Log current API rate limits (github.token) - env: - GH_TOKEN: ${{ github.token }} - run: gh api /rate_limit | jq diff --git a/.github/workflows/semantic-release.yml b/.github/workflows/semantic-release.yml new file mode 100644 index 0000000000000..722fc5aecb008 --- /dev/null +++ b/.github/workflows/semantic-release.yml @@ -0,0 +1,22 @@ +on: push + +concurrency: + group: semantic-release-${{ github.ref }} + cancel-in-progress: true + + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - macos-15-large + - macos-latest + - ubuntu-latest + - ubuntu-latest-arm64 + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v31 + - run: nix run .#semantic-release -- --version + diff --git a/pkgs/by-name/se/semantic-release/package.nix b/pkgs/by-name/se/semantic-release/package.nix index 86e3ae849c80e..a1ccf51034683 100644 --- a/pkgs/by-name/se/semantic-release/package.nix +++ b/pkgs/by-name/se/semantic-release/package.nix @@ -9,21 +9,22 @@ buildNpmPackage rec { pname = "semantic-release"; - version = "24.2.5"; + version = "24.2.7"; src = fetchFromGitHub { owner = "semantic-release"; repo = "semantic-release"; rev = "v${version}"; - hash = "sha256-WS3hd84vDSH/u7AxtkPL8E1UutUKHzARSzVYOHLlKPU="; + hash = "sha256-7BIEb4gQLppa+CXCR+oYPvb/l8UB6ihNh4veBdDG8ac="; }; - npmDepsHash = "sha256-uQWQ+0Ub1piW/BATHrrWfzjv10/f2fyVL5JwDF1NdqM="; + npmDepsHash = "sha256-ODu8foiTtU7bsaVL/ri4eCwpcyg/7CdSGtyPsA/myxU="; dontNpmBuild = true; nativeBuildInputs = [ python3 + # (python3.withPackages (ps: [ ps.setuptools ])) ] ++ lib.optional stdenv.hostPlatform.isDarwin cctools; From 40bf8775c4647cedf19f118a0d0dec09bec74aaf Mon Sep 17 00:00:00 2001 From: Fabricio Mera <55803899+fm7-1@users.noreply.github.com> Date: Fri, 1 Aug 2025 10:56:39 -0500 Subject: [PATCH 3/4] Add fm7-1 as package maintainer --- pkgs/by-name/se/semantic-release/package.nix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/se/semantic-release/package.nix b/pkgs/by-name/se/semantic-release/package.nix index a1ccf51034683..dd1f603e8b950 100644 --- a/pkgs/by-name/se/semantic-release/package.nix +++ b/pkgs/by-name/se/semantic-release/package.nix @@ -24,7 +24,6 @@ buildNpmPackage rec { nativeBuildInputs = [ python3 - # (python3.withPackages (ps: [ ps.setuptools ])) ] ++ lib.optional stdenv.hostPlatform.isDarwin cctools; @@ -40,6 +39,9 @@ buildNpmPackage rec { mainProgram = "semantic-release"; homepage = "https://semantic-release.gitbook.io/semantic-release/"; license = lib.licenses.mit; - maintainers = [ lib.maintainers.sestrella ]; + maintainers = [ + lib.maintainers.sestrella + lib.maintainers.fm7-1 + ]; }; } From b04debaeebb46225b6bbf01f6f6299e62541b08d Mon Sep 17 00:00:00 2001 From: Fabricio Mera <55803899+fm7-1@users.noreply.github.com> Date: Fri, 1 Aug 2025 10:59:11 -0500 Subject: [PATCH 4/4] Restore CI workflows --- .github/workflows/backport.yml | 76 +++++++ .github/workflows/codeowners-v2.yml | 147 +++++++++++++ .github/workflows/dismissed-review.yml | 65 ++++++ .github/workflows/edited.yml | 58 ++++++ .github/workflows/eval.yml | 255 +++++++++++++++++++++++ .github/workflows/lint.yml | 105 ++++++++++ .github/workflows/periodic-merge-24h.yml | 46 ++++ .github/workflows/periodic-merge-6h.yml | 43 ++++ .github/workflows/periodic-merge.yml | 63 ++++++ .github/workflows/pr.yml | 149 +++++++++++++ .github/workflows/push.yml | 48 +++++ .github/workflows/review-dismissed.yml | 17 ++ .github/workflows/reviewers.yml | 144 +++++++++++++ .github/workflows/semantic-release.yml | 22 -- 14 files changed, 1216 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/backport.yml create mode 100644 .github/workflows/codeowners-v2.yml create mode 100644 .github/workflows/dismissed-review.yml create mode 100644 .github/workflows/edited.yml create mode 100644 .github/workflows/eval.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/periodic-merge-24h.yml create mode 100644 .github/workflows/periodic-merge-6h.yml create mode 100644 .github/workflows/periodic-merge.yml create mode 100644 .github/workflows/pr.yml create mode 100644 .github/workflows/push.yml create mode 100644 .github/workflows/review-dismissed.yml create mode 100644 .github/workflows/reviewers.yml delete mode 100644 .github/workflows/semantic-release.yml diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 0000000000000..709d8a6edd8f9 --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,76 @@ +# WARNING: +# When extending this action, be aware that $GITHUB_TOKEN allows write access to +# the GitHub repository. This means that it should not evaluate user input in a +# way that allows code injection. + +name: Backport + +on: + pull_request_target: + types: [closed, labeled] + +permissions: + contents: read + issues: write + pull-requests: write + +defaults: + run: + shell: bash + +jobs: + backport: + name: Backport Pull Request + if: vars.NIXPKGS_CI_APP_ID && github.event.pull_request.merged == true && (github.event.action != 'labeled' || startsWith(github.event.label.name, 'backport')) + runs-on: ubuntu-24.04-arm + steps: + # Use a GitHub App to create the PR so that CI gets triggered + # The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs + - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + id: app-token + with: + app-id: ${{ vars.NIXPKGS_CI_APP_ID }} + private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ github.event.pull_request.head.sha }} + token: ${{ steps.app-token.outputs.token }} + + - name: Log current API rate limits + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: gh api /rate_limit | jq + + - name: Create backport PRs + id: backport + uses: korthout/backport-action@0193454f0c5947491d348f33a275c119f30eb736 # v3.2.1 + with: + # Config README: https://github.com/korthout/backport-action#backport-action + copy_labels_pattern: 'severity:\ssecurity' + github_token: ${{ steps.app-token.outputs.token }} + pull_description: |- + Bot-based backport to `${target_branch}`, triggered by a label in #${pull_number}. + + * [ ] Before merging, ensure that this backport is [acceptable for the release](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#changes-acceptable-for-releases). + * Even as a non-committer, if you find that it is not acceptable, leave a comment. + + - name: Log current API rate limits + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: gh api /rate_limit | jq + + - name: "Add 'has: port to stable' label" + if: steps.backport.outputs.created_pull_numbers != '' + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + # Not using the app on purpose to avoid triggering another workflow run after adding this label. + script: | + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + labels: [ '8.has: port to stable' ] + }) diff --git a/.github/workflows/codeowners-v2.yml b/.github/workflows/codeowners-v2.yml new file mode 100644 index 0000000000000..97fcfc63bdd2c --- /dev/null +++ b/.github/workflows/codeowners-v2.yml @@ -0,0 +1,147 @@ +# This workflow depends on two GitHub Apps with the following permissions: +# - For checking code owners: +# - Permissions: +# - Repository > Administration: read-only +# - Organization > Members: read-only +# - Install App on this repository, setting these variables: +# - OWNER_RO_APP_ID (variable) +# - OWNER_RO_APP_PRIVATE_KEY (secret) +# - For requesting code owners: +# - Permissions: +# - Repository > Administration: read-only +# - Organization > Members: read-only +# - Repository > Pull Requests: read-write +# - Install App on this repository, setting these variables: +# - OWNER_APP_ID (variable) +# - OWNER_APP_PRIVATE_KEY (secret) +# +# This split is done because checking code owners requires handling untrusted PR input, +# while requesting code owners requires PR write access, and those shouldn't be mixed. +# +# Note that the latter is also used for ./eval.yml requesting reviewers. + +name: Codeowners v2 + +on: + pull_request: + paths: + - .github/workflows/codeowners-v2.yml + pull_request_target: + types: [opened, ready_for_review, synchronize, reopened] + +concurrency: + group: codeowners-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +permissions: {} + +defaults: + run: + shell: bash + +env: + OWNERS_FILE: ci/OWNERS + # Don't do anything on draft PRs + DRY_MODE: ${{ github.event.pull_request.draft && '1' || '' }} + +jobs: + # Check that code owners is valid + check: + name: Check + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + sparse-checkout: .github/actions + - name: Check if the PR can be merged and checkout the merge and target commits + uses: ./.github/actions/get-merge-commit + with: + merged-as-untrusted: true + target-as-trusted: true + + - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 + + - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 + with: + # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere. + name: nixpkgs-ci + authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + + - name: Build codeowners validator + run: nix-build trusted/ci -A codeownersValidator + + - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + if: github.event_name == 'pull_request_target' && vars.OWNER_RO_APP_ID + id: app-token + with: + app-id: ${{ vars.OWNER_RO_APP_ID }} + private-key: ${{ secrets.OWNER_RO_APP_PRIVATE_KEY }} + permission-administration: read + permission-members: read + + - name: Log current API rate limits + if: steps.app-token.outputs.token + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: gh api /rate_limit | jq + + - name: Validate codeowners + if: steps.app-token.outputs.token + env: + OWNERS_FILE: untrusted/${{ env.OWNERS_FILE }} + GITHUB_ACCESS_TOKEN: ${{ steps.app-token.outputs.token }} + REPOSITORY_PATH: untrusted + OWNER_CHECKER_REPOSITORY: ${{ github.repository }} + # Set this to "notowned,avoid-shadowing" to check that all files are owned by somebody + EXPERIMENTAL_CHECKS: "avoid-shadowing" + run: result/bin/codeowners-validator + + - name: Log current API rate limits + if: steps.app-token.outputs.token + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: gh api /rate_limit | jq + + # Request reviews from code owners + request: + name: Request + runs-on: ubuntu-24.04-arm + steps: + - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 + + # Important: Because we use pull_request_target, this checks out the base branch of the PR, not the PR head. + # This is intentional, because we need to request the review of owners as declared in the base branch. + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + path: trusted + + - name: Build review request package + run: nix-build trusted/ci -A requestReviews + + - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + if: github.event_name == 'pull_request_target' && vars.OWNER_APP_ID + id: app-token + with: + app-id: ${{ vars.OWNER_APP_ID }} + private-key: ${{ secrets.OWNER_APP_PRIVATE_KEY }} + permission-administration: read + permission-members: read + permission-pull-requests: write + + - name: Log current API rate limits + if: steps.app-token.outputs.token + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: gh api /rate_limit | jq + + - name: Request reviews + if: steps.app-token.outputs.token + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: result/bin/request-code-owner-reviews.sh ${{ github.repository }} ${{ github.event.number }} "$OWNERS_FILE" + + - name: Log current API rate limits + if: steps.app-token.outputs.token + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: gh api /rate_limit | jq diff --git a/.github/workflows/dismissed-review.yml b/.github/workflows/dismissed-review.yml new file mode 100644 index 0000000000000..e8ab48bda0755 --- /dev/null +++ b/.github/workflows/dismissed-review.yml @@ -0,0 +1,65 @@ +name: Dismissed review + +on: + workflow_run: + workflows: + - Review dismissed + types: [completed] + +concurrency: + group: dismissed-review-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +permissions: + pull-requests: write + +defaults: + run: + shell: bash + +jobs: + # The `check-cherry-picks` workflow creates review comments which reviewers + # are encouraged to manually dismiss if they're not relevant. + # When a CI-generated review is dismissed, this job automatically minimizes + # it, preventing it from cluttering the PR. + minimize: + name: Minimize as resolved + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + // PRs from forks don't have any PRs associated by default. + // Thus, we request the PR number with an API call *to* the fork's repo. + // Multiple pull requests can be open from the same head commit, either via + // different base branches or head branches. + const { head_repository, head_sha, repository } = context.payload.workflow_run + await Promise.all( + (await github.paginate(github.rest.repos.listPullRequestsAssociatedWithCommit, { + owner: head_repository.owner.login, + repo: head_repository.name, + commit_sha: head_sha + })) + .filter(pull_request => pull_request.base.repo.id == repository.id) + .map(async (pull_request) => + Promise.all( + (await github.paginate(github.rest.pulls.listReviews, { + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pull_request.number + })).filter(review => + review.user.login == 'github-actions[bot]' && + review.state == 'DISMISSED' + ).map(review => github.graphql(` + mutation($node_id:ID!) { + minimizeComment(input: { + classifier: RESOLVED, + subjectId: $node_id + }) + { clientMutationId } + }`, + { node_id: review.node_id } + )) + ) + ) + ) diff --git a/.github/workflows/edited.yml b/.github/workflows/edited.yml new file mode 100644 index 0000000000000..49fccb5f48ba0 --- /dev/null +++ b/.github/workflows/edited.yml @@ -0,0 +1,58 @@ +# Some workflows depend on the base branch of the PR, but changing the base branch is not included in the default trigger events, which would be `opened`, `synchronize` or `reopened`. +# Instead it causes an `edited` event. +# Since `edited` is also triggered when PR title/body is changed, we use this wrapper workflow, to run the other workflows conditionally only. +# There are already feature requests for adding a `base_changed` event: +# - https://github.com/orgs/community/discussions/35058 +# - https://github.com/orgs/community/discussions/64119 +# +# Instead of adding this to each workflow's pull_request_target event, we trigger this in a separate workflow. +# This has the advantage, that we can actually skip running those jobs for simple edits like changing the title or description. +# The actual trigger happens by closing and re-opening the pull request, which triggers the default pull_request_target events. +# This is much simpler and reliable than other approaches. + +name: "Edited base branch" + +on: + pull_request_target: + types: [edited] + +concurrency: + group: edited-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +permissions: {} + +defaults: + run: + shell: bash + +jobs: + base: + name: Trigger jobs + runs-on: ubuntu-24.04 + if: github.event.changes.base.ref.from && github.event.changes.base.ref.from != github.event.pull_request.base.ref + steps: + # Use a GitHub App to create the PR so that CI gets triggered + # The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs + # We only need Pull Requests: write here, but the app is also used for backports. + - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + id: app-token + with: + app-id: ${{ vars.NIXPKGS_CI_APP_ID }} + private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }} + permission-pull-requests: write + + - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + github-token: ${{ steps.app-token.outputs.token }} + script: | + function changeState(state) { + return github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + state + }) + } + await changeState('closed') + await changeState('open') diff --git a/.github/workflows/eval.yml b/.github/workflows/eval.yml new file mode 100644 index 0000000000000..5999aedcb9382 --- /dev/null +++ b/.github/workflows/eval.yml @@ -0,0 +1,255 @@ +name: Eval + +on: + workflow_call: + inputs: + mergedSha: + required: true + type: string + targetSha: + type: string + systems: + required: true + type: string + secrets: + OWNER_APP_PRIVATE_KEY: + required: false + +permissions: {} + +defaults: + run: + shell: bash + +jobs: + eval: + runs-on: ubuntu-24.04-arm + strategy: + fail-fast: false + matrix: + system: ${{ fromJSON(inputs.systems) }} + name: ${{ matrix.system }} + outputs: + targetRunId: ${{ steps.targetRunId.outputs.targetRunId }} + steps: + - name: Enable swap + run: | + sudo fallocate -l 10G /swap + sudo chmod 600 /swap + sudo mkswap /swap + sudo swapon /swap + + - name: Check out the PR at the test merge commit + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ inputs.mergedSha }} + path: untrusted + + - name: Install Nix + uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 + 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 untrusted/ci -A eval.singleSystem \ + --argstr evalSystem "$MATRIX_SYSTEM" \ + --arg chunkSize 10000 \ + --out-link merged + # If it uses too much memory, slightly decrease chunkSize + + - name: Upload the output paths and eval stats + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: merged-${{ matrix.system }} + path: merged/* + + - name: Log current API rate limits + env: + GH_TOKEN: ${{ github.token }} + run: gh api /rate_limit | jq + + - name: Get target run id + if: inputs.targetSha + id: targetRunId + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + env: + MATRIX_SYSTEM: ${{ matrix.system }} + TARGET_SHA: ${{ inputs.targetSha }} + with: + script: | + const system = process.env.MATRIX_SYSTEM + const targetSha = process.env.TARGET_SHA + + let run_id + try { + run_id = (await github.rest.actions.listWorkflowRuns({ + ...context.repo, + workflow_id: 'push.yml', + event: 'push', + head_sha: targetSha + })).data.workflow_runs[0].id + } catch { + throw new Error(`Could not find a push.yml workflow run for ${targetSha}.`) + } + + // Waiting 120 * 5 sec = 10 min. max. + // Eval takes max 5-6 minutes, normally. + for (let i = 0; i < 120; i++) { + const result = await github.rest.actions.listWorkflowRunArtifacts({ + ...context.repo, + run_id, + name: `merged-${system}` + }) + if (result.data.total_count > 0) { + core.setOutput('targetRunId', run_id) + return + } + await new Promise(resolve => setTimeout(resolve, 5000)) + } + // No artifact found at this stage. This usually means that Eval failed on the target branch. + // This should only happen when Eval is broken on the target branch and this PR fixes it. + // Continue without targetRunId to skip the remaining steps, but pass the job. + + - name: Log current API rate limits + env: + GH_TOKEN: ${{ github.token }} + run: gh api /rate_limit | jq + + - uses: actions/download-artifact@v4 + if: steps.targetRunId.outputs.targetRunId + with: + run-id: ${{ steps.targetRunId.outputs.targetRunId }} + name: merged-${{ matrix.system }} + path: target + github-token: ${{ github.token }} + merge-multiple: true + + - name: Compare outpaths against the target branch + if: steps.targetRunId.outputs.targetRunId + env: + MATRIX_SYSTEM: ${{ matrix.system }} + run: | + nix-build untrusted/ci -A eval.diff \ + --arg beforeDir ./target \ + --arg afterDir "$(readlink ./merged)" \ + --argstr evalSystem "$MATRIX_SYSTEM" \ + --out-link diff + + - name: Upload outpaths diff and stats + if: steps.targetRunId.outputs.targetRunId + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: diff-${{ matrix.system }} + path: diff/* + + compare: + runs-on: ubuntu-24.04-arm + needs: [eval] + if: needs.eval.outputs.targetRunId + permissions: + statuses: write + steps: + - name: Download output paths and eval stats for all systems + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + pattern: diff-* + path: diff + merge-multiple: true + + - name: Check out the PR at the target commit + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ inputs.targetSha }} + path: trusted + + - name: Install Nix + uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 + with: + extra_nix_config: sandbox = true + + - name: Combine all output paths and eval stats + run: | + nix-build trusted/ci -A eval.combine \ + --arg diffDir ./diff \ + --out-link combined + + - name: Compare against the target branch + env: + AUTHOR_ID: ${{ github.event.pull_request.user.id }} + run: | + git -C trusted fetch --depth 1 origin ${{ inputs.mergedSha }} + git -C trusted diff --name-only ${{ inputs.mergedSha }} \ + | jq --raw-input --slurp 'split("\n")[:-1]' > touched-files.json + + # Use the target branch to get accurate maintainer info + nix-build trusted/ci -A eval.compare \ + --arg combinedDir "$(realpath ./combined)" \ + --arg touchedFilesJson ./touched-files.json \ + --argstr githubAuthorId "$AUTHOR_ID" \ + --out-link comparison + + cat comparison/step-summary.md >> "$GITHUB_STEP_SUMMARY" + + - name: Upload the comparison results + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: comparison + path: comparison/* + + - name: Add eval summary to commit statuses + if: ${{ github.event_name == 'pull_request_target' }} + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const { readFile } = require('node:fs/promises') + const changed = JSON.parse(await readFile('comparison/changed-paths.json', 'utf-8')) + const description = + 'Package: ' + [ + `added ${changed.attrdiff.added.length}`, + `removed ${changed.attrdiff.removed.length}`, + `changed ${changed.attrdiff.changed.length}` + ].join(', ') + + ' — Rebuild: ' + [ + `linux ${changed.rebuildCountByKernel.linux}`, + `darwin ${changed.rebuildCountByKernel.darwin}` + ].join(', ') + + const { serverUrl, repo, runId, payload } = context + const target_url = + `${serverUrl}/${repo.owner}/${repo.repo}/actions/runs/${runId}?pr=${payload.pull_request.number}` + + await github.rest.repos.createCommitStatus({ + ...repo, + sha: payload.pull_request.head.sha, + context: 'Eval Summary', + state: 'success', + description, + target_url + }) + + misc: + if: ${{ github.event_name != 'push' }} + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + sparse-checkout: .github/actions + - name: Check if the PR can be merged and checkout the merge commit + uses: ./.github/actions/get-merge-commit + with: + merged-as-untrusted: true + + - name: Install Nix + uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 + with: + extra_nix_config: sandbox = true + + - name: Ensure flake outputs on all systems still evaluate + run: nix flake check --all-systems --no-build ./untrusted + + - name: Query nixpkgs with aliases enabled to check for basic syntax errors + run: | + time nix-env -I ./untrusted -f ./untrusted -qa '*' --option restrict-eval true --option allow-import-from-derivation false >/dev/null diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000000..0b2da1070d200 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,105 @@ +name: Lint + +on: + workflow_call: + inputs: + mergedSha: + required: true + type: string + targetSha: + required: true + type: string + +permissions: {} + +defaults: + run: + shell: bash + +jobs: + treefmt: + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + sparse-checkout: .github/actions + - name: Check if the PR can be merged and checkout the merge commit + uses: ./.github/actions/get-merge-commit + with: + mergedSha: ${{ inputs.mergedSha }} + merged-as-untrusted: true + + - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 + with: + extra_nix_config: sandbox = true + + - name: Check that files are formatted + run: | + # Note that it's fine to run this on untrusted code because: + # - There's no secrets accessible here + # - The build is sandboxed + if ! nix-build untrusted/ci -A fmt.check; then + echo "Some files are not properly formatted" + echo "Please format them by going to the Nixpkgs root directory and running one of:" + echo " nix-shell --run treefmt" + echo " nix develop --command treefmt" + echo " nix fmt" + echo "Make sure your branch is up to date with master; rebase if not." + echo "If you're having trouble, please ping @NixOS/nix-formatting" + exit 1 + fi + + parse: + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + sparse-checkout: .github/actions + - name: Check if the PR can be merged and checkout the merge commit + uses: ./.github/actions/get-merge-commit + with: + mergedSha: ${{ inputs.mergedSha }} + merged-as-untrusted: true + + - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 + with: + extra_nix_config: sandbox = true + + - name: Parse all nix files + run: | + # Tests multiple versions at once, let's make sure all of them run, so keep-going. + nix-build untrusted/ci -A parse --keep-going + + nixpkgs-vet: + runs-on: ubuntu-24.04-arm + # This should take 1 minute at most, but let's be generous. The default of 6 hours is definitely too long. + timeout-minutes: 10 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + sparse-checkout: .github/actions + - name: Check if the PR can be merged and checkout merged and target commits + uses: ./.github/actions/get-merge-commit + with: + mergedSha: ${{ inputs.mergedSha }} + merged-as-untrusted: true + targetSha: ${{ inputs.targetSha }} + target-as-trusted: true + + - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 + with: + extra_nix_config: sandbox = true + + - name: Running nixpkgs-vet + env: + # Force terminal colors to be enabled. The library that `nixpkgs-vet` uses respects https://bixense.com/clicolors/ + CLICOLOR_FORCE: 1 + run: | + if nix-build untrusted/ci -A nixpkgs-vet --arg base "./trusted" --arg head "./untrusted"; then + exit 0 + else + exitCode=$? + echo "To run locally: ./ci/nixpkgs-vet.sh $GITHUB_BASE_REF https://github.com/$GITHUB_REPOSITORY.git" + echo "If you're having trouble, ping @NixOS/nixpkgs-vet" + exit "$exitCode" + fi diff --git a/.github/workflows/periodic-merge-24h.yml b/.github/workflows/periodic-merge-24h.yml new file mode 100644 index 0000000000000..63e3dfd138872 --- /dev/null +++ b/.github/workflows/periodic-merge-24h.yml @@ -0,0 +1,46 @@ +# This action periodically merges base branches into staging branches. +# This is done to +# * prevent conflicts or rather resolve them early +# * make all potential breakage happen on the staging branch +# * and make sure that all major rebuilds happen before the staging +# branch get’s merged back into its base branch. + +name: "Periodic Merges (24h)" + +on: + schedule: + # * is a special character in YAML so you have to quote this string + # Merge every 24 hours + - cron: '0 0 * * *' + workflow_dispatch: + +permissions: {} + +defaults: + run: + shell: bash + +jobs: + periodic-merge: + if: github.repository_owner == 'NixOS' + strategy: + # don't fail fast, so that all pairs are tried + fail-fast: false + # certain branches need to be merged in order, like master->staging-next->staging + # and disabling parallelism ensures the order of the pairs below. + max-parallel: 1 + matrix: + pairs: + - from: release-25.05 + into: staging-next-25.05 + - from: staging-next-25.05 + into: staging-25.05 + - name: merge-base(master,staging) → haskell-updates + from: master staging + into: haskell-updates + uses: ./.github/workflows/periodic-merge.yml + with: + from: ${{ matrix.pairs.from }} + into: ${{ matrix.pairs.into }} + name: ${{ matrix.pairs.name || format('{0} → {1}', matrix.pairs.from, matrix.pairs.into) }} + secrets: inherit diff --git a/.github/workflows/periodic-merge-6h.yml b/.github/workflows/periodic-merge-6h.yml new file mode 100644 index 0000000000000..15a7da3db4e2e --- /dev/null +++ b/.github/workflows/periodic-merge-6h.yml @@ -0,0 +1,43 @@ +# This action periodically merges base branches into staging branches. +# This is done to +# * prevent conflicts or rather resolve them early +# * make all potential breakage happen on the staging branch +# * and make sure that all major rebuilds happen before the staging +# branch get’s merged back into its base branch. + +name: "Periodic Merges (6h)" + +on: + schedule: + # * is a special character in YAML so you have to quote this string + # Merge every 6 hours + - cron: '0 */6 * * *' + workflow_dispatch: + +permissions: {} + +defaults: + run: + shell: bash + +jobs: + periodic-merge: + if: github.repository_owner == 'NixOS' + strategy: + # don't fail fast, so that all pairs are tried + fail-fast: false + # certain branches need to be merged in order, like master->staging-next->staging + # and disabling parallelism ensures the order of the pairs below. + max-parallel: 1 + matrix: + pairs: + - from: master + into: staging-next + - from: staging-next + into: staging + uses: ./.github/workflows/periodic-merge.yml + with: + from: ${{ matrix.pairs.from }} + into: ${{ matrix.pairs.into }} + name: ${{ format('{0} → {1}', matrix.pairs.from, matrix.pairs.into) }} + secrets: inherit diff --git a/.github/workflows/periodic-merge.yml b/.github/workflows/periodic-merge.yml new file mode 100644 index 0000000000000..046a0d2fb4dde --- /dev/null +++ b/.github/workflows/periodic-merge.yml @@ -0,0 +1,63 @@ +name: "Merge" + +on: + workflow_call: + inputs: + from: + description: Branch to merge into target branch. Can also be two branches separated by space to find the merge base between them. + required: true + type: string + into: + description: Target branch to merge into. + required: true + type: string + +defaults: + run: + shell: bash + +jobs: + merge: + runs-on: ubuntu-24.04-arm + steps: + # Use a GitHub App to create the PR so that CI gets triggered + # The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs + - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + id: app-token + with: + app-id: ${{ vars.NIXPKGS_CI_APP_ID }} + private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Find merge base between two branches + if: contains(inputs.from, ' ') + id: merge_base + env: + branches: ${{ inputs.from }} + run: | + # turn into bash array, split on space + read -ra branches <<< "$branches" + git fetch --shallow-since="1 month ago" origin "${branches[@]}" + merge_base="$(git merge-base "refs/remotes/origin/${branches[0]}" "refs/remotes/origin/${branches[1]}")" + echo "Found merge base: $merge_base" >&2 + echo "merge_base=$merge_base" >> "$GITHUB_OUTPUT" + + - name: ${{ inputs.from }} → ${{ inputs.into }} + uses: devmasx/merge-branch@854d3ac71ed1e9deb668e0074781b81fdd6e771f # 1.4.0 + with: + type: now + from_branch: ${{ steps.merge_base.outputs.merge_base || inputs.from }} + target_branch: ${{ inputs.into }} + github_token: ${{ steps.app-token.outputs.token }} + + - name: Comment on failure + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0 + if: ${{ failure() }} + with: + issue-number: 105153 + body: | + Periodic merge from `${{ inputs.from }}` into `${{ inputs.into }}` has [failed](https://github.com/NixOS/nixpkgs/actions/runs/${{ github.run_id }}). + token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000000000..d3a6d2a56a82b --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,149 @@ +name: PR + +on: + pull_request: + paths: + - .github/workflows/build.yml + - .github/workflows/check.yml + - .github/workflows/eval.yml + - .github/workflows/lint.yml + - .github/workflows/pr.yml + - .github/workflows/labels.yml + - .github/workflows/reviewers.yml # needs eval results from the same event type + pull_request_target: + +concurrency: + group: pr-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +permissions: {} + +jobs: + prepare: + runs-on: ubuntu-24.04-arm + outputs: + baseBranch: ${{ steps.branches.outputs.base }} + headBranch: ${{ steps.branches.outputs.head }} + mergedSha: ${{ steps.get-merge-commit.outputs.mergedSha }} + targetSha: ${{ steps.get-merge-commit.outputs.targetSha }} + systems: ${{ steps.systems.outputs.systems }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + sparse-checkout: | + .github/actions + ci/supportedBranches.js + ci/supportedSystems.json + - name: Check if the PR can be merged and get the test merge commit + uses: ./.github/actions/get-merge-commit + id: get-merge-commit + + - name: Load supported systems + id: systems + run: | + echo "systems=$(jq -c > "$GITHUB_OUTPUT" + + - name: Determine branch type + id: branches + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const { classify } = require('./ci/supportedBranches.js') + const { base, head } = context.payload.pull_request + + const baseClassification = classify(base.ref) + core.setOutput('base', baseClassification) + core.info('base classification:', baseClassification) + + const headClassification = + (base.repo.full_name == head.repo.full_name) ? + classify(head.ref) : + // PRs from forks are always considered WIP. + { type: ['wip'] } + core.setOutput('head', headClassification) + core.info('head classification:', headClassification) + + check: + name: Check + needs: [prepare] + uses: ./.github/workflows/check.yml + permissions: + # cherry-picks + pull-requests: write + with: + baseBranch: ${{ needs.prepare.outputs.baseBranch }} + headBranch: ${{ needs.prepare.outputs.headBranch }} + + lint: + name: Lint + needs: [prepare] + uses: ./.github/workflows/lint.yml + with: + mergedSha: ${{ needs.prepare.outputs.mergedSha }} + targetSha: ${{ needs.prepare.outputs.targetSha }} + + eval: + name: Eval + needs: [prepare] + uses: ./.github/workflows/eval.yml + permissions: + # compare + statuses: write + secrets: + OWNER_APP_PRIVATE_KEY: ${{ secrets.OWNER_APP_PRIVATE_KEY }} + with: + mergedSha: ${{ needs.prepare.outputs.mergedSha }} + targetSha: ${{ needs.prepare.outputs.targetSha }} + systems: ${{ needs.prepare.outputs.systems }} + + labels: + name: Labels + needs: [prepare, eval] + uses: ./.github/workflows/labels.yml + permissions: + issues: write + pull-requests: write + secrets: + NIXPKGS_CI_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }} + with: + headBranch: ${{ needs.prepare.outputs.headBranch }} + + reviewers: + name: Reviewers + needs: [prepare, eval] + if: | + needs.prepare.outputs.targetSha && + !contains(fromJSON(needs.prepare.outputs.headBranch).type, 'development') + uses: ./.github/workflows/reviewers.yml + secrets: + OWNER_APP_PRIVATE_KEY: ${{ secrets.OWNER_APP_PRIVATE_KEY }} + + build: + name: Build + needs: [prepare] + uses: ./.github/workflows/build.yml + secrets: + CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} + with: + baseBranch: ${{ needs.prepare.outputs.baseBranch }} + mergedSha: ${{ needs.prepare.outputs.mergedSha }} + + # This job's only purpose is to serve as a target for the "Required Status Checks" branch ruleset. + # It "needs" all the jobs that should block merging a PR. + # If they pass, it is skipped — which counts as "success" for purposes of the branch ruleset. + # However, if any of them fail, this job will also fail — thus blocking the branch ruleset. + no-pr-failures: + # Modify this list to add or remove jobs from required status checks. + needs: + - check + - lint + - eval + - build + # WARNING: + # Do NOT change the name of this job, otherwise the rule will not catch it anymore. + # This would prevent all PRs from merging. + name: no PR failures + if: ${{ failure() }} + runs-on: ubuntu-24.04-arm + steps: + - run: exit 1 diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 0000000000000..407b77194f35f --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,48 @@ +name: Push + +on: + pull_request: + paths: + - .github/workflows/push.yml + # eval is tested via pr.yml + push: + # Keep this synced with ci/request-reviews/dev-branches.txt + branches: + - master + - staging + - release-* + - staging-* + - haskell-updates + - python-updates + +permissions: {} + +jobs: + prepare: + runs-on: ubuntu-24.04-arm + outputs: + systems: ${{ steps.systems.outputs.systems }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + sparse-checkout: | + ci/supportedSystems.json + + - name: Load supported systems + id: systems + run: | + echo "systems=$(jq -c > "$GITHUB_OUTPUT" + + eval: + name: Eval + needs: [prepare] + uses: ./.github/workflows/eval.yml + # Those are not actually used on push, but will throw an error if not set. + permissions: + # compare + issues: write + pull-requests: write + statuses: write + with: + mergedSha: ${{ github.sha }} + systems: ${{ needs.prepare.outputs.systems }} diff --git a/.github/workflows/review-dismissed.yml b/.github/workflows/review-dismissed.yml new file mode 100644 index 0000000000000..988b4a47df14b --- /dev/null +++ b/.github/workflows/review-dismissed.yml @@ -0,0 +1,17 @@ +name: Review dismissed + +on: + pull_request_review: + types: [dismissed] + +permissions: {} + +defaults: + run: + shell: bash + +jobs: + trigger: + runs-on: ubuntu-24.04-arm + steps: + - run: echo This is a no-op only used as a trigger for workflow_run. diff --git a/.github/workflows/reviewers.yml b/.github/workflows/reviewers.yml new file mode 100644 index 0000000000000..1d518133cf6d2 --- /dev/null +++ b/.github/workflows/reviewers.yml @@ -0,0 +1,144 @@ +# This workflow will request reviews from the maintainers of each package +# listed in the PR's most recent eval comparison artifact. + +name: Reviewers + +on: + pull_request: + paths: + - .github/workflows/reviewers.yml + pull_request_target: + types: [ready_for_review] + workflow_call: + secrets: + OWNER_APP_PRIVATE_KEY: + required: true + +concurrency: + group: reviewers-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +permissions: {} + +defaults: + run: + shell: bash + +jobs: + request: + runs-on: ubuntu-24.04-arm + steps: + - name: Check out the PR at the base commit + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + path: trusted + sparse-checkout: ci + + - name: Install Nix + uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 + with: + extra_nix_config: sandbox = true + + - name: Build the requestReviews derivation + run: nix-build trusted/ci -A requestReviews + + # 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@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + if: github.event_name == 'pull_request_target' && vars.OWNER_APP_ID + id: app-token + with: + app-id: ${{ vars.OWNER_APP_ID }} + private-key: ${{ secrets.OWNER_APP_PRIVATE_KEY }} + permission-administration: read + permission-members: read + permission-pull-requests: write + + - name: Log current API rate limits (github.token) + env: + GH_TOKEN: ${{ github.token }} + run: gh api /rate_limit | jq + + # In the regular case, this workflow is called via workflow_call from the eval workflow directly. + # In the more special case, when a PR is undrafted an eval run will have started already. + - name: Wait for comparison to be done + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + id: eval + with: + script: | + const run_id = (await github.rest.actions.listWorkflowRuns({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'pr.yml', + event: context.eventName, + head_sha: context.payload.pull_request.head.sha + })).data.workflow_runs[0].id + + core.setOutput('run-id', run_id) + + // Waiting 120 * 5 sec = 10 min. max. + // The extreme case is an Eval run that just started when the PR is undrafted. + // Eval takes max 5-6 minutes, normally. + for (let i = 0; i < 120; i++) { + const result = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id, + name: 'comparison' + }) + if (result.data.total_count > 0) return + await new Promise(resolve => setTimeout(resolve, 5000)) + } + throw new Error("No comparison artifact found.") + + - name: Log current API rate limits (github.token) + env: + GH_TOKEN: ${{ github.token }} + run: gh api /rate_limit | jq + + - name: Download the comparison results + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + run-id: ${{ steps.eval.outputs.run-id }} + github-token: ${{ github.token }} + pattern: comparison + path: comparison + merge-multiple: true + + - name: Log current API rate limits (app-token) + if: ${{ steps.app-token.outputs.token }} + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: gh api /rate_limit | jq + + - name: Log current API rate limits (github.token) + env: + GH_TOKEN: ${{ github.token }} + run: gh api /rate_limit | jq + + - name: Requesting maintainer reviews + if: ${{ steps.app-token.outputs.token }} + env: + GH_TOKEN: ${{ github.token }} + REPOSITORY: ${{ github.repository }} + NUMBER: ${{ github.event.number }} + AUTHOR: ${{ github.event.pull_request.user.login }} + # Don't request reviewers on draft PRs + DRY_MODE: ${{ github.event.pull_request.draft && '1' || '' }} + run: | + # maintainers.json contains GitHub IDs. Look up handles to request reviews from. + # There appears to be no API to request reviews based on GitHub IDs + jq -r 'keys[]' comparison/maintainers.json \ + | while read -r id; do gh api /user/"$id" --jq .login; done \ + | GH_TOKEN=${{ steps.app-token.outputs.token }} result/bin/request-reviewers.sh "$REPOSITORY" "$NUMBER" "$AUTHOR" + + - name: Log current API rate limits (app-token) + if: ${{ steps.app-token.outputs.token }} + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: gh api /rate_limit | jq + + - name: Log current API rate limits (github.token) + env: + GH_TOKEN: ${{ github.token }} + run: gh api /rate_limit | jq diff --git a/.github/workflows/semantic-release.yml b/.github/workflows/semantic-release.yml deleted file mode 100644 index 722fc5aecb008..0000000000000 --- a/.github/workflows/semantic-release.yml +++ /dev/null @@ -1,22 +0,0 @@ -on: push - -concurrency: - group: semantic-release-${{ github.ref }} - cancel-in-progress: true - - -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: - - macos-15-large - - macos-latest - - ubuntu-latest - - ubuntu-latest-arm64 - steps: - - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v31 - - run: nix run .#semantic-release -- --version -