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
15 changes: 11 additions & 4 deletions .github/actions/get-merge-commit/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ name: Get merge commit
description: 'Checks whether the Pull Request is mergeable and checks out the repo at up to two commits: The result of a temporary merge of the head branch into the target branch ("merged"), and the parent of that commit on the target branch ("target"). Handles push events and merge conflicts gracefully.'

inputs:
mergedSha:
description: "The merge commit SHA, previously collected."
type: string
merged-as-untrusted:
description: "Whether to checkout the merge commit in the ./untrusted folder."
type: boolean
targetSha:
description: "The target commit SHA, previously collected."
type: string
target-as-trusted:
description: "Whether to checkout the target commit in the ./trusted folder."
type: boolean
Expand All @@ -22,6 +28,7 @@ runs:
using: composite
steps:
- id: commits
if: ${{ !inputs.mergedSha && !inputs.targetSha }}
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
Expand Down Expand Up @@ -72,17 +79,17 @@ runs:
}
throw new Error("Not retrying anymore. It's likely that GitHub is having internal issues: check https://www.githubstatus.com.")

- if: inputs.merged-as-untrusted && steps.commits.outputs.mergedSha
- if: inputs.merged-as-untrusted && (inputs.mergedSha || steps.commits.outputs.mergedSha)
# Would be great to do the checkouts in git worktrees of the existing spare checkout instead,
# but Nix is broken with them:
# https://github.com/NixOS/nix/issues/6073
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ steps.commits.outputs.mergedSha }}
ref: ${{ inputs.mergedSha || steps.commits.outputs.mergedSha }}
path: untrusted

- if: inputs.target-as-trusted && steps.commits.outputs.targetSha
- if: inputs.target-as-trusted && (inputs.targetSha || steps.commits.outputs.targetSha)
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ steps.commits.outputs.targetSha }}
ref: ${{ inputs.targetSha || steps.commits.outputs.targetSha }}
path: trusted
5 changes: 5 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: Build

on:
workflow_call:
inputs:
mergedSha:
required: true
type: string
secrets:
CACHIX_AUTH_TOKEN:
required: true
Expand Down Expand Up @@ -39,6 +43,7 @@ jobs:
- 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@17fe5fb4a23ad6cbbe47d6b3f359611ad276644c # v31
Expand Down
83 changes: 23 additions & 60 deletions .github/workflows/eval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ 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
Expand All @@ -13,34 +22,12 @@ defaults:
shell: bash

jobs:
prepare:
runs-on: ubuntu-24.04-arm
outputs:
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/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 <ci/supportedSystems.json)" >> "$GITHUB_OUTPUT"

eval:
runs-on: ubuntu-24.04-arm
needs: [prepare]
strategy:
fail-fast: false
matrix:
system: ${{ fromJSON(needs.prepare.outputs.systems) }}
system: ${{ fromJSON(inputs.systems) }}
name: ${{ matrix.system }}
steps:
- name: Enable swap
Expand All @@ -53,7 +40,7 @@ jobs:
- name: Check out the PR at the test merge commit
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ needs.prepare.outputs.mergedSha }}
ref: ${{ inputs.mergedSha }}
path: untrusted

