Compare commits

..

1 Commits

38023 changed files with 865256 additions and 1258390 deletions

View File

@@ -1,11 +1,13 @@
{
"name": "nixpkgs",
"image": "mcr.microsoft.com/devcontainers/universal:5-linux",
"image": "mcr.microsoft.com/devcontainers/universal:2-linux",
"features": {
"ghcr.io/devcontainers/features/nix:1": {
// fails in the devcontainer sandbox, enable sandbox via config instead
"multiUser": false,
"packages": "nixpkgs.nixd,nixpkgs.nixfmt",
// TODO: nixfmt-rfc-style → nixfmt (once it's in a stable release)
// https://github.com/NixOS/nixpkgs/issues/425583
"packages": "nixpkgs.nixd,nixpkgs.nixfmt-rfc-style",
"useAttributePath": true,
"extraNixConfig": "experimental-features = nix-command flakes,sandbox = true"
}

View File

@@ -64,9 +64,6 @@ insert_final_newline = unset
end_of_line = unset
trim_trailing_whitespace = unset
[*.json]
insert_final_newline = unset
[*.lock]
indent_size = unset

View File

@@ -310,6 +310,3 @@ c283f32d296564fd649ef3ed268c1f1f7b199c49 # !autorebase nix-shell --run treefmt
# treewide: clean up 'meta = with' pattern
567e8dfd8eddc5468e6380fc563ab8a27422ab1d
# nixfmt 1.2.0
28096cc5e3d8334fbe1845925f000f8c8c5e0aac # !autorebase nix-shell --run treefmt

23
.gitattributes vendored
View File

@@ -1,26 +1,7 @@
# node/js lock files
**/package-lock.json linguist-generated
**/yarn.nix linguist-generated
**/yarn.lock linguist-generated
# Rust lock files
**/Cargo.lock linguist-generated
pkgs/build-support/rust/**/Cargo.lock -linguist-generated
# NuGet, Gradle and others
**/deps.json linguist-generated
# Ruby lock files
**/gemset.nix linguist-generated
**/Gemfile.lock linguist-generated
# PHP lock files
**/composer.lock linguist-generated
# various package managers and tools
**/deps.nix linguist-generated
**/deps.json linguist-generated
**/deps.toml linguist-generated
**/node-packages.nix linguist-generated
pkgs/applications/editors/emacs-modes/*-generated.nix linguist-generated
pkgs/development/r-modules/*-packages.nix linguist-generated

6
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,6 @@
<!--
Please note: This blank issue template is meant for extraordinary issues
that do not fit the templates. Unless you know your issue is relevant to
Nixpkgs and requires the free-form blank issue, please use the issue
templates instead.
-->

View File

@@ -35,8 +35,9 @@ body:
If you are using an older version, please update to the latest stable version and check if the issue persists before continuing this bug report.
options:
- "Please select a version."
- "- Unstable (26.11)"
- "- Stable (26.05)"
- "- Unstable (26.05)"
- "- Stable (25.11)"
- "- Old Stable (25.05)"
default: 0
validations:
required: true
@@ -54,7 +55,7 @@ body:
description: "Please include a step-by-step guide for reproducing this issue. Consider writing in concise, numbered bullet points to ensure that Nixpkgs developers can retrace your steps."
validations:
required: true
- type: "textarea"
- type: "input"
id: "expected-behaviour"
attributes:
label: "Expected behaviour"
@@ -117,12 +118,10 @@ body:
options:
- label: "I assert that this is a bug and not a support request."
required: true
- label: "I assert that this is not a [duplicate of an existing issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+label%3A%220.kind%3A+bug%22+-label%3A%226.topic%3A+darwin%22+-label%3A%226.topic%3A+nixos%22). "
- label: "I assert that this is not a [duplicate of an existing issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aopen+is%3Aissue+label%3A%220.kind%3A+bug%22+-label%3A%226.topic%3A+darwin%22+-label%3A%226.topic%3A+nixos%22). "
required: true
- label: "I assert that I have read the [NixOS Code of Conduct](https://github.com/NixOS/.github/blob/master/CODE_OF_CONDUCT.md) and agree to abide by it."
required: true
- label: "I assert that I have read the [automation/AI policy](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#automationai-policy) and that this issue report complies with it."
required: true
- type: "markdown"
attributes:
value: |

View File

@@ -35,8 +35,9 @@ body:
If you are using an older version, please update to the latest stable version and check if the issue persists before continuing this bug report.
options:
- "Please select a version."
- "- Unstable (26.11)"
- "- Stable (26.05)"
- "- Unstable (26.05)"
- "- Stable (25.11)"
- "- Old Stable (25.05)"
default: 0
validations:
required: true
@@ -54,7 +55,7 @@ body:
description: "Please include a step-by-step guide for reproducing this issue. Consider writing in concise, numbered bullet points to ensure that Nixpkgs developers can retrace your steps."
validations:
required: true
- type: "textarea"
- type: "input"
id: "expected-behaviour"
attributes:
label: "Expected behaviour"
@@ -99,7 +100,7 @@ body:
attributes:
label: "Are you using nix-darwin?"
description: |
[`nix-darwin`](https://github.com/nix-darwin/nix-darwin) is a set of NixOS-like modules for macOS systems. Depending on your issue, this information may be relevant.
[`nix-darwin`](https://github.com/LnL7/nix-darwin) is a set of NixOS-like modules for macOS systems. Depending on your issue, this information may be relevant.
options:
- "Yes, I am using nix-darwin."
- "No, I am not using nix-darwin."
@@ -131,12 +132,10 @@ body:
options:
- label: "I assert that this is a bug and not a support request."
required: true
- label: "I assert that this is not a [duplicate of an existing issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+label%3A%220.kind%3A+bug%22+label%3A%226.topic%3A+darwin%22). "
- label: "I assert that this is not a [duplicate of an existing issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aopen+is%3Aissue+label%3A%220.kind%3A+bug%22+label%3A%226.topic%3A+darwin%22). "
required: true
- label: "I assert that I have read the [NixOS Code of Conduct](https://github.com/NixOS/.github/blob/master/CODE_OF_CONDUCT.md) and agree to abide by it."
required: true
- label: "I assert that I have read the [automation/AI policy](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#automationai-policy) and that this issue report complies with it."
required: true
- type: "markdown"
attributes:
value: |

View File

@@ -35,8 +35,9 @@ body:
If you are using an older version, please update to the latest stable version and check if the issue persists before continuing this bug report.
options:
- "Please select a version."
- "- Unstable (26.11)"
- "- Stable (26.05)"
- "- Unstable (26.05)"
- "- Stable (25.11)"
- "- Old Stable (25.05)"
default: 0
validations:
required: true
@@ -54,7 +55,7 @@ body:
description: "Please include a step-by-step guide for reproducing this issue. Consider writing in concise, numbered bullet points to ensure that Nixpkgs developers can retrace your steps."
validations:
required: true
- type: "textarea"
- type: "input"
id: "expected-behaviour"
attributes:
label: "Expected behaviour"
@@ -121,12 +122,10 @@ body:
options:
- label: "I assert that this is a bug and not a support request."
required: true
- label: "I assert that this is not a [duplicate of an existing issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+label%3A%220.kind%3A+bug%22+label%3A%226.topic%3A+nixos%22). "
- label: "I assert that this is not a [duplicate of an existing issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aopen+is%3Aissue+label%3A%220.kind%3A+bug%22+label%3A%226.topic%3A+nixos%22). "
required: true
- label: "I assert that I have read the [NixOS Code of Conduct](https://github.com/NixOS/.github/blob/master/CODE_OF_CONDUCT.md) and agree to abide by it."
required: true
- label: "I assert that I have read the [automation/AI policy](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#automationai-policy) and that this issue report complies with it."
required: true
- type: "markdown"
attributes:
value: |

View File

@@ -37,8 +37,9 @@ body:
If you are purposefully trying to build an ancient version of a package in an older Nixpkgs, please coordinate with the [NixOS Archivists](https://matrix.to/#/#archivists:nixos.org).
options:
- "Please select a version."
- "- Unstable (26.11)"
- "- Stable (26.05)"
- "- Unstable (26.05)"
- "- Stable (25.11)"
- "- Old Stable (25.05)"
default: 0
validations:
required: true
@@ -56,12 +57,12 @@ body:
description: |
Can [Hydra](https://hydra.nixos.org), Nixpkgs' Continuous Integration system, reproduce this build failure?
Please use the search function in the header bar to locate the last build job for the package in question.
- If there's a <img src="https://raw.githubusercontent.com/NixOS/hydra/refs/heads/master/subprojects/hydra/root/static/images/emojione-red-x-274c.svg" width="20px" align="top" alt="Red X"> icon near the package entry, say '**Yes, Hydra can reproduce this build failure.**'
- If there's a <img src="https://raw.githubusercontent.com/NixOS/hydra/refs/heads/master/subprojects/hydra/root/static/images/emojione-gray-x-2716.svg" width="20px" align="top" alt="Dark Gray X"> icon near the package entry, then the build failure occurs with another package, and you need to track the original failing package by going down the chain of 'Cached failures' until you reach the final package in the failing dependency chain. Once you locate the failing package, re-write this report against that package and say '**Yes, Hydra can reproduce this build failure.**'
- If there's a <img src="https://raw.githubusercontent.com/NixOS/hydra/refs/heads/master/subprojects/hydra/root/static/images/emojione-check-2714.svg" width="20px" align="top" alt="Green Check Mark"> icon near the package entry, then it most likely means it's a local issue with your system. (Maybe you ran out of space?)
- If there's a <img src="https://raw.githubusercontent.com/NixOS/hydra/refs/heads/master/src/root/static/images/emojione-red-x-274c.svg" width="20px" align="top" alt="Red X"> icon near the package entry, say '**Yes, Hydra can reproduce this build failure.**'
- If there's a <img src="https://raw.githubusercontent.com/NixOS/hydra/refs/heads/master/src/root/static/images/emojione-gray-x-2716.svg" width="20px" align="top" alt="Dark Gray X"> icon near the package entry, then the build failure occurs with another package, and you need to track the original failing package by going down the chain of 'Cached failures' until you reach the final package in the failing dependency chain. Once you locate the failing package, re-write this report against that package and say '**Yes, Hydra can reproduce this build failure.**'
- If there's a <img src="https://raw.githubusercontent.com/NixOS/hydra/refs/heads/master/src/root/static/images/emojione-check-2714.svg" width="20px" align="top" alt="Green Check Mark"> icon near the package entry, then it most likely means it's a local issue with your system. (Maybe you ran out of space?)
You can still open a build failure report, but please say '**No, Hydra cannot reproduce this build failure.**' below.
- If there's a <img src="https://raw.githubusercontent.com/NixOS/hydra/refs/heads/master/subprojects/hydra/root/static/images/emojione-question-2754.svg" width="20px" align="top" alt="Gray Question Mark"> icon near the package entry, say '**Hydra is currently rebuilding this package.**'
- If there's a <img src="https://raw.githubusercontent.com/NixOS/hydra/refs/heads/master/subprojects/hydra/root/static/images/emojione-stopsign-1f6d1.svg" width="20px" align="top" alt="Red Stop Sign"> icon near the package entry, then the build job was stopped manually. If this occurs, please coordinate with the [Infrastructure Team](https://matrix.to/#/#infra:nixos.org), and say '**The last build job was manually cancelled.**'
- If there's a <img src="https://raw.githubusercontent.com/NixOS/hydra/refs/heads/master/src/root/static/images/emojione-question-2754.svg" width="20px" align="top" alt="Gray Question Mark"> icon near the package entry, say '**Hydra is currently rebuilding this package.**'
- If there's a <img src="https://raw.githubusercontent.com/NixOS/hydra/refs/heads/master/src/root/static/images/emojione-stopsign-1f6d1.svg" width="20px" align="top" alt="Red Stop Sign"> icon near the package entry, then the build job was stopped manually. If this occurs, please coordinate with the [Infrastructure Team](https://matrix.to/#/#infra:nixos.org), and say '**The last build job was manually cancelled.**'
- If Hydra isn't supposed to build the package at all, say '**Hydra doesnt try to build the package.**'
options:
- "Please select the Hydra Status."
@@ -127,12 +128,10 @@ body:
options:
- label: "I assert that this is a bug and not a support request."
required: true
- label: "I assert that this is not a [duplicate of an existing issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+label%3A%220.kind%3A+build+failure%22)."
- label: "I assert that this is not a [duplicate of an existing issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aopen+is%3Aissue+label%3A%220.kind%3A+build+failure%22). "
required: true
- label: "I assert that I have read the [NixOS Code of Conduct](https://github.com/NixOS/.github/blob/master/CODE_OF_CONDUCT.md) and agree to abide by it."
required: true
- label: "I assert that I have read the [automation/AI policy](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#automationai-policy) and that this issue report complies with it."
required: true
- type: "markdown"
attributes:
value: |

View File

@@ -37,8 +37,9 @@ body:
If the package has been updated in unstable, but you believe the update should be backported to the stable release of Nixpkgs, please file the '**Request: backport to stable**' form instead.
options:
- "Please select a version."
- "- Unstable (26.11)"
- "- Stable (26.05)"
- "- Unstable (26.05)"
- "- Stable (25.11)"
- "- Old Stable (25.05)"
default: 0
validations:
required: true
@@ -100,12 +101,10 @@ body:
options:
- label: "I assert that this package update does not yet exist in an [open pull request](https://github.com/NixOS/nixpkgs/pulls?q=is%3Aopen+is%3Apr+label%3A%228.has%3A+package+%28update%29%22) or in [Nixpkgs Unstable](https://search.nixos.org/packages?channel=unstable)."
required: true
- label: "I assert that this is not a [duplicate of any known issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+label%3A%229.needs%3A+package+%28update%29%22)."
- label: "I assert that this is not a [duplicate of any known issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aopen+is%3Aissue+label%3A%229.needs%3A+package+%28update%29%22)."
required: true
- label: "I assert that I have read the [NixOS Code of Conduct](https://github.com/NixOS/.github/blob/master/CODE_OF_CONDUCT.md) and agree to abide by it."
required: true
- label: "I assert that I have read the [automation/AI policy](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#automationai-policy) and that this issue report complies with it."
required: true
- type: "markdown"
attributes:
value: |

View File

@@ -35,8 +35,9 @@ body:
If you are using an older or stable version, please update to the latest **unstable** version and check if the module still does not exist before continuing this request.
options:
- "Please select a version."
- "- Unstable (26.11)"
- "- Stable (26.05)"
- "- Unstable (26.05)"
- "- Stable (25.11)"
- "- Old Stable (25.05)"
default: 0
validations:
required: true
@@ -75,12 +76,10 @@ body:
options:
- label: "I assert that this module does not yet exist in an [open pull request](https://github.com/NixOS/nixpkgs/pulls?q=is%3Aopen+is%3Apr+label%3A%228.has%3A+module+%28new%29%22) or in [NixOS Unstable](https://search.nixos.org/options?channel=unstable)."
required: true
- label: "I assert that this is not a [duplicate of an existing issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+label%3A%229.needs%3A+module+%28new%29%22). "
- label: "I assert that this is not a [duplicate of an existing issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aopen+is%3Aissue+label%3A%229.needs%3A+module+%28new%29%22). "
required: true
- label: "I assert that I have read the [NixOS Code of Conduct](https://github.com/NixOS/.github/blob/master/CODE_OF_CONDUCT.md) and agree to abide by it."
required: true
- label: "I assert that I have read the [automation/AI policy](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#automationai-policy) and that this issue report complies with it."
required: true
- type: "markdown"
attributes:
value: |

View File

@@ -81,12 +81,10 @@ body:
options:
- label: "I assert that this backport does not yet exist in an [open pull request](https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+in%3Atitle+backport)."
required: true
- label: "I assert that this is not a [duplicate of any known issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+label%3A%229.needs%3A+port+to+stable%22+)."
- label: "I assert that this is not a [duplicate of any known issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+is%3Aopen+label%3A%229.needs%3A+port+to+stable%22+)."
required: true
- label: "I assert that I have read the [NixOS Code of Conduct](https://github.com/NixOS/.github/blob/master/CODE_OF_CONDUCT.md) and agree to abide by it."
required: true
- label: "I assert that I have read the [automation/AI policy](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#automationai-policy) and that this issue report complies with it."
required: true
- type: "markdown"
attributes:
value: |

View File

@@ -63,12 +63,10 @@ body:
options:
- label: "I assert that this request is not already implemented in the latest [NixOS](https://nixos.org/manual/nixos/unstable/) or [Nixpkgs](https://nixos.org/manual/nixpkgs/unstable/) manuals."
required: true
- label: "I assert that this is not a [duplicate of an existing documentation issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+label%3A%229.needs%3A+documentation%22)."
- label: "I assert that this is not a [duplicate of an existing documentation issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+is%3Aopen+label%3A%229.needs%3A+documentation%22)."
required: true
- label: "I assert that I have read the [NixOS Code of Conduct](https://github.com/NixOS/.github/blob/master/CODE_OF_CONDUCT.md) and agree to abide by it."
required: true
- label: "I assert that I have read the [automation/AI policy](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#automationai-policy) and that this issue report complies with it."
required: true
- type: "markdown"
attributes:
value: |

View File

@@ -133,12 +133,10 @@ body:
attributes:
label: "I assert that this issue is relevant for Nixpkgs"
options:
- label: "I assert that this is not a [duplicate of any known issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+label%3A%226.topic%3A+reproducible+builds%22)."
- label: "I assert that this is not a [duplicate of any known issue](https://github.com/NixOS/nixpkgs/issues?q=is%3Aopen+is%3Aissue+label%3A%226.topic%3A+reproducible+builds%22)."
required: true
- label: "I assert that I have read the [NixOS Code of Conduct](https://github.com/NixOS/.github/blob/master/CODE_OF_CONDUCT.md) and agree to abide by it."
required: true
- label: "I assert that I have read the [automation/AI policy](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#automationai-policy) and that this issue report complies with it."
required: true
- type: "markdown"
attributes:
value: |

View File

@@ -13,6 +13,7 @@ For new packages please briefly describe the package or provide a link to its ho
- Built on platform:
- [ ] x86_64-linux
- [ ] aarch64-linux
- [ ] x86_64-darwin
- [ ] aarch64-darwin
- Tested, as applicable:
- [ ] [NixOS tests] in [nixos/tests].
@@ -26,16 +27,21 @@ For new packages please briefly describe the package or provide a link to its ho
- [ ] Module addition: when adding a new NixOS module.
- [ ] Module update: when the change is significant.
- [ ] Fits [CONTRIBUTING.md], [pkgs/README.md], [maintainers/README.md] and other READMEs.
- [ ] Follows the [automation/AI policy].
[NixOS tests]: https://nixos.org/manual/nixos/unstable/index.html#sec-nixos-tests
[Package tests]: https://github.com/NixOS/nixpkgs/blob/master/pkgs/README.md#package-tests
[nixpkgs-review usage]: https://github.com/Mic92/nixpkgs-review#usage
[CONTRIBUTING.md]: https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md
[automation/AI policy]: https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#automationai-policy
[lib/tests]: https://github.com/NixOS/nixpkgs/blob/master/lib/tests
[maintainers/README.md]: https://github.com/NixOS/nixpkgs/blob/master/maintainers/README.md
[nixos/tests]: https://github.com/NixOS/nixpkgs/blob/master/nixos/tests
[pkgs/README.md]: https://github.com/NixOS/nixpkgs/blob/master/pkgs/README.md
[pkgs/test]: https://github.com/NixOS/nixpkgs/blob/master/pkgs/test
---
Add a :+1: [reaction] to [pull requests you find important].
[reaction]: https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/
[pull requests you find important]: https://github.com/NixOS/nixpkgs/pulls?q=is%3Aopen+sort%3Areactions-%2B1-desc

View File

@@ -7,21 +7,16 @@ inputs:
description: "Whether and which SHA to checkout for the merge commit in the ./nixpkgs/untrusted folder."
target-as-trusted-at:
description: "Whether and which SHA to checkout for the target commit in the ./nixpkgs/trusted folder."
untrusted-pin-bump:
description: "Commit that bumps ci/pinned.json; when set, ./nixpkgs/untrusted and ./nixpkgs/untrusted-pinned are derived from this commit."
runs:
using: composite
steps:
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
env:
MERGED_SHA: ${{ inputs.merged-as-untrusted-at }}
TARGET_SHA: ${{ inputs.target-as-trusted-at }}
PIN_BUMP_SHA: ${{ inputs.untrusted-pin-bump }}
with:
retries: 3
script: |
const { rm, writeFile } = require('node:fs/promises')
const { spawn } = require('node:child_process')
const { join } = require('node:path')
@@ -57,27 +52,13 @@ runs:
return pinned.pins.nixpkgs.revision
}
// Getting the pin-bump diff via the API avoids issues with `git fetch`
// thin-packs not having enough base objects to be applied locally.
// Returns a unified diff suitable for `git apply`.
async function getPinBumpDiff(ref) {
const { data } = await github.rest.repos.getCommit({
mediaType: { format: 'diff' },
...context.repo,
ref,
})
return data
}
const pin_bump_sha = process.env.PIN_BUMP_SHA
const commits = [
{
sha: process.env.MERGED_SHA,
path: 'untrusted',
},
{
sha: await getPinnedSha(pin_bump_sha || process.env.MERGED_SHA),
sha: await getPinnedSha(process.env.MERGED_SHA),
path: 'untrusted-pinned'
},
{
@@ -96,42 +77,20 @@ runs:
// 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)))
// On Linux, checking out onto tmpfs takes 1s and is faster by at least 10x.
// Currently, on Darwin we can only allocate 3.5GB, which isn't enough.
// See https://github.com/NixOS/nixpkgs/pull/506437
// Checking out onto tmpfs takes 1s and is faster by at least factor 10x.
await run('mkdir', 'nixpkgs')
if (process.env.RUNNER_OS === 'Linux') {
await run('sudo', 'mount', '-t', 'tmpfs', 'tmpfs', 'nixpkgs')
switch (process.env.RUNNER_OS) {
case 'macOS':
await run('sudo', 'mount_tmpfs', 'nixpkgs')
break
case 'Linux':
await run('sudo', 'mount', '-t', 'tmpfs', 'tmpfs', 'nixpkgs')
break
}
// Git worktree setup can race when multiple worktrees are created and
// initialized at the same time against one repository. See #511286.
// Keep the setup sequential so shared repo config updates cannot contend.
for (const { sha, path } of commits) {
// Create all worktrees in parallel.
await Promise.all(commits.map(async ({ sha, path }) => {
await run('git', 'worktree', 'add', join('nixpkgs', path), sha, '--no-checkout')
await run('git', '-C', join('nixpkgs', path), 'sparse-checkout', 'disable')
await run('git', '-C', join('nixpkgs', path), 'checkout', '--progress')
}
// Apply pin bump to untrusted worktree
if (pin_bump_sha) {
console.log('Fetching ci/pinned.json bump commit:', pin_bump_sha)
await writeFile('pin-bump.patch', await getPinBumpDiff(pin_bump_sha))
console.log('Applying untrusted ci/pinned.json bump to ./nixpkgs/untrusted')
try {
await run('git', '-C', join('nixpkgs', 'untrusted'), 'apply', '--3way', join('..', '..', 'pin-bump.patch'))
} catch {
core.setFailed([
`Failed to apply ci/pinned.json bump commit ${pin_bump_sha}.`,
`This commit does not apply cleanly onto the untrusted base ${process.env.MERGED_SHA}.`,
`Please rebase the PR or ensure the pin bump is standalone.`
].join(' '))
return
} finally {
await rm('pin-bump.patch')
}
}
console.log('final disk usage:')
await run('df', '-h')
}))

View File

@@ -5,5 +5,3 @@ updates:
schedule:
interval: "weekly"
labels: []
commit-message:
prefix: ".github"

View File

@@ -22,15 +22,22 @@
- doc/**/*
- nixos/doc/**/*
"backport release-26.05":
- all:
"backport release-25.05":
- any:
- changed-files:
- any-glob-to-any-file:
- .github/actions/**/*
- .github/actions/*
- .github/workflows/*
- ci/**/*.*
- maintainers/github-teams.json
"backport release-25.11":
- any:
- changed-files:
- any-glob-to-any-file:
- .github/actions/*
- .github/workflows/*
- .github/labeler*.yml
- ci/**/*.*
- maintainers/github-teams.json
- base-branch: ['master']
# keep-sorted end

37
.github/labeler.yml vendored
View File

@@ -9,7 +9,6 @@
- '^release-'
- '^staging-\d'
- '^staging-next-\d'
- '^staging-nixos-\d'
# NOTE: bsd, darwin and cross-compilation labels are handled by ofborg
"6.topic: agda":
@@ -264,21 +263,15 @@
- any-glob-to-any-file:
- nixos/modules/services/cluster/rancher/default.nix
- nixos/modules/services/cluster/rancher/k3s.nix
- nixos/tests/rancher/**/*
- nixos/tests/k3s/**/*
- pkgs/applications/networking/cluster/k3s/**/*
"6.topic: kernel":
- any:
- changed-files:
- any-glob-to-any-file:
- doc/packages/linux.section.md
- lib/kernel.nix
- nixos/doc/manual/configuration/linux-kernel.chapter.md
- nixos/modules/system/boot/kernel.nix
- nixos/tests/kernel-generic/**/*
- pkgs/build-support/kernel/**/*
- pkgs/os-specific/linux/kernel/**/*
- pkgs/top-level/linux-kernels.nix
"6.topic: lib":
- any:
@@ -323,13 +316,6 @@
- nixos/modules/services/x11/desktop-managers/mate.nix
- nixos/tests/mate.nix
- pkgs/desktops/mate/**/*
- pkgs/by-name/ca/caja/**/*
- pkgs/by-name/ca/caja-*/**/*
- pkgs/by-name/li/libmatekbd/**/*
- pkgs/by-name/li/libmatemixer/**/*
- pkgs/by-name/li/libmateweather/**/*
- pkgs/by-name/ma/marco/**/*
- pkgs/by-name/ma/mate-*/**/*
"6.topic: module system":
- any:
@@ -541,18 +527,6 @@
- pkgs/test/texlive/**
- pkgs/tools/typesetting/tex/**/*
"6.topic: tree-sitter":
- any:
- changed-files:
- any-glob-to-any-file:
- doc/packages/python-tree-sitter.section.md
- pkgs/applications/editors/emacs/elisp-packages/manual-packages/tree-sitter-langs/**/*
- pkgs/applications/editors/emacs/elisp-packages/manual-packages/treesit-grammars/**/*
- pkgs/applications/editors/vim/plugins/nvim-treesitter/**/*
- pkgs/by-name/*/*tree-sitter*/**/*
- pkgs/by-name/ne/neovim-unwrapped/treesitter-parsers.nix
- pkgs/development/python-modules/*tree-sitter*/**/*
"6.topic: updaters":
- any:
- changed-files:
@@ -602,15 +576,6 @@
- nixos/modules/services/x11/desktop-managers/xfce.nix
- nixos/tests/xfce.nix
- pkgs/desktops/xfce/**/*
- pkgs/by-name/ga/garcon/**/*
- pkgs/by-name/li/libxfce4*/**/*
- pkgs/by-name/th/thunar/**/*
- pkgs/by-name/th/thunar-*/**/*
- pkgs/by-name/tu/tumbler/**/*
- pkgs/by-name/xf/xfce4-*/**/*
- pkgs/by-name/xf/xfconf/**/*
- pkgs/by-name/xf/xfdesktop/**/*
- pkgs/by-name/xf/xfwm4/**/*
"6.topic: zig":
- any:

View File

@@ -10,18 +10,18 @@ Some architectural notes about key decisions and concepts in our workflows:
Thus they should be lowered to the minimum with `permissions: {}` in every workflow by default.
- By definition `pull_request_target` runs in the context of the **base** of the pull request.
This means that the workflow files to run will be taken from the base branch, not the PR, and actions/checkout will not checkout the PR, but the base branch, by default.
This means, that the workflow files to run will be taken from the base branch, not the PR, and actions/checkout will not checkout the PR, but the base branch, by default.
To protect our secrets, we need to make sure to **never execute code** from the pull request and always evaluate or build nix code from the pull request with the **sandbox enabled**.
- To test the pull request's contents, we checkout the "test merge commit".
This is a temporary commit that GitHub creates automatically as "what would happen if this PR was merged into the base branch now?".
This is a temporary commit that GitHub creates automatically as "what would happen, if this PR was merged into the base branch now?".
The checkout could be done via the virtual branch `refs/pull/<pr-number>/merge`, but doing so would cause failures when this virtual branch doesn't exist (anymore).
This can happen when the PR has conflicts, in which case the virtual branch is not created, or when the PR is getting merged while workflows are still running, in which case the branch won't exist anymore at the time of checkout.
Thus, we use the `prepare` job to check whether the PR is mergeable and the test merge commit exists and only then run the relevant jobs.
- Various workflows need to make comparisons against the base branch.
In this case, we checkout the parent of the "test merge commit" for best results.
Note that this is not necessarily the same as the default commit that actions/checkout would use, which is also a commit from the base branch (see above), but might be older.
Note, that this is not necessarily the same as the default commit that actions/checkout would use, which is also a commit from the base branch (see above), but might be older.
## Terminology

View File

@@ -11,8 +11,8 @@ on:
permissions:
contents: read
issues: write # adding the 'has: port to stable' and 'has: backport failed' label
pull-requests: write # creating backport pull requests
issues: write
pull-requests: write
defaults:
run:
@@ -21,22 +21,22 @@ defaults:
jobs:
backport:
name: Backport Pull Request
if: vars.NIXPKGS_CI_CLIENT_ID && github.event.pull_request.merged == true && (github.event.action != 'labeled' || startsWith(github.event.label.name, 'backport'))
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-slim
timeout-minutes: 3
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@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
client-id: ${{ vars.NIXPKGS_CI_CLIENT_ID }}
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
permission-workflows: write
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.event.pull_request.head.sha }}
token: ${{ steps.app-token.outputs.token }}
@@ -49,10 +49,9 @@ jobs:
- name: Create backport PRs
id: backport
uses: korthout/backport-action@2e830a1d0b8269505846ddd407a70876913ad1f8 # v4.6.0
uses: korthout/backport-action@d07416681cab29bf2661702f925f020aaa962997 # v3.4.1
with:
# Config README: https://github.com/korthout/backport-action#backport-action
add_author_as_reviewer: true
copy_labels_pattern: 'severity:\ssecurity'
github_token: ${{ steps.app-token.outputs.token }}
pull_description: |-
@@ -72,7 +71,7 @@ jobs:
- name: "Add 'has: port to stable' label"
if: steps.backport.outputs.created_pull_numbers != ''
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
# Not using the app on purpose to avoid triggering another workflow run after adding this label.
script: |
@@ -82,16 +81,3 @@ jobs:
issue_number: context.payload.pull_request.number,
labels: [ '8.has: port to stable' ]
})
- name: "Add 'has: failed backport' label"
if: steps.backport.outputs.was_successful == 'false'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
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: failed backport' ]
})

View File

@@ -30,8 +30,8 @@ concurrency:
# This is used as fallback without app only.
# This happens when testing in forks without setting up that app.
permissions:
issues: write # managing issue labels and comments
pull-requests: write # managing pull request labels and comments
issues: write
pull-requests: write
defaults:
run:
@@ -46,21 +46,21 @@ jobs:
# https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: |
ci/github-script
- name: Install dependencies
run: npm install @actions/artifact@6.2.1 bottleneck@2.19.5
run: npm install @actions/artifact bottleneck
# Use a GitHub App, because it has much higher rate limits: 12,500 instead of 5,000 req / hour.
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_CLIENT_ID
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_APP_ID
id: app-token
with:
client-id: ${{ vars.NIXPKGS_CI_CLIENT_ID }}
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
permission-administration: read
permission-contents: write
@@ -74,7 +74,7 @@ jobs:
run: gh api /rate_limit | jq
- name: Run bot
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ steps.app-token.outputs.token || github.token }}
retries: 3
@@ -91,27 +91,27 @@ jobs:
GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }}
run: gh api /rate_limit | jq
- uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # v6.2.0
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
name: Labels from touched files
if: |
github.event_name == 'pull_request_target' &&
!contains(fromJSON(inputs.headBranch).type, 'development')
with:
repo-token: ${{ steps.app-token.outputs.token || github.token }}
repo-token: ${{ steps.app-token.outputs.token }}
configuration-path: .github/labeler.yml # default
sync-labels: true
- uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # v6.2.0
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
name: Labels from touched files (no sync)
if: |
github.event_name == 'pull_request_target' &&
!contains(fromJSON(inputs.headBranch).type, 'development')
with:
repo-token: ${{ steps.app-token.outputs.token || github.token }}
repo-token: ${{ steps.app-token.outputs.token }}
configuration-path: .github/labeler-no-sync.yml
sync-labels: false
- uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # v6.2.0
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
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
@@ -120,7 +120,7 @@ jobs:
github.event_name == 'pull_request_target' &&
contains(fromJSON(inputs.headBranch).type, 'development')
with:
repo-token: ${{ steps.app-token.outputs.token || github.token }}
repo-token: ${{ steps.app-token.outputs.token }}
configuration-path: .github/labeler-development-branches.yml
sync-labels: true

View File

