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
111 changes: 80 additions & 31 deletions .github/actions/checkout/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,88 @@ inputs:
runs:
using: composite
steps:
- if: inputs.merged-as-untrusted-at
# 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
Comment thread
Mic92 marked this conversation as resolved.
Outdated
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
ref: ${{ inputs.merged-as-untrusted-at }}
path: untrusted

- if: inputs.target-as-trusted-at
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
ref: ${{ inputs.target-as-trusted-at }}
path: trusted

- if: inputs.pinned-from
id: pinned
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
env:
MERGED_SHA: ${{ inputs.merged-as-untrusted-at }}
PINNED_FROM: ${{ inputs.pinned-from }}
TARGET_SHA: ${{ inputs.target-as-trusted-at }}
with:
script: |
const path = require('node:path')
const pinned = require(path.resolve(path.join(process.env.PINNED_FROM, 'ci', 'pinned.json')))
core.setOutput('pinned-at', pinned.pins.nixpkgs.revision)
const { spawn } = require('node:child_process')
const { join } = require('node:path')

- if: steps.pinned.outputs.pinned-at
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
ref: ${{ steps.pinned.outputs.pinned-at }}
path: pinned
sparse-checkout: |
lib
maintainers
nixos/lib
pkgs
async function run(cmd, ...args) {
return new Promise((resolve, reject) => {
const proc = spawn(cmd, args, {
stdio: 'inherit'
})
proc.on('close', (code) => {
if (code === 0) resolve()
else reject(code)
})
})
}

// These are set automatically by the spare checkout for .github/actions.
// Undo them, otherwise git fetch below will not do anything.
await run('git', 'config', 'unset', 'remote.origin.promisor')
await run('git', 'config', 'unset', 'remote.origin.partialclonefilter')

// Getting the pinned SHA via API allows us to do one single fetch call for all commits.
// Otherwise we would have to fetch merged/target first, read pinned, fetch again.
// A single fetch call comes with a lot less overhead. The fetch takes essentially the
// same time no matter whether its 1, 2 or 3 commits at once.
async function getPinnedSha(ref) {
const { content, encoding } = (await github.rest.repos.getContent({
...context.repo,
path: 'ci/pinned.json',
ref,
})).data
const pinned = JSON.parse(Buffer.from(content, encoding).toString())
return pinned.pins.nixpkgs.revision
}

const commits = [
{
sha: process.env.MERGED_SHA,
path: 'untrusted',
},
{
sha: process.env.PINNED_FROM === 'untrusted' && (await getPinnedSha(process.env.MERGED_SHA)),
path: 'pinned'
},
{
sha: process.env.TARGET_SHA,
path: 'trusted',
},
{
sha: process.env.PINNED_FROM === 'trusted' && (await getPinnedSha(process.env.TARGET_SHA)),
path: 'pinned'
}
].filter(({ sha }) => Boolean(sha))

console.log('Checking out the following commits:', commits)

// Fetching all commits at once is much faster than doing multiple checkouts.
// This would fail without --refetch, because the we had a partial clone before, but changed it above.
await run('git', 'fetch', '--depth=1', '--refetch', 'origin', ...(commits.map(({ sha }) => sha)))

// Create all worktrees in parallel.
await Promise.all(commits.map(async ({ sha, path }) => {
// Checking out onto tmpfs takes 1s and is faster by at least factor 10x.
await run('mkdir', path)
switch (process.env.RUNNER_OS) {
case 'macOS':
await run('sudo', 'mount_tmpfs', path)
// macOS creates this hidden folder to log file system activity.
// This trips up git when adding a worktree below, because the target folder is not empty.
await run('sudo', 'rm', '-rf', join(path, '.fseventsd'))
break
Comment on lines +87 to +92

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This part doesn't work too well for MacOS, yet.

https://github.com/NixOS/nixpkgs/actions/runs/17147656253/job/48646939225
https://github.com/NixOS/nixpkgs/actions/runs/17146824086/job/48644655746
https://github.com/NixOS/nixpkgs/actions/runs/17146214373/job/48643006331

All the same error:

fatal: 'untrusted' already exists

(alternatively "pinned")

The problem here is that either darwin recreates the .fseventsd folder or creates other files/folders in there - which makes git unhappy.

A better fix might be to mount a single tmpfs and create subdirectories on it for the checkouts.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A better fix might be to mount a single tmpfs and create subdirectories on it for the checkouts.

Agreed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Working on a fix in #435806.

case 'Linux':
await run('sudo', 'mount', '-t', 'tmpfs', 'tmpfs', path)
break
}
await run('git', 'worktree', 'add', path, sha, '--no-checkout', '--force')
await run('git', '-C', path, 'sparse-checkout', 'disable')
await run('git', '-C', path, 'checkout', '--progress')
}))
4 changes: 2 additions & 2 deletions .github/workflows/eval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ jobs:
- name: Check out the PR at the target commit
uses: ./.github/actions/checkout
with:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
target-as-trusted-at: ${{ inputs.targetSha }}
pinned-from: trusted

Expand All @@ -240,7 +241,6 @@ jobs:
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

Expand Down Expand Up @@ -392,7 +392,7 @@ jobs:
uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31

- name: Ensure flake outputs on all systems still evaluate
run: nix flake check --all-systems --no-build ./untrusted
run: nix flake check --all-systems --no-build './untrusted?shallow=1'

- name: Query nixpkgs with aliases enabled to check for basic syntax errors
run: |
Expand Down
Loading