Files
lix/subprojects/nix-eval-jobs/tests/assets/flake.nix
T
Maximilian Bosch 8cb2306138 subprojects/nix-eval-jobs: bring back constituents
Hydra used to support aggregate jobs that only succeeded when their
constituents succeed. This is still used by e.g. nixpkgs[1].

Prior art:
* https://git.lix.systems/lix-project/nix-eval-jobs/pulls/17: got ported
  into the CppNix implementation[2]
* https://github.com/nix-community/nix-eval-jobs/pull/349: implements
  glob expressions for constituents - something we needed at work. This
  also restructures the code a bit which is what I re-used here. The
  globbing is not part of this patch.

Essentially, the following things happen here (assuming `--constituents`
is set):

* Derivations with `_hydraAggregate = true;` are considered aggregates.
  These are not written to stdout when received by a worker, but stored
  until the end.

* Constituents can be drv paths or strings (that must be the `attr` of
  another job). In that case, the derivation of the aggregate job is
  rewritten so that it depends on the drv of the constituent job.

* At the very end the aggregate jobs are also written to stdout.

Additionally, this fixes one bug, the old `hydra-eval-jobs`
implementation had (and we actually hit at work):

Given the leaf jobs `packages.foo` & `packages.bar`, an aggregate job
`aggregate0` with

    _hydraAggregate = true;
    constituents = [ "packages.bar" "packages.foo" ];

and an aggregate job `aggregate1` with

    constituents = [ "aggregate0" ];

then it may happen depending on the order of evaluation that `aggregate1`
depends on the old derivation of `aggregate0` (i.e. the one without
rewritten constituents) and doesn't depend on `packages.foo` and
`packages.bar` because it was rewritten before `aggregate0` was
rewritten.

This is done in here correctly, but topologically sorting the aggregate
jobs before rewriting those.

[1] https://github.com/NixOS/nixpkgs/blob/bba6b37c9d0898867a7d9c38a1b5b77efcfb07b9/nixos/release-combined.nix#L69
[2] https://github.com/nix-community/nix-eval-jobs/pull/340

Change-Id: I5baad5e57336b4985ef8595e903814de83eb01c1
2025-02-28 20:20:42 +01:00

75 lines
2.2 KiB
Nix

{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
outputs =
{ self, nixpkgs, ... }:
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
mkDrvWithConstituents =
name: constituents:
pkgs.runCommand name {
_hydraAggregate = true;
inherit constituents;
} "touch $out";
in
{
hydraJobs = import ./ci.nix { inherit pkgs; };
legacyPackages.x86_64-linux = {
brokenPkgs = {
brokenPackage = throw "this is an evaluation error";
};
infiniteRecursionPkgs = {
packageWithInfiniteRecursion =
let
recursion = [ recursion ];
in
derivation {
inherit (pkgs.stdenv.hostPlatform) system;
name = "drvB";
recursiveAttr = recursion;
builder = ":";
};
};
constituents = {
success = {
indirect_aggregate = mkDrvWithConstituents "indirect_aggregate" [
"anotherone"
];
direct_aggregate = mkDrvWithConstituents "direct_aggregate" [
self.hydraJobs.builtJob
];
mixed_aggregate = mkDrvWithConstituents "mixed_aggregate" [
self.hydraJobs.builtJob
"anotherone"
];
anotherone = pkgs.writeText "constituent" "text";
};
failures = {
aggregate = mkDrvWithConstituents "aggregate" [
"doesntexist"
"doesnteval"
];
doesnteval = pkgs.writeText "constituent" (toString { });
};
cycle = {
aggregate0 = mkDrvWithConstituents "aggregate0" [
"aggregate1"
];
aggregate1 = mkDrvWithConstituents "aggregate1" [
"aggregate0"
];
};
transitive = {
constituent = pkgs.hello;
# also flip the order to make sure the toposort works as intended.
aggregate1 = mkDrvWithConstituents "aggregate1" [ "constituent" ];
aggregate0 = mkDrvWithConstituents "aggregate0" [ "aggregate1" ];
};
};
};
};
}