1let
2 pinned = (builtins.fromJSON (builtins.readFile ./pinned.json)).pins;
3in
4{
5 system ? builtins.currentSystem,
6
7 nixpkgs ? null,
8 nixPath ? "nixVersions.latest",
9}:
10let
11 nixpkgs' =
12 if nixpkgs == null then
13 fetchTarball {
14 inherit (pinned.nixpkgs) url;
15 sha256 = pinned.nixpkgs.hash;
16 }
17 else
18 nixpkgs;
19
20 pkgs = import nixpkgs' {
21 inherit system;
22 # Nixpkgs generally — and CI specifically — do not use aliases,
23 # because we want to ensure they are not load-bearing.
24 allowAliases = false;
25 };
26
27 fmt =
28 let
29 treefmtNixSrc = fetchTarball {
30 inherit (pinned.treefmt-nix) url;
31 sha256 = pinned.treefmt-nix.hash;
32 };
33 treefmtEval = (import treefmtNixSrc).evalModule pkgs {
34 # Important: The auto-rebase script uses `git filter-branch --tree-filter`,
35 # which creates trees within the Git repository under `.git-rewrite/t`,
36 # notably without having a `.git` themselves.
37 # So if this projectRootFile were the default `.git/config`,
38 # having the auto-rebase script use treefmt on such a tree would make it
39 # format all files in the _parent_ Git tree as well.
40 projectRootFile = ".git-blame-ignore-revs";
41
42 # Be a bit more verbose by default, so we can see progress happening
43 settings.verbose = 1;
44
45 # By default it's info, which is too noisy since we have many unmatched files
46 settings.on-unmatched = "debug";
47
48 programs.actionlint.enable = true;
49
50 programs.biome = {
51 enable = true;
52 settings.formatter = {
53 useEditorconfig = true;
54 };
55 settings.javascript.formatter = {
56 quoteStyle = "single";
57 semicolons = "asNeeded";
58 };
59 settings.json.formatter.enabled = false;
60 };
61 settings.formatter.biome.excludes = [
62 "*.min.js"
63 "pkgs/*"
64 ];
65
66 programs.keep-sorted.enable = true;
67
68 # This uses nixfmt underneath, the default formatter for Nix code.
69 # See https://github.com/NixOS/nixfmt
70 programs.nixfmt = {
71 enable = true;
72 package = pkgs.nixfmt;
73 };
74
75 programs.yamlfmt = {
76 enable = true;
77 settings.formatter = {
78 retain_line_breaks = true;
79 };
80 };
81 settings.formatter.yamlfmt.excludes = [
82 # Breaks helm templating
83 "nixos/tests/k3s/k3s-test-chart/templates/*"
84 # Aligns comments with whitespace
85 "pkgs/development/haskell-modules/configuration-hackage2nix/main.yaml"
86 # TODO: Fix formatting for auto-generated file
87 "pkgs/development/haskell-modules/configuration-hackage2nix/transitive-broken.yaml"
88 ];
89
90 programs.nixf-diagnose.enable = true;
91 settings.formatter.nixf-diagnose = {
92 # Ensure nixfmt cleans up after nixf-diagnose.
93 priority = -1;
94 options = [
95 "--auto-fix"
96 # Rule names can currently be looked up here:
97 # https://github.com/nix-community/nixd/blob/main/libnixf/src/Basic/diagnostic.py
98 # TODO: Remove the following and fix things.
99 "--ignore=sema-unused-def-lambda-noarg-formal"
100 "--ignore=sema-unused-def-lambda-witharg-arg"
101 "--ignore=sema-unused-def-lambda-witharg-formal"
102 "--ignore=sema-unused-def-let"
103 # Keep this rule, because we have `lib.or`.
104 "--ignore=or-identifier"
105 ];
106 excludes = [
107 # Auto-generated; violates sema-extra-with
108 # Can only sensibly be removed when --auto-fix supports multiple fixes at once:
109 # https://github.com/inclyc/nixf-diagnose/issues/13
110 "pkgs/servers/home-assistant/component-packages.nix"
111 # https://github.com/nix-community/nixd/issues/708
112 "nixos/maintainers/scripts/azure-new/examples/basic/system.nix"
113 ];
114 };
115
116 settings.formatter.editorconfig-checker = {
117 command = "${pkgs.lib.getExe pkgs.editorconfig-checker}";
118 options = [ "-disable-indent-size" ];
119 includes = [ "*" ];
120 priority = 1;
121 };
122
123 # TODO: Upstream this into treefmt-nix eventually:
124 # https://github.com/numtide/treefmt-nix/issues/387
125 settings.formatter.markdown-code-runner = {
126 command = pkgs.lib.getExe pkgs.markdown-code-runner;
127 options =
128 let
129 config = pkgs.writers.writeTOML "markdown-code-runner-config" {
130 presets.nixfmt = {
131 language = "nix";
132 command = [ (pkgs.lib.getExe pkgs.nixfmt) ];
133 };
134 };
135 in
136 [ "--config=${config}" ];
137 includes = [ "*.md" ];
138 };
139 };
140 fs = pkgs.lib.fileset;
141 nixFilesSrc = fs.toSource {
142 root = ../.;
143 fileset = fs.difference ../. (fs.maybeMissing ../.git);
144 };
145 in
146 {
147 shell = treefmtEval.config.build.devShell;
148 pkg = treefmtEval.config.build.wrapper;
149 check = treefmtEval.config.build.check nixFilesSrc;
150 };
151
152in
153rec {
154 inherit pkgs fmt;
155 requestReviews = pkgs.callPackage ./request-reviews { };
156 codeownersValidator = pkgs.callPackage ./codeowners-validator { };
157
158 # FIXME(lf-): it might be useful to test other Nix implementations
159 # (nixVersions.stable and Lix) here somehow at some point to ensure we don't
160 # have eval divergence.
161 eval = pkgs.callPackage ./eval {
162 nix = pkgs.lib.getAttrFromPath (pkgs.lib.splitString "." nixPath) pkgs;
163 };
164
165 # CI jobs
166 lib-tests = import ../lib/tests/release.nix { inherit pkgs; };
167 manual-nixos = (import ../nixos/release.nix { }).manual.${system} or null;
168 manual-nixpkgs = (import ../doc { inherit pkgs; });
169 manual-nixpkgs-tests = (import ../doc { inherit pkgs; }).tests;
170 nixpkgs-vet = pkgs.callPackage ./nixpkgs-vet.nix {
171 nix = pkgs.nixVersions.latest;
172 };
173 parse = pkgs.lib.recurseIntoAttrs {
174 latest = pkgs.callPackage ./parse.nix { nix = pkgs.nixVersions.latest; };
175 lix = pkgs.callPackage ./parse.nix { nix = pkgs.lix; };
176 nix_2_28 = pkgs.callPackage ./parse.nix { nix = pkgs.nixVersions.nix_2_28; };
177 };
178 shell = import ../shell.nix { inherit nixpkgs system; };
179 tarball = import ../pkgs/top-level/make-tarball.nix {
180 # Mirrored from top-level release.nix:
181 nixpkgs = {
182 outPath = pkgs.lib.cleanSource ../.;
183 revCount = 1234;
184 shortRev = "abcdef";
185 revision = "0000000000000000000000000000000000000000";
186 };
187 officialRelease = false;
188 inherit pkgs lib-tests;
189 nix = pkgs.nixVersions.latest;
190 };
191}