Merge pull request #1176 from DeterminateSystems/broken-constituent

Broken constituents: emit useful log messages on evaluation errors on constituents
This commit is contained in:
Graham Christensen 2022-03-19 14:55:17 -04:00 committed by GitHub
commit 22026da4f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 19 deletions

View file

@ -799,7 +799,13 @@ sub checkJobsetWrapped {
foreach my $job (values %{$jobs}) {
next unless $job->{constituents};
my $x = $drvPathToId{$job->{drvPath}} or die;
if (defined $job->{error}) {
die "aggregate job $job->{jobName} failed with the error: $job->{error}\n";
}
my $x = $drvPathToId{$job->{drvPath}} or
die "aggregate job $job->{jobName} has no corresponding build record.\n";
foreach my $drvPath (@{$job->{constituents}}) {
my $constituent = $drvPathToId{$drvPath};
if (defined $constituent) {

View file

@ -0,0 +1,32 @@
use strict;
use warnings;
use Setup;
use Test2::V0;
use Hydra::Helper::Exec;
my $ctx = test_context();
my $jobsetCtx = $ctx->makeJobset(
expression => 'constituents-broken.nix',
);
my $jobset = $jobsetCtx->{"jobset"};
my ($res, $stdout, $stderr) = captureStdoutStderr(60,
("hydra-eval-jobset", $jobsetCtx->{"project"}->name, $jobset->name)
);
isnt($res, 0, "hydra-eval-jobset exits non-zero");
ok(utf8::decode($stderr), "Stderr output is UTF8-clean");
like(
$stderr,
qr/aggregate job mixed_aggregate failed with the error: constituentA: does not exist/,
"The stderr record includes a relevant error message"
);
$jobset->discard_changes; # refresh from DB
like(
$jobset->errormsg,
qr/aggregate job mixed_aggregate failed with the error: constituentA: does not exist/,
"The jobset records a relevant error message"
);
done_testing;

View file

@ -0,0 +1,19 @@
with import ./config.nix;
rec {
constituentA = null;
constituentB = mkDerivation {
name = "empty-dir-B";
builder = ./empty-dir-builder.sh;
};
mixed_aggregate = mkDerivation {
name = "mixed_aggregate";
_hydraAggregate = true;
constituents = [
"constituentA"
constituentB
];
builder = ./empty-dir-builder.sh;
};
}

View file

@ -145,10 +145,47 @@ sub nix_state_dir {
sub makeAndEvaluateJobset {
my ($self, %opts) = @_;
my $expression = $opts{'expression'} || die "Mandatory 'expression' option not passed to makeAndEValuateJobset.";
my $should_build = $opts{'build'} // 0;
my $expression = $opts{'expression'} || die "Mandatory 'expression' option not passed to makeAndEvaluateJobset.\n";
my $jobsdir = $opts{'jobsdir'} // $self->jobsdir;
my $should_build = $opts{'build'} // 0;
my $jobsetCtx = $self->makeJobset(
expression => $expression,
jobsdir => $jobsdir,
);
my $jobset = $jobsetCtx->{"jobset"};
evalSucceeds($jobset) or die "Evaluating jobs/$expression should exit with return code 0.\n";
my $builds = {};
for my $build ($jobset->builds) {
if ($should_build) {
runBuild($build) or die "Build '".$build->job."' from jobs/$expression should exit with return code 0.\n";
$build->discard_changes();
}
$builds->{$build->job} = $build;
}
return $builds;
}
# Create a jobset.
#
# In return, you get a hash of the user, project, and jobset records.
#
# This always uses an `expression` from the `jobsdir` directory.
#
# Hash Parameters:
#
# * expression: The file in the jobsdir directory to evaluate
# * jobsdir: An alternative jobsdir to source the expression from
sub makeJobset {
my ($self, %opts) = @_;
my $expression = $opts{'expression'} || die "Mandatory 'expression' option not passed to makeJobset.\n";
my $jobsdir = $opts{'jobsdir'} // $self->jobsdir;
# Create a new user for this test
my $user = $self->db()->resultset('Users')->create({
@ -174,23 +211,13 @@ sub makeAndEvaluateJobset {
my $jobsetinput = $jobset->jobsetinputs->create({name => "jobs", type => "path"});
$jobsetinput->jobsetinputalts->create({altnr => 0, value => $jobsdir});
evalSucceeds($jobset) or die "Evaluating jobs/$expression should exit with return code 0";
my $builds = {};
for my $build ($jobset->builds) {
if ($should_build) {
runBuild($build) or die "Build '".$build->job."' from jobs/$expression should exit with return code 0";
$build->discard_changes();
}
$builds->{$build->job} = $build;
}
return $builds;
return {
user => $user,
project => $project,
jobset => $jobset,
};
}
sub DESTROY
{
my ($self) = @_;
@ -200,7 +227,7 @@ sub DESTROY
sub write_file {
my ($path, $text) = @_;
open(my $fh, '>', $path) or die "Could not open file '$path' $!";
open(my $fh, '>', $path) or die "Could not open file '$path' $!\n.";
print $fh $text || "";
close $fh;
}