@@ -34,22 +34,25 @@ jobs:
matrix:
include:
- runner: ubuntu-24.04
system: x86_64-linux
name: x86_64-linux
systems: x86_64-linux
builds: [shell, manual-nixos, lib-tests, tarball]
desc: shell, docs, lib, tarball
- runner: ubuntu-24.04-arm
system: aarch64-linux
builds: [shell, manual-nixos, manual-nixpkgs]
name: aarch64-linux
systems: aarch64-linux
builds: [shell, manual-nixos, manual-nixpkgs, manual-nixpkgs-tests]
desc: shell, docs
- runner: macos-14
system: aarch64-darwin
name: darwin
systems: aarch64-darwin x86_64-darwin
builds: [shell]
desc: shell
name: '${{ matrix.system }}: ${{ matrix.desc }}'
name: '${{ matrix.name }}: ${{ matrix.desc }}'
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -59,12 +62,12 @@ jobs:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
target-as-trusted-at: ${{ inputs.targetSha }}
- uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
- uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31
with:
# Sandbox is disabled on MacOS by default.
extra_nix_config: sandbox = true
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
continue-on-error: true
with:
# The nixpkgs-gha cache should not be trusted or used outside of Nixpkgs and its forks' CI.
@@ -77,21 +80,21 @@ jobs:
- name: Build shell
if: contains(matrix.builds, 'shell')
env:
system: ${{ matrix.system }}
run: nix-build-uncached nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A shell --argstr system "$system"
run: echo "${{ matrix.systems }}" | xargs -n1 nix-build-uncached nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A shell --argstr system
- name: Build NixOS manual
if: |
contains(matrix.builds, 'manual-nixos') && !cancelled() &&
(contains(fromJSON(inputs.baseBranch).type, 'primary')
|| startsWith(fromJSON(inputs.baseBranch).branch, 'staging-nixos')
)
contains(fromJSON(inputs.baseBranch).type, 'primary')
run: nix-build-uncached nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A manual-nixos --out-link nixos-manual
- name: Build Nixpkgs manual
if: contains(matrix.builds, 'manual-nixpkgs') && !cancelled()
run: nix-build-uncached nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A manual-nixpkgs
run: nix-build-uncached nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A manual-nixpkgs -A manual-nixpkgs-tests
- name: Build Nixpkgs manual tests
if: contains(matrix.builds, 'manual-nixpkgs-tests') && !cancelled()
run: nix-build-uncached nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A manual-nixpkgs-tests
- name: Build lib tests
if: contains(matrix.builds, 'lib-tests') && !cancelled()
@@ -105,7 +108,7 @@ jobs:
if: |
contains(matrix.builds, 'manual-nixos') && !cancelled() &&
contains(fromJSON(inputs.baseBranch).type, 'primary')
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: ${{ inputs.artifact-prefix }}nixos-manual-${{ matrix.system }}
name: ${{ inputs.artifact-prefix }}nixos-manual-${{ matrix.name }}
path: nixos-manual

View File

@@ -16,14 +16,6 @@ on:
required: true
type: string
secrets:
# Can be provided in pull requests because the job it is used in does
# not evaluate untrusted code.
NIXPKGS_COMMIT_CHECK_APP_PRIVATE_KEY:
required: false
# Can be provided in pull requests because the job it is used in does
# not evaluate untrusted code.
NIXPKGS_MANUAL_EDIT_CHECK_APP_PRIVATE_KEY:
required: false
# Should only be provided in the merge queue, not in pull requests,
# where we're evaluating untrusted code.
CACHIX_AUTH_TOKEN_GHA:
@@ -39,11 +31,11 @@ jobs:
commits:
if: inputs.baseBranch && inputs.headBranch
permissions:
pull-requests: write # submitting PR reviews
pull-requests: write
runs-on: ubuntu-slim
timeout-minutes: 3
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
path: trusted
@@ -51,28 +43,19 @@ jobs:
ci/github-script
- name: Install dependencies
run: npm install bottleneck@2.19.5
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
if: github.event_name != 'pull_request' && vars.NIXPKGS_COMMIT_CHECK_CLIENT_ID
id: app-token
with:
client-id: ${{ vars.NIXPKGS_COMMIT_CHECK_CLIENT_ID }}
private-key: ${{ secrets.NIXPKGS_COMMIT_CHECK_APP_PRIVATE_KEY }}
permission-pull-requests: write
run: npm install bottleneck
- name: Log current API rate limits
env:
GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }}
GH_TOKEN: ${{ github.token }}
run: gh api /rate_limit | jq
- name: Check commits
id: check
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
TARGETS_STABLE: ${{ fromJSON(inputs.baseBranch).stable && !contains(fromJSON(inputs.headBranch).type, 'development') }}
with:
github-token: ${{ steps.app-token.outputs.token || github.token }}
script: |
const targetsStable = JSON.parse(process.env.TARGETS_STABLE)
require('./trusted/ci/github-script/commits.js')({
@@ -85,59 +68,14 @@ jobs:
- name: Log current API rate limits
env:
GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }}
run: gh api /rate_limit | jq
manual-file-edits:
if: inputs.baseBranch && inputs.headBranch
permissions:
pull-requests: write
runs-on: ubuntu-24.04-arm
timeout-minutes: 8
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
path: trusted
sparse-checkout: |
ci/github-script
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
if: github.event_name != 'pull_request' && vars.NIXPKGS_MANUAL_EDIT_CHECK_CLIENT_ID
id: app-token
with:
client-id: ${{ vars.NIXPKGS_MANUAL_EDIT_CHECK_CLIENT_ID }}
private-key: ${{ secrets.NIXPKGS_MANUAL_EDIT_CHECK_APP_PRIVATE_KEY }}
permission-pull-requests: write
- name: Log current API rate limits
env:
GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }}
run: gh api /rate_limit | jq
- name: Discourage manual edits to certain files
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.app-token.outputs.token || github.token }}
script: |
require('./trusted/ci/github-script/manual-file-edits.js')({
github,
context,
core,
dry: context.eventName == 'pull_request',
repoPath: 'trusted',
})
- name: Log current API rate limits
env:
GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }}
GH_TOKEN: ${{ github.token }}
run: gh api /rate_limit | jq
owners:
runs-on: ubuntu-24.04-arm
timeout-minutes: 5
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -147,9 +85,9 @@ jobs:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
target-as-trusted-at: ${{ inputs.targetSha }}
- uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
- uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
continue-on-error: true
with:
# The nixpkgs-gha cache should not be trusted or used outside of Nixpkgs and its forks' CI.

View File

@@ -7,7 +7,7 @@ on:
# This is used as fallback without app only.
# This happens when testing in forks without setting up that app.
permissions:
pull-requests: write # adding reactions to comments
pull-requests: write
defaults:
run:
@@ -23,22 +23,22 @@ jobs:
timeout-minutes: 2
if: contains(github.event.comment.body, '@NixOS/nixpkgs-merge-bot merge')
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: |
ci/github-script
# Use the GitHub App to make sure the reaction happens with the same user who will later merge.
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_CLIENT_ID
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_APP_ID
id: app-token
with:
client-id: ${{ vars.NIXPKGS_CI_CLIENT_ID }}
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
permission-pull-requests: write
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ steps.app-token.outputs.token || github.token }}
retries: 3

View File

@@ -36,14 +36,14 @@ jobs:
# 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@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
client-id: ${{ vars.NIXPKGS_CI_CLIENT_ID }}
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
permission-pull-requests: write
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |

View File

