phantom: resolve conflicts

This commit is contained in:
Reylak
2026-02-16 18:41:15 -03:00
16087 changed files with 204524 additions and 230278 deletions
+1 -3
View File
@@ -5,9 +5,7 @@
"ghcr.io/devcontainers/features/nix:1": {
// fails in the devcontainer sandbox, enable sandbox via config instead
"multiUser": false,
// TODO: nixfmt-rfc-style → nixfmt (once it's in a stable release)
// https://github.com/NixOS/nixpkgs/issues/425583
"packages": "nixpkgs.nixd,nixpkgs.nixfmt-rfc-style",
"packages": "nixpkgs.nixd,nixpkgs.nixfmt",
"useAttributePath": true,
"extraNixConfig": "experimental-features = nix-command flakes,sandbox = true"
}
+3
View File
@@ -310,3 +310,6 @@ c283f32d296564fd649ef3ed268c1f1f7b199c49 # !autorebase nix-shell --run treefmt
# treewide: clean up 'meta = with' pattern
567e8dfd8eddc5468e6380fc563ab8a27422ab1d
# nixfmt 1.2.0
28096cc5e3d8334fbe1845925f000f8c8c5e0aac # !autorebase nix-shell --run treefmt
+46 -6
View File
@@ -7,6 +7,8 @@ inputs:
description: "Whether and which SHA to checkout for the merge commit in the ./nixpkgs/untrusted folder."
target-as-trusted-at:
description: "Whether and which SHA to checkout for the target commit in the ./nixpkgs/trusted folder."
untrusted-pin-bump:
description: "Commit that bumps ci/pinned.json; when set, ./nixpkgs/untrusted and ./nixpkgs/untrusted-pinned are derived from this commit."
runs:
using: composite
@@ -15,8 +17,10 @@ runs:
env:
MERGED_SHA: ${{ inputs.merged-as-untrusted-at }}
TARGET_SHA: ${{ inputs.target-as-trusted-at }}
PIN_BUMP_SHA: ${{ inputs.untrusted-pin-bump }}
with:
script: |
const { rm, writeFile } = require('node:fs/promises')
const { spawn } = require('node:child_process')
const { join } = require('node:path')
@@ -52,13 +56,27 @@ runs:
return pinned.pins.nixpkgs.revision
}
// Getting the pin-bump diff via the API avoids issues with `git fetch`
// thin-packs not having enough base objects to be applied locally.
// Returns a unified diff suitable for `git apply`.
async function getPinBumpDiff(ref) {
const { data } = await github.rest.repos.getCommit({
mediaType: { format: 'diff' },
...context.repo,
ref,
})
return data
}
const pin_bump_sha = process.env.PIN_BUMP_SHA
const commits = [
{
sha: process.env.MERGED_SHA,
path: 'untrusted',
},
{
sha: await getPinnedSha(process.env.MERGED_SHA),
sha: await getPinnedSha(pin_bump_sha || process.env.MERGED_SHA),
path: 'untrusted-pinned'
},
{
@@ -89,8 +107,30 @@ runs:
}
// 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')
}))
await Promise.all(
commits.map(async ({ sha, path }) => {
await run('git', 'worktree', 'add', join('nixpkgs', path), sha, '--no-checkout')
await run('git', '-C', join('nixpkgs', path), 'sparse-checkout', 'disable')
await run('git', '-C', join('nixpkgs', path), 'checkout', '--progress')
})
)
// Apply pin bump to untrusted worktree
if (pin_bump_sha) {
console.log('Fetching ci/pinned.json bump commit:', pin_bump_sha)
await writeFile('pin-bump.patch', await getPinBumpDiff(pin_bump_sha))
console.log('Applying untrusted ci/pinned.json bump to ./nixpkgs/untrusted')
try {
await run('git', '-C', join('nixpkgs', 'untrusted'), 'apply', '--3way', join('..', '..', 'pin-bump.patch'))
} catch {
core.setFailed([
`Failed to apply ci/pinned.json bump commit ${pin_bump_sha}.`,
`This commit does not apply cleanly onto the untrusted base ${process.env.MERGED_SHA}.`,
`Please rebase the PR or ensure the pin bump is standalone.`
].join(' '))
return
} finally {
await rm('pin-bump.patch')
}
}
+1 -1
View File
@@ -26,7 +26,7 @@
- all:
- changed-files:
- any-glob-to-any-file:
- .github/actions/*
- .github/actions/**/*
- .github/workflows/*
- .github/labeler*.yml
- ci/**/*.*
+7
View File
@@ -316,6 +316,13 @@
- nixos/modules/services/x11/desktop-managers/mate.nix
- nixos/tests/mate.nix
- pkgs/desktops/mate/**/*
- pkgs/by-name/ca/caja/**/*
- pkgs/by-name/ca/caja-*/**/*
- pkgs/by-name/li/libmatekbd/**/*
- pkgs/by-name/li/libmatemixer/**/*
- pkgs/by-name/li/libmateweather/**/*
- pkgs/by-name/ma/marco/**/*
- pkgs/by-name/ma/mate-*/**/*
"6.topic: module system":
- any:
+3 -3
View File
@@ -10,18 +10,18 @@ Some architectural notes about key decisions and concepts in our workflows:
Thus they should be lowered to the minimum with `permissions: {}` in every workflow by default.
- By definition `pull_request_target` runs in the context of the **base** of the pull request.
This means, that the workflow files to run will be taken from the base branch, not the PR, and actions/checkout will not checkout the PR, but the base branch, by default.
This means that the workflow files to run will be taken from the base branch, not the PR, and actions/checkout will not checkout the PR, but the base branch, by default.
To protect our secrets, we need to make sure to **never execute code** from the pull request and always evaluate or build nix code from the pull request with the **sandbox enabled**.
- To test the pull request's contents, we checkout the "test merge commit".
This is a temporary commit that GitHub creates automatically as "what would happen, if this PR was merged into the base branch now?".
This is a temporary commit that GitHub creates automatically as "what would happen if this PR was merged into the base branch now?".
The checkout could be done via the virtual branch `refs/pull/<pr-number>/merge`, but doing so would cause failures when this virtual branch doesn't exist (anymore).
This can happen when the PR has conflicts, in which case the virtual branch is not created, or when the PR is getting merged while workflows are still running, in which case the branch won't exist anymore at the time of checkout.
Thus, we use the `prepare` job to check whether the PR is mergeable and the test merge commit exists and only then run the relevant jobs.
- Various workflows need to make comparisons against the base branch.
In this case, we checkout the parent of the "test merge commit" for best results.
Note, that this is not necessarily the same as the default commit that actions/checkout would use, which is also a commit from the base branch (see above), but might be older.
Note that this is not necessarily the same as the default commit that actions/checkout would use, which is also a commit from the base branch (see above), but might be older.
## Terminology
+2 -2
View File
@@ -36,7 +36,7 @@ jobs:
permission-pull-requests: write
permission-workflows: write
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.pull_request.head.sha }}
token: ${{ steps.app-token.outputs.token }}
@@ -49,7 +49,7 @@ jobs:
- name: Create backport PRs
id: backport
uses: korthout/backport-action@c656f5d5851037b2b38fb5db2691a03fa229e3b2 # v4.0.1
uses: korthout/backport-action@01619ebc9a6e3f6820274221b9956b3e7365000a # v4.1.0
with:
# Config README: https://github.com/korthout/backport-action#backport-action
copy_labels_pattern: 'severity:\ssecurity'
+5 -5
View File
@@ -46,14 +46,14 @@ jobs:
# https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: |
ci/github-script
- name: Install dependencies
run: npm install @actions/artifact bottleneck
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@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
@@ -97,7 +97,7 @@ jobs:
github.event_name == 'pull_request_target' &&
!contains(fromJSON(inputs.headBranch).type, 'development')
with:
repo-token: ${{ steps.app-token.outputs.token }}
repo-token: ${{ steps.app-token.outputs.token || github.token }}
configuration-path: .github/labeler.yml # default
sync-labels: true
@@ -107,7 +107,7 @@ jobs:
github.event_name == 'pull_request_target' &&
!contains(fromJSON(inputs.headBranch).type, 'development')
with:
repo-token: ${{ steps.app-token.outputs.token }}
repo-token: ${{ steps.app-token.outputs.token || github.token }}
configuration-path: .github/labeler-no-sync.yml
sync-labels: false
@@ -120,7 +120,7 @@ jobs:
github.event_name == 'pull_request_target' &&
contains(fromJSON(inputs.headBranch).type, 'development')
with:
repo-token: ${{ steps.app-token.outputs.token }}
repo-token: ${{ steps.app-token.outputs.token || github.token }}
configuration-path: .github/labeler-development-branches.yml
sync-labels: true
+5 -9
View File
@@ -41,7 +41,7 @@ jobs:
- runner: ubuntu-24.04-arm
name: aarch64-linux
systems: aarch64-linux
builds: [shell, manual-nixos, manual-nixpkgs, manual-nixpkgs-tests]
builds: [shell, manual-nixos, manual-nixpkgs]
desc: shell, docs
- runner: macos-14
name: darwin
@@ -52,7 +52,7 @@ jobs:
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -62,12 +62,12 @@ jobs:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
target-as-trusted-at: ${{ inputs.targetSha }}
- uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
- 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@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
- 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,11 +90,7 @@ jobs:
- name: Build Nixpkgs manual
if: contains(matrix.builds, 'manual-nixpkgs') && !cancelled()
run: nix-build-uncached nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A manual-nixpkgs -A manual-nixpkgs-tests
- name: Build Nixpkgs manual tests
if: contains(matrix.builds, 'manual-nixpkgs-tests') && !cancelled()
run: nix-build-uncached nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A manual-nixpkgs-tests
run: nix-build-uncached nixpkgs/untrusted/ci --arg nixpkgs ./nixpkgs/untrusted-pinned -A manual-nixpkgs
- name: Build lib tests
if: contains(matrix.builds, 'lib-tests') && !cancelled()
+5 -5
View File
@@ -35,7 +35,7 @@ jobs:
runs-on: ubuntu-slim
timeout-minutes: 3
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
path: trusted
@@ -43,7 +43,7 @@ jobs:
ci/github-script
- name: Install dependencies
run: npm install bottleneck
run: npm install bottleneck@2.19.5
- name: Log current API rate limits
env:
@@ -75,7 +75,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 5
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -85,9 +85,9 @@ jobs:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
target-as-trusted-at: ${{ inputs.targetSha }}
- uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
- uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
- 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.
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
timeout-minutes: 2
if: contains(github.event.comment.body, '@NixOS/nixpkgs-merge-bot merge')
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: |
+121 -19
View File
@@ -9,7 +9,11 @@ on:
mergedSha:
required: true
type: string
headSha:
required: false # only required when testVersions is true
type: string
targetSha:
required: true
type: string
systems:
required: true
@@ -36,8 +40,10 @@ jobs:
runs-on: ubuntu-slim
outputs:
versions: ${{ steps.versions.outputs.versions }}
ciPinBumpCommit: ${{ steps.find-pinned-commit.outputs.ciPinBumpCommit }}
ciPinBumpCommitShort: ${{ steps.find-pinned-commit.outputs.ciPinBumpCommitShort }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
path: trusted
@@ -45,7 +51,7 @@ jobs:
ci/supportedVersions.nix
- name: Check out the PR at the test merge commit
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
ref: ${{ inputs.mergedSha }}
@@ -53,8 +59,80 @@ jobs:
sparse-checkout: |
ci/pinned.json
- name: Find commit that touched ci/pinned.json
id: find-pinned-commit
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
TARGET_SHA: ${{ inputs.targetSha }}
HEAD_SHA: ${{ inputs.headSha }}
with:
script: |
const targetSha = process.env.TARGET_SHA
const headSha = process.env.HEAD_SHA
if (!targetSha || !headSha) {
core.setFailed('Error: Both targetSha and headSha inputs are required when testVersions is true.')
return
}
// Compare the two commits to get the list of commits in between
const comparison = await github.rest.repos.compareCommitsWithBasehead({
...context.repo,
basehead: `${targetSha}...${headSha}`,
})
if(comparison.data.commits.length > 50) {
core.setFailed('Error: Too many commits in comparison, cannot reliably find pinned.json change.')
return
}
const logRateLimit = async (label) => {
const { data } = await github.rest.rateLimit.get()
const { remaining, limit, used } = data.rate
core.info(`[Rate Limit ${label}] ${remaining}/${limit} remaining (${used} used)`)
}
await logRateLimit('before commit filtering')
// Filter commits that modified ci/pinned.json
const commitsModifyingPinned = (
await Promise.all(
comparison.data.commits.map(async (commit) => {
const commitDetails = await github.rest.repos.getCommit({
...context.repo,
ref: commit.sha,
})
const modifiesPinned = commitDetails.data.files?.some(
(file) => file.filename === "ci/pinned.json"
)
return modifiesPinned ? commit.sha : null
})
)
).filter((sha) => sha !== null)
await logRateLimit('after commit filtering')
if (commitsModifyingPinned.length === 0) {
// This should not happen as testVersions should only be true
// when ci/pinned.json was modified in the PR.
core.setFailed("Error: ci/pinned.json was not modified in this PR")
return
} else if (commitsModifyingPinned.length > 1) {
core.setFailed([
"Error: Multiple commits touch ci/pinned.json in this PR:",
...commitsModifyingPinned,
"Please ensure only a single commit modifies ci/pinned.json for accurate version matrix evaluation."
].join("\n"))
return
}
const ciPinBumpCommit = commitsModifyingPinned[0]
core.setOutput("ciPinBumpCommit", ciPinBumpCommit)
core.setOutput("ciPinBumpCommitShort", ciPinBumpCommit.substring(0, 7))
core.info(`Found pinned.json commit: ${ciPinBumpCommit}`)
- name: Install Nix
uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
- name: Load supported versions
id: versions
@@ -75,7 +153,7 @@ jobs:
# Failures for versioned Evals will be collected in a separate job below
# to not interrupt main Eval's compare step.
continue-on-error: ${{ matrix.version != '' }}
name: ${{ matrix.system }}${{ matrix.version && format(' @ {0}', matrix.version) || '' }}
name: ${{ matrix.system }}${{ matrix.version && format(' @ {0} ({1})', matrix.version, needs.versions.outputs.ciPinBumpCommitShort) || '' }}
timeout-minutes: 15
steps:
# This is not supposed to be used and just acts as a fallback.
@@ -89,20 +167,22 @@ jobs:
sudo mkswap /swap
sudo swapon /swap
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: .github/actions
- name: Check out the PR at merged and target commits
uses: ./.github/actions/checkout
with:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
# For versioned evals, use the target as the untrusted base and apply the pin-bump commit
merged-as-untrusted-at: ${{ matrix.version && inputs.targetSha || inputs.mergedSha }}
untrusted-pin-bump: ${{ matrix.version && needs.versions.outputs.ciPinBumpCommit }}
target-as-trusted-at: ${{ inputs.targetSha }}
- name: Install Nix
uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
- 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.
@@ -168,10 +248,11 @@ jobs:
needs: [eval]
if: ${{ !cancelled() && !failure() }}
permissions:
pull-requests: write
statuses: write
timeout-minutes: 5
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -189,7 +270,7 @@ jobs:
merge-multiple: true
- name: Install Nix
uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
- name: Combine all output paths and eval stats
run: |
@@ -254,6 +335,17 @@ jobs:
description,
target_url
})
- name: Request changes if PR is against an inappropriate branch
if: ${{ github.event_name == 'pull_request_target' }}
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
require('./nixpkgs/trusted/ci/github-script/check-target-branch.js')({
github,
context,
core,
dry: context.eventName == 'pull_request',
})
# Creates a matrix of Eval performance for various versions and systems.
report:
@@ -272,6 +364,7 @@ jobs:
ARTIFACT_PREFIX: ${{ inputs.artifact-prefix }}
SYSTEMS: ${{ inputs.systems }}
VERSIONS: ${{ needs.versions.outputs.versions }}
CI_PIN_BUMP_COMMIT: ${{ needs.versions.outputs.ciPinBumpCommit }}
with:
script: |
const { readFileSync } = require('node:fs')
@@ -280,8 +373,10 @@ jobs:
const prefix = process.env.ARTIFACT_PREFIX
const systems = JSON.parse(process.env.SYSTEMS)
const versions = JSON.parse(process.env.VERSIONS)
const ciPinBumpCommit = process.env.CI_PIN_BUMP_COMMIT
core.summary.addHeading('Lix/Nix version comparison')
core.summary.addRaw(`\n*Evaluated at commit: \`${ciPinBumpCommit}\` (commit that modified ci/pinned.json)*\n`, true)
core.summary.addTable(
[].concat(
[
@@ -312,7 +407,11 @@ jobs:
.filter((attr) => attr.split('.').length > 1)
if (attrs.length > 0) {
core.setFailed(
`${version} on ${system} has changed outpaths!\nNote: Please make sure to update ci/pinned.json separately from changes to other packages.`,
`${version} on ${system} has changed outpaths!\n` +
`Note: This indicates that commit ${ciPinBumpCommit} ` +
`(which modified ci/pinned.json) also contains other ` +
`changes affecting package outputs. ` +
`Please ensure ci/pinned.json is updated in a standalone commit.`
)
return { data: ':x:' }
}
@@ -342,7 +441,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -352,12 +451,15 @@ jobs:
merged-as-untrusted-at: ${{ inputs.mergedSha }}
- name: Install Nix
uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
- name: Run misc eval tasks in parallel
- name: Ensure flake outputs on all systems still evaluate
run: nix flake check --all-systems --no-build './nixpkgs/untrusted?shallow=1'
- name: Query nixpkgs with aliases enabled to check for basic syntax errors
run: |
# Ensure flake outputs on all systems still evaluate
nix flake check --all-systems --no-build './nixpkgs/untrusted?shallow=1' &
# Query nixpkgs with aliases enabled to check for basic syntax errors
nix-env -I ./nixpkgs/untrusted -f ./nixpkgs/untrusted -qa '*' --option restrict-eval true --option allow-import-from-derivation false >/dev/null &
wait
time nix-env -I ./nixpkgs/untrusted -f ./nixpkgs/untrusted -qa '*' --option restrict-eval true --option allow-import-from-derivation false >/dev/null
- name: Ensure NixOS modules meta is valid
run: |
time nix-instantiate -I ./nixpkgs/untrusted --strict --eval --json ./nixpkgs/untrusted/nixos --arg configuration '{}' --attr config.meta --option restrict-eval true --option allow-import-from-derivation false
+11 -12
View File
@@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- 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@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
- 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@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- 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@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
- uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
- 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@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- 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@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
- uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
- 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.
@@ -134,12 +134,10 @@ jobs:
runs-on: ubuntu-slim
timeout-minutes: 5
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
persist-credentials: true # Needed to run git fetch for large PRs.
path: trusted
sparse-checkout: |
ci/github-script
- name: Check commit messages
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
@@ -150,4 +148,5 @@ jobs:
github,
context,
core,
repoPath: 'trusted',
})
+2 -1
View File
@@ -25,7 +25,7 @@ jobs:
targetSha: ${{ steps.prepare.outputs.targetSha }}
systems: ${{ steps.prepare.outputs.systems }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: |
@@ -84,6 +84,7 @@ jobs:
# even though they are unused when working with the merge queue.
permissions:
# compare
pull-requests: write
statuses: write
secrets:
CACHIX_AUTH_TOKEN_GHA: ${{ secrets.CACHIX_AUTH_TOKEN_GHA }}
+2 -2
View File
@@ -34,7 +34,7 @@ jobs:
permission-contents: write
permission-pull-requests: write
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
@@ -65,5 +65,5 @@ jobs:
with:
issue-number: 105153
body: |
Periodic merge from `${{ inputs.from }}` into `${{ inputs.into }}` has [failed](https://github.com/NixOS/nixpkgs/actions/runs/${{ github.run_id }}).
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 }}).
token: ${{ steps.app-token.outputs.token }}
+3 -1
View File
@@ -31,7 +31,7 @@ jobs:
systems: ${{ steps.prepare.outputs.systems }}
touched: ${{ steps.prepare.outputs.touched }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout-cone-mode: true # default, for clarity
@@ -81,10 +81,12 @@ jobs:
uses: ./.github/workflows/eval.yml
permissions:
# compare
pull-requests: write
statuses: write
with:
artifact-prefix: ${{ inputs.artifact-prefix }}
mergedSha: ${{ needs.prepare.outputs.mergedSha }}
headSha: ${{ github.event.pull_request.head.sha }}
targetSha: ${{ needs.prepare.outputs.targetSha }}
systems: ${{ needs.prepare.outputs.systems }}
testVersions: ${{ contains(fromJSON(needs.prepare.outputs.touched), 'pinned') && !contains(fromJSON(needs.prepare.outputs.headBranch).type, 'development') }}
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-slim
timeout-minutes: 2
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: |
+3 -3
View File
@@ -30,7 +30,7 @@ jobs:
permission-pull-requests: write
- name: Fetch source
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: |
@@ -38,7 +38,7 @@ jobs:
maintainers/github-teams.json
- name: Install dependencies
run: npm install bottleneck
run: npm install bottleneck@2.19.5
- name: Synchronise teams
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
@@ -64,7 +64,7 @@ jobs:
echo "git-string=$name <$email>" >> "$GITHUB_OUTPUT"
- name: Create Pull Request
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
with:
token: ${{ steps.app-token.outputs.token }}
add-paths: maintainers/github-teams.json
+2 -2
View File
@@ -19,7 +19,7 @@ jobs:
push: ${{ steps.files.outputs.push }}
targetSha: ${{ steps.prepare.outputs.targetSha }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout-cone-mode: true # default, for clarity
@@ -40,7 +40,7 @@ jobs:
context,
core,
// Review comments will be posted by the main PR workflow on the pull_request_target event.
dry: false,
dry: true,
})
- name: Determine changed files
+7
View File
@@ -14,12 +14,19 @@ Janne Heß <janne@hess.ooo> <dasJ@users.noreply.github.com>
jopejoe1 <nixpkgs@missing.ninja>
jopejoe1 <nixpkgs@missing.ninja> <johannes@joens.email>
jopejoe1 <nixpkgs@missing.ninja> <34899572+jopejoe1@users.noreply.github.com>
jopejoe1 <nixpkgs@missing.ninja> <jopejoe1@missing.ninja>
jopejoe1 <nixpkgs@missing.ninja> <jopejoe1>
Jörg Thalheim <joerg@thalheim.io> <Mic92@users.noreply.github.com>
Lin Jian <me@linj.tech> <linj.dev@outlook.com>
Lin Jian <me@linj.tech> <75130626+jian-lin@users.noreply.github.com>
Martin Weinelt <hexa@darmstadt.ccc.de> <mweinelt@users.noreply.github.com>
Martin Häcker <spamfaenger@gmx.de> <spamfaenger@gmx.de>
moni <lythe1107@gmail.com> <lythe1107@icloud.com>
quantenzitrone <nix@dev.quantenzitrone.eu>
quantenzitrone <nix@dev.quantenzitrone.eu> <74491719+Quantenzitrone@users.noreply.github.com>
quantenzitrone <nix@dev.quantenzitrone.eu> <74491719+quantenzitrone@users.noreply.github.com>
quantenzitrone <nix@dev.quantenzitrone.eu> <general@dev.quantenzitrone.eu>
quantenzitrone <nix@dev.quantenzitrone.eu> <quantenzitrone@protonmail.com>
R. RyanTM <ryantm-bot@ryantm.com>
Robert Hensing <robert@roberthensing.nl> <roberth@users.noreply.github.com>
Sandro Jäckel <sandro.jaeckel@gmail.com>
+4 -5
View File
@@ -329,11 +329,10 @@ You can invoke the nixpkgs-merge-bot by commenting `@NixOS/nixpkgs-merge-bot mer
The bot will verify the following conditions, refusing to merge otherwise:
- the PR author should be @r-ryantm or a Nixpkgs committer;
- the invoker should be among the package maintainers;
- the invoker should be among the package maintainers on the targeted branch;
- the package should reside in `pkgs/by-name`.
Further, nixpkgs-merge-bot will ensure all CI checks and the ofborg builds for Linux have successfully completed before merging the pull request.
Should the checks still be underway, the bot will wait for them to finish before attempting the merge again.
Required status checks prevent PRs that fail them ("PR / ..." jobs) from being merged. Ofborg is not required by the checks.
For other pull requests, please see [I opened a PR, how do I get it merged?](#i-opened-a-pr-how-do-i-get-it-merged).
@@ -680,7 +679,7 @@ If you have any problems with formatting, please ping the [formatting team](http
{ buildInputs = if stdenv.hostPlatform.isDarwin then [ iconv ] else null; }
```
As an exception, an explicit conditional expression with null can be used when fixing a important bug without triggering a mass rebuild.
As an exception, an explicit conditional expression with null can be used when fixing an important bug without triggering a mass rebuild.
If this is done a follow up pull request _should_ be created to change the code to `lib.optional(s)`.
- Any style choices not covered here but that can be expressed as general rules should be left at the discretion of the authors of changes and _not_ commented in reviews.
@@ -865,7 +864,7 @@ If someone approved and didn't merge a few days later, they most likely just for
Please see it as your responsibility to actively remind reviewers of your open PRs.
The easiest way to do so is to notify them via GitHub.
Github notifies people involved, whenever you add a comment or push to your PR or re-request their review.
GitHub notifies people involved, whenever you add a comment or push to your PR or re-request their review.
Doing any of that will get their attention again.
Everyone deserves proper attention, and yes, that includes you!
However, please be mindful that committers can sadly not always give everyone the attention they deserve.
+1 -1
View File
@@ -70,7 +70,7 @@ For more information about contributing to the project, please visit the [contri
The infrastructure for NixOS and related projects is maintained by a nonprofit organization, the [NixOS Foundation](https://nixos.org/nixos/foundation.html).
To ensure the continuity and expansion of the NixOS infrastructure, we are looking for donations to our organization.
You can donate to the NixOS foundation through [SEPA bank transfers](https://nixos.org/donate.html) or by using Open Collective:
You can donate to the NixOS Foundation through [SEPA bank transfers](https://nixos.org/donate.html) or by using Open Collective:
<a href="https://opencollective.com/nixos#support"><img src="https://opencollective.com/nixos/tiers/supporter.svg?width=890" /></a>
+9 -9
View File
@@ -36,7 +36,7 @@
/maintainers/computed-team-list.nix @infinisil
## Standard environmentrelated libraries
/lib/customisation.nix @alyssais @NixOS/stdenv
/lib/derivations.nix @alyssais @NixOS/stdenv
/lib/derivations.nix @NixOS/stdenv
/lib/fetchers.nix @alyssais @NixOS/stdenv
/lib/meta.nix @alyssais @NixOS/stdenv
/lib/source-types.nix @alyssais @NixOS/stdenv
@@ -247,7 +247,6 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lo
/pkgs/applications/networking/browsers/firefox/update.nix
/pkgs/applications/networking/browsers/firefox/packages/firefox.nix @mweinelt
/pkgs/applications/networking/browsers/firefox/packages/firefox-esr-*.nix @mweinelt
/pkgs/applications/networking/browsers/librewolf @squalus @DominicWrege @fpletz
/pkgs/applications/networking/browsers/chromium @emilylange @networkException
/nixos/tests/chromium.nix @emilylange @networkException
@@ -400,9 +399,9 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/pkgs/applications/blockchains @mmahut @RaghavSood
# Go
/doc/languages-frameworks/go.section.md @kalbasit @katexochen @Mic92 @zowoq
/pkgs/build-support/go @kalbasit @katexochen @Mic92 @zowoq
/pkgs/development/compilers/go @kalbasit @katexochen @Mic92 @zowoq
/doc/languages-frameworks/go.section.md @kalbasit @katexochen @Mic92
/pkgs/build-support/go @kalbasit @katexochen @Mic92
/pkgs/development/compilers/go @kalbasit @katexochen @Mic92
# GNOME
/pkgs/desktops/gnome @jtojnar
@@ -423,8 +422,9 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/pkgs/applications/networking/cluster/terraform-providers @zowoq
# Forgejo
nixos/modules/services/misc/forgejo.nix @adamcstephens @bendlas @emilylange
pkgs/by-name/fo/forgejo/ @adamcstephens @bendlas @emilylange
nixos/modules/services/misc/forgejo.* @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
pkgs/by-name/fo/forgejo/ @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
nixos/tests/forgejo.nix @adamcstephens @bendlas @christoph-heiss @emilylange @nycodeghg @pyrox0 @tebriel
# Dotnet
/pkgs/build-support/dotnet @corngood
@@ -434,7 +434,7 @@ pkgs/by-name/fo/forgejo/ @adamcstephens @bendlas @emilylange
# Node.js
/pkgs/build-support/node/build-npm-package @winterqt
/pkgs/build-support/node/fetch-npm-deps @winterqt
/pkgs/build-support/node/prefetch-npm-deps @winterqt
/doc/languages-frameworks/javascript.section.md @winterqt
/pkgs/development/tools/pnpm @Scrumplex @gepbird
/pkgs/build-support/node/fetch-pnpm-deps @Scrumplex @gepbird
@@ -504,7 +504,7 @@ pkgs/development/interpreters/elixir/ @NixOS/beam
pkgs/development/interpreters/lfe/ @NixOS/beam
# Authelia
pkgs/servers/authelia/ @06kellyjac @dit7ya @nicomem
pkgs/by-name/au/authelia/ @06kellyjac @dit7ya @nicomem
# OctoDNS
pkgs/by-name/oc/octodns/ @anthonyroussel
+1 -1
View File
@@ -24,7 +24,7 @@ The Nixpkgs merge bot empowers package maintainers by enabling them to merge PRs
It serves as a bridge for maintainers to quickly respond to user feedback, facilitating a more self-reliant approach.
Especially when considering there are roughly 20 maintainers for every committer, this bot is a game-changer.
Following [RFC 172] the merge bot was originally implemented as a [python webapp](https://github.com/NixOS/nixpkgs-merge-bot), which has now been integrated into [`ci/github-script/bot.js`](./github-script/bot.js) and [`ci/github-script/merge.js`](./github-script/merge.js).
Following [RFC 172], the merge bot was originally implemented as a [python webapp](https://github.com/NixOS/nixpkgs-merge-bot), which has now been integrated into [`ci/github-script/bot.js`](./github-script/bot.js) and [`ci/github-script/merge.js`](./github-script/merge.js).
### Using the merge bot
+19 -12
View File
@@ -87,22 +87,30 @@ let
"pkgs/development/haskell-modules/configuration-hackage2nix/transitive-broken.yaml"
];
programs.nixf-diagnose.enable = true;
settings.formatter.nixf-diagnose = {
# Ensure nixfmt cleans up after nixf-diagnose.
priority = -1;
options = [
"--auto-fix"
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.
"--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"
"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`.
"--ignore=or-identifier"
"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:
@@ -172,7 +180,6 @@ rec {
lib-tests = import ../lib/tests/release.nix { inherit pkgs; };
manual-nixos = (import ../nixos/release.nix { }).manual.${system} or null;
manual-nixpkgs = (import ../doc { inherit pkgs; });
manual-nixpkgs-tests = (import ../doc { inherit pkgs; }).tests;
nixpkgs-vet = pkgs.callPackage ./nixpkgs-vet.nix {
nix = pkgs.nixVersions.latest;
};
+1 -1
View File
@@ -19,7 +19,7 @@ The following arguments can be used to fine-tune performance:
- `--max-jobs`: The maximum number of derivations to run at the same time.
Only each [supported system](../supportedSystems.json) gets a separate derivation, so it doesn't make sense to set this higher than that number.
- `--cores`: The number of cores to use for each job.
Recommended to set this to the amount of cores on your system divided by `--max-jobs`.
Recommended to set this to the number of cores on your system divided by `--max-jobs`.
- `--arg chunkSize`: The number of attributes that are evaluated simultaneously on a single core.
Lowering this decreases memory usage at the cost of increased evaluation time.
If this is too high, there won't be enough chunks to process them in parallel, and will also increase evaluation time.
+9 -5
View File
@@ -161,12 +161,13 @@ let
);
inherit
(callPackage ./maintainers.nix { } {
(callPackage ./maintainers.nix {
changedattrs = lib.attrNames (lib.groupBy (a: a.name) changedPackagePlatformAttrs);
changedpathsjson = touchedFilesJson;
removedattrs = lib.attrNames (lib.groupBy (a: a.name) removedPackagePlatformAttrs);
})
maintainers
users
teams
packages
;
in
@@ -178,10 +179,12 @@ runCommand "compare"
cmp-stats
codeowners
];
maintainers = builtins.toJSON maintainers;
users = builtins.toJSON users;
teams = builtins.toJSON teams;
packages = builtins.toJSON packages;
passAsFile = [
"maintainers"
"users"
"teams"
"packages"
];
}
@@ -262,6 +265,7 @@ runCommand "compare"
done
cp "$maintainersPath" "$out/maintainers.json"
cp "$usersPath" "$out/maintainers.json"
cp "$teamsPath" "$out/teams.json"
cp "$packagesPath" "$out/packages.json"
''
+39 -16
View File
@@ -1,7 +1,5 @@
{
lib,
}:
{
changedattrs,
changedpathsjson,
removedattrs,
@@ -20,7 +18,7 @@ let
# 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))
(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
@@ -51,15 +49,16 @@ let
# updates to .json files.
# TODO: Support by-name package sets.
filenames = lib.optional (lib.length path == 1) "pkgs/by-name/${sharded (lib.head path)}/";
# TODO: Refactor this so we can ping entire teams instead of the individual members.
# Note that this will require keeping track of GH team IDs in "maintainers/teams.nix".
maintainers = package.meta.maintainers or [ ];
# 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 `packge = null`, which is the
# case for libintl, for example.
(lib.filter (pkg: pkg.maintainers != [ ]))
(lib.filter (pkg: pkg.users != [ ] || pkg.teams != [ ]))
];
relevantFilenames =
@@ -94,20 +93,44 @@ let
attrsWithModifiedFiles = lib.filter (pkg: anyMatchingFiles pkg.filenames) attrsWithFilenames;
listToPing = lib.concatMap (
userPings =
pkg:
map (maintainer: {
id = maintainer.githubId;
inherit (maintainer) github;
type = "user";
userId = maintainer.githubId;
packageName = pkg.name;
dueToFiles = pkg.filenames;
}) pkg.maintainers
});
teamPings =
pkg: team:
if team ? github then
[
{
type = "team";
teamId = team.githubId;
packageName = pkg.name;
}
]
else
userPings pkg team.members;
maintainersToPing = lib.concatMap (
pkg: userPings pkg pkg.users ++ lib.concatMap (teamPings pkg) pkg.teams
) attrsWithModifiedFiles;
byMaintainer = lib.groupBy (ping: toString ping.id) listToPing;
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.packageName)))
];
byTeam = lib.pipe (byType.team or [ ]) [
(lib.groupBy (ping: toString ping.teamId))
(lib.mapAttrs (_team: lib.map (pkg: pkg.packageName)))
];
in
{
maintainers = lib.mapAttrs (_: lib.catAttrs "packageName") byMaintainer;
packages = lib.catAttrs "packageName" listToPing;
users = byUser;
teams = byTeam;
packages = lib.catAttrs "name" attrsWithModifiedFiles;
}
+139 -27
View File
@@ -9,6 +9,15 @@ module.exports = async ({ github, context, core, dry }) => {
const artifactClient = new DefaultArtifactClient()
// Detect if running in a fork (not NixOS/nixpkgs)
const isFork = context.repo.owner !== 'NixOS'
const orgId = (
await github.rest.orgs.get({
org: context.repo.owner,
})
).data.id
async function downloadMaintainerMap(branch) {
let run
@@ -68,9 +77,18 @@ module.exports = async ({ github, context, core, dry }) => {
// We get here when none of the 10 commits we looked at contained a maintainer map.
// For the master branch, we don't have any fallback options, so we error out.
// For other branches, we select a suitable fallback below.
if (branch === 'master') throw new Error('No maintainer map found.')
// In forks without merge-group history, return empty map to allow testing.
if (branch === 'master') {
if (isFork) {
core.warning(
'No maintainer map found. Using empty map (expected in forks without merge-group history).',
)
return {}
}
throw new Error('No maintainer map found.')
}
// For other branches, we select a suitable fallback below.
const { stable, version } = classify(branch)
const release = `release-${version}`
@@ -109,6 +127,11 @@ module.exports = async ({ github, context, core, dry }) => {
return []
}
// Forks don't have NixOS teams, return empty list
if (isFork) {
return []
}
if (!members[team_slug]) {
members[team_slug] = github.paginate(github.rest.teams.listMembersInOrg, {
org: context.repo.owner,
@@ -133,11 +156,38 @@ module.exports = async ({ github, context, core, dry }) => {
id,
})
.then((resp) => resp.data)
.catch((e) => {
// User may have deleted their account
if (e.status === 404) return null
throw e
})
}
return users[id]
}
// Same for teams
const teams = {}
function getTeam(id) {
if (!teams[id]) {
teams[id] = github
.request({
method: 'GET',
url: '/organizations/{orgId}/team/{id}',
orgId,
id,
})
.then((resp) => resp.data)
.catch((e) => {
// Team may have been deleted
if (e.status === 404) return null
throw e
})
}
return teams[id]
}
async function handlePullRequest({ item, stats, events }) {
const log = (k, v) => core.info(`PR #${item.number} - ${k}: ${v}`)
@@ -145,22 +195,10 @@ module.exports = async ({ github, context, core, dry }) => {
// This API request is important for the merge-conflict label, because it triggers the
// creation of a new test merge commit. This is needed to actually determine the state of a PR.
//
// NOTE (2025-12-15): Temporarily skipping mergeability checks here
// on GitHubs request to measure the impact of the resulting ref
// writes on their internal metrics; merge conflicts resulting from
// changes to target branches will not have labels applied for the
// duration. The label should still be updated on pushes.
//
// TODO: Restore mergeability checks in some form after a few days
// or when we hear back from GitHub.
const pull_request = (
await github.rest.pulls.get({
...context.repo,
pull_number,
// Undocumented parameter (as of 2025-12-15), added by GitHub
// for us; stability unclear.
skip_mergeability_checks: true,
})
).data
@@ -182,17 +220,49 @@ module.exports = async ({ github, context, core, dry }) => {
})
// Check for any human reviews other than the PR author, GitHub actions and other GitHub apps.
// Accounts could be deleted as well, so don't count them.
const reviews = (
await github.paginate(github.rest.pulls.listReviews, {
...context.repo,
pull_number,
})
).filter(
await github.graphql(
`query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
# Unlikely that there's ever more than 100 reviews, so let's not bother,
# but once https://github.com/actions/github-script/issues/309 is resolved,
# it would be easy to enable pagination.
reviews(first: 100) {
nodes {
state
user: author {
# Only get users, no bots
... on User {
login
# Set the id field in the resulting JSON to GraphQL's databaseId
# databaseId in GraphQL-land is the same as id in REST-land
id: databaseId
}
}
onBehalfOf(first: 100) {
nodes {
slug
}
}
}
}
}
}
}`,
{
owner: context.repo.owner,
repo: context.repo.repo,
pr: pull_number,
},
)
).repository.pullRequest.reviews.nodes.filter(
(r) =>
r.user &&
!r.user.login.endsWith('[bot]') &&
r.user.type !== 'Bot' &&
// The `... on User` makes it such that .login only exists for users,
// but we still need to filter the others out.
// Accounts could be deleted as well, so don't count them.
r.user?.login &&
// Also exclude author reviews, can't request their review in any case
r.user.id !== pull_request.user?.id,
)
@@ -311,9 +381,40 @@ module.exports = async ({ github, context, core, dry }) => {
expectedHash: artifact.digest,
})
const evalLabels = JSON.parse(
const changedPaths = JSON.parse(
await readFile(`${pull_number}/changed-paths.json`, 'utf-8'),
).labels
)
const evalLabels = changedPaths.labels
// Fetch all PR commits to check their messages for package patterns
const prCommits = await github.paginate(github.rest.pulls.listCommits, {
...context.repo,
pull_number,
per_page: 100,
})
const commitSubjects = prCommits.map(
(c) => c.commit.message.split('\n')[0],
)
// Label new package PRs: "packagename: init at X.Y.Z"
// Exclude NixOS module commits like "nixos/timekpr: init at 0.5.8"
const newPackagePattern = /^(?<!nixos\/)\S+: init at\b/
const hasNewPackages = changedPaths.attrdiff?.added?.length > 0
const commitsIndicateNewPackage = commitSubjects.some((msg) =>
newPackagePattern.test(msg),
)
evalLabels['8.has: package (new)'] =
hasNewPackages && commitsIndicateNewPackage
// Label package update PRs: "packagename: X.Y.Z -> A.B.C"
// Matches versions like: 1.2.3, 0-unstable-2024-01-15, 1.3rc1, alpha, unstable
// Exclude NixOS module commits like "nixos/ncps: types.str -> types.path"
const updatePackagePattern =
/^(?<!nixos\/)\S+: [\w.-]*\d[\w.-]* (->|→) [\w.-]*\d[\w.-]*$/
const commitsIndicateUpdate = commitSubjects.some((msg) =>
updatePackagePattern.test(msg),
)
evalLabels['8.has: package (update)'] = commitsIndicateUpdate
// TODO: Get "changed packages" information from list of changed by-name files
// in addition to just the Eval results, to make this work for these packages
@@ -361,6 +462,16 @@ module.exports = async ({ github, context, core, dry }) => {
if (e.code !== 'ENOENT') throw e
}
let team_maintainers = []
try {
team_maintainers = Object.keys(
JSON.parse(await readFile(`${pull_number}/teams.json`, 'utf-8')),
).map((id) => parseInt(id))
} catch (e) {
// Older artifacts don't have the teams.json, yet.
if (e.code !== 'ENOENT') throw e
}
// We set this label earlier already, but the current PR state can be very different
// after handleReviewers has requested reviews, so update it in this case to prevent
// this label from flip-flopping.
@@ -373,14 +484,15 @@ module.exports = async ({ github, context, core, dry }) => {
pull_request,
reviews,
// TODO: Use maintainer map instead of the artifact.
maintainers: Object.keys(
user_maintainers: Object.keys(
JSON.parse(
await readFile(`${pull_number}/maintainers.json`, 'utf-8'),
),
).map((id) => parseInt(id)),
team_maintainers,
owners,
getTeamMembers,
getUser,
getTeam,
})
}
}
+213
View 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
+3 -2
View File
@@ -3,6 +3,7 @@ module.exports = async ({ github, context, core, dry, cherryPicks }) => {
const { classify } = require('../supportedBranches.js')
const withRateLimit = require('./withRateLimit.js')
const { dismissReviews, postReview } = require('./reviews.js')
const reviewKey = 'check-commits'
await withRateLimit({ github, core }, async (stats) => {
stats.prs = 1
@@ -193,7 +194,7 @@ module.exports = async ({ github, context, core, dry, cherryPicks }) => {
// An empty results array will always trigger this condition, which is helpful
// to clean up reviews created by the prepare step when on the wrong branch.
if (results.every(({ severity }) => severity === 'info')) {
await dismissReviews({ github, context, dry })
await dismissReviews({ github, context, dry, reviewKey })
return
}
@@ -316,6 +317,6 @@ module.exports = async ({ github, context, core, dry, cherryPicks }) => {
// Posting a review could fail for very long comments. This can only happen with
// multiple commits all hitting the truncation limit for the diff. If you ever hit
// this case, consider just splitting up those commits into multiple PRs.
await postReview({ github, context, core, dry, body })
await postReview({ github, context, core, dry, body, reviewKey })
})
}
+100 -10
View File
@@ -1,14 +1,37 @@
// @ts-check
const { classify } = require('../supportedBranches.js')
const { promisify } = require('node:util')
const execFile = promisify(require('node:child_process').execFile)
/**
* @param {{
* args: string[]
* core: import('@actions/core'),
* quiet?: boolean,
* repoPath?: string,
* }} RunGitProps
*/
async function runGit({ args, repoPath, core, quiet }) {
if (repoPath) {
args = ['-C', repoPath, ...args]
}
if (!quiet) {
core.info(`About to run \`git ${args.map((s) => `'${s}'`).join(' ')}\``)
}
return await execFile('git', args)
}
/**
* @param {{
* github: InstanceType<import('@actions/github/lib/utils').GitHub>,
* context: import('@actions/github/lib/context').Context
* core: import('@actions/core')
* context: import('@actions/github/lib/context').Context,
* core: import('@actions/core'),
* repoPath?: string,
* }} CheckCommitMessagesProps
*/
async function checkCommitMessages({ github, context, core }) {
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) {
@@ -32,25 +55,82 @@ async function checkCommitMessages({ github, context, core }) {
if (
baseBranchType.includes('development') &&
headBranchType.includes('development')
headBranchType.includes('development') &&
pr.base.repo.id === pr.head.repo?.id
) {
// This matches, for example, PRs from staging-next to master, or vice versa.
// This matches, for example, PRs from NixOS:staging-next to NixOS:master, or vice versa.
// Ignore them: we should only care about PRs introducing *new* commits.
// We still want to run on PRs from, e.g., Someone:master to NixOS:master, though.
core.info(
'This PR is from one development branch to another. Skipping checks.',
)
return
}
const commits = await github.paginate(github.rest.pulls.listCommits, {
...context.repo,
pull_number,
})
/**
* 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,
* }[]}
*/
let commits
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,
})),
)
}
const failures = new Set()
for (const commit of commits) {
const message = commit.commit.message
const message = commit.message
const firstLine = message.split('\n')[0]
const logMsgStart = `Commit ${commit.sha}'s message's subject ("${firstLine}")`
@@ -72,6 +152,16 @@ async function checkCommitMessages({ github, context, core }) {
failures.add(commit.sha)
}
const fixups = ['amend!', 'fixup!', 'squash!']
if (fixups.some((s) => firstLine.startsWith(s))) {
core.error(
`${logMsgStart} was detected as not meeting our guidelines because ` +
`it begins with "${fixups.find((s) => firstLine.startsWith(s))}". ` +
'Did you forget to run `git rebase -i --autosquash`?',
)
failures.add(commit.sha)
}
if (!failures.has(commit.sha)) {
core.info(`${logMsgStart} passed our automated checks!`)
}
+1 -1
View File
@@ -171,7 +171,7 @@ async function handleMerge({
async function merge() {
if (dry) {
core.info(`Merging #${pull_number}... (dry)`)
return 'Merge completed (dry)'
return ['Merge completed (dry)']
}
// Using GraphQL mutations instead of the REST /merge endpoint, because the latter
+261 -313
View File
@@ -5,43 +5,76 @@
"packages": {
"": {
"dependencies": {
"@actions/artifact": "2.3.2",
"@actions/artifact": "5.0.3",
"@actions/core": "1.11.1",
"@actions/github": "6.0.1",
"bottleneck": "2.19.5",
"commander": "14.0.0"
"commander": "14.0.3"
}
},
"node_modules/@actions/artifact": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.3.2.tgz",
"integrity": "sha512-uX2Mr5KEPcwnzqa0Og9wOTEKIae6C/yx9P/m8bIglzCS5nZDkcQC/zRWjjoEsyVecL6oQpBx5BuqQj/yuVm0gw==",
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-5.0.3.tgz",
"integrity": "sha512-FIEG8Kum0wABZnktJvFi1xuVPc31xrunhZwLCvjrCGISQOm0ifyo7cjqf6PHiEeqoWMa5HIGOsB+lGM4aKCseA==",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1",
"@actions/http-client": "^2.1.0",
"@azure/storage-blob": "^12.15.0",
"@octokit/core": "^3.5.1",
"@actions/core": "^2.0.0",
"@actions/github": "^6.0.1",
"@actions/http-client": "^3.0.2",
"@azure/storage-blob": "^12.29.1",
"@octokit/core": "^5.2.1",
"@octokit/plugin-request-log": "^1.0.4",
"@octokit/plugin-retry": "^3.0.9",
"@octokit/request-error": "^5.0.0",
"@octokit/request": "^8.4.1",
"@octokit/request-error": "^5.1.1",
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
"archiver": "^7.0.1",
"jwt-decode": "^3.1.2",
"unzip-stream": "^0.3.1"
}
},
"node_modules/@actions/artifact/node_modules/@actions/github": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz",
"integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==",
"node_modules/@actions/artifact/node_modules/@actions/core": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-2.0.3.tgz",
"integrity": "sha512-Od9Thc3T1mQJYddvVPM4QGiLUewdh+3txmDYHHxoNdkqysR1MbCT+rFOtNUxYAz+7+6RIsqipVahY2GJqGPyxA==",
"license": "MIT",
"dependencies": {
"@actions/http-client": "^2.0.1",
"@octokit/core": "^3.6.0",
"@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
"@actions/exec": "^2.0.0",
"@actions/http-client": "^3.0.2"
}
},
"node_modules/@actions/artifact/node_modules/@actions/exec": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-2.0.0.tgz",
"integrity": "sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw==",
"license": "MIT",
"dependencies": {
"@actions/io": "^2.0.0"
}
},
"node_modules/@actions/artifact/node_modules/@actions/http-client": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-3.0.2.tgz",
"integrity": "sha512-JP38FYYpyqvUsz+Igqlc/JG6YO9PaKuvqjM3iGvaLqFnJ7TFmcLyy2IDrY0bI0qCQug8E9K+elv5ZNfw62ZJzA==",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^6.23.0"
}
},
"node_modules/@actions/artifact/node_modules/@actions/io": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-2.0.0.tgz",
"integrity": "sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg==",
"license": "MIT"
},
"node_modules/@actions/artifact/node_modules/undici": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz",
"integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==",
"license": "MIT",
"engines": {
"node": ">=18.17"
}
},
"node_modules/@actions/core": {
@@ -78,66 +111,6 @@
"undici": "^5.28.5"
}
},
"node_modules/@actions/github/node_modules/@octokit/auth-token": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==",
"license": "MIT",
"engines": {
"node": ">= 18"
}
},
"node_modules/@actions/github/node_modules/@octokit/core": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.1.tgz",
"integrity": "sha512-dKYCMuPO1bmrpuogcjQ8z7ICCH3FP6WmxpwC03yjzGfZhj9fTJg6+bS1+UAplekbN2C+M61UNllGOOoAfGCrdQ==",
"license": "MIT",
"dependencies": {
"@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.1.0",
"@octokit/request": "^8.4.1",
"@octokit/request-error": "^5.1.1",
"@octokit/types": "^13.0.0",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@actions/github/node_modules/@octokit/endpoint": {
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz",
"integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.1.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@actions/github/node_modules/@octokit/graphql": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz",
"integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==",
"license": "MIT",
"dependencies": {
"@octokit/request": "^8.4.1",
"@octokit/types": "^13.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@actions/github/node_modules/@octokit/openapi-types": {
"version": "24.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
"license": "MIT"
},
"node_modules/@actions/github/node_modules/@octokit/plugin-paginate-rest": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz",
@@ -198,30 +171,6 @@
"@octokit/openapi-types": "^20.0.0"
}
},
"node_modules/@actions/github/node_modules/@octokit/request": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz",
"integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==",
"license": "MIT",
"dependencies": {
"@octokit/endpoint": "^9.0.6",
"@octokit/request-error": "^5.1.1",
"@octokit/types": "^13.1.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@actions/github/node_modules/@octokit/types": {
"version": "13.10.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^24.2.0"
}
},
"node_modules/@actions/http-client": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
@@ -251,49 +200,52 @@
}
},
"node_modules/@azure/core-auth": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz",
"integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==",
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz",
"integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@azure/core-util": "^1.11.0",
"@azure/abort-controller": "^2.1.2",
"@azure/core-util": "^1.13.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-client": {
"version": "1.9.4",
"resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.4.tgz",
"integrity": "sha512-f7IxTD15Qdux30s2qFARH+JxgwxWLG2Rlr4oSkPGuLWm+1p5y1+C04XGLA0vmX6EtqfutmjvpNmAfgwVIS5hpw==",
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz",
"integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==",
"license": "MIT",
"peer": true,
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@azure/core-auth": "^1.4.0",
"@azure/core-rest-pipeline": "^1.20.0",
"@azure/core-tracing": "^1.0.0",
"@azure/core-util": "^1.6.1",
"@azure/logger": "^1.0.0",
"@azure/abort-controller": "^2.1.2",
"@azure/core-auth": "^1.10.0",
"@azure/core-rest-pipeline": "^1.22.0",
"@azure/core-tracing": "^1.3.0",
"@azure/core-util": "^1.13.0",
"@azure/logger": "^1.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-http-compat": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.3.0.tgz",
"integrity": "sha512-qLQujmUypBBG0gxHd0j6/Jdmul6ttl24c8WGiLXIk7IHXdBlfoBqW27hyz3Xn6xbfdyVSarl1Ttbk0AwnZBYCw==",
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.3.2.tgz",
"integrity": "sha512-Tf6ltdKzOJEgxZeWLCjMxrxbodB/ZeCbzzA1A2qHbhzAjzjHoBVSUeSl/baT/oHAxhc4qdqVaDKnc2+iE932gw==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@azure/core-client": "^1.3.0",
"@azure/core-rest-pipeline": "^1.20.0"
"@azure/abort-controller": "^2.1.2"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
},
"peerDependencies": {
"@azure/core-client": "^1.10.0",
"@azure/core-rest-pipeline": "^1.22.0"
}
},
"node_modules/@azure/core-lro": {
@@ -324,97 +276,119 @@
}
},
"node_modules/@azure/core-rest-pipeline": {
"version": "1.21.0",
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.21.0.tgz",
"integrity": "sha512-a4MBwe/5WKbq9MIxikzgxLBbruC5qlkFYlBdI7Ev50Y7ib5Vo/Jvt5jnJo7NaWeJ908LCHL0S1Us4UMf1VoTfg==",
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz",
"integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@azure/core-auth": "^1.8.0",
"@azure/core-tracing": "^1.0.1",
"@azure/core-util": "^1.11.0",
"@azure/logger": "^1.0.0",
"@typespec/ts-http-runtime": "^0.2.3",
"@azure/abort-controller": "^2.1.2",
"@azure/core-auth": "^1.10.0",
"@azure/core-tracing": "^1.3.0",
"@azure/core-util": "^1.13.0",
"@azure/logger": "^1.3.0",
"@typespec/ts-http-runtime": "^0.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-tracing": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.2.0.tgz",
"integrity": "sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz",
"integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-util": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.12.0.tgz",
"integrity": "sha512-13IyjTQgABPARvG90+N2dXpC+hwp466XCdQXPCRlbWHgd3SJd5Q1VvaBGv6k1BIa4MQm6hAF1UBU1m8QUxV8sQ==",
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz",
"integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@typespec/ts-http-runtime": "^0.2.2",
"@azure/abort-controller": "^2.1.2",
"@typespec/ts-http-runtime": "^0.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
}
},
"node_modules/@azure/core-xml": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.4.5.tgz",
"integrity": "sha512-gT4H8mTaSXRz7eGTuQyq1aIJnJqeXzpOe9Ay7Z3FrCouer14CbV3VzjnJrNrQfbBpGBLO9oy8BmrY75A0p53cA==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.5.0.tgz",
"integrity": "sha512-D/sdlJBMJfx7gqoj66PKVmhDDaU6TKA49ptcolxdas29X7AfvLTmfAGLjAcIMBK7UZ2o4lygHIqVckOlQU3xWw==",
"license": "MIT",
"dependencies": {
"fast-xml-parser": "^5.0.7",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
}
},
"node_modules/@azure/logger": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.2.0.tgz",
"integrity": "sha512-0hKEzLhpw+ZTAfNJyRrn6s+V0nDWzXk9OjBr2TiGIu0OfMr5s2V4FpKLTAK3Ca5r5OKLbf4hkOGDPyiRjie/jA==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz",
"integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==",
"license": "MIT",
"dependencies": {
"@typespec/ts-http-runtime": "^0.2.2",
"@typespec/ts-http-runtime": "^0.3.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
}
},
"node_modules/@azure/storage-blob": {
"version": "12.27.0",
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.27.0.tgz",
"integrity": "sha512-IQjj9RIzAKatmNca3D6bT0qJ+Pkox1WZGOg2esJF2YLHb45pQKOwGPIAV+w3rfgkj7zV3RMxpn/c6iftzSOZJQ==",
"version": "12.31.0",
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.31.0.tgz",
"integrity": "sha512-DBgNv10aCSxopt92DkTDD0o9xScXeBqPKGmR50FPZQaEcH4JLQ+GEOGEDv19V5BMkB7kxr+m4h6il/cCDPvmHg==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.1.2",
"@azure/core-auth": "^1.4.0",
"@azure/core-client": "^1.6.2",
"@azure/core-http-compat": "^2.0.0",
"@azure/core-auth": "^1.9.0",
"@azure/core-client": "^1.9.3",
"@azure/core-http-compat": "^2.2.0",
"@azure/core-lro": "^2.2.0",
"@azure/core-paging": "^1.1.1",
"@azure/core-rest-pipeline": "^1.10.1",
"@azure/core-tracing": "^1.1.2",
"@azure/core-util": "^1.6.1",
"@azure/core-xml": "^1.4.3",
"@azure/logger": "^1.0.0",
"@azure/core-paging": "^1.6.2",
"@azure/core-rest-pipeline": "^1.19.1",
"@azure/core-tracing": "^1.2.0",
"@azure/core-util": "^1.11.0",
"@azure/core-xml": "^1.4.5",
"@azure/logger": "^1.1.4",
"@azure/storage-common": "^12.3.0",
"events": "^3.0.0",
"tslib": "^2.2.0"
"tslib": "^2.8.1"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
}
},
"node_modules/@azure/storage-common": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/@azure/storage-common/-/storage-common-12.3.0.tgz",
"integrity": "sha512-/OFHhy86aG5Pe8dP5tsp+BuJ25JOAl9yaMU3WZbkeoiFMHFtJ7tu5ili7qEdBXNW9G5lDB19trwyI6V49F/8iQ==",
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.1.2",
"@azure/core-auth": "^1.9.0",
"@azure/core-http-compat": "^2.2.0",
"@azure/core-rest-pipeline": "^1.19.1",
"@azure/core-tracing": "^1.2.0",
"@azure/core-util": "^1.11.0",
"@azure/logger": "^1.1.4",
"events": "^3.3.0",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@bufbuild/protobuf": {
@@ -474,60 +448,103 @@
}
},
"node_modules/@octokit/auth-token": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^6.0.3"
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/core": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz",
"integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@octokit/auth-token": "^2.4.4",
"@octokit/graphql": "^4.5.8",
"@octokit/request": "^5.6.3",
"@octokit/request-error": "^2.0.5",
"@octokit/types": "^6.0.3",
"@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.1.0",
"@octokit/request": "^8.4.1",
"@octokit/request-error": "^5.1.1",
"@octokit/types": "^13.0.0",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/core/node_modules/@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"node_modules/@octokit/core/node_modules/@octokit/openapi-types": {
"version": "24.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
"license": "MIT"
},
"node_modules/@octokit/core/node_modules/@octokit/types": {
"version": "13.10.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^6.0.3",
"deprecation": "^2.0.0",
"once": "^1.4.0"
"@octokit/openapi-types": "^24.2.0"
}
},
"node_modules/@octokit/endpoint": {
"version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz",
"integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^6.0.3",
"is-plain-object": "^5.0.0",
"@octokit/types": "^13.1.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": {
"version": "24.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
"license": "MIT"
},
"node_modules/@octokit/endpoint/node_modules/@octokit/types": {
"version": "13.10.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^24.2.0"
}
},
"node_modules/@octokit/graphql": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz",
"integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==",
"license": "MIT",
"dependencies": {
"@octokit/request": "^5.6.0",
"@octokit/types": "^6.0.3",
"@octokit/request": "^8.4.1",
"@octokit/types": "^13.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": {
"version": "24.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
"license": "MIT"
},
"node_modules/@octokit/graphql/node_modules/@octokit/types": {
"version": "13.10.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^24.2.0"
}
},
"node_modules/@octokit/openapi-types": {
@@ -536,18 +553,6 @@
"integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==",
"license": "MIT"
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "2.21.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
"integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^6.40.0"
},
"peerDependencies": {
"@octokit/core": ">=2"
}
},
"node_modules/@octokit/plugin-request-log": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
@@ -557,19 +562,6 @@
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "5.16.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
"integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^6.39.0",
"deprecation": "^2.3.1"
},
"peerDependencies": {
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/plugin-retry": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz",
@@ -581,17 +573,18 @@
}
},
"node_modules/@octokit/request": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz",
"integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==",
"license": "MIT",
"dependencies": {
"@octokit/endpoint": "^6.0.1",
"@octokit/request-error": "^2.1.0",
"@octokit/types": "^6.16.1",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"@octokit/endpoint": "^9.0.6",
"@octokit/request-error": "^5.1.1",
"@octokit/types": "^13.1.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/request-error": {
@@ -623,15 +616,19 @@
"@octokit/openapi-types": "^24.2.0"
}
},
"node_modules/@octokit/request/node_modules/@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"node_modules/@octokit/request/node_modules/@octokit/openapi-types": {
"version": "24.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
"license": "MIT"
},
"node_modules/@octokit/request/node_modules/@octokit/types": {
"version": "13.10.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^6.0.3",
"deprecation": "^2.0.0",
"once": "^1.4.0"
"@octokit/openapi-types": "^24.2.0"
}
},
"node_modules/@octokit/types": {
@@ -708,9 +705,9 @@
}
},
"node_modules/@typespec/ts-http-runtime": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.2.3.tgz",
"integrity": "sha512-oRhjSzcVjX8ExyaF8hC0zzTqxlVuRlgMHL/Bh4w3xB9+wjbm0FpXylVU/lBrn+kgphwYTrOk3tp+AVShGmlYCg==",
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.3.tgz",
"integrity": "sha512-91fp6CAAJSRtH5ja95T1FHSKa8aPW9/Zw6cta81jlZTUw/+Vq8jM/AfF/14h2b71wwR84JUTW/3Y8QPhDAawFA==",
"license": "MIT",
"dependencies": {
"http-proxy-agent": "^7.0.0",
@@ -718,7 +715,7 @@
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
}
},
"node_modules/abort-controller": {
@@ -734,9 +731,9 @@
}
},
"node_modules/agent-base": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
"integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
"license": "MIT",
"engines": {
"node": ">= 14"
@@ -953,9 +950,9 @@
"license": "MIT"
},
"node_modules/commander": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz",
"integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
"integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
"license": "MIT",
"engines": {
"node": ">=20"
@@ -1082,9 +1079,9 @@
"license": "MIT"
},
"node_modules/fast-xml-parser": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz",
"integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==",
"version": "5.3.6",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.6.tgz",
"integrity": "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==",
"funding": [
{
"type": "github",
@@ -1093,7 +1090,7 @@
],
"license": "MIT",
"dependencies": {
"strnum": "^2.1.0"
"strnum": "^2.1.2"
},
"bin": {
"fxparser": "src/cli/cli.js"
@@ -1116,9 +1113,10 @@
}
},
"node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
"integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
@@ -1202,15 +1200,6 @@
"node": ">=8"
}
},
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -1299,9 +1288,9 @@
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"version": "4.17.23",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"license": "MIT"
},
"node_modules/lru-cache": {
@@ -1361,26 +1350,6 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -1654,9 +1623,9 @@
}
},
"node_modules/strnum": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz",
"integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz",
"integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==",
"funding": [
{
"type": "github",
@@ -1685,12 +1654,6 @@
"b4a": "^1.6.4"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT"
},
"node_modules/traverse": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
@@ -1720,6 +1683,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz",
"integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==",
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -1762,22 +1726,6 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"license": "MIT",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+8 -2
View File
@@ -1,10 +1,16 @@
{
"private": true,
"//": [
"Keep `@actions/core` and `@actions/github` in sync with",
"https://github.com/actions/github-script/blob/main/package.json.",
"Keep `@actions/artifact` and `bottleneck` in sync with",
"`.github/workflows/bot.yml`."
],
"dependencies": {
"@actions/artifact": "2.3.2",
"@actions/artifact": "5.0.3",
"@actions/core": "1.11.1",
"@actions/github": "6.0.1",
"bottleneck": "2.19.5",
"commander": "14.0.0"
"commander": "14.0.3"
}
}
+6 -3
View File
@@ -1,5 +1,6 @@
const { classify } = require('../supportedBranches.js')
const { postReview } = require('./reviews.js')
const { postReview, dismissReviews } = require('./reviews.js')
const reviewKey = 'prepare'
module.exports = async ({ github, context, core, dry }) => {
const pull_number = context.payload.pull_request.number
@@ -46,7 +47,7 @@ module.exports = async ({ github, context, core, dry }) => {
`Please target \`${correctBranch}\` instead.`,
].join('\n')
await postReview({ github, context, core, dry, body })
await postReview({ github, context, core, dry, body, reviewKey })
throw new Error('The PR targets a channel branch.')
}
@@ -170,12 +171,14 @@ module.exports = async ({ github, context, core, dry }) => {
' ```',
].join('\n')
await postReview({ github, context, core, dry, body })
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) {
+123 -80
View File
@@ -6,28 +6,29 @@ async function handleReviewers({
dry,
pull_request,
reviews,
maintainers,
user_maintainers,
team_maintainers,
owners,
getTeamMembers,
getUser,
getTeam,
}) {
const pull_number = pull_request.number
const requested_reviewers = new Set(
pull_request.requested_reviewers.map(({ login }) => login.toLowerCase()),
)
log(
'reviewers - requested_reviewers',
Array.from(requested_reviewers).join(', '),
)
// Users that the PR has already reached, e.g. they've left a review or have been requested for one
const users_reached = new Set([
...pull_request.requested_reviewers.map(({ login }) => login.toLowerCase()),
...reviews.map(({ user }) => user.login.toLowerCase()),
])
log('reviewers - users_reached', Array.from(users_reached).join(', '))
const existing_reviewers = new Set(
reviews.map(({ user }) => user?.login.toLowerCase()).filter(Boolean),
)
log(
'reviewers - existing_reviewers',
Array.from(existing_reviewers).join(', '),
)
// Same for teams
const teams_reached = new Set([
...pull_request.requested_teams.map(({ slug }) => slug.toLowerCase()),
...reviews.flatMap(({ onBehalfOf }) =>
onBehalfOf.nodes.map(({ slug }) => slug.toLowerCase()),
),
])
log('reviewers - teams_reached', Array.from(teams_reached).join(', '))
// Early sanity check, before we start making any API requests. The list of maintainers
// does not have duplicates so the only user to filter out from this list would be the
@@ -35,90 +36,130 @@ async function handleReviewers({
// further down again.
// This is to protect against huge treewides consuming all our API requests for no
// reason.
if (maintainers.length > 16) {
if (user_maintainers.length + team_maintainers.length > 16) {
core.warning('Too many potential reviewers, skipping review requests.')
// Return a boolean on whether the "needs: reviewers" label should be set.
return existing_reviewers.size === 0 && requested_reviewers.size === 0
return users_reached.size === 0 && teams_reached.size === 0
}
const users = new Set([
...(await Promise.all(
maintainers.map(async (id) => (await getUser(id)).login.toLowerCase()),
)),
// Users that should be reached
var users_to_reach = new Set([
...(
await Promise.all(
user_maintainers.map(async (id) => {
const user = await getUser(id)
// User may have deleted their account
return user?.login?.toLowerCase()
}),
)
).filter(Boolean),
...owners
.filter((handle) => handle && !handle.includes('/'))
.map((handle) => handle.toLowerCase()),
])
log('reviewers - users', Array.from(users).join(', '))
const teams = new Set(
owners
.map((handle) => handle.split('/'))
.filter(([org, slug]) => org === context.repo.owner && slug)
.map(([, slug]) => slug),
)
log('reviewers - teams', Array.from(teams).join(', '))
const team_members = new Set(
(await Promise.all(Array.from(teams, getTeamMembers)))
.flat(1)
.map(({ login }) => login.toLowerCase()),
)
log('reviewers - team_members', Array.from(team_members).join(', '))
const new_reviewers = users
.union(team_members)
// We can't request a review from the author.
.difference(new Set([pull_request.user?.login.toLowerCase()]))
log('reviewers - new_reviewers', Array.from(new_reviewers).join(', '))
// Filter users to repository collaborators. If they're not, they can't be requested
// for review. In that case, they probably missed their invite to the maintainers team.
const reviewers = (
await Promise.all(
Array.from(new_reviewers, async (username) => {
// TODO: Restructure this file to only do the collaborator check for those users
// who were not already part of a team. Being a member of a team makes them
// collaborators by definition.
try {
await github.rest.repos.checkCollaborator({
...context.repo,
username,
})
return username
} catch (e) {
if (e.status !== 404) throw e
core.warning(
`PR #${pull_number}: User ${username} cannot be requested for review because they don't exist or are not a repository collaborator, ignoring. They probably missed the automated invite to the maintainers team (see <https://github.com/NixOS/nixpkgs/issues/234293>).`,
)
}
}),
)
).filter(Boolean)
log('reviewers - reviewers', reviewers.join(', '))
users_to_reach = new Set(
(
await Promise.all(
Array.from(users_to_reach, async (username) => {
// TODO: Restructure this file to only do the collaborator check for those users
// who were not already part of a team. Being a member of a team makes them
// collaborators by definition.
try {
await github.rest.repos.checkCollaborator({
...context.repo,
username,
})
return username
} catch (e) {
if (e.status !== 404) throw e
core.warning(
`PR #${pull_number}: User ${username} cannot be requested for review because they don't exist or are not a repository collaborator, ignoring. They probably missed the automated invite to the maintainers team (see <https://github.com/NixOS/nixpkgs/issues/234293>).`,
)
}
}),
)
).filter(Boolean),
)
log('reviewers - users_to_reach', Array.from(users_to_reach).join(', '))
if (reviewers.length > 15) {
// Similar for teams
var teams_to_reach = new Set([
...(
await Promise.all(
team_maintainers.map(async (id) => {
const team = await getTeam(id)
// Team may have been deleted
return team?.slug?.toLowerCase()
}),
)
).filter(Boolean),
...owners
.map((handle) => handle.split('/'))
.filter(
([org, slug]) =>
org.toLowerCase() === context.repo.owner.toLowerCase() && slug,
)
.map(([, slug]) => slug.toLowerCase()),
])
teams_to_reach = new Set(
(
await Promise.all(
Array.from(teams_to_reach, async (slug) => {
try {
await github.rest.teams.checkPermissionsForRepoInOrg({
org: context.repo.owner,
team_slug: slug,
owner: context.repo.owner,
repo: context.repo.repo,
})
return slug
} catch (e) {
if (e.status !== 404) throw e
core.warning(
`PR #${pull_number}: Team ${slug} cannot be requested for review because it doesn't exist or has no repository permissions, ignoring. Probably wasn't added to the nixpkgs-maintainers team (see https://github.com/NixOS/nixpkgs/tree/master/maintainers#maintainer-teams)`,
)
}
}),
)
).filter(Boolean),
)
log('reviewers - teams_to_reach', Array.from(teams_to_reach).join(', '))
if (users_to_reach.size + teams_to_reach.size > 15) {
core.warning(
`Too many reviewers (${reviewers.join(', ')}), skipping review requests.`,
`Too many reviewers (users: ${Array.from(users_to_reach).join(', ')}, teams: ${Array.from(teams_to_reach).join(', ')}), skipping review requests.`,
)
// Return a boolean on whether the "needs: reviewers" label should be set.
return existing_reviewers.size === 0 && requested_reviewers.size === 0
return users_reached.size === 0 && teams_reached.size === 0
}
const non_requested_reviewers = new Set(reviewers)
.difference(requested_reviewers)
// We don't want to rerequest reviews from people who already reviewed.
.difference(existing_reviewers)
log(
'reviewers - non_requested_reviewers',
Array.from(non_requested_reviewers).join(', '),
// We don't want to rerequest reviews from people who already reviewed or were requested
const users_not_yet_reached = Array.from(
users_to_reach.difference(users_reached),
)
log('reviewers - users_not_yet_reached', users_not_yet_reached.join(', '))
// We don't want to rerequest reviews from teams who already reviewed or were requested
const teams_not_yet_reached = Array.from(
teams_to_reach.difference(teams_reached),
)
log('reviewers - teams_not_yet_reached', teams_not_yet_reached.join(', '))
if (non_requested_reviewers.size === 0) {
if (
users_not_yet_reached.length === 0 &&
teams_not_yet_reached.length === 0
) {
log('Has reviewer changes', 'false (skipped)')
} else if (dry) {
core.info(
`Requesting reviewers for #${pull_number}: ${Array.from(non_requested_reviewers).join(', ')} (dry)`,
`Requesting user reviewers for #${pull_number}: ${users_not_yet_reached.join(', ')} (dry)`,
)
core.info(
`Requesting team reviewers for #${pull_number}: ${teams_not_yet_reached.join(', ')} (dry)`,
)
} else {
// We had tried the "request all reviewers at once" thing in the past, but it didn't work out:
@@ -128,15 +169,17 @@ async function handleReviewers({
await github.rest.pulls.requestReviewers({
...context.repo,
pull_number,
reviewers,
reviewers: users_not_yet_reached,
team_reviewers: teams_not_yet_reached,
})
}
// Return a boolean on whether the "needs: reviewers" label should be set.
return (
non_requested_reviewers.size === 0 &&
existing_reviewers.size === 0 &&
requested_reviewers.size === 0
users_not_yet_reached.length === 0 &&
teams_not_yet_reached.length === 0 &&
users_reached.size === 0 &&
teams_reached.size === 0
)
}
+193 -51
View File
@@ -1,59 +1,190 @@
async function dismissReviews({ github, context, dry }) {
const pull_number = context.payload.pull_request.number
// @ts-check
const eventToState = {
COMMENT: 'COMMENTED',
REQUEST_CHANGES: 'CHANGES_REQUESTED',
}
/**
* @param {{
* github: InstanceType<import('@actions/github/lib/utils').GitHub>,
* context: import('@actions/github/lib/context').Context,
* core: import('@actions/core'),
* dry: boolean,
* reviewKey?: string,
* }} DismissReviewsProps
*/
async function dismissReviews({ github, context, core, dry, reviewKey }) {
const pull_number = context.payload.pull_request?.number
if (!pull_number) {
core.warning('dismissReviews called outside of pull_request context')
return
}
if (dry) {
return
}
await Promise.all(
(
await github.paginate(github.rest.pulls.listReviews, {
...context.repo,
pull_number,
})
)
.filter((review) => review.user?.login === 'github-actions[bot]')
.map(async (review) => {
if (review.state === 'CHANGES_REQUESTED') {
await github.rest.pulls.dismissReview({
...context.repo,
pull_number,
review_id: review.id,
message: 'All good now, thank you!',
})
}
await github.graphql(
`mutation($node_id:ID!) {
minimizeComment(input: {
classifier: RESOLVED,
subjectId: $node_id
})
{ clientMutationId }
}`,
{ node_id: review.node_id },
)
}),
)
}
async function postReview({ github, context, core, dry, body }) {
const pull_number = context.payload.pull_request.number
const pendingReview = (
const reviews = (
await github.paginate(github.rest.pulls.listReviews, {
...context.repo,
pull_number,
})
).find(
).filter(
(review) =>
review.user?.login === 'github-actions[bot]' &&
// If a review is still pending, we can just update this instead
// of posting a new one.
(review.state === 'CHANGES_REQUESTED' ||
// No need to post a new review, if an older one with the exact
// same content had already been dismissed.
review.body === body),
review.state !== 'DISMISSED',
)
const changesRequestedReviews = reviews.filter(
(review) => review.state === 'CHANGES_REQUESTED',
)
const commentRegex = new RegExp(
/<!-- nixpkgs review key: (.*)(?:; resolved: .*)? -->/,
)
const reviewKeyRegex = new RegExp(
`<!-- (nixpkgs review key: ${reviewKey})(?:; resolved: .*)? -->`,
)
const commentResolvedRegex = new RegExp(
/<!-- nixpkgs review key: .*; resolved: true -->/,
)
let reviewsToMinimize = reviews
let /** @type {typeof reviews} */ reviewsToDismiss = []
let /** @type {typeof reviews} */ reviewsToResolve = []
if (reviewKey && reviews.every((review) => commentRegex.test(review.body))) {
reviewsToMinimize = reviews.filter((review) =>
reviewKeyRegex.test(review.body),
)
}
// 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([
...reviewsToMinimize.map(async (review) =>
github.graphql(
`mutation($node_id:ID!) {
minimizeComment(input: {
classifier: OUTDATED,
subjectId: $node_id
})
{ clientMutationId }
}`,
{ node_id: review.node_id },
),
),
...reviewsToDismiss.map(async (review) =>
github.rest.pulls.dismissReview({
...context.repo,
pull_number,
review_id: review.id,
message: 'Review dismissed automatically',
}),
),
...reviewsToResolve.map(async (review) =>
github.rest.pulls.updateReview({
...context.repo,
pull_number,
review_id: review.id,
body: review.body.replace(
reviewKeyRegex,
`<!-- nixpkgs review key: ${reviewKey}; resolved: true -->`,
),
}),
),
])
}
/**
* @param {{
* github: InstanceType<import('@actions/github/lib/utils').GitHub>,
* context: import('@actions/github/lib/context').Context
* core: import('@actions/core'),
* dry: boolean,
* body: string,
* event: keyof eventToState,
* reviewKey: string,
* }} PostReviewProps
*/
async function postReview({
github,
context,
core,
dry,
body,
event = 'REQUEST_CHANGES',
reviewKey,
}) {
const pull_number = context.payload.pull_request?.number
if (!pull_number) {
core.warning('postReview called outside of pull_request context')
return
}
const reviewKeyRegex = new RegExp(
`<!-- (nixpkgs review key: ${reviewKey})(?:; resolved: .*)? -->`,
)
const reviewKeyComment = `<!-- nixpkgs review key: ${reviewKey}; resolved: false -->`
body = body + '\n\n' + reviewKeyComment
const reviews = (
await github.paginate(github.rest.pulls.listReviews, {
...context.repo,
pull_number,
})
).filter(
(review) =>
review.user?.login === 'github-actions[bot]' &&
review.state !== 'DISMISSED',
)
/** @type {null | typeof reviews[number]} */
let pendingReview
const matchingReviews = reviews.filter((review) =>
reviewKeyRegex.test(review.body),
)
if (matchingReviews.length === 0) {
pendingReview = null
} else if (
matchingReviews.length === 1 &&
matchingReviews[0].state === eventToState[event]
) {
pendingReview = matchingReviews[0]
} else {
await dismissReviews({
github,
context,
core,
dry,
reviewKey,
})
pendingReview = null
}
if (dry) {
if (pendingReview)
@@ -62,17 +193,28 @@ async function postReview({ github, context, core, dry, body }) {
core.info(body)
} else {
if (pendingReview) {
await github.rest.pulls.updateReview({
...context.repo,
pull_number,
review_id: pendingReview.id,
body,
})
await Promise.all([
github.rest.pulls.updateReview({
...context.repo,
pull_number,
review_id: pendingReview.id,
body,
}),
github.graphql(
`mutation($node_id:ID!) {
unminimizeComment(input: {
subjectId: $node_id
})
{ clientMutationId }
}`,
{ node_id: pendingReview.node_id },
),
])
} else {
await github.rest.pulls.createReview({
...context.repo,
pull_number,
event: 'REQUEST_CHANGES',
event,
body,
})
}
+11
View File
@@ -105,4 +105,15 @@ program
await run(checkCommitMessages, owner, repo, pr, options)
})
program
.command('check-target-branch')
.description('Check that the PR is made against the correct branch')
.argument('<owner>', 'Owner of the GitHub repository to run on (Example: NixOS)')
.argument('<repo>', 'Name of the GitHub repository to run on (Example: nixpkgs)')
.argument('<pr>', 'Number of the Pull Request to run on')
.action(async (owner, repo, pr, options) => {
const checkCommitMessages = (await import('./check-target-branch.js')).default
await run(checkCommitMessages, owner, repo, pr, options)
})
await program.parse()
+6 -6
View File
@@ -9,9 +9,9 @@
},
"branch": "nixpkgs-unstable",
"submodules": false,
"revision": "ee09932cedcef15aaf476f9343d1dea2cb77e261",
"url": "https://github.com/NixOS/nixpkgs/archive/ee09932cedcef15aaf476f9343d1dea2cb77e261.tar.gz",
"hash": "1xz5pa6la2fyj5b1cfigmg3nmml11fyf9ah0rnr4zfgmnwimn2gn"
"revision": "bde09022887110deb780067364a0818e89258968",
"url": "https://github.com/NixOS/nixpkgs/archive/bde09022887110deb780067364a0818e89258968.tar.gz",
"hash": "13mi187zpa4rw680qbwp7pmykjia8cra3nwvjqmsjba3qhlzif5l"
},
"treefmt-nix": {
"type": "Git",
@@ -22,9 +22,9 @@
},
"branch": "main",
"submodules": false,
"revision": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4",
"url": "https://github.com/numtide/treefmt-nix/archive/5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4.tar.gz",
"hash": "0cr6aj9bk7n3y09lwmfjr7xg1f069332xf4q99z3kj1c1mp0wl82"
"revision": "e96d59dff5c0d7fddb9d113ba108f03c3ef99eca",
"url": "https://github.com/numtide/treefmt-nix/archive/e96d59dff5c0d7fddb9d113ba108f03c3ef99eca.tar.gz",
"hash": "02gqyxila3ghw8gifq3mns639x86jcq079kvfvjm42mibx7z5fzb"
}
},
"version": 5
+1 -1
View File
@@ -44,7 +44,7 @@ function classify(branch) {
}
}
module.exports = { classify }
module.exports = { classify, split }
// If called directly via CLI, runs the following tests:
if (!module.parent) {
+2 -2
View File
@@ -111,7 +111,7 @@ This syntax is taken from [MyST](https://myst-parser.readthedocs.io/en/latest/us
#### HTML
Inlining HTML is not allowed.
Parts of the documentation gets rendered to various non-HTML formats, such as man pages in the case of NixOS manual.
Parts of the documentation get rendered to various non-HTML formats, such as man pages in the case of NixOS manual.
#### Roles
@@ -407,7 +407,7 @@ To define a referenceable figure use the following fencing:
:::
```
Defining figures through the `figure` fencing class adds them to a `List of Figures` after the `Table of Contents`.
Defining figures through the `figure` fencing class adds them to a `List of Figures` after the `Table of Contents`.
Though this is not shown in the rendered documentation on nixos.org.
#### Footnotes
+2 -2
View File
@@ -4,7 +4,7 @@ The `nix-shell` command has popularized the concept of transient shell environme
<!--
We should try to document the product, not its development process in the Nixpkgs reference manual,
but *something* needs to be said to provide context for this library.
This is the most future proof sentence I could come up with while Nix itself does yet make use of this.
This is the most future proof sentence I could come up with while Nix itself does not yet make use of this.
Relevant is the current status of the devShell attribute "project": https://github.com/NixOS/nix/issues/7501
-->
However, `nix-shell` is not the only way to create such environments, and even `nix-shell` itself can indirectly benefit from this library.
@@ -60,7 +60,7 @@ devShellTools.unstructuredDerivationInputEnv {
#}
```
Note that `args` is not included, because Nix does not added it to the builder process environment.
Note that `args` is not included, because Nix does not add it to the builder process environment.
:::
+7 -5
View File
@@ -536,7 +536,7 @@ See [](#chap-pkgs-fetchers-caveats) for more details on how to work with the `ha
Returns a [fixed-output derivation](https://nixos.org/manual/nix/stable/glossary.html#gloss-fixed-output-derivation) which downloads an archive from a given URL and decompresses it.
Despite its name, `fetchzip` is not limited to `.zip` files but can also be used with [various compressed tarball formats](#tar-files) by default.
This can extended by specifying additional attributes, see [](#ex-fetchers-fetchzip-rar-archive) to understand how to do that.
This can be extended by specifying additional attributes, see [](#ex-fetchers-fetchzip-rar-archive) to understand how to do that.
### Inputs {#sec-pkgs-fetchers-fetchzip-inputs}
@@ -765,7 +765,7 @@ Used with Subversion. Expects `url` to a Subversion directory, `rev`, and `hash`
## `fetchgit` {#fetchgit}
Used with Git. Expects `url` to a Git repo, `rev` or `tag`, and `hash`. `rev` in this case can be full the git commit id (SHA1 hash), or use `tag` for a tag name like `refs/tags/v1.0`.
Used with Git. Expects `url` to a Git repo, `rev` or `tag`, and `hash`. `rev` in this case can be the full git commit id (SHA1 hash), or use `tag` for a tag name like `refs/tags/v1.0`.
If you want to fetch a tag you should pass the `tag` parameter instead of `rev` which has the same effect as setting `rev = "refs/tags"/${version}"`.
This is safer than just setting `rev = version` w.r.t. possible branch and tag name conflicts.
@@ -799,7 +799,7 @@ Additionally, the following optional arguments can be given:
*`deepClone`* (Boolean)
: Clone the entire repository as opposing to just creating a shallow clone.
: Clone the entire repository as opposed to just creating a shallow clone.
This implies `leaveDotGit`.
*`fetchTags`* (Boolean)
@@ -855,9 +855,11 @@ Used with Mercurial. Expects `url`, `rev`, `hash`, overridable with [`<pkg>.over
A number of fetcher functions wrap part of `fetchurl` and `fetchzip`. They are mainly convenience functions intended for commonly used destinations of source code in Nixpkgs. These wrapper fetchers are listed below.
## `fetchFromGitea` {#fetchfromgitea}
## `fetchFromGitea`, `fetchFromForgejo` and `fetchFromCodeberg` {#fetchfromgitea}
`fetchFromGitea` expects five arguments. `domain` is the gitea server name. `owner` is a string corresponding to the Gitea user or organization that controls this repository. `repo` corresponds to the name of the software repository. These are located at the top of every Gitea HTML page as `owner`/`repo`. `rev` corresponds to the Git commit hash or tag (e.g `v1.0`) that will be downloaded from Git. Finally, `hash` corresponds to the hash of the extracted directory. Again, other hash algorithms are also available but `hash` is currently preferred.
`fetchFromGitea`, also aliased to `fetchFromForgejo`, expects five arguments. `domain` is the Gitea/Forgejo server name. `owner` is a string corresponding to the user or organization that controls this repository. `repo` corresponds to the name of the software repository. These are located at the top of every Gitea/Forgejo HTML page as `owner`/`repo`. `rev` corresponds to the Git commit hash or tag (e.g `v1.0`) that will be downloaded from Git. Finally, `hash` corresponds to the hash of the extracted directory. Again, other hash algorithms are also available but `hash` is currently preferred.
As <codeberg.org> is currently the most popular public Forgejo server, the `fetchFromCodeberg` fetcher is also available, which pre-fills the `domain` attribute.
## `fetchFromGitHub` {#fetchfromgithub}
@@ -8,7 +8,7 @@ Build helpers don't always support fixed-point arguments yet, as support in [`st
Developers can use the Nixpkgs library function [`lib.customisation.extendMkDerivation`](#function-library-lib.customisation.extendMkDerivation) to define a build helper supporting fixed-point arguments from an existing one with such support, with an attribute overlay similar to the one taken by [`<pkg>.overrideAttrs`](#sec-pkg-overrideAttrs).
Besides overriding, `lib.extendMkDerivation` also supports `excludeDrvArgNames` to optionally exclude some arguments in the input fixed-point arguments from passing down the base build helper (specified as `constructDrv`).
Besides overriding, `lib.extendMkDerivation` also supports `excludeDrvArgNames` to optionally exclude some arguments in the input fixed-point arguments from passing down to the base build helper (specified as `constructDrv`).
:::{.example #ex-build-helpers-extendMkDerivation}
@@ -73,7 +73,7 @@ Similarly, if you encounter errors similar to `Error_Protocol ("certificate has
A value of `null` means that `buildImage` will use the first image available in the repository.
:::{.note}
This must be used with `fromImageName`. Using only `fromImageTag` without `fromImageName` will make `buildImage` use the first image available in the repository
This must be used with `fromImageName`. Using only `fromImageTag` without `fromImageName` will make `buildImage` use the first image available in the repository.
:::
_Default value:_ `null`.
@@ -1013,7 +1013,7 @@ Because of this, using this function requires the `kvm` device to be available,
A value of `null` means that `exportImage` will use the first image available in the repository.
:::{.note}
This must be used with `fromImageName`. Using only `fromImageTag` without `fromImageName` will make `exportImage` use the first image available in the repository
This must be used with `fromImageName`. Using only `fromImageTag` without `fromImageName` will make `exportImage` use the first image available in the repository.
:::
_Default value:_ `null`.
@@ -1145,7 +1145,7 @@ $ file /nix/store/by3f40xvc4l6bkis74l0fj4zsy0djgkn-hello.tar.gz
/nix/store/by3f40xvc4l6bkis74l0fj4zsy0djgkn-hello.tar.gz: POSIX tar archive (GNU)
```
If the archive was actually compressed, the output of file would've mentioned that fact.
If the archive was actually compressed, the output of `file` would've mentioned that fact.
Because of this, it may be important to set a proper `name` attribute when using `exportImage` with other functions from `dockerTools`.
:::
@@ -8,7 +8,7 @@ This function can create images in two ways:
- using a virtual machine to create a full NixOS installation.
When testing early-boot or lifecycle parts of NixOS such as a bootloader or multiple generations, it is necessary to opt for a full NixOS system installation.
Whereas for many web servers, applications, it is possible to work with a Nix store only disk image and is faster to build.
Whereas for many web servers and applications, it is possible to work with a Nix store only disk image, which is faster to build.
NixOS tests also use this function when preparing the VM. The `cptofs` method is used when `virtualisation.useBootLoader` is false (the default). Otherwise the second method is used.
@@ -39,7 +39,7 @@ Features are separated in various sections depending on if you opt for a Nix-sto
### On bit-to-bit reproducibility {#sec-make-disk-image-features-reproducibility}
Images are **NOT** deterministic, please do not hesitate to try to fix this, source of determinisms are (not exhaustive) :
Images are **NOT** deterministic. Please do not hesitate to try to fix this. Sources of non-determinism are (not exhaustive):
- bootloader installation has timestamps
- SQLite Nix store database contains registration times
+3 -3
View File
@@ -5,8 +5,8 @@ It makes no assumptions about the container runner you choose to use to run the
The set of functions in `pkgs.ociTools` currently does not handle the [OCI image specification](https://github.com/opencontainers/image-spec).
At a high-level an OCI implementation would download an OCI Image then unpack that image into an OCI Runtime filesystem bundle.
At this point the OCI Runtime Bundle would be run by an OCI Runtime.
At a high level, an OCI implementation would download an OCI Image then unpack that image into an OCI Runtime filesystem bundle.
At this point, the OCI Runtime Bundle would be run by an OCI Runtime.
`pkgs.ociTools` provides utilities to create OCI Runtime bundles.
## buildContainer {#ssec-pkgs-ociTools-buildContainer}
@@ -54,7 +54,7 @@ Note that no user namespace is created, which means that you won't be able to ru
`os` **DEPRECATED**
: Specifies the operating system on which the container filesystem is based on.
: Specifies the operating system on which the container filesystem is based.
If specified, its value should follow the [OCI Image Configuration Specification](https://github.com/opencontainers/image-spec/blob/main/config.md#properties).
According to the linked specification, all possible values for `$GOOS` in [the Go docs](https://go.dev/doc/install/source#environment) should be valid, but will commonly be one of `darwin` or `linux`.
@@ -6,7 +6,7 @@ For hermeticity, Nix derivations do not allow any state to be carried over betwe
However, we can tell Nix explicitly what the previous build state was, by representing that previous state as a derivation output. This allows the passed build state to be used for an incremental build.
To change a normal derivation to a checkpoint based build, these steps must be taken:
To change a normal derivation to a checkpoint-based build, these steps must be taken:
```nix
{
checkpointArtifacts = (pkgs.checkpointBuildTools.prepareCheckpointBuild pkgs.virtualbox);
@@ -14,11 +14,11 @@ Accepted arguments are:
- `executableName`
The name of the wrapper executable. Defaults to `pname` if set, or `name` otherwise.
- `targetPkgs`
Packages to be installed for the main host's architecture (i.e. x86_64 on x86_64 installations). Along with libraries binaries are also installed.
Packages to be installed for the main host's architecture (i.e. x86_64 on x86_64 installations). Along with libraries, binaries are also installed.
- `multiPkgs`
Packages to be installed for all architectures supported by a host (i.e. i686 and x86_64 on x86_64 installations). Only libraries are installed by default.
- `multiArch`
Whether to install 32bit multiPkgs into the FHSEnv in 64bit environments
Whether to install 32-bit multiPkgs into the FHSEnv in 64-bit environments
- `extraBuildCommands`
Additional commands to be executed for finalizing the directory structure.
- `extraBuildCommandsMulti`
@@ -47,11 +47,9 @@ You can create a simple environment using a `shell.nix` like this:
(with pkgs; [
udev
alsa-lib
])
++ (with pkgs.xorg; [
libX11
libXcursor
libXrandr
libx11
libxcursor
libxrandr
]);
multiPkgs =
pkgs:
@@ -1,6 +1,6 @@
# pkgs.makeSetupHook {#sec-pkgs.makeSetupHook}
`pkgs.makeSetupHook` is a build helper that produces hooks that go in to `nativeBuildInputs`
`pkgs.makeSetupHook` is a build helper that produces hooks that go into `nativeBuildInputs`
## Usage {#sec-pkgs.makeSetupHook-usage}
@@ -136,7 +136,7 @@ A set of functions that build a predefined set of minimal Linux distributions im
### Attributes {#vm-tools-diskImageFuns-attributes}
* `size` (optional, defaults to `4096`). The size of the image, in MiB.
* `extraPackages` (optional). A list names of additional packages from the distribution that should be included in the image.
* `extraPackages` (optional). A list of names of additional packages from the distribution that should be included in the image.
### Examples {#vm-tools-diskImageFuns-examples}
+2 -2
View File
@@ -63,7 +63,7 @@ Note the moduleNames used in cmake find_package are case sensitive.
Check a packaged static site's links with the [`lychee` package](https://search.nixos.org/packages?show=lychee&type=packages&query=lychee).
You may use Nix to reproducibly build static websites, such as for software documentation.
Some packages will install documentation in their `out` or `doc` outputs, or maybe you have dedicated package where you've made your static site reproducible by running a generator, such as [Hugo](https://gohugo.io/) or [mdBook](https://rust-lang.github.io/mdBook/), in a derivation.
Some packages will install documentation in their `out` or `doc` outputs, or maybe you have a dedicated package where you've made your static site reproducible by running a generator, such as [Hugo](https://gohugo.io/) or [mdBook](https://rust-lang.github.io/mdBook/), in a derivation.
If you have a static site that can be built with Nix, you can use `lycheeLinkCheck` to check that the hyperlinks in your site are correct, and do so as part of your Nix workflow and CI.
@@ -578,7 +578,7 @@ Use the derivation hash to invalidate the output via name, for testing.
Type: `(a@{ name, ... } -> Derivation) -> a -> Derivation`
Normally, fixed output derivations can and should be cached by their output hash only, but for testing we want to re-fetch everytime the fetcher changes.
Normally, fixed output derivations can and should be cached by their output hash only, but for testing we want to re-fetch every time the fetcher changes.
Changes to the fetcher become apparent in the drvPath, which is a hash of how to fetch, rather than a fixed store path.
By inserting this hash into the name, we can make sure to re-run the fetcher every time the fetcher changes.
@@ -8,7 +8,7 @@ Like [`stdenv.mkDerivation`](#sec-using-stdenv), each of these build helpers cre
The function `runCommandWith` returns a derivation built using the specified command(s), in a specified environment.
It is the underlying base function of all [`runCommand*` variants].
It is the underlying base function of all [`runCommand*` variants].
The general behavior is controlled via a single attribute set passed
as the first argument, and allows specifying `stdenv` freely.
@@ -45,7 +45,7 @@ runCommandWith :: {
:::
`stdenv` (Derivation)
: The [standard environment](#chap-stdenv) to use, defaulting to `pkgs.stdenv`
: The [standard environment](#chap-stdenv) to use, defaulting to `pkgs.stdenv`.
`derivationArgs` (Attribute set)
: Additional arguments for [`mkDerivation`](#sec-using-stdenv).
@@ -160,7 +160,7 @@ runCommandWith { inherit name derivationArgs; } buildCommand
## Writing text files {#trivial-builder-text-writing}
Nixpkgs provides the following functions for producing derivations which write text files or executable scripts into the Nix store.
They are useful for creating files from Nix expression, and are all implemented as convenience wrappers around `writeTextFile`.
They are useful for creating files from Nix expressions, and are all implemented as convenience wrappers around `writeTextFile`.
Each of these functions will cause a derivation to be produced.
When you coerce the result of each of these functions to a string with [string interpolation](https://nixos.org/manual/nix/stable/language/string-interpolation) or [`toString`](https://nixos.org/manual/nix/stable/language/builtins#builtins-toString), it will evaluate to the [store path](https://nixos.org/manual/nix/stable/store/store-path) of this derivation.
@@ -682,7 +682,7 @@ writeTextFile {
## `concatTextFile`, `concatText`, `concatScript` {#trivial-builder-concatText}
These functions concatenate `files` to the Nix store in a single file. This is useful for configuration files structured in lines of text. `concatTextFile` takes an attribute set and expects two arguments, `name` and `files`. `name` corresponds to the name used in the Nix store path. `files` will be the files to be concatenated. You can also set `executable` to true to make this file have the executable bit set.
`concatText` and`concatScript` are simple wrappers over `concatTextFile`.
`concatText` and `concatScript` are simple wrappers over `concatTextFile`.
Here are a few examples:
```nix
+1 -1
View File
@@ -2,6 +2,6 @@
* Make sure you have a [GitHub account](https://github.com/signup/free)
* Make sure there is no open issue on the topic
* [Submit a new issue](https://github.com/NixOS/nixpkgs/issues/new/choose) by choosing the kind of topic and fill out the template
* [Submit a new issue](https://github.com/NixOS/nixpkgs/issues/new/choose) by choosing the kind of topic and filling out the template
<!-- In the future this section could also include more detailed information on the issue templates -->
+3 -1
View File
@@ -54,7 +54,8 @@ stdenvNoCC.mkDerivation (
};
in
{
name = "nixpkgs-manual";
version = lib.trivial.release;
pname = "nixpkgs-manual";
nativeBuildInputs = [ nixos-render-docs ];
@@ -168,6 +169,7 @@ stdenvNoCC.mkDerivation (
};
tests = {
# Don't run this in CI because it's not reproducible
manpage-urls = callPackage ../tests/manpage-urls.nix { };
};
};
+1
View File
@@ -22,6 +22,7 @@ haredo.section.md
installShellFiles.section.md
julec.section.md
just.section.md
libglycin.section.md
libiconv.section.md
libxml2.section.md
meson.section.md
+47
View File
@@ -0,0 +1,47 @@
# libglycin {#libglycin-hooks}
[Glycin](https://gitlab.gnome.org/GNOME/glycin) is a library for sandboxed and extendable image loading.
[]{#libglycin-setup-hook} For most applications using it, individual image formats are loaded through binaries provided by `glycin-loaders`. The paths of these loaders must be injected into the environment, e.g. using [`wrapGAppsHook`](#ssec-gnome-hooks). `libglycin.setupHook` will do that.
[]{#libglycin-patch-vendor-hook} Additionally, for Rust projects `glycin` Rust crate itself requires a patch to become self-contained. `libglycin.patchVendorHook` will do that. This is not needed for projects using the ELF library from `libglycin` package.
## Example code snippet {#libglycin-hooks-example-code-snippet}
```nix
{
lib,
rustPlatform,
libglycin,
glycin-loaders,
wrapGAppsHook4,
}:
rustPlatform.buildRustPackage {
# ...
cargoHash = "...";
nativeBuildInputs = [
wrapGAppsHook4
libglycin.patchVendorHook
];
buildInputs = [
libglycin.setupHook
glycin-loaders
];
# ...
}
```
## Variables controlling glycin-loaders {#libglycin-hook-variables-controlling}
### `glycinCargoDepsPath` {#glycin-cargo-deps-path}
Path to a directory containing the `glycin` crate to patch. Defaults to the crate directory created by `cargoSetupHook`, or `./vendor/`.
### `dontWrapGlycinLoaders` {#glycin-dont-wrap}
Disable adding the Glycin loaders path `XDG_DATA_DIRS` with `wrapGAppsHook`.
+4
View File
@@ -79,6 +79,10 @@ The [bundle type](https://tauri.app/v1/guides/building/) to build.
Disables using `tauriBuildHook`.
#### `dontTauriFixup` {#dont-tauri-fixup}
Disables the `tauriFixupHook` pre fixup phase.
#### `dontTauriInstall` {#dont-tauri-install}
Disables using `tauriInstallPostBuildHook` and `tauriInstallHook`.
+1 -1
View File
@@ -10,7 +10,7 @@ The hook runs in `installCheckPhase`, requiring `doInstallCheck` is enabled for
lib,
stdenv,
udevCheckHook,
# ...
# ...
}:
stdenv.mkDerivation (finalAttrs: {
+1 -1
View File
@@ -9,7 +9,7 @@ You use it like this:
lib,
stdenv,
versionCheckHook,
# ...
# ...
}:
stdenv.mkDerivation (finalAttrs: {
+4
View File
@@ -32,6 +32,10 @@ stdenv.mkDerivation {
The variables below are exclusive to `zig`.
#### `dontUseZigConfigure` {#dont-use-zig-configure}
Disables using `zigConfigurePhase`.
#### `dontUseZigBuild` {#dont-use-zig-build}
Disables using `zigBuildPhase`.
@@ -129,6 +129,8 @@ The hooks do the following:
- []{#ssec-gnome-hooks-gst-grl-plugins} Setup hooks of `gst_all_1.gstreamer` and `grilo` will populate the `GST_PLUGIN_SYSTEM_PATH_1_0` and `GRL_PLUGIN_PATH` variables, respectively, which will then be added to the wrapper by `wrapGApps*` hook.
- []{#ssec-gnome-hooks-libglycin} `libglycin`'s [setup hook](#libglycin-setup-hook) will populate `XDG_DATA_DIRS` with the path to the loaders.
You can also pass additional arguments to `makeWrapper` using `gappsWrapperArgs` in `preFixup` hook:
```nix
+1 -1
View File
@@ -56,7 +56,7 @@ android.section.md
astal.section.md
beam.section.md
chicken.section.md
coq.section.md
rocq.section.md
cosmic.section.md
crystal.section.md
cuda.section.md
+148 -9
View File
@@ -96,7 +96,7 @@ neovim.overrideAttrs (oldAttrs: {
})
```
### Specificities for some plugins {#neovim-plugin-specificities}
## Specificities for some plugins {#neovim-plugin-specificities}
### Plugin optional configuration {#neovim-plugin-required-snippet}
@@ -105,7 +105,7 @@ 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`.
#### LuaRocks based plugins {#neovim-luarocks-based-plugins}
## LuaRocks based plugins {#neovim-luarocks-based-plugins}
In order to automatically handle plugin dependencies, several Neovim plugins
upload their package to [LuaRocks](https://www.luarocks.org). This means less work for nixpkgs maintainers in the long term as dependencies get updated automatically.
@@ -122,12 +122,34 @@ For instance:
```
To update these packages, you should use the lua updater rather than vim's.
#### Treesitter {#neovim-plugin-treesitter}
## Treesitter {#neovim-plugin-treesitter}
By default `nvim-treesitter` encourages you to download, compile and install
the required Treesitter grammars at run time with `:TSInstall`. This works
poorly on NixOS. Instead, to install the `nvim-treesitter` plugins with a set
of precompiled grammars, you can use the `nvim-treesitter.withPlugins` function:
[Treesitter](https://tree-sitter.github.io/) provides syntax parsing for Neovim, enabling features like:
Advanced syntax highlighting, Code folding, Indentation and more.
Most Neovim users manage treesitter through the `nvim-treesitter` plugin, which provides:
- Commands for managing grammars and queries,
e.g. `:TSInstall`, which downloads, compiles and installs them at runtime.
- A custom indentation implementation ([`:h indentexpr`](https://neovim.io/doc/user/options.html#'indentexpr'))
for languages with `indents.scm` queries.
These features build on top of treesitter functionality that is built into Neovim.
In nixpkgs, grammars and queries are precompiled and packaged separately. This means:
- You can use treesitter features **without** installing `nvim-treesitter`.
- You only need `nvim-treesitter` if you want its custom indentation implementation.
- Plugins that depend on grammars can reference them directly.
### Treesitter setup using `nvim-treesitter` {#neovim-plugin-nvim-treesitter}
::: {.tip}
Choose this approach if you want to use `nvim-treesitter`'s custom indentation expression.
:::
To install `nvim-treesitter` combined with a set of precompiled grammars,
you can use the `nvim-treesitter.withPlugins` function:
```nix
(pkgs.neovim.override {
@@ -148,10 +170,127 @@ of precompiled grammars, you can use the `nvim-treesitter.withPlugins` function:
To enable all grammars packaged in nixpkgs, use `pkgs.vimPlugins.nvim-treesitter.withAllGrammars`.
For how to configure `nvim-treesitter` and set up syntax highlighting, indentation, folding, etc.,
please refer to the `:help nvim-treesitter-quickstart` plugin documentation.
### Testing Neovim plugins {#testing-neovim-plugins}
::: {.note}
When using Nix-managed grammars, `:checkhealth nvim-treesitter` will report no installed languages.
This is expected behavior because:
- The `nvim-treesitter` health check searches its configured install directory.
- Nix installs grammars to the Nix store and adds them to the `runtimepath` instead.
**To verify Nix-managed parsers and queries**, use `:checkhealth vim.treesitter` instead.
:::
### Treesitter setup using standalone grammars and queries {#neovim-plugin-treesitter-standalone}
::: {.tip}
Choose this approach if you
- Want minimal dependencies.
- Don't need `nvim-treesitter`'s custom indentation expression.
:::
You can install the standalone parsers and queries directly without installing `nvim-treesitter`:
```nix
(pkgs.neovim.override {
configure = {
packages.myPlugins =
with pkgs.vimPlugins;
let
# Select the grammars you need
treesitter-grammars = with nvim-treesitter-parsers; [
nix
python
];
# Queries are needed for treesitter based syntax highlighting and folds.
treesitter-queries = map (p: p.associatedQuery) treesitter-grammars;
in
{
start = [
# regular plugins
]
++ treesitter-grammars
++ treesitter-queries;
};
};
})
```
You can enable treesitter features for installed grammars in a `FileType` autocommand
or in an `ftplugin/<language>.lua` script, e.g.
```lua
vim.api.nvim_create_autocmd('FileType', {
pattern = { 'rust', 'javascript', 'zig' },
callback = function(ev)
local bufnr = ev.buf
-- Enable treesitter syntax highlighting and parsing for the current buffer
-- (Requires queries to be installed)
vim.treesitter.start(bufnr)
-- Enable treesitter based code folding
-- (folds are window-scoped, not buffer-scoped)
-- (Requires queries to be installed)
vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()'
vim.wo.foldmethod = 'expr'
end,
})
```
### Treesitter grammars as plugin dependencies {#neovim-plugin-treesitter-grammar-dependencies}
Some Neovim plugins (like `neotest` adapters, `markdoc-nvim`, `hurl-nvim`) depend on treesitter grammars.
These dependencies are usually declared in plugin overrides.
::: {.important}
Some plugin READMEs may suggest that they depend on `nvim-treesitter`.
**This is almost always not the case.**
`nvim-treesitter` no longer provides a Lua module API for other plugins to use.
In the vast majority of cases, these plugins:
- **Depend on parsers** (not on `nvim-treesitter` or its queries).
- **Bundle their own queries** (either as `*.scm` files or hardcoded in the Lua sources).
:::
To add grammars as a plugin dependency, add an [override](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/overrides.nix):
```nix
{
foo-nvim = super.foo-nvim.overrideAttrs {
dependencies = with self.nvim-treesitter-parsers; [
markdown
markdown_inline
html
];
};
}
```
If a plugin actually does depend on the `nvim-treesitter` legacy module API, you can add
`nvim-treesitter-legacy` as a dependency:
```nix
{
foo-legacy-nvim = super.foo-legacy-nvim.overrideAttrs {
dependencies = with self; [
nvim-treesitter-legacy
nvim-treesitter-parsers.nix
];
};
}
```
::: {.caution}
`nvim-treesitter-legacy` exists for the purpose of easing transition and will be removed in 26.11.
If a Neovim configuration contains both `nvim-treesitter` and `nvim-treesitter-legacy`, it will fail to evaluate.
:::
## Testing Neovim plugins {#testing-neovim-plugins}
### neovimRequireCheck {#testing-neovim-plugins-neovim-require-check}
#### neovimRequireCheck {#testing-neovim-plugins-neovim-require-check}
`neovimRequireCheck` is a simple test which checks if Neovim can require lua modules without errors. This is often enough to catch missing dependencies.
It accepts a single string for a module, or a list of module strings to test.
+1 -1
View File
@@ -112,7 +112,7 @@ For example, to propagate a dependency on SDL2 for lockfiles that select the Nim
lib,
# …
SDL2,
# …
# …
}:
{
+2 -2
View File
@@ -116,14 +116,14 @@ Here is a second example, this time using a source archive generated with `dune-
buildDunePackage,
}:
buildDunePackage (finalAtts: {
buildDunePackage (finalAttrs: {
pname = "wtf8";
version = "1.0.2";
minimalOCamlVersion = "4.02";
src = fetchurl {
url = "https://github.com/flowtype/ocaml-wtf8/releases/download/v${finalAtts.version}/wtf8-v${finalAtts.version}.tbz";
url = "https://github.com/flowtype/ocaml-wtf8/releases/download/v${finalAttrs.version}/wtf8-v${finalAttrs.version}.tbz";
hash = "sha256-d5/3KUBAWRj8tntr4RkJ74KWW7wvn/B/m1nx0npnzyc=";
};
+36 -36
View File
@@ -50,7 +50,6 @@ sets are
* `pkgs.python27Packages`
* `pkgs.python3Packages`
* `pkgs.python310Packages`
* `pkgs.python311Packages`
* `pkgs.python312Packages`
* `pkgs.python313Packages`
@@ -99,13 +98,14 @@ The following is an example:
hypothesis,
}:
buildPythonPackage rec {
buildPythonPackage (finalAttrs: {
pname = "pytest";
version = "3.3.1";
pyproject = true;
src = fetchPypi {
inherit pname version;
inherit (finalAttrs) pname version;
hash = "sha256-z4Q23FnYaVNG/NOrKW3kZCXsqwDWQJbOvnn7Ueyy65M=";
};
@@ -130,7 +130,7 @@ buildPythonPackage rec {
nativeCheckInputs = [ hypothesis ];
meta = {
changelog = "https://github.com/pytest-dev/pytest/releases/tag/${version}";
changelog = "https://github.com/pytest-dev/pytest/releases/tag/${finalAttrs.version}";
description = "Framework for writing tests";
homepage = "https://github.com/pytest-dev/pytest";
license = lib.licenses.mit;
@@ -140,7 +140,7 @@ buildPythonPackage rec {
lsix
];
};
}
})
```
The `buildPythonPackage` mainly does four things:
@@ -304,13 +304,13 @@ specifying an interpreter version), like this:
fetchPypi,
}:
python3Packages.buildPythonApplication rec {
python3Packages.buildPythonApplication (finalAttrs: {
pname = "luigi";
version = "2.7.9";
pyproject = true;
src = fetchPypi {
inherit pname version;
inherit (finalAttrs) pname version;
hash = "sha256-Pe229rT0aHwA98s+nTHQMEFKZPo/yw6sot8MivFDvAw=";
};
@@ -324,7 +324,7 @@ python3Packages.buildPythonApplication rec {
meta = {
# ...
};
}
})
```
This is then added to `pkgs/by-name` just as any other application would be.
@@ -896,7 +896,7 @@ on NixOS.
# ...
environment.systemPackages = with pkgs; [
(python310.withPackages (
(python314.withPackages (
ps: with ps; [
numpy
toolz
@@ -928,13 +928,13 @@ building Python libraries is [`buildPythonPackage`](#buildpythonpackage-function
setuptools,
}:
buildPythonPackage rec {
buildPythonPackage (finalAttrs: {
pname = "toolz";
version = "0.10.0";
pyproject = true;
src = fetchPypi {
inherit pname version;
inherit (finalAttrs) pname version;
hash = "sha256-CP3V73yWSArRHBLUct4hrNMjWZlvaaUlkpm1QP66RWA=";
};
@@ -950,12 +950,12 @@ buildPythonPackage rec {
];
meta = {
changelog = "https://github.com/pytoolz/toolz/releases/tag/${version}";
changelog = "https://github.com/pytoolz/toolz/releases/tag/${finalAttrs.version}";
homepage = "https://github.com/pytoolz/toolz";
description = "List processing tools and functional utilities";
license = lib.licenses.bsd3;
};
}
})
```
What happens here? The function [`buildPythonPackage`](#buildpythonpackage-function) is called and as argument
@@ -985,13 +985,13 @@ with import <nixpkgs> { };
(
let
my_toolz = python313.pkgs.buildPythonPackage rec {
my_toolz = python313.pkgs.buildPythonPackage (finalAttrs: {
pname = "toolz";
version = "0.10.0";
pyproject = true;
src = fetchPypi {
inherit pname version;
inherit (finalAttrs) pname version;
hash = "sha256-CP3V73yWSArRHBLUct4hrNMjWZlvaaUlkpm1QP66RWA=";
};
@@ -1005,7 +1005,7 @@ with import <nixpkgs> { };
description = "List processing tools and functional utilities";
# [...]
};
};
});
in
python313.withPackages (
@@ -1062,13 +1062,13 @@ order to build [`datashape`](https://github.com/blaze/datashape).
pytestCheckHook,
}:
buildPythonPackage rec {
buildPythonPackage (finalAttrs: {
pname = "datashape";
version = "0.4.7";
pyproject = true;
src = fetchPypi {
inherit pname version;
inherit (finalAttrs) pname version;
hash = "sha256-FLLvdm1MllKrgTGC6Gb0k0deZeVYvtCCLji/B7uhong=";
};
@@ -1083,12 +1083,12 @@ buildPythonPackage rec {
nativeCheckInputs = [ pytestCheckHook ];
meta = {
changelog = "https://github.com/blaze/datashape/releases/tag/${version}";
changelog = "https://github.com/blaze/datashape/releases/tag/${finalAttrs.version}";
homepage = "https://github.com/ContinuumIO/datashape";
description = "Data description language";
license = lib.licenses.bsd2;
};
}
})
```
We can see several runtime dependencies, `numpy`, `multipledispatch`, and
@@ -1111,13 +1111,13 @@ when building the bindings and are therefore added as [`buildInputs`](#var-stden
libxslt,
}:
buildPythonPackage rec {
buildPythonPackage (finalAttrs: {
pname = "lxml";
version = "3.4.4";
pyproject = true;
src = fetchPypi {
inherit pname version;
inherit (finalAttrs) pname version;
hash = "sha256-s9NiusRxFydHzaNRMjjxFcvWxfi45jGb9ql6eJJyQJk=";
};
@@ -1137,13 +1137,13 @@ buildPythonPackage rec {
];
meta = {
changelog = "https://github.com/lxml/lxml/releases/tag/lxml-${version}";
changelog = "https://github.com/lxml/lxml/releases/tag/lxml-${finalAttrs.version}";
description = "Pythonic binding for the libxml2 and libxslt libraries";
homepage = "https://lxml.de";
license = lib.licenses.bsd3;
maintainers = with lib.maintainers; [ sjourdois ];
};
}
})
```
In this example `lxml` and Nix are able to work out exactly where the relevant
@@ -1173,13 +1173,13 @@ therefore we have to set `LDFLAGS` and `CFLAGS`.
scipy,
}:
buildPythonPackage rec {
buildPythonPackage (finalAttrs: {
pname = "pyfftw";
version = "0.9.2";
pyproject = true;
src = fetchPypi {
inherit pname version;
inherit (finalAttrs) pname version;
hash = "sha256-9ru2r6kwhUCaskiFoaPNuJCfCVoUL01J40byvRt4kHQ=";
};
@@ -1207,7 +1207,7 @@ buildPythonPackage rec {
pythonImportsCheck = [ "pyfftw" ];
meta = {
changelog = "https://github.com/pyFFTW/pyFFTW/releases/tag/v${version}";
changelog = "https://github.com/pyFFTW/pyFFTW/releases/tag/v${finalAttrs.version}";
description = "Pythonic wrapper around FFTW, the FFT library, presenting a unified interface for all the supported transforms";
homepage = "http://hgomersall.github.com/pyFFTW";
license = with lib.licenses; [
@@ -1215,7 +1215,7 @@ buildPythonPackage rec {
bsd3
];
};
}
})
```
Note also the line [`doCheck = false;`](#var-stdenv-doCheck), we explicitly disabled running the test-suite.
@@ -1609,13 +1609,13 @@ We first create a function that builds `toolz` in `~/path/to/toolz/release.nix`
setuptools,
}:
buildPythonPackage rec {
buildPythonPackage (finalAttrs: {
pname = "toolz";
version = "0.10.0";
pyproject = true;
src = fetchPypi {
inherit pname version;
inherit (finalAttrs) pname version;
hash = "sha256-CP3V73yWSArRHBLUct4hrNMjWZlvaaUlkpm1QP66RWA=";
};
@@ -1627,7 +1627,7 @@ buildPythonPackage rec {
description = "List processing tools and functional utilities";
license = lib.licenses.bsd3;
};
}
})
```
It takes an argument [`buildPythonPackage`](#buildpythonpackage-function). We now call this function using
@@ -1682,7 +1682,7 @@ with import <nixpkgs> { };
});
};
in
pkgs.python310.override { inherit packageOverrides; };
pkgs.python313.override { inherit packageOverrides; };
in
python.withPackages (ps: [ ps.pandas ])
@@ -1706,7 +1706,7 @@ with import <nixpkgs> { };
let
packageOverrides = self: super: { scipy = super.scipy_0_17; };
in
(pkgs.python310.override { inherit packageOverrides; }).withPackages (ps: [ ps.blaze ])
(pkgs.python313.override { inherit packageOverrides; }).withPackages (ps: [ ps.blaze ])
).env
```
@@ -1722,13 +1722,13 @@ let
newpkgs = import pkgs.path {
overlays = [
(self: super: {
python310 =
python313 =
let
packageOverrides = python-self: python-super: {
numpy = python-super.numpy_1_18;
};
in
super.python310.override { inherit packageOverrides; };
super.python313.override { inherit packageOverrides; };
})
];
};
@@ -2135,7 +2135,7 @@ The following rules are desired to be respected:
* `pythonImportsCheck` is set. This is still a good smoke test even if `pytestCheckHook` is set.
* `meta.platforms` takes the default value in many cases.
It does not need to be set explicitly unless the package requires a specific platform.
* The file is formatted with `nixfmt-rfc-style`.
* The file is formatted correctly (e.g., `nix-shell --run treefmt`).
* Commit names of Python libraries must reflect that they are Python
libraries (e.g. `python3Packages.numpy: 1.11 -> 1.12` rather than `numpy: 1.11 -> 1.12`).
See also [`pkgs/README.md`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/README.md#commit-conventions).
@@ -1,14 +1,21 @@
# Coq and coq packages {#sec-language-coq}
# Rocq and rocq packages {#sec-language-rocq}
## Coq derivation: `coq` {#coq-derivation-coq}
Note that "The Rocq Prover" (Rocq for short) is the new name of the
proof assistant formerly known as Coq. The `coq` and `coqPackages`
derivations currently remain for both older versions of Coq, but also
some versions of Rocq during the renaming transition. In the latter
case, the `coq` derivation encompasses the compatibility binaries
(`coqtop`, `coqc`, etc.) in addition to the `rocq` binary. The packages
only in `coqPackages` are the ones which currently still depend on these
compatibility binaries.
The Coq derivation is overridable through the `coq.override overrides`, where overrides is an attribute set which contains the arguments to override. We recommend overriding either of the following:
## Rocq derivation: `rocq-core` {#rocq-derivation-rocq}
* `version` (optional, defaults to the latest version of Coq selected for nixpkgs, see `pkgs/top-level/coq-packages` to witness this choice), which follows the conventions explained in the `coqPackages` section below,
* `customOCamlPackages` (optional, defaults to `null`, which lets Coq choose a version automatically), which can be set to any of the ocaml packages attribute of `ocaml-ng` (such as `ocaml-ng.ocamlPackages_4_10` which is the default for Coq 8.11 for example).
* `coq-version` (optional, defaults to the short version e.g. "8.10"), is a version number of the form "x.y" that indicates which Coq's version build behavior to mimic when using a source which is not a release. E.g. `coq.override { version = "d370a9d1328a4e1cdb9d02ee032f605a9d94ec7a"; coq-version = "8.10"; }`.
The Rocq derivation is overridable through the `rocq-core.override overrides`, where overrides is an attribute set which contains the arguments to override. We recommend overriding either of the following:
The associated package set can be obtained using `mkCoqPackages coq`, where `coq` is the derivation to use.
* `version` (optional, defaults to the latest version of Rocq selected for nixpkgs, see `pkgs/top-level/rocq-packages` to witness this choice), which follows the conventions explained in the `rocqPackages` section below,
* `customOCamlPackages` (optional, defaults to `null`, which lets Rocq choose a version automatically), which can be set to any of the ocaml packages attribute of `ocaml-ng` (such as `ocaml-ng.ocamlPackages_4_14` which is the default for Rocq 9.1 for example).
* `rocq-version` (optional, defaults to the short version e.g. "9.1"), is a version number of the form "x.y" that indicates which Rocq's version build behavior to mimic when using a source which is not a release. E.g. `rocq-core.override { version = "40be8435e132aab2231a79091f011ebc3e64a753"; rocq-version = "9.1"; }`.
## Creating custom Coq environments with `coq.withPackages` {#coq-withPackages}
@@ -29,9 +36,11 @@ coq.withPackages (
)
```
## Coq packages attribute sets: `coqPackages` {#coq-packages-attribute-sets-coqpackages}
If you install the `vsrocq-language-server` or `rocq-lsp` server, make sure to list them as part of the above `coq.withPackages` expression instead of installing them separately if you want them to find your Coq/Rocq packages.
The recommended way of defining a derivation for a Coq library, is to use the `coqPackages.mkCoqDerivation` function, which is essentially a specialization of `mkDerivation` taking into account most of the specifics of Coq libraries. The following attributes are supported:
## Rocq packages attribute sets: `rocqPackages` {#rocq-packages-attribute-sets-rocqpackages}
The recommended way of defining a derivation for a Rocq library, is to use the `rocqPackages.mkRocqDerivation` function, which is essentially a specialization of `mkDerivation` taking into account most of the specifics of Rocq libraries. The following attributes are supported:
* `pname` (required) is the name of the package,
* `version` (optional, defaults to `null`), is the version to fetch and build,
@@ -41,108 +50,85 @@ The recommended way of defining a derivation for a Coq library, is to use the `c
* if it is a path or a string representing an absolute path (i.e. starting with `"/"`), the provided path is selected as a source, and the `version` attribute of the resulting derivation is set to `"dev"`,
* if it is a string of the form `owner:branch` then it tries to download the `branch` of owner `owner` for a project of the same name using the same vcs, and the `version` attribute of the resulting derivation is set to `"dev"`, additionally if the owner is not provided (i.e. if the `owner:` prefix is missing), it defaults to the original owner of the package (see below),
* if it is a string of the form `"#N"`, and the domain is github, then it tries to download the current head of the pull request `#N` from github,
* `defaultVersion` (optional). Coq libraries may be compatible with some specific versions of Coq only. The `defaultVersion` attribute is used when no `version` is provided (or if `version = null`) to select the version of the library to use by default, depending on the context. This selection will mainly depend on a `coq` version number but also possibly on other packages versions (e.g. `mathcomp`). If its value ends up to be `null`, the package is marked for removal in end-user `coqPackages` attribute set.
* `defaultVersion` (optional). Rocq libraries may be compatible with some specific versions of Rocq only. The `defaultVersion` attribute is used when no `version` is provided (or if `version = null`) to select the version of the library to use by default, depending on the context. This selection will mainly depend on a `rocq-core` version number but also possibly on other packages versions (e.g. `mathcomp`). If its value ends up to be `null`, the package is marked for removal in end-user `rocqPackages` attribute set.
* `release` (optional, defaults to `{}`), lists all the known releases of the library and for each of them provides an attribute set with at least a `hash` attribute (you may put the empty string `""` in order to automatically insert a fake hash, this will trigger an error which will allow you to find the correct hash), each attribute set of the list of releases also takes optional overloading arguments for the fetcher as below (i.e.`domain`, `owner`, `repo`, `rev`, `artifact` assuming the default fetcher is used) and optional overrides for the result of the fetcher (i.e. `version` and `src`).
* `fetcher` (optional, defaults to a generic fetching mechanism supporting github or gitlab based infrastructures), is a function that takes at least an `owner`, a `repo`, a `rev`, and a `hash` and returns an attribute set with a `version` and `src`.
* `repo` (optional, defaults to the value of `pname`),
* `owner` (optional, defaults to `"coq-community"`).
* `domain` (optional, defaults to `"github.com"`), domains including the strings `"github"` or `"gitlab"` in their names are automatically supported, otherwise, one must change the `fetcher` argument to support them (cf `pkgs/development/coq-modules/heq/default.nix` for an example),
* `owner` (optional, defaults to `"rocq-community"`).
* `domain` (optional, defaults to `"github.com"`), domains including the strings `"github"` or `"gitlab"` in their names are automatically supported, otherwise, one must change the `fetcher` argument to support them (cf `pkgs/development/rocq-modules/bignums/default.nix` for an example),
* `releaseRev` (optional, defaults to `(v: v)`), provides a default mapping from release names to revision hashes/branch names/tags,
* `releaseArtifact` (optional, defaults to `(v: null)`), provides a default mapping from release names to artifact names (only works for github artifact for now),
* `displayVersion` (optional), provides a way to alter the computation of `name` from `pname`, by explaining how to display version numbers,
* `namePrefix` (optional, defaults to `[ "coq" ]`), provides a way to alter the computation of `name` from `pname`, by explaining which dependencies must occur in `name`,
* `namePrefix` (optional, defaults to `[ "rocq-core" ]`), provides a way to alter the computation of `name` from `pname`, by explaining which dependencies must occur in `name`,
* `nativeBuildInputs` (optional), is a list of executables that are required to build the current derivation, in addition to the default ones (namely `which`, `dune` and `ocaml` depending on whether `useDune`, `useDuneifVersion` and `mlPlugin` are set).
* `extraNativeBuildInputs` (optional, deprecated), an additional list of derivation to add to `nativeBuildInputs`,
* `overrideNativeBuildInputs` (optional) replaces the default list of derivation to which `nativeBuildInputs` and `extraNativeBuildInputs` adds extra elements,
* `buildInputs` (optional), is a list of libraries and dependencies that are required to build and run the current derivation, in addition to the default one `[ coq ]`,
* `buildInputs` (optional), is a list of libraries and dependencies that are required to build and run the current derivation, in addition to the default one `[ rocq-core ]`,
* `extraBuildInputs` (optional, deprecated), an additional list of derivation to add to `buildInputs`,
* `overrideBuildInputs` (optional) replaces the default list of derivation to which `buildInputs` and `extraBuildInputs` adds extras elements,
* `propagatedBuildInputs` (optional) is passed as is to `mkDerivation`, we recommend to use this for Coq libraries and Coq plugin dependencies, as this makes sure the paths of the compiled libraries and plugins will always be added to the build environments of subsequent derivation, which is necessary for Coq packages to work correctly,
* `mlPlugin` (optional, defaults to `false`). Some extensions (plugins) might require OCaml and sometimes other OCaml packages. Standard dependencies can be added by setting the current option to `true`. For a finer grain control, the `coq.ocamlPackages` attribute can be used in `nativeBuildInputs`, `buildInputs`, and `propagatedBuildInputs` to depend on the same package set Coq was built against.
* `propagatedBuildInputs` (optional) is passed as is to `mkDerivation`, we recommend to use this for Rocq libraries and Rocq plugin dependencies, as this makes sure the paths of the compiled libraries and plugins will always be added to the build environments of subsequent derivation, which is necessary for Rocq packages to work correctly,
* `mlPlugin` (optional, defaults to `false`). Some extensions (plugins) might require OCaml and sometimes other OCaml packages. Standard dependencies can be added by setting the current option to `true`. For a finer grain control, the `rocq-core.ocamlPackages` attribute can be used in `nativeBuildInputs`, `buildInputs`, and `propagatedBuildInputs` to depend on the same package set Rocq was built against.
* `useDuneifVersion` (optional, default to `(x: false)` uses Dune to build the package if the provided predicate evaluates to true on the version, e.g. `useDuneifVersion = versions.isGe "1.1"` will use dune if the version of the package is greater or equal to `"1.1"`,
* `useDune` (optional, defaults to `false`) uses Dune to build the package if set to true, the presence of this attribute overrides the behavior of the previous one.
* `opam-name` (optional, defaults to concatenating with a dash separator the components of `namePrefix` and `pname`), name of the Dune package to build.
* `enableParallelBuilding` (optional, defaults to `true`), since it is activated by default, we provide a way to disable it.
* `extraInstallFlags` (optional), allows to extend `installFlags` which initializes the variable `COQMF_COQLIB` so as to install in the proper subdirectory. Indeed Coq libraries should be installed in `$(out)/lib/coq/${coq.coq-version}/user-contrib/`. Such directories are automatically added to the `$COQPATH` environment variable by the hook defined in the Coq derivation.
* `setCOQBIN` (optional, defaults to `true`), by default, the environment variable `$COQBIN` is set to the current Coq's binary, but one can disable this behavior by setting it to `false`,
* `extraInstallFlags` (optional), allows to extend `installFlags` which initializes the variables `COQLIBINSTALL` and `COQPLUGININSTALL` so as to install in the proper subdirectory. Indeed Rocq libraries should be installed in `$(out)/lib/coq/${rocq-core.rocq-version}/user-contrib/`. Such directories are automatically added to the `$ROCQPATH` environment variable by the hook defined in the Rocq derivation.
* `setROCQBIN` (optional, defaults to `true`), by default, the environment variable `$ROCQBIN` is set to the current Rocq's binary, but one can disable this behavior by setting it to `false`,
* `useMelquiondRemake` (optional, default to `null`) is an attribute set, which, if given, overloads the `preConfigurePhases`, `configureFlags`, `buildPhase`, and `installPhase` attributes of the derivation for a specific use in libraries using `remake` as set up by Guillaume Melquiond for `flocq`, `gappalib`, `interval`, and `coquelicot` (see the corresponding derivation for concrete examples of use of this option). For backward compatibility, the attribute `useMelquiondRemake.logpath` must be set to the logical root of the library (otherwise, one can pass `useMelquiondRemake = {}` to activate this without backward compatibility).
* `dropAttrs`, `keepAttrs`, `dropDerivationAttrs` are all optional and allow to tune which attribute is added or removed from the final call to `mkDerivation`.
It also takes other standard `mkDerivation` attributes, they are added as such, except for `meta` which extends an automatically computed `meta` (where the `platform` is the same as `coq` and the homepage is automatically computed).
It also takes other standard `mkDerivation` attributes, they are added as such, except for `meta` which extends an automatically computed `meta` (where the `platform` is the same as `rocq-core` and the homepage is automatically computed).
Here is a simple package example. It is a pure Coq library, thus it depends on Coq. It builds on the Mathematical Components library, thus it also takes some `mathcomp` derivations as `extraBuildInputs`.
Here is a simple package example. It is a pure Rocq library, thus it depends on Rocq. It builds on the Mathematical Components library, thus it also takes some `mathcomp` derivations as `extraBuildInputs`.
```nix
{
lib,
mkCoqDerivation,
mkRocqDerivation,
version ? null,
coq,
rocq-core,
mathcomp,
mathcomp-finmap,
mathcomp-bigenough,
}:
mkCoqDerivation {
# namePrefix leads to e.g. `name = coq8.11-mathcomp1.11-multinomials-1.5.2`
mkRocqDerivation {
# namePrefix leads to e.g. `name = rocq-core9.1-mathcomp2.5.0-multinomials-2.4.0`
namePrefix = [
"coq"
"rocq-core"
"mathcomp"
];
pname = "multinomials";
owner = "math-comp";
inherit version;
defaultVersion =
let
case = rocq: mc: out: {
cases = [
rocq-core
mc
];
inherit out;
};
in
with lib.versions;
lib.switch
[ coq.version mathcomp.version ]
[ rocq-core.rocq-version mathcomp.version ]
[
{
cases = [
(range "8.7" "8.12")
(isEq "1.11")
];
out = "1.5.2";
}
{
cases = [
(range "8.7" "8.11")
(range "1.8" "1.10")
];
out = "1.5.0";
}
{
cases = [
(range "8.7" "8.10")
(range "1.8" "1.10")
];
out = "1.4";
}
{
cases = [
(isEq "8.6")
(range "1.6" "1.7")
];
out = "1.1";
}
(case (range "8.18" "9.1") (range "2.1.0" "2.5.0") "2.4.0")
(case (range "8.17" "9.0") (range "2.1.0" "2.3.0") "2.3.0")
]
null;
release = {
"1.5.2".hash = "sha256-mjCx9XKa38Nz9E6wNK7YSqHdJ7YTua5fD3d6J4e7WpU=";
"1.5.1".hash = "sha256-Q8tm0y2FQAt2V1kZYkDlHWRia/lTvXAMVjdmzEV11I4=";
"1.5.0".hash = "sha256-HIK0f21G69oEW8JG46gSBde/Q2LR3GiBCv680gHbmRg=";
"1.5.0".rev = "1.5";
"1.4".hash = "sha256-F9g3MSIr3B6UZ3p8QWjz3/Jpw9sudJ+KRlvjiHSO024=";
"1.3".hash = "sha256-BPJTlAL0ETHvLMBslE0KFVt3DNoaGuMrHt2SBGyJe1A=";
"1.2".hash = "sha256-mHXBXSLYO4BN+jfN50y/+XCx0Qq5g4Ac2Y/qlsbgAdY=";
"1.1".hash = "sha256-ejAsMQbB/LtU9j+g160VdGXULrCe9s0gBWzyhKqmCuE=";
"1.0".hash = "sha256-tZTOltEBBKWciDxDMs/Ye4Jnq/33CANrHJ4FBMPtq+I=";
"2.4.0".sha256 = "sha256-7zfIddRH+Sl4nhEPtS/lMZwRUZI45AVFpcC/UC8Z0Yo=";
"2.3.0".sha256 = "sha256-usIcxHOAuN+f/j3WjVbPrjz8Hl9ac8R6kYeAKi3CEts=";
};
propagatedBuildInputs = [
mathcomp.ssreflect
mathcomp.boot
mathcomp.algebra
mathcomp-finmap
mathcomp.fingroup
mathcomp-bigenough
];
@@ -153,13 +139,13 @@ mkCoqDerivation {
}
```
## Three ways of overriding Coq packages {#coq-overriding-packages}
## Three ways of overriding Rocq packages {#rocq-overriding-packages}
There are three distinct ways of changing a Coq package by overriding one of its values: `.override`, `overrideCoqDerivation`, and `.overrideAttrs`. This section explains what sort of values can be overridden with each of these methods.
There are three distinct ways of changing a Rocq package by overriding one of its values: `.override`, `overrideRocqDerivation`, and `.overrideAttrs`. This section explains what sort of values can be overridden with each of these methods.
### `.override` {#coq-override}
### `.override` {#rocq-override}
`.override` lets you change arguments to a Coq derivation. In the case of the `multinomials` package above, `.override` would let you override arguments like `mkCoqDerivation`, `version`, `coq`, `mathcomp`, `mathcom-finmap`, etc.
`.override` lets you change arguments to a Rocq derivation. In the case of the `multinomials` package above, `.override` would let you override arguments like `mkRocqDerivation`, `version`, `rocq-core`, `mathcomp`, `mathcom-finmap`, etc.
For example, assuming you have a special `mathcomp` dependency you want to use, here is how you could override the `mathcomp` dependency:
@@ -167,35 +153,35 @@ For example, assuming you have a special `mathcomp` dependency you want to use,
multinomials.override { mathcomp = my-special-mathcomp; }
```
In Nixpkgs, all Coq derivations take a `version` argument. This can be overridden in order to easily use a different version:
In Nixpkgs, all Rocq derivations take a `version` argument. This can be overridden in order to easily use a different version:
```nix
coqPackages.multinomials.override { version = "1.5.1"; }
rocqPackages.multinomials.override { version = "1.5.1"; }
```
Refer to [](#coq-packages-attribute-sets-coqpackages) for all the different formats that you can potentially pass to `version`, as well as the restrictions.
Refer to [](#rocq-packages-attribute-sets-rocqpackages) for all the different formats that you can potentially pass to `version`, as well as the restrictions.
### `overrideCoqDerivation` {#coq-overrideCoqDerivation}
### `overrideRocqDerivation` {#rocq-overrideRocqDerivation}
The `overrideCoqDerivation` function lets you easily change arguments to `mkCoqDerivation`. These arguments are described in [](#coq-packages-attribute-sets-coqpackages).
The `overrideRocqDerivation` function lets you easily change arguments to `mkRocqDerivation`. These arguments are described in [](#rocq-packages-attribute-sets-rocqpackages).
For example, here is how you could locally add a new release of the `multinomials` library, and set the `defaultVersion` to use this release:
```nix
coqPackages.lib.overrideCoqDerivation {
rocqPackages.lib.overrideRocqDerivation {
defaultVersion = "2.0";
release."2.0".hash = "sha256-czoP11rtrIM7+OLdMisv2EF7n/IbGuwFxHiPtg3qCNM=";
} coqPackages.multinomials
} rocqPackages.multinomials
```
### `.overrideAttrs` {#coq-overrideAttrs}
### `.overrideAttrs` {#rocq-overrideAttrs}
`.overrideAttrs` lets you override arguments to the underlying `stdenv.mkDerivation` call. Internally, `mkCoqDerivation` uses `stdenv.mkDerivation` to create derivations for Coq libraries. You can override arguments to `stdenv.mkDerivation` with `.overrideAttrs`.
`.overrideAttrs` lets you override arguments to the underlying `stdenv.mkDerivation` call. Internally, `mkRocqDerivation` uses `stdenv.mkDerivation` to create derivations for Rocq libraries. You can override arguments to `stdenv.mkDerivation` with `.overrideAttrs`.
For instance, here is how you could add some code to be performed in the derivation after installation is complete:
```nix
coqPackages.multinomials.overrideAttrs (oldAttrs: {
rocqPackages.multinomials.overrideAttrs (oldAttrs: {
postInstall = oldAttrs.postInstall or "" + ''
echo "you can do anything you want here"
'';
+5 -3
View File
@@ -32,7 +32,7 @@ to your Nixpkgs configuration (`~/.config/nixpkgs/config.nix`) and install it by
$ nix-env -f '<nixpkgs>' -qaP -A eclipses.plugins --description
```
If there is a need to install plugins that are not available in Nixpkgs then it may be possible to define these plugins outside Nixpkgs using the `buildEclipseUpdateSite` and `buildEclipsePlugin` functions found in the `nixpkgs.eclipses.plugins` attribute set. Use the `buildEclipseUpdateSite` function to install a plugin distributed as an Eclipse update site. This function takes `{ name, src }` as argument, where `src` indicates the Eclipse update site archive. All Eclipse features and plugins within the downloaded update site will be installed. When an update site archive is not available, then the `buildEclipsePlugin` function can be used to install a plugin that consists of a pair of feature and plugin JARs. This function takes an argument `{ name, srcFeature, srcPlugin }` where `srcFeature` and `srcPlugin` are the feature and plugin JARs, respectively.
If there is a need to install plugins that are not available in Nixpkgs then it may be possible to define these plugins outside Nixpkgs using the `buildEclipseUpdateSite` and `buildEclipsePlugin` functions found in the `nixpkgs.eclipses.plugins` attribute set. Use the `buildEclipseUpdateSite` function to install a plugin distributed as an Eclipse update site. This function takes `{ src }` and either `pname` or `name` + `version` as arguments, where `src` indicates the Eclipse update site archive. All Eclipse features and plugins within the downloaded update site will be installed. When an update site archive is not available, then the `buildEclipsePlugin` function can be used to install a plugin that consists of a pair of feature and plugin JARs. This function takes `{ srcFeature, srcPlugin }` and either `pname` or `name` + `version` as arguments, where `srcFeature` and `srcPlugin` are the feature and plugin JARs, respectively.
Expanding the previous example with two plugins using the above functions, we have:
@@ -47,7 +47,8 @@ Expanding the previous example with two plugins using the above functions, we ha
plugins = [
plugins.color-theme
(plugins.buildEclipsePlugin {
name = "myplugin1-1.0";
pname = "myplugin1";
version = "1.0";
srcFeature = fetchurl {
url = "http://…/features/myplugin1.jar";
hash = "sha256-123…";
@@ -58,7 +59,8 @@ Expanding the previous example with two plugins using the above functions, we ha
};
})
(plugins.buildEclipseUpdateSite {
name = "myplugin2-1.0";
pname = "myplugin2";
version = "1.0";
src = fetchurl {
stripRoot = false;
url = "http://…/myplugin2.zip";
+14
View File
@@ -0,0 +1,14 @@
# Friction {#friction-graphics}
[Friction](https://friction.graphics/) is an open-source vector motion graphics application for creating animations for web and video platforms.
## Wayland support {#friction-graphics-wayland}
Upstream explicitly forces X11 (XCB) on Linux due to incomplete Wayland support (fullscreen does not work, some mouse interactions are broken).
This means the application runs under XWayland by default and does not respect compositor-level HiDPI scaling.
To enable native Wayland support, removing the forced X11 override:
```nix
friction-graphics.override { enableWayland = true; }
```
+1 -1
View File
@@ -10,6 +10,7 @@ eclipse.section.md
elm.section.md
emacs.section.md
firefox.section.md
friction-graphics.section.md
fish.section.md
fuse.section.md
geant4.section.md
@@ -32,7 +33,6 @@ cataclysm-dda.section.md
urxvt.section.md
vcpkg.section.md
weechat.section.md
xorg.section.md
uv.section.md
build-support.md
```
-34
View File
@@ -1,34 +0,0 @@
# X.org {#sec-xorg}
The Nix expressions for the X.org packages reside in `pkgs/servers/x11/xorg/default.nix`. This file is automatically generated from lists of tarballs in an X.org release. As such, it should not be modified directly; rather, you should modify the lists, the generator script, or the file `pkgs/servers/x11/xorg/overrides.nix`, in which you can override or add to the derivations produced by the generator.
## Katamari Tarballs {#katamari-tarballs}
X.org upstream releases used to include [katamari](https://en.wiktionary.org/wiki/%E3%81%8B%E3%81%9F%E3%81%BE%E3%82%8A) releases, which included a holistic recommended version for each tarball, up until 7.7. To create a list of tarballs in a katamari release:
```ShellSession
export release="X11R7.7"
export url="mirror://xorg/$release/src/everything/"
cat $(PRINT_PATH=1 nix-prefetch-url $url | tail -n 1) \
| perl -e 'while (<>) { if (/(href|HREF)="([^"]*.bz2)"/) { print "$ENV{'url'}$2\n"; }; }' \
| sort > "tarballs-$release.list"
```
## Individual Tarballs {#individual-tarballs}
The upstream release process for [X11R7.8](https://x.org/wiki/Releases/7.8/) does not include a planned katamari. Instead, each component of X.org is released as its own tarball. We maintain `pkgs/servers/x11/xorg/tarballs.list` as a list of tarballs for each individual package. This list includes X.org core libraries and protocol descriptions, extra newer X11 interface libraries, like `xorg.libxcb`, and classic utilities which are largely unused but still available if needed, like `xorg.imake`.
## Generating Nix Expressions {#generating-nix-expressions}
The generator is invoked as follows:
```ShellSession
cd pkgs/servers/x11/xorg
<tarballs.list perl ./generate-expr-from-tarballs.pl
```
For each of the tarballs in the `.list` files, the script downloads it, unpacks it, and searches its `configure.ac` and `*.pc.in` files for dependencies. This information is used to generate `default.nix`. The generator caches downloaded tarballs between runs. Pay close attention to the `NOT FOUND: $NAME` messages at the end of the run, since they may indicate missing dependencies. (Some might be optional dependencies, however.)
## Overriding the Generator {#overriding-the-generator}
If the expression for a package requires derivation attributes that the generator cannot figure out automatically (say, `patches` or a `postInstall` hook), you should modify `pkgs/servers/x11/xorg/overrides.nix`.
+3 -3
View File
@@ -28,7 +28,7 @@ Packages, including the Nix packages collection, are distributed through
[channels](https://nixos.org/nix/manual/#sec-channels). The collection is
distributed for users of Nix on non-NixOS distributions through the channel
`nixpkgs-unstable`. Users of NixOS generally use one of the `nixos-*` channels,
e.g. `nixos-22.11`, which includes all packages and modules for the stable NixOS
e.g., `nixos-22.11`, which includes all packages and modules for the stable NixOS
22.11. Stable NixOS releases are generally only given
security updates. More up-to-date packages and modules are available via the
`nixos-unstable` channel.
@@ -36,7 +36,7 @@ security updates. More up-to-date packages and modules are available via the
Both `nixos-unstable` and `nixpkgs-unstable` follow the `master` branch of the
Nixpkgs repository, although both do lag the `master` branch by generally
[a couple of days](https://status.nixos.org/). Updates to a channel are
distributed as soon as all tests for that channel pass, e.g.
distributed as soon as all tests for that channel pass, e.g.,
[this table](https://hydra.nixos.org/job/nixpkgs/trunk/unstable#tabs-constituents)
shows the status of tests for the `nixpkgs-unstable` channel.
@@ -47,4 +47,4 @@ The binaries are made available via a [binary cache](https://cache.nixos.org).
The current Nix expressions of the channels are available in the
[Nixpkgs repository](https://github.com/NixOS/nixpkgs) in branches
that correspond to the channel names (e.g. `nixos-22.11-small`).
that correspond to the channel names (e.g., `nixos-22.11-small`).
+68 -23
View File
@@ -119,6 +119,12 @@
"ex-testEqualArrayOrMap-test-function-add-cowbell": [
"index.html#ex-testEqualArrayOrMap-test-function-add-cowbell"
],
"friction-graphics": [
"index.html#friction-graphics"
],
"friction-graphics-wayland": [
"index.html#friction-graphics-wayland"
],
"ghc-deprecation-policy": [
"index.html#ghc-deprecation-policy"
],
@@ -311,7 +317,12 @@
"release-notes.html#sec-nixpkgs-release-26.05-highlights"
],
"sec-nixpkgs-release-26.05-incompatibilities": [
"release-notes.html#sec-nixpkgs-release-26.05-incompatibilities"
"release-notes.html#sec-nixpkgs-release-26.05-incompatibilities",
"index.html#sec-xorg",
"index.html#katamari-tarballs",
"index.html#individual-tarballs",
"index.html#generating-nix-expressions",
"index.html#overriding-the-generator"
],
"sec-nixpkgs-release-26.05-lib": [
"release-notes.html#sec-nixpkgs-release-26.05-lib"
@@ -2468,6 +2479,27 @@
"setup-hook-gdk-pixbuf": [
"index.html#setup-hook-gdk-pixbuf"
],
"libglycin-hooks": [
"index.html#libglycin-hooks"
],
"libglycin-setup-hook": [
"index.html#libglycin-setup-hook"
],
"libglycin-patch-vendor-hook": [
"index.html#libglycin-patch-vendor-hook"
],
"libglycin-hooks-example-code-snippet": [
"index.html#libglycin-hooks-example-code-snippet"
],
"libglycin-hook-variables-controlling": [
"index.html#libglycin-hook-variables-controlling"
],
"glycin-cargo-deps-path": [
"index.html#glycin-cargo-deps-path"
],
"glycin-dont-wrap": [
"index.html#glycin-dont-wrap"
],
"ghc": [
"index.html#ghc"
],
@@ -2666,6 +2698,9 @@
"dont-tauri-build": [
"index.html#dont-tauri-build"
],
"dont-tauri-fixup": [
"index.html#dont-tauri-fixup"
],
"dont-tauri-install": [
"index.html#dont-tauri-install"
],
@@ -2733,6 +2768,9 @@
"index.html#zig-exclusive-variables",
"index.html#zig-hook-exclusive-variables"
],
"dont-use-zig-configure": [
"index.html#dont-use-zig-configure"
],
"dont-use-zig-build": [
"index.html#dont-use-zig-build"
],
@@ -2933,25 +2971,32 @@
"sec-chicken-override-scope": [
"index.html#sec-chicken-override-scope"
],
"sec-language-coq": [
"sec-language-rocq": [
"index.html#sec-language-rocq",
"index.html#sec-language-coq"
],
"coq-derivation-coq": [
"rocq-derivation-rocq": [
"index.html#rocq-derivation-rocq",
"index.html#coq-derivation-coq"
],
"coq-packages-attribute-sets-coqpackages": [
"rocq-packages-attribute-sets-rocqpackages": [
"index.html#rocq-packages-attribute-sets-rocqpackages",
"index.html#coq-packages-attribute-sets-coqpackages"
],
"coq-overriding-packages": [
"rocq-overriding-packages": [
"index.html#rocq-overriding-packages",
"index.html#coq-overriding-packages"
],
"coq-override": [
"rocq-override": [
"index.html#rocq-override",
"index.html#coq-override"
],
"coq-overrideCoqDerivation": [
"rocq-overrideRocqDerivation": [
"index.html#rocq-overrideRocqDerivation",
"index.html#coq-overrideCoqDerivation"
],
"coq-overrideAttrs": [
"rocq-overrideAttrs": [
"index.html#rocq-overrideAttrs",
"index.html#coq-overrideAttrs"
],
"crystal": [
@@ -3158,6 +3203,9 @@
"ssec-gnome-hooks-gst-grl-plugins": [
"index.html#ssec-gnome-hooks-gst-grl-plugins"
],
"ssec-gnome-hooks-libglycin": [
"index.html#ssec-gnome-hooks-libglycin"
],
"ssec-gnome-updating": [
"index.html#ssec-gnome-updating"
],
@@ -4254,6 +4302,18 @@
"index.html#neovim-plugin-treesitter",
"index.html#vim-plugin-treesitter"
],
"neovim-plugin-nvim-treesitter": [
"index.html#neovim-plugin-nvim-treesitter",
"index.html#vim-plugin-nvim-treesitter"
],
"neovim-plugin-treesitter-standalone": [
"index.html#neovim-plugin-treesitter-standalone",
"index.html#vim-plugin-treesitter-standalone"
],
"neovim-plugin-treesitter-grammar-dependencies": [
"index.html#neovim-plugin-treesitter-grammar-dependencies",
"index.html#vim-plugin-treesitter-grammar-dependencies"
],
"managing-plugins-with-vim-plug": [
"index.html#managing-plugins-with-vim-plug"
],
@@ -4495,21 +4555,6 @@
"sec-weechat": [
"index.html#sec-weechat"
],
"sec-xorg": [
"index.html#sec-xorg"
],
"katamari-tarballs": [
"index.html#katamari-tarballs"
],
"individual-tarballs": [
"index.html#individual-tarballs"
],
"generating-nix-expressions": [
"index.html#generating-nix-expressions"
],
"overriding-the-generator": [
"index.html#overriding-the-generator"
],
"sec-build-support": [
"index.html#sec-build-support"
],
+38
View File
@@ -55,12 +55,24 @@
adding `pkg-config`, `xfce4-dev-tools`, and `wrapGAppsHook3` to your `nativeBuildInputs` and
`--enable-maintainer-mode` to your `configureFlags`.
- `albert` has been updated to the version 34.0.5. This release redesigns the query system to support stateful asynchronous handlers and infinite scrolling, and adds internationalized tokenization.
This update introduces several breaking changes: the Python plugin interface is now v5.0, the `PATH` plugin has been renamed to `Commandline`, and the QStylesheets-based widgets box model frontend has been removed.
For more information read the [changelog for 34.0.0](https://albertlauncher.github.io/2026/01/19/albert-v34.0.0-released/).
- `cargo-codspeed` has been updated from `3.0.5` to `4.2.0`. Version `4.0.0` includes breaking changes. For more information read the [changelog for 4.0.0](https://github.com/CodSpeedHQ/codspeed-rust/releases/tag/v4.0.0).
- `corepack_latest` has been removed, as Corepack is no longer distributed with Node.js.
- `nodePackages.browser-sync` has been removed, as it was unmaintained within nixpkgs.
- `spoof` has been removed, as there are many issues upstream with it working on modern OS versions, and it appears to be unmaintained.
- `nodePackages.coc-go` and `nodePackages.coc-tsserver`, along with their vim plugins, have been removed from nixpkgs due to being unmaintained.
- `nodePackages.wavedrom-cli` has been removed, as it was unmaintained within nixpkgs.
- `arti` has been updated to major version 2, which removed the long-deprecated `proxy.socks_port` and `proxy.dns_port` and the legacy syntax for specifying directory authorities. For more information, see the [changelog for 2.0.0](https://gitlab.torproject.org/tpo/core/arti/-/blob/arti-v2.0.0/CHANGELOG.md).
- `kanata` now requires `karabiner-dk` version 6.0+ or later.
The package has been updated to use the new `karabiner-dk` package and the `darwinDriver` output stays at the version defined in the package.
@@ -70,14 +82,28 @@
- `forgejo` has been updated to major version 14. For more information, see the [release blog post](https://forgejo.org/2026-01-release-v14-0/) and [full release notes](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/release-notes-published/14.0.0.md)
- `bartender` has been updated to major version 6. This removes support for MacOS Sonoma (and adds support for Tahoe). For more information, see [the release notes](https://www.macbartender.com/Bartender6/release_notes/) or [the Bartender 6 support page](https://www.macbartender.com/Bartender6/support/).
- `lima` has been updated from `1.x` to `2.x`. This major update includes several breaking changes, such as `/tmp/lima` no longer being mounted by default.
- `minio_legacy_fs` has been removed. If you used that package, migrate your data to be compatible with the newest minio and use the package `minio`.
- `mercure` has been update to `0.21.4` (or later). Version [0.21.0](https://github.com/dunglas/mercure/releases/v0.21.0) and [0.21.2](https://github.com/dunglas/mercure/releases/tag/v0.21.2) introduce breaking changes to the package.
- `n8n` has been updated to version 2. You can find the breaking changes here: https://docs.n8n.io/2-0-breaking-changes/.
- `gurk-rs` has been updated from `0.6.4` to `0.8.0`. Version `0.8.0` includes breaking changes. For more information read the [release notes for 0.8.0](https://github.com/boxdot/gurk-rs/releases/tag/v0.8.0).
- `iroh` has been removed and split up into `iroh-dns-server` and `iroh-relay`.
- the `xorg` package set has been deprecated, packages have moved to the top level.
- `python3Packages.pygame` has been been renamed to `python3Packages.pygame-original`, the attribute `python3Packages.pygame` will from python 3.14 default to the more actively maintained `python3Packages.pygame-ce`
- `peertube` has been updated from `7.3.0` to `8.0.2`, introducing several breaking changes.
Some notable new features include channel collaboration and video player redesign with a new theme.
For details on how to upgrade, see the `IMPORTANT NOTES` section of the [v8.0.0 CHANGELOG entry](https://docs.joinpeertube.org/CHANGELOG#v8-0-0).
- `python3Packages.gradio` has been updated to version 6. See upstream's migration guide at https://www.gradio.app/main/guides/gradio-6-migration-guide.
- `vicinae` has been updated to v0.17. Version 0.17 contains a complete overhaul of the configuration system. For update instructions, see the [release notes for v0.17.0](https://github.com/vicinaehq/vicinae/releases/tag/v0.17.0) and the [upstream configuration documentation](https://docs.vicinae.com/config).
@@ -89,6 +115,8 @@
- `jetbrains.plugins.addPlugins` no longer supports plugin names or ID strings.
You can still use `addPlugins` with plugin derivations, such as plugins packaged outside of Nixpkgs.
- The `programs.captive-browser` module no longer falls back on a setcap wrapper around udhcpc to discover your network's DNS server due to [GHSA-wc3r-c66x-8xmc](https://github.com/NixOS/nixpkgs/security/advisories/GHSA-wc3r-c66x-8xmc) (CVE-2026-25740). If you're using this module, you must either configure `programs.captive-browser.dhcp-dns` manually or enable one of NetworkManager, dhcpcd, or systemd-networkd.
- The `services.yggdrasil` module has been refactored with the following breaking changes:
- The `services.yggdrasil.configFile` option has been removed. Configuration should now be specified directly via `services.yggdrasil.settings`.
- The `services.yggdrasil.persistentKeys` option has been removed. To maintain persistent keys and IPv6 addresses across reboots, use `services.yggdrasil.settings.PrivateKeyPath` to securely load your private key from a file via systemd credentials. The private key must be in PEM format (PKCS #8).
@@ -103,6 +131,8 @@
retained for packages that have not completed migration. `asio_1_10` has been removed as no packages depend on it anymore.
`asio` also no longer propagates `boost` as it is used independent from `boost` in most cases.
- `stalwart-mail` has been renamed to `stalwart`
- Ethercalc and its associated module have been removed, as the package is unmaintained and cannot be installed from source with npm now.
- `coreth` has been removed, as upstream has moved it into `avalanchego`.
@@ -134,12 +164,18 @@
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
- `balatro` now supports the Google Play and Xbox PC versions of the game. Pass the `apk` or `Assets.zip` as `balatro.override { src = "…" }`.
- `uptime-kuma` has been updated to v2, which requires an automated migration that can take a few hours. **A backup is highly recommended.**
If your SQLite database is corrupted, the migration might fail and require [manual intervention](https://github.com/louislam/uptime-kuma/issues/5281).
See the [migration guide](https://github.com/louislam/uptime-kuma/wiki/Migration-From-v1-To-v2) for more information.
- Switch inhibitors were introduced, which add a pre-switch check that compares a list of strings between the previous and the new generation, and refuses to switch into the new generation when there is a difference between the two lists. This allows to avoid switching into a system when for instance the systemd version changed by adding `config.systemd.package.version` to the switch inhibitors for your system. You can still forcefully switch into any generation by setting `NIXOS_NO_CHECK=1`.
- GNU Taler has been updated to version 1.3.
This release focuses on getting everything ready for a deployment of GNU Taler by Magnet bank.
For more details, see the [upstream release notes](https://www.taler.net/en/news/2025-13.html).
- The `services.nextcloud-spreed-signaling` NixOS module has been added to facilitate declarative management of a standalone Spreed signaling server ("High Performance Backend" for Nextcloud Talk).
- `fetchPnpmDeps` and `pnpmConfigHook` were added as top-level attributes, replacing the now deprecated `pnpm.fetchDeps` and `pnpm.configHook` attributes.
@@ -149,6 +185,8 @@
- `openrgb` was updated to 1.0rc2, which now uses Plugin API version 4.
Some existing OpenRGB plugins may be incompatible or require updates.
- the `neovim` wrapper sets provider-related configuration in its generated config rather than as wrapper arguments. It should not affect configuration unless you set `wrapRc` to false.
- We now use the upstream wrapper script for Gradle, supporting both the `JAVA_HOME` and `GRADLE_OPTS` environment variables.
## Nixpkgs Library {#sec-nixpkgs-release-26.05-lib}
+1 -1
View File
@@ -513,7 +513,7 @@ Unless set to `false`, some build systems with good support for parallel buildin
### Fixed-point arguments of `mkDerivation` {#mkderivation-recursive-attributes}
If you pass a function to `mkDerivation`, it will receive as its argument the final arguments, including the overrides when reinvoked via `overrideAttrs`. For example:
If you pass a function to `mkDerivation`, it will call the function with an argument that represents the final state of the package: the return value of the function itself, with any overrides applied, as the function is reinvoked by any `overrideAttrs` calls. For example:
```nix
mkDerivation (finalAttrs: {
+12
View File
@@ -116,6 +116,10 @@
&& !self.legacyPackages.${system}.stdenv.targetPlatform.isPower64
# Exclude armv6l-linux because "cannot bootstrap GHC on this platform ('armv6l-linux' with libc 'defaultLibc')"
&& system != "armv6l-linux"
# Exclude armv7l-linux because "cannot bootstrap GHC on this platform ('armv7l-linux' with libc 'defaultLibc')"
&& system != "armv7l-linux"
# Exclude powerpc64le-linux because "cannot bootstrap GHC on this platform ('powerpc64le-linux' with libc 'defaultLibc')"
&& system != "powerpc64le-linux"
# Exclude riscv64-linux because "cannot bootstrap GHC on this platform ('riscv64-linux' with libc 'defaultLibc')"
&& system != "riscv64-linux"
)
@@ -165,6 +169,10 @@
(
# Exclude armv6l-linux because "Package ghc-9.6.6 in .../pkgs/development/compilers/ghc/common-hadrian.nix:579 is not available on the requested hostPlatform"
system != "armv6l-linux"
# Exclude armv7l-linux because "cannot bootstrap GHC on this platform ('armv7l-linux' with libc 'defaultLibc')"
&& system != "armv7l-linux"
# Exclude powerpc64le-linux because "cannot bootstrap GHC on this platform ('powerpc64le-linux' with libc 'defaultLibc')"
&& system != "powerpc64le-linux"
# Exclude riscv64-linux because "Package ghc-9.6.6 in .../pkgs/development/compilers/ghc/common-hadrian.nix:579 is not available on the requested hostPlatform"
&& system != "riscv64-linux"
# Exclude x86_64-freebsd because "Package ghc-9.6.6 in .../pkgs/development/compilers/ghc/common-hadrian.nix:579 is not available on the requested hostPlatform"
@@ -182,6 +190,10 @@
system: _:
# Exclude armv6l-linux because "cannot bootstrap GHC on this platform ('armv6l-linux' with libc 'defaultLibc')"
system != "armv6l-linux"
# Exclude armv7l-linux because "cannot bootstrap GHC on this platform ('armv7l-linux' with libc 'defaultLibc')"
&& system != "armv7l-linux"
# Exclude powerpc64le-linux because "cannot bootstrap GHC on this platform ('powerpc64le-linux' with libc 'defaultLibc')"
&& system != "powerpc64le-linux"
# Exclude riscv64-linux because "cannot bootstrap GHC on this platform ('riscv64-linux' with libc 'defaultLibc')"
&& system != "riscv64-linux"
# Exclude x86_64-freebsd because "Package go-1.22.12-freebsd-amd64-bootstrap in /nix/store/0yw40qnrar3lvc5hax5n49abl57apjbn-source/pkgs/development/compilers/go/binary.nix:50 is not available on the requested hostPlatform"
+44 -2
View File
@@ -105,6 +105,24 @@ let
# network
network = callLibs ./network;
# flakes
flakes = callLibs ./flakes.nix;
inherit (builtins)
getContext
hasContext
convertHash
hashString
parseDrvName
placeholder
fromJSON
fromTOML
toFile
toJSON
toString
toXML
tryEval
;
inherit (self.trivial)
id
const
@@ -112,6 +130,8 @@ let
concat
"or"
and
mul
div
xor
bitAnd
bitOr
@@ -163,6 +183,8 @@ let
pathExists
genericClosure
readFile
ceil
floor
;
inherit (self.fixedPoints)
fix
@@ -295,6 +317,7 @@ let
elemAt
isList
concatAttrValues
replaceElemAt
;
inherit (self.strings)
concatStrings
@@ -326,7 +349,6 @@ let
escape
escapeShellArg
escapeShellArgs
isPath
isStorePath
isStringLike
isValidPosixName
@@ -371,6 +393,8 @@ let
toInt
toIntBase10
fileContents
appendContext
unsafeDiscardStringContext
;
inherit (self.stringsWithDeps)
textClosureList
@@ -395,7 +419,13 @@ let
renameCrossIndexTo
mapCrossIndex
;
inherit (self.derivations) lazyDerivation optionalDrvAttr warnOnInstantiate;
inherit (self.derivations)
lazyDerivation
optionalDrvAttr
warnOnInstantiate
addDrvOutputDependencies
unsafeDiscardOutputDependency
;
inherit (self.generators) mkLuaInline;
inherit (self.meta)
addMetaAttrs
@@ -419,7 +449,13 @@ let
pathType
pathIsDirectory
pathIsRegularFile
baseNameOf
dirOf
isPath
packagesFromDirectoryRecursive
hashFile
readDir
readFileType
;
inherit (self.sources)
cleanSourceFilter
@@ -433,6 +469,7 @@ let
pathIsGitRepo
revOrTag
repoRevToName
filterSource
;
inherit (self.modules)
evalModules
@@ -563,11 +600,16 @@ let
imap
;
inherit (self.versions)
compareVersions
splitVersion
;
inherit (self.network.ipv6)
mkEUI64Suffix
;
inherit (self.flakes)
parseFlakeRef
flakeRefToString
;
}
);
in
+5
View File
@@ -21,6 +21,11 @@ let
if pkg ? meta.position && isString pkg.meta.position then "${prefix}${pkg.meta.position}" else "";
in
{
inherit (builtins)
addDrvOutputDependencies
unsafeDiscardOutputDependency
;
/**
Restrict a derivation to a predictable set of attribute names, so
that the returned attrset is not strict in the actual derivation,
+3 -3
View File
@@ -16,7 +16,7 @@ It should have the following properties:
Non-goals are:
- Efficient:
If the abstraction proves itself worthwhile but too slow, it can be still be optimized further.
If the abstraction proves itself worthwhile but too slow, it can still be optimized further.
## Tests
@@ -90,7 +90,7 @@ One of the following:
- `"regular"`, `"symlink"`, `"unknown"` or any other non-`"directory"` string:
A nested file with its file type.
These specific strings are chosen to be compatible with `builtins.readDir` for a simpler implementation.
Distinguishing between different file types is not strictly necessary for the functionality this library,
Distinguishing between different file types is not strictly necessary for the functionality of this library,
but it does allow nicer printing of file sets.
- `null`:
@@ -127,7 +127,7 @@ Arguments:
### Empty file set without a base
There is a special representation for an empty file set without a base path.
This is used for return values that should be empty but when there's no base path that would makes sense.
This is used for return values that should be empty but when there's no base path that would make sense.
Arguments:
- Alternative: This could also be represented using `_internalBase = /.` and `_internalTree = null`.
+10 -10
View File
@@ -191,7 +191,7 @@ in
if isStringLike path then
throw ''lib.fileset.maybeMissing: Argument ("${toString path}") is a string-like value, but it should be a path instead.''
else
throw ''lib.fileset.maybeMissing: Argument is of type ${typeOf path}, but it should be a path instead.''
throw "lib.fileset.maybeMissing: Argument is of type ${typeOf path}, but it should be a path instead."
else if !pathExists path then
_emptyWithoutBase
else
@@ -443,7 +443,7 @@ in
lib.fileset.toSource: `root` (${toString root}) is a string-like value, but it should be a path instead.
Paths in strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.''
else
throw ''lib.fileset.toSource: `root` is of type ${typeOf root}, but it should be a path instead.''
throw "lib.fileset.toSource: `root` is of type ${typeOf root}, but it should be a path instead."
# Currently all Nix paths have the same filesystem root, but this could change in the future.
# See also ../path/README.md
else if !fileset._internalIsEmptyWithoutBase && rootFilesystemRoot != filesetFilesystemRoot then
@@ -453,7 +453,7 @@ in
`fileset`: Filesystem root is "${toString filesetFilesystemRoot}"
Different filesystem roots are not supported.''
else if !pathExists root then
throw ''lib.fileset.toSource: `root` (${toString root}) is a path that does not exist.''
throw "lib.fileset.toSource: `root` (${toString root}) is a path that does not exist."
else if pathType root != "directory" then
throw ''
lib.fileset.toSource: `root` (${toString root}) is a file, but it should be a directory instead. Potential solutions:
@@ -619,7 +619,7 @@ in
unions =
filesets:
if !isList filesets then
throw ''lib.fileset.unions: Argument is of type ${typeOf filesets}, but it should be a list instead.''
throw "lib.fileset.unions: Argument is of type ${typeOf filesets}, but it should be a list instead."
else
pipe filesets [
# Annotate the elements with context, used by _coerceMany for better errors
@@ -808,16 +808,16 @@ in
fileFilter =
predicate: path:
if !isFunction predicate then
throw ''lib.fileset.fileFilter: First argument is of type ${typeOf predicate}, but it should be a function instead.''
throw "lib.fileset.fileFilter: First argument is of type ${typeOf predicate}, but it should be a function instead."
else if !isPath path then
if path._type or "" == "fileset" then
throw ''
lib.fileset.fileFilter: Second argument is a file set, but it should be a path instead.
If you need to filter files in a file set, use `intersection fileset (fileFilter pred ./.)` instead.''
else
throw ''lib.fileset.fileFilter: Second argument is of type ${typeOf path}, but it should be a path instead.''
throw "lib.fileset.fileFilter: Second argument is of type ${typeOf path}, but it should be a path instead."
else if !pathExists path then
throw ''lib.fileset.fileFilter: Second argument (${toString path}) is a path that does not exist.''
throw "lib.fileset.fileFilter: Second argument (${toString path}) is a path that does not exist."
else
_fileFilter predicate path;
@@ -862,7 +862,7 @@ in
# but removing a subdirectory using file set functions
difference
(fromSource (lib.sources.sourceByRegex ./. [
"^README\.md$"
"^README\\.md$"
# This regex includes everything in ./doc
"^doc(/.*)?$"
])
@@ -896,9 +896,9 @@ in
lib.fileset.fromSource: The source origin of the argument is a string-like value ("${toString path}"), but it should be a path instead.
Sources created from paths in strings cannot be turned into file sets, use `lib.sources` or derivations instead.''
else
throw ''lib.fileset.fromSource: The source origin of the argument is of type ${typeOf path}, but it should be a path instead.''
throw "lib.fileset.fromSource: The source origin of the argument is of type ${typeOf path}, but it should be a path instead."
else if !pathExists path then
throw ''lib.fileset.fromSource: The source origin (${toString path}) of the argument is a path that does not exist.''
throw "lib.fileset.fromSource: The source origin (${toString path}) of the argument is a path that does not exist."
else if isFiltered then
_fromSourceFilter path source.filter
else
+1 -1
View File
@@ -211,7 +211,7 @@ rec {
${context} ("${toString value}") is a string-like value, but it should be a file set or a path instead.
Paths represented as strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.''
else
error ''${context} is of type ${typeOf value}, but it should be a file set or a path instead.''
error "${context} is of type ${typeOf value}, but it should be a file set or a path instead."
else if !pathExists value then
error ''
${context} (${toString value}) is a path that does not exist.
+11
View File
@@ -25,6 +25,17 @@ let
in
{
inherit (builtins)
baseNameOf
dirOf
isPath
;
inherit (builtins)
readDir
readFileType
hashFile
;
/**
The type of a path. The path needs to exist and be accessible.
+12
View File
@@ -0,0 +1,12 @@
/**
Flake operations.
*/
{ lib }:
{
inherit (builtins)
parseFlakeRef
flakeRefToString
;
}
+12
View File
@@ -742,6 +742,18 @@ lib.mapAttrs mkLicense (
fullName = "Historical Permission Notice and Disclaimer - sell xserver variant with MIT disclaimer";
};
hpndSellVariantSafetyClause = {
fullName = "HPND - sell variant with safety critical systems clause";
url = "https://gitlab.freedesktop.org/xorg/driver/xf86-video-voodoo/-/blob/68a5b6d98ae34749cca889f4373b4043d00bfe6a/src/voodoo_dga.c#L12-33";
# TODO: if the license gets accepted to spdx then
# add spdxId
# else
# remove license
# && replace reference with whatever this license is supposed to be then
# https://github.com/spdx/license-list-XML/issues/2922
# spdxId = "HPND-sell-variant-safety-clause";
};
hpndDec = {
fullName = "Historical Permission Notice and Disclaimer - DEC variant";
spdxId = "HPND-DEC";
+37
View File
@@ -2019,4 +2019,41 @@ rec {
:::
*/
concatAttrValues = set: concatLists (attrValues set);
/**
Replaces a list's nth element with a new element
# Inputs
`list`
: Input list
`idx`
: index to replace
`newElem`
: new element to replace with
# Type
```
replaceElemAt :: [a] -> int - b -> [a]
```
# Examples
:::{.example}
## `replaceElemAt` usage example
```nix
lib.replaceElemAt` [1 2 3] 0 "a"
=> ["a" 2 3]
```
:::
*/
replaceElemAt =
list: idx: newElem:
assert lib.assertMsg (idx >= 0 && idx < length list)
"'lists.replaceElemAt' called with index ${toString idx} on a list of size ${toString (length list)}";
genList (i: if i == idx then newElem else elemAt list i) (length list);
}
+43 -1
View File
@@ -12,6 +12,7 @@ let
concatMap
concatStringsSep
elem
elemAt
filter
foldl'
functionArgs
@@ -20,12 +21,14 @@ let
head
id
imap1
init
isAttrs
isBool
isFunction
oldestSupportedReleaseIsAtLeast
isList
isString
last
length
mapAttrs
mapAttrsToList
@@ -34,12 +37,16 @@ let
optional
optionalAttrs
optionalString
pipe
recursiveUpdate
remove
reverseList
sort
sortOn
seq
setAttrByPath
substring
take
throwIfNot
trace
typeOf
@@ -60,6 +67,8 @@ let
;
inherit (lib.strings)
isConvertibleWithToString
levenshtein
levenshteinAtMost
;
showDeclPrefix =
@@ -304,8 +313,41 @@ let
addErrorContext
"while evaluating the error message for definitions for `${optText}', which is an option that does not exist"
(addErrorContext "while evaluating a definition from `${firstDef.file}'" (showDefs [ firstDef ]));
# absInvalidOptionParent is absolute; other variables are relative to the submodule prefix
absInvalidOptionParent = init (prefix ++ firstDef.prefix);
invalidOptionParent = init firstDef.prefix;
siblingOptionNames = attrNames (attrByPath invalidOptionParent { } options);
candidateNames =
if invalidOptionParent == [ ] then remove "_module" siblingOptionNames else siblingOptionNames;
invalidOptionName = last firstDef.prefix;
# For small option sets, check all; for large sets, only check distance ≤ 2
suggestions =
if length candidateNames < 100 then
pipe candidateNames [
(sortOn (levenshtein invalidOptionName))
(take 3)
]
else
pipe candidateNames [
# levenshteinAtMost is only fast for distance ≤ 2
(filter (levenshteinAtMost 2 invalidOptionName))
(sortOn (levenshtein invalidOptionName))
(take 3)
];
suggestion =
if suggestions == [ ] then
""
else if length suggestions == 1 then
"\n\nDid you mean `${showOption (absInvalidOptionParent ++ [ (head suggestions) ])}'?"
else
"\n\nDid you mean ${
concatStringsSep ", " (
map (s: "`${showOption (absInvalidOptionParent ++ [ s ])}'") (init suggestions)
)
} or `${showOption (absInvalidOptionParent ++ [ (last suggestions) ])}'?";
in
"The option `${optText}' does not exist. Definition values:${defText}";
"The option `${optText}' does not exist. Definition values:${defText}${suggestion}";
in
if
attrNames options == [ "_module" ]
+63 -1
View File
@@ -672,11 +672,30 @@ rec {
is necessary for complex values, e.g. functions, or values that depend on
other values or packages.
# Examples
:::{.example}
## `literalExpression` usage example
```nix
llvmPackages = mkOption {
type = types.str;
description = ''
Version of llvm packages to use for
this module
'';
example = literalExpression ''
llvmPackages = pkgs.llvmPackages_20;
'';
};
```
:::
# Inputs
`text`
: 1\. Function argument
: The text to render as a Nix expression
*/
literalExpression =
text:
@@ -688,6 +707,49 @@ rec {
inherit text;
};
/**
For use in the `defaultText` and `example` option attributes. Causes the
given string to be rendered verbatim in the documentation as a code
block with the language bassed on the provided input tag.
If you wish to render Nix code, please see `literalExpression`.
# Examples
:::{.example}
## `literalCode` usage example
```nix
myPythonScript = mkOption {
type = types.str;
description = ''
Example python script used by a module
'';
example = literalCode "python" ''
print("Hello world!")
'';
};
```
:::
# Inputs
`languageTag`
: The language tag to use when producing the code block (i.e. `js`, `rs`, etc).
`text`
: The text to render as a Nix expression
*/
literalCode =
languageTag: text:
lib.literalMD ''
```${languageTag}
${text}
```
'';
/**
For use in the `defaultText` and `example` option attributes. Causes the
given MD text to be inserted verbatim in the documentation, for when
+1 -1
View File
@@ -239,7 +239,7 @@ in
# The subpath string to append
subpath:
assert assertMsg (isPath path)
''lib.path.append: The first argument is of type ${builtins.typeOf path}, but a path was expected'';
"lib.path.append: The first argument is of type ${builtins.typeOf path}, but a path was expected";
assert assertMsg (isValid subpath) ''
lib.path.append: Second argument is not a valid subpath string:
${subpathInvalidReason subpath}'';
+3 -1
View File
@@ -200,7 +200,7 @@ let
## `sourceByRegex` usage example
```nix
src = sourceByRegex ./my-subproject [".*\.py$" "^database.sql$"]
src = sourceByRegex ./my-subproject [".*\\.py$" "^database\\.sql$"]
```
:::
@@ -529,4 +529,6 @@ in
trace
;
inherit (builtins) filterSource;
}
+1
View File
@@ -39,6 +39,7 @@ rec {
toJSON
typeOf
unsafeDiscardStringContext
appendContext
;
/**
+3 -1
View File
@@ -384,11 +384,13 @@ let
if pkgs.stdenv.hostPlatform.canExecute final then
lib.getExe (pkgs.writeShellScriptBin "exec" ''exec "$@"'')
else if final.isWindows then
"${wine}/bin/wine${optionalString (final.parsed.cpu.bits == 64) "64"}"
"${wine}/bin/wine"
else if final.isLinux && pkgs.stdenv.hostPlatform.isLinux && final.qemuArch != null then
"${pkgs.qemu-user}/bin/qemu-${final.qemuArch}"
else if final.isWasi then
"${pkgs.wasmtime}/bin/wasmtime"
else if final.isGhcjs then
"${pkgs.nodejs-slim}/bin/node"
else if final.isMmix then
"${pkgs.mmixware}/bin/mmix"
else
+15 -14
View File
@@ -22,6 +22,10 @@ rec {
linux-kernel.autoModules = false;
};
##
## POWER
##
powernv = {
linux-kernel = {
name = "PowerNV";
@@ -29,16 +33,16 @@ rec {
baseConfig = "powernv_defconfig";
target = "vmlinux";
autoModules = true;
# avoid driver/FS trouble arising from unusual page size
extraConfig = ''
PPC_64K_PAGES n
PPC_4K_PAGES y
IPV6 y
};
};
ATA_BMDMA y
ATA_SFF y
VIRTIO_MENU y
'';
ppc64 = {
linux-kernel = {
name = "powerpc64";
baseConfig = "ppc64_defconfig";
target = "vmlinux";
autoModules = true;
};
};
@@ -85,7 +89,6 @@ rec {
BLK_DEV_DM m
DM_CRYPT m
MD y
REISERFS_FS m
BTRFS_FS m
XFS_FS m
JFS_FS m
@@ -430,7 +433,6 @@ rec {
BLK_DEV_DM m
DM_CRYPT m
MD y
REISERFS_FS m
EXT4_FS m
USB_STORAGE_CYPRESS_ATACB m
@@ -475,7 +477,6 @@ rec {
FRAMEBUFFER_CONSOLE y
EXT2_FS y
EXT3_FS y
REISERFS_FS y
MAGIC_SYSRQ y
# The kernel doesn't boot at all, with FTRACE
@@ -628,8 +629,8 @@ rec {
else if platform.parsed.cpu == lib.systems.parse.cpuTypes.mipsel then
(import ./examples.nix { inherit lib; }).mipsel-linux-gnu
else if platform.parsed.cpu == lib.systems.parse.cpuTypes.powerpc64le then
powernv
else if platform.isPower64 then
if platform.isLittleEndian then powernv else ppc64
else if platform.isLoongArch64 then
loongarch64-multiplatform
+1 -1
View File
@@ -331,7 +331,7 @@ in
testAttrs = {
expectedError = {
type = "ThrownError";
msg = ''A definition for option `foo' is not of type `string or signed integer convertible to it.*'';
msg = "A definition for option `foo' is not of type `string or signed integer convertible to it.*";
};
};
};
+27 -1
View File
@@ -54,6 +54,32 @@ let
missingGithubIds = lib.concatLists (lib.mapAttrsToList checkMaintainer lib.maintainers);
uniqueFields = [
"github"
"githubId"
"email"
"matrix"
];
nonUniqueFields = lib.filterAttrs (field: nonUnique: nonUnique != { }) (
lib.genAttrs uniqueFields (
field:
lib.pipe lib.maintainers [
(lib.mapAttrsToList (handle: m: m // { inherit handle; }))
(lib.groupBy (m: toString (m.${field} or null)))
(lib.filterAttrs (v: ms: v != "" && lib.length ms > 1))
(lib.mapAttrs (v: ms: map (m: m.handle) ms))
]
)
);
uniquenessError =
value:
if nonUniqueFields == { } then
value
else
throw "lib.maintainers has non-unique fields: ${lib.generators.toPretty { } nonUniqueFields}";
success = pkgs.runCommand "checked-maintainers-success" { } "mkdir $out";
failure =
@@ -73,4 +99,4 @@ let
exit 1
'';
in
if missingGithubIds == [ ] then success else failure
uniquenessError (if missingGithubIds == [ ] then success else failure)
+18 -5
View File
@@ -867,7 +867,7 @@ runTests {
testEscapeNixIdentifierNoQuote = {
expr = strings.escapeNixIdentifier "foo";
expected = ''foo'';
expected = "foo";
};
testEscapeNixIdentifierNumber = {
@@ -2634,7 +2634,7 @@ runTests {
sections = {
};
};
expected = '''';
expected = "";
};
testToINIWithGlobalSectionGlobalEmptyIsTheSameAsToINI =
@@ -3002,12 +3002,12 @@ runTests {
testToLuaEmptyAttrSet = {
expr = generators.toLua { } { };
expected = ''{}'';
expected = "{}";
};
testToLuaEmptyList = {
expr = generators.toLua { } [ ];
expected = ''{}'';
expected = "{}";
};
testToLuaListOfVariousTypes = {
@@ -3052,7 +3052,7 @@ runTests {
41
43
];
expected = ''{ 41, 43 }'';
expected = "{ 41, 43 }";
};
testToLuaEmptyBindings = {
@@ -4909,4 +4909,17 @@ runTests {
targetTarget = "prefix-tt";
};
};
testReplaceElemAt = {
expr = lib.replaceElemAt [ 1 2 3 ] 1 "a";
expected = [
1
"a"
3
];
};
testReplaceElemAtOutOfRange = testingThrow (lib.replaceElemAt [ 1 2 3 ] 5 "a");
testReplaceElemAtNegative = testingThrow (lib.replaceElemAt [ 1 2 3 ] (-1) "a");
}
+32 -4
View File
@@ -58,12 +58,19 @@ logFailure() {
evalConfig() {
local attr=$1
shift
local script="import ./default.nix { modules = [ $* ];}"
local nix_args=()
if [ "${ABORT_ON_WARN-0}" = "1" ]; then
local-nix-instantiate --option abort-on-warn true -E "$script" -A "$attr"
else
local-nix-instantiate -E "$script" -A "$attr"
nix_args+=(--option abort-on-warn true)
fi
if [ "${STRICT_EVAL-0}" = "1" ]; then
nix_args+=(--strict)
fi
local script="import ./default.nix { modules = [ $* ];}"
local-nix-instantiate "${nix_args[@]}" -E "$script" -A "$attr"
}
reportFailure() {
@@ -247,6 +254,19 @@ checkConfigError 'A definition for option .* is not of type .fileset.. Definitio
checkConfigError 'A definition for option .* is not of type .fileset.. Definition values:\n.*' config.filesetCardinal.err3 ./fileset.nix
checkConfigError 'A definition for option .* is not of type .fileset.. Definition values:\n.*' config.filesetCardinal.err4 ./fileset.nix
# types.serializableValueWith
checkConfigOutput '^null$' config.nullableValue.null ./types.nix
checkConfigOutput '^true$' config.nullableValue.bool ./types.nix
checkConfigOutput '^1$' config.nullableValue.int ./types.nix
checkConfigOutput '^1.1$' config.nullableValue.float ./types.nix
checkConfigOutput '^"foo"$' config.nullableValue.str ./types.nix
checkConfigOutput '^".*/store.*"$' config.nullableValue.path ./types.nix
STRICT_EVAL=1 checkConfigOutput '^\{"foo":1\}$' config.nullableValue.attrs ./types.nix
STRICT_EVAL=1 checkConfigOutput '^\[\{"bar":\[1\]\}\]$' config.nullableValue.list ./types.nix
checkConfigError 'A definition for option .* is not of type .VAL value.. .*' config.nullableValue.lambda ./types.nix
checkConfigError 'A definition for option .* is not of type .VAL value.. .*' config.structuredValue.null ./types.nix
# Check boolean option.
checkConfigOutput '^false$' config.enable ./declare-enable.nix
checkConfigError 'The option .* does not exist. Definition values:\n\s*- In .*: true' config.enable ./define-enable.nix
@@ -850,6 +870,14 @@ checkConfigError 'A definition for option .* is not of type .*' config.addCheckF
checkConfigOutput '^true$' config.result ./v2-check-coherence.nix
# Option name suggestions
checkConfigError 'Did you mean .set\.enable.\?' config.set ./error-typo-nested.nix
checkConfigError 'Did you mean .set.\?' config ./error-typo-outside-with-nested.nix
checkConfigError 'Did you mean .bar., .baz. or .foo.\?' config ./error-typo-multiple-suggestions.nix
checkConfigError 'Did you mean .enable., .ebe. or .enabled.\?' config ./error-typo-large-attrset.nix
checkConfigError 'Did you mean .services\.myservice\.port. or .services\.myservice\.enable.\?' config.services.myservice ./error-typo-submodule.nix
checkConfigError 'Did you mean .services\.nginx\.virtualHosts\."example\.com"\.ssl\.certificate. or .services\.nginx\.virtualHosts\."example\.com"\.ssl\.certificateKey.\?' config.services.nginx.virtualHosts.\"example.com\" ./error-typo-deeply-nested.nix
cat <<EOF
====== module tests ======
$pass Pass
@@ -0,0 +1,42 @@
{ lib, ... }:
{
options.services = {
nginx = {
enable = lib.mkOption {
default = false;
type = lib.types.bool;
};
virtualHosts = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options = {
enableSSL = lib.mkOption {
default = false;
type = lib.types.bool;
};
ssl = {
certificate = lib.mkOption {
default = "";
type = lib.types.str;
};
certificateKey = lib.mkOption {
default = "";
type = lib.types.str;
};
};
};
}
);
default = { };
};
};
};
config = {
services.nginx.virtualHosts."example.com" = {
# Typo: "certficate" instead of "certificate" (nested within submodule)
ssl.certficate = "/path/to/cert";
};
};
}
@@ -0,0 +1,56 @@
{ lib, ... }:
let
inherit (lib) mkOption concatMapAttrs;
ten = {
a = null;
b = null;
c = null;
d = null;
e = null;
f = null;
g = null;
h = null;
i = null;
j = null;
};
# Generate 1000 options (10 * 10 * 10)
generatedOptions = concatMapAttrs (
k1: _:
concatMapAttrs (
k2: _:
concatMapAttrs (k3: _: {
"${k1}${k2}${k3}" = mkOption {
type = lib.types.bool;
default = false;
};
}) ten
) ten
) ten;
# Add some sensible options that are close to our typo
sensibleOptions = {
enable = mkOption {
type = lib.types.bool;
default = false;
};
enabled = mkOption {
type = lib.types.bool;
default = false;
};
disable = mkOption {
type = lib.types.bool;
default = false;
};
};
in
{
options = generatedOptions // sensibleOptions;
config = {
# Typo: "enble" is distance 1 from "enable"
enble = true;
};
}

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