- name: Install Nix
Expand All @@ -78,12 +65,12 @@ jobs:
path: merged/*

- name: Get target run id
if: needs.prepare.outputs.targetSha
if: inputs.targetSha
id: targetRunId
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
env:
MATRIX_SYSTEM: ${{ matrix.system }}
TARGET_SHA: ${{ needs.prepare.outputs.targetSha }}
TARGET_SHA: ${{ inputs.targetSha }}
with:
script: |
const system = process.env.MATRIX_SYSTEM
Expand All @@ -92,14 +79,13 @@ jobs:
let run_id
try {
run_id = (await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
...context.repo,
workflow_id: 'push.yml',
event: 'push',
head_sha: targetSha
})).data.workflow_runs[0].id
} catch {
throw new Error(`Could not find an push.yml workflow run for ${targetSha}.`)
throw new Error(`Could not find a push.yml workflow run for ${targetSha}.`)
}

core.setOutput('targetRunId', run_id)
Expand All @@ -108,8 +94,7 @@ jobs:
// 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,
...context.repo,
run_id,
name: `merged-${system}`
})
Expand Down Expand Up @@ -147,11 +132,9 @@ jobs:

compare:
runs-on: ubuntu-24.04-arm
needs: [prepare, eval]
if: needs.prepare.outputs.targetSha
needs: [eval]
if: inputs.targetSha
permissions:
issues: write # needed to create *new* labels
pull-requests: write
statuses: write
steps:
- name: Download output paths and eval stats for all systems
Expand All @@ -164,7 +147,7 @@ jobs:
- name: Check out the PR at the target commit
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ needs.prepare.outputs.targetSha }}
ref: ${{ inputs.targetSha }}
path: trusted

- name: Install Nix
Expand All @@ -182,8 +165,8 @@ jobs:
env:
AUTHOR_ID: ${{ github.event.pull_request.user.id }}
run: |
git -C trusted fetch --depth 1 origin ${{ needs.prepare.outputs.mergedSha }}
git -C trusted diff --name-only ${{ needs.prepare.outputs.mergedSha }} \
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
Expand Down Expand Up @@ -224,34 +207,14 @@ jobs:
`${serverUrl}/${repo.owner}/${repo.repo}/actions/runs/${runId}?pr=${payload.pull_request.number}`

await github.rest.repos.createCommitStatus({
owner: repo.owner,
repo: repo.repo,
...repo,
sha: payload.pull_request.head.sha,
context: 'Eval / Summary',
context: 'Eval Summary',
state: 'success',
description,
target_url
})

labels:
name: Labels
needs: [compare]
uses: ./.github/workflows/labels.yml
permissions:
issues: write
pull-requests: write

reviewers:
name: Reviewers
# No dependency on "compare", so that it can start at the same time.
# We only wait for the "comparison" artifact to be available, which makes the start-to-finish time
# for the eval workflow considerably faster.
needs: [prepare, eval]
if: needs.prepare.outputs.targetSha
uses: ./.github/workflows/reviewers.yml
secrets:
OWNER_APP_PRIVATE_KEY: ${{ secrets.OWNER_APP_PRIVATE_KEY }}

misc:
if: ${{ github.event_name != 'push' }}
runs-on: ubuntu-24.04-arm
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ name: Lint

on:
workflow_call:
inputs:
mergedSha:
required: true
type: string
targetSha:
required: true
type: string

permissions: {}

Expand All @@ -19,6 +26,7 @@ jobs:
- 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@17fe5fb4a23ad6cbbe47d6b3f359611ad276644c # v31
Expand Down Expand Up @@ -50,6 +58,7 @@ jobs:
- 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@17fe5fb4a23ad6cbbe47d6b3f359611ad276644c # v31
Expand All @@ -72,7 +81,9 @@ jobs:
- 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@17fe5fb4a23ad6cbbe47d6b3f359611ad276644c # v31
Expand Down
69 changes: 68 additions & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,27 @@ concurrency:
permissions: {}

jobs:
prepare:
runs-on: ubuntu-24.04-arm
outputs:
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/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 <ci/supportedSystems.json)" >> "$GITHUB_OUTPUT"

check:
name: Check
uses: ./.github/workflows/check.yml
Expand All @@ -27,21 +48,67 @@ jobs:

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: [eval]
uses: ./.github/workflows/labels.yml
permissions:
issues: write
pull-requests: write
statuses: write

reviewers:
name: Reviewers
needs: [prepare, eval]
if: needs.prepare.outputs.targetSha
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:
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
Comment on lines +96 to +114
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume, before merging, we should confirm in NixOS/org#130 that we are definitely planning to enable required status checks at some point?

I can't see why we wouldn't want to... But if the proposal was blocked for any reason, then we wouldn't need to merge this job.


Alternatively, we could merge it optimistically so that we can see it working in production.

Once we've proven the CI is working, it will be easier to argue in favour of requiring it.

With this approach, we can still remove the job later if the proposal is blocked or we change our minds (for whatever reason).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we could merge it optimistically

I'd say let's do that, yes. It's not going to do any harm if unused - especially with the new naming that doesn't say anything about "required" anymore.

Loading
Loading