Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .github/workflows/dismissed-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Dismissed review

on:
workflow_run:
workflows:
- Review dismissed
types: [completed]

concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || 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 }
))
)
)
)
50 changes: 10 additions & 40 deletions .github/workflows/eval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,46 +213,6 @@ jobs:
name: comparison
path: comparison/*

- name: Labelling pull request
if: ${{ github.event_name == 'pull_request_target' }}
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const { readFile } = require('node:fs/promises')

const pr = {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number
}

// Get all currently set labels that we manage
const before =
(await github.paginate(github.rest.issues.listLabelsOnIssue, pr))
.map(({ name }) => name)
.filter(name => name.startsWith('10.rebuild') || name == '11.by: package-maintainer')

// And the labels that should be there
const after = JSON.parse(await readFile('comparison/changed-paths.json', 'utf-8')).labels

// Remove the ones not needed anymore
await Promise.all(
before.filter(name => !after.includes(name))
.map(name => github.rest.issues.removeLabel({
...pr,
name
}))
)

// And add the ones that aren't set already
const added = after.filter(name => !before.includes(name))
if (added.length > 0) {
await github.rest.issues.addLabels({
...pr,
labels: added
})
}

- name: Add eval summary to commit statuses
if: ${{ github.event_name == 'pull_request_target' }}
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
Expand Down Expand Up @@ -285,6 +245,16 @@ jobs:
target_url
})

labels:
name: Labels
needs: [ compare ]
uses: ./.github/workflows/labels.yml
permissions:
issues: write
pull-requests: write
with:
caller: ${{ github.workflow }}

reviewers:
name: Reviewers
# No dependency on "compare", so that it can start at the same time.
Expand Down
126 changes: 123 additions & 3 deletions .github/workflows/labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,23 @@
name: "Label PR"

on:
pull_request_target:
workflow_call:
inputs:
caller:
description: Name of the calling workflow.
required: true
type: string
workflow_run:
workflows:
- Review dismissed
- Review submitted
types: [completed]

concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.run_id }}
group: ${{ inputs.caller }}-${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read
issues: write # needed to create *new* labels
pull-requests: write

Expand All @@ -23,8 +32,113 @@ jobs:
runs-on: ubuntu-24.04-arm
if: "!contains(github.event.pull_request.title, '[skip treewide]')"
steps:
- 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: 'eval.yml',
event: 'pull_request_target',
head_sha: context.payload.pull_request?.head.sha ?? context.payload.workflow_run.head_sha
})).data.workflow_runs[0]?.id
core.setOutput('run-id', run_id)

- name: Download the comparison results
if: steps.eval.outputs.run-id
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: Labels from eval
if: steps.eval.outputs.run-id && github.event_name != 'pull_request'
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const { readFile } = require('node:fs/promises')

let pull_requests
if (context.payload.workflow_run) {
// 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
pull_requests = (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)
} else {
pull_requests = [ context.payload.pull_request ]
}

await Promise.all(
pull_requests.map(async (pull_request) => {
const pr = {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pull_request.number
}

// Get all currently set labels that we manage
const before =
(await github.paginate(github.rest.issues.listLabelsOnIssue, pr))
.map(({ name }) => name)
.filter(name =>
name.startsWith('10.rebuild') ||
name == '11.by: package-maintainer' ||
name.startsWith('12.approvals:') ||
name == '12.approved-by: package-maintainer'
)

const approvals =
(await github.paginate(github.rest.pulls.listReviews, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pull_request.number
}))
.filter(review => review.state == 'APPROVED')
.map(review => review.user.id)

const maintainers = Object.keys(
JSON.parse(await readFile('comparison/maintainers.json', 'utf-8'))
)

// And the labels that should be there
const after = JSON.parse(await readFile('comparison/changed-paths.json', 'utf-8')).labels
if (approvals.length > 0) after.push(`12.approvals: ${approvals.length > 2 ? '3+' : approvals.length}`)
if (maintainers.some(id => approvals.includes(id))) after.push('12.approved-by: package-maintainer')

// Remove the ones not needed anymore
await Promise.all(
before.filter(name => !after.includes(name))
.map(name => github.rest.issues.removeLabel({
...pr,
name
}))
)

// And add the ones that aren't set already
const added = after.filter(name => !before.includes(name))
if (added.length > 0) {
await github.rest.issues.addLabels({
...pr,
labels: added
})
}
})
)

- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
name: Labels from touched files
if: |
github.event_name != 'workflow_run' &&
github.event.pull_request.head.repo.owner.login != 'NixOS' || !(
github.head_ref == 'haskell-updates' ||
github.head_ref == 'python-updates' ||
Expand All @@ -35,8 +149,11 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }}
configuration-path: .github/labeler.yml # default
sync-labels: true

- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
name: Labels from touched files (no sync)
if: |
github.event_name != 'workflow_run' &&
github.event.pull_request.head.repo.owner.login != 'NixOS' || !(
github.head_ref == 'haskell-updates' ||
github.head_ref == 'python-updates' ||
Expand All @@ -47,11 +164,14 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }}
configuration-path: .github/labeler-no-sync.yml
sync-labels: false

- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
name: Labels from touched files (development branches)
# Development branches like staging-next, haskell-updates and python-updates get special labels.
# This is to avoid the mass of labels there, which is mostly useless - and really annoying for
# the backport labels.
if: |
github.event_name != 'workflow_run' &&
github.event.pull_request.head.repo.owner.login == 'NixOS' && (
github.head_ref == 'haskell-updates' ||
github.head_ref == 'python-updates' ||
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/review-dismissed.yml
Original file line number Diff line number Diff line change
@@ -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.
17 changes: 17 additions & 0 deletions .github/workflows/review-submitted.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Review submitted

on:
pull_request_review:
types: [submitted]

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.
Loading