@@ -9,14 +9,7 @@ on:
mergedSha:
required: true
type: string
headSha:
required: false # only required when testVersions is true
type: string
targetSha:
required: true
type: string
baseBranch:
required: true
type: string
systems:
required: true
@@ -26,10 +19,6 @@ on:
default: false
type: boolean
secrets:
# Can be provided in pull requests because the job it is used in does
# not evaluate untrusted code.
NIXPKGS_BRANCH_CHECK_APP_PRIVATE_KEY:
required: false
# Should only be provided in the merge queue, not in pull requests,
# where we're evaluating untrusted code.
CACHIX_AUTH_TOKEN_GHA:
@@ -47,10 +36,8 @@ jobs:
runs-on: ubuntu-slim
outputs:
versions: ${{ steps.versions.outputs.versions }}
ciPinBumpCommit: ${{ steps.find-pinned-commit.outputs.ciPinBumpCommit }}
ciPinBumpCommitShort: ${{ steps.find-pinned-commit.outputs.ciPinBumpCommitShort }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
path: trusted
@@ -58,7 +45,7 @@ jobs:
ci/supportedVersions.nix
- name: Check out the PR at the test merge commit
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
ref: ${{ inputs.mergedSha }}
@@ -66,80 +53,8 @@ jobs:
sparse-checkout: |
ci/pinned.json
- name: Find commit that touched ci/pinned.json
id: find-pinned-commit
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
TARGET_SHA: ${{ inputs.targetSha }}
HEAD_SHA: ${{ inputs.headSha }}
with:
script: |
const targetSha = process.env.TARGET_SHA
const headSha = process.env.HEAD_SHA
if (!targetSha || !headSha) {
core.setFailed('Error: Both targetSha and headSha inputs are required when testVersions is true.')
return
}
// Compare the two commits to get the list of commits in between
const comparison = await github.rest.repos.compareCommitsWithBasehead({
...context.repo,
basehead: `${targetSha}...${headSha}`,
})
if(comparison.data.commits.length > 50) {
core.setFailed('Error: Too many commits in comparison, cannot reliably find pinned.json change.')
return
}
const logRateLimit = async (label) => {
const { data } = await github.rest.rateLimit.get()
const { remaining, limit, used } = data.rate
core.info(`[Rate Limit ${label}] ${remaining}/${limit} remaining (${used} used)`)
}
await logRateLimit('before commit filtering')
// Filter commits that modified ci/pinned.json
const commitsModifyingPinned = (
await Promise.all(
comparison.data.commits.map(async (commit) => {
const commitDetails = await github.rest.repos.getCommit({
...context.repo,
ref: commit.sha,
})
const modifiesPinned = commitDetails.data.files?.some(
(file) => file.filename === "ci/pinned.json"
)
return modifiesPinned ? commit.sha : null
})
)
).filter((sha) => sha !== null)
await logRateLimit('after commit filtering')
if (commitsModifyingPinned.length === 0) {
// This should not happen as testVersions should only be true
// when ci/pinned.json was modified in the PR.
core.setFailed("Error: ci/pinned.json was not modified in this PR")
return
} else if (commitsModifyingPinned.length > 1) {
core.setFailed([
"Error: Multiple commits touch ci/pinned.json in this PR:",
...commitsModifyingPinned,
"Please ensure only a single commit modifies ci/pinned.json for accurate version matrix evaluation."
].join("\n"))
return
}
const ciPinBumpCommit = commitsModifyingPinned[0]
core.setOutput("ciPinBumpCommit", ciPinBumpCommit)
core.setOutput("ciPinBumpCommitShort", ciPinBumpCommit.substring(0, 7))
core.info(`Found pinned.json commit: ${ciPinBumpCommit}`)
- name: Install Nix
uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31
- name: Load supported versions
id: versions
@@ -160,8 +75,8 @@ jobs:
# Failures for versioned Evals will be collected in a separate job below
# to not interrupt main Eval's compare step.
continue-on-error: ${{ matrix.version != '' }}
name: ${{ matrix.system }}${{ matrix.version && format(' @ {0} ({1})', matrix.version, needs.versions.outputs.ciPinBumpCommitShort) || '' }}
timeout-minutes: 20
name: ${{ matrix.system }}${{ matrix.version && format(' @ {0}', matrix.version) || '' }}
timeout-minutes: 15
steps:
# This is not supposed to be used and just acts as a fallback.
# Without swap, when Eval runs OOM, it will fail badly with a
@@ -174,22 +89,20 @@ jobs:
sudo mkswap /swap
sudo swapon /swap
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
- name: Check out the PR at merged and target commits
uses: ./.github/actions/checkout
with:
# For versioned evals, use the target as the untrusted base and apply the pin-bump commit
merged-as-untrusted-at: ${{ matrix.version && inputs.targetSha || inputs.mergedSha }}
untrusted-pin-bump: ${{ matrix.version && needs.versions.outputs.ciPinBumpCommit }}
merged-as-untrusted-at: ${{ inputs.mergedSha }}
target-as-trusted-at: ${{ inputs.targetSha }}
- name: Install Nix
uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
continue-on-error: true
with:
# The nixpkgs-gha cache should not be trusted or used outside of Nixpkgs and its forks' CI.
@@ -245,7 +158,7 @@ jobs:
--out-link diff
- name: Upload outpaths diff and stats
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: ${{ inputs.artifact-prefix }}${{ matrix.version && format('{0}-', matrix.version) || '' }}diff-${{ matrix.system }}
path: diff/*
@@ -255,11 +168,10 @@ jobs:
needs: [eval]
if: ${{ !cancelled() && !failure() }}
permissions:
pull-requests: write # submitting 'wrong branch' reviews
statuses: write # creating 'Eval Summary' commit statuses
statuses: write
timeout-minutes: 5
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -270,14 +182,14 @@ jobs:
target-as-trusted-at: ${{ inputs.targetSha }}
- name: Download output paths and eval stats for all systems
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
pattern: ${{ inputs.artifact-prefix }}diff-*
path: diff
merge-multiple: true
- name: Install Nix
uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31
- name: Combine all output paths and eval stats
run: |
@@ -286,7 +198,7 @@ jobs:
--out-link combined
- name: Upload the maintainer list
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: ${{ inputs.artifact-prefix }}maintainers
path: combined/maintainers.json
@@ -294,7 +206,6 @@ jobs:
- name: Compare against the target branch
env:
TARGET_SHA: ${{ inputs.mergedSha }}
BASE_BRANCH: ${{ fromJSON(inputs.baseBranch).branch }}
run: |
git -C nixpkgs/trusted diff --name-only "$TARGET_SHA" \
| jq --raw-input --slurp 'split("\n")[:-1]' > touched-files.json
@@ -303,30 +214,23 @@ jobs:
nix-build nixpkgs/trusted/ci --arg nixpkgs ./nixpkgs/trusted-pinned -A eval.compare \
--arg combinedDir ./combined \
--arg touchedFilesJson ./touched-files.json \
--argstr baseBranch "$BASE_BRANCH" \
--out-link comparison
cat comparison/step-summary.md >> "$GITHUB_STEP_SUMMARY"
- name: Upload the comparison results
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: ${{ inputs.artifact-prefix }}comparison
path: comparison/*
- name: Add eval summary to commit statuses
if: ${{ github.event_name == 'pull_request_target' }}
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const { readFile } = require('node:fs/promises')
const changed = JSON.parse(await readFile('comparison/changed-paths.json', 'utf-8'))
const removedByKernel = Object.fromEntries(
Object.entries(changed.attrdiffByKernel ?? {}).map(([kernel, diff]) => [
kernel,
diff.removed.length,
]),
)
const description =
'Package: ' + [
`added ${changed.attrdiff.added.length}`,
@@ -336,15 +240,7 @@ jobs:
' — Rebuild: ' + [
`linux ${changed.rebuildCountByKernel.linux}`,
`darwin ${changed.rebuildCountByKernel.darwin}`
].join(', ') +
(
Object.values(removedByKernel).some((count) => count > 0)
? ' — Removed: ' + [
`linux ${removedByKernel.linux ?? 0}`,
`darwin ${removedByKernel.darwin ?? 0}`
].join(', ')
: ''
)
].join(', ')
const { serverUrl, repo, runId, payload } = context
const target_url =
@@ -359,47 +255,23 @@ jobs:
target_url
})
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
if: github.event_name == 'pull_request_target' && vars.NIXPKGS_BRANCH_CHECK_CLIENT_ID
id: app-token
with:
client-id: ${{ vars.NIXPKGS_BRANCH_CHECK_CLIENT_ID }}
private-key: ${{ secrets.NIXPKGS_BRANCH_CHECK_APP_PRIVATE_KEY }}
permission-pull-requests: write
# It's fine to reuse this app in the 'pull-request-target / prepare' job,
# because that job has to run before this one.
- name: Request changes if PR is against an inappropriate branch
if: ${{ github.event_name == 'pull_request_target' }}
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.app-token.outputs.token || github.token }}
script: |
require('./nixpkgs/trusted/ci/github-script/check-target-branch.js')({
github,
context,
core,
dry: context.eventName == 'pull_request',
})
# Creates a matrix of Eval performance for various versions and systems.
report:
runs-on: ubuntu-slim
needs: [versions, eval]
steps:
- name: Download output paths and eval stats for all versions
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
pattern: "*-diff-*"
path: versions
- name: Add version comparison table to job summary
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
ARTIFACT_PREFIX: ${{ inputs.artifact-prefix }}
SYSTEMS: ${{ inputs.systems }}
VERSIONS: ${{ needs.versions.outputs.versions }}
CI_PIN_BUMP_COMMIT: ${{ needs.versions.outputs.ciPinBumpCommit }}
with:
script: |
const { readFileSync } = require('node:fs')
@@ -408,10 +280,8 @@ jobs:
const prefix = process.env.ARTIFACT_PREFIX
const systems = JSON.parse(process.env.SYSTEMS)
const versions = JSON.parse(process.env.VERSIONS)
const ciPinBumpCommit = process.env.CI_PIN_BUMP_COMMIT
core.summary.addHeading('Lix/Nix version comparison')
core.summary.addRaw(`\n*Evaluated at commit: \`${ciPinBumpCommit}\` (commit that modified ci/pinned.json)*\n`, true)
core.summary.addTable(
[].concat(
[
@@ -442,11 +312,7 @@ jobs:
.filter((attr) => attr.split('.').length > 1)
if (attrs.length > 0) {
core.setFailed(
`${version} on ${system} has changed outpaths!\n` +
`Note: This indicates that commit ${ciPinBumpCommit} ` +
`(which modified ci/pinned.json) also contains other ` +
`changes affecting package outputs. ` +
`Please ensure ci/pinned.json is updated in a standalone commit.`
`${version} on ${system} has changed outpaths!\nNote: Please make sure to update ci/pinned.json separately from changes to other packages.`,
)
return { data: ':x:' }
}
@@ -476,7 +342,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -486,15 +352,12 @@ jobs:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
- name: Install Nix
uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31
- name: Ensure flake outputs on all systems still evaluate
run: nix flake check --all-systems --no-build './nixpkgs/untrusted?shallow=1'
- name: Query nixpkgs with aliases enabled to check for basic syntax errors
- name: Run misc eval tasks in parallel
run: |
time nix-env -I ./nixpkgs/untrusted -f ./nixpkgs/untrusted -qa '*' --option restrict-eval true --option allow-import-from-derivation false >/dev/null
- name: Ensure NixOS modules meta is valid
run: |
time nix-instantiate -I ./nixpkgs/untrusted --strict --eval --json ./nixpkgs/untrusted/nixos --arg configuration '{}' --attr config.meta --option restrict-eval true --option allow-import-from-derivation false
# Ensure flake outputs on all systems still evaluate
nix flake check --all-systems --no-build './nixpkgs/untrusted?shallow=1' &
# Query nixpkgs with aliases enabled to check for basic syntax errors
nix-env -I ./nixpkgs/untrusted -f ./nixpkgs/untrusted -qa '*' --option restrict-eval true --option allow-import-from-derivation false >/dev/null &
wait

View File

@@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -35,7 +35,7 @@ jobs:
with:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
- uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
- uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31
# TODO: Figure out how to best enable caching for the treefmt job. Cachix won't work well,
# because the cache would be invalidated on every commit - treefmt checks every file.
@@ -61,7 +61,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -70,9 +70,9 @@ jobs:
with:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
- uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
- uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
continue-on-error: true
with:
# The nixpkgs-gha cache should not be trusted or used outside of Nixpkgs and its forks' CI.
@@ -90,7 +90,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -100,9 +100,9 @@ jobs:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
target-as-trusted-at: ${{ inputs.targetSha }}
- uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
- uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
continue-on-error: true
with:
# The nixpkgs-gha cache should not be trusted or used outside of Nixpkgs and its forks' CI.
@@ -124,29 +124,3 @@ jobs:
echo "If you're having trouble, ping @NixOS/nixpkgs-vet"
exit "$exitCode"
fi
commits:
# Only check commits if we have access to the pull_request context.
#
# Luckily there's no need to lint commit messages in the Merge Queue, because
# changes to the target branch can't change commit messages on the base branch.
if: ${{ github.event.pull_request.number }}
runs-on: ubuntu-24.04-arm
timeout-minutes: 8
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: true # Needed to run git fetch for large PRs.
path: trusted
- name: Check commit messages
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const checkCommitMessages = require('./trusted/ci/github-script/lint-commits.js')
checkCommitMessages({
github,
context,
core,
repoPath: 'trusted',
})

View File

@@ -25,22 +25,20 @@ jobs:
targetSha: ${{ steps.prepare.outputs.targetSha }}
systems: ${{ steps.prepare.outputs.systems }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: |
ci/github-script/supportedSystems.js
ci/supportedSystems.json
- id: prepare
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
MERGED_SHA: ${{ inputs.mergedSha }}
TARGET_SHA: ${{ inputs.targetSha }}
with:
script: |
const { classify } = require('./ci/supportedBranches.js')
const supportedSystems = require('./ci/github-script/supportedSystems.js')
const baseBranch = (
context.payload.merge_group?.base_ref ??
context.payload.pull_request.base.ref
@@ -49,23 +47,19 @@ jobs:
core.setOutput('base', baseClassification)
core.info('base classification:', baseClassification)
const mergedSha = context.payload.merge_group?.head_sha ?? process.env.MERGED_SHA
core.setOutput('mergedSha', mergedSha)
core.info(`mergedSha: ${mergedSha}`)
const targetSha = context.payload.merge_group?.base_sha ?? process.env.TARGET_SHA
core.setOutput('targetSha', targetSha)
core.info(`targetSha: ${targetSha}`)
const systems = await supportedSystems({ github, context, targetSha })
core.setOutput('systems', systems)
core.setOutput('mergedSha', context.payload.merge_group?.head_sha ?? process.env.MERGED_SHA)
core.info(`mergedSha: ${context.payload.merge_group?.head_sha ?? process.env.MERGED_SHA}`)
core.setOutput('targetSha', context.payload.merge_group?.base_sha ?? process.env.TARGET_SHA)
core.info(`targetSha: ${context.payload.merge_group?.base_sha ?? process.env.TARGET_SHA}`)
core.setOutput('systems', require('./ci/supportedSystems.json'))
check:
name: Check
needs: [prepare]
uses: ./.github/workflows/check.yml
permissions:
pull-requests: write # cherry-picks: unused in merge queue but required for check workflow
# cherry-picks; formality right now, but unused
pull-requests: write
secrets:
CACHIX_AUTH_TOKEN_GHA: ${{ secrets.CACHIX_AUTH_TOKEN_GHA }}
with:
@@ -89,15 +83,14 @@ jobs:
# The eval workflow requests these permissions so we must explicitly allow them,
# even though they are unused when working with the merge queue.
permissions:
pull-requests: write # compare: unused in merge queue but required by eval workflow
statuses: write # compare: unused in merge queue but required by eval workflow
# compare
statuses: write
secrets:
CACHIX_AUTH_TOKEN_GHA: ${{ secrets.CACHIX_AUTH_TOKEN_GHA }}
with:
artifact-prefix: ${{ inputs.artifact-prefix }}
mergedSha: ${{ needs.prepare.outputs.mergedSha }}
targetSha: ${{ needs.prepare.outputs.targetSha }}
baseBranch: ${{ needs.prepare.outputs.baseBranch }}
systems: ${{ needs.prepare.outputs.systems }}
build:
@@ -124,9 +117,9 @@ jobs:
- build
runs-on: ubuntu-slim
permissions:
statuses: write # creating 'no PR failures' commit status
statuses: write
steps:
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
RESULTS: ${{ toJSON(needs.*.result) }}
with:

View File

@@ -22,7 +22,7 @@ defaults:
jobs:
periodic-merge:
if: github.repository_owner == 'NixOS' || github.event_name == 'workflow_dispatch'
if: github.repository_owner == 'NixOS'
strategy:
# don't fail fast, so that all pairs are tried
fail-fast: false
@@ -31,12 +31,14 @@ jobs:
max-parallel: 1
matrix:
pairs:
- from: release-26.05
into: staging-next-26.05
- from: staging-next-26.05
into: staging-26.05
- from: release-26.05
into: staging-nixos-26.05
- from: release-25.05
into: staging-next-25.05
- from: staging-next-25.05
into: staging-25.05
- from: release-25.11
into: staging-next-25.11
- from: staging-next-25.11
into: staging-25.11
- name: merge-base(master,staging) → haskell-updates
from: master staging
into: haskell-updates
@@ -47,34 +49,3 @@ jobs:
name: ${{ matrix.pairs.name || format('{0} → {1}', matrix.pairs.from, matrix.pairs.into) }}
secrets:
NIXPKGS_CI_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
# Resets the target branch of the current haskell-updates PR.
# This makes GitHub hide all the commits that are already part of staging and gives us a much clearer PR view.
haskell-updates:
needs: periodic-merge
runs-on: ubuntu-slim
permissions:
pull-requests: write
steps:
- name: Find PR and update target branch
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
// There will at most be a single haskell-updates PR anyway, so no need to paginate.
await Promise.all(
(
await github.rest.pulls.list({
...context.repo,
state: 'open',
head: `${context.repo.owner}:haskell-updates`,
})
).data.map((pr) =>
github.rest.pulls.update({
...context.repo,
pull_number: pr.number,
// Just updating to the same branch to trigger a UI update.
// This is staging most of the time, but could be staging-next in rare cases.
base: pr.base.ref,
}),
),
)

View File

@@ -22,7 +22,7 @@ defaults:
jobs:
periodic-merge:
if: github.repository_owner == 'NixOS' || github.event_name == 'workflow_dispatch'
if: github.repository_owner == 'NixOS'
strategy:
# don't fail fast, so that all pairs are tried
fail-fast: false

View File

@@ -26,15 +26,15 @@ jobs:
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@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
client-id: ${{ vars.NIXPKGS_CI_CLIENT_ID }}
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@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
@@ -60,10 +60,10 @@ jobs:
github_token: ${{ steps.app-token.outputs.token }}
- name: Comment on failure
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
if: ${{ failure() }}
env:
BODY_TEXT: |
Periodic merge from `${{ inputs.from }}` into [`${{ inputs.into }}`](https://github.com/NixOS/nixpkgs/tree/${{ inputs.into }}) has [failed](https://github.com/NixOS/nixpkgs/actions/runs/${{ github.run_id }}).
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
gh pr comment 105153 --body "$BODY_TEXT"
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 }}

View File

@@ -10,12 +10,6 @@ on:
secrets:
NIXPKGS_CI_APP_PRIVATE_KEY:
required: true
NIXPKGS_BRANCH_CHECK_APP_PRIVATE_KEY:
required: true
NIXPKGS_COMMIT_CHECK_APP_PRIVATE_KEY:
required: true
NIXPKGS_MANUAL_EDIT_CHECK_APP_PRIVATE_KEY:
required: true
concurrency:
group: pr-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }}
@@ -27,7 +21,8 @@ jobs:
prepare:
runs-on: ubuntu-slim
permissions:
pull-requests: write # submitting 'wrong branch' reviews
# wrong branch review comment
pull-requests: write
outputs:
baseBranch: ${{ steps.prepare.outputs.base }}
headBranch: ${{ steps.prepare.outputs.head }}
@@ -36,27 +31,15 @@ jobs:
systems: ${{ steps.prepare.outputs.systems }}
touched: ${{ steps.prepare.outputs.touched }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout-cone-mode: true # default, for clarity
sparse-checkout: |
ci/github-script
# It's fine to reuse this app in the 'eval / compare' job,
# because this job has to run before that one.
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
if: vars.NIXPKGS_BRANCH_CHECK_CLIENT_ID && github.actor != 'dependabot[bot]'
id: app-token
with:
client-id: ${{ vars.NIXPKGS_BRANCH_CHECK_CLIENT_ID }}
private-key: ${{ secrets.NIXPKGS_BRANCH_CHECK_APP_PRIVATE_KEY }}
permission-pull-requests: write
- id: prepare
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ steps.app-token.outputs.token || github.token }}
retries: 10
# The default for this includes code 422, which happens regularly for us when comparing commits:
# 422 - Server Error: Sorry, this diff is taking too long to generate.
@@ -78,9 +61,6 @@ jobs:
permissions:
# cherry-picks
pull-requests: write
secrets:
NIXPKGS_COMMIT_CHECK_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_COMMIT_CHECK_APP_PRIVATE_KEY }}
NIXPKGS_MANUAL_EDIT_CHECK_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_MANUAL_EDIT_CHECK_APP_PRIVATE_KEY }}
with:
baseBranch: ${{ needs.prepare.outputs.baseBranch }}
headBranch: ${{ needs.prepare.outputs.headBranch }}
@@ -101,16 +81,11 @@ jobs:
uses: ./.github/workflows/eval.yml
permissions:
# compare
pull-requests: write
statuses: write
secrets:
NIXPKGS_BRANCH_CHECK_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_BRANCH_CHECK_APP_PRIVATE_KEY }}
with:
artifact-prefix: ${{ inputs.artifact-prefix }}
mergedSha: ${{ needs.prepare.outputs.mergedSha }}
headSha: ${{ github.event.pull_request.head.sha }}
targetSha: ${{ needs.prepare.outputs.targetSha }}
baseBranch: ${{ needs.prepare.outputs.baseBranch }}
systems: ${{ needs.prepare.outputs.systems }}
testVersions: ${{ contains(fromJSON(needs.prepare.outputs.touched), 'pinned') && !contains(fromJSON(needs.prepare.outputs.headBranch).type, 'development') }}
@@ -150,7 +125,7 @@ jobs:
permissions:
statuses: write
steps:
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
RESULTS: ${{ toJSON(needs.*.result) }}
with:

View File

@@ -9,7 +9,7 @@ on:
# This is used as fallback without app only.
# This happens when testing in forks without setting up that app.
permissions:
pull-requests: write # minimizing dismissed reviews and adding reactions
pull-requests: write
defaults:
run:
@@ -20,22 +20,22 @@ jobs:
runs-on: ubuntu-slim
timeout-minutes: 2
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: |
ci/github-script
# Use the GitHub App to make sure the reaction happens with the same user who will later merge.
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_CLIENT_ID
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_APP_ID
id: app-token
with:
client-id: ${{ vars.NIXPKGS_CI_CLIENT_ID }}
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
permission-pull-requests: write
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ steps.app-token.outputs.token || github.token }}
retries: 3

View File

@@ -2,7 +2,7 @@ name: Teams
on:
schedule:
# Every Monday at 19:42 (randomly chosen)
# Every Tuesday at 19:42 (randomly chosen)
- cron: '42 19 * * 1'
workflow_dispatch:
@@ -19,10 +19,10 @@ jobs:
steps:
# Use a GitHub App to create the PR so that CI gets triggered and to
# request team member lists.
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
client-id: ${{ vars.NIXPKGS_CI_CLIENT_ID }}
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
private-key: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
permission-administration: read
permission-contents: write
@@ -30,7 +30,7 @@ jobs:
permission-pull-requests: write
- name: Fetch source
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: |
@@ -38,10 +38,10 @@ jobs:
maintainers/github-teams.json
- name: Install dependencies
run: npm install bottleneck@2.19.5
run: npm install bottleneck
- name: Synchronise teams
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
@@ -64,7 +64,7 @@ jobs:
echo "git-string=$name <$email>" >> "$GITHUB_OUTPUT"
- name: Create Pull Request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11
with:
token: ${{ steps.app-token.outputs.token }}
add-paths: maintainers/github-teams.json

View File

@@ -19,14 +19,14 @@ jobs:
push: ${{ steps.files.outputs.push }}
targetSha: ${{ steps.prepare.outputs.targetSha }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout-cone-mode: true # default, for clarity
sparse-checkout: |
ci/github-script
- id: prepare
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
retries: 10
# The default for this includes code 422, which happens regularly for us when comparing commits:
@@ -40,12 +40,12 @@ jobs:
context,
core,
// Review comments will be posted by the main PR workflow on the pull_request_target event.
dry: true,
dry: false,
})
- name: Determine changed files
id: files
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const files = (await github.paginate(github.rest.pulls.listFiles, {
@@ -55,16 +55,10 @@ jobs:
})).map(file => file.filename)
if (files.some(file => [
'.github/workflows/build.yml',
'.github/workflows/check.yml',
'.github/workflows/eval.yml',
'.github/workflows/lint.yml',
'.github/workflows/merge-group.yml',
'.github/workflows/test.yml',
'ci/github-script/supportedSystems.js',
'ci/pinned.json',
'ci/supportedBranches.js',
'pkgs/top-level/release-supported-systems.json',
].includes(file))) core.setOutput('merge-group', true)
if (files.some(file => [
@@ -77,19 +71,8 @@ jobs:
'.github/workflows/pull-request-target.yml',
'.github/workflows/test.yml',
'ci/github-script/bot.js',
'ci/github-script/check-target-branch.js',
'ci/github-script/commits.js',
'ci/github-script/get-pr-commit-details.js',
'ci/github-script/lint-commits.js',
'ci/github-script/merge.js',
'ci/github-script/prepare.js',
'ci/github-script/reviewers.js',
'ci/github-script/reviews.js',
'ci/github-script/supportedSystems.js',
'ci/github-script/withRateLimit.js',
'ci/pinned.json',
'ci/supportedBranches.js',
'pkgs/top-level/release-supported-systems.json',
].includes(file))) core.setOutput('pr', true)
merge-group:
@@ -99,8 +82,8 @@ jobs:
uses: ./.github/workflows/merge-group.yml
# Those are actually only used on the merge_group event, but will throw an error if not set.
permissions:
pull-requests: write # unused on pull_request, required by merge-group workflow
statuses: write # unused on pull_request, required by merge-group workflow
pull-requests: write
statuses: write
with:
artifact-prefix: mg-
mergedSha: ${{ needs.prepare.outputs.mergedSha }}
@@ -113,13 +96,10 @@ jobs:
uses: ./.github/workflows/pull-request-target.yml
# Those are actually only used on the pull_request_target event, but will throw an error if not set.
permissions:
issues: write # unused on pull_request, required by bot workflow
pull-requests: write # unused on pull_request, required by PR workflow
statuses: write # unused on pull_request, required by PR workflow
issues: write
pull-requests: write
statuses: write
secrets:
NIXPKGS_CI_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_CI_APP_PRIVATE_KEY }}
NIXPKGS_BRANCH_CHECK_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_BRANCH_CHECK_APP_PRIVATE_KEY }}
NIXPKGS_COMMIT_CHECK_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_COMMIT_CHECK_APP_PRIVATE_KEY }}
NIXPKGS_MANUAL_EDIT_CHECK_APP_PRIVATE_KEY: ${{ secrets.NIXPKGS_MANUAL_EDIT_CHECK_APP_PRIVATE_KEY }}
with:
artifact-prefix: pr-

2
.github/zizmor.yml vendored
View File

@@ -10,5 +10,3 @@
rules:
dangerous-triggers:
disable: true
secrets-outside-env:
disable: true

View File

@@ -14,21 +14,12 @@ Janne Heß <janne@hess.ooo> <dasJ@users.noreply.github.com>
jopejoe1 <nixpkgs@missing.ninja>
jopejoe1 <nixpkgs@missing.ninja> <johannes@joens.email>
jopejoe1 <nixpkgs@missing.ninja> <34899572+jopejoe1@users.noreply.github.com>
jopejoe1 <nixpkgs@missing.ninja> <jopejoe1@missing.ninja>
jopejoe1 <nixpkgs@missing.ninja> <jopejoe1>
Jörg Thalheim <joerg@thalheim.io> <Mic92@users.noreply.github.com>
Katalin Rebhan <me@dblsaiko.net>
Lin Jian <me@linj.tech> <linj.dev@outlook.com>
Lin Jian <me@linj.tech> <75130626+jian-lin@users.noreply.github.com>
Martin Weinelt <hexa@darmstadt.ccc.de> <mweinelt@users.noreply.github.com>
Martin Häcker <spamfaenger@gmx.de> <spamfaenger@gmx.de>
moni <lythe1107@gmail.com> <lythe1107@icloud.com>
Noah Biewesch <dev@noahbiewesch.com> <90870942+trueNAHO@users.noreply.github.com>
quantenzitrone <nix@dev.quantenzitrone.eu>
quantenzitrone <nix@dev.quantenzitrone.eu> <74491719+Quantenzitrone@users.noreply.github.com>
quantenzitrone <nix@dev.quantenzitrone.eu> <74491719+quantenzitrone@users.noreply.github.com>
quantenzitrone <nix@dev.quantenzitrone.eu> <general@dev.quantenzitrone.eu>
quantenzitrone <nix@dev.quantenzitrone.eu> <quantenzitrone@protonmail.com>
R. RyanTM <ryantm-bot@ryantm.com>
Robert Hensing <robert@roberthensing.nl> <roberth@users.noreply.github.com>
Sandro Jäckel <sandro.jaeckel@gmail.com>

View File

@@ -206,7 +206,7 @@ For example, if you make a change to `texlive`, you probably would only check th
#### Meets Nixpkgs contribution standards
The last two checkboxes are about whether it fits the guidelines in this `CONTRIBUTING.md` file.
The last checkbox is about whether it fits the guidelines in this `CONTRIBUTING.md` file.
This document details our standards for commit messages, reviews, licensing of contributions, etc...
Everyone should read and understand these standards before submitting a pull request.
@@ -329,17 +329,18 @@ You can invoke the nixpkgs-merge-bot by commenting `@NixOS/nixpkgs-merge-bot mer
The bot will verify the following conditions, refusing to merge otherwise:
- the PR author should be @r-ryantm or a Nixpkgs committer;
- the invoker should be among the package maintainers on the targeted branch;
- the invoker should be among the package maintainers;
- the package should reside in `pkgs/by-name`.
Required status checks prevent PRs that fail them ("PR / ..." jobs) from being merged. Ofborg is not required by the checks.
Further, nixpkgs-merge-bot will ensure all CI checks and the ofborg builds for Linux have successfully completed before merging the pull request.
Should the checks still be underway, the bot will wait for them to finish before attempting the merge again.
For other pull requests, please see [I opened a PR, how do I get it merged?](#i-opened-a-pr-how-do-i-get-it-merged).
In case the PR is stuck waiting for the author to apply a trivial change and the author allowed members to modify the PR, consider applying it yourself.
You should pay extra attention to make sure the addition doesn't go against the idea of the original PR and would not be opposed by the author.
Please see the [`nixpkgs-committers` repository](https://github.com/NixOS/nixpkgs-committers) for information on how to proceed to be granted this level of access.
Please see the discussion in [GitHub nixpkgs issue #321665](https://github.com/NixOS/nixpkgs/issues/321665) for information on how to proceed to be granted this level of access.
As a maintainer, when you leave the Nix community, please create an issue or post on [Discourse](https://discourse.nixos.org) with references to the packages and modules you maintained, so they can be taken over by other contributors.
@@ -442,7 +443,6 @@ The staging workflow is used for all stable branches with corresponding names:
- `master`/`release-YY.MM`
- `staging`/`staging-YY.MM`
- `staging-next`/`staging-next-YY.MM`
- `staging-nixos`/`staging-nixos-YY.MM`
[^1]: Except changes that cause no more rebuilds than kernel updates
@@ -506,7 +506,7 @@ These PRs go to `staging-nixos`, see [the next section for more context](#change
Changes causing a rebuild of all NixOS tests get a special [`10.rebuild-nixos-tests`](https://github.com/NixOS/nixpkgs/issues?q=state%3Aopen%20label%3A10.rebuild-nixos-tests) label.
These changes pose a significant impact on the build infrastructure.
Hence, these PRs should either target a `staging`-branch or `staging-nixos`-branch, provided one of following conditions applies:
Hence, these PRs should either target a `staging`-branch or `staging-nixos`, provided one of following conditions applies:
* The label `10.rebuild-nixos-tests` is set, or
* The PR is a change affecting the Linux kernel.
@@ -680,7 +680,7 @@ If you have any problems with formatting, please ping the [formatting team](http
{ buildInputs = if stdenv.hostPlatform.isDarwin then [ iconv ] else null; }
```
As an exception, an explicit conditional expression with null can be used when fixing an important bug without triggering a mass rebuild.
As an exception, an explicit conditional expression with null can be used when fixing a important bug without triggering a mass rebuild.
If this is done a follow up pull request _should_ be created to change the code to `lib.optional(s)`.
- Any style choices not covered here but that can be expressed as general rules should be left at the discretion of the authors of changes and _not_ commented in reviews.
@@ -865,7 +865,7 @@ If someone approved and didn't merge a few days later, they most likely just for
Please see it as your responsibility to actively remind reviewers of your open PRs.
The easiest way to do so is to notify them via GitHub.
GitHub notifies people involved, whenever you add a comment or push to your PR or re-request their review.
Github notifies people involved, whenever you add a comment or push to your PR or re-request their review.
Doing any of that will get their attention again.
Everyone deserves proper attention, and yes, that includes you!
However, please be mindful that committers can sadly not always give everyone the attention they deserve.
@@ -889,77 +889,3 @@ As mentioned previously, it is unfortunately perfectly normal for a PR to sit ar
Please don't blow up situations where progress is happening but is merely not going fast enough for your tastes.
Honking in a traffic jam will not make you go any faster.
# Automation/AI policy
Every contribution to Nixpkgs and related development venues, including code, documentation, and communication on GitHub and Matrix, must have a **responsible person in the loop** who is accountable for that contribution and reviews it before submission, and must **transparently disclose** any nontrivial use of automation to produce it, including but not limited to LLMbased AI tools.
The following sections give more detail.
## Scope
Any use of automated tools to generate nontrivial amounts of output as part of a contribution, in whole or in part, verbatim or edited, is covered by this policy, except as listed in the Exemptions section.
Both LLMbased AI tools and handwritten automation are covered.
Contributions include code and documentation in commits, commit messages, pull request summaries and reviews, issue and vulnerability reports, GitHub comments, Matrix messages, and Discourse posts.
The covered venues are the GitHub repositories for Nixpkgs and [related projects](https://github.com/orgs/NixOS/teams/nixpkgs-core/repositories) under the jurisdiction of the Nixpkgs core team, Matrix rooms that are focused on development of those projects, and Discourse topics about Nixpkgs development.
## Accountability
Everyone who submits a contribution to Nixpkgs is responsible for it, regardless of the use of automated tooling.
Before submission, they must establish a reasonable level of understanding of the contribution and expectation of its correctness.
A contributor submitting a contribution intended for inclusion in Nixpkgs is also responsible for ensuring that it is [appropriately licensed](https://github.com/NixOS/nixpkgs/blob/master/COPYING) and credited, and not encumbered by any incompatible copyright.
When output from automated tooling is used in contributions, a contributor must establish confidence in that output.
This can be achieved by establishing confidence in the correctness of the toolings logic, manual review of the included output, or using further automation to verify the output (e.g. programmatically checking whether a refactor avoids causing rebuilds).
As the inner workings of LLMbased AI tools cannot be sufficiently understood at present, only the latter two options are available when those are used; vibe coding without review is not permitted.
When automation is used to verify output, the verification tooling itself must be disclosed and reviewed in line with this policy.
This policy applies equally to any further discussion of a contribution.
Comments and reviews must separately satisfy the same requirements of understanding, review, and disclosure.
Contributors are expected to be able to answer questions about their contribution and respond to feedback appropriately, without simply forwarding messages back and forth to automated tools.
It is not permitted to submit automated contributions without any manual review or intervention, outside of standard community automation.
Automation without any manual review must not be used as the sole arbiter of whether to merge a change.
## Transparency
All covered use of automated tooling for a contribution must be disclosed as part of that contribution.
In the case of LLMbased AI tooling used for commits, this **must** be in the form of an `Assisted-by:` Git commit trailer, including at least the tool name and the primary model name and version used for the contribution.
A `Co-authored-by:` trailer does not satisfy this policy.
Any adequate form of disclosure is permitted for other kinds of tooling and contribution.
Pull request summaries and review comments must be disclosed separately to commits.
## Exemptions
The following situations are fully or partially exempt:
* Use of standard deterministic editor/IDE/formatter/text transformation tooling to produce changes that the author manually reviews and understands is exempt, including inline “autocompletion” (even if LLMbased) of short, rote snippets of text that do not contribute anything beyond boilerplate the author would have written anyway.
* Use of standard community automation is exempt, such as `nix-update`, the official Nixpkgs CI bots, the @r-ryantm update bot, other maintainerapproved bots that run update scripts, and the Nixpkgs security tracker bot.
* Use of AI tools for research, testing, debugging, or private review is out of scope, if no substantial amount of their output is included in the resulting contribution.
However, if these tools had a significant technical influence on your contribution, you are still responsible for it per the Accountability section, and are expected to disclose this where relevant.
* Use of machine translation is exempt from the requirement to understand the translated output.
However, the requirements of appropriate confidence in the original text, responsibility, and disclosure still apply, and you are encouraged to additionally include the original untranslated contribution.
* Use of automation in a contribution clearly marked as not being ready for merge (e.g. a draft pull request) is exempt from the requirement for full selfreview, as long as some amount of review has been done and it is expected that the requirements will be met by the time it is marked as ready.
This does not waive any other requirement.
* Use of automated tools to develop upstream software packaged inside Nixpkgs is not in scope.
## Enforcement
If you believe that someone is using automation without appropriate disclosure and review, you can politely ask them if thats the case and point them to this policy as appropriate.
Please assume good faith and remain civil; its not always possible to determine, and it is more likely that someone overlooked this policy than deliberately violated it.
If you think someone is continuing to break the policy after this, please escalate to the [Nixpkgs core team](https://nixos.org/community/teams/nixpkgs-core/) rather than fighting over it.
If a contribution is clearly in violation of the policy (e.g. the contributor admits it was not followed, or there are AI tool attributions that do not meet our required format), it can be closed or hidden, preferably after informing the contributor of the policy and giving them a chance to address the violations.
Deliberate violations of this policy are considered to break the [Code of Conduct](https://github.com/NixOS/.github/blob/master/CODE_OF_CONDUCT.md) clause against “Wasting other peoples time with low quality contributions, including but not limited to LLM and bot spam”.
Repeated violations are grounds for further moderation action.
## Credits
This policy takes inspiration from similar policies in [LLVM](https://llvm.org/docs/AIToolPolicy.html), [Mesa](https://gitlab.freedesktop.org/mesa/mesa/-/blob/mesa-26.1.0-rc1/docs/submittingpatches.rst?ref_type=tags), [Fedora](https://docs.fedoraproject.org/en-US/council/policy/ai-contribution-policy/), and the [Linux kernel](https://docs.kernel.org/7.0/process/coding-assistants.html), along with [a proposal by the author of Anubis](https://xeiaso.net/notes/2025/assisted-by-footer/).

View File

@@ -1,4 +1,4 @@
Copyright (c) 2003-2026 Eelco Dolstra and the Nixpkgs/NixOS contributors
Copyright (c) 2003-2025 Eelco Dolstra and the Nixpkgs/NixOS contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -1,9 +1,9 @@
<p align="center">
<a href="https://nixos.org">
<picture>
<source media="(prefers-color-scheme: light)" srcset="https://brand.nixos.org/logos/nixos-logo-rainbow-gradient-black-regular-horizontal-minimal.svg">
<source media="(prefers-color-scheme: dark)" srcset="https://brand.nixos.org/logos/nixos-logo-rainbow-gradient-white-regular-horizontal-minimal.svg">
<img src="https://brand.nixos.org/logos/nixos-logo-rainbow-gradient-black-regular-horizontal-minimal.svg" width="500px" alt="NixOS logo">
<source media="(prefers-color-scheme: light)" srcset="https://brand.nixos.org/logos/nixos-logo-default-gradient-black-regular-horizontal-minimal.svg">
<source media="(prefers-color-scheme: dark)" srcset="https://brand.nixos.org/logos/nixos-logo-default-gradient-white-regular-horizontal-minimal.svg">
<img src="https://brand.nixos.org/logos/nixos-logo-default-gradient-black-regular-horizontal-minimal.svg" width="500px" alt="NixOS logo">
</picture>
</a>
</p>
@@ -13,7 +13,7 @@
<a href="https://opencollective.com/nixos"><img src="https://opencollective.com/nixos/tiers/supporter/badge.svg?label=supporters&color=brightgreen" alt="Open Collective supporters" /></a>
</p>
[Nixpkgs](https://github.com/nixos/nixpkgs) is a collection of over 140,000 software packages that can be installed with the [Nix](https://nixos.org/nix/) package manager.
[Nixpkgs](https://github.com/nixos/nixpkgs) is a collection of over 120,000 software packages that can be installed with the [Nix](https://nixos.org/nix/) package manager.
It also implements [NixOS](https://nixos.org/nixos/), a purely-functional Linux distribution.
# Manuals
@@ -47,9 +47,9 @@ Here are some of the main ones:
Nixpkgs and NixOS are built and tested by our continuous integration system, [Hydra](https://hydra.nixos.org/).
* [Continuous package builds for unstable/master](https://hydra.nixos.org/jobset/nixos/trunk-combined)
* [Continuous package builds for the NixOS 26.05 release](https://hydra.nixos.org/jobset/nixos/release-26.05)
* [Continuous package builds for the NixOS 25.05 release](https://hydra.nixos.org/jobset/nixos/release-25.05)
* [Tests for unstable/master](https://hydra.nixos.org/job/nixos/trunk-combined/tested#tabs-constituents)
* [Tests for the NixOS 26.05 release](https://hydra.nixos.org/job/nixos/release-26.05/tested#tabs-constituents)
* [Tests for the NixOS 25.05 release](https://hydra.nixos.org/job/nixos/release-25.05/tested#tabs-constituents)
Artifacts successfully built with Hydra are published to cache at https://cache.nixos.org/.
When successful build and test criteria are met, the Nixpkgs expressions are distributed via [Nix channels](https://nix.dev/manual/nix/stable/command-ref/nix-channel.html).
@@ -70,7 +70,7 @@ For more information about contributing to the project, please visit the [contri
The infrastructure for NixOS and related projects is maintained by a nonprofit organization, the [NixOS Foundation](https://nixos.org/nixos/foundation.html).
To ensure the continuity and expansion of the NixOS infrastructure, we are looking for donations to our organization.
You can donate to the NixOS Foundation through [SEPA bank transfers](https://nixos.org/donate.html) or by using Open Collective:
You can donate to the NixOS foundation through [SEPA bank transfers](https://nixos.org/donate.html) or by using Open Collective:
<a href="https://opencollective.com/nixos#support"><img src="https://opencollective.com/nixos/tiers/supporter.svg?width=890" /></a>

210
ci/OWNERS
View File

@@ -21,31 +21,30 @@
/ci/OWNERS @infinisil @philiptaron
# Development support
/.editorconfig @Mic92
/.editorconfig @Mic92 @zowoq
/shell.nix @infinisil @NixOS/Security
# Libraries
/lib @infinisil @hsjobeki @llakala
/lib/generators.nix @infinisil @hsjobeki @llakala
/lib/cli.nix @infinisil @hsjobeki @llakala
/lib/debug.nix @infinisil @hsjobeki @llakala
/lib/asserts.nix @infinisil @hsjobeki @llakala
/lib/path/* @infinisil @hsjobeki @llakala
/lib/fileset @infinisil @hsjobeki @llakala
/maintainers/github-teams.json @infinisil @llakala
/maintainers/computed-team-list.nix @infinisil @llakala
/lib @infinisil @hsjobeki
/lib/generators.nix @infinisil @hsjobeki @Profpatsch
/lib/cli.nix @infinisil @hsjobeki @Profpatsch
/lib/debug.nix @infinisil @hsjobeki @Profpatsch
/lib/asserts.nix @infinisil @hsjobeki @Profpatsch
/lib/path/* @infinisil @hsjobeki
/lib/fileset @infinisil @hsjobeki
/maintainers/github-teams.json @infinisil
/maintainers/computed-team-list.nix @infinisil
## Standard environmentrelated libraries
/lib/customisation.nix @alyssais @NixOS/stdenv @llakala
/lib/derivations.nix @NixOS/stdenv @llakala
/lib/fetchers.nix @alyssais @NixOS/stdenv @llakala
/lib/meta.nix @alyssais @NixOS/stdenv @llakala
/lib/meta-types.nix @infinisil @adisbladis @NixOS/stdenv @llakala
/lib/source-types.nix @alyssais @NixOS/stdenv @llakala
/lib/systems @alyssais @NixOS/stdenv @llakala
/lib/customisation.nix @alyssais @NixOS/stdenv
/lib/derivations.nix @alyssais @NixOS/stdenv
/lib/fetchers.nix @alyssais @NixOS/stdenv
/lib/meta.nix @alyssais @NixOS/stdenv
/lib/source-types.nix @alyssais @NixOS/stdenv
/lib/systems @alyssais @NixOS/stdenv
## Libraries / Module system
/lib/modules.nix @infinisil @roberth @hsjobeki @llakala
/lib/types.nix @infinisil @roberth @hsjobeki @llakala
/lib/options.nix @infinisil @roberth @hsjobeki @llakala
/lib/modules.nix @infinisil @roberth @hsjobeki
/lib/types.nix @infinisil @roberth @hsjobeki
/lib/options.nix @infinisil @roberth @hsjobeki
/lib/tests/modules.sh @infinisil @roberth @hsjobeki
/lib/tests/modules @infinisil @roberth @hsjobeki
@@ -57,54 +56,51 @@
/pkgs/top-level/splice.nix @Ericson2314
/pkgs/top-level/release-cross.nix @Ericson2314
/pkgs/top-level/by-name-overlay.nix @infinisil @philiptaron
/pkgs/top-level/config.nix @jopejoe1
/pkgs/top-level/make-tarball.nix @jopejoe1
/pkgs/top-level/packages-config.nix @jopejoe1
/pkgs/top-level/packages-info.nix @jopejoe1
/pkgs/top-level/release-lib.nix @jopejoe1
/pkgs/top-level/release.nix @jopejoe1
/pkgs/stdenv @philiptaron @NixOS/stdenv @llakala
/pkgs/stdenv/generic @Ericson2314 @NixOS/stdenv @llakala
/pkgs/stdenv/generic/problems.nix @infinisil @llakala
/pkgs/test/problems @infinisil
/pkgs/stdenv/generic/check-meta.nix @infinisil @Ericson2314 @adisbladis @NixOS/stdenv @llakala
/pkgs/stdenv @philiptaron @NixOS/stdenv
/pkgs/stdenv/generic @Ericson2314 @NixOS/stdenv
/pkgs/stdenv/generic/check-meta.nix @Ericson2314 @adisbladis @NixOS/stdenv
/pkgs/stdenv/generic/meta-types.nix @adisbladis @NixOS/stdenv
/pkgs/stdenv/cross @Ericson2314 @NixOS/stdenv
/pkgs/build-support @philiptaron
/pkgs/build-support/cc-wrapper @Ericson2314
/pkgs/build-support/bintools-wrapper @Ericson2314
/pkgs/build-support/setup-hooks @Ericson2314
/pkgs/build-support/setup-hooks/arrayUtilities @ConnorBaker
/pkgs/build-support/setup-hooks/auto-patchelf.sh @layus
/pkgs/by-name/au/auto-patchelf @layus
## Format generators/serializers
/pkgs/pkgs-lib @Stunkymonkey @h7x4
/pkgs/pkgs-lib/formats/json2x @Stunkymonkey @h7x4 @figsoda
# Nixpkgs build-support
/pkgs/build-support/writers @lassulus
/pkgs/build-support/writers @lassulus @Profpatsch
# Nixpkgs make-disk-image
/doc/build-helpers/images/makediskimage.section.md @raitobezarius
/nixos/lib/make-disk-image.nix @raitobezarius
# Nix, the package manager
# @raitobezarius is not "code owner", but is listed here to be notified of changes
# pertaining to the Nix package manager.
# i.e. no authority over those files.
# Otherwise keep in-sync with lib.teams.nix.
pkgs/tools/package-management/nix/ @Artturin @Ericson2314 @lovesegfault @Mic92 @philiptaron @roberth @tomberek @xokdvium @raitobezarius
nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lovesegfault @Mic92 @philiptaron @roberth @tomberek @xokdvium @raitobezarius
pkgs/tools/package-management/nix/ @NixOS/nix-team @raitobezarius
nixos/modules/installer/tools/nix-fallback-paths.nix @NixOS/nix-team @raitobezarius
# Nixpkgs documentation
/maintainers/scripts/db-to-md.sh @jtojnar @ryantm
/maintainers/scripts/doc @jtojnar @ryantm
# Contributor documentation
/CONTRIBUTING.md
/.github/PULL_REQUEST_TEMPLATE.md
/doc/contributing/
/doc/contributing/contributing-to-documentation.chapter.md @jtojnar
/lib/README.md
/doc/README.md
/nixos/README.md
/pkgs/README.md
/pkgs/by-name/README.md
/maintainers/README.md
/CONTRIBUTING.md @infinisil
/.github/PULL_REQUEST_TEMPLATE.md @infinisil
/doc/contributing/ @infinisil
/doc/contributing/contributing-to-documentation.chapter.md @jtojnar @infinisil
/lib/README.md @infinisil
/doc/README.md @infinisil
/nixos/README.md @infinisil
/pkgs/README.md @infinisil
/pkgs/by-name/README.md @infinisil
/maintainers/README.md @infinisil
# User-facing development documentation
/doc/development.md @infinisil
@@ -119,9 +115,12 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lo
/nixos/modules/system/activation/bootspec.cue @grahamc @cole-h @raitobezarius
# NixOS Render Docs
/pkgs/by-name/ni/nixos-render-docs @GetPsyched @hsjobeki
/doc/redirects.json @GetPsyched
/nixos/doc/manual/redirects.json @GetPsyched
/pkgs/by-name/ni/nixos-render-docs @fricklerhandwerk @GetPsyched @hsjobeki
/doc/redirects.json @fricklerhandwerk @GetPsyched @hsjobeki
/nixos/doc/manual/redirects.json @fricklerhandwerk @GetPsyched @hsjobeki
# NixOS integration test driver
/nixos/lib/test-driver @tfc
# NixOS QEMU virtualisation
/nixos/modules/virtualisation/qemu-vm.nix @raitobezarius
@@ -182,10 +181,12 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lo
/pkgs/by-name/an/android* @NixOS/android
# Python-related code and docs
/doc/languages-frameworks/python.section.md @mweinelt
/maintainers/scripts/update-python-libraries @mweinelt
/pkgs/by-name/up/update-python-libraries @mweinelt
/pkgs/development/interpreters/python @mweinelt
/doc/languages-frameworks/python.section.md @mweinelt @natsukium
/maintainers/scripts/update-python-libraries @mweinelt @natsukium
/pkgs/by-name/up/update-python-libraries @mweinelt @natsukium
/pkgs/development/interpreters/python @mweinelt @natsukium
/pkgs/top-level/python-packages.nix @natsukium
/pkgs/top-level/release-python.nix @natsukium
# CUDA
/pkgs/top-level/cuda-packages.nix @NixOS/cuda-maintainers
@@ -199,7 +200,6 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lo
/doc/languages-frameworks/haskell.section.md @sternenseemann @maralorn @wolfgangwalther
/maintainers/scripts/haskell @sternenseemann @maralorn @wolfgangwalther
/pkgs/development/compilers/ghc @sternenseemann @maralorn @wolfgangwalther
/pkgs/development/compilers/ghc/9.6.6-debian-binary.nix @sternenseemann @maralorn @wolfgangwalther @OPNA2608
/pkgs/development/haskell-modules @sternenseemann @maralorn @wolfgangwalther
/pkgs/test/haskell @sternenseemann @maralorn @wolfgangwalther
/pkgs/top-level/release-haskell.nix @sternenseemann @maralorn @wolfgangwalther
@@ -215,10 +215,10 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lo
/pkgs/development/r-modules @jbedo
# Rust
/pkgs/development/compilers/rust @NixOS/rust @alyssais
/pkgs/build-support/rust @NixOS/rust
/pkgs/development/compilers/rust @alyssais @Mic92 @zowoq @winterqt
/pkgs/build-support/rust @zowoq @winterqt
/pkgs/build-support/rust/fetch-cargo-vendor* @TomaSajt
/doc/languages-frameworks/rust.section.md @NixOS/rust
/doc/languages-frameworks/rust.section.md @zowoq @winterqt
# Tcl
/pkgs/development/interpreters/tcl @fgaz
@@ -230,10 +230,14 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lo
# C compilers
/pkgs/development/compilers/gcc
/pkgs/development/compilers/llvm @NixOS/llvm
/pkgs/development/compilers/emscripten @raitobezarius
/doc/toolchains/llvm.chapter.md @NixOS/llvm
/doc/languages-frameworks/emscripten.section.md @raitobezarius
# Audio
/nixos/modules/services/audio/botamusique.nix @mweinelt
/nixos/modules/services/audio/snapserver.nix @mweinelt
/nixos/tests/botamusique.nix @mweinelt
/nixos/tests/snapcast.nix @mweinelt
# Browsers
@@ -241,6 +245,7 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lo
/pkgs/applications/networking/browsers/firefox/update.nix
/pkgs/applications/networking/browsers/firefox/packages/firefox.nix @mweinelt
/pkgs/applications/networking/browsers/firefox/packages/firefox-esr-*.nix @mweinelt
/pkgs/applications/networking/browsers/librewolf @squalus @DominicWrege @fpletz @LordGrimmauld
/pkgs/applications/networking/browsers/chromium @emilylange @networkException
/nixos/tests/chromium.nix @emilylange @networkException
@@ -260,18 +265,18 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/pkgs/applications/editors/jetbrains @leona-ya @theCapypara
# Licenses
/lib/licenses @alyssais @emilazy @jopejoe1 @llakala
/lib/licenses.nix @alyssais @emilazy @jopejoe1
# Qt
/pkgs/development/libraries/qt-5 @K900 @NickCao @SuperSandro2000
/pkgs/development/libraries/qt-6 @K900 @NickCao @SuperSandro2000
/pkgs/development/libraries/qt-5 @K900 @NickCao @SuperSandro2000 @ttuegel
/pkgs/development/libraries/qt-6 @K900 @NickCao @SuperSandro2000 @ttuegel
# KDE Frameworks 5
/pkgs/development/libraries/kde-frameworks @K900 @NickCao @SuperSandro2000
/pkgs/development/libraries/kde-frameworks @K900 @NickCao @SuperSandro2000 @ttuegel
# KDE / Plasma 6
/pkgs/kde @K900 @NickCao @SuperSandro2000
/maintainers/scripts/kde @K900 @NickCao @SuperSandro2000
/pkgs/kde @K900 @NickCao @SuperSandro2000 @ttuegel
/maintainers/scripts/kde @K900 @NickCao @SuperSandro2000 @ttuegel
# PostgreSQL and related stuff
/pkgs/by-name/po/postgresqlTestHook @NixOS/postgres
@@ -286,6 +291,13 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/nixos/modules/services/databases/mysql.nix @6543
/nixos/modules/services/backup/mysql-backup.nix @6543
# Hardened profile & related modules
/nixos/modules/profiles/hardened.nix @joachifm
/nixos/modules/security/lock-kernel-modules.nix @joachifm
/nixos/modules/security/misc.nix @joachifm
/nixos/tests/hardened.nix @joachifm
/pkgs/os-specific/linux/kernel/hardened/ @fabianhjr @joachifm
# Home Automation
/nixos/modules/services/home-automation/home-assistant.nix @mweinelt
/nixos/modules/services/home-automation/zigbee2mqtt.nix @mweinelt
@@ -295,14 +307,8 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/pkgs/by-name/es/esphome @mweinelt
# Linux kernel
/doc/packages/linux.section.md @NixOS/linux-kernel
/lib/kernel.nix @NixOS/linux-kernel
/nixos/doc/manual/configuration/linux-kernel.chapter.md @NixOS/linux-kernel
/nixos/modules/system/boot/kernel.nix @NixOS/linux-kernel
/nixos/tests/kernel-generic/ @NixOS/linux-kernel
/pkgs/build-support/kernel/ @NixOS/linux-kernel
/pkgs/os-specific/linux/kernel/ @NixOS/linux-kernel
/pkgs/top-level/linux-kernels.nix @NixOS/linux-kernel
/pkgs/os-specific/linux/kernel/ @NixOS/linux-kernel
# Network Time Daemons
/pkgs/by-name/ch/chrony @thoughtpolice
@@ -322,16 +328,16 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/nixos/tests/knot.nix @mweinelt
# Web servers
/doc/packages/nginx.section.md @leona-ya @Ma27
/pkgs/servers/http/nginx/ @helsinki-Jo @leona-ya @Ma27
/nixos/modules/services/web-servers/nginx/ @leona-ya @Ma27
/doc/packages/nginx.section.md @raitobezarius
/pkgs/servers/http/nginx/ @raitobezarius
/nixos/modules/services/web-servers/nginx/ @raitobezarius
# D
/pkgs/build-support/dlang @jtbx @TomaSajt
# Dhall
/pkgs/development/dhall-modules @Gabriella439
/pkgs/development/interpreters/dhall @Gabriella439
/pkgs/development/dhall-modules @Gabriella439 @Profpatsch
/pkgs/development/interpreters/dhall @Gabriella439 @Profpatsch
# Agda
/pkgs/build-support/agda @NixOS/agda
@@ -344,6 +350,9 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/pkgs/development/idris-modules @Infinisil
/pkgs/development/compilers/idris2 @mattpolzin
# Bazel
/pkgs/by-name/ba/bazel_7 @Profpatsch
# NixOS modules for e-mail and dns services
/nixos/modules/services/mail/mailman.nix @peti
/nixos/modules/services/mail/postfix.nix @peti
@@ -364,14 +373,10 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/pkgs/development/lua-modules @NixOS/lua
# Neovim
/pkgs/applications/editors/neovim @NixOS/neovim
/doc/languages-frameworks/neovim.section.md @NixOS/neovim
/pkgs/applications/editors/neovim @NixOS/neovim
# VimPlugins
/pkgs/applications/editors/vim/plugins @NixOS/neovim
## nvim-treesitter
/pkgs/applications/editors/vim/plugins/nvim-treesitter/overrides.nix @NixOS/neovim @figsoda
/pkgs/applications/editors/vim/plugins/utils/nvim-treesitter @NixOS/neovim @figsoda
# VsCode Extensions
/pkgs/applications/editors/vscode/extensions
@@ -389,15 +394,18 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/nixos/tests/docker-tools* @roberth @jhol
/doc/build-helpers/images/dockertools.section.md @roberth @jhol
# Blockchains
/pkgs/applications/blockchains @mmahut @RaghavSood
# Go
/doc/languages-frameworks/go.section.md @kalbasit @katexochen @Mic92
/pkgs/build-support/go @kalbasit @katexochen @Mic92
/pkgs/development/compilers/go @kalbasit @katexochen @Mic92
/doc/languages-frameworks/go.section.md @kalbasit @katexochen @Mic92 @zowoq
/pkgs/build-support/go @kalbasit @katexochen @Mic92 @zowoq
/pkgs/development/compilers/go @kalbasit @katexochen @Mic92 @zowoq
# GNOME
/pkgs/desktops/gnome @NixOS/gnome
/pkgs/desktops/gnome/extensions @NixOS/gnome
/pkgs/build-support/make-hardcode-gsettings-patch @NixOS/gnome
/pkgs/desktops/gnome @jtojnar
/pkgs/desktops/gnome/extensions @jtojnar
/pkgs/build-support/make-hardcode-gsettings-patch @jtojnar
# Cinnamon
/pkgs/by-name/ci/cinnamon-* @mkg20001
@@ -413,9 +421,8 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/pkgs/applications/networking/cluster/terraform-providers @zowoq
# Forgejo
nixos/modules/services/misc/forgejo.* @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
pkgs/by-name/fo/forgejo/ @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
nixos/tests/forgejo.nix @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
nixos/modules/services/misc/forgejo.nix @adamcstephens @bendlas @emilylange
pkgs/by-name/fo/forgejo/ @adamcstephens @bendlas @emilylange
# Dotnet
/pkgs/build-support/dotnet @corngood
@@ -425,11 +432,9 @@ nixos/tests/forgejo.nix @adamcstephens @bendlas @christoph-heiss @
# Node.js
/pkgs/build-support/node/build-npm-package @winterqt
/pkgs/build-support/node/prefetch-npm-deps @winterqt
/pkgs/build-support/node/fetch-npm-deps @winterqt
/doc/languages-frameworks/javascript.section.md @winterqt
/pkgs/development/tools/pnpm @Scrumplex @gepbird
/pkgs/build-support/node/fetch-pnpm-deps @Scrumplex @gepbird
/pkgs/test/pnpm @Scrumplex @gepbird
# OCaml
/pkgs/build-support/ocaml @ulrikstrid
@@ -471,7 +476,7 @@ pkgs/by-name/lx/lxc* @adamcstephens
/pkgs/desktops/expidus @RossComputerGuy
# GNU Tar & Zip
/pkgs/by-name/gn/gnutar @RossComputerGuy
/pkgs/tools/archivers/gnutar @RossComputerGuy
/pkgs/by-name/zi/zip @RossComputerGuy
# SELinux
@@ -486,7 +491,7 @@ pkgs/by-name/lx/lxc* @adamcstephens
# Darwin
/pkgs/by-name/ap/apple-sdk @NixOS/darwin-core
/pkgs/os-specific/darwin @NixOS/darwin-core
/pkgs/os-specific/darwin/apple-source-releases @NixOS/darwin-core
/pkgs/stdenv/darwin @NixOS/darwin-core
# BEAM
@@ -496,7 +501,7 @@ pkgs/development/interpreters/elixir/ @NixOS/beam
pkgs/development/interpreters/lfe/ @NixOS/beam
# Authelia
pkgs/by-name/au/authelia/ @06kellyjac @nicomem
pkgs/servers/authelia/ @06kellyjac @dit7ya @nicomem
# OctoDNS
pkgs/by-name/oc/octodns/ @anthonyroussel
@@ -506,23 +511,10 @@ pkgs/by-name/oc/octodns/ @anthonyroussel
pkgs/by-name/te/teleport* @arianvp @justinas @sigma @tomberek @techknowlogick @JuliusFreudenberger
# Warp-terminal
pkgs/by-name/wa/warp-terminal/ @emilytrau @imadnyc @4evy @johnrtitor
pkgs/by-name/wa/warp-terminal/ @emilytrau @imadnyc @FlameFlag @johnrtitor
# Nim
/doc/languages-frameworks/nim.section.md @NixOS/nim
/pkgs/build-support/build-nim-package.nix @NixOS/nim
/pkgs/build-support/build-nim-sbom.nix @NixOS/nim
/pkgs/top-level/nim-overrides.nix @NixOS/nim
# Radicle
/pkgs/build-support/fetchradicle/ @NixOS/radicle
/pkgs/build-support/fetchradiclepatch/ @NixOS/radicle
# Zellij plugins
/pkgs/by-name/ze/zellij/plugins/ @PerchunPak
# Test-driver
/nixos/lib/test-driver @NixOS/test-driver
/nixos/lib/testing @NixOS/test-driver
/nixos/tests/nixos-test-driver @NixOS/test-driver
/nixos/modules/virtualisation/nspawn-container/run-nspawn @NixOS/test-driver

View File

@@ -24,7 +24,7 @@ The Nixpkgs merge bot empowers package maintainers by enabling them to merge PRs
It serves as a bridge for maintainers to quickly respond to user feedback, facilitating a more self-reliant approach.
Especially when considering there are roughly 20 maintainers for every committer, this bot is a game-changer.
Following [RFC 172], the merge bot was originally implemented as a [python webapp](https://github.com/NixOS/nixpkgs-merge-bot), which has now been integrated into [`ci/github-script/bot.js`](./github-script/bot.js) and [`ci/github-script/merge.js`](./github-script/merge.js).
Following [RFC 172] the merge bot was originally implemented as a [python webapp](https://github.com/NixOS/nixpkgs-merge-bot), which has now been integrated into [`ci/github-script/bot.js`](./github-script/bot.js) and [`ci/github-script/merge.js`](./github-script/merge.js).
### Using the merge bot
@@ -51,16 +51,6 @@ To ensure security and a focused utility, the bot adheres to specific limitation
- opened by [@r-ryantm](https://nix-community.github.io/nixpkgs-update/r-ryantm/).
- The user attempting to merge is a member of [@NixOS/nixpkgs-maintainers].
- The user attempting to merge is a maintainer of all packages touched by the PR.
- No [committer][@NixOS/nixpkgs-committers] has an outstanding "changes requested" review.
These block both the merge queue and auto-merge, so the bot refuses to merge until the review is addressed or dismissed.
Once these constraints are met, the bot picks a merge strategy based on the `no PR failures` commit status:
- CI passing: the PR is added to the merge queue.
- CI unfinished (pending or missing status): the bot enables [Auto Merge], which queues the PR once required checks succeed.
Note that if CI later fails, nothing happens until it is fixed and passes.
- CI already failing (`error`/`failure` status): the bot does not enable Auto Merge, because it would never trigger, and fixing CI requires a new push that invalidates the merge command.
A fresh `@NixOS/nixpkgs-merge-bot merge` comment is needed once CI is green again.
### Approving merge bot changes
@@ -114,4 +104,3 @@ This script can also be run locally to print basic test cases.
[@NixOS/nixpkgs-ci]: https://github.com/orgs/NixOS/teams/nixpkgs-ci
[@NixOS/nixpkgs-core]: https://github.com/orgs/NixOS/teams/nixpkgs-core
[RFC 172]: https://github.com/NixOS/rfcs/pull/172
[Auto Merge]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/automatically-merging-a-pull-request

View File

@@ -26,7 +26,124 @@ let
fmt =
let
treefmt = pkgs.treefmt.withConfig ./treefmt.nix;
treefmtNixSrc = fetchTarball {
inherit (pinned.treefmt-nix) url;
sha256 = pinned.treefmt-nix.hash;
};
treefmtEval = (import treefmtNixSrc).evalModule pkgs {
# Important: The auto-rebase script uses `git filter-branch --tree-filter`,
# which creates trees within the Git repository under `.git-rewrite/t`,
# notably without having a `.git` themselves.
# So if this projectRootFile were the default `.git/config`,
# having the auto-rebase script use treefmt on such a tree would make it
# format all files in the _parent_ Git tree as well.
projectRootFile = ".git-blame-ignore-revs";
# Be a bit more verbose by default, so we can see progress happening
settings.verbose = 1;
# By default it's info, which is too noisy since we have many unmatched files
settings.on-unmatched = "debug";
programs.actionlint.enable = true;
programs.biome = {
enable = true;
# Disable settings validation because its inputs are liable to hash mismatch
validate.enable = false;
settings.formatter = {
useEditorconfig = true;
};
settings.javascript.formatter = {
quoteStyle = "single";
semicolons = "asNeeded";
};
settings.json.formatter.enabled = false;
};
settings.formatter.biome.excludes = [
"*.min.js"
"pkgs/*"
];
programs.keep-sorted.enable = true;
# This uses nixfmt underneath, the default formatter for Nix code.
# See https://github.com/NixOS/nixfmt
programs.nixfmt = {
enable = true;
package = pkgs.nixfmt;
};
programs.yamlfmt = {
enable = true;
settings.formatter = {
retain_line_breaks = true;
};
};
settings.formatter.yamlfmt.excludes = [
# Aligns comments with whitespace
"pkgs/development/haskell-modules/configuration-hackage2nix/main.yaml"
# TODO: Fix formatting for auto-generated file
"pkgs/development/haskell-modules/configuration-hackage2nix/transitive-broken.yaml"
];
programs.nixf-diagnose.enable = true;
settings.formatter.nixf-diagnose = {
# Ensure nixfmt cleans up after nixf-diagnose.
priority = -1;
options = [
"--auto-fix"
# Rule names can currently be looked up here:
# https://github.com/nix-community/nixd/blob/main/libnixf/src/Basic/diagnostic.py
# TODO: Remove the following and fix things.
"--ignore=sema-unused-def-lambda-noarg-formal"
"--ignore=sema-unused-def-lambda-witharg-arg"
"--ignore=sema-unused-def-lambda-witharg-formal"
"--ignore=sema-unused-def-let"
# Keep this rule, because we have `lib.or`.
"--ignore=or-identifier"
];
excludes = [
# Auto-generated; violates sema-extra-with
# Can only sensibly be removed when --auto-fix supports multiple fixes at once:
# https://github.com/inclyc/nixf-diagnose/issues/13
"pkgs/servers/home-assistant/component-packages.nix"
# https://github.com/nix-community/nixd/issues/708
"nixos/maintainers/scripts/azure-new/examples/basic/system.nix"
];
};
settings.formatter.editorconfig-checker = {
command = "${pkgs.lib.getExe pkgs.editorconfig-checker}";
options = [
"-disable-indent-size"
# TODO: Remove this once this upstream issue is fixed:
# https://github.com/editorconfig-checker/editorconfig-checker/issues/505
"-disable-charset"
];
includes = [ "*" ];
priority = 1;
};
# TODO: Upstream this into treefmt-nix eventually:
# https://github.com/numtide/treefmt-nix/issues/387
settings.formatter.markdown-code-runner = {
command = pkgs.lib.getExe pkgs.markdown-code-runner;
options =
let
config = pkgs.writers.writeTOML "markdown-code-runner-config" {
presets.nixfmt = {
language = "nix";
command = [ (pkgs.lib.getExe pkgs.nixfmt) ];
};
};
in
[ "--config=${config}" ];
includes = [ "*.md" ];
};
programs.zizmor.enable = true;
};
fs = pkgs.lib.fileset;
nixFilesSrc = fs.toSource {
root = ../.;
@@ -34,24 +151,14 @@ let
};
in
{
pkg = treefmt;
check = treefmt.check nixFilesSrc;
shell = treefmtEval.config.build.devShell;
pkg = treefmtEval.config.build.wrapper;
check = treefmtEval.config.build.check nixFilesSrc;
};
# nixos-render-docs and nixos-render-docs-redirects
# Should be used from tree to build the matching in-tree documentation
docPkgs = pkgs.extend (
final: prev: {
nixos-render-docs = final.callPackage ../pkgs/by-name/ni/nixos-render-docs/package.nix { };
nixos-render-docs-redirects =
final.callPackage ../pkgs/by-name/ni/nixos-render-docs-redirects/package.nix
{ };
}
);
in
rec {
inherit pkgs docPkgs fmt;
inherit pkgs fmt;
codeownersValidator = pkgs.callPackage ./codeowners-validator { };
# FIXME(lf-): it might be useful to test other Nix implementations
@@ -64,15 +171,15 @@ rec {
# CI jobs
lib-tests = import ../lib/tests/release.nix { inherit pkgs; };
manual-nixos = (import ../nixos/release.nix { }).manual.${system} or null;
manual-nixpkgs = (import ../doc { pkgs = docPkgs; });
manual-nixpkgs = (import ../doc { inherit pkgs; });
manual-nixpkgs-tests = (import ../doc { inherit pkgs; }).tests;
nixpkgs-vet = pkgs.callPackage ./nixpkgs-vet.nix {
nix = pkgs.nixVersions.latest;
};
parse = pkgs.lib.recurseIntoAttrs {
nix_latest = pkgs.callPackage ./parse.nix { nix = pkgs.nixVersions.latest; };
stable = pkgs.callPackage ./parse.nix { nix = pkgs.nixVersions.stable; };
latest = pkgs.callPackage ./parse.nix { nix = pkgs.nixVersions.latest; };
lix = pkgs.callPackage ./parse.nix { nix = pkgs.lix; };
lix_latest = pkgs.callPackage ./parse.nix { nix = pkgs.lixPackageSets.latest.lix; };
nix_2_28 = pkgs.callPackage ./parse.nix { nix = pkgs.nixVersions.nix_2_28; };
};
shell = import ../shell.nix { inherit nixpkgs system; };
tarball = import ../pkgs/top-level/make-tarball.nix {

View File

@@ -10,16 +10,16 @@ nix-build ci -A eval.baseline
The two most important arguments are:
- `--arg evalSystems`: The set of systems for which `nixpkgs` should be evaluated.
Defaults to the [supported systems](../../pkgs/top-level/release-supported-systems.json) for the branch.
Defaults to the four official platforms (`x86_64-linux`, `aarch64-linux`, `x86_64-darwin` and `aarch64-darwin`).
Example: `--arg evalSystems '["x86_64-linux" "aarch64-darwin"]'`
- `--arg quickTest`: Enables testing a single chunk of the current system only for quick iteration.
Example: `--arg quickTest true`
The following arguments can be used to fine-tune performance:
- `--max-jobs`: The maximum number of derivations to run at the same time.
Only each supported system gets a separate derivation, so it doesn't make sense to set this higher than that number.
Only each [supported system](../supportedSystems.json) gets a separate derivation, so it doesn't make sense to set this higher than that number.
- `--cores`: The number of cores to use for each job.
Recommended to set this to the number of cores on your system divided by `--max-jobs`.
Recommended to set this to the amount of cores on your system divided by `--max-jobs`.
- `--arg chunkSize`: The number of attributes that are evaluated simultaneously on a single core.
Lowering this decreases memory usage at the cost of increased evaluation time.
If this is too high, there won't be enough chunks to process them in parallel, and will also increase evaluation time.

85
ci/eval/attrpaths.nix Normal file
View File

@@ -0,0 +1,85 @@
# This expression will, as efficiently as possible, dump a
# *superset* of all attrpaths of derivations which might be
# part of a release on *any* platform.
#
# This expression runs single-threaded under all current Nix
# implementations, but much faster and with much less memory
# used than ./outpaths.nix itself.
#
# Once you have the list of attrnames you can split it up into
# $NUM_CORES batches and evaluate the outpaths separately for each
# batch, in parallel.
#
# To dump the attrnames:
#
# nix-instantiate --eval --strict --json ci/eval/attrpaths.nix -A names
#
{
lib ? import (path + "/lib"),
trace ? false,
path ? ./../..,
extraNixpkgsConfigJson ? "{}",
}:
let
# TODO: Use mapAttrsToListRecursiveCond when this PR lands:
# https://github.com/NixOS/nixpkgs/pull/395160
justAttrNames =
path: value:
let
result =
if path == [ "AAAAAASomeThingsFailToEvaluate" ] || !(lib.isAttrs value) then
[ ]
else if lib.isDerivation value then
[ path ]
else
lib.pipe value [
(lib.mapAttrsToList (
name: value:
lib.addErrorContext "while evaluating package set attribute path '${
lib.showAttrPath (path ++ [ name ])
}'" (justAttrNames (path ++ [ name ]) value)
))
lib.concatLists
];
in
lib.traceIf trace "** ${lib.showAttrPath path}" result;
outpaths = import ./outpaths.nix {
inherit path;
extraNixpkgsConfig = builtins.fromJSON extraNixpkgsConfigJson;
attrNamesOnly = true;
};
paths = [
# Some of the following are based on variants, which are disabled with `attrNamesOnly = true`.
# Until these have been removed from release.nix / hydra, we manually add them to the list.
[
"pkgsLLVM"
"stdenv"
]
[
"pkgsArocc"
"stdenv"
]
[
"pkgsZig"
"stdenv"
]
[
"pkgsStatic"
"stdenv"
]
[
"pkgsMusl"
"stdenv"
]
]
++ justAttrNames [ ] outpaths;
names = map lib.showAttrPath paths;
in
{
inherit paths names;
}

View File

@@ -2,8 +2,8 @@
{
lib ? import ../../lib,
path ? ../..,
# The file containing the preEval result
preEvalFile,
# The file containing all available attribute paths, which are split into chunks here
attrpathFile,
chunkSize,
myChunk,
includeBroken,
@@ -12,13 +12,12 @@
}:
let
preEvalResult = lib.importJSON preEvalFile;
myAttrpaths = lib.sublist (chunkSize * myChunk) chunkSize preEvalResult.paths;
attrpaths = lib.importJSON attrpathFile;
myAttrpaths = lib.sublist (chunkSize * myChunk) chunkSize attrpaths;
unfiltered = import ./outpaths.nix {
inherit path;
inherit includeBroken systems;
inherit (preEvalResult) attrPathsDisallowedForInternalUse;
extraNixpkgsConfig = builtins.fromJSON extraNixpkgsConfigJson;
};

View File

@@ -49,7 +49,6 @@ in
{
combinedDir,
touchedFilesJson,
baseBranch,
ownersFile ? ../../OWNERS,
}:
let
@@ -75,38 +74,9 @@ let
{
attrdiff: {
added: ["package1"],
changed: ["package2", "package3", "package4"],
changed: ["package2", "package3"],
removed: ["package4"],
},
attrdiffByKernel: {
darwin: {
added: [],
changed: ["package2", "package4"],
removed: ["package4"],
},
linux: {
added: ["package1"],
changed: ["package3", "package4"],
removed: [],
},
},
attrdiffByPlatform: {
aarch64-darwin: {
added: [],
changed: ["package2"],
removed: ["package4"],
},
aarch64-linux: {
added: ["package1"],
changed: ["package3"],
removed: [],
},
x86_64-linux: {
added: [],
changed: ["package4"],
removed: [],
},
},
labels: {
"10.rebuild-darwin: 1-10": true,
"10.rebuild-linux: 1-10": true
@@ -143,8 +113,6 @@ let
inherit (import ./utils.nix { inherit lib; })
groupByKernel
convertToPackagePlatformAttrs
groupAttrdiffByKernel
groupAttrdiffByPlatform
groupByPlatform
extractPackageNames
getLabels
@@ -155,29 +123,21 @@ let
# - values: lists of `packagePlatformPath`s
diffAttrs = builtins.fromJSON (builtins.readFile "${combined}/combined-diff.json");
changedPackagePlatformAttrs = convertToPackagePlatformAttrs diffAttrs.changed;
rebuildsPackagePlatformAttrs = convertToPackagePlatformAttrs diffAttrs.rebuilds;
removedPackagePlatformAttrs = convertToPackagePlatformAttrs diffAttrs.removed;
changed-paths =
let
attrdiff = lib.mapAttrs (_: extractPackageNames) {
inherit (diffAttrs) added changed removed;
};
attrdiffByPlatform = groupAttrdiffByPlatform {
inherit (diffAttrs) added changed removed;
};
attrdiffByKernel = groupAttrdiffByKernel {
inherit (diffAttrs) added changed removed;
};
rebuildsByPlatform = groupByPlatform rebuildsPackagePlatformAttrs;
rebuildsByKernel = groupByKernel rebuildsPackagePlatformAttrs;
rebuildCountByKernel = lib.mapAttrs (
kernel: kernelRebuilds: lib.length kernelRebuilds
) rebuildsByKernel;
rebuildNames = extractPackageNames diffAttrs.rebuilds;
in
writeText "changed-paths.json" (
builtins.toJSON {
inherit attrdiff attrdiffByKernel attrdiffByPlatform;
attrdiff = lib.mapAttrs (_: extractPackageNames) { inherit (diffAttrs) added changed removed; };
inherit
rebuildsByPlatform
rebuildsByKernel
@@ -191,22 +151,22 @@ let
) rebuildsByKernel
// {
"10.rebuild-nixos-tests" =
lib.elem "nixosTests.simple-container" rebuildNames || lib.elem "nixosTests.simple-vm" rebuildNames;
lib.elem "nixosTests.simple" (extractPackageNames diffAttrs.rebuilds)
&&
# Only set this label when no other label with indication for staging has been set.
# This avoids confusion whether to target staging or batch this with kernel updates.
lib.last (lib.sort lib.lessThan (lib.attrValues rebuildCountByKernel)) <= 500;
};
}
);
getMaintainers = callPackage ./maintainers.nix { };
inherit
(getMaintainers {
affectedAttrPaths = map (a: a.packagePath) (
convertToPackagePlatformAttrs (diffAttrs.changed ++ diffAttrs.removed)
);
changedFiles = lib.importJSON touchedFilesJson;
(callPackage ./maintainers.nix { } {
changedattrs = lib.attrNames (lib.groupBy (a: a.name) changedPackagePlatformAttrs);
changedpathsjson = touchedFilesJson;
removedattrs = lib.attrNames (lib.groupBy (a: a.name) removedPackagePlatformAttrs);
})
users
teams
maintainers
packages
;
in
@@ -218,12 +178,10 @@ runCommand "compare"
cmp-stats
codeowners
];
users = builtins.toJSON users;
teams = builtins.toJSON teams;
packages = builtins.toJSON (lib.map (lib.concatStringsSep ".") packages);
maintainers = builtins.toJSON maintainers;
packages = builtins.toJSON packages;
passAsFile = [
"users"
"teams"
"maintainers"
"packages"
];
}
@@ -239,33 +197,34 @@ runCommand "compare"
jq -r -f ${./generate-step-summary.jq} < ${changed-paths}
} >> $out/step-summary.md
{
echo
echo "# Performance comparison"
echo
echo "This compares the performance of this branch against the \`${baseBranch}\` branch."
echo
} >> $out/step-summary.md
# cmp-stats only compares the stats chunks present in both revisions, so the
# comparison is still produced when packages were added/removed. The paired
# chunks may cover different attrs in that case, so caveat the figures.
if ! jq -e '(.attrdiff.added | length == 0) and (.attrdiff.removed | length == 0)' "${changed-paths}" > /dev/null; then
if jq -e '(.attrdiff.added | length == 0) and (.attrdiff.removed | length == 0)' "${changed-paths}" > /dev/null; then
# Chunks have changed between revisions
# We cannot generate a performance comparison
{
echo "> [!NOTE]"
echo "> The package sets differ between the two revisions. This comparison only"
echo "> covers packages evaluated in both, so treat the figures as approximate."
echo
echo "# Performance comparison"
echo
echo "This compares the performance of this branch against its pull request base branch (e.g., 'master')"
echo
echo "For further help please refer to: [ci/README.md](https://github.com/NixOS/nixpkgs/blob/master/ci/README.md)"
echo
} >> $out/step-summary.md
cmp-stats --explain ${combined}/before/stats ${combined}/after/stats >> $out/step-summary.md
else
# Package chunks are the same in both revisions
# We can use the to generate a performance comparison
{
echo
echo "# Performance Comparison"
echo
echo "Performance stats were skipped because the package sets differ between the two revisions."
echo
echo "For further help please refer to: [ci/README.md](https://github.com/NixOS/nixpkgs/blob/master/ci/README.md)"
} >> $out/step-summary.md
fi
{
echo "For further help please refer to: [ci/README.md](https://github.com/NixOS/nixpkgs/blob/master/ci/README.md)"
echo
} >> $out/step-summary.md
cmp-stats --explain ${combined}/before/stats ${combined}/after/stats >> $out/step-summary.md
jq -r '.[]' "${touchedFilesJson}" > ./touched-files
readarray -t touchedFiles < ./touched-files
echo "This PR touches ''${#touchedFiles[@]} files"
@@ -303,7 +262,6 @@ runCommand "compare"
done
cp "$usersPath" "$out/maintainers.json"
cp "$teamsPath" "$out/teams.json"
cp "$maintainersPath" "$out/maintainers.json"
cp "$packagesPath" "$out/packages.json"
''

View File

@@ -1,59 +1,71 @@
# Figure out which maintainers (users/teams) are relevant for a PR:
# - All maintainers that can be linked directly to changedFiles
# - Maintainers of affectedAttrPaths if a file directly related to the attribute is in changedFiles
#
# Files and attributes are linked in various ways:
# - pkgs/by-name/<attr>/* is linked to pkgs.<attr>
# - The file position of various attributes of pkgs.<attr>
# - Explicitly specified file positions in derivations
#
# Test with
# nix-instantiate --eval --strict --json test.nix -A result | jq
#
# Empty list as an output means success
# Dependencies coming from the CI-pinned Nixpkgs
{
lib,
}:
# Function arguments
{
# Files that were changed
# Type: ListOf (Nixpkgs-root-relative path)
changedFiles,
# Attributes whose value was affected by the change
# Type: ListOf (ListOf String)
affectedAttrPaths,
# Nixpkgs used to check maintainers. Customisable for testing
pkgs ? import ../../.. {
changedattrs,
changedpathsjson,
removedattrs,
}:
let
pkgs = import ../../.. {
system = "x86_64-linux";
# We should never try to ping maintainers through package aliases, this can only lead to errors.
# One example case is, where an attribute is a throw alias, but then re-introduced in a PR.
# This would trigger the throw. By disabling aliases, we can fallback gracefully below.
config.allowAliases = false;
overlays = [ ];
},
}:
let
nixpkgsRoot = toString ../../.. + "/";
stripNixpkgsRootFromKeys = lib.mapAttrs' (
file: value: lib.nameValuePair (lib.removePrefix nixpkgsRoot file) value
);
};
moduleMeta = (pkgs.nixos { }).config.meta;
changedpaths = lib.importJSON changedpathsjson;
# Currently just nixos module maintainers, but in the future we can use this for code owners too
fileUsers = stripNixpkgsRootFromKeys moduleMeta.maintainers;
fileTeams = stripNixpkgsRootFromKeys moduleMeta.teams;
# Extract attributes that changed from by-name paths.
# This allows pinging reviewers for pure refactors.
touchedattrs = lib.pipe changedpaths [
(lib.filter (changed: lib.hasPrefix "pkgs/by-name/" changed))
(map (lib.splitString "/"))
(map (path: lib.elemAt path 3))
lib.unique
];
anyMatchingFile = filename: lib.any (lib.hasPrefix filename) changedFiles;
anyMatchingFile = filename: lib.any (lib.hasPrefix filename) changedpaths;
anyMatchingFiles = files: lib.any anyMatchingFile files;
sharded = name: "${lib.substring 0 2 name}/${name}";
attrsWithMaintainers = lib.pipe (changedattrs ++ removedattrs ++ touchedattrs) [
# An attribute can appear in changed/removed *and* touched
lib.unique
(map (
name:
let
path = lib.splitString "." name;
# Some packages might be reported as changed on a different platform, but
# not even have an attribute on the platform the maintainers are requested on.
# Fallback to `null` for these to filter them out below.
package = lib.attrByPath path null pkgs;
in
{
inherit name package;
# Adds all files in by-name to each package, no matter whether they are discoverable
# via meta attributes below. For example, this allows pinging maintainers for
# updates to .json files.
# TODO: Support by-name package sets.
filenames = lib.optional (lib.length path == 1) "pkgs/by-name/${sharded (lib.head path)}/";
# TODO: Refactor this so we can ping entire teams instead of the individual members.
# Note that this will require keeping track of GH team IDs in "maintainers/teams.nix".
maintainers = package.meta.maintainers or [ ];
}
))
# No need to match up packages without maintainers with their files.
# This also filters out attributes where `packge = null`, which is the
# case for libintl, for example.
(lib.filter (pkg: pkg.maintainers != [ ]))
];
relevantFilenames =
drv:
(lib.unique (
map (pos: lib.removePrefix nixpkgsRoot pos.file) (
map (pos: lib.removePrefix "${toString ../../..}/" pos.file) (
lib.filter (x: x != null) [
(drv.meta.maintainersPosition or null)
(drv.meta.teamsPosition or null)
@@ -76,84 +88,26 @@ let
)
));
relevantAffectedAttrPaths = lib.filter (
attrPath:
# Some packages might be reported as changed on a different platform, but
# not even have an attribute on the platform the maintainers are requested on.
# Fallback to `null` for these to filter them out
let
package = lib.attrByPath attrPath null pkgs;
in
package != null && anyMatchingFiles (relevantFilenames package)
) affectedAttrPaths;
attrsWithFilenames = map (
pkg: pkg // { filenames = pkg.filenames ++ relevantFilenames pkg.package; }
) attrsWithMaintainers;
# Extract attributes that changed from by-name paths.
# This allows pinging reviewers for pure refactors.
changedByNameAttrPaths = lib.pipe changedFiles [
(lib.filter (changed: lib.hasPrefix "pkgs/by-name/" changed))
(map (lib.splitString "/"))
# Filters out e.g. pkgs/by-name/README.md
(lib.filter (path: lib.length path > 3))
(map (path: lib.elemAt path 3))
(map lib.singleton)
# Filter out new packages
(lib.filter (attrPath: lib.hasAttrByPath attrPath pkgs))
];
attrsWithModifiedFiles = lib.filter (pkg: anyMatchingFiles pkg.filenames) attrsWithFilenames;
# An attribute can appear in affected *and* touched
attrPathsToGetMaintainersFor = lib.unique (relevantAffectedAttrPaths ++ changedByNameAttrPaths);
attrPathEntities = lib.concatMap (
attrPath:
let
package = lib.getAttrFromPath attrPath pkgs;
in
# meta.maintainers also contains all individual team members.
# We only want to ping individuals if they're added individually as maintainers, not via teams.
userPings { inherit attrPath; } (package.meta.nonTeamMaintainers or [ ])
++ lib.concatMap (teamPings { inherit attrPath; }) (package.meta.teams or [ ])
) attrPathsToGetMaintainersFor;
changedFileEntities = lib.concatMap (
file:
userPings { inherit file; } (fileUsers.${file} or [ ])
++ lib.concatMap (teamPings { inherit file; }) (fileTeams.${file} or [ ])
) changedFiles;
userPings =
context:
listToPing = lib.concatMap (
pkg:
map (maintainer: {
type = "user";
userId = maintainer.githubId;
inherit context;
});
id = maintainer.githubId;
inherit (maintainer) github;
packageName = pkg.name;
dueToFiles = pkg.filenames;
}) pkg.maintainers
) attrsWithModifiedFiles;
teamPings =
context: team:
if team ? githubId then
[
{
type = "team";
teamId = team.githubId;
inherit context;
}
]
else
userPings context team.members;
byType = lib.groupBy (ping: ping.type) (attrPathEntities ++ changedFileEntities);
byUser = lib.pipe (byType.user or [ ]) [
(lib.groupBy (ping: toString ping.userId))
(lib.mapAttrs (_user: lib.map (pkg: pkg.context)))
];
byTeam = lib.pipe (byType.team or [ ]) [
(lib.groupBy (ping: toString ping.teamId))
(lib.mapAttrs (_team: lib.map (pkg: pkg.context)))
];
byMaintainer = lib.groupBy (ping: toString ping.id) listToPing;
in
{
users = byUser;
teams = byTeam;
packages = attrPathsToGetMaintainersFor;
maintainers = lib.mapAttrs (_: lib.catAttrs "packageName") byMaintainer;
packages = lib.catAttrs "packageName" listToPing;
}

View File

@@ -1,311 +0,0 @@
{
pkgs ? import ../../.. {
config = { };
overlays = [ ];
},
lib ? pkgs.lib,
}:
let
fun = import ./maintainers.nix { inherit lib; };
utils = import ./utils.nix { inherit lib; };
mockPkgs =
{
packages ? [ ],
modules ? [ ],
githubTeams ? true,
}:
lib.updateManyAttrsByPath
(lib.imap0 (i: p: {
path = p;
update = _: {
meta.maintainersPosition.file = lib.concatStringsSep "/" p;
meta.nonTeamMaintainers = [ { githubId = i; } ];
meta.teams =
if githubTeams then [ { githubId = i + 100; } ] else [ { members = [ { githubId = i + 100; } ]; } ];
};
}) packages)
{
nixos =
{ }:
{
config.meta.maintainers = lib.listToAttrs (
lib.imap0 (i: m: lib.nameValuePair m [ { githubId = i; } ]) modules
);
config.meta.teams = lib.listToAttrs (
lib.imap0 (
i: m:
lib.nameValuePair m (
if githubTeams then [ { githubId = i + 100; } ] else [ { members = [ { githubId = i + 100; } ]; } ]
)
) modules
);
};
};
tests = {
testEmpty = {
expr = fun {
pkgs = mockPkgs { };
changedFiles = [ ];
affectedAttrPaths = [ ];
};
expected = {
packages = [ ];
teams = { };
users = { };
};
};
testNonExistentAffected = {
expr = fun {
pkgs = mockPkgs { };
changedFiles = [ "a" ];
affectedAttrPaths = [ [ "b" ] ];
};
expected = {
packages = [ ];
teams = { };
users = { };
};
};
testIrrelevantAffected = {
expr = fun {
pkgs = mockPkgs {
packages = [ [ "b" ] ];
};
changedFiles = [ "a" ];
affectedAttrPaths = [ [ "b" ] ];
};
expected = {
packages = [ ];
teams = { };
users = { };
};
};
testRelevantAffected = {
expr = fun {
pkgs = mockPkgs {
packages = [ [ "b" ] ];
};
# Also tests that subpaths work
changedFiles = [ "b/c" ];
affectedAttrPaths = [ [ "b" ] ];
};
expected = {
packages = [ [ "b" ] ];
teams."100" = [
{ attrPath = [ "b" ]; }
];
users."0" = [
{ attrPath = [ "b" ]; }
];
};
};
testRelevantAffectedNonGitHub = {
expr = fun {
pkgs = mockPkgs {
packages = [ [ "b" ] ];
githubTeams = false;
};
changedFiles = [ "b/c" ];
affectedAttrPaths = [ [ "b" ] ];
};
expected = {
packages = [ [ "b" ] ];
teams = { };
users."0" = [
{ attrPath = [ "b" ]; }
];
users."100" = [
{ attrPath = [ "b" ]; }
];
};
};
testByNameChanged = {
expr = fun {
pkgs = mockPkgs {
packages = [ [ "hello" ] ];
};
changedFiles = [ "pkgs/by-name/he/hello/sources.json" ];
affectedAttrPaths = [ ];
};
expected = {
packages = [ [ "hello" ] ];
teams."100" = [
{ attrPath = [ "hello" ]; }
];
users."0" = [
{ attrPath = [ "hello" ]; }
];
};
};
testByNameNonExistentChanged = {
expr = fun {
pkgs = mockPkgs {
packages = [ ];
};
# Happens when a new package was added to pkgs/by-name
changedFiles = [ "pkgs/by-name/he/hello/sources.json" ];
affectedAttrPaths = [ ];
};
expected = {
packages = [ ];
teams = { };
users = { };
};
};
testByNameReadmeChanged = {
expr = fun {
pkgs = mockPkgs {
packages = [ [ "hello" ] ];
};
changedFiles = [ "pkgs/by-name/README.md" ];
affectedAttrPaths = [ ];
};
expected = {
packages = [ ];
teams = { };
users = { };
};
};
testNoDuplicates = {
expr = fun {
pkgs = mockPkgs {
packages = [ [ "hello" ] ];
};
changedFiles = [
"hello"
"pkgs/by-name/he/hello/sources.json"
];
affectedAttrPaths = [ [ "hello" ] ];
};
expected = {
packages = [ [ "hello" ] ];
teams."100" = [
{ attrPath = [ "hello" ]; }
];
users."0" = [
{ attrPath = [ "hello" ]; }
];
};
};
testModuleMaintainers = {
expr = fun {
pkgs = mockPkgs {
modules = [ "a" ];
};
changedFiles = [ "a" ];
affectedAttrPaths = [ ];
};
expected = {
packages = [ ];
teams."100" = [
{ file = "a"; }
];
users."0" = [
{ file = "a"; }
];
};
};
testModuleMaintainersNonGithub = {
expr = fun {
pkgs = mockPkgs {
modules = [ "a" ];
githubTeams = false;
};
changedFiles = [ "a" ];
affectedAttrPaths = [ ];
};
expected = {
packages = [ ];
teams = { };
users."100" = [
{ file = "a"; }
];
users."0" = [
{ file = "a"; }
];
};
};
testGroupAttrdiffByPlatform = {
expr = utils.groupAttrdiffByPlatform {
added = [
"new-tool.aarch64-linux"
"new-tool.x86_64-darwin"
];
changed = [
"updated-tool.x86_64-darwin"
"shared-tool.x86_64-darwin"
];
removed = [
"removed-tool.aarch64-darwin"
"shared-tool.aarch64-darwin"
];
};
expected = {
aarch64-darwin = {
added = [ ];
changed = [ ];
removed = [
"removed-tool"
"shared-tool"
];
};
aarch64-linux = {
added = [ "new-tool" ];
changed = [ ];
removed = [ ];
};
x86_64-darwin = {
added = [ "new-tool" ];
changed = [
"shared-tool"
"updated-tool"
];
removed = [ ];
};
};
};
testGroupAttrdiffByKernel = {
expr =
let
grouped = utils.groupAttrdiffByKernel {
added = [
"new-tool.aarch64-linux"
"new-tool.x86_64-darwin"
];
changed = [
"updated-tool.x86_64-darwin"
"shared-tool.x86_64-darwin"
];
removed = [
"removed-tool.aarch64-darwin"
"shared-tool.aarch64-darwin"
];
};
in
lib.mapAttrs (_: diff: lib.mapAttrs (_: lib.sort lib.lessThan) diff) grouped;
expected = {
darwin = {
added = [ "new-tool" ];
changed = [
"shared-tool"
"updated-tool"
];
removed = [
"removed-tool"
"shared-tool"
];
};
linux = {
added = [ "new-tool" ];
changed = [ ];
removed = [ ];
};
};
};
};
in
{
result = lib.runTests tests;
}

View File

@@ -150,50 +150,6 @@ rec {
in
lib.genAttrs [ "linux" "darwin" ] filterKernel;
/*
Group an attrdiff-style mapping by a derived key such as platform or kernel.
Turns
{
added = [ "new-tool.aarch64-linux" "new-tool.x86_64-darwin" ];
changed = [ "updated-tool.x86_64-darwin" "shared-tool.x86_64-darwin" ];
removed = [ "removed-tool.aarch64-darwin" "shared-tool.aarch64-darwin" ];
}
into
{
aarch64-darwin = {
added = [ ];
changed = [ ];
removed = [ "removed-tool" "shared-tool" ];
};
aarch64-linux = {
added = [ "new-tool" ];
changed = [ ];
removed = [ ];
};
x86_64-darwin = {
added = [ "new-tool" ];
changed = [ "shared-tool" "updated-tool" ];
removed = [ ];
};
}
when used with `groupByPlatform`.
*/
groupAttrdiffBy =
grouper: attrdiff:
let
groupedByKind = lib.mapAttrs (
_: packagePlatformPaths:
grouper (convertToPackagePlatformAttrs (uniqueStrings packagePlatformPaths))
) attrdiff;
groups = uniqueStrings (lib.flatten (map builtins.attrNames (lib.attrValues groupedByKind)));
in
lib.genAttrs groups (group: lib.mapAttrs (_: byGroup: byGroup.${group} or [ ]) groupedByKind);
groupAttrdiffByPlatform = groupAttrdiffBy groupByPlatform;
groupAttrdiffByKernel = groupAttrdiffBy groupByKernel;
/*
Maps an attrs of `kernel - rebuild counts` mappings to an attrs of labels

View File

@@ -17,7 +17,6 @@
busybox,
jq,
nix,
perf,
}:
{
@@ -39,7 +38,8 @@ let
fileset = unions (
map (lib.path.append ../..) [
".version"
"ci/eval/pre-eval.nix"
"ci/supportedSystems.json"
"ci/eval/attrpaths.nix"
"ci/eval/chunk.nix"
"ci/eval/outpaths.nix"
"default.nix"
@@ -53,15 +53,13 @@ let
);
};
supportedSystems = builtins.fromJSON (
builtins.readFile ../../pkgs/top-level/release-supported-systems.json
);
supportedSystems = builtins.fromJSON (builtins.readFile ../supportedSystems.json);
preEval =
attrpathsSuperset =
{
evalSystem,
}:
runCommand "pre-eval"
runCommand "attrpaths-superset.json"
{
src = nixpkgs;
# Don't depend on -dev outputs to reduce closure size for CI.
@@ -74,15 +72,15 @@ let
export NIX_STATE_DIR=$(mktemp -d)
mkdir $out
export GC_INITIAL_HEAP_SIZE=4g
command time -f "Pre-eval done [%MKB max resident, %Es elapsed] %C" \
command time -f "Attribute eval done [%MKB max resident, %Es elapsed] %C" \
nix-instantiate --eval --strict --json --show-trace \
"$src/ci/eval/pre-eval.nix" \
-A result \
"$src/ci/eval/attrpaths.nix" \
-A paths \
-I "$src" \
--argstr extraNixpkgsConfigJson ${lib.escapeShellArg (builtins.toJSON extraNixpkgsConfig)} \
--option restrict-eval true \
--option allow-import-from-derivation false \
--option eval-system "${evalSystem}" > $out/result.json
--option eval-system "${evalSystem}" > $out/paths.json
'';
singleSystem =
@@ -91,10 +89,8 @@ let
# Note that this is intentionally not called `system`,
# because `--argstr system` would only be passed to the ci/default.nix file!
evalSystem ? builtins.currentSystem,
# The path to the `result.json` file from `preEval`
preEvalFile ? "${preEval { inherit evalSystem; }}/result.json",
# Output the number of assembly instructions executed during evaluation
countInstructions ? false,
# The path to the `paths.json` file from `attrpathsSuperset`
attrpathFile ? "${attrpathsSuperset { inherit evalSystem; }}/paths.json",
}:
let
singleChunk = writeShellScript "single-chunk" ''
@@ -103,7 +99,6 @@ let
myChunk=$2
system=$3
outputDir=$4
preEvalFile=$5
# Default is 5, higher values effectively disable the warning.
# This randomly breaks Eval.
@@ -125,12 +120,12 @@ let
--show-trace \
--arg chunkSize "$chunkSize" \
--arg myChunk "$myChunk" \
--arg preEvalFile "$preEvalFile" \
--arg attrpathFile "${attrpathFile}" \
--arg systems "[ \"$system\" ]" \
--arg includeBroken ${lib.boolToString includeBroken} \
--argstr extraNixpkgsConfigJson ${lib.escapeShellArg (builtins.toJSON extraNixpkgsConfig)} \
-I ${nixpkgs} \
-I "$preEvalFile" \
-I ${attrpathFile} \
> "$outputDir/result/$myChunk" \
2> "$outputDir/stderr/$myChunk"
exitCode=$?
@@ -150,16 +145,13 @@ let
runCommand "nixpkgs-eval-${evalSystem}"
{
# Don't depend on -dev outputs to reduce closure size for CI.
nativeBuildInputs = map lib.getBin (
[
busybox
jq
nix
]
++ lib.optionals countInstructions [ perf ]
);
nativeBuildInputs = map lib.getBin [
busybox
jq
nix
];
env = {
inherit evalSystem chunkSize countInstructions;
inherit evalSystem chunkSize;
};
__structuredAttrs = true;
unsafeDiscardReferences.out = true;
@@ -171,6 +163,12 @@ let
echo "System: $evalSystem"
cores=$NIX_BUILD_CORES
echo "Cores: $cores"
attrCount=$(jq length "${attrpathFile}")
echo "Attribute count: $attrCount"
echo "Chunk size: $chunkSize"
# Same as `attrCount / chunkSize` but rounded up
chunkCount=$(( (attrCount - 1) / chunkSize + 1 ))
echo "Chunk count: $chunkCount"
mkdir -p $out/${evalSystem}
@@ -191,78 +189,29 @@ let
done
) &
chunkedEval() {
local chunkOutputDir=$1
local preEvalFile=$2
seq_end=$(( chunkCount - 1 ))
local attrCount=$(jq '.paths | length' "$preEvalFile")
echo "Attribute count: $attrCount"
echo "Chunk size: $chunkSize"
# Same as `attrCount / chunkSize` but rounded up
local chunkCount=$(( (attrCount - 1) / chunkSize + 1 ))
echo "Chunk count: $chunkCount"
${lib.optionalString quickTest ''
seq_end=0
''}
local seq_end=$(( chunkCount - 1 ))
${lib.optionalString quickTest ''
seq_end=0
''}
chunkOutputDir=$(mktemp -d)
mkdir "$chunkOutputDir"/{result,stats,timestats,stderr}
mkdir -p "$chunkOutputDir"/{result,stats,timestats,stderr}
seq -w 0 "$seq_end" |
command time -f "%e" -o "$out/${evalSystem}/total-time" \
xargs -I{} -P"$cores" \
${singleChunk} "$chunkSize" {} "$evalSystem" "$chunkOutputDir"
runAllChunks() {
seq -w 0 "$seq_end" |
xargs -I{} -P"$cores" \
${singleChunk} "$chunkSize" {} "$evalSystem" "$chunkOutputDir" "$preEvalFile"
}
cp -r "$chunkOutputDir"/stats $out/${evalSystem}/stats-by-chunk
if [[ -n "$countInstructions" ]]; then
export seq_end cores chunkSize evalSystem chunkOutputDir preEvalFile
export -f runAllChunks
perf stat \
--event instructions:u --field-separator , --output "$chunkOutputDir"/perf-output-file \
bash -c runAllChunks
cat "$chunkOutputDir"/perf-output-file | tail -n 1 | cut -d, -f1 > "$chunkOutputDir"/instructions
rm "$chunkOutputDir"/perf-output-file
else
runAllChunks
fi
if (( chunkSize * chunkCount != attrCount )); then
# A final incomplete chunk would mess up the stats, don't include it
rm "$chunkOutputDir"/stats/"$seq_end"
fi
}
chunkOutputDirs=$(mktemp -d)
# Preparation for the second eval
disallowedAttributesPreEvalFile=$(mktemp)
jq '{
paths: (.attrPathsDisallowedForInternalUse | map(.attrPath)),
attrPathsDisallowedForInternalUse: []
}' ${preEvalFile} > "$disallowedAttributesPreEvalFile"
startEpoch=$(date +%s)
# The first eval evaluates only attributes that are not disallowed for internal Nixpkgs use, ensuring that they don't depend on disallowed attributes
# Because the first eval doesn't evaluate the disallowed attributes themselves, but we still want to check that they don't fail evaluation, we evaluate them separately in a second eval
# The reason we need two evals is because we want disallowed attributes to be able to depend on other disallowed attributes, which inherently needs a separate Nixpkgs instantiation
# And while we could interleave that instantiation into a single eval, that would ~double memory usage for all chunks, while doing it separately doesn't
echo "Evaluating the internally allowed attributes"
chunkedEval "$chunkOutputDirs"/allowed ${preEvalFile}
echo "Evaluating the internally disallowed attributes"
chunkedEval "$chunkOutputDirs"/disallowed "$disallowedAttributesPreEvalFile"
echo $(( $(date +%s) - startEpoch )) > "$out/${evalSystem}/total-time"
# We only use the stats from the allowed attrs eval, because the disallowed attrs are generally not even a full chunk
cp -r "$chunkOutputDirs"/allowed/stats $out/${evalSystem}/stats-by-chunk
if [[ -f "$chunkOutputDirs"/allowed/instructions ]]; then
cp "$chunkOutputDirs"/allowed/instructions $out/${evalSystem}/instructions
if (( chunkSize * chunkCount != attrCount )); then
# A final incomplete chunk would mess up the stats, don't include it
rm "$chunkOutputDir"/stats/"$seq_end"
fi
cat "$chunkOutputDirs"/*/result/* | jq -s 'add | map_values(.outputs)' > $out/${evalSystem}/paths.json
cat "$chunkOutputDirs"/*/result/* | jq -s 'add | map_values(.meta)' > $out/${evalSystem}/meta.json
cat "$chunkOutputDir"/result/* | jq -s 'add | map_values(.outputs)' > $out/${evalSystem}/paths.json
cat "$chunkOutputDir"/result/* | jq -s 'add | map_values(.meta)' > $out/${evalSystem}/meta.json
'';
diff = callPackage ./diff.nix { };
@@ -299,20 +248,14 @@ let
}) | from_entries
' > $out/maintainers.json
mkdir -p $out/before/stats $out/before/instructions
mkdir -p $out/before/stats
for d in ${diffDir}/before/*; do
cp -r "$d"/stats-by-chunk $out/before/stats/$(basename "$d")
if [[ -f "$d"/instructions ]]; then
cp "$d"/instructions $out/before/instructions/$(basename "$d")
fi
done
mkdir -p $out/after/stats $out/after/instructions
mkdir -p $out/after/stats
for d in ${diffDir}/after/*; do
cp -r "$d"/stats-by-chunk $out/after/stats/$(basename "$d")
if [[ -f "$d"/instructions ]]; then
cp "$d"/instructions $out/after/instructions/$(basename "$d")
fi
done
'';
@@ -322,16 +265,13 @@ let
{
# Whether to evaluate on a specific set of systems, by default all are evaluated
evalSystems ? if quickTest then [ "x86_64-linux" ] else supportedSystems,
# Output the number of assembly instructions executed during evaluation on
# each system
countInstructions ? false,
}:
symlinkJoin {
name = "nixpkgs-eval-baseline";
paths = map (
evalSystem:
singleSystem {
inherit evalSystem countInstructions;
inherit evalSystem;
}
) evalSystems;
};
@@ -347,12 +287,6 @@ let
# | jq --raw-input --slurp 'split("\n")[:-1]' > touched-files.json
# ```
touchedFilesJson ? builtins.toFile "touched-files.json" "[ ]",
# The branch the local comparison is made against; matches the `master`
# used in the touched-files expression above.
baseBranch ? "master",
# Output the number of assembly instructions executed during evaluation on
# each system
countInstructions ? false,
}:
let
diffs = symlinkJoin {
@@ -363,14 +297,14 @@ let
inherit evalSystem;
beforeDir = baseline;
afterDir = singleSystem {
inherit evalSystem countInstructions;
inherit evalSystem;
};
}
) evalSystems;
};
comparisonReport = compare {
combinedDir = combine { diffDir = diffs; };
inherit touchedFilesJson baseBranch;
inherit touchedFilesJson;
};
in
comparisonReport;
@@ -378,7 +312,7 @@ let
in
{
inherit
preEval
attrpathsSuperset
singleSystem
diff
combine

35
ci/eval/outpaths.nix Executable file → Normal file
View File

@@ -6,15 +6,11 @@
includeBroken ? true, # set this to false to exclude meta.broken packages from the output
path ? ./../..,
# used by ./pre-eval.nix
# used by ./attrpaths.nix
attrNamesOnly ? false,
# Set this to `null` to build for builtins.currentSystem only
systems ? builtins.fromJSON (
builtins.readFile (path + "/pkgs/top-level/release-supported-systems.json")
),
attrPathsDisallowedForInternalUse ? [ ],
systems ? builtins.fromJSON (builtins.readFile ../supportedSystems.json),
# Customize the config used to evaluate nixpkgs
extraNixpkgsConfig ? { },
@@ -37,25 +33,6 @@ let
allowVariants = !attrNamesOnly;
checkMeta = true;
# We don't need to care about problems being caught using the
# standard mechanism, because any problems whose kind is not
# nixpkgsInternalUseAllowed cause the corresponding attributes to
# be disallowed entirely for internal use with
# attrPathsDisallowedForInternalUse, see also ./pre-eval.nix
problems.matchers = lib.mkForce [
# We only need to set the broken handler to error, so that CI
# doesn't evaluate those. No reason it couldn't evaluate them
# afaik, but this is how it's been before.
{
kind = "broken";
handler = "error";
}
];
inherit attrPathsDisallowedForInternalUse;
# Silence the `x86_64-darwin` deprecation warning.
allowDeprecatedx86_64Darwin = true;
handleEvalIssue =
reason: errormsg:
let
@@ -90,9 +67,7 @@ let
nixosJobs = import (path + "/nixos/release.nix") {
inherit attrNamesOnly;
supportedSystems = lib.filter (lib.hasSuffix "-linux") (
if systems == null then [ builtins.currentSystem ] else systems
);
supportedSystems = if systems == null then [ builtins.currentSystem ] else systems;
};
recurseIntoAttrs = attrs: attrs // { recurseForDerivations = true; };
@@ -126,8 +101,6 @@ in
tweak (
(removeAttrs nixpkgsJobs blacklist)
// {
nixosTests = lib.filterAttrs (
name: _: name == "simple-container" || name == "simple-vm"
) nixosJobs.tests;
nixosTests.simple = nixosJobs.tests.simple;
}
)

View File

@@ -1,128 +0,0 @@
# This file does a fast pre-evaluation of Nixpkgs to determine:
# - paths: A *superset* of all attrpaths of derivations which might be part of a release on *any* platform.
# - attrPathsDisallowedForInternalUse: Attribute paths whose meta.problems has problems whose kinds should not be used internally in Nixpkgs
#
# This expression runs single-threaded under all current Nix
# implementations, but much faster and with much less memory
# used than ./outpaths.nix itself.
#
# Once you have the list of attrnames you can split it up into
# $NUM_CORES batches and evaluate the outpaths separately for each
# batch, in parallel.
#
# To dump the result:
#
# nix-instantiate --eval --strict --json ci/eval/pre-eval.nix -A result
#
{
lib ? import (path + "/lib"),
trace ? false,
path ? ./../..,
extraNixpkgsConfigJson ? "{}",
}:
let
# TODO: Use mapAttrsToListRecursiveCond when this PR lands:
# https://github.com/NixOS/nixpkgs/pull/395160
listAttrs =
path: value:
let
result =
if path == [ "AAAAAASomeThingsFailToEvaluate" ] || !(lib.isAttrs value) then
[ ]
else if lib.isDerivation value then
[
{
inherit path value;
}
]
else
lib.pipe value [
(lib.mapAttrsToList (
name: value:
lib.addErrorContext "while evaluating package set attribute path '${
lib.showAttrPath (path ++ [ name ])
}'" (listAttrs (path ++ [ name ]) value)
))
lib.concatLists
];
in
lib.traceIf trace "** ${lib.showAttrPath path}" result;
outpaths = import ./outpaths.nix {
inherit path;
extraNixpkgsConfig = builtins.fromJSON extraNixpkgsConfigJson;
attrNamesOnly = true;
};
list =
map
(path: {
inherit path;
# This looks a bit weird, but the only reason we care about this value
# is for the meta.problems check below, and stdenv's certainly don't
# have any problems, so this is fine :)
value = { };
})
[
# Some of the following are based on variants, which are disabled with `attrNamesOnly = true`.
# Until these have been removed from release.nix / hydra, we manually add them to the list.
[
"pkgsLLVM"
"stdenv"
]
[
"pkgsArocc"
"stdenv"
]
[
"pkgsZig"
"stdenv"
]
[
"pkgsStatic"
"stdenv"
]
[
"pkgsMusl"
"stdenv"
]
]
++ listAttrs [ ] outpaths;
paths = map (attrs: attrs.path) list;
names = map lib.showAttrPath paths;
inherit (import ../../pkgs/stdenv/generic/problems.nix { inherit lib; })
disallowNixpkgsInternalUseKinds
;
# Determine the list of attributes whose packages have any meta.problems
# with a kind that's disallowed from internal Nixpkgs use
attrPathsDisallowedForInternalUse = lib.pipe list [
(lib.map (
attrs:
attrs
// {
problematicProblems = builtins.tryEval (
lib.filterAttrs (name: problem: disallowNixpkgsInternalUseKinds ? ${problem.kind}) (
attrs.value.meta.problems or { }
)
);
}
))
(lib.filter (attrs: attrs.problematicProblems.success && attrs.problematicProblems.value != { }))
(lib.map (attrs: {
attrPath = attrs.path;
reason = "it has certain meta.problems whose kinds are disallowed: ${
lib.generators.toPretty { } attrs.problematicProblems.value
}";
}))
];
in
{
# TODO: Do we still need these? Probably not
inherit paths names;
result = {
inherit paths attrPathsDisallowedForInternalUse;
};
}

View File

@@ -1,6 +1,6 @@
module.exports = async ({ github, context, core, dry }) => {
const path = require('node:path')
const { DefaultArtifactClient } = await import('@actions/artifact')
const { DefaultArtifactClient } = require('@actions/artifact')
const { readFile, writeFile } = require('node:fs/promises')
const withRateLimit = require('./withRateLimit.js')
const { classify } = require('../supportedBranches.js')
@@ -9,15 +9,6 @@ module.exports = async ({ github, context, core, dry }) => {
const artifactClient = new DefaultArtifactClient()
// Detect if running in a fork (not NixOS/nixpkgs)
const isFork = context.repo.owner !== 'NixOS'
const orgId = (
await github.rest.orgs.get({
org: context.repo.owner,
})
).data.id
async function downloadMaintainerMap(branch) {
let run
@@ -77,18 +68,9 @@ module.exports = async ({ github, context, core, dry }) => {
// We get here when none of the 10 commits we looked at contained a maintainer map.
// For the master branch, we don't have any fallback options, so we error out.
// In forks without merge-group history, return empty map to allow testing.
if (branch === 'master') {
if (isFork) {
core.warning(
'No maintainer map found. Using empty map (expected in forks without merge-group history).',
)
return {}
}
throw new Error('No maintainer map found.')
}
// For other branches, we select a suitable fallback below.
if (branch === 'master') throw new Error('No maintainer map found.')
const { stable, version } = classify(branch)
const release = `release-${version}`
@@ -127,11 +109,6 @@ module.exports = async ({ github, context, core, dry }) => {
return []
}
// Forks don't have NixOS teams, return empty list
if (isFork) {
return []
}
if (!members[team_slug]) {
members[team_slug] = github.paginate(github.rest.teams.listMembersInOrg, {
org: context.repo.owner,
@@ -156,38 +133,11 @@ module.exports = async ({ github, context, core, dry }) => {
id,
})
.then((resp) => resp.data)
.catch((e) => {
// User may have deleted their account
if (e.status === 404) return null
throw e
})
}
return users[id]
}
// Same for teams
const teams = {}
function getTeam(id) {
if (!teams[id]) {
teams[id] = github
.request({
method: 'GET',
url: '/organizations/{orgId}/team/{id}',
orgId,
id,
})
.then((resp) => resp.data)
.catch((e) => {
// Team may have been deleted
if (e.status === 404) return null
throw e
})
}
return teams[id]
}
async function handlePullRequest({ item, stats, events }) {
const log = (k, v) => core.info(`PR #${item.number} - ${k}: ${v}`)
@@ -206,55 +156,6 @@ module.exports = async ({ github, context, core, dry }) => {
const maintainers = await getMaintainerMap(pull_request.base.ref)
// Check for any human reviews other than the PR author, GitHub actions and other GitHub apps.
// `commit { oid }` is needed by handleMerge to verify approvals are against the current head.
const reviews = (
await github.graphql(
`query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
# Unlikely that there's ever more than 100 reviews, so let's not bother,
# but once https://github.com/actions/github-script/issues/309 is resolved,
# it would be easy to enable pagination.
reviews(first: 100) {
nodes {
state
commit { oid }
user: author {
# Only get users, no bots
... on User {
login
# Set the id field in the resulting JSON to GraphQL's databaseId
# databaseId in GraphQL-land is the same as id in REST-land
id: databaseId
}
}
onBehalfOf(first: 100) {
nodes {
slug
}
}
}
}
}
}
}`,
{
owner: context.repo.owner,
repo: context.repo.repo,
pr: pull_number,
},
)
).repository.pullRequest.reviews.nodes.filter(
(r) =>
// The `... on User` makes it such that .login only exists for users,
// but we still need to filter the others out.
// Accounts could be deleted as well, so don't count them.
r.user?.login &&
// Also exclude author reviews, can't request their review in any case
r.user.id !== pull_request.user?.id,
)
const merge_bot_eligible = await handleMerge({
github,
context,
@@ -263,12 +164,26 @@ module.exports = async ({ github, context, core, dry }) => {
dry,
pull_request,
events,
reviews,
maintainers,
getTeamMembers,
getUser,
})
// Check for any human reviews other than the PR author, GitHub actions and other GitHub apps.
// Accounts could be deleted as well, so don't count them.
const reviews = (
await github.paginate(github.rest.pulls.listReviews, {
...context.repo,
pull_number,
})
).filter(
(r) =>
r.user &&
!r.user.login.endsWith('[bot]') &&
r.user.type !== 'Bot' &&
r.user.id !== pull_request.user?.id,
)
const approvals = new Set(
reviews
.filter((review) => review.state === 'APPROVED')
@@ -384,40 +299,9 @@ module.exports = async ({ github, context, core, dry }) => {
expectedHash: artifact.digest,
})
const changedPaths = JSON.parse(
const evalLabels = JSON.parse(
await readFile(`${pull_number}/changed-paths.json`, 'utf-8'),
)
const evalLabels = changedPaths.labels
// Fetch all PR commits to check their messages for package patterns
const prCommits = await github.paginate(github.rest.pulls.listCommits, {
...context.repo,
pull_number,
per_page: 100,
})
const commitSubjects = prCommits.map(
(c) => c.commit.message.split('\n')[0],
)
// Label new package PRs: "packagename: init at X.Y.Z"
// Exclude NixOS module commits like "nixos/timekpr: init at 0.5.8"
const newPackagePattern = /^(?<!nixos\/)\S+: init at\b/
const hasNewPackages = changedPaths.attrdiff?.added?.length > 0
const commitsIndicateNewPackage = commitSubjects.some((msg) =>
newPackagePattern.test(msg),
)
evalLabels['8.has: package (new)'] =
hasNewPackages && commitsIndicateNewPackage
// Label package update PRs: "packagename: X.Y.Z -> A.B.C"
// Matches versions like: 1.2.3, 0-unstable-2024-01-15, 1.3rc1, alpha, unstable
// Exclude NixOS module commits like "nixos/ncps: types.str -> types.path"
const updatePackagePattern =
/^(?<!nixos\/)\S+: [\w.-]*\d[\w.-]* (->|→) [\w.-]*\d[\w.-]*$/
const commitsIndicateUpdate = commitSubjects.some((msg) =>
updatePackagePattern.test(msg),
)
evalLabels['8.has: package (update)'] = commitsIndicateUpdate
).labels
// TODO: Get "changed packages" information from list of changed by-name files
// in addition to just the Eval results, to make this work for these packages
@@ -465,16 +349,6 @@ module.exports = async ({ github, context, core, dry }) => {
if (e.code !== 'ENOENT') throw e
}
let team_maintainers = []
try {
team_maintainers = Object.keys(
JSON.parse(await readFile(`${pull_number}/teams.json`, 'utf-8')),
).map((id) => parseInt(id))
} catch (e) {
// Older artifacts don't have the teams.json, yet.
if (e.code !== 'ENOENT') throw e
}
// We set this label earlier already, but the current PR state can be very different
// after handleReviewers has requested reviews, so update it in this case to prevent
// this label from flip-flopping.
@@ -487,15 +361,14 @@ module.exports = async ({ github, context, core, dry }) => {
pull_request,
reviews,
// TODO: Use maintainer map instead of the artifact.
user_maintainers: Object.keys(
maintainers: Object.keys(
JSON.parse(
await readFile(`${pull_number}/maintainers.json`, 'utf-8'),
),
).map((id) => parseInt(id)),
team_maintainers,
owners,
getTeamMembers,
getUser,
getTeam,
})
}
}

View File

@@ -1,221 +0,0 @@
/// @ts-check
// TODO: should this be combined with the branch checks in prepare.js?
// They do seem quite similar, but this needs to run after eval,
// and prepare.js obviously doesn't.
const { classify, split } = require('../supportedBranches.js')
const { readFile } = require('node:fs/promises')
const { postReview, dismissReviews } = require('./reviews.js')
const reviewKey = 'check-target-branch'
/**
* @param {{
* github: InstanceType<import('@actions/github/lib/utils').GitHub>,
* context: import('@actions/github/lib/context').Context
* core: import('@actions/core')
* dry: boolean
* }} CheckTargetBranchProps
*/
async function checkTargetBranch({ github, context, core, dry }) {
/**
* @type {{
* attrdiff: {
* added: string[],
* changed: string[],
* removed: string[],
* },
* attrdiffByKernel: Record<string, {
* added: string[],
* changed: string[],
* removed: string[],
* }>,
* attrdiffByPlatform: Record<string, {
* added: string[],
* changed: string[],
* removed: string[],
* }>,
* labels: Record<string, boolean>,
* rebuildCountByKernel: Record<string, number>,
* rebuildsByKernel: Record<string, string[]>,
* rebuildsByPlatform: Record<string, string[]>,
* }}
*/
const changed = JSON.parse(
await readFile('comparison/changed-paths.json', 'utf-8'),
)
const pull_number = context.payload.pull_request?.number
if (!pull_number) {
core.warning(
'Skipping checkTargetBranch: no pull_request number (is this being run as part of a merge group?)',
)
return
}
const prInfo = (
await github.rest.pulls.get({
...context.repo,
pull_number,
})
).data
const base = prInfo.base.ref
const head = prInfo.head.ref
const baseClassification = classify(base)
const headClassification = classify(head)
// Don't run on, e.g., staging-nixos to master merges.
if (headClassification.type.includes('development')) {
core.info(
`Skipping checkTargetBranch: PR is from a development branch (${head})`,
)
await dismissReviews({
github,
context,
core,
dry,
reviewKey,
})
return
}
// Don't run on PRs against staging branches, wip branches, haskell-updates, etc.
if (!baseClassification.type.includes('primary')) {
core.info(
`Skipping checkTargetBranch: PR is against a non-primary base branch (${base})`,
)
await dismissReviews({
github,
context,
core,
dry,
reviewKey,
})
return
}
const maxRebuildCount = Math.max(
...Object.values(changed.rebuildCountByKernel),
)
const rebuildsAllTests =
changed.attrdiff.changed.includes('nixosTests.simple-container') ||
changed.attrdiff.changed.includes('nixosTests.simple-vm')
// https://github.com/NixOS/nixpkgs/pull/521157
// These should go to master and release-xx.xx when backported
let isExemptKernelUpdate = false
if (prInfo.changed_files === 1) {
const changedFiles = (
await github.rest.pulls.listFiles({
...context.repo,
pull_number,
})
).data
isExemptKernelUpdate =
changedFiles.length === 1 &&
changedFiles[0].filename ===
'pkgs/os-specific/linux/kernel/xanmod-kernels.nix'
}
// https://github.com/NixOS/nixpkgs/pull/483194#issuecomment-3793393218
const isExemptHomeAssistantUpdate =
maxRebuildCount <= 1500 && head === 'wip-home-assistant'
core.info(
[
`checkTargetBranch: this PR:`,
` * causes ${maxRebuildCount} rebuilds`,
` * ${rebuildsAllTests ? 'rebuilds' : 'does not rebuild'} all NixOS tests`,
` * ${isExemptKernelUpdate ? 'is' : 'is not'} an exempt kernel update`,
` * ${isExemptHomeAssistantUpdate ? 'is' : 'is not'} an exempt home-assistant update`,
].join('\n'),
)
if (
maxRebuildCount >= 1000 &&
!isExemptHomeAssistantUpdate &&
!isExemptKernelUpdate
) {
const desiredBranch =
base === 'master' ? 'staging' : `staging-${split(base).version}`
const body = [
`The PR's base branch is set to \`${base}\`, but this PR causes ${maxRebuildCount} rebuilds.`,
'It is therefore considered a mass rebuild.',
`Please [change the base branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-base-branch-of-a-pull-request) to [the right base branch for your changes](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#branch-conventions) (probably \`${desiredBranch}\`).`,
].join('\n')
await postReview({
github,
context,
core,
dry,
body,
event: 'REQUEST_CHANGES',
reviewKey,
})
} else if (rebuildsAllTests && !isExemptKernelUpdate) {
let branchText
if (base === 'master' && maxRebuildCount >= 500) {
branchText = '(probably either `staging-nixos` or `staging`)'
} else if (base === 'master') {
branchText = '(probably `staging-nixos`)'
} else if (maxRebuildCount >= 500) {
branchText = `(probably either \`staging-nixos-${split(base).version}\` or \`staging-${split(base).version}\`)`
} else {
branchText = `(probably \`staging-nixos-${split(base).version}\`)`
}
const body = [
`The PR's base branch is set to \`${base}\`, but this PR rebuilds all NixOS tests.`,
base === 'master' && maxRebuildCount >= 500
? `Since this PR also causes ${maxRebuildCount} rebuilds, it may also be considered a mass rebuild.`
: '',
`Please [change the base branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-base-branch-of-a-pull-request) to [the right base branch for your changes](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#branch-conventions) ${branchText}.`,
].join('\n')
await postReview({
github,
context,
core,
dry,
body,
event: 'REQUEST_CHANGES',
reviewKey,
})
} else if (
maxRebuildCount >= 500 &&
!isExemptKernelUpdate &&
!isExemptHomeAssistantUpdate
) {
const stagingBranch =
base === 'master' ? 'staging' : `staging-${split(base).version}`
const body = [
`The PR's base branch is set to \`${base}\`, and this PR causes ${maxRebuildCount} rebuilds.`,
`Please consider whether this PR causes a mass rebuild according to [our conventions](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#branch-conventions).`,
`If it does cause a mass rebuild, please [change the base branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-base-branch-of-a-pull-request) to [the right base branch for your changes](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#branch-conventions) (probably \`${stagingBranch}\`).`,
`If it does not cause a mass rebuild, this message can be ignored.`,
].join('\n')
await postReview({
github,
context,
core,
dry,
body,
event: 'REQUEST_CHANGES',
reviewKey,
})
} else {
core.info('checkTargetBranch: this PR is against an appropriate branch.')
await dismissReviews({
github,
context,
core,
dry,
reviewKey,
})
}
}
module.exports = checkTargetBranch

View File

@@ -3,7 +3,6 @@ module.exports = async ({ github, context, core, dry, cherryPicks }) => {
const { classify } = require('../supportedBranches.js')
const withRateLimit = require('./withRateLimit.js')
const { dismissReviews, postReview } = require('./reviews.js')
const reviewKey = 'check-commits'
await withRateLimit({ github, core }, async (stats) => {
stats.prs = 1
@@ -194,7 +193,7 @@ module.exports = async ({ github, context, core, dry, cherryPicks }) => {
// An empty results array will always trigger this condition, which is helpful
// to clean up reviews created by the prepare step when on the wrong branch.
if (results.every(({ severity }) => severity === 'info')) {
await dismissReviews({ github, context, dry, reviewKey })
await dismissReviews({ github, context, dry })
return
}
@@ -317,6 +316,6 @@ module.exports = async ({ github, context, core, dry, cherryPicks }) => {
// Posting a review could fail for very long comments. This can only happen with
// multiple commits all hitting the truncation limit for the diff. If you ever hit
// this case, consider just splitting up those commits into multiple PRs.
await postReview({ github, context, core, dry, body, reviewKey })
await postReview({ github, context, core, dry, body })
})
}

View File

@@ -1,117 +0,0 @@
// @ts-check
const { promisify } = require('node:util')
const execFile = promisify(require('node:child_process').execFile)
/**
* @typedef {{
* subject: string,
* sha: string,
* author: { name: string, email: string },
* committer: { name: string, email: string}
* changedPaths: string[],
* changedPathSegments: Set<string>,
* }} Commit
*/
/**
* @param {{
* args: string[]
* core: import('@actions/core'),
* quiet?: boolean,
* repoPath?: string,
* }} RunGitProps
*/
async function runGit({ args, repoPath, core, quiet }) {
if (repoPath) {
args = ['-C', repoPath, ...args]
}
if (!quiet) {
core.info(`About to run \`git ${args.map((s) => `'${s}'`).join(' ')}\``)
}
return await execFile('git', args)
}
/**
* Gets the SHA, subject and changed files for each commit in the given PR.
*
* Don't use GitHub API at all: the "list commits on PR" endpoint has a limit
* of 250 commits and doesn't return the changed files.
*
* @param {{
* core: import('@actions/core'),
* pr: Awaited<ReturnType<InstanceType<import('@actions/github/lib/utils').GitHub>["rest"]["pulls"]["get"]>>["data"]
* repoPath?: string,
* }} GetCommitMessagesForPRProps
*
* @returns {Promise<Commit[]>}
*/
async function getCommitDetailsForPR({ core, pr, repoPath }) {
await runGit({
args: ['fetch', `--depth=1`, 'origin', pr.base.sha],
repoPath,
core,
})
await runGit({
args: ['fetch', `--depth=${pr.commits + 1}`, 'origin', pr.head.sha],
repoPath,
core,
})
const shas = (
await runGit({
args: [
'rev-list',
`--max-count=${pr.commits}`,
`${pr.base.sha}..${pr.head.sha}`,
],
repoPath,
core,
})
).stdout
.split('\n')
.map((s) => s.trim())
.filter(Boolean)
return Promise.all(
shas.map(async (sha) => {
// Subject, author name, author email, committer name, committer email (all tab-seperated)
// then a blank line, then filenames.
const result = (
await runGit({
args: [
'log',
'--format=%s\t%aN\t%aE\t%cN\t%cE',
'--name-only',
'-1',
sha,
],
repoPath,
core,
quiet: true,
})
).stdout.split('\n')
const [subject, authorName, authorEmail, committerName, committerEmail] =
result[0].split('\t')
const changedPaths = result.slice(2, -1)
const changedPathSegments = new Set(
changedPaths.flatMap((path) => path.split('/')),
)
return {
sha,
subject,
author: { name: authorName, email: authorEmail },
committer: { name: committerName, email: committerEmail },
changedPaths,
changedPathSegments,
}
}),
)
}
module.exports = { getCommitDetailsForPR }

View File

@@ -1,223 +0,0 @@
// @ts-check
const { classify } = require('../supportedBranches.js')
const { getCommitDetailsForPR } = require('./get-pr-commit-details.js')
/** @typedef {import('./get-pr-commit-details.js').Commit} Commit */
/**
* @param {{
* github: InstanceType<import('@actions/github/lib/utils').GitHub>,
* context: typeof import('@actions/github').context,
* core: import('@actions/core'),
* repoPath?: string,
* }} LintCommitsProps
*/
async function lintCommits({ github, context, core, repoPath }) {
// This check should only be run when we have the pull_request context.
const pull_number = context.payload.pull_request?.number
if (!pull_number) {
core.info('This is not a pull request. Skipping checks.')
return
}
const pr = (
await github.rest.pulls.get({
...context.repo,
pull_number,
})
).data
const baseBranchType = classify(
pr.base.ref.replace(/^refs\/heads\//, ''),
).type
const headBranchType = classify(
pr.head.ref.replace(/^refs\/heads\//, ''),
).type
if (
baseBranchType.includes('development') &&
headBranchType.includes('development') &&
pr.base.repo.id === pr.head.repo?.id
) {
// This matches, for example, PRs from NixOS:staging-next to NixOS:master, or vice versa.
// Ignore them: we should only care about PRs introducing *new* commits.
// We still want to run on PRs from, e.g., Someone:master to NixOS:master, though.
core.info(
'This PR is from one development branch to another. Skipping checks.',
)
return
}
const commits = await getCommitDetailsForPR({ core, pr, repoPath })
await checkCommitMessages({ commits, core })
await checkCommitMetadata({ commits, core })
}
/**
* @param {{
* commits: Commit[],
* core: import('@actions/core'),
* }} CheckCommitMessagesProps
*/
async function checkCommitMessages({ commits, core }) {
const failures = new Set()
const conventionalCommitTypes = [
'build',
'chore',
'ci',
'doc',
'docs',
'feat',
'feature',
'fix',
'perf',
'refactor',
'style',
'test',
]
/**
* @param {string[]} types e.g. ["fix", "feat"]
* @param {string?} sha commit hash
*/
function makeConventionalCommitRegex(types, sha = null) {
core.info(
`${
sha
? `Conventional commit types for ${sha?.slice(0, 16)}`
: 'Default conventional commit types'
}: ${JSON.stringify(types)}`,
)
return new RegExp(`^(${types.join('|')})!?(\\(.*\\))?!?:`)
}
// Optimize for the common case that we don't have path segments with the
// same name as a conventional commit type.
const fullConventionalCommitRegex = makeConventionalCommitRegex(
conventionalCommitTypes,
)
for (const commit of commits) {
const logMsgStart = `Commit ${commit.sha}'s message's subject ("${commit.subject}")`
// If we have a commit `perf: ...`, and we touch a file containing the path
// segment "perf", we don't want to flag this.
const filteredTypes = conventionalCommitTypes.filter(
(type) => !commit.changedPathSegments.has(type),
)
const conventionalCommitRegex =
filteredTypes.length === conventionalCommitTypes.length
? fullConventionalCommitRegex
: makeConventionalCommitRegex(filteredTypes, commit.sha)
if (!commit.subject.includes(': ')) {
core.error(
`${logMsgStart} was detected as not meeting our guidelines because ` +
'it does not contain a colon followed by a whitespace. ' +
'There are likely other issues as well.',
)
failures.add(commit.sha)
}
if (commit.subject.endsWith('.')) {
core.error(
`${logMsgStart} was detected as not meeting our guidelines because ` +
'it ends in a period. There may be other issues as well.',
)
failures.add(commit.sha)
}
const fixups = ['amend!', 'fixup!', 'squash!']
if (fixups.some((s) => commit.subject.startsWith(s))) {
core.error(
`${logMsgStart} was detected as not meeting our guidelines because ` +
`it begins with "${fixups.find((s) => commit.subject.startsWith(s))}". ` +
'Did you forget to run `git rebase -i --autosquash`?',
)
failures.add(commit.sha)
}
if (conventionalCommitRegex.test(commit.subject)) {
core.error(
`${logMsgStart} was detected as not meeting our guidelines because ` +
'it seems to use conventional commit (conventionalcommits.org) ' +
'formatting. Nixpkgs has its own, different, commit message ' +
'formatting standards.',
)
failures.add(commit.sha)
}
if (!failures.has(commit.sha)) {
core.info(`${logMsgStart} passed our automated checks!`)
}
}
if (failures.size !== 0) {
core.error(
'Please review the guidelines at ' +
'<https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#commit-conventions>, ' +
'as well as the applicable area-specific guidelines linked there.',
)
core.setFailed('Committers: merging is discouraged.')
}
}
/**
* @param {{
* commits: Commit[],
* core: import('@actions/core'),
* }} CheckGitFieldsProps
*/
async function checkCommitMetadata({ commits, core }) {
const failures = new Set()
/** @type {(s: string) => boolean} */
const isEmail = (s) => /^.+@.*$/.test(s)
for (const commit of commits) {
if (!commit.author.name) {
core.error(`Commit ${commit.sha} author's name field is missing`)
failures.add(commit.sha)
}
if (!commit.author.email || !isEmail(commit.author.email)) {
core.error(
`Commit ${commit.sha} author's email field is missing or invalid`,
)
failures.add(commit.sha)
}
if (!commit.committer.name) {
core.error(`Commit ${commit.sha} committer's name field is missing`)
failures.add(commit.sha)
}
if (!commit.committer.email || !isEmail(commit.committer.email)) {
core.error(
`Commit ${commit.sha} committer's email field is missing or invalid`,
)
failures.add(commit.sha)
}
if (!failures.has(commit.sha)) {
core.info(
`Commit ${commit.sha}'s git fields passed our automated checks!`,
)
}
}
if (failures.size !== 0) {
core.error(
'Please add the missing commit fields. ' +
'You can use the noreply email address generated for you by GitHub ' +
'(https://docs.github.com/en/account-and-profile/reference/email-addresses-reference#your-noreply-email-address) ' +
"if you'd like.",
)
core.setFailed('Committers: merging is discouraged.')
}
}
module.exports = lintCommits

View File

@@ -1,95 +0,0 @@
// @ts-check
const { classify } = require('../supportedBranches.js')
const { getCommitDetailsForPR } = require('./get-pr-commit-details')
/**
* @param {{
* github: InstanceType<import('@actions/github/lib/utils').GitHub>,
* context: import('@actions/github/lib/context').Context,
* core: import('@actions/core'),
* repoPath?: string,
* dry: boolean,
* }} CheckManualFileEditsProps
*/
async function checkManualFileEdits({ github, context, core, repoPath, dry }) {
const { dismissReviews, postReview } = require('./reviews.js')
const reviewKey = 'manual-file-edits'
const pull_number = context.payload.pull_request?.number
if (!pull_number) {
core.info('This is not a pull request. Skipping checks.')
return
}
const pr = (
await github.rest.pulls.get({
...context.repo,
pull_number,
})
).data
if (pr.user.login.endsWith('[bot]')) {
core.info('This is a bot, so these checks do not apply.')
return
}
const baseBranchType = classify(
pr.base.ref.replace(/^refs\/heads\//, ''),
).type
const headBranchType = classify(
pr.head.ref.replace(/^refs\/heads\//, ''),
).type
if (
baseBranchType.includes('development') &&
headBranchType.includes('development') &&
pr.base.repo.id === pr.head.repo?.id
) {
// This matches, for example, PRs from NixOS:staging-next to NixOS:master, or vice versa.
// Ignore them: we should only care about PRs introducing *new* commits.
// We still want to run on PRs from, e.g., Someone:master to NixOS:master, though.
core.info(
'This PR is from one development branch to another. Skipping checks.',
)
return
}
const details = await getCommitDetailsForPR({ core, pr, repoPath })
if (
details.some(({ changedPaths }) =>
changedPaths.includes('maintainers/github-teams.json'),
)
) {
postReview({
github,
context,
core,
dry,
event: 'REQUEST_CHANGES',
body: [
'maintainers/github-teams.json is supposed to accurately reflect the state of the teams in GitHub.\n',
'Therefore, it should not be edited manually.\n',
'All changes to teams listed in maintainers/github-teams.json should be performed in GitHub by a team maintainer.\n',
"Team maintainers are listed in the github-teams.json file and in GitHub's UI.\n",
'If there is no team maintainer available, an org owner can make the needed change, please contact one by',
'following the instructions at https://github.com/NixOS/org/blob/main/doc/github-org-owners.md#how-to-contact-the-team.\n',
'Thank you!',
].reduce(
(prev, curr) => prev + (!prev || prev.endsWith('\n') ? '' : ' ') + curr,
'',
),
reviewKey,
})
} else {
dismissReviews({
github,
context,
core,
dry,
reviewKey,
})
}
}
module.exports = checkManualFileEdits

View File

@@ -2,11 +2,11 @@ const { classify } = require('../supportedBranches.js')
function runChecklist({
committers,
events,
files,
pull_request,
log,
maintainers,
reviews,
user,
userIsMaintainer,
}) {
@@ -27,35 +27,18 @@ function runChecklist({
.reduce((acc, cur) => acc?.intersection(cur) ?? cur)
const approvals = new Set(
reviews
events
.filter(
({ state, commit }) =>
state === 'APPROVED' &&
({ event, state, commit_id }) =>
event === 'reviewed' &&
state === 'approved' &&
// Only approvals for the current head SHA count, otherwise authors could push
// bad code between the approval and the merge.
commit?.oid === pull_request.head.sha,
commit_id === pull_request.head.sha,
)
.map(({ user }) => user.id),
)
// A "changes requested" review from a committer blocks both the merge queue and
// auto-merge, even if it was made on an older commit (unlike approvals, GitHub does
// not auto-dismiss changes-requested reviews on push). For each committer, take their
// latest actionable review; if it's CHANGES_REQUESTED, they're blocking the PR.
// Dismissed reviews surface as DISMISSED and comment-only follow-ups as COMMENTED, so
// both are skipped naturally — the prior actionable review still stands until the
// committer explicitly approves or requests changes again.
const committerReviewState = new Map()
for (const { user, state } of reviews) {
if (
committers.has(user.id) &&
['APPROVED', 'CHANGES_REQUESTED'].includes(state)
) {
committerReviewState.set(user.id, state)
}
}
const noBlockingReviews = !Array.from(committerReviewState.values()).includes(
'CHANGES_REQUESTED',
.map(({ user }) => user?.id)
// Some users have been deleted, so filter these out.
.filter(Boolean),
)
const checklist = {
@@ -63,22 +46,13 @@ function runChecklist({
classify(pull_request.base.ref).type.includes('development'),
'PR touches only files of packages in `pkgs/by-name/`.': allByName,
'PR is at least one of:': {
'Approved by a [committer](https://github.com/orgs/NixOS/teams/nixpkgs-committers).':
committers.intersection(approvals).size > 0,
'Approved by a committer.': committers.intersection(approvals).size > 0,
'Backported via label.':
pull_request.user.login === 'nixpkgs-ci[bot]' &&
pull_request.head.ref.startsWith('backport-'),
'Opened by a [committer](https://github.com/orgs/NixOS/teams/nixpkgs-committers).':
committers.has(pull_request.user.id),
'Opened by [@r-ryantm](https://nix-community.github.io/nixpkgs-update/r-ryantm/).':
pull_request.user.login === 'r-ryantm',
'Opened by a committer.': committers.has(pull_request.user.id),
'Opened by r-ryantm.': pull_request.user.login === 'r-ryantm',
},
'PR is not a draft': !pull_request.draft,
// CI state is intentionally *not* a checklist item: auto-merge exists precisely to
// cover unfinished CI, and an already-failed CI is reported via the merge message
// (see merge() below) rather than a blanket refusal.
'PR is not blocked by a "changes requested" review from a [committer](https://github.com/orgs/NixOS/teams/nixpkgs-committers).':
noBlockingReviews,
}
if (user) {
@@ -88,9 +62,8 @@ function runChecklist({
if (allByName) {
// We can only determine the below, if all packages are in by-name, since
// we can't reliably relate changed files to packages outside by-name.
checklist[
`${user.login} is a maintainer of all touched packages on the ${pull_request.base.ref} branch.`
] = eligible.has(user.id)
checklist[`${user.login} is a maintainer of all touched packages.`] =
eligible.has(user.id)
}
} else {
// This is only used when no user is passed, i.e. for labeling.
@@ -119,7 +92,7 @@ function hasMergeCommand(body) {
return (body ?? '')
.replace(/<!--.*?-->/gms, '')
.replace(/(^`{3,})[^`].*?\1/gms, '')
.match(/^@NixOS\/nixpkgs-merge-bot merge\s*$/im)
.match(/^@NixOS\/nixpkgs-merge-bot merge\s*$/m)
}
async function handleMergeComment({ github, body, node_id, reaction }) {
@@ -145,7 +118,6 @@ async function handleMerge({
dry,
pull_request,
events,
reviews,
maintainers,
getTeamMembers,
getUser,
@@ -171,14 +143,6 @@ async function handleMerge({
// including an early exit when the first non-by-name file is found.
if (files.length >= 100) return false
const noPrFailuresState = (
await github.rest.repos.listCommitStatusesForRef({
...context.repo,
ref: pull_request.head.sha,
per_page: 100,
})
).data.find(({ context }) => context === 'no PR failures')?.state
// Only look through comments *after* the latest (force) push.
const lastPush = events.findLastIndex(
({ event, sha, commit_id }) =>
@@ -204,12 +168,10 @@ async function handleMerge({
)),
)
// Returns `{ reaction, messages }`: the reaction to leave on the merge comment and the
// lines to append to the bot's reply. Throws only on an unexpected API error.
async function merge() {
if (dry) {
core.info(`Merging #${pull_number}... (dry)`)
return { reaction: 'ROCKET', messages: ['Merge completed (dry)'] }
return 'Merge completed (dry)'
}
// Using GraphQL mutations instead of the REST /merge endpoint, because the latter
@@ -229,38 +191,16 @@ async function handleMerge({
}`,
{ node_id: pull_request.node_id, sha: pull_request.head.sha },
)
log('merge', 'Queued for merge')
return {
reaction: 'ROCKET',
messages: [
`:heavy_check_mark: [Queued](${resp.enqueuePullRequest.mergeQueueEntry.mergeQueue.url}) for merge (#306934)`,
],
}
return [
`:heavy_check_mark: [Queued](${resp.enqueuePullRequest.mergeQueueEntry.mergeQueue.url}) for merge (#306934)`,
]
} catch (e) {
log('Enqueuing failed', e.response.errors[0].message)
log('Enqueing failed', e.response.errors[0].message)
}
// Enqueuing fails when the required status checks are not satisfied, yet. If CI has
// already failed, enabling auto-merge would be pointless: it would never fire, and
// fixing CI requires a new push, which invalidates this merge command anyway (we only
// act on comments after the latest push). So we don't enable auto-merge and instead
// ask for a fresh command once CI is green again.
if (['error', 'failure'].includes(noPrFailuresState)) {
log('merge', 'CI has failed, not enabling auto-merge')
return {
reaction: 'THUMBS_DOWN',
messages: [
':x: Pull Request could not be merged: CI has failed (#305350).',
'',
'> [!TIP]',
'> PRs cannot be merged while CI is failing.',
'> Once CI is passing, comment `@NixOS/nixpkgs-merge-bot merge` again.',
],
}
}
// CI has not finished yet, so we enable auto-merge. We could also only use auto-merge,
// but this often gets stuck for no apparent reason.
// If required status checks are not satisfied, yet, the above will fail. In this case
// we can enable auto-merge. We could also only use auto-merge, but this often gets
// stuck for no apparent reason.
try {
await github.graphql(
`mutation($node_id: ID!, $sha: GitObjectID) {
@@ -272,18 +212,12 @@ async function handleMerge({
}`,
{ node_id: pull_request.node_id, sha: pull_request.head.sha },
)
log('merge', 'Auto-merge enabled')
return {
reaction: 'ROCKET',
messages: [
`:heavy_check_mark: Enabled Auto Merge (#306934)`,
'',
'> [!TIP]',
'> [Auto Merge](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/automatically-merging-a-pull-request) will queue this PR once required CI checks succeed.',
'> If CI fails instead, fixing it needs a new push, which disables Auto Merge and invalidates this command — comment `@NixOS/nixpkgs-merge-bot merge` again once CI is green.',
'> If GitHub gets stuck even though CI passed (it sometimes does), leaving another approval should kick off the merge.',
],
}
return [
`:heavy_check_mark: Enabled Auto Merge (#306934)`,
'',
'> [!TIP]',
'> Sometimes GitHub gets stuck after enabling Auto Merge. In this case, leaving another approval should trigger the merge.',
]
} catch (e) {
log('Auto Merge failed', e.response.errors[0].message)
throw new Error(e.response.errors[0].message)
@@ -326,11 +260,11 @@ async function handleMerge({
const { result, eligible, checklist } = runChecklist({
committers,
events,
files,
pull_request,
log,
maintainers,
reviews,
user: comment.user,
userIsMaintainer: await isMaintainer(comment.user.login),
})
@@ -367,12 +301,10 @@ async function handleMerge({
}
if (result) {
await react('ROCKET')
try {
const { reaction, messages } = await merge()
await react(reaction)
body.push(...messages)
body.push(...(await merge()))
} catch (e) {
await react('THUMBS_DOWN')
// Remove the HTML comment with node_id reference to allow retrying this merge on the next run.
body.shift()
body.push(`:x: Merge failed with: ${e} (#371492)`)
@@ -397,11 +329,11 @@ async function handleMerge({
const { result } = runChecklist({
committers,
events,
files,
pull_request,
log,
maintainers,
reviews,
})
// Returns a boolean, which indicates whether the PR is merge-bot eligible in principle.

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,10 @@
{
"private": true,
"//": [
"Keep `@actions/core` and `@actions/github` in sync with",
"https://github.com/actions/github-script/blob/main/package.json.",
"Keep `@actions/artifact` and `bottleneck` in sync with",
"`.github/workflows/bot.yml`."
],
"dependencies": {
"@actions/artifact": "6.2.1",
"@actions/core": "1.10.1",
"@actions/github": "9.1.0",
"@actions/artifact": "2.3.2",
"@actions/core": "1.11.1",
"@actions/github": "6.0.1",
"bottleneck": "2.19.5",
"commander": "14.0.3"
"commander": "14.0.0"
}
}

View File

@@ -1,7 +1,5 @@
const { classify } = require('../supportedBranches.js')
const { postReview, dismissReviews } = require('./reviews.js')
const reviewKey = 'prepare'
const supportedSystems = require('./supportedSystems.js')
const { postReview } = require('./reviews.js')
module.exports = async ({ github, context, core, dry }) => {
const pull_number = context.payload.pull_request.number
@@ -48,7 +46,7 @@ module.exports = async ({ github, context, core, dry }) => {
`Please target \`${correctBranch}\` instead.`,
].join('\n')
await postReview({ github, context, core, dry, body, reviewKey })
await postReview({ github, context, core, dry, body })
throw new Error('The PR targets a channel branch.')
}
@@ -172,17 +170,9 @@ module.exports = async ({ github, context, core, dry }) => {
' ```',
].join('\n')
await postReview({
github,
context,
core,
dry,
body,
event: 'REQUEST_CHANGES',
reviewKey,
})
} else {
await dismissReviews({ github, context, core, dry, reviewKey })
await postReview({ github, context, core, dry, body })
throw new Error(`The PR contains commits from a different base.`)
}
}
@@ -216,8 +206,7 @@ module.exports = async ({ github, context, core, dry }) => {
core.setOutput('mergedSha', mergedSha)
core.setOutput('targetSha', targetSha)
const systems = await supportedSystems({ github, context, targetSha })
core.setOutput('systems', systems)
core.setOutput('systems', require('../supportedSystems.json'))
const files = (
await github.paginate(github.rest.pulls.listFiles, {

View File

@@ -6,29 +6,28 @@ async function handleReviewers({
dry,
pull_request,
reviews,
user_maintainers,
team_maintainers,
maintainers,
owners,
getTeamMembers,
getUser,
getTeam,
}) {
const pull_number = pull_request.number
// Users that the PR has already reached, e.g. they've left a review or have been requested for one
const users_reached = new Set([
...pull_request.requested_reviewers.map(({ login }) => login.toLowerCase()),
...reviews.map(({ user }) => user.login.toLowerCase()),
])
log('reviewers - users_reached', Array.from(users_reached).join(', '))
const requested_reviewers = new Set(
pull_request.requested_reviewers.map(({ login }) => login.toLowerCase()),
)
log(
'reviewers - requested_reviewers',
Array.from(requested_reviewers).join(', '),
)
// Same for teams
const teams_reached = new Set([
...pull_request.requested_teams.map(({ slug }) => slug.toLowerCase()),
...reviews.flatMap(({ onBehalfOf }) =>
onBehalfOf.nodes.map(({ slug }) => slug.toLowerCase()),
),
])
log('reviewers - teams_reached', Array.from(teams_reached).join(', '))
const existing_reviewers = new Set(
reviews.map(({ user }) => user?.login.toLowerCase()).filter(Boolean),
)
log(
'reviewers - existing_reviewers',
Array.from(existing_reviewers).join(', '),
)
// Early sanity check, before we start making any API requests. The list of maintainers
// does not have duplicates so the only user to filter out from this list would be the
@@ -36,130 +35,90 @@ async function handleReviewers({
// further down again.
// This is to protect against huge treewides consuming all our API requests for no
// reason.
if (user_maintainers.length + team_maintainers.length > 16) {
if (maintainers.length > 16) {
core.warning('Too many potential reviewers, skipping review requests.')
// Return a boolean on whether the "needs: reviewers" label should be set.
return users_reached.size === 0 && teams_reached.size === 0
return existing_reviewers.size === 0 && requested_reviewers.size === 0
}
// Users that should be reached
var users_to_reach = new Set([
...(
await Promise.all(
user_maintainers.map(async (id) => {
const user = await getUser(id)
// User may have deleted their account
return user?.login?.toLowerCase()
}),
)
).filter(Boolean),
const users = new Set([
...(await Promise.all(
maintainers.map(async (id) => (await getUser(id)).login.toLowerCase()),
)),
...owners
.filter((handle) => handle && !handle.includes('/'))
.map((handle) => handle.toLowerCase()),
])
log('reviewers - users', Array.from(users).join(', '))
const teams = new Set(
owners
.map((handle) => handle.split('/'))
.filter(([org, slug]) => org === context.repo.owner && slug)
.map(([, slug]) => slug),
)
log('reviewers - teams', Array.from(teams).join(', '))
const team_members = new Set(
(await Promise.all(Array.from(teams, getTeamMembers)))
.flat(1)
.map(({ login }) => login.toLowerCase()),
)
log('reviewers - team_members', Array.from(team_members).join(', '))
const new_reviewers = users
.union(team_members)
// We can't request a review from the author.
.difference(new Set([pull_request.user?.login.toLowerCase()]))
log('reviewers - new_reviewers', Array.from(new_reviewers).join(', '))
// Filter users to repository collaborators. If they're not, they can't be requested
// for review. In that case, they probably missed their invite to the maintainers team.
users_to_reach = new Set(
(
await Promise.all(
Array.from(users_to_reach, async (username) => {
// TODO: Restructure this file to only do the collaborator check for those users
// who were not already part of a team. Being a member of a team makes them
// collaborators by definition.
try {
await github.rest.repos.checkCollaborator({
...context.repo,
username,
})
return username
} catch (e) {
if (e.status !== 404) throw e
core.warning(
`PR #${pull_number}: User ${username} cannot be requested for review because they don't exist or are not a repository collaborator, ignoring. They probably missed the automated invite to the maintainers team (see <https://github.com/NixOS/nixpkgs/issues/234293>).`,
)
}
}),
)
).filter(Boolean),
)
log('reviewers - users_to_reach', Array.from(users_to_reach).join(', '))
const reviewers = (
await Promise.all(
Array.from(new_reviewers, async (username) => {
// TODO: Restructure this file to only do the collaborator check for those users
// who were not already part of a team. Being a member of a team makes them
// collaborators by definition.
try {
await github.rest.repos.checkCollaborator({
...context.repo,
username,
})
return username
} catch (e) {
if (e.status !== 404) throw e
core.warning(
`PR #${pull_number}: User ${username} cannot be requested for review because they don't exist or are not a repository collaborator, ignoring. They probably missed the automated invite to the maintainers team (see <https://github.com/NixOS/nixpkgs/issues/234293>).`,
)
}
}),
)
).filter(Boolean)
log('reviewers - reviewers', reviewers.join(', '))
// Similar for teams
var teams_to_reach = new Set([
...(
await Promise.all(
team_maintainers.map(async (id) => {
const team = await getTeam(id)
// Team may have been deleted
return team?.slug?.toLowerCase()
}),
)
).filter(Boolean),
...owners
.map((handle) => handle.split('/'))
.filter(
([org, slug]) =>
org.toLowerCase() === context.repo.owner.toLowerCase() && slug,
)
.map(([, slug]) => slug.toLowerCase()),
])
teams_to_reach = new Set(
(
await Promise.all(
Array.from(teams_to_reach, async (slug) => {
try {
await github.rest.teams.checkPermissionsForRepoInOrg({
org: context.repo.owner,
team_slug: slug,
owner: context.repo.owner,
repo: context.repo.repo,
})
return slug
} catch (e) {
if (e.status !== 404) throw e
core.warning(
`PR #${pull_number}: Team ${slug} cannot be requested for review because it doesn't exist or has no repository permissions, ignoring. Probably wasn't added to the nixpkgs-maintainers team (see https://github.com/NixOS/nixpkgs/tree/master/maintainers#maintainer-teams)`,
)
}
}),
)
).filter(Boolean),
)
log('reviewers - teams_to_reach', Array.from(teams_to_reach).join(', '))
if (users_to_reach.size + teams_to_reach.size > 15) {
if (reviewers.length > 15) {
core.warning(
`Too many reviewers (users: ${Array.from(users_to_reach).join(', ')}, teams: ${Array.from(teams_to_reach).join(', ')}), skipping review requests.`,
`Too many reviewers (${reviewers.join(', ')}), skipping review requests.`,
)
// Return a boolean on whether the "needs: reviewers" label should be set.
return users_reached.size === 0 && teams_reached.size === 0
return existing_reviewers.size === 0 && requested_reviewers.size === 0
}
// We don't want to rerequest reviews from people who already reviewed or were requested
const users_not_yet_reached = Array.from(
users_to_reach.difference(users_reached),
const non_requested_reviewers = new Set(reviewers)
.difference(requested_reviewers)
// We don't want to rerequest reviews from people who already reviewed.
.difference(existing_reviewers)
log(
'reviewers - non_requested_reviewers',
Array.from(non_requested_reviewers).join(', '),
)
log('reviewers - users_not_yet_reached', users_not_yet_reached.join(', '))
// We don't want to rerequest reviews from teams who already reviewed or were requested
const teams_not_yet_reached = Array.from(
teams_to_reach.difference(teams_reached),
)
log('reviewers - teams_not_yet_reached', teams_not_yet_reached.join(', '))
if (
users_not_yet_reached.length === 0 &&
teams_not_yet_reached.length === 0
) {
if (non_requested_reviewers.size === 0) {
log('Has reviewer changes', 'false (skipped)')
} else if (dry) {
core.info(
`Requesting user reviewers for #${pull_number}: ${users_not_yet_reached.join(', ')} (dry)`,
)
core.info(
`Requesting team reviewers for #${pull_number}: ${teams_not_yet_reached.join(', ')} (dry)`,
`Requesting reviewers for #${pull_number}: ${Array.from(non_requested_reviewers).join(', ')} (dry)`,
)
} else {
// We had tried the "request all reviewers at once" thing in the past, but it didn't work out:
@@ -169,17 +128,15 @@ async function handleReviewers({
await github.rest.pulls.requestReviewers({
...context.repo,
pull_number,
reviewers: users_not_yet_reached,
team_reviewers: teams_not_yet_reached,
reviewers,
})
}
// Return a boolean on whether the "needs: reviewers" label should be set.
return (
users_not_yet_reached.length === 0 &&
teams_not_yet_reached.length === 0 &&
users_reached.size === 0 &&
teams_reached.size === 0
non_requested_reviewers.size === 0 &&
existing_reviewers.size === 0 &&
requested_reviewers.size === 0
)
}

View File

@@ -1,235 +1,60 @@
// @ts-check
const eventToState = {
COMMENT: 'COMMENTED',
REQUEST_CHANGES: 'CHANGES_REQUESTED',
}
// Use substring checks in order to allow testing in forks
// Usernames must also end in "[bot]"
const reviewUsers = [
'github-actions',
'nixpkgs-ci',
'branch-check',
'commit-check',
'manual-edit',
]
/**
* @typedef {InstanceType<import('@actions/github/lib/utils').GitHub>} GitHub
* @typedef {typeof import('@actions/github').context} Context
*
* @typedef {Awaited<ReturnType<GitHub['rest']['pulls']['listReviews']>>['data'][number]} Review
* @typedef {Review & { user: NonNullable<Review['user']> }} ReviewWithNonNullUser
*/
/**
* @param {{
* github: GitHub,
* context: Context,
* core: import('@actions/core'),
* dry: boolean,
* reviewKey?: string,
* }} DismissReviewsProps
*/
async function dismissReviews({ github, context, core, dry, reviewKey }) {
const pull_number = context.payload.pull_request?.number
if (!pull_number) {
core.warning('dismissReviews called outside of pull_request context')
return
}
async function dismissReviews({ github, context, dry }) {
const pull_number = context.payload.pull_request.number
if (dry) {
return
}
const allReviews = await github.paginate(github.rest.pulls.listReviews, {
...context.repo,
pull_number,
})
const reviews = /** @type {ReviewWithNonNullUser[]} */ (
allReviews.filter(
(review) =>
review.user &&
review.state !== 'DISMISSED' &&
review.user.login.endsWith('[bot]') &&
reviewUsers.some((substr) => review.user?.login.includes(substr)),
)
)
const reviewsByUser = reviews.reduce(
(prev, curr) => {
if (!(curr.user.login in prev)) {
prev[curr.user.login] = []
}
prev[curr.user.login].push(curr)
return prev
},
/** @type {Record<string, ReviewWithNonNullUser[]> } */ ({}),
)
const commentRegex = new RegExp(
/<!-- nixpkgs review key: (.*)(?:; resolved: .*)? -->/,
)
const reviewKeyRegex = new RegExp(
`<!-- (nixpkgs review key: ${reviewKey})(?:; resolved: .*)? -->`,
)
const commentResolvedRegex = new RegExp(
/<!-- nixpkgs review key: .*; resolved: true -->/,
)
let reviewsToMinimize = reviews
const /** @type {ReviewWithNonNullUser[]} */ reviewsToDismiss = []
const /** @type {ReviewWithNonNullUser[]} */ reviewsToResolve = []
if (reviewKey && reviews.every((review) => commentRegex.test(review.body))) {
reviewsToMinimize = reviews.filter((review) =>
reviewKeyRegex.test(review.body),
)
}
for (const reviewsForUser of Object.values(reviewsByUser)) {
// Make sure that we don't dismiss all reviews by a user if they
// have any reviews we don't want to dismiss.
if (
reviewsForUser.every(
(review) =>
commentResolvedRegex.test(review.body) ||
(reviewKey && reviewKeyRegex.test(review.body)) ||
// If we are called by check-commits and the review body is clearly
// from `commits.js`, then we can safely dismiss the review.
// This helps with pre-existing reviews (before the comments were added).
(reviewKey &&
reviewKey === 'check-commits' &&
review.body.includes('PR / Check / cherry-pick')),
)
) {
reviewsToDismiss.push(
...reviewsForUser.filter(
(review) => review.state === 'CHANGES_REQUESTED',
),
)
} else {
reviewsToResolve.push(
...reviewsForUser.filter(
(review) =>
review.state === 'CHANGES_REQUESTED' &&
!commentResolvedRegex.test(review.body) &&
reviewsToMinimize.some(
(toMinimize) => toMinimize.node_id === review.node_id,
),
),
)
}
}
await Promise.all([
...reviewsToMinimize.map(async (review) =>
github.graphql(
`mutation($node_id:ID!) {
minimizeComment(input: {
classifier: OUTDATED,
subjectId: $node_id
})
{ clientMutationId }
}`,
{ node_id: review.node_id },
),
),
...reviewsToDismiss.map(async (review) =>
github.rest.pulls.dismissReview({
await Promise.all(
(
await github.paginate(github.rest.pulls.listReviews, {
...context.repo,
pull_number,
review_id: review.id,
message: 'Review dismissed automatically',
})
)
.filter((review) => review.user?.login === 'github-actions[bot]')
.map(async (review) => {
if (review.state === 'CHANGES_REQUESTED') {
await github.rest.pulls.dismissReview({
...context.repo,
pull_number,
review_id: review.id,
message: 'All good now, thank you!',
})
}
await github.graphql(
`mutation($node_id:ID!) {
minimizeComment(input: {
classifier: RESOLVED,
subjectId: $node_id
})
{ clientMutationId }
}`,
{ node_id: review.node_id },
)
}),
),
...reviewsToResolve.map(async (review) =>
github.rest.pulls.updateReview({
...context.repo,
pull_number,
review_id: review.id,
body: review.body.replace(
reviewKeyRegex,
`<!-- nixpkgs review key: ${reviewKey}; resolved: true -->`,
),
}),
),
])
)
}
/**
* @param {{
* github: GitHub,
* context: Context,
* core: import('@actions/core'),
* dry: boolean,
* body: string,
* event: keyof eventToState,
* reviewKey: string,
* }} PostReviewProps
*/
async function postReview({
github,
context,
core,
dry,
body,
event = 'REQUEST_CHANGES',
reviewKey,
}) {
const pull_number = context.payload.pull_request?.number
if (!pull_number) {
core.warning('postReview called outside of pull_request context')
return
}
async function postReview({ github, context, core, dry, body }) {
const pull_number = context.payload.pull_request.number
const reviewKeyRegex = new RegExp(
`<!-- (nixpkgs review key: ${reviewKey})(?:; resolved: .*)? -->`,
)
const reviewKeyComment = `<!-- nixpkgs review key: ${reviewKey}; resolved: false -->`
body = body + '\n\n' + reviewKeyComment
const reviews = (
const pendingReview = (
await github.paginate(github.rest.pulls.listReviews, {
...context.repo,
pull_number,
})
).filter(
).find(
(review) =>
review.user &&
review.state !== 'DISMISSED' &&
review.user.login.endsWith('[bot]') &&
reviewUsers.some((substr) => review.user?.login.includes(substr)),
review.user?.login === 'github-actions[bot]' &&
// If a review is still pending, we can just update this instead
// of posting a new one.
(review.state === 'CHANGES_REQUESTED' ||
// No need to post a new review, if an older one with the exact
// same content had already been dismissed.
review.body === body),
)
/** @type {null | Review} */
let pendingReview
const matchingReviews = reviews.filter((review) =>
reviewKeyRegex.test(review.body),
)
if (matchingReviews.length === 0) {
pendingReview = null
} else if (
matchingReviews.length === 1 &&
matchingReviews[0].state === eventToState[event]
) {
pendingReview = matchingReviews[0]
} else {
await dismissReviews({
github,
context,
core,
dry,
reviewKey,
})
pendingReview = null
}
if (dry) {
if (pendingReview)
core.info(`pending review found: ${pendingReview.html_url}`)
@@ -237,28 +62,17 @@ async function postReview({
core.info(body)
} else {
if (pendingReview) {
await Promise.all([
github.rest.pulls.updateReview({
...context.repo,
pull_number,
review_id: pendingReview.id,
body,
}),
github.graphql(
`mutation($node_id:ID!) {
unminimizeComment(input: {
subjectId: $node_id
})
{ clientMutationId }
}`,
{ node_id: pendingReview.node_id },
),
])
await github.rest.pulls.updateReview({
...context.repo,
pull_number,
review_id: pendingReview.id,
body,
})
} else {
await github.rest.pulls.createReview({
...context.repo,
pull_number,
event,
event: 'REQUEST_CHANGES',
body,
})
}

View File

@@ -94,37 +94,4 @@ program
await run(getTeams, owner, repo, undefined, { ...options, outFile })
})
program
.command('lint-commits')
.description('Lint for common errors in commit messages')
.argument('<owner>', 'Owner of the GitHub repository to run on (Example: NixOS)')
.argument('<repo>', 'Name of the GitHub repository to run on (Example: nixpkgs)')
.argument('<pr>', 'Number of the Pull Request to run on')
.action(async (owner, repo, pr, options) => {
const checkCommitMessages = (await import('./lint-commits.js')).default
await run(checkCommitMessages, owner, repo, pr, options)
})
program
.command('check-target-branch')
.description('Check that the PR is made against the correct branch')
.argument('<owner>', 'Owner of the GitHub repository to run on (Example: NixOS)')
.argument('<repo>', 'Name of the GitHub repository to run on (Example: nixpkgs)')
.argument('<pr>', 'Number of the Pull Request to run on')
.action(async (owner, repo, pr, options) => {
const checkCommitMessages = (await import('./check-target-branch.js')).default
await run(checkCommitMessages, owner, repo, pr, options)
})
program
.command('manual-file-edits')
.description("Error when files that shouldn't be edited manually are")
.argument('<owner>', 'Owner of the GitHub repository to run on (Example: NixOS)')
.argument('<repo>', 'Name of the GitHub repository to run on (Example: nixpkgs)')
.argument('<pr>', 'Number of the Pull Request to run on')
.action(async (owner, repo, pr, options) => {
const checkManualFileEdits = (await import('./manual-file-edits.js')).default
await run(checkManualFileEdits, owner, repo, pr, options)
})
await program.parse()

View File

@@ -1,10 +0,0 @@
module.exports = async ({ github, context, targetSha }) => {
const { content, encoding } = (
await github.rest.repos.getContent({
...context.repo,
path: 'pkgs/top-level/release-supported-systems.json',
ref: targetSha,
})
).data
return JSON.parse(Buffer.from(content, encoding).toString())
}

View File

@@ -28,14 +28,7 @@ runCommand "nix-parse-${nix.name}"
# the other CI jobs will report in more detail. This job is about checking parsing
# across different implementations / versions, not about providing the best DX.
# Returning all parse errors requires significantly more resources.
find . -type f -iname '*.nix' | xargs -P $(nproc) nix-instantiate --parse 2>&1 >/dev/null | {
# Also fail on (deprecation) warnings printed to stderr.
if grep "warning"; then
echo "Failing due to warnings in stderr" >&2
exit 1
fi
}
find . -type f -iname '*.nix' | xargs -P $(nproc) nix-instantiate --parse >/dev/null
touch $out
''

View File

@@ -9,10 +9,23 @@
},
"branch": "nixpkgs-unstable",
"submodules": false,
"revision": "6edbf1a6a03e75886a6609c088801a0856449e88",
"url": "https://github.com/NixOS/nixpkgs/archive/6edbf1a6a03e75886a6609c088801a0856449e88.tar.gz",
"hash": "sha256-0lkauQbtrljJqwtzTCILPAiHAJyMvn6XDo264moDv30="
"revision": "ee09932cedcef15aaf476f9343d1dea2cb77e261",
"url": "https://github.com/NixOS/nixpkgs/archive/ee09932cedcef15aaf476f9343d1dea2cb77e261.tar.gz",
"hash": "1xz5pa6la2fyj5b1cfigmg3nmml11fyf9ah0rnr4zfgmnwimn2gn"
},
"treefmt-nix": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "numtide",
"repo": "treefmt-nix"
},
"branch": "main",
"submodules": false,
"revision": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4",
"url": "https://github.com/numtide/treefmt-nix/archive/5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4.tar.gz",
"hash": "0cr6aj9bk7n3y09lwmfjr7xg1f069332xf4q99z3kj1c1mp0wl82"
}
},
"version": 8
"version": 5
}

View File

@@ -44,7 +44,7 @@ function classify(branch) {
}
}
module.exports = { classify, split }
module.exports = { classify }
// If called directly via CLI, runs the following tests:
if (!module.parent) {

6
ci/supportedSystems.json Normal file
View File

@@ -0,0 +1,6 @@
[
"aarch64-linux",
"aarch64-darwin",
"x86_64-linux",
"x86_64-darwin"
]

View File

@@ -1,175 +0,0 @@
{
lib,
pkgs,
...
}:
{
runtimeInputs = [
# tree-root uses `git rev-parse --show-toplevel`
pkgs.gitMinimal
];
settings = {
# numtide/treefmt-nix defaults
excludes = [
"*.lock"
"*.patch"
"*.diff"
"package-lock.json"
"go.mod"
"go.sum"
".gitattributes"
".gitignore"
".gitmodules"
"COPYING"
"LICENSE"
];
# Be a bit more verbose by default, so we can see progress happening
verbose = 1;
# By default it's info, which is too noisy since we have many unmatched files
on-unmatched = "debug";
formatter = {
# keep-sorted start block=yes newline_separated=yes
actionlint = {
command = lib.getExe pkgs.actionlint;
includes = [
".github/workflows/*.yml"
".github/workflows/*.yaml"
];
};
biome = {
command = lib.getExe pkgs.biome;
excludes = [
"*.min.js"
"pkgs/*"
];
includes = [
"*.js"
"*.ts"
"*.mjs"
"*.mts"
"*.cjs"
"*.cts"
"*.jsx"
"*.tsx"
"*.d.ts"
"*.d.cts"
"*.d.mts"
"*.css"
];
options = [
"check"
"--write"
"--no-errors-on-unmatched"
"--use-editorconfig=true"
"--javascript-formatter-quote-style=single"
"--semicolons=as-needed"
];
};
editorconfig-checker = {
command = lib.getExe pkgs.editorconfig-checker;
options = [
"-disable-indent-size"
# TODO: Remove this once this upstream issue is fixed:
# https://github.com/editorconfig-checker/editorconfig-checker/issues/505
"-disable-charset"
];
includes = [ "*" ];
priority = 1;
};
keep-sorted = {
command = lib.getExe pkgs.keep-sorted;
includes = [ "*" ];
};
markdown-code-runner = {
command = lib.getExe pkgs.markdown-code-runner;
options =
let
config = pkgs.writers.writeTOML "markdown-code-runner-config" {
presets.nixfmt = {
language = "nix";
command = [ (lib.getExe pkgs.nixfmt) ];
};
};
in
[ "--config=${config}" ];
includes = [ "*.md" ];
};
nixf-diagnose = {
command = lib.getExe pkgs.nixf-diagnose;
excludes = [
# Auto-generated; violates sema-extra-with
# Can only sensibly be removed when --auto-fix supports multiple fixes at once:
# https://github.com/inclyc/nixf-diagnose/issues/13
"pkgs/servers/home-assistant/component-packages.nix"
# https://github.com/nix-community/nixd/issues/708
"nixos/maintainers/scripts/azure-new/examples/basic/system.nix"
];
includes = [ "*.nix" ];
options = [
"--auto-fix"
# Rule names can currently be looked up here:
# https://github.com/nix-community/nixd/blob/main/libnixf/src/Basic/diagnostic.py
# TODO: Remove the following and fix things.
"--ignore=sema-unused-def-lambda-noarg-formal"
"--ignore=sema-unused-def-lambda-witharg-arg"
"--ignore=sema-unused-def-lambda-witharg-formal"
"--ignore=sema-unused-def-let"
# TODO: remove after outstanding prelude diagnostics issues are fixed:
# https://github.com/nix-community/nixd/issues/761
# https://github.com/nix-community/nixd/issues/762
"--ignore=sema-primop-removed-prefix"
"--ignore=sema-primop-overridden"
"--ignore=sema-constant-overridden"
"--ignore=sema-primop-unknown"
];
# Ensure nixfmt cleans up after nixf-diagnose.
priority = -1;
};
# This uses nixfmt underneath, the default formatter for Nix code.
# See https://github.com/NixOS/nixfmt
nixfmt = {
command = lib.getExe pkgs.nixfmt;
includes = [ "*.nix" ];
};
yamlfmt = {
command = lib.getExe pkgs.yamlfmt;
excludes = [
# Aligns comments with whitespace
"pkgs/development/haskell-modules/configuration-hackage2nix/main.yaml"
# TODO: Fix formatting for auto-generated file
"pkgs/development/haskell-modules/configuration-hackage2nix/transitive-broken.yaml"
];
includes = [
"*.yaml"
"*.yml"
];
options = [
"-formatter"
"retain_line_breaks=true"
];
};
zizmor = {
command = lib.getExe pkgs.zizmor;
includes = [
".github/workflows/*.yml"
".github/workflows/*.yaml"
".github/actions/**/*.yml"
".github/actions/**/*.yaml"
];
};
# keep-sorted end
};
};
}

View File

@@ -1,9 +1,8 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -E 'with import ../. {}; mkShell { packages = [ npins ]; }'
#!nix-shell -i bash -p npins
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"
npins --lock-file pinned.json upgrade
npins --lock-file pinned.json update

View File

@@ -1,32 +1,21 @@
# Contributing to the Nixpkgs manual
# Contributing to the Nixpkgs reference manual
This directory houses the source files for the Nixpkgs manual.
This directory houses the source files for the Nixpkgs reference manual.
> [!NOTE]
> [!IMPORTANT]
> We are actively restructuring our documentation to follow the [Diátaxis framework](https://diataxis.fr/)
>
> We are actively restructuring our documentation to be more beginner friendly.
> Going forward, this directory should **only** contain [reference documentation](https://nix.dev/contributing/documentation/diataxis#reference).
> For tutorials, guides and explanations, contribute to <https://nix.dev/> instead.
>
> We are actively working to generate **all** reference documentation from the [doc-comments](https://github.com/NixOS/rfcs/blob/master/rfcs/0145-doc-strings.md) present in code.
> This also provides the benefit of using `:doc` in the `nix repl` to view reference documentation locally on the fly.
When writing new docs use **Progressive Disclosure**
For documentation only relevant for contributors, use Markdown files next to the source and regular code comments.
Start simple, pick up beginners.
Use **examples** first to show how to get something done. Keep **Explanation** lean.
Use our [styleguide](./styleguide.md) for more in depth guidance on writing good documentation.
This directory contains **guides** and **reference** documentation for Nixpkgs.
Borrowing from [Diátaxis framework](https://diataxis.fr/) what suits our needs:
**Guides** are task-oriented. They can be tutorial-style walkthroughs or how-to sections.
Explanations appear as prose after examples.
**Reference** documentation is the specification of functions and attributes.
We are actively working to generate **all** reference documentation from the [doc-comments](https://github.com/NixOS/rfcs/blob/master/rfcs/0145-doc-strings.md) present in code.
This also provides the benefit of using `:doc` in the `nix repl` to view reference documentation locally on the fly.
See [Document structure](#document-structure) for a structural template.
> [!TIP]
> Feedback for improving support for parsing and rendering doc-comments is highly appreciated.
> [Open an issue](https://github.com/NixOS/nixpkgs/issues/new?labels=6.topic%3A+documentation&title=Doc%3A+) to request bugfixes or new features.
Rendered documentation:
- [Unstable (from master)](https://nixos.org/manual/nixpkgs/unstable/)
@@ -47,7 +36,7 @@ If the build succeeds, the manual will be in `./result/share/doc/nixpkgs/manual.
### Development environment
To reduce repetition, consider using tools from the provided development environment:
In order to reduce repetition, consider using tools from the provided development environment:
Load it from the Nixpkgs documentation directory with
@@ -65,11 +54,9 @@ Make sure that your local files aren't added to Git history by adding the follow
/**/.direnv
```
#### Live preview
#### `devmode`
Run [`devmode`](../pkgs/by-name/de/devmode/README.md) for a live preview while editing the manual: it rebuilds on every change and reloads the page in your browser automatically.
Changes to the renderer 'pkgs/by-name/ni/nixos-render-docs' need a manual restart. Run: `devmode` again.
Use [`devmode`](../pkgs/by-name/de/devmode/README.md) for a live preview when editing the manual.
### Testing redirects
@@ -124,7 +111,7 @@ This syntax is taken from [MyST](https://myst-parser.readthedocs.io/en/latest/us
#### HTML
Inlining HTML is not allowed.
Parts of the documentation get rendered to various non-HTML formats, such as man pages in the case of NixOS manual.
Parts of the documentation gets rendered to various non-HTML formats, such as man pages in the case of NixOS manual.
#### Roles
@@ -220,105 +207,12 @@ When needed, each convention explains why it exists, so you can make a decision
Note that these conventions are about the **structure** of the manual (and its source files), not about the content that goes in it.
You, as the writer of documentation, are still in charge of its content.
**For prose style, see the [documentation styleguide](./styleguide.md).**
### Document structure
Organize each chapter as guide sections first, then a single `## Reference` section.
A well-structured chapter looks like this:
````markdown
# Foo {#foo}
`foo` builds Foo projects from a `foo.toml`.
## Package a Foo application {#foo-packaging}
:::{.example #ex-foo-packaging}
# Package the hello app
```nix
{ foo }:
buildFooPackage {
pname = "hello";
version = "1.0";
}
```
:::
`buildFooPackage` needs `pname` and `version`.
Keep explanation short, and place it after the example.
## Reference {#foo-reference}
### `buildFooPackage` {#foo-buildFooPackage}
Builds a Foo application from source.
#### Inputs {#foo-buildFooPackage-inputs}
`pname` (String)
: The program name.
#### Examples {#foo-buildFooPackage-examples}
See [](#ex-foo-packaging).
````
Examples live in one place: the guide owns them and the reference links to them.
Guides introduce minimal working examples that are goal-oriented (typical usage).
Reference may introduce additional examples that are unit-oriented. (minimal usage, edge-cases).
If the guide example is already sufficient, just link to it from the reference.
Follow this structure strictly; to deviate, ping @NixOS/documentation-team.
### One sentence per line
Put each sentence in its own line.
This makes reviews and suggestions much easier, since GitHub's review system is based on lines.
It also helps identifying long sentences at a glance.
Not everything has been migrated to this format yet.
Please always use it for new content.
When changing existing content, update formatting if possible, but avoid excessive diffs.
### Examples first
Put examples before detailed explanations (see the [styleguide](./styleguide.md) for the rationale).
Use this structure for each documented item:
1. Title
2. Abstract (optional, one sentence max)
3. Example
4. Explanation (details, edge cases, types, defaults)
Rendered example:
````markdown
## `lib.toUpper`
Converts all characters in a string to uppercase.
:::{.example #ex-lib-toUpper}
# Converting a string to uppercase
```nix
lib.toUpper "hello"
=> "HELLO"
```
:::
Only acts on ASCII characters.
Unicode characters are passed through unchanged.
````
### Writing Function Documentation
Function documentation is *reference documentation*, for which
@@ -351,17 +245,11 @@ Returns the difference as a number.
Use the [admonition syntax](#admonitions) for callouts and examples.
### `callPackage`-compatible examples
### Provide self-contained examples
Provide at least one example per function, in its doc-comment.
Keep each example at the level it documents:
- A **reference example** might sometimes live in a doc-comment and show function call shape.
- A **guide example** lives in a guide section and shows a complete task that may compose several functions.
When the task is nothing more than the call itself, the guide example is enough.
The reference example links to the guide example.
Provide at least one example per function, and make examples self-contained.
This is easier to understand for beginners.
It also helps with testing that it actually works especially once we introduce automation.
Example code should be such that it can be passed to `pkgs.callPackage`.
Instead of something like:
@@ -515,7 +403,7 @@ To define a referenceable figure use the following fencing:
:::
```
Defining figures through the `figure` fencing class adds them to a `List of Figures` after the `Table of Contents`.
Defining figures through the `figure` fencing class adds them to a `List of Figures` after the `Table of Contents`.
Though this is not shown in the rendered documentation on nixos.org.
#### Footnotes

View File

@@ -25,5 +25,6 @@ build-helpers/dev-shell-tools.chapter.md
build-helpers/special.md
build-helpers/images.md
hooks/index.md
languages-frameworks/index.md
packages/index.md
```

View File

@@ -2,9 +2,9 @@
The `nix-shell` command has popularized the concept of transient shell environments for development or testing purposes.
<!--
We should try to document the product, not its development process in the Nixpkgs manual,
We should try to document the product, not its development process in the Nixpkgs reference manual,
but *something* needs to be said to provide context for this library.
This is the most future proof sentence I could come up with while Nix itself does not yet make use of this.
This is the most future proof sentence I could come up with while Nix itself does yet make use of this.
Relevant is the current status of the devShell attribute "project": https://github.com/NixOS/nix/issues/7501
-->
However, `nix-shell` is not the only way to create such environments, and even `nix-shell` itself can indirectly benefit from this library.
@@ -60,7 +60,7 @@ devShellTools.unstructuredDerivationInputEnv {
#}
```
Note that `args` is not included, because Nix does not add it to the builder process environment.
Note that `args` is not included, because Nix does not added it to the builder process environment.
:::

View File

@@ -536,7 +536,7 @@ See [](#chap-pkgs-fetchers-caveats) for more details on how to work with the `ha
Returns a [fixed-output derivation](https://nixos.org/manual/nix/stable/glossary.html#gloss-fixed-output-derivation) which downloads an archive from a given URL and decompresses it.
Despite its name, `fetchzip` is not limited to `.zip` files but can also be used with [various compressed tarball formats](#tar-files) by default.
This can be extended by specifying additional attributes, see [](#ex-fetchers-fetchzip-rar-archive) to understand how to do that.
This can extended by specifying additional attributes, see [](#ex-fetchers-fetchzip-rar-archive) to understand how to do that.
### Inputs {#sec-pkgs-fetchers-fetchzip-inputs}
@@ -765,7 +765,7 @@ Used with Subversion. Expects `url` to a Subversion directory, `rev`, and `hash`
## `fetchgit` {#fetchgit}
Used with Git. Expects `url` to a Git repo, `rev` or `tag`, and `hash`. `rev` in this case can be the full git commit id (SHA1 hash), or use `tag` for a tag name like `refs/tags/v1.0`.
Used with Git. Expects `url` to a Git repo, `rev` or `tag`, and `hash`. `rev` in this case can be full the git commit id (SHA1 hash), or use `tag` for a tag name like `refs/tags/v1.0`.
If you want to fetch a tag you should pass the `tag` parameter instead of `rev` which has the same effect as setting `rev = "refs/tags"/${version}"`.
This is safer than just setting `rev = version` w.r.t. possible branch and tag name conflicts.
@@ -799,7 +799,7 @@ Additionally, the following optional arguments can be given:
*`deepClone`* (Boolean)
: Clone the entire repository as opposed to just creating a shallow clone.
: Clone the entire repository as opposing to just creating a shallow clone.
This implies `leaveDotGit`.
*`fetchTags`* (Boolean)
@@ -855,11 +855,9 @@ Used with Mercurial. Expects `url`, `rev`, `hash`, overridable with [`<pkg>.over
A number of fetcher functions wrap part of `fetchurl` and `fetchzip`. They are mainly convenience functions intended for commonly used destinations of source code in Nixpkgs. These wrapper fetchers are listed below.
## `fetchFromGitea`, `fetchFromForgejo` and `fetchFromCodeberg` {#fetchfromgitea}
## `fetchFromGitea` {#fetchfromgitea}
`fetchFromGitea`, also aliased to `fetchFromForgejo`, expects five arguments. `domain` is the Gitea/Forgejo server name. `owner` is a string corresponding to the user or organization that controls this repository. `repo` corresponds to the name of the software repository. These are located at the top of every Gitea/Forgejo HTML page as `owner`/`repo`. `rev` corresponds to the Git commit hash or tag (e.g `v1.0`) that will be downloaded from Git. Finally, `hash` corresponds to the hash of the extracted directory. Again, other hash algorithms are also available but `hash` is currently preferred.
As <codeberg.org> is currently the most popular public Forgejo server, the `fetchFromCodeberg` fetcher is also available, which pre-fills the `domain` attribute.
`fetchFromGitea` expects five arguments. `domain` is the gitea server name. `owner` is a string corresponding to the Gitea user or organization that controls this repository. `repo` corresponds to the name of the software repository. These are located at the top of every Gitea HTML page as `owner`/`repo`. `rev` corresponds to the Git commit hash or tag (e.g `v1.0`) that will be downloaded from Git. Finally, `hash` corresponds to the hash of the extracted directory. Again, other hash algorithms are also available but `hash` is currently preferred.
## `fetchFromGitHub` {#fetchfromgithub}
@@ -901,6 +899,10 @@ However, `fetchFromBitbucket` will automatically switch to using `fetchgit` and
When `fetchgit` is used, refer to the `fetchgit` section for documentation of its available options.
## `fetchFromSavannah` {#fetchfromsavannah}
This is used with Savannah repositories. The arguments expected are very similar to `fetchFromGitHub` above.
## `fetchFromRepoOrCz` {#fetchfromrepoorcz}
This is used with repo.or.cz repositories. The arguments expected are very similar to `fetchFromGitHub` above.
@@ -920,14 +922,14 @@ respectively. Otherwise, the fetcher uses `fetchzip`.
This is used with Radicle repositories. The arguments expected are similar to `fetchgit`.
Requires a `seed` argument (e.g. `seed.radicle.dev` or `rosa.radicle.network`) and a `repo` argument
Requires a `seed` argument (e.g. `seed.radicle.xyz` or `rosa.radicle.xyz`) and a `repo` argument
(the repository id *without* the `rad:` prefix). Also accepts an optional `node` argument which
contains the id of the node from which to fetch the specified ref. If `node` is `null` (the
default), a canonical ref is fetched instead.
```nix
fetchFromRadicle {
seed = "seed.radicle.dev";
seed = "seed.radicle.xyz";
repo = "z3gqcJUoA1n9HaHKufZs5FCSGazv5"; # heartwood
tag = "releases/1.3.0";
hash = "sha256-4o88BWKGGOjCIQy7anvzbA/kPOO+ZsLMzXJhE61odjw=";
@@ -942,7 +944,7 @@ contains the full revision id of the Radicle patch to fetch.
```nix
fetchRadiclePatch {
seed = "rosa.radicle.network";
seed = "rosa.radicle.xyz";
repo = "z4V1sjrXqjvFdnCUbxPFqd5p4DtH5"; # radicle-explorer
revision = "d97d872386c70607beda2fb3fc2e60449e0f4ce4"; # patch: d77e064
hash = "sha256-ttnNqj0lhlSP6BGzEhhUOejKkkPruM9yMwA5p9Di4bk=";
@@ -1003,27 +1005,3 @@ fetchtorrent {
- `config`: When using `transmission` as the `backend`, a json configuration can
be supplied to transmission. Refer to the [upstream documentation](https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md) for information on how to configure.
## `fetchItchIo` {#fetchitchio}
`fetchItchIo` is a fetcher for downloading game assets from [itch.io](https://itch.io/). It accepts these arguments:
- `gameUrl`: The store page URL of the game.
- `upload`: The numerical ID of the asset to download. To find the upload ID of an asset, check the basename of the request URL when you download the asset using a browser.
- `hash`.
- `name` (optional): The derivation name, often the filename of the asset.
- `extraMessage` (optional): Extra message printed if the API key is not provided or if the account did not purchase the game.
For this fetcher to work, the environment variable `NIX_ITCHIO_API_KEY` must be set for the nix building process (which is nix-daemon in multi-user mode), and it must belong to an account that has bought the game if it is behind a paywall.
To get your API key, go to the ["API key" section](https://itch.io/user/settings/api-keys) of your account settings on itch.io.
```nix
{ fetchItchIo }:
fetchItchIo {
name = "DungeonDuelMonsters-linux-x64.zip";
hash = "sha256-gq2nGwpaStqaVI1pL63xygxOI/z53o+zLwiKizG98Ks=";
gameUrl = "https://mikaygo.itch.io/ddm";
upload = "13371354";
}
```

View File

@@ -1,50 +1,48 @@
# Fixed-point arguments of build helpers {#chap-build-helpers-finalAttrs}
`stdenv.mkDerivation` also accepts a [fixed-point function](#function-library-lib.fixedPoints.fix) instead of a plain attribute set:
As mentioned in the beginning of this part, `stdenv.mkDerivation` could alternatively accept a fixed-point function. The input of this function, typically named `finalAttrs`, is expected to be the final state of the attribute set. A build helper like this is said to accept **fixed-point arguments**.
```nix
{
stdenv,
fetchurl,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "hello";
version = "2.12";
Build helpers don't always support fixed-point arguments yet, as support in [`stdenv.mkDerivation`](#mkderivation-recursive-attributes) was first included in Nixpkgs 22.05.
src = fetchurl {
url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz";
hash = "sha256-...";
};
})
```
## Defining a build helper with `lib.extendMkDerivation` {#sec-build-helper-extendMkDerivation}
The function's input, conventionally named `finalAttrs`, is the final state of the attribute set. Here `src` reads `finalAttrs.version` instead of repeating the version string. A build helper like this is said to accept **fixed-point arguments**.
Developers can use the Nixpkgs library function [`lib.customisation.extendMkDerivation`](#function-library-lib.customisation.extendMkDerivation) to define a build helper supporting fixed-point arguments from an existing one with such support, with an attribute overlay similar to the one taken by [`<pkg>.overrideAttrs`](#sec-pkg-overrideAttrs).
Attributes that reference each other through `finalAttrs` stay correct when changing any of them with [`overrideAttrs`](#sec-pkg-overrideAttrs), because they all access the final values of the fixed-point computation.
`rec` cannot do this: its self-references are fixed when the set is defined and ignore later overrides.
See [recursive-sets](https://nix.dev/manual/nix/stable/language/syntax#recursive-sets) for the underlying mechanism.
## Define a build helper with `lib.extendMkDerivation` {#sec-build-helper-extendMkDerivation}
Use [`lib.customisation.extendMkDerivation`](#function-library-lib.customisation.extendMkDerivation) to define a build helper with fixed-point support from an existing one.
Its argument `extendDrvArgs` takes an attribute overlay similar to [`<pkg>.overrideAttrs`](#sec-pkg-overrideAttrs).
Besides overriding, `lib.extendMkDerivation` also supports `excludeDrvArgNames` to optionally exclude some arguments in the input fixed-point arguments from passing down to the base build helper (specified as `constructDrv`).
Besides overriding, `lib.extendMkDerivation` also supports `excludeDrvArgNames` to optionally exclude some arguments in the input fixed-point arguments from passing down the base build helper (specified as `constructDrv`).
:::{.example #ex-build-helpers-extendMkDerivation}
# Example `mkLocalDerivation` - a build helper over `mkDerivation`
# Example definition of `mkLocalDerivation` extended from `stdenv.mkDerivation` with `lib.extendMkDerivation`
Define a build helper named `mkLocalDerivation` that builds locally without using substitutes by default.
We want to define a build helper named `mkLocalDerivation` that builds locally without using substitutes by default.
Use `lib.extendMkDerivation`:
Instead of taking a plain attribute set,
```nix
{
lib,
stdenv,
}:
preferLocalBuild ? true,
allowSubstitute ? false,
specialArg ? (_: false),
...
}@args:
stdenv.mkDerivation (
removeAttrs [
# Don't pass specialArg into mkDerivation.
"specialArg"
] args
// {
# Arguments to pass
inherit preferLocalBuild allowSubstitute;
# Some expressions involving specialArg
greeting = if specialArg "hi" then "hi" else "hello";
}
)
```
we could define with `lib.extendMkDerivation` an attribute overlay to make the result build helper also accept the attribute set's fixed point passing to the underlying `stdenv.mkDerivation`, named `finalAttrs` here:
```nix
lib.extendMkDerivation {
constructDrv = stdenv.mkDerivation;
excludeDrvArgNames = [
@@ -69,77 +67,4 @@ lib.extendMkDerivation {
```
:::
To apply extra changes to the result derivation, pass `transformDrv` to `lib.extendMkDerivation`:
```nix
lib.customisation.extendMkDerivation { transformDrv = drv: /...; }
```
Construct a wrapper derivation around another derivation using `transformDrv`
The wrapper has access to the original arguments
:::{.example #ex-build-helpers-extendMkDerivation-transformDrv-wrapper}
# Define a custom build helper that downloads and builds
```nix
{
lib,
stdenvNoCC,
cacert,
configure-example,
download-example,
}:
lib.extendMkDerivation {
constructDrv = stdenvNoCC.mkDerivation;
excludeDrvArgNames = [
"bar"
];
extendDrvArgs =
finalAttrs:
{
bar,
foo,
hash ? "",
...
}@args:
{
inherit hash;
nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
cacert
download-example
];
buildPhase = ''
runHook preBuild
download-example --foo="$foo" --out="$out"
runHook postBuild
'';
impureEnvVars = lib.fetchers.proxyImpureEnvVars;
outputHash = if finalAttrs.hash != "" then finalAttrs.hash else lib.fakeHash;
outputHashFormat = "recursive";
passthru = args.passthru or { } // {
inherit bar;
};
};
transformDrv =
unwrapped:
stdenvNoCC.mkDerivation (finalAttrs: {
name = finalAttrs.src.name + "-wrapped";
src = unwrapped;
nativeBuildInputs = [
configure-example
];
inherit (unwrapped) bar;
buildPhase = ''
runHook preBuild
configure-example --bar="$bar"
runHook postBuild
'';
});
}
```
If one needs to apply extra changes to the result derivation, pass the derivation transformation function to `lib.extendMkDerivation` as `lib.customisation.extendMkDerivation { transformDrv = drv: ...; }`.

View File

@@ -73,7 +73,7 @@ Similarly, if you encounter errors similar to `Error_Protocol ("certificate has
A value of `null` means that `buildImage` will use the first image available in the repository.
:::{.note}
This must be used with `fromImageName`. Using only `fromImageTag` without `fromImageName` will make `buildImage` use the first image available in the repository.
This must be used with `fromImageName`. Using only `fromImageTag` without `fromImageName` will make `buildImage` use the first image available in the repository
:::
_Default value:_ `null`.
@@ -1013,7 +1013,7 @@ Because of this, using this function requires the `kvm` device to be available,
A value of `null` means that `exportImage` will use the first image available in the repository.
:::{.note}
This must be used with `fromImageName`. Using only `fromImageTag` without `fromImageName` will make `exportImage` use the first image available in the repository.
This must be used with `fromImageName`. Using only `fromImageTag` without `fromImageName` will make `exportImage` use the first image available in the repository
:::
_Default value:_ `null`.
@@ -1145,7 +1145,7 @@ $ file /nix/store/by3f40xvc4l6bkis74l0fj4zsy0djgkn-hello.tar.gz
/nix/store/by3f40xvc4l6bkis74l0fj4zsy0djgkn-hello.tar.gz: POSIX tar archive (GNU)
```
If the archive was actually compressed, the output of `file` would've mentioned that fact.
If the archive was actually compressed, the output of file would've mentioned that fact.
Because of this, it may be important to set a proper `name` attribute when using `exportImage` with other functions from `dockerTools`.
:::
@@ -1194,7 +1194,7 @@ This is currently implemented by linking to the `env` binary from the `coreutils
### binSh {#sssec-pkgs-dockerTools-helpers-binSh}
This provides a `/bin/sh` link to the `bash` binary from the `bash` package.
This provides a `/bin/sh` link to the `bash` binary from the `bashInteractive` package.
Because of this, it supports cases such as running a command interactively in a container (for example by running `docker container run -it <image_name>`).
### caCertificates {#sssec-pkgs-dockerTools-helpers-caCertificates}
@@ -1498,7 +1498,7 @@ The environment in the image doesn't match `nix-shell` or `nix-build` exactly, a
This shell is started when running the image.
This can be seen as an equivalent of the `NIX_BUILD_SHELL` [environment variable](https://nixos.org/manual/nix/stable/command-ref/nix-shell.html#environment-variables) for {manpage}`nix-shell(1)`.
_Default value:_ the `bash` binary from the `bash` package.
_Default value:_ the `bash` binary from the `bashInteractive` package.
`command` (String or Null; _optional_)

View File

@@ -8,7 +8,7 @@ This function can create images in two ways:
- using a virtual machine to create a full NixOS installation.
When testing early-boot or lifecycle parts of NixOS such as a bootloader or multiple generations, it is necessary to opt for a full NixOS system installation.
Whereas for many web servers and applications, it is possible to work with a Nix store only disk image, which is faster to build.
Whereas for many web servers, applications, it is possible to work with a Nix store only disk image and is faster to build.
NixOS tests also use this function when preparing the VM. The `cptofs` method is used when `virtualisation.useBootLoader` is false (the default). Otherwise the second method is used.
@@ -39,7 +39,7 @@ Features are separated in various sections depending on if you opt for a Nix-sto
### On bit-to-bit reproducibility {#sec-make-disk-image-features-reproducibility}
Images are **NOT** deterministic. Please do not hesitate to try to fix this. Sources of non-determinism are (not exhaustive):
Images are **NOT** deterministic, please do not hesitate to try to fix this, source of determinisms are (not exhaustive) :
- bootloader installation has timestamps
- SQLite Nix store database contains registration times

View File

@@ -5,8 +5,8 @@ It makes no assumptions about the container runner you choose to use to run the
The set of functions in `pkgs.ociTools` currently does not handle the [OCI image specification](https://github.com/opencontainers/image-spec).
At a high level, an OCI implementation would download an OCI Image then unpack that image into an OCI Runtime filesystem bundle.
At this point, the OCI Runtime Bundle would be run by an OCI Runtime.
At a high-level an OCI implementation would download an OCI Image then unpack that image into an OCI Runtime filesystem bundle.
At this point the OCI Runtime Bundle would be run by an OCI Runtime.
`pkgs.ociTools` provides utilities to create OCI Runtime bundles.
## buildContainer {#ssec-pkgs-ociTools-buildContainer}
@@ -54,7 +54,7 @@ Note that no user namespace is created, which means that you won't be able to ru
`os` **DEPRECATED**
: Specifies the operating system on which the container filesystem is based.
: Specifies the operating system on which the container filesystem is based on.
If specified, its value should follow the [OCI Image Configuration Specification](https://github.com/opencontainers/image-spec/blob/main/config.md#properties).
According to the linked specification, all possible values for `$GOOS` in [the Go docs](https://go.dev/doc/install/source#environment) should be valid, but will commonly be one of `darwin` or `linux`.

View File

@@ -3,7 +3,6 @@
This chapter describes several special build helpers.
```{=include=} sections
special/buildenv.section.md
special/fakenss.section.md
special/fhs-environments.section.md
special/makesetuphook.section.md

View File

@@ -1,101 +0,0 @@
# buildEnv {#sec-buildEnv}
`buildEnv` constructs a derivation containing directories and symbolic links, which resembles the profile layout where a list of derivations or store paths are installed.
Unlike [`symlinkJoin`](#trivial-builder-symlinkJoin), `buildEnv` takes special care of the outputs to link and checks for content collisions across the paths by default.
A common use case for `buildEnv` is constructing environment wrappers, such as an interpreter with modules or a program with extensions.
For example, [`python.withPackage`](#attributes-on-interpreters-packages) is based on `buildEnv`.
## Arguments {#sec-buildEnv-arguments}
`buildEnv` takes [fixed-point arguments (`buildEnv (finalAttrs: { })`)](#chap-build-helpers-finalAttrs) as well as a plain attribute set.
Unless otherwise noted, arguments can be overridden directly using [`<pkg>.overrideAttrs`](#sec-pkg-overrideAttrs).
`buildEnv` enforces [structured attributes (`{ __structuredAttrs = true; }`)](https://nix.dev/manual/nix/2.18/language/advanced-attributes.html#adv-attr-structuredAttrs).
- `name` or `pname` and `version` (required):
The name of the environment.
- `paths` (required):
The derivations or store paths to symlink ("install").
The elements can be any path-like object that string-interpolates to a store path.
The priority of each path is taken from `<path>.meta.priority` and falls back to `lib.meta.defaultPriority` if not set.
The argument `paths` is passed as attribute `passthru.paths` to prevent unexpected context pollution.
`passthru.paths` can be overridden with `<pkg>.overrideAttrs`.
- `extraOutputsToInstall` (default to `[ ]`):
Package outputs to include in addition to what `meta.outputsToInstall` specifies.
- `includeClosures` (default to `false`):
Whether to include closures of all input paths.
The list of the closure paths are constructed with `writeClosure`.
They are installed with lower priority and with build-time exceptions silenced.
- `extraPrefix` (default to `""`):
Root the result in directory `"$out${extraPrefix}"`, e.g. `"/share"`.
- `ignoreCollisions` (default: `false`):
Don't fail the build upon content collisions.
- `checkCollisionContents` (default: `true`):
If there is a collision, check whether the contents and permissions match; and only if not, throw a collision error.
- `ignoreSingleFileOutputs` (default: `false`):
Don't fail the build upon single-file outputs.
- `manifest` (default: `""`):
The manifest file (if any). A symlink `$out/manifest` will be created to it.
- `pathsToLink` (default: `[ "/" ]`):
The paths (relative to each element of `paths`) that we want to symlink (e.g., `["/bin"]`).
Any file outside the directories in this list won't be symlinked into the produced environment.
- `postBuild` (default: `""`):
Shell commands to run after building the symlink tree.
- `passthru` and `meta` (default: `{ }`):
`stdenv.mkDerivation`-supported attributes not passing down to `builtins.derivation`.
- `derivationArgs` (default: `{ }`):
Additional `stdenv.mkDerivation` arguments, such as `nativeBuildInputs`/`buildInputs` for `postBuild` dependencies and setup hooks.
`derivationArgs` is not passed down to `stdenv.mkDerivation`.
Override its attributes directly via `<pkg>.overrideAttrs` and reference directly via `finalAttrs`.
## Build-time exceptions {#sec-buildEnv-exceptions}
There are situations where the specified `paths` might not produce sensible profile layout.
By default, the builder fails early upon detecting these exceptions.
`buildEnv` provides arguments to fine-tune or ignore certain exceptions.
### Path collisions {#ssec-buildEnv-collisions}
Path collisions occur when files provided by two more output paths with the same priority overlap with each other, making the result profile layout potentially affected by the order of elements of `paths`.
This is undesirable in several use cases, such as when `paths` are determined by merging Nix modules.
If the argument `checkCollisionContents` is `true`, the builder checks whether the overlapping paths share the same content and mode, and fails only if not.
The argument `ignoreCollisions` silence the collision checks and allow the files to be overwritten based on the order of chosen output paths.
In addition to silencing this exception with `ignoreCollisions`, one can also adjust the priority of colliding packages and store paths.
Store paths can specify priority in the form
```nix
{
outPath = <path>;
meta.priority = <priority>;
}
```
And [`lib.meta.setPrio`](#function-library-lib.meta.setPrio)-related Nixpkgs Library functions also apply to a string-like attribute set (`{ outPath = <path>; }`).
### Single-file outputs {#ssec-buildEnv-singleFileOutputs}
When an output path provides a single file instead of a directory, it inherently cannot merge into the result layout.
All discoverable packages should configure their `meta.outputsToInstall` correctly, so that single-file outputs won't be installed into a profile.
Set `ignoreSingleFileOutputs` to `true` to drop all single-file output paths silently.
This option is useful when the specified paths contain the output paths of package tests.

View File

@@ -6,7 +6,7 @@ For hermeticity, Nix derivations do not allow any state to be carried over betwe
However, we can tell Nix explicitly what the previous build state was, by representing that previous state as a derivation output. This allows the passed build state to be used for an incremental build.
To change a normal derivation to a checkpoint-based build, these steps must be taken:
To change a normal derivation to a checkpoint based build, these steps must be taken:
```nix
{
checkpointArtifacts = (pkgs.checkpointBuildTools.prepareCheckpointBuild pkgs.virtualbox);

View File

@@ -14,11 +14,11 @@ Accepted arguments are:
- `executableName`
The name of the wrapper executable. Defaults to `pname` if set, or `name` otherwise.
- `targetPkgs`
Packages to be installed for the main host's architecture (i.e. x86_64 on x86_64 installations). Along with libraries, binaries are also installed.
Packages to be installed for the main host's architecture (i.e. x86_64 on x86_64 installations). Along with libraries binaries are also installed.
- `multiPkgs`
Packages to be installed for all architectures supported by a host (i.e. i686 and x86_64 on x86_64 installations). Only libraries are installed by default.
- `multiArch`
Whether to install 32-bit multiPkgs into the FHSEnv in 64-bit environments
Whether to install 32bit multiPkgs into the FHSEnv in 64bit environments
- `extraBuildCommands`
Additional commands to be executed for finalizing the directory structure.
- `extraBuildCommandsMulti`
@@ -47,9 +47,11 @@ You can create a simple environment using a `shell.nix` like this:
(with pkgs; [
udev
alsa-lib
libx11
libxcursor
libxrandr
])
++ (with pkgs.xorg; [
libX11
libXcursor
libXrandr
]);
multiPkgs =
pkgs:

View File

@@ -1,6 +1,6 @@
# pkgs.makeSetupHook {#sec-pkgs.makeSetupHook}
`pkgs.makeSetupHook` is a build helper that produces hooks that go into `nativeBuildInputs`
`pkgs.makeSetupHook` is a build helper that produces hooks that go in to `nativeBuildInputs`
## Usage {#sec-pkgs.makeSetupHook-usage}

View File

@@ -92,14 +92,14 @@ Generate a script that can be used to run an interactive session in the given im
### Examples {#vm-tools-makeImageTestScript-examples}
Create a script for running a Fedora 43 VM:
Create a script for running a Fedora 27 VM:
```nix
{ pkgs }: pkgs.vmTools.makeImageTestScript pkgs.vmTools.diskImages.fedora43x86_64
{ pkgs }: with pkgs; with vmTools; makeImageTestScript diskImages.fedora27x86_64
```
Create a script for running an Ubuntu 24.04 VM:
Create a script for running an Ubuntu 20.04 VM:
```nix
{ pkgs }: pkgs.vmTools.makeImageTestScript pkgs.vmTools.diskImages.ubuntu2404x86_64
{ pkgs }: with pkgs; with vmTools; makeImageTestScript diskImages.ubuntu2004x86_64
```
## `vmTools.diskImageFuns` {#vm-tools-diskImageFuns}
@@ -109,41 +109,44 @@ A set of functions that build a predefined set of minimal Linux distributions im
### Images {#vm-tools-diskImageFuns-images}
* Fedora
* `fedora42x86_64`
* `fedora43x86_64`
* Rocky Linux
* `rocky9x86_64`
* `rocky10x86_64`
* AlmaLinux
* `alma9x86_64`
* `alma10x86_64`
* Oracle Linux
* `oracle9x86_64`
* Amazon Linux
* `amazon2023x86_64`
* `fedora26x86_64`
* `fedora27x86_64`
* CentOS
* `centos6i386`
* `centos6x86_64`
* `centos7x86_64`
* Ubuntu
* `ubuntu1404i386`
* `ubuntu1404x86_64`
* `ubuntu1604i386`
* `ubuntu1604x86_64`
* `ubuntu1804i386`
* `ubuntu1804x86_64`
* `ubuntu2004i386`
* `ubuntu2004x86_64`
* `ubuntu2204i386`
* `ubuntu2204x86_64`
* `ubuntu2404x86_64`
* Debian
* `debian10i386`
* `debian10x86_64`
* `debian11i386`
* `debian11x86_64`
* `debian12i386`
* `debian12x86_64`
* `debian13i386`
* `debian13x86_64`
### Attributes {#vm-tools-diskImageFuns-attributes}
* `size` (optional, defaults to `4096`). The size of the image, in MiB.
* `extraPackages` (optional). A list of names of additional packages from the distribution that should be included in the image.
* `extraPackages` (optional). A list names of additional packages from the distribution that should be included in the image.
### Examples {#vm-tools-diskImageFuns-examples}
8GiB image containing Firefox in addition to the default packages:
```nix
{ pkgs }:
pkgs.vmTools.diskImageFuns.ubuntu2404x86_64 {
with pkgs;
with vmTools;
diskImageFuns.ubuntu2004x86_64 {
extraPackages = [ "firefox" ];
size = 8192;
}

View File

@@ -63,7 +63,7 @@ Note the moduleNames used in cmake find_package are case sensitive.
Check a packaged static site's links with the [`lychee` package](https://search.nixos.org/packages?show=lychee&type=packages&query=lychee).
You may use Nix to reproducibly build static websites, such as for software documentation.
Some packages will install documentation in their `out` or `doc` outputs, or maybe you have a dedicated package where you've made your static site reproducible by running a generator, such as [Hugo](https://gohugo.io/) or [mdBook](https://rust-lang.github.io/mdBook/), in a derivation.
Some packages will install documentation in their `out` or `doc` outputs, or maybe you have dedicated package where you've made your static site reproducible by running a generator, such as [Hugo](https://gohugo.io/) or [mdBook](https://rust-lang.github.io/mdBook/), in a derivation.
If you have a static site that can be built with Nix, you can use `lycheeLinkCheck` to check that the hyperlinks in your site are correct, and do so as part of your Nix workflow and CI.
@@ -98,14 +98,6 @@ It has two modes:
: The path to the files to check.
`relocatable` (boolean, optional) {#tester-lycheeLinkCheck-param-relocatable}
: Whether the site is expected to be relocatable, i.e. servable from any URL path prefix.
When `true` (the default), root-relative links (starting with `/`) are treated as errors, because they break when the site is served from a subpath or opened via `file://` URLs.
When `false`, root-relative links are resolved against the `site` directory.
`remap` (attribute set, optional) {#tester-lycheeLinkCheck-param-remap}
: An attribute set where the attribute names are regular expressions.
@@ -137,13 +129,6 @@ It has two modes:
Example: `{ "include_verbatim" = true; }`
`extraArgs` (list of strings, optional) {#tester-lycheeLinkCheck-param-extraArgs}
: Extra command line arguments to pass to the `lychee` invocation.
These are passed in both the offline (build) and [`online`](#tester-lycheeLinkCheck-return) modes.
Example: `[ "--format" "json" ]`
`lychee` (derivation, optional) {#tester-lycheeLinkCheck-param-lychee}
: The `lychee` package to use.
@@ -593,7 +578,7 @@ Use the derivation hash to invalidate the output via name, for testing.
Type: `(a@{ name, ... } -> Derivation) -> a -> Derivation`
Normally, fixed output derivations can and should be cached by their output hash only, but for testing we want to re-fetch every time the fetcher changes.
Normally, fixed output derivations can and should be cached by their output hash only, but for testing we want to re-fetch everytime the fetcher changes.
Changes to the fetcher become apparent in the drvPath, which is a hash of how to fetch, rather than a fixed store path.
By inserting this hash into the name, we can make sure to re-run the fetcher every time the fetcher changes.
@@ -737,102 +722,4 @@ Notable attributes:
* `driverInteractive`: a script that launches an interactive Python session in the context of the `testScript`.
## `modularServiceCompliance` {#tester-modularServiceCompliance}
Compliance suite for [modular service](https://nixos.org/manual/nixos/unstable/#modular-services) integrations.
Tests that a service manager integration correctly handles the portable modular services contract: `process.argv`, sub-services, assertions, and warnings.
### Return value {#tester-modularServiceCompliance-return}
An attribute set of derivations which perform the tests during their build.
### Inputs {#tester-modularServiceCompliance-inputs}
`evalConfig` (function)
: `{ services } -> { config; checkDrv; }`.
Function to evaluate the given services in the integration's full context.
This function is called for evaluation checks on configurations that will not be run.
- Input `services` is an attrset of modular service configurations. These should be used verbatim.
- Output attribute `config` is the resulting evaluated services attrset (e.g., the value of the `system.services` option in NixOS).
This attribute must be available even if `checkDrv` would fail.
- Output attribute `checkDrv` is a representative derivation whose existence and buildability prove the eval is sound (e.g., `system.build.toplevel` in NixOS, but could perhaps be more specific in the case of another process manager integration).
`mkTest` (function)
: `{ name, services, testExe } -> derivation`.
- Input `name` is a test name, suitable for use as a derivation name.
- Input `services` is an attrset of modular service configurations, matching the structure of the integration's services option.
- Input `testExe` is a store path to an executable that verifies the services.
- Output: a derivation that runs the service manager with the provided configuration inputs and then calls `testExe` after starting the services. That executable must have access to `sharedDir`.
`sharedDir` (string)
: Path to a directory writable by service processes and readable by `testExe`.
The integration must ensure this directory is available when the services and `testExe` run.
:::{.example #ex-modularServiceCompliance-nixos}
# NixOS invocation of the compliance suite
```nix
# In nixos/tests/all-tests.nix:
# modularServiceCompliance =
recurseIntoAttrs (
pkgs.testers.modularServiceCompliance {
sharedDir = "/tmp/modular-service-compliance";
evalConfig =
{ services }:
let
machine = evalSystem (
{ ... }:
{
system.services = services;
system.stateVersion = "25.05";
fileSystems."/" = {
device = "/test/dummy";
fsType = "auto";
};
boot.loader.grub.enable = false;
}
);
in
{
config = machine.config.system.services;
checkDrv = machine.config.system.build.toplevel;
};
mkTest =
{
name,
services,
testExe,
}:
runTest {
_class = "nixosTest";
inherit name;
nodes.machine.system.services = services;
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.succeed("${testExe}")
'';
};
}
)
```
:::
### Manual compliance items {#tester-modularServiceCompliance-manual}
The following compliance items are not yet automated and must be verified manually when implementing a new modular service integration.
- **Failing assertions prevent deployment.**
A service with `assertions = [{ assertion = false; message = "..."; }]` must cause the deployment to fail.
The mechanism is integration-specific (e.g., NixOS checks assertions during `system.build.toplevel` evaluation).
- **Warnings are visible to the user.**
A service with `warnings = [ "..." ]` must surface the warning to the user.
On NixOS these are `builtins.warn` messages emitted during evaluation.
[file system object]: https://nix.dev/manual/nix/latest/store/file-system-object

View File

@@ -8,7 +8,7 @@ Like [`stdenv.mkDerivation`](#sec-using-stdenv), each of these build helpers cre
The function `runCommandWith` returns a derivation built using the specified command(s), in a specified environment.
It is the underlying base function of all [`runCommand*` variants].
It is the underlying base function of all [`runCommand*` variants].
The general behavior is controlled via a single attribute set passed
as the first argument, and allows specifying `stdenv` freely.
@@ -45,7 +45,7 @@ runCommandWith :: {
:::
`stdenv` (Derivation)
: The [standard environment](#chap-stdenv) to use, defaulting to `pkgs.stdenv`.
: The [standard environment](#chap-stdenv) to use, defaulting to `pkgs.stdenv`
`derivationArgs` (Attribute set)
: Additional arguments for [`mkDerivation`](#sec-using-stdenv).
@@ -160,7 +160,7 @@ runCommandWith { inherit name derivationArgs; } buildCommand
## Writing text files {#trivial-builder-text-writing}
Nixpkgs provides the following functions for producing derivations which write text files or executable scripts into the Nix store.
They are useful for creating files from Nix expressions, and are all implemented as convenience wrappers around `writeTextFile`.
They are useful for creating files from Nix expression, and are all implemented as convenience wrappers around `writeTextFile`.
Each of these functions will cause a derivation to be produced.
When you coerce the result of each of these functions to a string with [string interpolation](https://nixos.org/manual/nix/stable/language/string-interpolation) or [`toString`](https://nixos.org/manual/nix/stable/language/builtins#builtins-toString), it will evaluate to the [store path](https://nixos.org/manual/nix/stable/store/store-path) of this derivation.
@@ -682,7 +682,7 @@ writeTextFile {
## `concatTextFile`, `concatText`, `concatScript` {#trivial-builder-concatText}
These functions concatenate `files` to the Nix store in a single file. This is useful for configuration files structured in lines of text. `concatTextFile` takes an attribute set and expects two arguments, `name` and `files`. `name` corresponds to the name used in the Nix store path. `files` will be the files to be concatenated. You can also set `executable` to true to make this file have the executable bit set.
`concatText` and `concatScript` are simple wrappers over `concatTextFile`.
`concatText` and`concatScript` are simple wrappers over `concatTextFile`.
Here are a few examples:
```nix
@@ -734,80 +734,7 @@ Some basic Bash options are set by default (`errexit`, `nounset`, and `pipefail`
Extra arguments may be passed to `stdenv.mkDerivation` by setting `derivationArgs`; note that variables set in this manner will be set when the shell script is _built,_ not when it's run.
Runtime environment variables can be set with the `runtimeEnv` argument.
`writeShellApplication` has the following arguments:
`name` (String)
: The name of the script to write.
`text` (String)
: The shell script's text, not including a shebang.
`runtimeInputs` (List of derivations or strings, _optional_)
: Inputs to add to the shell script's `$PATH` at runtime.
Each elements can either be a normal derivation, or a string containing a path, in which case it will be suffixed with `/bin` to create a `PATH` expression (see [`lib.strings.makeBinPath`](#function-library-lib.strings.makeBinPath) for more information).
`runtimeEnv` (Attribute set, _optional_)
: Extra environment variables to set at runtime.
`checkPhase` (String, _optional_)
: The `checkPhase` to run.
The script path will be given as `$target` in the `checkPhase`
_Default behavior:_ run [`shellcheck`](https://github.com/koalaman/shellcheck) (on supported platforms) and `bash -n` (check syntax but don't execute commands).
`excludeShellChecks` (List of strings, _optional_)
: Checks to exclude when running `shellcheck`.
For example, `excludeShellChecks = [ "SC2016" ]` would prevent `shellcheck` from reporting `SC2016`, but would still detect any other problems.
See [the `shellcheck` wiki](https://www.shellcheck.net/wiki/) for a list of checks.
`extraShellCheckFlags` (List of strings, _optional_)
: Extra command-line flags to pass to `shellcheck`.
`bashOptions` (List of strings, _optional_)
: Bash options to activate with `set -o` at the start of the script
_Default:_ `[ "errexit" "nounset" "pipefail" ]`, which means:
1. A failing command inside of a command list or pipeline will make the script exit, except if used as a conditional (inside a `while`, `if`, `&&`, `||`, etc.);
2. Any attempt to expand an undefined variable will make the script exit.
`inheritPath` (Bool, _optional_)
: Whether the script will inherit the PATH from its parent environment.
_Default:_ `true`
`meta` (Attribute set, _optional_)
: `stdenv.mkDerivation`'s [`meta`](#chap-meta) argument
`passthru` (Attribute set, _optional_)
: `stdenv.mkDerivation`'s [`passthru`](#chap-passthru) argument
`derivationArgs` (Attribute set, _optional_)
: Extra arguments to pass to [`stdenv.mkDerivation`](#chap-stdenv)
::: {.caution}
Certain derivation attributes are also set internally, so overriding those could cause problems.
:::
::: {.example #ex-writeShellApplication}
# Usage of `writeShellApplication`
The following shell application can refer to `curl` directly, rather than needing to write `${curl}/bin/curl`
For example, the following shell application can refer to `curl` directly, rather than needing to write `${curl}/bin/curl`:
```nix
writeShellApplication {
@@ -823,7 +750,6 @@ writeShellApplication {
'';
}
```
:::
## `symlinkJoin` {#trivial-builder-symlinkJoin}

View File

@@ -1,3 +1,11 @@
# Contributing to Nixpkgs documentation {#chap-contributing}
This section has been moved to [doc/README.md](https://github.com/NixOS/nixpkgs/blob/master/doc/README.md).
## devmode {#sec-contributing-devmode}
This section has been moved to [doc/README.md](https://github.com/NixOS/nixpkgs/blob/master/doc/README.md).
## Syntax {#sec-contributing-markup}
This section has been moved to [doc/README.md](https://github.com/NixOS/nixpkgs/blob/master/doc/README.md).

View File

@@ -1,5 +1,5 @@
{
pkgs ? (import ../ci { }).docPkgs,
pkgs ? (import ../ci { }).pkgs,
nixpkgs ? { },
}:

View File

@@ -2,6 +2,6 @@
* Make sure you have a [GitHub account](https://github.com/signup/free)
* Make sure there is no open issue on the topic
* [Submit a new issue](https://github.com/NixOS/nixpkgs/issues/new/choose) by choosing the kind of topic and filling out the template
* [Submit a new issue](https://github.com/NixOS/nixpkgs/issues/new/choose) by choosing the kind of topic and fill out the template
<!-- In the future this section could also include more detailed information on the issue templates -->

View File

@@ -37,16 +37,16 @@ runCommand "manual.epub"
</book>
'';
__structuredAttrs = true;
passAsFile = [ "epub" ];
}
''
mkdir scratch
printf "%s" "$epub" | xsltproc \
xsltproc \
--param chapter.autolabel 0 \
--nonet \
--output scratch/ \
${docbook_xsl_ns}/xml/xsl/docbook/epub/docbook.xsl \
-
$epubPath
echo "application/epub+zip" > mimetype
zip -0Xq -b "$TMPDIR" "$out" mimetype

View File

@@ -1,7 +0,0 @@
<div class="manual-header">
<nav class="manual-header--tabs">
<a class="manual-header--tab manual-header--tab-active" href="#">Nixpkgs</a>
<a class="manual-header--tab" href="https://nixos.org/manual/nixos/stable/">NixOS</a>
</nav>
<span class="manual-header--title">Nixpkgs Manual</span>
</div>

View File

@@ -54,8 +54,7 @@ stdenvNoCC.mkDerivation (
};
in
{
version = lib.trivial.release;
pname = "nixpkgs-manual";
name = "nixpkgs-manual";
nativeBuildInputs = [ nixos-render-docs ];
@@ -73,7 +72,6 @@ stdenvNoCC.mkDerivation (
../anchor.min.js
../manpage-urls.json
../redirects.json
../nav.json
]
);
};
@@ -117,10 +115,8 @@ stdenvNoCC.mkDerivation (
--script ./highlightjs/loader.js \
--script ./anchor.min.js \
--script ./anchor-use.js \
--sidebar-depth 3 \
--nav ./nav.json \
--header ${./header.html}\
--no-navheader \
--toc-depth 1 \
--section-toc-depth 1 \
manual.md \
out/index.html
@@ -161,7 +157,7 @@ stdenvNoCC.mkDerivation (
buildArgs = toString ../.;
open = "/share/doc/nixpkgs/index.html";
};
nixos-render-docs-redirects' = writeShellScriptBin "redirects" ''${lib.getExe nixos-render-docs-redirects} --file '${toString ../redirects.json}' "$@"'';
nixos-render-docs-redirects' = writeShellScriptBin "redirects" "${lib.getExe nixos-render-docs-redirects} --file ${toString ../redirects.json} $@";
in
mkShellNoCC {
packages = [
@@ -172,7 +168,6 @@ stdenvNoCC.mkDerivation (
};
tests = {
# Don't run this in CI because it's not reproducible
manpage-urls = callPackage ../tests/manpage-urls.nix { };
};
};

View File

@@ -1,84 +0,0 @@
# Package your first application {#chap-first-package}
Package an application with Nixpkgs by picking the build helper for its language and setting a few attributes.
Each language ecosystem has its own build helper.
See [](#chap-language-support) for the full set.
## Package a Go application {#first-package-go}
`buildGoModule` builds Go programs that use Go modules.
Write the package to `package.nix`:
:::{.example #ex-first-package-go}
# Package `pet` with `buildGoModule`
```nix
# package.nix
{
buildGoModule,
fetchFromGitHub,
lib,
}:
buildGoModule (finalAttrs: {
pname = "pet";
version = "0.3.4";
src = fetchFromGitHub {
owner = "knqyf263";
repo = "pet";
tag = "v${finalAttrs.version}";
hash = "sha256-Gjw1dRrgM8D3G7v6WIM2+50r4HmTXvx0Xxme2fH9TlQ=";
};
vendorHash = "sha256-6hCgv2/8UIRHw1kCe3nLkxF23zE/7t5RDwEjSzX3pBQ=";
meta = {
description = "Simple command-line snippet manager, written in Go";
homepage = "https://github.com/knqyf263/pet";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ kalbasit ];
};
})
```
:::
`buildGoModule` needs `pname`, `version`, `src`, and `vendorHash`.
Pin Nixpkgs and call the package from `default.nix`:
```nix
# default.nix
let
nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz";
pkgs = import nixpkgs { };
in
pkgs.callPackage ./package.nix { }
```
Build it:
```shell
$ nix-build ./default.nix
# or equivalent
$ nix-build
```
Run it:
```shell
$ ./result/bin/pet --help
pet - Simple command-line snippet manager.
```
`vendorHash` pins the fetched dependencies.
To find its value:
1. Set `vendorHash` to an empty string `""`.
2. Run `nix-build`.
3. Copy the correct value from the error into `vendorHash`.
See the [Go reference](#sec-language-go) for every attribute and advanced usage.

View File

@@ -1,24 +0,0 @@
# checkPhaseThreadLimitHook {#setup-hook-check-phase-thread-limit}
This hook defaults a variety of environment variables known
to control thread counts to 1. Many of these otherwise default
to `$(nproc)`, which causes massive overloads on build machines
if nix build jobs and build cores are already tuned to fully utilize
compute capacity of a builder without additional parallelism.
Currently sets the following environment variables:
- [`OMP_NUM_THREADS`](https://www.openmp.org/spec-html/5.0/openmpse50.html)
- [`OPENBLAS_NUM_THREADS`](https://github.com/OpenMathLib/OpenBLAS/blob/e7b45174355edec1f04de1cabcf5ca6a98ea7fbc/USAGE.md#how-can-i-use-openblas-in-multi-threaded-applications)
- [`MKL_NUM_THREADS`](https://www.intel.com/content/www/us/en/docs/onemkl/developer-guide-linux/2023-0/mkl-domain-num-threads.html)
- [`BLIS_NUM_THREADS`](https://github.com/flame/blis/blob/b8b75b4e19459f5d618b57aa814ca38b1d82eb82/docs/Multithreading.md#specifying-multithreading)
- `VECLIB_MAXIMUM_THREADS`: Only affects darwin, see [`man 7 Accelerate`](https://manp.gs/mac/7/Accelerate)
- [`NUMBA_NUM_THREADS`](https://numba.readthedocs.io/en/stable/reference/envvars.html#threading-control)
- [`NUMEXPR_NUM_THREADS`](https://numexpr.readthedocs.io/en/latest/user_guide.html#threadpool-configuration)
The `NIX_CHECK_PHASE_DEFAULT_NUM_THREADS` environment variable
can be used to override the default thread count limit.
`dontLimitCheckPhaseThreads = true;` can be used to disable
thread limiting on an individual package.
This hook will not attempt to override already existing
definitions for thread count environment variables.

View File

@@ -13,7 +13,6 @@ aws-c-common.section.md
bmake.section.md
breakpoint.section.md
cernlib.section.md
check-phase-thread-limit-hook.section.md
cmake.section.md
desktop-file-utils.section.md
gdk-pixbuf.section.md
@@ -21,24 +20,16 @@ ghc.section.md
gnome.section.md
haredo.section.md
installShellFiles.section.md
installFonts.section.md
julec.section.md
just.section.md
libglycin.section.md
libiconv.section.md
libxml2.section.md
meson.section.md
mpi-check-hook.section.md
ninja.section.md
nodejs-install-executables.section.md
nodejs-install-manuals.section.md
npm-build-hook.section.md
npm-config-hook.section.md
npm-install-hook.section.md
patch-rc-path-hooks.section.md
perl.section.md
pkg-config.section.md
pnpm.section.md
postgresql-test-hook.section.md
premake.section.md
python.section.md
@@ -50,7 +41,6 @@ unzip.section.md
validatePkgConfig.section.md
versionCheckHook.section.md
waf.section.md
writable-tmpdir-as-home-hook.section.md
zig.section.md
xcbuild.section.md
xfce4-dev-tools.section.md

View File

@@ -1,24 +0,0 @@
# `installFonts` {#installfonts}
This hook installs common font formats to the proper location. In its default state, the hook automatically handles ttf, ttc, otf, bdf, and psf. Given a `webfont` output, woff and woff2 formats will be installed under this output.
The automatic behavior of the hook can be disabled by setting the `dontInstallFonts` variable to true.
Additionally, it exposes the `installFont` function that can be used from your `postInstall`
hook, to install additional formats:
## `installFont` {#installfonts-installfont}
The `installFont` function takes two arguments, a file extension to move (*without* a preceding dot), and the install location.
### Example Usage {#installfonts-installfont-exampleusage}
```nix
{
nativeBuildInputs = [ installFonts ];
postInstall = ''
installFont svg $out/share/fonts/svg
'';
}
```

Some files were not shown because too many files have changed in this diff Show More