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:
@ -55,6 +55,10 @@ sub jobset_PUT {
|
||||
|
||||
requireProjectOwner($c, $c->stash->{project});
|
||||
|
||||
if (length($c->stash->{project}->declfile)) {
|
||||
error($c, "can't modify jobset of declarative project", 403);
|
||||
}
|
||||
|
||||
if (defined $c->stash->{jobset}) {
|
||||
txn_do($c->model('DB')->schema, sub {
|
||||
updateJobset($c, $c->stash->{jobset});
|
||||
@ -88,6 +92,10 @@ sub jobset_DELETE {
|
||||
|
||||
requireProjectOwner($c, $c->stash->{project});
|
||||
|
||||
if (length($c->stash->{project}->declfile)) {
|
||||
error($c, "can't modify jobset of declarative project", 403);
|
||||
}
|
||||
|
||||
txn_do($c->model('DB')->schema, sub {
|
||||
$c->stash->{jobset}->jobsetevals->delete;
|
||||
$c->stash->{jobset}->builds->delete;
|
||||
|
@ -154,7 +154,19 @@ sub updateProject {
|
||||
, enabled => defined $c->stash->{params}->{enabled} ? 1 : 0
|
||||
, hidden => defined $c->stash->{params}->{visible} ? 0 : 1
|
||||
, owner => $owner
|
||||
, declfile => trim($c->stash->{params}->{declfile})
|
||||
, decltype => trim($c->stash->{params}->{decltype})
|
||||
, declvalue => trim($c->stash->{params}->{declvalue})
|
||||
});
|
||||
if (length($project->declfile)) {
|
||||
$project->jobsets->update_or_create(
|
||||
{ name=> ".jobsets"
|
||||
, nixexprinput => ""
|
||||
, nixexprpath => ""
|
||||
, emailoverride => ""
|
||||
, triggertime => time
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,21 @@ __PACKAGE__->table("Projects");
|
||||
data_type: 'text'
|
||||
is_nullable: 1
|
||||
|
||||
=head2 declfile
|
||||
|
||||
data_type: 'text'
|
||||
is_nullable: 1
|
||||
|
||||
=head2 decltype
|
||||
|
||||
data_type: 'text'
|
||||
is_nullable: 1
|
||||
|
||||
=head2 declvalue
|
||||
|
||||
data_type: 'text'
|
||||
is_nullable: 1
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->add_columns(
|
||||
@ -90,6 +105,12 @@ __PACKAGE__->add_columns(
|
||||
{ data_type => "text", is_foreign_key => 1, is_nullable => 0 },
|
||||
"homepage",
|
||||
{ data_type => "text", is_nullable => 1 },
|
||||
"declfile",
|
||||
{ data_type => "text", is_nullable => 1 },
|
||||
"decltype",
|
||||
{ data_type => "text", is_nullable => 1 },
|
||||
"declvalue",
|
||||
{ data_type => "text", is_nullable => 1 },
|
||||
);
|
||||
|
||||
=head1 PRIMARY KEY
|
||||
@ -282,8 +303,8 @@ Composing rels: L</projectmembers> -> username
|
||||
__PACKAGE__->many_to_many("usernames", "projectmembers", "username");
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07043 @ 2015-07-30 16:52:20
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:67kWIE0IGmEJTvOIATAKaw
|
||||
# Created by DBIx::Class::Schema::Loader v0.07043 @ 2016-03-11 10:39:17
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1ats3brIVhRTWLToIYSoaQ
|
||||
|
||||
my %hint = (
|
||||
columns => [
|
||||
|
Reference in New Issue
Block a user