mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-08-25 17:55:21 +00:00
Compare commits
1 Commits
release-26
...
revert-497
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ebd17b0f7 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"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
|
||||
|
||||
@@ -23,15 +23,15 @@ insert_final_newline = false
|
||||
|
||||
# see https://nixos.org/nixpkgs/manual/#chap-conventions
|
||||
|
||||
[*.{bash,css,js,json,lock,md,nix,pl,pm,py,rb,sh,ts,xml}]
|
||||
[*.{bash,css,js,json,lock,md,nix,pl,pm,py,rb,sh,xml}]
|
||||
indent_style = space
|
||||
|
||||
# Match docbook files, set indent width of one
|
||||
[*.xml]
|
||||
indent_size = 1
|
||||
|
||||
# Match js/json/lockfiles/markdown/nix/ruby/ts files, set indent width of two
|
||||
[*.{js,json,lock,md,nix,rb,ts}]
|
||||
# Match json/lockfiles/markdown/nix/ruby files, set indent width of two
|
||||
[*.{js,json,lock,md,nix,rb}]
|
||||
indent_size = 2
|
||||
|
||||
# Match all the Bash code in Nix files, set indent width of two
|
||||
|
||||
23
.gitattributes
vendored
23
.gitattributes
vendored
@@ -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
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
@@ -54,7 +54,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,8 +121,6 @@ body:
|
||||
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: |
|
||||
|
||||
@@ -54,7 +54,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"
|
||||
@@ -135,8 +135,6 @@ body:
|
||||
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: |
|
||||
|
||||
@@ -54,7 +54,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"
|
||||
@@ -125,8 +125,6 @@ body:
|
||||
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: |
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/04_build_failure.yml
vendored
2
.github/ISSUE_TEMPLATE/04_build_failure.yml
vendored
@@ -131,8 +131,6 @@ body:
|
||||
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: |
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/05_update_request.yml
vendored
2
.github/ISSUE_TEMPLATE/05_update_request.yml
vendored
@@ -104,8 +104,6 @@ body:
|
||||
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: |
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/06_module_request.yml
vendored
2
.github/ISSUE_TEMPLATE/06_module_request.yml
vendored
@@ -79,8 +79,6 @@ body:
|
||||
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: |
|
||||
|
||||
@@ -85,8 +85,6 @@ body:
|
||||
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: |
|
||||
|
||||
@@ -67,8 +67,6 @@ body:
|
||||
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: |
|
||||
|
||||
@@ -137,8 +137,6 @@ body:
|
||||
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: |
|
||||
|
||||
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -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,14 +27,12 @@ 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
|
||||
|
||||
35
.github/actions/checkout/action.yml
vendored
35
.github/actions/checkout/action.yml
vendored
@@ -13,13 +13,12 @@ inputs:
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.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')
|
||||
@@ -96,22 +95,25 @@ 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) {
|
||||
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')
|
||||
}
|
||||
// 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) {
|
||||
@@ -132,6 +134,3 @@ runs:
|
||||
await rm('pin-bump.patch')
|
||||
}
|
||||
}
|
||||
|
||||
console.log('final disk usage:')
|
||||
await run('df', '-h')
|
||||
|
||||
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@@ -1,11 +1,7 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directories:
|
||||
- "/"
|
||||
- ".github/actions/*/*"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
labels: []
|
||||
commit-message:
|
||||
prefix: ".github"
|
||||
|
||||
2
.github/labeler-no-sync.yml
vendored
2
.github/labeler-no-sync.yml
vendored
@@ -22,7 +22,7 @@
|
||||
- doc/**/*
|
||||
- nixos/doc/**/*
|
||||
|
||||
"backport release-26.05":
|
||||
"backport release-25.11":
|
||||
- all:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
|
||||
8
.github/labeler.yml
vendored
8
.github/labeler.yml
vendored
@@ -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":
|
||||
@@ -271,14 +270,8 @@
|
||||
- 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:
|
||||
@@ -552,6 +545,7 @@
|
||||
- pkgs/by-name/*/*tree-sitter*/**/*
|
||||
- pkgs/by-name/ne/neovim-unwrapped/treesitter-parsers.nix
|
||||
- pkgs/development/python-modules/*tree-sitter*/**/*
|
||||
- pkgs/development/tools/parsing/tree-sitter/**/*
|
||||
|
||||
"6.topic: updaters":
|
||||
- any:
|
||||
|
||||
29
.github/workflows/backport.yml
vendored
29
.github/workflows/backport.yml
vendored
@@ -11,7 +11,7 @@ on:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write # adding the 'has: port to stable' and 'has: backport failed' label
|
||||
issues: write # adding the 'has: port to stable' label
|
||||
pull-requests: write # creating backport pull requests
|
||||
|
||||
defaults:
|
||||
@@ -21,26 +21,24 @@ 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
# Avoid materializing full nixpkgs tree
|
||||
sparse-checkout: .
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
persist-credentials: true
|
||||
|
||||
@@ -51,7 +49,7 @@ jobs:
|
||||
|
||||
- name: Create backport PRs
|
||||
id: backport
|
||||
uses: korthout/backport-action@2e830a1d0b8269505846ddd407a70876913ad1f8 # v4.6.0
|
||||
uses: korthout/backport-action@4aaf0e03a94ff0a619c9a511b61aeb42adea5b02 # v4.2.0
|
||||
with:
|
||||
# Config README: https://github.com/korthout/backport-action#backport-action
|
||||
add_author_as_reviewer: true
|
||||
@@ -74,7 +72,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: |
|
||||
@@ -84,16 +82,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' ]
|
||||
})
|
||||
|
||||
23
.github/workflows/bot.yml
vendored
23
.github/workflows/bot.yml
vendored
@@ -41,23 +41,26 @@ jobs:
|
||||
run:
|
||||
runs-on: ubuntu-slim
|
||||
if: github.event_name != 'schedule' || github.repository_owner == 'NixOS'
|
||||
env:
|
||||
# TODO: Remove after 2026-03-04, when Node 24 becomes the default.
|
||||
# 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
ci/github-script
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --package-lock-only=false @actions/artifact bottleneck
|
||||
working-directory: ci/github-script
|
||||
run: npm install @actions/artifact@5.0.3 bottleneck@2.19.5
|
||||
|
||||
# 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
|
||||
@@ -71,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
|
||||
@@ -88,7 +91,7 @@ jobs:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }}
|
||||
run: gh api /rate_limit | jq
|
||||
|
||||
- uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.0
|
||||
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
|
||||
name: Labels from touched files
|
||||
if: |
|
||||
github.event_name == 'pull_request_target' &&
|
||||
@@ -98,7 +101,7 @@ jobs:
|
||||
configuration-path: .github/labeler.yml # default
|
||||
sync-labels: true
|
||||
|
||||
- uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.0
|
||||
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
|
||||
name: Labels from touched files (no sync)
|
||||
if: |
|
||||
github.event_name == 'pull_request_target' &&
|
||||
@@ -108,7 +111,7 @@ jobs:
|
||||
configuration-path: .github/labeler-no-sync.yml
|
||||
sync-labels: false
|
||||
|
||||
- uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.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
|
||||
|
||||
29
.github/workflows/build.yml
vendored
29
.github/workflows/build.yml
vendored
@@ -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
|
||||
name: aarch64-linux
|
||||
systems: aarch64-linux
|
||||
builds: [shell, manual-nixos, manual-nixpkgs]
|
||||
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31.11.1
|
||||
- uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
|
||||
with:
|
||||
# Sandbox is disabled on MacOS by default.
|
||||
extra_nix_config: sandbox = true
|
||||
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
|
||||
continue-on-error: true
|
||||
with:
|
||||
# The nixpkgs-gha cache should not be trusted or used outside of Nixpkgs and its forks' CI.
|
||||
@@ -77,16 +80,12 @@ 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
|
||||
@@ -105,7 +104,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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ inputs.artifact-prefix }}nixos-manual-${{ matrix.system }}
|
||||
name: ${{ inputs.artifact-prefix }}nixos-manual-${{ matrix.name }}
|
||||
path: nixos-manual
|
||||
|
||||
109
.github/workflows/check.yml
vendored
109
.github/workflows/check.yml
vendored
@@ -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:
|
||||
@@ -43,7 +35,7 @@ jobs:
|
||||
runs-on: ubuntu-slim
|
||||
timeout-minutes: 3
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: trusted
|
||||
@@ -51,29 +43,19 @@ jobs:
|
||||
ci/github-script
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --package-lock-only=false bottleneck
|
||||
working-directory: trusted/ci/github-script
|
||||
|
||||
- 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@2.19.5
|
||||
|
||||
- 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')({
|
||||
@@ -86,101 +68,26 @@ jobs:
|
||||
|
||||
- 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
|
||||
|
||||
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 }}
|
||||
run: gh api /rate_limit | jq
|
||||
|
||||
github-script:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
|
||||
- name: Checkout merge and target commits
|
||||
uses: ./.github/actions/checkout
|
||||
with:
|
||||
merged-as-untrusted-at: ${{ inputs.mergedSha }}
|
||||
target-as-trusted-at: ${{ inputs.targetSha }}
|
||||
|
||||
- name: Install dependencies to trusted/
|
||||
run: |
|
||||
npm ci --package-lock-only=false
|
||||
echo "$PWD/node_modules/.bin" >> "$GITHUB_PATH"
|
||||
working-directory: nixpkgs/trusted/ci/github-script
|
||||
|
||||
- name: Link trusted/ dependencies to untrusted/
|
||||
run: ln -s "$PWD/trusted/ci/github-script/node_modules" untrusted/ci/github-script/node_modules
|
||||
working-directory: nixpkgs
|
||||
|
||||
- name: Type-check ci/github-script
|
||||
run: tsc --build
|
||||
working-directory: nixpkgs/untrusted/ci/github-script
|
||||
|
||||
owners:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
|
||||
- name: Checkout merge and target commits
|
||||
uses: ./.github/actions/checkout
|
||||
with:
|
||||
merged-as-untrusted-at: ${{ inputs.mergedSha }}
|
||||
target-as-trusted-at: ${{ inputs.targetSha }}
|
||||
|
||||
- uses: cachix/install-nix-action@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31.11.1
|
||||
- uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
|
||||
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
|
||||
continue-on-error: true
|
||||
with:
|
||||
# The nixpkgs-gha cache should not be trusted or used outside of Nixpkgs and its forks' CI.
|
||||
|
||||
10
.github/workflows/comment.yml
vendored
10
.github/workflows/comment.yml
vendored
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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
|
||||
|
||||
6
.github/workflows/edited.yml
vendored
6
.github/workflows/edited.yml
vendored
@@ -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: |
|
||||
|
||||
79
.github/workflows/eval.yml
vendored
79
.github/workflows/eval.yml
vendored
@@ -15,9 +15,6 @@ on:
|
||||
targetSha:
|
||||
required: true
|
||||
type: string
|
||||
baseBranch:
|
||||
required: true
|
||||
type: string
|
||||
systems:
|
||||
required: true
|
||||
type: string
|
||||
@@ -26,10 +23,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:
|
||||
@@ -50,7 +43,7 @@ jobs:
|
||||
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: trusted
|
||||
@@ -58,7 +51,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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ inputs.mergedSha }}
|
||||
@@ -68,7 +61,7 @@ jobs:
|
||||
|
||||
- name: Find commit that touched ci/pinned.json
|
||||
id: find-pinned-commit
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
env:
|
||||
TARGET_SHA: ${{ inputs.targetSha }}
|
||||
HEAD_SHA: ${{ inputs.headSha }}
|
||||
@@ -139,7 +132,7 @@ jobs:
|
||||
core.info(`Found pinned.json commit: ${ciPinBumpCommit}`)
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31.11.1
|
||||
uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
|
||||
|
||||
- name: Load supported versions
|
||||
id: versions
|
||||
@@ -161,7 +154,7 @@ jobs:
|
||||
# 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
|
||||
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,7 +167,7 @@ jobs:
|
||||
sudo mkswap /swap
|
||||
sudo swapon /swap
|
||||
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
@@ -187,9 +180,9 @@ jobs:
|
||||
target-as-trusted-at: ${{ inputs.targetSha }}
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31.11.1
|
||||
uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
|
||||
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # 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 +238,7 @@ jobs:
|
||||
--out-link diff
|
||||
|
||||
- name: Upload outpaths diff and stats
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ inputs.artifact-prefix }}${{ matrix.version && format('{0}-', matrix.version) || '' }}diff-${{ matrix.system }}
|
||||
path: diff/*
|
||||
@@ -259,7 +252,7 @@ jobs:
|
||||
statuses: write # creating 'Eval Summary' commit statuses
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
@@ -270,14 +263,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@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
pattern: ${{ inputs.artifact-prefix }}diff-*
|
||||
path: diff
|
||||
merge-multiple: true
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31.11.1
|
||||
uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
|
||||
|
||||
- name: Combine all output paths and eval stats
|
||||
run: |
|
||||
@@ -286,7 +279,7 @@ jobs:
|
||||
--out-link combined
|
||||
|
||||
- name: Upload the maintainer list
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ inputs.artifact-prefix }}maintainers
|
||||
path: combined/maintainers.json
|
||||
@@ -294,7 +287,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 +295,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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.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 +321,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 =
|
||||
@@ -358,24 +335,12 @@ jobs:
|
||||
description,
|
||||
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
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
github-token: ${{ steps.app-token.outputs.token || github.token }}
|
||||
script: |
|
||||
require('./nixpkgs/trusted/ci/github-script/check-target-branch.ts')({
|
||||
require('./nixpkgs/trusted/ci/github-script/check-target-branch.js')({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
@@ -388,13 +353,13 @@ jobs:
|
||||
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@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.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 }}
|
||||
@@ -476,7 +441,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
@@ -486,7 +451,7 @@ jobs:
|
||||
merged-as-untrusted-at: ${{ inputs.mergedSha }}
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31.11.1
|
||||
uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
|
||||
|
||||
- name: Ensure flake outputs on all systems still evaluate
|
||||
run: nix flake check --all-systems --no-build './nixpkgs/untrusted?shallow=1'
|
||||
|
||||
24
.github/workflows/lint.yml
vendored
24
.github/workflows/lint.yml
vendored
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31.11.1
|
||||
- uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
|
||||
|
||||
# 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31.11.1
|
||||
- uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
|
||||
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31.11.1
|
||||
- uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
|
||||
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
|
||||
continue-on-error: true
|
||||
with:
|
||||
# The nixpkgs-gha cache should not be trusted or used outside of Nixpkgs and its forks' CI.
|
||||
@@ -131,15 +131,15 @@ jobs:
|
||||
# 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
|
||||
runs-on: ubuntu-slim
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
script: |
|
||||
const checkCommitMessages = require('./trusted/ci/github-script/lint-commits.js')
|
||||
|
||||
7
.github/workflows/merge-group.yml
vendored
7
.github/workflows/merge-group.yml
vendored
@@ -25,14 +25,14 @@ jobs:
|
||||
targetSha: ${{ steps.prepare.outputs.targetSha }}
|
||||
systems: ${{ steps.prepare.outputs.systems }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
ci/github-script/supportedSystems.js
|
||||
|
||||
- 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 }}
|
||||
@@ -97,7 +97,6 @@ jobs:
|
||||
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:
|
||||
@@ -126,7 +125,7 @@ jobs:
|
||||
permissions:
|
||||
statuses: write # creating 'no PR failures' commit status
|
||||
steps:
|
||||
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
env:
|
||||
RESULTS: ${{ toJSON(needs.*.result) }}
|
||||
with:
|
||||
|
||||
43
.github/workflows/periodic-merge-24h.yml
vendored
43
.github/workflows/periodic-merge-24h.yml
vendored
@@ -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,10 @@ 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.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 +45,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,
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
2
.github/workflows/periodic-merge-6h.yml
vendored
2
.github/workflows/periodic-merge-6h.yml
vendored
@@ -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
|
||||
|
||||
16
.github/workflows/periodic-merge.yml
vendored
16
.github/workflows/periodic-merge.yml
vendored
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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: |
|
||||
with:
|
||||
issue-number: 105153
|
||||
body: |
|
||||
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"
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
30
.github/workflows/pull-request-target.yml
vendored
30
.github/workflows/pull-request-target.yml
vendored
@@ -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 }}
|
||||
@@ -36,27 +30,15 @@ jobs:
|
||||
systems: ${{ steps.prepare.outputs.systems }}
|
||||
touched: ${{ steps.prepare.outputs.touched }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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 +60,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 }}
|
||||
@@ -103,14 +82,11 @@ jobs:
|
||||
# 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 +126,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:
|
||||
|
||||
10
.github/workflows/review.yml
vendored
10
.github/workflows/review.yml
vendored
@@ -20,22 +20,22 @@ jobs:
|
||||
runs-on: ubuntu-slim
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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
|
||||
|
||||
15
.github/workflows/teams.yml
vendored
15
.github/workflows/teams.yml
vendored
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
@@ -38,11 +38,10 @@ jobs:
|
||||
maintainers/github-teams.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --package-lock-only=false bottleneck
|
||||
working-directory: ci/github-script
|
||||
run: npm install bottleneck@2.19.5
|
||||
|
||||
- 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: |
|
||||
@@ -65,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@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
add-paths: maintainers/github-teams.json
|
||||
|
||||
16
.github/workflows/test.yml
vendored
16
.github/workflows/test.yml
vendored
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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:
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
|
||||
- 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, {
|
||||
@@ -62,9 +62,7 @@ jobs:
|
||||
'.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,9 +75,8 @@ jobs:
|
||||
'.github/workflows/pull-request-target.yml',
|
||||
'.github/workflows/test.yml',
|
||||
'ci/github-script/bot.js',
|
||||
'ci/github-script/check-target-branch.ts',
|
||||
'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',
|
||||
@@ -87,9 +84,7 @@ jobs:
|
||||
'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:
|
||||
@@ -118,8 +113,5 @@ jobs:
|
||||
statuses: write # unused on pull_request, required by PR workflow
|
||||
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
2
.github/zizmor.yml
vendored
@@ -10,5 +10,3 @@
|
||||
rules:
|
||||
dangerous-triggers:
|
||||
disable: true
|
||||
secrets-outside-env:
|
||||
disable: true
|
||||
|
||||
1
.mailmap
1
.mailmap
@@ -22,7 +22,6 @@ 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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -442,7 +442,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 +505,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.
|
||||
@@ -571,10 +570,7 @@ If a contributor does not want committers to push to their branch, they must unc
|
||||
|
||||
### Release notes
|
||||
|
||||
If you add or remove a NixOS module, or make other breaking or significant NixOS changes, write about it in the next NixOS release notes in [`nixos/doc/manual/release-notes`](./nixos/doc/manual/release-notes).
|
||||
|
||||
If you make major or breaking changes to a package (other than removal), write about it in the next Nixpkgs release notes in [`doc/release-notes`](./doc/release-notes).
|
||||
Package removals should not get a Nixpkgs release note, [a throwing alias should be added instead](./pkgs/README.md#steps-to-remove-a-package-from-nixpkgs).
|
||||
If you removed packages or made some major NixOS changes, write about it in the next release notes in [`nixos/doc/manual/release-notes`](./nixos/doc/manual/release-notes).
|
||||
|
||||
### File naming and organisation
|
||||
|
||||
@@ -892,77 +888,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 non‐trivial use of automation to produce it, including but not limited to LLM‐based AI tools.
|
||||
|
||||
The following sections give more detail.
|
||||
|
||||
## Scope
|
||||
|
||||
Any use of automated tools to generate non‐trivial 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 LLM‐based AI tools and hand‐written 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 tooling’s 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 LLM‐based 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 LLM‐based 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 “auto‐completion” (even if LLM‐based) 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 maintainer‐approved 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 self‐review, 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 that’s the case and point them to this policy as appropriate.
|
||||
Please assume good faith and remain civil; it’s 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 people’s 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/).
|
||||
|
||||
@@ -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.11 release](https://hydra.nixos.org/jobset/nixos/release-25.11)
|
||||
* [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.11 release](https://hydra.nixos.org/job/nixos/release-25.11/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).
|
||||
|
||||
69
ci/OWNERS
69
ci/OWNERS
@@ -21,15 +21,15 @@
|
||||
/ci/OWNERS @infinisil @philiptaron
|
||||
|
||||
# Development support
|
||||
/.editorconfig @Mic92
|
||||
/.editorconfig @Mic92 @zowoq
|
||||
/shell.nix @infinisil @NixOS/Security
|
||||
|
||||
# Libraries
|
||||
/lib @infinisil @hsjobeki
|
||||
/lib/generators.nix @infinisil @hsjobeki
|
||||
/lib/cli.nix @infinisil @hsjobeki
|
||||
/lib/debug.nix @infinisil @hsjobeki
|
||||
/lib/asserts.nix @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
|
||||
@@ -75,7 +75,11 @@
|
||||
/pkgs/pkgs-lib @Stunkymonkey @h7x4
|
||||
|
||||
# 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
|
||||
@@ -184,6 +188,8 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lo
|
||||
/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
|
||||
@@ -213,10 +219,10 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lo
|
||||
/pkgs/development/r-modules @jbedo
|
||||
|
||||
# Rust
|
||||
/pkgs/development/compilers/rust @alyssais @Mic92 @winterqt
|
||||
/pkgs/build-support/rust @winterqt
|
||||
/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 @winterqt
|
||||
/doc/languages-frameworks/rust.section.md @zowoq @winterqt
|
||||
|
||||
# Tcl
|
||||
/pkgs/development/interpreters/tcl @fgaz
|
||||
@@ -228,7 +234,9 @@ 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
|
||||
@@ -260,7 +268,7 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
|
||||
/pkgs/applications/editors/jetbrains @leona-ya @theCapypara
|
||||
|
||||
# Licenses
|
||||
/lib/licenses @alyssais @emilazy @jopejoe1
|
||||
/lib/licenses.nix @alyssais @emilazy @jopejoe1
|
||||
|
||||
# Qt
|
||||
/pkgs/development/libraries/qt-5 @K900 @NickCao @SuperSandro2000 @ttuegel
|
||||
@@ -286,6 +294,9 @@ 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
|
||||
/pkgs/os-specific/linux/kernel/hardened/ @fabianhjr
|
||||
|
||||
# Home Automation
|
||||
/nixos/modules/services/home-automation/home-assistant.nix @mweinelt
|
||||
/nixos/modules/services/home-automation/zigbee2mqtt.nix @mweinelt
|
||||
@@ -295,14 +306,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
|
||||
@@ -321,12 +326,17 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
|
||||
/nixos/tests/kea.nix @mweinelt
|
||||
/nixos/tests/knot.nix @mweinelt
|
||||
|
||||
# Web servers
|
||||
/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
|
||||
@@ -339,6 +349,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
|
||||
@@ -363,9 +376,6 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
|
||||
|
||||
# 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
|
||||
@@ -467,7 +477,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
|
||||
@@ -482,7 +492,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
|
||||
@@ -492,7 +502,7 @@ pkgs/development/interpreters/elixir/ @NixOS/beam
|
||||
pkgs/development/interpreters/lfe/ @NixOS/beam
|
||||
|
||||
# Authelia
|
||||
pkgs/by-name/au/authelia/ @06kellyjac @nicomem
|
||||
pkgs/by-name/au/authelia/ @06kellyjac @dit7ya @nicomem
|
||||
|
||||
# OctoDNS
|
||||
pkgs/by-name/oc/octodns/ @anthonyroussel
|
||||
@@ -502,17 +512,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
|
||||
|
||||
11
ci/README.md
11
ci/README.md
@@ -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
|
||||
|
||||
152
ci/default.nix
152
ci/default.nix
@@ -26,7 +26,132 @@ 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;
|
||||
ignore = [
|
||||
# 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.
|
||||
"sema-unused-def-lambda-noarg-formal"
|
||||
"sema-unused-def-lambda-witharg-arg"
|
||||
"sema-unused-def-lambda-witharg-formal"
|
||||
"sema-unused-def-let"
|
||||
# Keep this rule, because we have `lib.or`.
|
||||
"or-identifier"
|
||||
# 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
|
||||
"sema-primop-removed-prefix"
|
||||
"sema-primop-overridden"
|
||||
"sema-constant-overridden"
|
||||
"sema-primop-unknown"
|
||||
];
|
||||
};
|
||||
settings.formatter.nixf-diagnose = {
|
||||
# Ensure nixfmt cleans up after nixf-diagnose.
|
||||
priority = -1;
|
||||
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 +159,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 +179,14 @@ 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; });
|
||||
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 {
|
||||
|
||||
85
ci/eval/attrpaths.nix
Normal file
85
ci/eval/attrpaths.nix
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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,19 +151,20 @@ 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
|
||||
@@ -220,7 +181,7 @@ runCommand "compare"
|
||||
];
|
||||
users = builtins.toJSON users;
|
||||
teams = builtins.toJSON teams;
|
||||
packages = builtins.toJSON (lib.map (lib.concatStringsSep ".") packages);
|
||||
packages = builtins.toJSON packages;
|
||||
passAsFile = [
|
||||
"users"
|
||||
"teams"
|
||||
@@ -239,33 +200,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"
|
||||
|
||||
@@ -1,59 +1,70 @@
|
||||
# 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,
|
||||
changedattrs,
|
||||
changedpathsjson,
|
||||
removedattrs,
|
||||
}:
|
||||
# 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 ../../.. {
|
||||
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 && changed != "pkgs/by-name/README.md"))
|
||||
(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)}/";
|
||||
# meta.maintainers also contains all individual team members.
|
||||
# We only want to ping individuals if they're added individually as maintainers, not via teams.
|
||||
users = package.meta.nonTeamMaintainers or [ ];
|
||||
teams = package.meta.teams or [ ];
|
||||
}
|
||||
))
|
||||
# No need to match up packages without maintainers with their files.
|
||||
# This also filters out attributes where `package = null`, which is the
|
||||
# case for libintl, for example.
|
||||
(lib.filter (pkg: pkg.users != [ ] || pkg.teams != [ ]))
|
||||
];
|
||||
|
||||
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 +87,50 @@ 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))
|
||||
];
|
||||
|
||||
# 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;
|
||||
attrsWithModifiedFiles = lib.filter (pkg: anyMatchingFiles pkg.filenames) attrsWithFilenames;
|
||||
|
||||
userPings =
|
||||
context:
|
||||
pkg:
|
||||
map (maintainer: {
|
||||
type = "user";
|
||||
userId = maintainer.githubId;
|
||||
inherit context;
|
||||
packageName = pkg.name;
|
||||
});
|
||||
|
||||
teamPings =
|
||||
context: team:
|
||||
if team ? githubId then
|
||||
pkg: team:
|
||||
if team ? github then
|
||||
[
|
||||
{
|
||||
type = "team";
|
||||
teamId = team.githubId;
|
||||
inherit context;
|
||||
packageName = pkg.name;
|
||||
}
|
||||
]
|
||||
else
|
||||
userPings context team.members;
|
||||
userPings pkg team.members;
|
||||
|
||||
byType = lib.groupBy (ping: ping.type) (attrPathEntities ++ changedFileEntities);
|
||||
maintainersToPing = lib.concatMap (
|
||||
pkg: userPings pkg pkg.users ++ lib.concatMap (teamPings pkg) pkg.teams
|
||||
) attrsWithModifiedFiles;
|
||||
|
||||
byType = lib.groupBy (ping: ping.type) maintainersToPing;
|
||||
|
||||
byUser = lib.pipe (byType.user or [ ]) [
|
||||
(lib.groupBy (ping: toString ping.userId))
|
||||
(lib.mapAttrs (_user: lib.map (pkg: pkg.context)))
|
||||
(lib.mapAttrs (_user: lib.map (pkg: pkg.packageName)))
|
||||
];
|
||||
byTeam = lib.pipe (byType.team or [ ]) [
|
||||
(lib.groupBy (ping: toString ping.teamId))
|
||||
(lib.mapAttrs (_team: lib.map (pkg: pkg.context)))
|
||||
(lib.mapAttrs (_team: lib.map (pkg: pkg.packageName)))
|
||||
];
|
||||
in
|
||||
{
|
||||
users = byUser;
|
||||
teams = byTeam;
|
||||
packages = attrPathsToGetMaintainersFor;
|
||||
packages = lib.catAttrs "name" attrsWithModifiedFiles;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
busybox,
|
||||
jq,
|
||||
nix,
|
||||
perf,
|
||||
}:
|
||||
|
||||
{
|
||||
@@ -39,7 +38,7 @@ let
|
||||
fileset = unions (
|
||||
map (lib.path.append ../..) [
|
||||
".version"
|
||||
"ci/eval/pre-eval.nix"
|
||||
"ci/eval/attrpaths.nix"
|
||||
"ci/eval/chunk.nix"
|
||||
"ci/eval/outpaths.nix"
|
||||
"default.nix"
|
||||
@@ -57,11 +56,11 @@ let
|
||||
builtins.readFile ../../pkgs/top-level/release-supported-systems.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 +73,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 +90,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 +100,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 +121,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 +146,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 +164,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 +190,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 +249,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 +266,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 +288,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 +298,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 +313,7 @@ let
|
||||
in
|
||||
{
|
||||
inherit
|
||||
preEval
|
||||
attrpathsSuperset
|
||||
singleSystem
|
||||
diff
|
||||
combine
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
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
|
||||
@@ -14,8 +14,6 @@
|
||||
builtins.readFile (path + "/pkgs/top-level/release-supported-systems.json")
|
||||
),
|
||||
|
||||
attrPathsDisallowedForInternalUse ? [ ],
|
||||
|
||||
# Customize the config used to evaluate nixpkgs
|
||||
extraNixpkgsConfig ? { },
|
||||
}:
|
||||
@@ -37,22 +35,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;
|
||||
|
||||
@@ -126,8 +108,6 @@ in
|
||||
tweak (
|
||||
(removeAttrs nixpkgsJobs blacklist)
|
||||
// {
|
||||
nixosTests = lib.filterAttrs (
|
||||
name: _: name == "simple-container" || name == "simple-vm"
|
||||
) nixosJobs.tests;
|
||||
nixosTests = lib.filterAttrs (name: _: name == "simple") nixosJobs.tests;
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
3
ci/github-script/.gitignore
vendored
3
ci/github-script/.gitignore
vendored
@@ -1,5 +1,2 @@
|
||||
comparison
|
||||
comparison.zip
|
||||
node_modules
|
||||
step-summary.md
|
||||
*.tsbuildinfo
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// @ts-nocheck
|
||||
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')
|
||||
@@ -207,8 +206,20 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
|
||||
const maintainers = await getMaintainerMap(pull_request.base.ref)
|
||||
|
||||
const merge_bot_eligible = await handleMerge({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
log,
|
||||
dry,
|
||||
pull_request,
|
||||
events,
|
||||
maintainers,
|
||||
getTeamMembers,
|
||||
getUser,
|
||||
})
|
||||
|
||||
// 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!) {
|
||||
@@ -220,7 +231,6 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
reviews(first: 100) {
|
||||
nodes {
|
||||
state
|
||||
commit { oid }
|
||||
user: author {
|
||||
# Only get users, no bots
|
||||
... on User {
|
||||
@@ -256,20 +266,6 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
r.user.id !== pull_request.user?.id,
|
||||
)
|
||||
|
||||
const merge_bot_eligible = await handleMerge({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
log,
|
||||
dry,
|
||||
pull_request,
|
||||
events,
|
||||
reviews,
|
||||
maintainers,
|
||||
getTeamMembers,
|
||||
getUser,
|
||||
})
|
||||
|
||||
const approvals = new Set(
|
||||
reviews
|
||||
.filter((review) => review.state === 'APPROVED')
|
||||
@@ -396,13 +392,6 @@ module.exports = async ({ github, context, core, dry }) => {
|
||||
pull_number,
|
||||
per_page: 100,
|
||||
})
|
||||
|
||||
// label llm-assisted PRs accordingly
|
||||
const assistedByPattern = /Assisted-by: (?!nix-init)/i
|
||||
evalLabels['llm-assisted'] = prCommits.some((c) =>
|
||||
assistedByPattern.test(c.commit.message),
|
||||
)
|
||||
|
||||
const commitSubjects = prCommits.map(
|
||||
(c) => c.commit.message.split('\n')[0],
|
||||
)
|
||||
|
||||
213
ci/github-script/check-target-branch.js
Normal file
213
ci/github-script/check-target-branch.js
Normal file
@@ -0,0 +1,213 @@
|
||||
/// @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[],
|
||||
* },
|
||||
* 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')
|
||||
|
||||
// https://github.com/NixOS/nixpkgs/pull/481205#issuecomment-3790123921
|
||||
// These should go to staging-nixos instead of master,
|
||||
// but release-xx.xx (not staging-xx.xx) when backported
|
||||
let isExemptKernelUpdate = false
|
||||
if (prInfo.changed_files === 1 && base.startsWith('release-')) {
|
||||
const changedFiles = (
|
||||
await github.rest.pulls.listFiles({
|
||||
...context.repo,
|
||||
pull_number,
|
||||
})
|
||||
).data
|
||||
isExemptKernelUpdate =
|
||||
changedFiles.length === 1 &&
|
||||
changedFiles[0].filename ===
|
||||
'pkgs/os-specific/linux/kernel/kernels-org.json'
|
||||
}
|
||||
|
||||
// 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: 'COMMENT',
|
||||
reviewKey,
|
||||
})
|
||||
|
||||
throw new Error('This PR is against the wrong branch.')
|
||||
} 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 {
|
||||
branchText = `(probably \`staging-${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: 'COMMENT',
|
||||
reviewKey,
|
||||
})
|
||||
|
||||
throw new Error('This PR is against the wrong branch.')
|
||||
} 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: 'COMMENT',
|
||||
reviewKey,
|
||||
})
|
||||
} else {
|
||||
core.info('checkTargetBranch: this PR is against an appropriate branch.')
|
||||
|
||||
await dismissReviews({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
dry,
|
||||
reviewKey,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = checkTargetBranch
|
||||
@@ -1,231 +0,0 @@
|
||||
import type * as actionsCore from '@actions/core'
|
||||
import type { context as actionsContext } from '@actions/github'
|
||||
import type { GitHub } from '@actions/github/lib/utils'
|
||||
|
||||
// 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'
|
||||
|
||||
type ChangedPaths = {
|
||||
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[]>
|
||||
}
|
||||
|
||||
async function checkTargetBranch({
|
||||
github,
|
||||
context,
|
||||
core,
|
||||
dry,
|
||||
}: {
|
||||
github: InstanceType<typeof GitHub>
|
||||
context: typeof actionsContext
|
||||
core: typeof actionsCore
|
||||
dry: boolean
|
||||
}) {
|
||||
const changed: ChangedPaths = 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: string
|
||||
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
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck
|
||||
module.exports = async ({ github, context, core, dry, cherryPicks }) => {
|
||||
const { execFileSync } = require('node:child_process')
|
||||
const { classify } = require('../supportedBranches.js')
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
// @ts-nocheck
|
||||
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: typeof 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: typeof 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 }
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck
|
||||
const excludeTeams = [
|
||||
/^voters.*$/,
|
||||
/^nixpkgs-maintainers$/,
|
||||
|
||||
@@ -1,17 +1,37 @@
|
||||
// @ts-check
|
||||
const { classify } = require('../supportedBranches.js')
|
||||
const { getCommitDetailsForPR } = require('./get-pr-commit-details.js')
|
||||
|
||||
/** @typedef {import('./get-pr-commit-details.js').Commit} Commit */
|
||||
const { promisify } = require('node:util')
|
||||
const execFile = promisify(require('node:child_process').execFile)
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* github: InstanceType<typeof import('@actions/github/lib/utils').GitHub>,
|
||||
* context: typeof import('@actions/github').context,
|
||||
* core: typeof import('@actions/core'),
|
||||
* args: string[]
|
||||
* core: import('@actions/core'),
|
||||
* quiet?: boolean,
|
||||
* repoPath?: string,
|
||||
* }} LintCommitsProps
|
||||
* }} RunGitProps
|
||||
*/
|
||||
async function lintCommits({ github, context, core, repoPath }) {
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* github: InstanceType<import('@actions/github/lib/utils').GitHub>,
|
||||
* context: import('@actions/github/lib/context').Context,
|
||||
* core: import('@actions/core'),
|
||||
* repoPath?: string,
|
||||
* }} CheckCommitMessagesProps
|
||||
*/
|
||||
async function checkCommitMessages({ 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) {
|
||||
@@ -47,83 +67,84 @@ async function lintCommits({ github, context, core, repoPath }) {
|
||||
return
|
||||
}
|
||||
|
||||
const commits = await getCommitDetailsForPR({ core, pr, repoPath })
|
||||
|
||||
await checkCommitMessages({ commits, core })
|
||||
await checkCommitMetadata({ commits, core })
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* commits: Commit[],
|
||||
* core: typeof 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',
|
||||
'services',
|
||||
'style',
|
||||
'test',
|
||||
'update',
|
||||
]
|
||||
|
||||
/**
|
||||
* @param {string[]} types e.g. ["fix", "feat"]
|
||||
* @param {string?} sha commit hash
|
||||
* GitHub's API will return a maximum of 250 commits.
|
||||
* We will use it if we can, but fall back to using git locally.
|
||||
* This type is used to abstract over the differences between the two.
|
||||
* @type {{
|
||||
* message: string,
|
||||
* sha: string,
|
||||
* }[]}
|
||||
*/
|
||||
function makeConventionalCommitRegex(types, sha = null) {
|
||||
core.info(
|
||||
`${
|
||||
sha
|
||||
? `Conventional commit types for ${sha?.slice(0, 16)}`
|
||||
: 'Default conventional commit types'
|
||||
}: ${JSON.stringify(types)}`,
|
||||
)
|
||||
let commits
|
||||
|
||||
return new RegExp(`^(${types.join('|')})!?(\\(.*\\))?!?:`)
|
||||
if (pr.commits < 250) {
|
||||
commits = (
|
||||
await github.paginate(github.rest.pulls.listCommits, {
|
||||
...context.repo,
|
||||
pull_number,
|
||||
})
|
||||
).map((commit) => ({ message: commit.commit.message, sha: commit.sha }))
|
||||
} else {
|
||||
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)
|
||||
|
||||
commits = await Promise.all(
|
||||
shas.map(async (sha) => ({
|
||||
sha,
|
||||
message: (
|
||||
await runGit({
|
||||
args: ['log', '--format=%s', '-1', sha],
|
||||
repoPath,
|
||||
core,
|
||||
quiet: true,
|
||||
})
|
||||
).stdout,
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
// 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,
|
||||
)
|
||||
const failures = new Set()
|
||||
|
||||
for (const commit of commits) {
|
||||
const logMsgStart = `Commit ${commit.sha}'s message's subject ("${commit.subject}")`
|
||||
const message = commit.message
|
||||
const firstLine = message.split('\n')[0]
|
||||
|
||||
// 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)
|
||||
const logMsgStart = `Commit ${commit.sha}'s message's subject ("${firstLine}")`
|
||||
|
||||
if (!commit.subject.includes(': ')) {
|
||||
if (!firstLine.includes(': ')) {
|
||||
core.error(
|
||||
`${logMsgStart} was detected as not meeting our guidelines because ` +
|
||||
'it does not contain a colon followed by a whitespace. ' +
|
||||
'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('.')) {
|
||||
if (firstLine.endsWith('.')) {
|
||||
core.error(
|
||||
`${logMsgStart} was detected as not meeting our guidelines because ` +
|
||||
'it ends in a period. There may be other issues as well.',
|
||||
@@ -132,25 +153,15 @@ async function checkCommitMessages({ commits, core }) {
|
||||
}
|
||||
|
||||
const fixups = ['amend!', 'fixup!', 'squash!']
|
||||
if (fixups.some((s) => commit.subject.startsWith(s))) {
|
||||
if (fixups.some((s) => firstLine.startsWith(s))) {
|
||||
core.error(
|
||||
`${logMsgStart} was detected as not meeting our guidelines because ` +
|
||||
`it begins with "${fixups.find((s) => commit.subject.startsWith(s))}". ` +
|
||||
`it begins with "${fixups.find((s) => firstLine.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!`)
|
||||
}
|
||||
@@ -159,66 +170,11 @@ async function checkCommitMessages({ commits, core }) {
|
||||
if (failures.size !== 0) {
|
||||
core.error(
|
||||
'Please review the guidelines at ' +
|
||||
'<https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#commit-conventions>, ' +
|
||||
'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: typeof 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
|
||||
module.exports = checkCommitMessages
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
const { classify } = require('../supportedBranches.js')
|
||||
const { getCommitDetailsForPR } = require('./get-pr-commit-details')
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* github: InstanceType<typeof import('@actions/github/lib/utils').GitHub>,
|
||||
* context: typeof import('@actions/github').context,
|
||||
* core: typeof 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
|
||||
@@ -1,13 +1,12 @@
|
||||
// @ts-nocheck
|
||||
const { classify } = require('../supportedBranches.js')
|
||||
|
||||
function runChecklist({
|
||||
committers,
|
||||
events,
|
||||
files,
|
||||
pull_request,
|
||||
log,
|
||||
maintainers,
|
||||
reviews,
|
||||
user,
|
||||
userIsMaintainer,
|
||||
}) {
|
||||
@@ -28,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 = {
|
||||
@@ -74,12 +56,6 @@ function runChecklist({
|
||||
'Opened by [@r-ryantm](https://nix-community.github.io/nixpkgs-update/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) {
|
||||
@@ -89,9 +65,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.
|
||||
@@ -120,7 +95,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 }) {
|
||||
@@ -146,7 +121,6 @@ async function handleMerge({
|
||||
dry,
|
||||
pull_request,
|
||||
events,
|
||||
reviews,
|
||||
maintainers,
|
||||
getTeamMembers,
|
||||
getUser,
|
||||
@@ -172,14 +146,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 }) =>
|
||||
@@ -205,12 +171,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
|
||||
@@ -231,37 +195,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)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@@ -274,17 +217,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)
|
||||
@@ -327,11 +265,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),
|
||||
})
|
||||
@@ -368,12 +306,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)`)
|
||||
@@ -398,11 +334,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.
|
||||
|
||||
1035
ci/github-script/package-lock.json
generated
1035
ci/github-script/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,18 +2,15 @@
|
||||
"private": true,
|
||||
"//": [
|
||||
"Keep `@actions/core` and `@actions/github` in sync with",
|
||||
"https://github.com/actions/github-script/blob/main/package.json."
|
||||
"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": "5.0.3",
|
||||
"@actions/core": "1.11.1",
|
||||
"@actions/github": "6.0.1",
|
||||
"bottleneck": "2.19.5",
|
||||
"commander": "14.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node24": "24.0.4",
|
||||
"@types/node": "24.13.3",
|
||||
"typescript": "7.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck
|
||||
const { classify } = require('../supportedBranches.js')
|
||||
const { postReview, dismissReviews } = require('./reviews.js')
|
||||
const reviewKey = 'prepare'
|
||||
@@ -173,20 +172,14 @@ 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, reviewKey })
|
||||
|
||||
throw new Error(`The PR contains commits from a different base.`)
|
||||
}
|
||||
}
|
||||
|
||||
await dismissReviews({ github, context, core, dry, reviewKey })
|
||||
|
||||
let mergedSha, targetSha
|
||||
|
||||
if (prInfo.mergeable) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck
|
||||
async function handleReviewers({
|
||||
github,
|
||||
context,
|
||||
|
||||
@@ -1,31 +1,15 @@
|
||||
// @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<typeof 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: typeof import('@actions/core'),
|
||||
* github: InstanceType<import('@actions/github/lib/utils').GitHub>,
|
||||
* context: import('@actions/github/lib/context').Context,
|
||||
* core: import('@actions/core'),
|
||||
* dry: boolean,
|
||||
* reviewKey?: string,
|
||||
* }} DismissReviewsProps
|
||||
@@ -41,32 +25,18 @@ async function dismissReviews({ github, context, core, dry, reviewKey }) {
|
||||
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 reviews = (
|
||||
await github.paginate(github.rest.pulls.listReviews, {
|
||||
...context.repo,
|
||||
pull_number,
|
||||
})
|
||||
).filter(
|
||||
(review) =>
|
||||
review.user?.login === 'github-actions[bot]' &&
|
||||
review.state !== 'DISMISSED',
|
||||
)
|
||||
|
||||
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 changesRequestedReviews = reviews.filter(
|
||||
(review) => review.state === 'CHANGES_REQUESTED',
|
||||
)
|
||||
|
||||
const commentRegex = new RegExp(
|
||||
@@ -80,8 +50,8 @@ async function dismissReviews({ github, context, core, dry, reviewKey }) {
|
||||
)
|
||||
|
||||
let reviewsToMinimize = reviews
|
||||
const /** @type {ReviewWithNonNullUser[]} */ reviewsToDismiss = []
|
||||
const /** @type {ReviewWithNonNullUser[]} */ reviewsToResolve = []
|
||||
let /** @type {typeof reviews} */ reviewsToDismiss = []
|
||||
let /** @type {typeof reviews} */ reviewsToResolve = []
|
||||
|
||||
if (reviewKey && reviews.every((review) => commentRegex.test(review.body))) {
|
||||
reviewsToMinimize = reviews.filter((review) =>
|
||||
@@ -89,39 +59,29 @@ async function dismissReviews({ github, context, core, dry, reviewKey }) {
|
||||
)
|
||||
}
|
||||
|
||||
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,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
// If we want to dismiss all reviews with the key reviewKey,
|
||||
// but there are other requested changes from CI, we can't dismiss,
|
||||
// because then the other requested changes will be dismissed too.
|
||||
if (
|
||||
changesRequestedReviews.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 = changesRequestedReviews
|
||||
} else if (reviewsToMinimize.length) {
|
||||
reviewsToResolve = reviewsToMinimize.filter(
|
||||
(review) =>
|
||||
review.state === 'CHANGES_REQUESTED' &&
|
||||
!commentResolvedRegex.test(review.body),
|
||||
)
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
@@ -161,12 +121,12 @@ async function dismissReviews({ github, context, core, dry, reviewKey }) {
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* github: GitHub,
|
||||
* context: Context,
|
||||
* core: typeof import('@actions/core'),
|
||||
* github: InstanceType<import('@actions/github/lib/utils').GitHub>,
|
||||
* context: import('@actions/github/lib/context').Context
|
||||
* core: import('@actions/core'),
|
||||
* dry: boolean,
|
||||
* body: string,
|
||||
* event: keyof typeof eventToState,
|
||||
* event: keyof eventToState,
|
||||
* reviewKey: string,
|
||||
* }} PostReviewProps
|
||||
*/
|
||||
@@ -198,13 +158,11 @@ async function postReview({
|
||||
})
|
||||
).filter(
|
||||
(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]' &&
|
||||
review.state !== 'DISMISSED',
|
||||
)
|
||||
|
||||
/** @type {null | Review} */
|
||||
/** @type {null | typeof reviews[number]} */
|
||||
let pendingReview
|
||||
const matchingReviews = reviews.filter((review) =>
|
||||
reviewKeyRegex.test(review.body),
|
||||
|
||||
@@ -112,19 +112,8 @@ program
|
||||
.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 checkTargetBranch = (await import('./check-target-branch.ts')).default
|
||||
await run(checkTargetBranch, 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)
|
||||
const checkCommitMessages = (await import('./check-target-branch.js')).default
|
||||
await run(checkCommitMessages, owner, repo, pr, options)
|
||||
})
|
||||
|
||||
await program.parse()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck
|
||||
module.exports = async ({ github, context, targetSha }) => {
|
||||
const { content, encoding } = (
|
||||
await github.rest.repos.getContent({
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"es2024",
|
||||
"ESNext.Array",
|
||||
"ESNext.Collection",
|
||||
"ESNext.Error",
|
||||
"ESNext.Iterator",
|
||||
"ESNext.Promise"
|
||||
],
|
||||
"module": "nodenext",
|
||||
"target": "es2024",
|
||||
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "node16",
|
||||
|
||||
"allowImportingTsExtensions": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck
|
||||
module.exports = async ({ github, core, maxConcurrent = 1 }, callback) => {
|
||||
const Bottleneck = require('bottleneck')
|
||||
|
||||
|
||||
@@ -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
|
||||
''
|
||||
|
||||
@@ -9,23 +9,23 @@
|
||||
},
|
||||
"branch": "nixpkgs-unstable",
|
||||
"submodules": false,
|
||||
"revision": "7525d999cd850b9a488817abc89c75dc733acf17",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/7525d999cd850b9a488817abc89c75dc733acf17.tar.gz",
|
||||
"hash": "sha256-4IHyyLgLBdKefkljdKod4IMn023pQiDXAWJA187cmdY="
|
||||
"revision": "bde09022887110deb780067364a0818e89258968",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/bde09022887110deb780067364a0818e89258968.tar.gz",
|
||||
"hash": "13mi187zpa4rw680qbwp7pmykjia8cra3nwvjqmsjba3qhlzif5l"
|
||||
},
|
||||
"nixpkgs-26.05-darwin": {
|
||||
"treefmt-nix": {
|
||||
"type": "Git",
|
||||
"repository": {
|
||||
"type": "GitHub",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs"
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix"
|
||||
},
|
||||
"branch": "nixpkgs-26.05-darwin",
|
||||
"branch": "main",
|
||||
"submodules": false,
|
||||
"revision": "51fe96f9107566e6b8eeb7fc4ba696c01e548b04",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/51fe96f9107566e6b8eeb7fc4ba696c01e548b04.tar.gz",
|
||||
"hash": "sha256-yj0LPLnsmYoLmA3FGANjeTEwej0/DHjZBXWnDQDUuIs="
|
||||
"revision": "e96d59dff5c0d7fddb9d113ba108f03c3ef99eca",
|
||||
"url": "https://github.com/numtide/treefmt-nix/archive/e96d59dff5c0d7fddb9d113ba108f03c3ef99eca.tar.gz",
|
||||
"hash": "02gqyxila3ghw8gifq3mns639x86jcq079kvfvjm42mibx7z5fzb"
|
||||
}
|
||||
},
|
||||
"version": 8
|
||||
"version": 5
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
/*
|
||||
#!nix-shell -i node -p nodejs
|
||||
*/
|
||||
// @ts-nocheck
|
||||
|
||||
const typeConfig = {
|
||||
master: ['development', 'primary'],
|
||||
|
||||
175
ci/treefmt.nix
175
ci/treefmt.nix
@@ -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
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -217,38 +217,6 @@ 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
|
||||
|
||||
Readers look at examples first: an example communicates what something does faster than a description.
|
||||
Put examples before detailed explanations.
|
||||
|
||||
Prefer this structure for each documented item:
|
||||
|
||||
1. Title
|
||||
2. Abstract (optional, one sentence max, the example often speaks for itself)
|
||||
3. Example
|
||||
4. Explanation (details, edge cases, types, defaults)
|
||||
|
||||
For instance:
|
||||
|
||||
````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
|
||||
|
||||
@@ -920,14 +920,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 +942,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=";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -129,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.
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
pkgs ? (import ../ci { }).docPkgs,
|
||||
pkgs ? (import ../ci { }).pkgs,
|
||||
nixpkgs ? { },
|
||||
}:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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,7 +20,6 @@ ghc.section.md
|
||||
gnome.section.md
|
||||
haredo.section.md
|
||||
installShellFiles.section.md
|
||||
installFonts.section.md
|
||||
julec.section.md
|
||||
just.section.md
|
||||
libglycin.section.md
|
||||
@@ -30,11 +28,6 @@ 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
|
||||
|
||||
@@ -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
|
||||
'';
|
||||
}
|
||||
```
|
||||
@@ -1,29 +0,0 @@
|
||||
# nodejsInstallExecutables {#nodejs-install-executables}
|
||||
|
||||
Hook for wrapping Node.js executables.
|
||||
Primarily created for a multi-language environment.
|
||||
|
||||
## Examples {#nodejs-install-executables-example}
|
||||
|
||||
[](#npm-build-hook-example-snippet)
|
||||
|
||||
## Variables controlling `nodejsInstallExecutables` {#nodejs-install-executables-variables}
|
||||
|
||||
### `nodejsInstallExecutables` Exclusive Variables {#nodejs-install-executables-exclusive-variables}
|
||||
|
||||
#### `makeWrapperArgs` {#nodejs-install-executables-wrapper-args}
|
||||
|
||||
Flags to pass to the call to [`makeWrapper`](#fun-makeWrapper).
|
||||
To avoid double-wrapping, this flag can also be accessed in Bash.
|
||||
|
||||
```nix
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
#...
|
||||
dontWrapGApps = true;
|
||||
|
||||
postInstall = ''
|
||||
makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
|
||||
'';
|
||||
#...
|
||||
})
|
||||
```
|
||||
@@ -1,12 +0,0 @@
|
||||
# nodejsInstallManuals {#nodejs-install-manuals}
|
||||
|
||||
Detects manuals in Node.js packages, and attempts to install them in standard locations.
|
||||
This detection is done by inspecting the package.json of the project and finding any entries
|
||||
with type `man`.
|
||||
|
||||
|
||||
There are no ways currently to configure this hook.
|
||||
|
||||
## Examples {#nodejs-install-manuals-example}
|
||||
|
||||
[](#npm-build-hook-example-snippet)
|
||||
@@ -1,93 +0,0 @@
|
||||
# npmHooks.npmBuildHook {#npm-build-hook}
|
||||
|
||||
Hook for building packages that use npm. Can be used in multi-language environments.
|
||||
|
||||
## Examples {#npm-build-hook-snippet}
|
||||
|
||||
:::{.example #npm-build-hook-example-snippet}
|
||||
|
||||
# Using `npmHooks`
|
||||
|
||||
```nix
|
||||
{
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
fetchNpmDeps,
|
||||
npmHooks,
|
||||
nodejsInstallExecutables,
|
||||
nodejsInstallManuals,
|
||||
nodejs,
|
||||
}:
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "some-npm-project";
|
||||
version = "1.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "JohnNpm";
|
||||
repo = "SomeProject";
|
||||
tag = finalAttrs.version;
|
||||
hash = "...";
|
||||
};
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
nativeBuildInputs = [
|
||||
nodejs
|
||||
nodejsInstallExecutables
|
||||
nodejsInstallManuals
|
||||
npmHooks.npmConfigHook
|
||||
npmHooks.npmBuildHook
|
||||
npmHooks.npmInstallHook
|
||||
];
|
||||
|
||||
npmBuildScript = "build";
|
||||
|
||||
npmBuildFlags = [
|
||||
"--prod"
|
||||
];
|
||||
|
||||
npmFlags = [
|
||||
"--ignore-scripts"
|
||||
];
|
||||
|
||||
npmDeps = fetchNpmDeps {
|
||||
inherit (finalAttrs) src;
|
||||
hash = "...";
|
||||
};
|
||||
|
||||
makeWrapperArgs = [
|
||||
"--set"
|
||||
"NODE_ENV"
|
||||
"production"
|
||||
];
|
||||
|
||||
meta = {
|
||||
description = "npm project";
|
||||
};
|
||||
})
|
||||
```
|
||||
:::
|
||||
|
||||
## Variables controlling `npmBuildHook` {#npm-build-hook-variables}
|
||||
|
||||
### `npmBuildHook` Exclusive Variables {#npm-build-hook-exclusive-variables}
|
||||
|
||||
#### `npmBuildScript` {#npm-build-hook-script}
|
||||
|
||||
Controls the script ran to build the npm package within the `package.json` file.
|
||||
Required to be set, usually to `build`, but can vary between packages.
|
||||
|
||||
#### `npmBuildFlags` {#npm-build-hook-flags}
|
||||
|
||||
Controls the arguments to the {command}`npm run $npmBuildScript` command.
|
||||
|
||||
#### `dontNpmBuild` {#npm-build-hook-dont}
|
||||
|
||||
Disables `npmBuildHook` when enabled
|
||||
|
||||
### Honored Variables {#npm-build-hook-honored-variables}
|
||||
|
||||
The following variables are honored by the `npmBuildHook`.
|
||||
|
||||
- [`npmWorkspace`](#javascript-buildNpmPackage-npmWorkspace)
|
||||
- [`npmFlags`](#javascript-buildNpmPackage-npmFlags)
|
||||
@@ -1,41 +0,0 @@
|
||||
# npmHooks.npmConfigHook {#npm-config-hook}
|
||||
|
||||
Hook for configuring packages that use npm.
|
||||
Primarily made for a multi-language environment.
|
||||
|
||||
## Examples {#npm-config-hook-snippet}
|
||||
|
||||
[](#npm-build-hook-example-snippet)
|
||||
|
||||
## Variables controlling `npmConfigHook` {#npm-config-hook-variables}
|
||||
|
||||
### `npmConfigHook` Exclusive Variables {#npm-config-hook-exclusive-variables}
|
||||
|
||||
#### `npmDeps` {#npm-config-hook-deps}
|
||||
|
||||
Derivation that contains the npm package dependencies.
|
||||
Usually built with `fetchNpmDeps`.
|
||||
This attribute is required or the hook will abort the build.
|
||||
|
||||
#### `makeCacheWritable` {#npm-config-hook-writable-cache}
|
||||
|
||||
Whether to make the dependency cache writable prior to installing the dependencies.
|
||||
Don't set this unless npm tries to write to the cache directory.
|
||||
|
||||
#### `npmInstallFlags` {#npm-config-hook-install-flags}
|
||||
|
||||
Flags to pass to the {command}`npm ci` call for installing the dependencies to the build environment.
|
||||
Defaults to `--ignore-scripts`, which cannot be removed.
|
||||
This does not control anything with the `npmInstallHook`.
|
||||
|
||||
#### `npmRebuildFlags` {#npm-config-hook-rebuild-flags}
|
||||
|
||||
Flags to pass to the {command}`npm rebuild` command after the dependencies are installed to the environment.
|
||||
|
||||
### Honored Variables {#npm-config-hook-honored-variables}
|
||||
|
||||
The following variables are honored by the `npmConfigHook`.
|
||||
|
||||
- [`npmWorkspace`](#javascript-buildNpmPackage-npmWorkspace)
|
||||
- [`npmFlags`](#javascript-buildNpmPackage-npmFlags)
|
||||
- `npmRoot`
|
||||
@@ -1,35 +0,0 @@
|
||||
# npmHooks.npmInstallHook {#npm-install-hook}
|
||||
|
||||
Hook to install node_modules for npm packages.
|
||||
Does not create wrappers for executable npm projects
|
||||
Primarily made for a multi-language environment.
|
||||
|
||||
## Examples {#npm-install-hook-snippet}
|
||||
|
||||
[](#npm-build-hook-example-snippet)
|
||||
|
||||
## Variables controlling `npmInstallHook` {#npm-install-hook-variables}
|
||||
|
||||
### `npmInstallHook` Exclusive Variables {#npm-install-hook-exclusive-variables}
|
||||
|
||||
#### `dontNpmPrune` {#npm-install-hook-dont-prune}
|
||||
|
||||
Whether to run {command}`npm prune` on the `node_modules` or not.
|
||||
Defaults to `true`.
|
||||
|
||||
#### `npmInstallFlags` {#npm-install-hook-prune-flags}
|
||||
|
||||
Flags to pass to the {command}`npm prune` call for the `node_modules` of the package.
|
||||
Defaults to `--omit=dev --no-save` which cannot be modified.
|
||||
|
||||
#### `dontNpmInstall` {#npm-install-hook-dont}
|
||||
|
||||
Controls whether `npmInstallHook` is enabled or not.
|
||||
Defaults to `true`, so the hook will run.
|
||||
|
||||
### Honored Variables {#npm-install-hook-honored-variables}
|
||||
|
||||
The following variables are honored by the `npmInstallHook`.
|
||||
|
||||
- [`npmWorkspace`](#javascript-buildNpmPackage-npmWorkspace)
|
||||
- [`npmFlags`](#javascript-buildNpmPackage-npmFlags)
|
||||
@@ -27,7 +27,7 @@ Alternatively, you can pass composeAndroidPackages to the `withSdk` passthrough:
|
||||
}
|
||||
```
|
||||
|
||||
These will export `ANDROID_HOME` and `ANDROID_NDK_ROOT` to the SDK and NDK directories
|
||||
These will export `ANDROID_SDK_ROOT` and `ANDROID_NDK_ROOT` to the SDK and NDK directories
|
||||
in the specified Android build environment.
|
||||
|
||||
## Deploying an Android SDK installation with plugins {#deploying-an-android-sdk-installation-with-plugins}
|
||||
@@ -308,7 +308,7 @@ Ensure that your buildToolsVersion and ndkVersion match what is declared in andr
|
||||
If you are using cmake, make sure its declared version is correct too.
|
||||
|
||||
Otherwise, you may get cryptic errors from aapt2 and the Android Gradle plugin warning
|
||||
that it cannot install the build tools because the SDK directory is not writable.
|
||||
that it cannot install the build tools because the SDK directory is not writeable.
|
||||
|
||||
```gradle
|
||||
android {
|
||||
|
||||
@@ -6,68 +6,46 @@ In this document and related Nix expressions, we use the term, _BEAM_, to descri
|
||||
|
||||
## Available versions and deprecations schedule {#available-versions-and-deprecations-schedule}
|
||||
|
||||
### Erlang OTP {#erlang}
|
||||
|
||||
Nixpkgs follows upstream Erlang in their [support lifecycle](https://erlang.org/download/otp_versions_tree.html) and keeps up to the last 3 released versions of Erlang available. Due to upstream and NixOS release timings, this may mean removal of the oldest release prior to upstream fully dropping support.
|
||||
|
||||
### Elixir {#elixir}
|
||||
|
||||
Nixpkgs follows the [official elixir deprecation schedule](https://hexdocs.pm/elixir/compatibility-and-deprecations.html) and keeps up to the last 5 released versions of Elixir available.
|
||||
Nixpkgs follows the [official elixir deprecation schedule](https://hexdocs.pm/elixir/compatibility-and-deprecations.html) and keeps the last 5 released versions of Elixir available.
|
||||
|
||||
## Structure {#beam-structure}
|
||||
|
||||
All BEAM-related expressions are available via top-level package sets. It is recommended to work with a single package set to ensure consistent versions.
|
||||
All BEAM-related expressions are available via the top-level `beam` attribute, which includes:
|
||||
|
||||
- `beamPackages` - default OTP version
|
||||
- `beamMinimalPackages` - default OTP version, without wxwidgets, which saves ~1GB in closure size
|
||||
- `interpreters`: a set of compilers running on the BEAM, including multiple Erlang/OTP versions (`beam.interpreters.erlang_22`, etc), Elixir (`beam.interpreters.elixir`) and LFE (Lisp Flavoured Erlang) (`beam.interpreters.lfe`).
|
||||
|
||||
There are also OTP version specific package sets, e.g. for OTP 28:
|
||||
- `packages`: a set of package builders (Mix and rebar3), each compiled with a specific Erlang/OTP version, e.g. `beam.packages.erlang22`.
|
||||
|
||||
- `beam28Packages`
|
||||
- `beamMinimal28Packages`
|
||||
The default Erlang compiler, defined by `beam.interpreters.erlang`, is aliased as `erlang`. The default BEAM package set is defined by `beam.packages.erlang` and aliased at the top level as `beamPackages`.
|
||||
|
||||
Inside each package set are:
|
||||
To create a package builder built with a custom Erlang version, use the lambda, `beam.packagesWith`, which accepts an Erlang/OTP derivation and produces a package builder similar to `beam.packages.erlang`.
|
||||
|
||||
- erlang itself (version comes from package set)
|
||||
- interpreters: elixir (multiple versions, e.g. elixir_1_18) and lfe
|
||||
- packages: rebar3, hex, etc
|
||||
- builders: mixRelease, buildRebar3, etc
|
||||
- hooks: for composing builders and packages
|
||||
Many Erlang/OTP distributions available in `beam.interpreters` have versions with ODBC and/or Java enabled or without wx (no observer support). For example, there's `beam.interpreters.erlang_22_odbc_javac`, which corresponds to `beam.interpreters.erlang_22` and `beam.interpreters.erlang_22_nox`, which corresponds to `beam.interpreters.erlang_22`.
|
||||
|
||||
To use a non-default Elixir it's important to keep the rest of the package set consistent, so it's recommended to use `.extend`. This ensures that builders like `mixRelease`, `fetchMixDeps`, and `buildMix` all pick up the overridden Elixir:
|
||||
## Build Tools {#build-tools}
|
||||
|
||||
```nix
|
||||
let
|
||||
beamPackages = beam27Packages.extend (self: super: { elixir = self.elixir_1_18; });
|
||||
in
|
||||
beamPackages.mixRelease {
|
||||
# ...
|
||||
}
|
||||
```
|
||||
### Rebar3 {#build-tools-rebar3}
|
||||
|
||||
## Build Tools {#beam-build-tools}
|
||||
We provide a version of Rebar3, under `rebar3`. We also provide a helper to fetch Rebar3 dependencies from a lockfile under `fetchRebar3Deps`.
|
||||
|
||||
### Rebar3 {#beam-build-tools-rebar3}
|
||||
|
||||
We provide a version of Rebar3, under `beamPackages.rebar3`. We also provide a helper to fetch Rebar3 dependencies from a lockfile under `beamPackages.fetchRebar3Deps`.
|
||||
|
||||
We also provide a version on Rebar3 with plugins included, under `beamPackages.rebar3WithPlugins`. This package is a function which takes two arguments: `plugins`, a list of nix derivations to include as plugins (loaded only when specified in `rebar.config`), and `globalPlugins`, which should always be loaded by rebar3. Example: `beamPackages.rebar3WithPlugins { globalPlugins = [beamPackages.pc]; }`.
|
||||
We also provide a version on Rebar3 with plugins included, under `rebar3WithPlugins`. This package is a function which takes two arguments: `plugins`, a list of nix derivations to include as plugins (loaded only when specified in `rebar.config`), and `globalPlugins`, which should always be loaded by rebar3. Example: `rebar3WithPlugins { globalPlugins = [beamPackages.pc]; }`.
|
||||
|
||||
When adding a new plugin it is important that the `name` attribute is the same as the atom used by rebar3 to refer to the plugin.
|
||||
|
||||
### Erlang.mk {#beam-build-tools-erlangmk}
|
||||
### Mix & Erlang.mk {#build-tools-other}
|
||||
|
||||
Erlang.mk works exactly as expected. There is a bootstrap process that needs to be run, which is supported by the `buildErlangMk` derivation.
|
||||
|
||||
### Mix {#beam-build-tools-mix}
|
||||
For Elixir applications use `mixRelease` to make a release. See examples for more details.
|
||||
|
||||
For Elixir applications that use [mix release](https://hexdocs.pm/mix/Mix.Release.html), use the `mixRelease` builder to make a release. See examples for more details.
|
||||
|
||||
There is also a `buildMix` helper, whose behavior is closer to that of `buildErlangMk` and `buildRebar3`. The primary difference is that `mixRelease` makes a release, while `buildMix` only builds the package, which is more useful for libraries and other dependencies.
|
||||
There is also a `buildMix` helper, whose behavior is closer to that of `buildErlangMk` and `buildRebar3`. The primary difference is that mixRelease makes a release, while buildMix only builds the package, making it useful for libraries and other dependencies.
|
||||
|
||||
## How to Install BEAM Packages {#how-to-install-beam-packages}
|
||||
|
||||
To use any of these builders in your environment, refer to them by their attribute path under `beamPackages` (or another BEAM package set), e.g. `beamPackages.rebar3`:
|
||||
BEAM builders are not registered at the top level, because they are not relevant to the vast majority of Nix users.
|
||||
To use any of those builders into your environment, refer to them by their attribute path under `beamPackages`, e.g. `beamPackages.rebar3`:
|
||||
|
||||
::: {.example #ex-beam-ephemeral-shell}
|
||||
# Ephemeral shell
|
||||
@@ -97,39 +75,35 @@ pkgs.mkShell { packages = [ pkgs.beamPackages.rebar3 ]; }
|
||||
|
||||
#### Rebar3 Packages {#rebar3-packages}
|
||||
|
||||
The builder `beamPackages.buildRebar3` can be used to build a derivation that understands how to build a Rebar3 project.
|
||||
The Nix function, `buildRebar3`, defined in `beam.packages.erlang.buildRebar3` and aliased at the top level, can be used to build a derivation that understands how to build a Rebar3 project.
|
||||
|
||||
If a package needs to compile native code via Rebar3's port compilation mechanism, add `compilePort = true;` to the derivation.
|
||||
|
||||
#### Erlang.mk Packages {#erlang-mk-packages}
|
||||
|
||||
Erlang.mk functions similarly to Rebar3, except we use `beamPackages.buildErlangMk` instead of `beamPackages.buildRebar3`.
|
||||
|
||||
If a package needs to compile native code via Erlang.mk's port compilation mechanism, add `compilePorts = true;` to the derivation.
|
||||
|
||||
### Elixir Applications {#packaging-elixir-applications}
|
||||
Erlang.mk functions similarly to Rebar3, except we use `buildErlangMk` instead of `buildRebar3`.
|
||||
|
||||
#### Mix Packages {#mix-packages}
|
||||
|
||||
`beamPackages.mixRelease` is used to make a release in the mix sense. Dependencies will need to be fetched with `beamPackages.fetchMixDeps` and passed to it.
|
||||
`mixRelease` is used to make a release in the mix sense. Dependencies will need to be fetched with `fetchMixDeps` and passed to it.
|
||||
|
||||
#### mixRelease - Elixir Phoenix example {#mix-release-elixir-phoenix-example}
|
||||
|
||||
There are 3 steps: frontend dependencies (javascript), backend dependencies (elixir), and the final derivation that puts both of those together.
|
||||
there are 3 steps: frontend dependencies (javascript), backend dependencies (elixir), and the final derivation that puts both of those together
|
||||
|
||||
##### mixRelease - Frontend dependencies (javascript) {#mix-release-javascript-deps}
|
||||
|
||||
For phoenix projects, inside of Nixpkgs you can either use `fetchYarnDeps` or `buildNpmPackage`. An example with `buildNpmPackage` can be found [here](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/pl/plausible/package.nix), and an example with `fetchYarnDeps` can be found [here](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/pi/pinchflat/package.nix).
|
||||
For phoenix projects, inside of Nixpkgs you can either use yarn2nix (mkYarnModule) or node2nix. An example with yarn2nix can be found [here](https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/web-apps/plausible/default.nix#L39). An example with node2nix will follow. To package something outside of nixpkgs, you have alternatives like [npmlock2nix](https://github.com/nix-community/npmlock2nix) or [nix-npm-buildpackage](https://github.com/serokell/nix-npm-buildpackage)
|
||||
|
||||
##### mixRelease - backend dependencies (mix) {#mix-release-mix-deps}
|
||||
|
||||
There are 2 ways to package backend dependencies: either per-dependency mix2nix or with a fixed-output-derivation (FOD).
|
||||
|
||||
When writing an elixir project targeting `mixRelease`, you can also consider using [deps_nix](https://github.com/code-supply/deps_nix) with `mixNixDeps`. `deps_nix` supports git dependencies, but is intended to be added to the project's `mix.exs` directly.
|
||||
There are 2 ways to package backend dependencies. With mix2nix and with a fixed-output-derivation (FOD).
|
||||
|
||||
###### mix2nix {#mix2nix}
|
||||
|
||||
`mix2nix` is a cli tool available in Nixpkgs. It will generate a Nix expression from a `mix.lock` file. It is quite standard in the 2nix tool series.
|
||||
|
||||
Note that currently mix2nix can't handle git dependencies inside the mix.lock file. If you have git dependencies, you can either add them manually (see [example](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/pl/pleroma/package.nix)) or use the FOD method.
|
||||
Note that currently mix2nix can't handle git dependencies inside the mix.lock file. If you have git dependencies, you can either add them manually (see [example](https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/pleroma/default.nix#L20)) or use the FOD method.
|
||||
|
||||
The advantage of using mix2nix is that nix will know your whole dependency graph. On a dependency update, this won't trigger a full rebuild and download of all the dependencies, where FOD will do so.
|
||||
|
||||
@@ -177,7 +151,7 @@ You will need to run the build process once to fix the hash to correspond to you
|
||||
|
||||
###### FOD {#fixed-output-derivation}
|
||||
|
||||
A fixed output derivation will download mix dependencies from the internet. To ensure reproducibility, a hash will be supplied. Note that mix is relatively reproducible. An FOD generating a different hash on each run hasn't been observed (as opposed to npm where the chances are relatively high). See [akkoma](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/ak/akkoma/package.nix) for a usage example of FOD.
|
||||
A fixed output derivation will download mix dependencies from the internet. To ensure reproducibility, a hash will be supplied. Note that mix is relatively reproducible. An FOD generating a different hash on each run hasn't been observed (as opposed to npm where the chances are relatively high). See [elixir-ls](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/beam-modules/elixir-ls/default.nix) for a usage example of FOD.
|
||||
|
||||
Practical steps
|
||||
|
||||
@@ -202,11 +176,12 @@ Note that if after you've replaced the value, nix suggests another hash, then mi
|
||||
Here is how your `default.nix` file would look for a Phoenix project.
|
||||
|
||||
```nix
|
||||
{
|
||||
# beam27Packages or beam29Packages is available if you need a particular version
|
||||
beamPackages,
|
||||
}:
|
||||
with import <nixpkgs> { };
|
||||
|
||||
let
|
||||
# beam.interpreters.erlang_26 is available if you need a particular version
|
||||
packages = beam.packagesWith beam.interpreters.erlang;
|
||||
|
||||
pname = "your_project";
|
||||
version = "0.0.1";
|
||||
|
||||
@@ -216,7 +191,7 @@ let
|
||||
};
|
||||
|
||||
# if using mix2nix you can use the mixNixDeps attribute
|
||||
mixFodDeps = beamPackages.fetchMixDeps {
|
||||
mixFodDeps = packages.fetchMixDeps {
|
||||
pname = "mix-deps-${pname}";
|
||||
inherit src version;
|
||||
# nix will complain and tell you the right value to replace this with
|
||||
@@ -225,8 +200,11 @@ let
|
||||
# if you have build time environment variables add them here
|
||||
MY_ENV_VAR = "my_value";
|
||||
};
|
||||
|
||||
nodeDependencies = (pkgs.callPackage ./assets/default.nix { }).shell.nodeDependencies;
|
||||
|
||||
in
|
||||
beamPackages.mixRelease {
|
||||
packages.mixRelease {
|
||||
inherit
|
||||
src
|
||||
pname
|
||||
@@ -237,6 +215,9 @@ beamPackages.mixRelease {
|
||||
MY_ENV_VAR = "my_value";
|
||||
|
||||
postBuild = ''
|
||||
ln -sf ${nodeDependencies}/lib/node_modules assets/node_modules
|
||||
npm run deploy --prefix ./assets
|
||||
|
||||
# for external task you need a workaround for the no deps check flag
|
||||
# https://github.com/phoenixframework/phoenix/issues/2690
|
||||
mix do deps.loadpaths --no-deps-check, phx.digest
|
||||
@@ -248,7 +229,7 @@ beamPackages.mixRelease {
|
||||
Setup will require the following steps:
|
||||
|
||||
- Move your secrets to runtime environment variables. For more information refer to the [runtime.exs docs](https://hexdocs.pm/mix/Mix.Tasks.Release.html#module-runtime-configuration). On a fresh Phoenix build that would mean that both `DATABASE_URL` and `SECRET_KEY` need to be moved to `runtime.exs`.
|
||||
- Generate a Nix expression for your frontend dependencies using `fetchNpmDeps`/`buildNpmPackage` or `fetchYarnDeps`, depending on whether the project uses npm or yarn
|
||||
- `cd assets` and `nix-shell -p node2nix --run "node2nix --development"` will generate a Nix expression containing your frontend dependencies
|
||||
- commit and push those changes
|
||||
- you can now `nix-build .`
|
||||
- To run the release, set the `RELEASE_TMP` environment variable to a directory that your program has write access to. It will be used to store the BEAM settings.
|
||||
@@ -267,7 +248,7 @@ in your project with the following
|
||||
}:
|
||||
|
||||
let
|
||||
release = pkgs.callPackage ./default.nix { };
|
||||
release = pkgs.callPackage ./default.nix;
|
||||
release_name = "app";
|
||||
working_directory = "/home/app";
|
||||
in
|
||||
@@ -339,10 +320,9 @@ Usually, we need to create a `shell.nix` file and do our development inside the
|
||||
|
||||
with pkgs;
|
||||
let
|
||||
# pin OTP via beam27Packages/beam28Packages/... and Elixir via .extend
|
||||
beamPackages = beam27Packages.extend (self: super: { elixir = self.elixir_1_18; });
|
||||
elixir = beam.packages.erlang_27.elixir_1_18;
|
||||
in
|
||||
mkShell { buildInputs = [ beamPackages.elixir ]; }
|
||||
mkShell { buildInputs = [ elixir ]; }
|
||||
```
|
||||
|
||||
### Using an overlay {#beam-using-overlays}
|
||||
@@ -357,7 +337,7 @@ let
|
||||
self: super: {
|
||||
elixir_1_18 = super.elixir_1_18.override {
|
||||
version = "1.18.1";
|
||||
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
||||
sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -375,17 +355,18 @@ Here is an example `shell.nix`.
|
||||
with import <nixpkgs> { };
|
||||
|
||||
let
|
||||
# pin OTP via beam27Packages/beam28Packages/... and Elixir via .extend
|
||||
beamPackages = beam27Packages.extend (self: super: { elixir = self.elixir_1_18; });
|
||||
|
||||
# define packages to install
|
||||
basePackages = [
|
||||
git
|
||||
beamPackages.elixir
|
||||
# replace with beam.packages.erlang.elixir_1_18 if you need
|
||||
beam.packages.erlang.elixir
|
||||
nodejs
|
||||
postgresql_14
|
||||
# only used for frontend dependencies
|
||||
# you are free to use yarn2nix as well
|
||||
nodePackages.node2nix
|
||||
# formatting js file
|
||||
prettier
|
||||
nodePackages.prettier
|
||||
];
|
||||
|
||||
inputs = basePackages ++ lib.optionals stdenv.hostPlatform.isLinux [ inotify-tools ];
|
||||
@@ -398,13 +379,13 @@ let
|
||||
export HEX_HOME=$PWD/.nix-mix
|
||||
# make hex from Nixpkgs available
|
||||
# `mix local.hex` will install hex into MIX_HOME and should take precedence
|
||||
export MIX_PATH="${beamPackages.hex}/lib/erlang/lib/hex/ebin"
|
||||
export MIX_PATH="${beam.packages.erlang.hex}/lib/erlang/lib/hex/ebin"
|
||||
export PATH=$MIX_HOME/bin:$HEX_HOME/bin:$PATH
|
||||
export LANG=C.UTF-8
|
||||
# keep your shell history in iex
|
||||
export ERL_AFLAGS="-kernel shell_history enabled"
|
||||
|
||||
# postgres related
|
||||
# postges related
|
||||
# keep all your db data in a folder inside the project
|
||||
export PGDATA="$PWD/db"
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ pkgs.buildEmscriptenPackage {
|
||||
|
||||
## Debugging {#declarative-debugging}
|
||||
|
||||
Use `nix-shell -I nixpkgs=/some/dir/nixpkgs -A emscriptenPackages.libz` and from there you can go through the individual steps. This makes it easy to build a good `unit test` or list the files of the project.
|
||||
Use `nix-shell -I nixpkgs=/some/dir/nixpkgs -A emscriptenPackages.libz` and from there you can go trough the individual steps. This makes it easy to build a good `unit test` or list the files of the project.
|
||||
|
||||
1. `nix-shell -I nixpkgs=/some/dir/nixpkgs -A emscriptenPackages.libz`
|
||||
2. `cd /tmp/`
|
||||
|
||||
@@ -105,7 +105,7 @@ Given the requirements above, the package expression would become messy quickly:
|
||||
}
|
||||
```
|
||||
|
||||
Fortunately, we have a [family of hooks]{#ssec-gnome-hooks-wrapgappshook} that automate this. They work in conjunction with other setup hooks that populate environment variables, and will then wrap all executables in `bin` and `libexec` directories using said variables. If a package has multiple outputs, these hooks will work on `outputBin` by default, or on the outputs listed in `wrapGAppsInOutputs` if set.
|
||||
Fortunately, we have a [family of hooks]{#ssec-gnome-hooks-wrapgappshook} that automate this. They work in conjunction with other setup hooks that populate environment variables, and will then wrap all executables in `bin` and `libexec` directories using said variables.
|
||||
|
||||
- [`wrapGAppsHook3`]{#ssec-gnome-hooks-wrapgappshook3} for GTK 3 apps. For convenience, it also adds `dconf.lib` for a GIO module implementing a GSettings backend using `dconf`, `gtk3` for GSettings schemas, and `librsvg` for GdkPixbuf loader to the closure.
|
||||
- [`wrapGAppsHook4`]{#ssec-gnome-hooks-wrapgappshook4} for GTK 4 apps. Same as `wrapGAppsHook3` but replaces `gtk3` with `gtk4`.
|
||||
|
||||
@@ -101,7 +101,6 @@ If `true`, the intermediate fetcher downloads dependencies from the
|
||||
|
||||
This is useful if your code depends on C code and `go mod tidy` does not include the needed sources to build or
|
||||
if any dependency has case-insensitive conflicts which will produce platform-dependent `vendorHash` checksums.
|
||||
It may also be needed if the module targets language version 1.16 or earlier, since vendoring compiles all dependencies against language version 1.16 in this case.
|
||||
|
||||
Defaults to `false`.
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Each supported language or software ecosystem has its own package set named `<la
|
||||
# Navigate Java compiler variants in `javaPackages` with `nix repl`
|
||||
|
||||
```shell-session
|
||||
$ nix repl -f '<nixpkgs>' -I nixpkgs=channel:nixpkgs-unstable
|
||||
$ nix repl '<nixpkgs>' -I nixpkgs=channel:nixpkgs-unstable
|
||||
nix-repl> javaPackages.<tab>
|
||||
javaPackages.compiler javaPackages.openjfx15 javaPackages.openjfx21 javaPackages.recurseForDerivations
|
||||
javaPackages.jogl_2_4_0 javaPackages.openjfx17 javaPackages.openjfx25
|
||||
@@ -79,7 +79,6 @@ ios.section.md
|
||||
java.section.md
|
||||
javascript.section.md
|
||||
julia.section.md
|
||||
lean4.section.md
|
||||
lisp.section.md
|
||||
lua.section.md
|
||||
maven.section.md
|
||||
|
||||
@@ -45,14 +45,17 @@ If a particular lock file is present, it is a strong indication of which package
|
||||
|
||||
It's better to try to use a Nix tool that understands the lock file.
|
||||
Using a different tool might give you a hard-to-understand error because different packages have been installed.
|
||||
An example of problems that could arise can be found [here](https://github.com/NixOS/nixpkgs/pull/126629).
|
||||
Upstream use npm, but this is an attempt to package it with `yarn2nix` (that uses yarn.lock).
|
||||
|
||||
Using a different tool forces you to commit a lock file to the repository.
|
||||
These files are fairly large, so when packaging for nixpkgs, this approach does not scale well.
|
||||
|
||||
Exceptions to this rule are:
|
||||
|
||||
- When you encounter one of the bugs from a Nix tool. In each of the tool-specific instructions, known problems will be detailed. If you have a problem with a particular tool, then it's best to try another tool, even if this means you will have to re-create a lock file and commit it to Nixpkgs.
|
||||
- When you encounter one of the bugs from a Nix tool. In each of the tool-specific instructions, known problems will be detailed. If you have a problem with a particular tool, then it's best to try another tool, even if this means you will have to re-create a lock file and commit it to Nixpkgs. In general `yarn2nix` has fewer known problems, and so a simple search in Nixpkgs will reveal many `yarn.lock` files committed.
|
||||
- Some lock files contain particular version of a package that has been pulled off npm for some reason. In that case, you can recreate upstream lock (by removing the original and `npm install`, `yarn`, ...) and commit this to nixpkgs.
|
||||
- The only tool that supports workspaces (a feature of npm that helps manage sub-directories with different package.json from a single top level package.json) is `yarn2nix`. If upstream has workspaces you should try `yarn2nix`.
|
||||
|
||||
### Try to use upstream package.json {#javascript-upstream-package-json}
|
||||
|
||||
@@ -89,14 +92,14 @@ Exceptions to this rule are:
|
||||
Each tool has an abstraction to just build the node_modules (dependencies) directory.
|
||||
You can always use the `stdenv.mkDerivation` with the node_modules to build the package (symlink the node_modules directory and then use the package build command).
|
||||
The node_modules abstraction can be also used to build some web framework frontends.
|
||||
For an example of this see how [plausible](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/pl/plausible/package.nix) is built.
|
||||
For an example of this see how [plausible](https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/web-apps/plausible/default.nix) is built. `mkYarnModules` to make the derivation containing node_modules.
|
||||
Then when building the frontend you can just symlink the node_modules directory.
|
||||
|
||||
## Tool-specific instructions {#javascript-tool-specific}
|
||||
|
||||
### buildNpmPackage {#javascript-buildNpmPackage}
|
||||
|
||||
`buildNpmPackage` allows you to package npm-based projects in Nixpkgs without the use of an auto-generated dependencies file.
|
||||
`buildNpmPackage` allows you to package npm-based projects in Nixpkgs without the use of an auto-generated dependencies file (as used in [node2nix](#javascript-node2nix)).
|
||||
It works by utilizing npm's cache functionality -- creating a reproducible cache that contains the dependencies of a project, and pointing npm to it.
|
||||
|
||||
Here's an example:
|
||||
@@ -144,10 +147,10 @@ If these are not defined, `npm pack` may miss some files, and no binaries will b
|
||||
* `npmDepsHash`: The output hash of the dependencies for this project. Can be calculated in advance with [`prefetch-npm-deps`](#javascript-buildNpmPackage-prefetch-npm-deps).
|
||||
* `makeCacheWritable`: Whether to make the cache writable prior to installing dependencies. Don't set this unless npm tries to write to the cache directory, as it can slow down the build.
|
||||
* `npmBuildScript`: The script to run to build the project. Defaults to `"build"`.
|
||||
* []{#javascript-buildNpmPackage-npmWorkspace} `npmWorkspace`: The workspace directory within the project to build and install.
|
||||
* `npmWorkspace`: The workspace directory within the project to build and install.
|
||||
* `dontNpmBuild`: Option to disable running the build script. Set to `true` if the package does not have a build script. Defaults to `false`. Alternatively, setting `buildPhase` explicitly also disables this.
|
||||
* `dontNpmInstall`: Option to disable running `npm install`. Defaults to `false`. Alternatively, setting `installPhase` explicitly also disables this.
|
||||
* []{#javascript-buildNpmPackage-npmFlags} `npmFlags`: Flags to pass to all npm commands.
|
||||
* `npmFlags`: Flags to pass to all npm commands.
|
||||
* `npmInstallFlags`: Flags to pass to `npm ci`.
|
||||
* `npmBuildFlags`: Flags to pass to `npm run ${npmBuildScript}`.
|
||||
* `npmPackFlags`: Flags to pass to `npm pack`.
|
||||
@@ -303,9 +306,28 @@ It's recommended to set `package-lock-only = true` in your project-local [`.npmr
|
||||
|
||||
This package puts the corepack wrappers for pnpm and yarn in your PATH, and they will honor the `packageManager` setting in the `package.json`.
|
||||
|
||||
### node2nix {#javascript-node2nix}
|
||||
|
||||
#### Preparation {#javascript-node2nix-preparation}
|
||||
|
||||
You will need to generate a Nix expression for the dependencies. Don't forget the `-l package-lock.json` if there is a lock file. Most probably you will need the `--development` to include the `devDependencies`
|
||||
|
||||
So the command will most likely be:
|
||||
```sh
|
||||
node2nix --development -l package-lock.json
|
||||
```
|
||||
|
||||
See `node2nix` [docs](https://github.com/svanderburg/node2nix) for more info.
|
||||
|
||||
#### Pitfalls {#javascript-node2nix-pitfalls}
|
||||
|
||||
- If upstream package.json does not have a "version" attribute, `node2nix` will crash. You will need to add it like shown in [the package.json section](#javascript-upstream-package-json).
|
||||
- `node2nix` has some [bugs](https://github.com/svanderburg/node2nix/issues/238) related to working with lock files from npm distributed with `nodejs_16`.
|
||||
- `node2nix` does not like missing packages from npm. If you see something like `Cannot resolve version: vue-loader-v16@undefined` then you might want to try another tool. The package might have been pulled off of npm.
|
||||
|
||||
### pnpm {#javascript-pnpm}
|
||||
|
||||
pnpm is available as the top-level package `pnpm`. Additionally, there are variants pinned to certain major versions, like `pnpm_8`, `pnpm_9`, `pnpm_10`, `pnpm_10_29_2` and `pnpm_11`, which support different sets of lock file versions.
|
||||
pnpm is available as the top-level package `pnpm`. Additionally, there are variants pinned to certain major versions, like `pnpm_8`, `pnpm_9` and `pnpm_10`, which support different sets of lock file versions.
|
||||
|
||||
When packaging an application that includes a `pnpm-lock.yaml`, you need to fetch the pnpm store for that project using a fixed-output-derivation. The function `fetchPnpmDeps` can create this pnpm store derivation. In conjunction, the setup hook `pnpmConfigHook` will prepare the build environment to install the pre-fetched dependencies store. Here is an example for a package that contains `package.json` and a `pnpm-lock.yaml` files using the fetcher and setup hook above:
|
||||
|
||||
@@ -313,18 +335,11 @@ When packaging an application that includes a `pnpm-lock.yaml`, you need to fetc
|
||||
{
|
||||
fetchPnpmDeps,
|
||||
nodejs,
|
||||
pnpm_11,
|
||||
pnpm,
|
||||
pnpmConfigHook,
|
||||
stdenv,
|
||||
}:
|
||||
let
|
||||
# It is recommended to pin pnpm to a major version, due to regular breaking changes in the store format
|
||||
# The latest major version is always available under `pkgs.pnpm`
|
||||
# Optionally override pnpm to use a custom nodejs version
|
||||
# Make sure that the same nodejs version is referenced in nativeBuildInputs
|
||||
# pnpm = pnpm_11.override { nodejs = nodejs_24; };
|
||||
pnpm = pnpm_11;
|
||||
in
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "foo";
|
||||
version = "0-unstable-1980-01-01";
|
||||
@@ -341,8 +356,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
|
||||
pnpmDeps = fetchPnpmDeps {
|
||||
inherit (finalAttrs) pname version src;
|
||||
inherit pnpm;
|
||||
fetcherVersion = 4;
|
||||
fetcherVersion = 3;
|
||||
hash = "...";
|
||||
};
|
||||
})
|
||||
@@ -364,7 +378,7 @@ It is highly recommended to use a pinned version of pnpm (i.e., `pnpm_9` or `pnp
|
||||
+let
|
||||
+ # Optionally override pnpm to use a custom nodejs version
|
||||
+ # Make sure that the same nodejs version is referenced in nativeBuildInputs
|
||||
+ # pnpm = pnpm_10.override { nodejs-slim = nodejs-slim_22; };
|
||||
+ # pnpm = pnpm_10.override { nodejs = nodejs_20; };
|
||||
+in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "foo";
|
||||
@@ -384,7 +398,7 @@ It is highly recommended to use a pinned version of pnpm (i.e., `pnpm_9` or `pnp
|
||||
pnpmDeps = fetchPnpmDeps {
|
||||
inherit (finalAttrs) pname version src;
|
||||
+ pnpm = pnpm_10;
|
||||
fetcherVersion = 4;
|
||||
fetcherVersion = 3;
|
||||
hash = "...";
|
||||
};
|
||||
})
|
||||
@@ -406,8 +420,6 @@ In case you are patching `package.json` or `pnpm-lock.yaml`, make sure to pass `
|
||||
}
|
||||
```
|
||||
|
||||
If needed, `dontPnpmConfigure = true;` can be used to fully disable `pnpmConfigHook` without manually removing it from inputs.
|
||||
|
||||
#### Dealing with `sourceRoot` {#javascript-pnpm-sourceRoot}
|
||||
|
||||
If the pnpm project is in a subdirectory, you can just define `sourceRoot` or `setSourceRoot` for `fetchPnpmDeps`.
|
||||
@@ -493,32 +505,40 @@ In this example, `prePnpmInstall` will be run by both `pnpmConfigHook` and by th
|
||||
|
||||
#### pnpm `fetcherVersion` {#javascript-pnpm-fetcherVersion}
|
||||
|
||||
This is the version of the output of `fetchPnpmDeps`. New packages should use `4`:
|
||||
This is the version of the output of `fetchPnpmDeps`, if you haven't set it already, you can use `1` with your current hash:
|
||||
|
||||
```nix
|
||||
{
|
||||
# ...
|
||||
pnpmDeps = fetchPnpmDeps {
|
||||
# ...
|
||||
fetcherVersion = 4;
|
||||
hash = "..."; # clear this hash and generate a new one
|
||||
fetcherVersion = 1;
|
||||
hash = "..."; # you can use your already set hash here
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
When upgrading to a newer `fetcherVersion`, you need to regenerate the hash.
|
||||
After upgrading to a newer `fetcherVersion`, you need to regenerate the hash:
|
||||
|
||||
```nix
|
||||
{
|
||||
# ...
|
||||
pnpmDeps = fetchPnpmDeps {
|
||||
# ...
|
||||
fetcherVersion = 2;
|
||||
hash = "..."; # clear this hash and generate a new one
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
This variable ensures that we can make changes to the output of `fetchPnpmDeps` without breaking existing hashes.
|
||||
Changes can include workarounds or bug fixes to existing PNPM issues.
|
||||
|
||||
##### Version history {#javascript-pnpm-fetcherVersion-versionHistory}
|
||||
|
||||
Version 3 is the recommended value for new packages. Versions 1 and 2 are deprecated and scheduled for removal in the 26.11 release; existing packages must migrate.
|
||||
|
||||
- 1: Initial version, nothing special.
|
||||
- 1: Initial version, nothing special
|
||||
- 2: [Ensure consistent permissions](https://github.com/NixOS/nixpkgs/pull/422975)
|
||||
- 3: [Build a reproducible tarball](https://github.com/NixOS/nixpkgs/pull/469950)
|
||||
- 4: [Dump SQLite database to an SQL file](https://github.com/NixOS/nixpkgs/pull/522703)
|
||||
|
||||
### Yarn {#javascript-yarn}
|
||||
|
||||
@@ -597,6 +617,139 @@ To install the package `yarnInstallHook` uses both `npm` and `yarn` to cleanup p
|
||||
|
||||
- `yarnKeepDevDeps`: Disables the removal of devDependencies from `node_modules` before installation.
|
||||
|
||||
#### yarn2nix {#javascript-yarn2nix}
|
||||
|
||||
> [!WARNING]
|
||||
> The `yarn2nix` functions have been deprecated in favor of `yarnConfigHook`, `yarnBuildHook` and `yarnInstallHook` (for Yarn v1) and `yarn-berry_*.*` tooling (Yarn v3 and v4). Documentation for `yarn2nix` functions still appears here for the sake of the packages that still use them. See also a tracking issue [#324246](https://github.com/NixOS/nixpkgs/issues/324246).
|
||||
|
||||
##### Preparation {#javascript-yarn2nix-preparation}
|
||||
|
||||
You will need at least a `yarn.lock` file. If upstream does not have one you need to generate it and reference it in your package definition.
|
||||
|
||||
If the downloaded files contain the `package.json` and `yarn.lock` files they can be used like this:
|
||||
|
||||
```nix
|
||||
{
|
||||
offlineCache = fetchYarnDeps {
|
||||
yarnLock = src + "/yarn.lock";
|
||||
hash = "....";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
##### mkYarnPackage {#javascript-yarn2nix-mkYarnPackage}
|
||||
|
||||
> [!WARNING]
|
||||
> The `mkYarnPackage` functions have been deprecated in favor of `yarnConfigHook`, `yarnBuildHook` and `yarnInstallHook` (for Yarn v1) and `yarn-berry_*.*` tooling (Yarn v3 and v4). Documentation for `mkYarnPackage` functions still appears here for the sake of the packages that still use them. See also a tracking issue [#324246](https://github.com/NixOS/nixpkgs/issues/324246).
|
||||
|
||||
`mkYarnPackage` will by default try to generate a binary. For packages only generating static assets (Svelte, Vue, React, Webpack, ...), you will need to explicitly override the build step with your instructions.
|
||||
|
||||
It's important to use the `--offline` flag. For example if you script is `"build": "something"` in `package.json` use:
|
||||
|
||||
```nix
|
||||
{
|
||||
nativeBuildInputs = [ writableTmpDirAsHomeHook ];
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
yarn --offline build
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
}
|
||||
```
|
||||
|
||||
The `distPhase` is packing the package's dependencies in a tarball using `yarn pack`. You can disable it using:
|
||||
|
||||
```nix
|
||||
{ doDist = false; }
|
||||
```
|
||||
|
||||
The configure phase can sometimes fail because it makes many assumptions that may not always apply. One common override is:
|
||||
|
||||
```nix
|
||||
{
|
||||
configurePhase = ''
|
||||
runHook preConfigure
|
||||
|
||||
ln -s $node_modules node_modules
|
||||
|
||||
runHook postConfigure
|
||||
'';
|
||||
}
|
||||
```
|
||||
|
||||
or if you need a writeable node_modules directory:
|
||||
|
||||
```nix
|
||||
{
|
||||
configurePhase = ''
|
||||
runHook preConfigure
|
||||
|
||||
cp -r $node_modules node_modules
|
||||
chmod +w node_modules
|
||||
|
||||
runHook postConfigure
|
||||
'';
|
||||
}
|
||||
```
|
||||
|
||||
##### mkYarnModules {#javascript-yarn2nix-mkYarnModules}
|
||||
|
||||
This will generate a derivation including the `node_modules` directory.
|
||||
If you have to build a derivation for an integrated web framework (Rails, Phoenix, etc.), this is probably the easiest way.
|
||||
|
||||
#### Overriding dependency behavior {#javascript-mkYarnPackage-overriding-dependencies}
|
||||
|
||||
In the `mkYarnPackage` record the property `pkgConfig` can be used to override packages when you encounter problems building.
|
||||
|
||||
For instance, say your package is throwing errors when trying to invoke node-sass:
|
||||
|
||||
```
|
||||
ENOENT: no such file or directory, scandir '/build/source/node_modules/node-sass/vendor'
|
||||
```
|
||||
|
||||
To fix this we will specify different versions of build inputs to use, as well as some post install steps to get the software built the way we want:
|
||||
|
||||
```nix
|
||||
mkYarnPackage rec {
|
||||
pkgConfig = {
|
||||
node-sass = {
|
||||
buildInputs = with final; [
|
||||
python
|
||||
libsass
|
||||
pkg-config
|
||||
];
|
||||
postInstall = ''
|
||||
LIBSASS_EXT=auto yarn --offline run build
|
||||
rm build/config.gypi
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
##### Pitfalls {#javascript-yarn2nix-pitfalls}
|
||||
|
||||
- If version is missing from upstream package.json, yarn will silently install nothing. In that case, you will need to override package.json as shown in the [package.json section](#javascript-upstream-package-json)
|
||||
- Having trouble with `node-gyp`? Try adding these lines to the `yarnPreBuild` steps:
|
||||
|
||||
```nix
|
||||
{
|
||||
yarnPreBuild = ''
|
||||
mkdir -p $HOME/.node-gyp/${nodejs.version}
|
||||
echo 9 > $HOME/.node-gyp/${nodejs.version}/installVersion
|
||||
ln -sfv ${nodejs}/include $HOME/.node-gyp/${nodejs.version}
|
||||
export npm_config_nodedir=${nodejs}
|
||||
'';
|
||||
}
|
||||
```
|
||||
|
||||
- The `echo 9` steps comes from this answer: <https://stackoverflow.com/a/49139496>
|
||||
- Exporting the headers in `npm_config_nodedir` comes from this issue: <https://github.com/nodejs/node-gyp/issues/1191#issuecomment-301243919>
|
||||
- `offlineCache` (described [above](#javascript-yarn2nix-preparation)) must be specified to avoid [Import From Derivation](#ssec-import-from-derivation) (IFD) when used inside Nixpkgs.
|
||||
|
||||
#### Yarn Berry v3/v4 {#javascript-yarn-v3-v4}
|
||||
Yarn Berry (v3 / v4) have similar formats, they start with blocks like these:
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# Lean 4 {#sec-language-lean4}
|
||||
|
||||
Lean 4 is a strict functional language with dependent types. `leanPackages` provides the toolchain and a curated set of libraries — including the full mathlib dependency tree — with its own Lean toolchain. A standalone compiler is also available as `pkgs.lean4` for use outside the package set.
|
||||
|
||||
## Building Lean 4 projects with `buildLakePackage` {#lean4-buildLakePackage}
|
||||
|
||||
```nix
|
||||
leanPackages.buildLakePackage {
|
||||
pname = "my-project";
|
||||
version = "0.1.0";
|
||||
src = ./.;
|
||||
leanDeps = with leanPackages; [ mathlib ];
|
||||
lakeHash = null; # all deps nix-managed; set to lib.fakeHash for Lake-managed deps
|
||||
}
|
||||
```
|
||||
|
||||
Dependencies are declared in the lakefile for Lake and in the Nix expression for Nix. `leanDeps` provides Nix-managed libraries whose `.olean` files — the default build artifact of the Lake library facet — are reused without recompilation. `buildLakePackage` injects them via `lake --packages`, which takes precedence over Lake's own dependency resolution, producing a hermetic build.
|
||||
|
||||
Sui generis among nixpkgs builders, `buildLakePackage` supports heterogeneous dependency resolution, in that Nix transparently substitutes for upstream-managed dependencies at per-package granularity: Nix-managed dependencies via `leanDeps` and Lake-managed dependencies via `lakeHash` compose in the same derivation. Setting `lakeHash = lib.fakeHash` and building will report the expected hash for a fixed-output derivation that pins what Lake would normally fetch, less Nix-managed dependencies. Nix-managed dependencies take precedence by name — so moving a dependency from `lakeHash` to `leanDeps` will change the expected hash — providing an on-ramp for projects to incrementally adopt nix-managed libraries. Setting `lakeHash = null` (the default) declares that all dependencies are Nix-managed and no fixed-output fetch is performed during the build.
|
||||
|
||||
A `lake-manifest.json` is required at the project root. If all dependencies are Nix-managed, an empty manifest suffices:
|
||||
|
||||
```json
|
||||
{"version":"1.1.0","packagesDir":".lake/packages","packages":[]}
|
||||
```
|
||||
|
||||
## Development shells {#lean4-dev-shells}
|
||||
|
||||
In `nix develop`, the scoped `lean4` and `buildLakePackage` provide the same toolchain used for hermetic builds. Note that Lake's normal dependency resolution is available in the shell — Lake may fetch dependencies not covered by `leanDeps` from the network, as is standard for Nix development shells.
|
||||
|
||||
## The `leanPackages` scope {#lean4-leanPackages}
|
||||
|
||||
`leanPackages` is a `lib.makeScope` with its own `lean4`. Overriding it propagates to all packages and to `buildLakePackage`:
|
||||
|
||||
```nix
|
||||
leanPackages.overrideScope (
|
||||
self: super: {
|
||||
lean4 = myCustomLean4;
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
The `lean4` supplied by `leanPackages` is binary-patched to ensure that the Lean language server discovers the wrapped `lake` rather than an unwrapped one. This is necessary because Lake's `serve` subcommand has a vexing invocation pattern: it derives `LAKE` from `IO.appPath` and unconditionally sets it in the spawned environment, bypassing any wrapper. The binary patch rewrites store path references so that this discovery mechanism finds the correct binary, enabling LSP integration — including the InfoView, which requires Lean-specific protocol extensions — without improper mutation of the user's project directory.
|
||||
|
||||
Note that `leanPackages.lean4` supplants Lake's built-in cache invalidation for dependencies in `/nix/store/`, deferring entirely to Nix's bespoke dependency model. Lake's trace validation — which checks compiler "hash," platform, and package identity — is gracefully subsumed by guarantees Nix already provides. Cache coherence responsibilities are delegated to the orchestrator of streamlined Nix integration.
|
||||
|
||||
For Emacs, `emacsPackages.nael` and `emacsPackages.nael-lsp` (eglot-based and lsp-mode-based respectively, available via MELPA) provide Lean 4 support including proof state display via eldoc. For VSCode (unfree) / VSCodium, `vscode-extensions.leanprover.lean4` is available. Editor packages discover the toolchain from `PATH`.
|
||||
|
||||
## Relationship to earlier Lean 4 Nix support {#lean4-history}
|
||||
|
||||
Users familiar with the per-module derivation approach (2020–2025) should note that `buildLakePackage` follows a different architecture. The earlier integration discovered dependencies at evaluation time via import-from-derivation — an ambitious attempt to reconcile declarative package management with fine-grained build semantics, ultimately undermined by Nix's own evaluation model. It was [removed upstream](https://github.com/leanprover/lean4/commit/535435955b482176e8d62a54deebcacdec0827db). `buildLakePackage` treats Lake as a build driver and uses Nix for package-level boundaries, while `nix develop` and `nix-shell` achieve feature parity with the vanilla Lake development experience.
|
||||
@@ -17,14 +17,14 @@ Consider the following package:
|
||||
maven,
|
||||
}:
|
||||
|
||||
maven.buildMavenPackage (finalAttrs: {
|
||||
maven.buildMavenPackage rec {
|
||||
pname = "jd-cli";
|
||||
version = "1.2.1";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "intoolswetrust";
|
||||
repo = "jd-cli";
|
||||
tag = "jd-cli-${finalAttrs.version}";
|
||||
tag = "jd-cli-${version}";
|
||||
hash = "sha256-rRttA5H0A0c44loBzbKH7Waoted3IsOgxGCD2VM0U/Q=";
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ maven.buildMavenPackage (finalAttrs: {
|
||||
license = lib.licenses.gpl3Plus;
|
||||
maintainers = with lib.maintainers; [ majiir ];
|
||||
};
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
This package calls `maven.buildMavenPackage` to do its work. The primary difference from `stdenv.mkDerivation` is the `mvnHash` variable, which is a hash of all of the Maven dependencies.
|
||||
@@ -133,7 +133,7 @@ step 2 which will most probably fail the build. The `go-offline` plugin cannot
|
||||
handle these so-called [dynamic dependencies](https://github.com/qaware/go-offline-maven-plugin?tab=readme-ov-file#dynamic-dependencies).
|
||||
In that case you must add these dynamic dependencies manually with:
|
||||
```nix
|
||||
maven.buildMavenPackage {
|
||||
maven.buildMavenPackage rec {
|
||||
manualMvnArtifacts = [
|
||||
# add dynamic test dependencies here
|
||||
"org.apache.maven.surefire:surefire-junit-platform:3.1.2"
|
||||
|
||||
@@ -64,7 +64,6 @@ For instance, `sqlite-lua` needs `g:sqlite_clib_path` to be set to work. Nixpkgs
|
||||
- `wrapRc`: Nix, not being able to write in your `$HOME`, loads the
|
||||
generated Neovim configuration via the `$VIMINIT` environment variable, i.e. : `export VIMINIT='lua dofile("/nix/store/…-init.lua")'`. This has side effects like preventing Neovim from sourcing your `init.lua` in `$XDG_CONFIG_HOME/nvim` (see bullet 7 of [`:help startup`](https://neovim.io/doc/user/starting.html#startup) in Neovim). Disable it if you want to generate your own wrapper. You can still reuse the generated vimscript init code via `neovim.passthru.initRc`.
|
||||
- `plugins`: A list of plugins to add to the wrapper.
|
||||
- `extraLuaPackages`: A function passed on to `lua.withPackages`
|
||||
- `withPython3`, `withNodeJs`, `withRuby` control when to enable neovim
|
||||
providers (see `:h provider`).
|
||||
|
||||
@@ -91,7 +90,6 @@ wrapNeovimUnstable neovim-unwrapped {
|
||||
(nvim-treesitter.withPlugins (p: [ p.nix p.python ]))
|
||||
hex-nvim
|
||||
];
|
||||
extraLuaPackages = lp: [ lp.mpack ];
|
||||
withPython3 = true;
|
||||
withNodeJs = false;
|
||||
withRuby = false;
|
||||
@@ -115,25 +113,6 @@ patch those plugins but expose the necessary configuration under
|
||||
`PLUGIN.passthru.initLua` for neovim plugins. For instance, the `unicode-vim` plugin
|
||||
needs the path towards a unicode database so we expose the following snippet `vim.g.Unicode_data_directory="${self.unicode-vim}/autoload/unicode"` under `vimPlugins.unicode-vim.passthru.initLua`.
|
||||
|
||||
### Plugin license overrides {#neovim-plugin-license-overrides}
|
||||
|
||||
Generated Vim and Neovim plugins get their `meta.license` from GitHub license metadata when possible.
|
||||
Some upstream repositories do not expose a license file that GitHub can detect, or only mention the license in a README.
|
||||
In those cases, add a manual `meta.license` override in [overrides.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/overrides.nix).
|
||||
|
||||
For example, if upstream documents that a plugin uses the Vim license but GitHub does not detect it:
|
||||
|
||||
```nix
|
||||
{
|
||||
foo-nvim = super.foo-nvim.overrideAttrs (old: {
|
||||
meta = old.meta // {
|
||||
# README says this plugin is distributed under the Vim license.
|
||||
license = lib.licenses.vim;
|
||||
};
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## LuaRocks based plugins {#neovim-luarocks-based-plugins}
|
||||
|
||||
In order to automatically handle plugin dependencies, several Neovim plugins
|
||||
|
||||
@@ -59,9 +59,6 @@ Here is a simple package example.
|
||||
- The library will be installed using the `angstrom.install` file that dune
|
||||
generates.
|
||||
|
||||
- It also accepts an optional `dunePackages` argument, if there is more than one
|
||||
dune package that needs to be built (see `zipperposition`)
|
||||
|
||||
```nix
|
||||
{
|
||||
lib,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user