Enable declarative projects.

This allows fully declarative project specifications. This is best
illustrated by example:

* I create a new project, setting the declarative spec file to
  "spec.json" and the declarative input to a git repo pointing
  at git://github.com/shlevy/declarative-hydra-example.git
* hydra creates a special ".jobsets" jobset alongside the project
* Just before evaluating the ".jobsets" jobset, hydra fetches
  declarative-hydra-example.git, reads spec.json as a jobset spec,
  and updates the jobset's configuration accordingly:
{
    "enabled": 1,
    "hidden": false,
    "description": "Jobsets",
    "nixexprinput": "src",
    "nixexprpath": "default.nix",
    "checkinterval": 300,
    "schedulingshares": 100,
    "enableemail": false,
    "emailoverride": "",
    "keepnr": 3,
    "inputs": {
        "src": { "type": "git", "value": "git://github.com/shlevy/declarative-hydra-example.git", "emailresponsible": false },
        "nixpkgs": { "type": "git", "value": "git://github.com/NixOS/nixpkgs.git release-16.03", "emailresponsible": false }
    }
}
* When the "jobsets" job of the ".jobsets" jobset completes, hydra
  reads its output as a JSON representation of a dictionary of
  jobset specs and creates a jobset named "master" configured
  accordingly (In this example, this is the same configuration as
  .jobsets itself, except using release.nix instead of default.nix):
{
    "enabled": 1,
    "hidden": false,
    "description": "js",
    "nixexprinput": "src",
    "nixexprpath": "release.nix",
    "checkinterval": 300,
    "schedulingshares": 100,
    "enableemail": false,
    "emailoverride": "",
    "keepnr": 3,
    "inputs": {
        "src": { "type": "git", "value": "git://github.com/shlevy/declarative-hydra-example.git", "emailresponsible": false },
        "nixpkgs": { "type": "git", "value": "git://github.com/NixOS/nixpkgs.git release-16.03", "emailresponsible": false }
    }
}
This commit is contained in:
Shea Levy
2016-03-11 18:14:58 -05:00
parent 995f3b21db
commit 4392d3e21d
12 changed files with 168 additions and 4 deletions

View File

@ -22,7 +22,8 @@ use Hydra::Helper::CatalystUtils;
our @ISA = qw(Exporter);
our @EXPORT = qw(
fetchInput evalJobs checkBuild inputsToArgs
restartBuild getPrevJobsetEval
restartBuild getPrevJobsetEval updateDeclarativeJobset
handleDeclarativeJobsetBuild
);
@ -467,4 +468,66 @@ sub checkBuild {
};
sub updateDeclarativeJobset {
my ($db, $project, $jobsetName, $declSpec) = @_;
my @allowed_keys = qw(
enabled
hidden
description
nixexprinput
nixexprpath
checkinterval
schedulingshares
enableemail
emailoverride
keepnr
);
my %update = ( name => $jobsetName );
foreach my $key (@allowed_keys) {
$update{$key} = $declSpec->{$key};
delete $declSpec->{$key};
}
txn_do($db, sub {
my $jobset = $project->jobsets->update_or_create(\%update);
$jobset->jobsetinputs->delete;
while ((my $name, my $data) = each %{$declSpec->{"inputs"}}) {
my $input = $jobset->jobsetinputs->create(
{ name => $name,
type => $data->{type},
emailresponsible => $data->{emailresponsible}
});
$input->jobsetinputalts->create({altnr => 0, value => $data->{value}});
}
delete $declSpec->{"inputs"};
die "invalid keys in declarative specification file\n" if (%{$declSpec});
});
};
sub handleDeclarativeJobsetBuild {
my ($db, $project, $build) = @_;
eval {
my $id = $build->id;
die "Declarative jobset build $id failed" unless $build->buildstatus == 0;
my $declPath = ($build->buildoutputs)[0]->path;
my $declText = read_file($declPath)
or die "Couldn't read declarative specification file $declPath: $!";
my $declSpec = decode_json($declText);
txn_do($db, sub {
my @kept = keys %$declSpec;
push @kept, ".jobsets";
$project->jobsets->search({ name => { "not in" => \@kept } })->update({ enabled => 0, hidden => 1 });
while ((my $jobsetName, my $spec) = each %$declSpec) {
updateDeclarativeJobset($db, $project, $jobsetName, $spec);
}
});
};
$project->jobsets->find({ name => ".jobsets" })->update({ errormsg => $@, errortime => time, fetcherrormsg => undef })
if defined $@;
};
1;

View File

@ -264,7 +264,7 @@ Readonly our $inputNameRE => "(?:[A-Za-z_][A-Za-z0-9-_]*)";
sub parseJobsetName {
my ($s) = @_;
$s =~ /^($projectNameRE):($jobsetNameRE)$/ or die "invalid jobset specifier $s\n";
$s =~ /^($projectNameRE):(\.?$jobsetNameRE)$/ or die "invalid jobset specifier $s\n";
return ($1, $2);
}