hydra-eval-jobset: Use nix-eval-jobs
instead of hydra-eval-jobs
incrementally ingest eval results nix-eval-jobs streams output, unlike hydra-eval-jobs. Now that we've migrated, we can use this to: 1. Use less RAM by avoiding buffering a whole eval's worth of metadata into a Perl string and an array of JSON objects. 2. Make evals latency a bit lower by allowing the queue runner to start ingesting builds faster. Also use the newly-restored constituents support in `nix-eval-jobs` Note, we pass --workers and --max-memory-size to n-e-j Lost in the h-e-j -> n-e-j migration, causing evaluation to always be single threaded and limited to 4GiB RAM. Follow the config settings like h-e-j used to do (via C++ code). `nix-eval-jobs` should check `hydraJobs` and then `checks` with flakes (cherry picked from commit 6d4ccff43c41adaf6e4b2b9bced7243bc2f6e97b) (cherry picked from commit b0e9b4b2f99f9d8f5c4e780e89f955c394b5ced4) (cherry picked from commit cdfc5c81e8037d3e4818a3e459d0804b2c157ea9) (cherry picked from commit 4b107e6ff36bd89958fba36e0fe0340903e7cd13) Co-Authored-By: Maximilian Bosch <maximilian@mbosch.me>
This commit is contained in:
parent
0c9726af59
commit
d84ff32ce6
@ -21,7 +21,7 @@
|
|||||||
# hide nix-eval-jobs dev tooling from our lock file
|
# hide nix-eval-jobs dev tooling from our lock file
|
||||||
inputs.nix-eval-jobs.inputs.nix-github-actions.follows = "";
|
inputs.nix-eval-jobs.inputs.nix-github-actions.follows = "";
|
||||||
|
|
||||||
outputs = { self, nixpkgs, nix, ... }:
|
outputs = { self, nixpkgs, nix, nix-eval-jobs, ... }:
|
||||||
let
|
let
|
||||||
systems = [ "x86_64-linux" "aarch64-linux" ];
|
systems = [ "x86_64-linux" "aarch64-linux" ];
|
||||||
forEachSystem = nixpkgs.lib.genAttrs systems;
|
forEachSystem = nixpkgs.lib.genAttrs systems;
|
||||||
@ -32,6 +32,7 @@
|
|||||||
overlays.default = final: prev: {
|
overlays.default = final: prev: {
|
||||||
hydra = final.callPackage ./package.nix {
|
hydra = final.callPackage ./package.nix {
|
||||||
inherit (nixpkgs.lib) fileset;
|
inherit (nixpkgs.lib) fileset;
|
||||||
|
nix-eval-jobs = nix-eval-jobs.packages.${final.system}.default;
|
||||||
rawSrc = self;
|
rawSrc = self;
|
||||||
nix-perl-bindings = final.nixComponents.nix-perl-bindings;
|
nix-perl-bindings = final.nixComponents.nix-perl-bindings;
|
||||||
};
|
};
|
||||||
@ -75,6 +76,7 @@
|
|||||||
packages = forEachSystem (system: {
|
packages = forEachSystem (system: {
|
||||||
hydra = nixpkgs.legacyPackages.${system}.callPackage ./package.nix {
|
hydra = nixpkgs.legacyPackages.${system}.callPackage ./package.nix {
|
||||||
inherit (nixpkgs.lib) fileset;
|
inherit (nixpkgs.lib) fileset;
|
||||||
|
nix-eval-jobs = nix-eval-jobs.packages.${system}.default;
|
||||||
rawSrc = self;
|
rawSrc = self;
|
||||||
nix = nix.packages.${system}.nix;
|
nix = nix.packages.${system}.nix;
|
||||||
nix-perl-bindings = nix.hydraJobs.perlBindings.${system};
|
nix-perl-bindings = nix.hydraJobs.perlBindings.${system};
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
, xz
|
, xz
|
||||||
, gnutar
|
, gnutar
|
||||||
, gnused
|
, gnused
|
||||||
|
, nix-eval-jobs
|
||||||
|
|
||||||
, rpm
|
, rpm
|
||||||
, dpkg
|
, dpkg
|
||||||
@ -190,6 +191,7 @@ stdenv.mkDerivation (finalAttrs: {
|
|||||||
openldap
|
openldap
|
||||||
postgresql_13
|
postgresql_13
|
||||||
pixz
|
pixz
|
||||||
|
nix-eval-jobs
|
||||||
];
|
];
|
||||||
|
|
||||||
checkInputs = [
|
checkInputs = [
|
||||||
@ -218,6 +220,7 @@ stdenv.mkDerivation (finalAttrs: {
|
|||||||
darcs
|
darcs
|
||||||
gnused
|
gnused
|
||||||
breezy
|
breezy
|
||||||
|
nix-eval-jobs
|
||||||
] ++ lib.optionals stdenv.isLinux [ rpm dpkg cdrkit ]
|
] ++ lib.optionals stdenv.isLinux [ rpm dpkg cdrkit ]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ use Hydra::Helper::Nix;
|
|||||||
use Hydra::Model::DB;
|
use Hydra::Model::DB;
|
||||||
use Hydra::Plugin;
|
use Hydra::Plugin;
|
||||||
use Hydra::Schema;
|
use Hydra::Schema;
|
||||||
|
use IPC::Run;
|
||||||
use JSON::MaybeXS;
|
use JSON::MaybeXS;
|
||||||
use Net::Statsd;
|
use Net::Statsd;
|
||||||
use Nix::Store;
|
use Nix::Store;
|
||||||
@ -357,22 +358,32 @@ sub evalJobs {
|
|||||||
my @cmd;
|
my @cmd;
|
||||||
|
|
||||||
if (defined $flakeRef) {
|
if (defined $flakeRef) {
|
||||||
@cmd = ("hydra-eval-jobs",
|
my $nix_expr =
|
||||||
"--flake", $flakeRef,
|
"let " .
|
||||||
"--gc-roots-dir", getGCRootsDir,
|
"flake = builtins.getFlake (toString \"$flakeRef\"); " .
|
||||||
"--max-jobs", 1);
|
"in " .
|
||||||
|
"flake.hydraJobs " .
|
||||||
|
"or flake.checks " .
|
||||||
|
"or (throw \"flake '$flakeRef' does not provide any Hydra jobs or checks\")";
|
||||||
|
|
||||||
|
@cmd = ("nix-eval-jobs", "--expr", $nix_expr);
|
||||||
} else {
|
} else {
|
||||||
my $nixExprInput = $inputInfo->{$nixExprInputName}->[0]
|
my $nixExprInput = $inputInfo->{$nixExprInputName}->[0]
|
||||||
or die "cannot find the input containing the job expression\n";
|
or die "cannot find the input containing the job expression\n";
|
||||||
|
|
||||||
@cmd = ("hydra-eval-jobs",
|
@cmd = ("nix-eval-jobs",
|
||||||
"<" . $nixExprInputName . "/" . $nixExprPath . ">",
|
"<" . $nixExprInputName . "/" . $nixExprPath . ">",
|
||||||
"--gc-roots-dir", getGCRootsDir,
|
|
||||||
"--max-jobs", 1,
|
|
||||||
inputsToArgs($inputInfo));
|
inputsToArgs($inputInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
push @cmd, "--no-allow-import-from-derivation" if $config->{allow_import_from_derivation} // "true" ne "true";
|
push @cmd, ("--gc-roots-dir", getGCRootsDir);
|
||||||
|
push @cmd, ("--max-jobs", 1);
|
||||||
|
push @cmd, "--meta";
|
||||||
|
push @cmd, "--constituents";
|
||||||
|
push @cmd, "--force-recurse";
|
||||||
|
push @cmd, ("--option", "allow-import-from-derivation", "false") if $config->{allow_import_from_derivation} // "true" ne "true";
|
||||||
|
push @cmd, ("--workers", $config->{evaluator_workers} // 1);
|
||||||
|
push @cmd, ("--max-memory-size", $config->{evaluator_max_memory_size} // 4096);
|
||||||
|
|
||||||
if (defined $ENV{'HYDRA_DEBUG'}) {
|
if (defined $ENV{'HYDRA_DEBUG'}) {
|
||||||
sub escape {
|
sub escape {
|
||||||
@ -384,14 +395,33 @@ sub evalJobs {
|
|||||||
print STDERR "evaluator: @escaped\n";
|
print STDERR "evaluator: @escaped\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
(my $res, my $jobsJSON, my $stderr) = captureStdoutStderr(21600, @cmd);
|
my $evalProc = IPC::Run::start \@cmd,
|
||||||
die "hydra-eval-jobs returned " . ($res & 127 ? "signal $res" : "exit code " . ($res >> 8))
|
'>', IPC::Run::new_chunker, \my $out,
|
||||||
. ":\n" . ($stderr ? decode("utf-8", $stderr) : "(no output)\n")
|
'2>', \my $err;
|
||||||
if $res;
|
|
||||||
|
|
||||||
print STDERR "$stderr";
|
return sub {
|
||||||
|
while (1) {
|
||||||
|
$evalProc->pump;
|
||||||
|
if (!defined $out && !defined $err) {
|
||||||
|
$evalProc->finish;
|
||||||
|
if ($?) {
|
||||||
|
die "nix-eval-jobs returned " . ($? & 127 ? "signal $?" : "exit code " . ($? >> 8)) . "\n";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return decode_json($jobsJSON);
|
if (defined $err) {
|
||||||
|
print STDERR "$err";
|
||||||
|
undef $err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined $out && $out ne '') {
|
||||||
|
my $job = decode_json($out);
|
||||||
|
undef $out;
|
||||||
|
return $job;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -420,7 +450,7 @@ sub checkBuild {
|
|||||||
my $firstOutputName = $outputNames[0];
|
my $firstOutputName = $outputNames[0];
|
||||||
my $firstOutputPath = $buildInfo->{outputs}->{$firstOutputName};
|
my $firstOutputPath = $buildInfo->{outputs}->{$firstOutputName};
|
||||||
|
|
||||||
my $jobName = $buildInfo->{jobName} or die;
|
my $jobName = $buildInfo->{attr} or die;
|
||||||
my $drvPath = $buildInfo->{drvPath} or die;
|
my $drvPath = $buildInfo->{drvPath} or die;
|
||||||
|
|
||||||
my $build;
|
my $build;
|
||||||
@ -474,9 +504,30 @@ sub checkBuild {
|
|||||||
|
|
||||||
my $time = time();
|
my $time = time();
|
||||||
|
|
||||||
sub null {
|
sub getMeta {
|
||||||
my ($s) = @_;
|
my ($s, $def) = @_;
|
||||||
return $s eq "" ? undef : $s;
|
return ($s || "") eq "" ? $def : $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getMetaStrings {
|
||||||
|
my ($v, $k, $acc) = @_;
|
||||||
|
my $t = ref $v;
|
||||||
|
|
||||||
|
if ($t eq 'HASH') {
|
||||||
|
push @$acc, $v->{$k} if exists $v->{$k};
|
||||||
|
} elsif ($t eq 'ARRAY') {
|
||||||
|
getMetaStrings($_, $k, $acc) foreach @$v;
|
||||||
|
} elsif (defined $v) {
|
||||||
|
push @$acc, $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getMetaConcatStrings {
|
||||||
|
my ($v, $k) = @_;
|
||||||
|
|
||||||
|
my @strings;
|
||||||
|
getMetaStrings($v, $k, \@strings);
|
||||||
|
return join(", ", @strings) || undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add the build to the database.
|
# Add the build to the database.
|
||||||
@ -484,19 +535,19 @@ sub checkBuild {
|
|||||||
{ timestamp => $time
|
{ timestamp => $time
|
||||||
, jobset_id => $jobset->id
|
, jobset_id => $jobset->id
|
||||||
, job => $jobName
|
, job => $jobName
|
||||||
, description => null($buildInfo->{description})
|
, description => getMeta($buildInfo->{meta}->{description}, undef)
|
||||||
, license => null($buildInfo->{license})
|
, license => getMetaConcatStrings($buildInfo->{meta}->{license}, "shortName")
|
||||||
, homepage => null($buildInfo->{homepage})
|
, homepage => getMeta($buildInfo->{meta}->{homepage}, undef)
|
||||||
, maintainers => null($buildInfo->{maintainers})
|
, maintainers => getMetaConcatStrings($buildInfo->{meta}->{maintainers}, "email")
|
||||||
, maxsilent => $buildInfo->{maxSilent}
|
, maxsilent => getMeta($buildInfo->{meta}->{maxSilent}, 7200)
|
||||||
, timeout => $buildInfo->{timeout}
|
, timeout => getMeta($buildInfo->{meta}->{timeout}, 36000)
|
||||||
, nixname => $buildInfo->{nixName}
|
, nixname => $buildInfo->{name}
|
||||||
, drvpath => $drvPath
|
, drvpath => $drvPath
|
||||||
, system => $buildInfo->{system}
|
, system => $buildInfo->{system}
|
||||||
, priority => $buildInfo->{schedulingPriority}
|
, priority => getMeta($buildInfo->{meta}->{schedulingPriority}, 100)
|
||||||
, finished => 0
|
, finished => 0
|
||||||
, iscurrent => 1
|
, iscurrent => 1
|
||||||
, ischannel => $buildInfo->{isChannel}
|
, ischannel => getMeta($buildInfo->{meta}->{isChannel}, 0)
|
||||||
});
|
});
|
||||||
|
|
||||||
$build->buildoutputs->create({ name => $_, path => $buildInfo->{outputs}->{$_} })
|
$build->buildoutputs->create({ name => $_, path => $buildInfo->{outputs}->{$_} })
|
||||||
@ -665,7 +716,7 @@ sub checkJobsetWrapped {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Hash the arguments to hydra-eval-jobs and check the
|
# Hash the arguments to nix-eval-jobs and check the
|
||||||
# JobsetInputHashes to see if the previous evaluation had the same
|
# JobsetInputHashes to see if the previous evaluation had the same
|
||||||
# inputs. If so, bail out.
|
# inputs. If so, bail out.
|
||||||
my @args = ($jobset->nixexprinput // "", $jobset->nixexprpath // "", inputsToArgs($inputInfo));
|
my @args = ($jobset->nixexprinput // "", $jobset->nixexprpath // "", inputsToArgs($inputInfo));
|
||||||
@ -687,19 +738,12 @@ sub checkJobsetWrapped {
|
|||||||
|
|
||||||
# Evaluate the job expression.
|
# Evaluate the job expression.
|
||||||
my $evalStart = clock_gettime(CLOCK_MONOTONIC);
|
my $evalStart = clock_gettime(CLOCK_MONOTONIC);
|
||||||
my $jobs = evalJobs($project->name . ":" . $jobset->name, $inputInfo, $jobset->nixexprinput, $jobset->nixexprpath, $flakeRef);
|
my $evalStop;
|
||||||
my $evalStop = clock_gettime(CLOCK_MONOTONIC);
|
my $jobsIter = evalJobs($project->name . ":" . $jobset->name, $inputInfo, $jobset->nixexprinput, $jobset->nixexprpath, $flakeRef);
|
||||||
|
|
||||||
if ($jobsetsJobset) {
|
|
||||||
my @keys = keys %$jobs;
|
|
||||||
die "The .jobsets jobset must only have a single job named 'jobsets'"
|
|
||||||
unless (scalar @keys) == 1 && $keys[0] eq "jobsets";
|
|
||||||
}
|
|
||||||
Net::Statsd::timing("hydra.evaluator.eval_time", int(($evalStop - $evalStart) * 1000));
|
|
||||||
|
|
||||||
if ($dryRun) {
|
if ($dryRun) {
|
||||||
foreach my $name (keys %{$jobs}) {
|
while (defined(my $job = $jobsIter->())) {
|
||||||
my $job = $jobs->{$name};
|
my $name = $job->{attr};
|
||||||
if (defined $job->{drvPath}) {
|
if (defined $job->{drvPath}) {
|
||||||
print STDERR "good job $name: $job->{drvPath}\n";
|
print STDERR "good job $name: $job->{drvPath}\n";
|
||||||
} else {
|
} else {
|
||||||
@ -709,36 +753,20 @@ sub checkJobsetWrapped {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
die "Jobset contains a job with an empty name. Make sure the jobset evaluates to an attrset of jobs.\n"
|
|
||||||
if defined $jobs->{""};
|
|
||||||
|
|
||||||
$jobs->{$_}->{jobName} = $_ for keys %{$jobs};
|
|
||||||
|
|
||||||
my $jobOutPathMap = {};
|
|
||||||
my $jobsetChanged = 0;
|
|
||||||
my $dbStart = clock_gettime(CLOCK_MONOTONIC);
|
|
||||||
|
|
||||||
|
|
||||||
# Store the error messages for jobs that failed to evaluate.
|
# Store the error messages for jobs that failed to evaluate.
|
||||||
my $evaluationErrorTime = time;
|
my $evaluationErrorTime = time;
|
||||||
my $evaluationErrorMsg = "";
|
my $evaluationErrorMsg = "";
|
||||||
foreach my $job (values %{$jobs}) {
|
|
||||||
next unless defined $job->{error};
|
|
||||||
$evaluationErrorMsg .=
|
|
||||||
($job->{jobName} ne "" ? "in job ‘$job->{jobName}’" : "at top-level") .
|
|
||||||
":\n" . $job->{error} . "\n\n";
|
|
||||||
}
|
|
||||||
setJobsetError($jobset, $evaluationErrorMsg, $evaluationErrorTime);
|
|
||||||
|
|
||||||
my $evaluationErrorRecord = $db->resultset('EvaluationErrors')->create(
|
my $evaluationErrorRecord = $db->resultset('EvaluationErrors')->create(
|
||||||
{ errormsg => $evaluationErrorMsg
|
{ errormsg => $evaluationErrorMsg
|
||||||
, errortime => $evaluationErrorTime
|
, errortime => $evaluationErrorTime
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
my $jobOutPathMap = {};
|
||||||
|
my $jobsetChanged = 0;
|
||||||
my %buildMap;
|
my %buildMap;
|
||||||
$db->txn_do(sub {
|
|
||||||
|
|
||||||
|
$db->txn_do(sub {
|
||||||
my $prevEval = getPrevJobsetEval($db, $jobset, 1);
|
my $prevEval = getPrevJobsetEval($db, $jobset, 1);
|
||||||
|
|
||||||
# Clear the "current" flag on all builds. Since we're in a
|
# Clear the "current" flag on all builds. Since we're in a
|
||||||
@ -751,7 +779,7 @@ sub checkJobsetWrapped {
|
|||||||
, evaluationerror => $evaluationErrorRecord
|
, evaluationerror => $evaluationErrorRecord
|
||||||
, timestamp => time
|
, timestamp => time
|
||||||
, checkouttime => abs(int($checkoutStop - $checkoutStart))
|
, checkouttime => abs(int($checkoutStop - $checkoutStart))
|
||||||
, evaltime => abs(int($evalStop - $evalStart))
|
, evaltime => 0
|
||||||
, hasnewbuilds => 0
|
, hasnewbuilds => 0
|
||||||
, nrbuilds => 0
|
, nrbuilds => 0
|
||||||
, flake => $flakeRef
|
, flake => $flakeRef
|
||||||
@ -759,11 +787,24 @@ sub checkJobsetWrapped {
|
|||||||
, nixexprpath => $jobset->nixexprpath
|
, nixexprpath => $jobset->nixexprpath
|
||||||
});
|
});
|
||||||
|
|
||||||
# Schedule each successfully evaluated job.
|
my @jobsWithConstituents;
|
||||||
foreach my $job (permute(values %{$jobs})) {
|
|
||||||
next if defined $job->{error};
|
while (defined(my $job = $jobsIter->())) {
|
||||||
#print STDERR "considering job " . $project->name, ":", $jobset->name, ":", $job->{jobName} . "\n";
|
if ($jobsetsJobset) {
|
||||||
checkBuild($db, $jobset, $ev, $inputInfo, $job, \%buildMap, $prevEval, $jobOutPathMap, $plugins);
|
die "The .jobsets jobset must only have a single job named 'jobsets'"
|
||||||
|
unless $job->{attr} eq "jobsets";
|
||||||
|
}
|
||||||
|
|
||||||
|
$evaluationErrorMsg .=
|
||||||
|
($job->{attr} ne "" ? "in job ‘$job->{attr}’" : "at top-level") .
|
||||||
|
":\n" . $job->{error} . "\n\n" if defined $job->{error};
|
||||||
|
|
||||||
|
checkBuild($db, $jobset, $ev, $inputInfo, $job, \%buildMap, $prevEval, $jobOutPathMap, $plugins)
|
||||||
|
unless defined $job->{error};
|
||||||
|
|
||||||
|
if (defined $job->{constituents}) {
|
||||||
|
push @jobsWithConstituents, $job;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Have any builds been added or removed since last time?
|
# Have any builds been added or removed since last time?
|
||||||
@ -801,21 +842,20 @@ sub checkJobsetWrapped {
|
|||||||
$drvPathToId{$x->{drvPath}} = $x;
|
$drvPathToId{$x->{drvPath}} = $x;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $job (values %{$jobs}) {
|
foreach my $job (values @jobsWithConstituents) {
|
||||||
next unless $job->{constituents};
|
next unless defined $job->{constituents};
|
||||||
|
|
||||||
if (defined $job->{error}) {
|
if (defined $job->{error}) {
|
||||||
die "aggregate job ‘$job->{jobName}’ failed with the error: $job->{error}\n";
|
die "aggregate job ‘$job->{attr}’ failed with the error: $job->{error}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
my $x = $drvPathToId{$job->{drvPath}} or
|
my $x = $drvPathToId{$job->{drvPath}} or
|
||||||
die "aggregate job ‘$job->{jobName}’ has no corresponding build record.\n";
|
die "aggregate job ‘$job->{attr}’ has no corresponding build record.\n";
|
||||||
foreach my $drvPath (@{$job->{constituents}}) {
|
foreach my $drvPath (@{$job->{constituents}}) {
|
||||||
my $constituent = $drvPathToId{$drvPath};
|
my $constituent = $drvPathToId{$drvPath};
|
||||||
if (defined $constituent) {
|
if (defined $constituent) {
|
||||||
$db->resultset('AggregateConstituents')->update_or_create({aggregate => $x->{id}, constituent => $constituent->{id}});
|
$db->resultset('AggregateConstituents')->update_or_create({aggregate => $x->{id}, constituent => $constituent->{id}});
|
||||||
} else {
|
} else {
|
||||||
warn "aggregate job ‘$job->{jobName}’ has a constituent ‘$drvPath’ that doesn't correspond to a Hydra build\n";
|
warn "aggregate job ‘$job->{attr}’ has a constituent ‘$drvPath’ that doesn't correspond to a Hydra build\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -857,11 +897,15 @@ sub checkJobsetWrapped {
|
|||||||
$jobset->update({ enabled => 0 }) if $jobset->enabled == 2;
|
$jobset->update({ enabled => 0 }) if $jobset->enabled == 2;
|
||||||
|
|
||||||
$jobset->update({ lastcheckedtime => time, forceeval => undef });
|
$jobset->update({ lastcheckedtime => time, forceeval => undef });
|
||||||
|
|
||||||
|
$evaluationErrorRecord->update({ errormsg => $evaluationErrorMsg });
|
||||||
|
setJobsetError($jobset, $evaluationErrorMsg, $evaluationErrorTime);
|
||||||
|
|
||||||
|
$evalStop = clock_gettime(CLOCK_MONOTONIC);
|
||||||
|
$ev->update({ evaltime => abs(int($evalStop - $evalStart)) });
|
||||||
});
|
});
|
||||||
|
|
||||||
my $dbStop = clock_gettime(CLOCK_MONOTONIC);
|
Net::Statsd::timing("hydra.evaluator.eval_time", int(($evalStop - $evalStart) * 1000));
|
||||||
|
|
||||||
Net::Statsd::timing("hydra.evaluator.db_time", int(($dbStop - $dbStart) * 1000));
|
|
||||||
Net::Statsd::increment("hydra.evaluator.evals");
|
Net::Statsd::increment("hydra.evaluator.evals");
|
||||||
Net::Statsd::increment("hydra.evaluator.cached_evals") unless $jobsetChanged;
|
Net::Statsd::increment("hydra.evaluator.cached_evals") unless $jobsetChanged;
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,14 @@ isnt($res, 0, "hydra-eval-jobset exits non-zero");
|
|||||||
ok(utf8::decode($stderr), "Stderr output is UTF8-clean");
|
ok(utf8::decode($stderr), "Stderr output is UTF8-clean");
|
||||||
like(
|
like(
|
||||||
$stderr,
|
$stderr,
|
||||||
qr/aggregate job ‘mixed_aggregate’ failed with the error: constituentA: does not exist/,
|
qr/aggregate job ‘mixed_aggregate’ failed with the error: "constituentA": does not exist/,
|
||||||
"The stderr record includes a relevant error message"
|
"The stderr record includes a relevant error message"
|
||||||
);
|
);
|
||||||
|
|
||||||
$jobset->discard_changes; # refresh from DB
|
$jobset->discard_changes({ '+columns' => {'errormsg' => 'errormsg'} }); # refresh from DB
|
||||||
like(
|
like(
|
||||||
$jobset->errormsg,
|
$jobset->errormsg,
|
||||||
qr/aggregate job ‘mixed_aggregate’ failed with the error: constituentA: does not exist/,
|
qr/aggregate job ‘mixed_aggregate’ failed with the error: "constituentA": does not exist/,
|
||||||
"The jobset records a relevant error message"
|
"The jobset records a relevant error message"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
22
t/evaluator/evaluate-meta.t
Normal file
22
t/evaluator/evaluate-meta.t
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use feature 'unicode_strings';
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Setup;
|
||||||
|
use Test2::V0;
|
||||||
|
|
||||||
|
my $ctx = test_context();
|
||||||
|
|
||||||
|
my $builds = $ctx->makeAndEvaluateJobset(
|
||||||
|
expression => "meta.nix",
|
||||||
|
build => 1
|
||||||
|
);
|
||||||
|
|
||||||
|
my $build = $builds->{"full-of-meta"};
|
||||||
|
|
||||||
|
is($build->finished, 1, "Build should be finished.");
|
||||||
|
is($build->description, "This is the description of the job.", "Wrong description extracted from the build.");
|
||||||
|
is($build->license, "MIT, BSD", "Wrong licenses extracted from the build.");
|
||||||
|
is($build->homepage, "https://example.com/", "Wrong homepage extracted from the build.");
|
||||||
|
is($build->maintainers, 'alice@example.com, bob@not.found', "Wrong maintainers extracted from the build.");
|
||||||
|
|
||||||
|
done_testing;
|
17
t/jobs/meta.nix
Normal file
17
t/jobs/meta.nix
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
with import ./config.nix;
|
||||||
|
{
|
||||||
|
full-of-meta =
|
||||||
|
mkDerivation {
|
||||||
|
name = "full-of-meta";
|
||||||
|
builder = ./empty-dir-builder.sh;
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "This is the description of the job.";
|
||||||
|
license = [ { shortName = "MIT"; } "BSD" ];
|
||||||
|
homepage = "https://example.com/";
|
||||||
|
maintainers = [ "alice@example.com" { email = "bob@not.found"; } ];
|
||||||
|
|
||||||
|
outPath = "${placeholder "out"}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -22,11 +22,11 @@ is(nrQueuedBuildsForJobset($jobset), 0, "Evaluating jobs/broken-constituent.nix
|
|||||||
|
|
||||||
like(
|
like(
|
||||||
$jobset->errormsg,
|
$jobset->errormsg,
|
||||||
qr/^does-not-exist: does not exist$/m,
|
qr/^"does-not-exist": does not exist$/m,
|
||||||
"Evaluating jobs/broken-constituent.nix should log an error for does-not-exist");
|
"Evaluating jobs/broken-constituent.nix should log an error for does-not-exist");
|
||||||
like(
|
like(
|
||||||
$jobset->errormsg,
|
$jobset->errormsg,
|
||||||
qr/^does-not-evaluate: error: assertion 'false' failed$/m,
|
qr/^"does-not-evaluate": "error: assertion 'false' failed/m,
|
||||||
"Evaluating jobs/broken-constituent.nix should log an error for does-not-evaluate");
|
"Evaluating jobs/broken-constituent.nix should log an error for does-not-evaluate");
|
||||||
|
|
||||||
done_testing;
|
done_testing;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user