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
75 lines
2.2 KiB
Nix
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" ];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|