forked from lix-project/hydra
Merge branch 'custom-channels' of https://github.com/aszlig/hydra
This commit is contained in:
commit
30823078c4
|
@ -129,6 +129,7 @@ static void findJobsWrapped(EvalState & state, JSONObject & top,
|
||||||
res.attr("schedulingPriority", drv.queryMetaInt("schedulingPriority", 100));
|
res.attr("schedulingPriority", drv.queryMetaInt("schedulingPriority", 100));
|
||||||
res.attr("timeout", drv.queryMetaInt("timeout", 36000));
|
res.attr("timeout", drv.queryMetaInt("timeout", 36000));
|
||||||
res.attr("maxSilent", drv.queryMetaInt("maxSilent", 7200));
|
res.attr("maxSilent", drv.queryMetaInt("maxSilent", 7200));
|
||||||
|
res.attr("isChannel", drv.queryMetaBool("isHydraChannel", false));
|
||||||
|
|
||||||
/* If this is an aggregate, then get its constituents. */
|
/* If this is an aggregate, then get its constituents. */
|
||||||
Bindings::iterator a = v.attrs->find(state.symbols.create("_hydraAggregate"));
|
Bindings::iterator a = v.attrs->find(state.symbols.create("_hydraAggregate"));
|
||||||
|
|
|
@ -32,10 +32,9 @@ sub all : Chained('get_builds') PathPart {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub nix : Chained('get_builds') PathPart('channel') CaptureArgs(1) {
|
sub nix : Chained('get_builds') PathPart('channel/latest') CaptureArgs(1) {
|
||||||
my ($self, $c, $channelName) = @_;
|
my ($self, $c, $channelName) = @_;
|
||||||
eval {
|
|
||||||
if ($channelName eq "latest") {
|
|
||||||
$c->stash->{channelName} = $c->stash->{channelBaseName} . "-latest";
|
$c->stash->{channelName} = $c->stash->{channelBaseName} . "-latest";
|
||||||
$c->stash->{channelBuilds} = $c->stash->{latestSucceeded}
|
$c->stash->{channelBuilds} = $c->stash->{latestSucceeded}
|
||||||
->search_literal("exists (select 1 from buildproducts where build = me.id and type = 'nix-build')")
|
->search_literal("exists (select 1 from buildproducts where build = me.id and type = 'nix-build')")
|
||||||
|
@ -43,12 +42,6 @@ sub nix : Chained('get_builds') PathPart('channel') CaptureArgs(1) {
|
||||||
, join => ["buildoutputs"]
|
, join => ["buildoutputs"]
|
||||||
, order_by => ["me.id", "buildoutputs.name"]
|
, order_by => ["me.id", "buildoutputs.name"]
|
||||||
, '+select' => ['buildoutputs.path', 'buildoutputs.name'], '+as' => ['outpath', 'outname'] });
|
, '+select' => ['buildoutputs.path', 'buildoutputs.name'], '+as' => ['outpath', 'outname'] });
|
||||||
}
|
|
||||||
else {
|
|
||||||
notFound($c, "Unknown channel `$channelName'.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
error($c, $@) if $@;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ sub channel_contents : Chained('nix') PathPart('') Args(0) {
|
||||||
# garbage-collected. That should be true for the "latest"
|
# garbage-collected. That should be true for the "latest"
|
||||||
# channel.
|
# channel.
|
||||||
getChannelData($c, 0);
|
getChannelData($c, 0);
|
||||||
|
$c->stash->{genericChannel} = 1;
|
||||||
$c->stash->{template} = 'channel-contents.tt';
|
$c->stash->{template} = 'channel-contents.tt';
|
||||||
$c->stash->{nixPkgs} = [sortPkgs @{$c->stash->{nixPkgs}}];
|
$c->stash->{nixPkgs} = [sortPkgs @{$c->stash->{nixPkgs}}];
|
||||||
}
|
}
|
||||||
|
|
83
src/lib/Hydra/Controller/Channel.pm
Normal file
83
src/lib/Hydra/Controller/Channel.pm
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package Hydra::Controller::Channel;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use base 'Hydra::Base::Controller::REST';
|
||||||
|
|
||||||
|
|
||||||
|
sub channel : Chained('/') PathPart('channel/custom') CaptureArgs(3) {
|
||||||
|
my ($self, $c, $projectName, $jobsetName, $channelName) = @_;
|
||||||
|
|
||||||
|
$c->stash->{project} = $c->model('DB::Projects')->find($projectName);
|
||||||
|
|
||||||
|
notFound($c, "Project $projectName doesn't exist.")
|
||||||
|
if !$c->stash->{project};
|
||||||
|
|
||||||
|
$c->stash->{jobset} = $c->stash->{project}->jobsets->find({
|
||||||
|
name => $jobsetName
|
||||||
|
});
|
||||||
|
|
||||||
|
notFound($c, "Jobset $jobsetName doesn't exist.")
|
||||||
|
if !$c->stash->{jobset};
|
||||||
|
|
||||||
|
my $lastSuccessful = $c->model('DB::Builds')->find(
|
||||||
|
{ 'eval.hasnewbuilds' => 1
|
||||||
|
, project => $projectName
|
||||||
|
, jobset => $jobsetName
|
||||||
|
, job => $channelName
|
||||||
|
, buildstatus => 0
|
||||||
|
},
|
||||||
|
{ rows => 1, order_by => "eval.id desc"
|
||||||
|
, join => { jobsetevalmembers => 'eval' }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
notFound($c, "Channel $channelName either doesn't exist ".
|
||||||
|
"or was never built successfully.")
|
||||||
|
if !$lastSuccessful;
|
||||||
|
|
||||||
|
$c->stash->{lastSuccessful} = $lastSuccessful;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub overview : Chained('channel') PathPart('') Args(0) {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
|
||||||
|
$c->stash->{constituents} = [
|
||||||
|
$c->stash->{lastSuccessful}->constituents_->search(
|
||||||
|
{}, {order_by => ["job"]}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
$c->stash->{genericChannel} = 0;
|
||||||
|
$c->stash->{template} = 'channel-contents.tt';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub nixexprs : Chained('channel') PathPart('') Args(1) {
|
||||||
|
my ($self, $c, $productName) = @_;
|
||||||
|
|
||||||
|
my $product = $c->stash->{lastSuccessful}->buildproducts->find(
|
||||||
|
{ type => "channel", name => $productName }
|
||||||
|
);
|
||||||
|
|
||||||
|
my $url = $c->uri_for(
|
||||||
|
$c->controller("Build")->action_for("download"),
|
||||||
|
[$c->stash->{lastSuccessful}->id],
|
||||||
|
$product->productnr,
|
||||||
|
$productName
|
||||||
|
);
|
||||||
|
|
||||||
|
$c->res->redirect($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub binary_cache_url : Chained('channel') PathPart('binary-cache-url') Args(0) {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
$c->stash->{'plain'} = { data => $c->uri_for('/') };
|
||||||
|
$c->response->content_type('text/plain');
|
||||||
|
$c->forward('Hydra::View::Plain');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
1;
|
|
@ -108,43 +108,43 @@ sub jobs_tab : Chained('jobsetChain') PathPart('jobs-tab') Args(0) {
|
||||||
$c->stash->{filter} = $c->request->params->{filter} // "";
|
$c->stash->{filter} = $c->request->params->{filter} // "";
|
||||||
my $filter = "%" . $c->stash->{filter} . "%";
|
my $filter = "%" . $c->stash->{filter} . "%";
|
||||||
|
|
||||||
my @evals = $c->stash->{jobset}->jobsetevals->search({ hasnewbuilds => 1}, { order_by => "id desc", rows => 20 });
|
my ($evals, $builds) = searchBuildsAndEvalsForJobset(
|
||||||
|
$c->stash->{jobset},
|
||||||
my $evals = {};
|
{ job => { ilike => $filter }, ischannel => 0 },
|
||||||
my %jobs;
|
10000
|
||||||
my $nrBuilds = 0;
|
);
|
||||||
|
|
||||||
foreach my $eval (@evals) {
|
|
||||||
my @builds = $eval->builds->search(
|
|
||||||
{ job => { ilike => $filter } },
|
|
||||||
{ columns => ['id', 'job', 'finished', 'buildstatus'] });
|
|
||||||
foreach my $b (@builds) {
|
|
||||||
my $jobName = $b->get_column('job');
|
|
||||||
$evals->{$eval->id}->{timestamp} = $eval->timestamp;
|
|
||||||
$evals->{$eval->id}->{jobs}->{$jobName} =
|
|
||||||
{ id => $b->id, finished => $b->finished, buildstatus => $b->buildstatus };
|
|
||||||
$jobs{$jobName} = 1;
|
|
||||||
$nrBuilds++;
|
|
||||||
}
|
|
||||||
last if $nrBuilds >= 10000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($c->request->params->{showInactive}) {
|
if ($c->request->params->{showInactive}) {
|
||||||
$c->stash->{showInactive} = 1;
|
$c->stash->{showInactive} = 1;
|
||||||
foreach my $job ($c->stash->{jobset}->jobs->search({ name => { ilike => $filter } })) {
|
foreach my $job ($c->stash->{jobset}->jobs->search({ name => { ilike => $filter } })) {
|
||||||
next if defined $jobs{$job->name};
|
next if defined $builds->{$job->name};
|
||||||
$c->stash->{inactiveJobs}->{$job->name} = $jobs{$job->name} = 1;
|
$c->stash->{inactiveJobs}->{$job->name} = $builds->{$job->name} = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$c->stash->{evals} = $evals;
|
$c->stash->{evals} = $evals;
|
||||||
my @jobs = sort (keys %jobs);
|
my @jobs = sort (keys %$builds);
|
||||||
$c->stash->{nrJobs} = scalar @jobs;
|
$c->stash->{nrJobs} = scalar @jobs;
|
||||||
splice @jobs, 250 if $c->stash->{filter} eq "";
|
splice @jobs, 250 if $c->stash->{filter} eq "";
|
||||||
$c->stash->{jobs} = [@jobs];
|
$c->stash->{jobs} = [@jobs];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub channels_tab : Chained('jobsetChain') PathPart('channels-tab') Args(0) {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
$c->stash->{template} = 'jobset-channels-tab.tt';
|
||||||
|
|
||||||
|
my ($evals, $builds) = searchBuildsAndEvalsForJobset(
|
||||||
|
$c->stash->{jobset},
|
||||||
|
{ ischannel => 1 }
|
||||||
|
);
|
||||||
|
|
||||||
|
$c->stash->{evals} = $evals;
|
||||||
|
my @channels = sort (keys %$builds);
|
||||||
|
$c->stash->{channels} = [@channels];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Hydra::Base::Controller::ListBuilds needs this.
|
# Hydra::Base::Controller::ListBuilds needs this.
|
||||||
sub get_builds : Chained('jobsetChain') PathPart('') CaptureArgs(0) {
|
sub get_builds : Chained('jobsetChain') PathPart('') CaptureArgs(0) {
|
||||||
my ($self, $c) = @_;
|
my ($self, $c) = @_;
|
||||||
|
|
|
@ -453,6 +453,7 @@ sub checkBuild {
|
||||||
, busy => 0
|
, busy => 0
|
||||||
, locker => ""
|
, locker => ""
|
||||||
, iscurrent => 1
|
, iscurrent => 1
|
||||||
|
, ischannel => $buildInfo->{isChannel}
|
||||||
});
|
});
|
||||||
|
|
||||||
$build->buildoutputs->create({ name => $_, path => $buildInfo->{outputs}->{$_} })
|
$build->buildoutputs->create({ name => $_, path => $buildInfo->{outputs}->{$_} })
|
||||||
|
|
|
@ -10,6 +10,7 @@ use Hydra::Helper::Nix;
|
||||||
our @ISA = qw(Exporter);
|
our @ISA = qw(Exporter);
|
||||||
our @EXPORT = qw(
|
our @EXPORT = qw(
|
||||||
getBuild getPreviousBuild getNextBuild getPreviousSuccessfulBuild
|
getBuild getPreviousBuild getNextBuild getPreviousSuccessfulBuild
|
||||||
|
searchBuildsAndEvalsForJobset
|
||||||
error notFound gone accessDenied
|
error notFound gone accessDenied
|
||||||
forceLogin requireUser requireProjectOwner requireAdmin requirePost isAdmin isProjectOwner
|
forceLogin requireUser requireProjectOwner requireAdmin requirePost isAdmin isProjectOwner
|
||||||
trim
|
trim
|
||||||
|
@ -85,6 +86,44 @@ sub getPreviousSuccessfulBuild {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub searchBuildsAndEvalsForJobset {
|
||||||
|
my ($jobset, $condition, $maxBuilds) = @_;
|
||||||
|
|
||||||
|
my @evals = $jobset->jobsetevals->search(
|
||||||
|
{ hasnewbuilds => 1},
|
||||||
|
{ order_by => "id desc",
|
||||||
|
rows => 20
|
||||||
|
});
|
||||||
|
|
||||||
|
my $evals = {};
|
||||||
|
my %builds;
|
||||||
|
my $nrBuilds = 0;
|
||||||
|
|
||||||
|
foreach my $eval (@evals) {
|
||||||
|
my @allBuilds = $eval->builds->search(
|
||||||
|
$condition,
|
||||||
|
{ columns => ['id', 'job', 'finished', 'buildstatus'] }
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach my $b (@allBuilds) {
|
||||||
|
my $jobName = $b->get_column('job');
|
||||||
|
|
||||||
|
$evals->{$eval->id}->{timestamp} = $eval->timestamp;
|
||||||
|
$evals->{$eval->id}->{builds}->{$jobName} = {
|
||||||
|
id => $b->id,
|
||||||
|
finished => $b->finished,
|
||||||
|
buildstatus => $b->buildstatus
|
||||||
|
};
|
||||||
|
$builds{$jobName} = 1;
|
||||||
|
$nrBuilds++;
|
||||||
|
}
|
||||||
|
last if $maxBuilds && $nrBuilds >= $maxBuilds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($evals, \%builds);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sub error {
|
sub error {
|
||||||
my ($c, $msg, $status) = @_;
|
my ($c, $msg, $status) = @_;
|
||||||
$c->response->status($status) if defined $status;
|
$c->response->status($status) if defined $status;
|
||||||
|
|
|
@ -116,6 +116,12 @@ __PACKAGE__->table("Builds");
|
||||||
default_value: 36000
|
default_value: 36000
|
||||||
is_nullable: 1
|
is_nullable: 1
|
||||||
|
|
||||||
|
=head2 ischannel
|
||||||
|
|
||||||
|
data_type: 'integer'
|
||||||
|
default_value: 0
|
||||||
|
is_nullable: 1
|
||||||
|
|
||||||
=head2 iscurrent
|
=head2 iscurrent
|
||||||
|
|
||||||
data_type: 'integer'
|
data_type: 'integer'
|
||||||
|
@ -239,6 +245,8 @@ __PACKAGE__->add_columns(
|
||||||
{ data_type => "integer", default_value => 3600, is_nullable => 1 },
|
{ data_type => "integer", default_value => 3600, is_nullable => 1 },
|
||||||
"timeout",
|
"timeout",
|
||||||
{ data_type => "integer", default_value => 36000, is_nullable => 1 },
|
{ data_type => "integer", default_value => 36000, is_nullable => 1 },
|
||||||
|
"ischannel",
|
||||||
|
{ data_type => "integer", default_value => 0, is_nullable => 1 },
|
||||||
"iscurrent",
|
"iscurrent",
|
||||||
{ data_type => "integer", default_value => 0, is_nullable => 1 },
|
{ data_type => "integer", default_value => 0, is_nullable => 1 },
|
||||||
"nixexprinput",
|
"nixexprinput",
|
||||||
|
@ -558,8 +566,8 @@ __PACKAGE__->many_to_many(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.07043 @ 2015-08-10 15:10:41
|
# Created by DBIx::Class::Schema::Loader v0.07043 @ 2015-09-10 17:34:23
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:rjifgnPtjY96MaQ7eiGzaA
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:JRelp13Cyfi+QVxC92xuqQ
|
||||||
|
|
||||||
__PACKAGE__->has_many(
|
__PACKAGE__->has_many(
|
||||||
"dependents",
|
"dependents",
|
||||||
|
|
|
@ -190,7 +190,7 @@
|
||||||
<td>[% IF cachedBuild; INCLUDE renderFullBuildLink build=cachedBuild; ELSE %]<em>unknown</em>[% END %]</td>
|
<td>[% IF cachedBuild; INCLUDE renderFullBuildLink build=cachedBuild; ELSE %]<em>unknown</em>[% END %]</td>
|
||||||
</tr>
|
</tr>
|
||||||
[% END %]
|
[% END %]
|
||||||
[% IF !isAggregate && build.finished; actualBuild = build.iscachedbuild ? cachedBuild : build %]
|
[% IF (!isAggregate || !build.ischannel) && build.finished; actualBuild = build.iscachedbuild ? cachedBuild : build %]
|
||||||
[% IF actualBuild %]
|
[% IF actualBuild %]
|
||||||
<tr>
|
<tr>
|
||||||
<th>Duration:</th>
|
<th>Duration:</th>
|
||||||
|
@ -202,7 +202,7 @@
|
||||||
<td>[% INCLUDE renderDateTime timestamp = build.stoptime; %]</td>
|
<td>[% INCLUDE renderDateTime timestamp = build.stoptime; %]</td>
|
||||||
</tr>
|
</tr>
|
||||||
[% END %]
|
[% END %]
|
||||||
[% IF !isAggregate && buildLogExists(build) %]
|
[% IF (!isAggregate || !build.ischannel) && buildLogExists(build) %]
|
||||||
<tr>
|
<tr>
|
||||||
<th>Logfile:</th>
|
<th>Logfile:</th>
|
||||||
<td>
|
<td>
|
||||||
|
@ -217,7 +217,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
[% IF build.buildproducts && !isAggregate %]
|
[% IF build.ischannel || (build.buildproducts && !isAggregate) %]
|
||||||
|
|
||||||
<h3>Build products</h3>
|
<h3>Build products</h3>
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,13 @@ $ nix-env -i foo</pre>
|
||||||
$ nix-channel --update
|
$ nix-channel --update
|
||||||
$ nix-env -u '*'</pre>
|
$ nix-env -u '*'</pre>
|
||||||
|
|
||||||
|
[% IF genericChannel %]
|
||||||
|
|
||||||
<p>Alternatively, if you have associated the
|
<p>Alternatively, if you have associated the
|
||||||
<tt>application/nix-package</tt> MIME type with the
|
<tt>application/nix-package</tt> MIME type with the
|
||||||
<tt>nix-install-package</tt> program in your web browser, you can
|
<tt>nix-install-package</tt> program in your web browser, you can
|
||||||
install the package simply by clicking on the packages below.</p>
|
install the package simply by clicking on the packages below.</p>
|
||||||
|
|
||||||
|
|
||||||
<h2>Packages</h2>
|
<h2>Packages</h2>
|
||||||
|
|
||||||
<p>This channel contains the following packages.</p>
|
<p>This channel contains the following packages.</p>
|
||||||
|
@ -69,5 +70,17 @@ install the package simply by clicking on the packages below.</p>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
[% ELSE %]
|
||||||
|
[% PROCESS "product-list.tt" %]
|
||||||
|
|
||||||
|
<h2>Contents</h2>
|
||||||
|
|
||||||
|
[% INCLUDE renderProductList build=lastSuccessful %]
|
||||||
|
|
||||||
|
<p>Upgrades depend on the success/failure of the following constituents:</p>
|
||||||
|
|
||||||
|
[% INCLUDE renderBuildList builds=constituents %]
|
||||||
|
|
||||||
|
[% END %]
|
||||||
|
|
||||||
[% END %]
|
[% END %]
|
||||||
|
|
34
src/root/jobset-channels-tab.tt
Normal file
34
src/root/jobset-channels-tab.tt
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[% PROCESS common.tt %]
|
||||||
|
|
||||||
|
[% IF channels.size == 0 %]
|
||||||
|
|
||||||
|
<div class="alert">There are no channels available.</div>
|
||||||
|
|
||||||
|
[% ELSE %]
|
||||||
|
|
||||||
|
[% evalIds = evals.keys.nsort.reverse %]
|
||||||
|
<table class="table table-striped table-condensed table-header-rotated">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 1em;">Channel</th>
|
||||||
|
[% FOREACH eval IN evalIds %]
|
||||||
|
<th class="rotate-45">
|
||||||
|
<div><span>
|
||||||
|
<a href="[% c.uri_for('/eval' eval) %]">[% INCLUDE renderRelativeDate timestamp=evals.$eval.timestamp %]</a>
|
||||||
|
</span></div></th>
|
||||||
|
[% END %]
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
[% FOREACH chan IN channels-%]
|
||||||
|
<tr>
|
||||||
|
<th><span><a href="[% c.uri_for('/channel/custom' project.name jobset.name chan) %]">[% chan %]</a></span></th>
|
||||||
|
[% FOREACH eval IN evalIds %]
|
||||||
|
<td>[% r = evals.$eval.builds.$chan; IF r.id %]<a href="[% c.uri_for('/build' r.id) %]">[% INCLUDE renderBuildStatusIcon size=16 build=r %]</a>[% END %]</td>
|
||||||
|
[% END %]
|
||||||
|
</tr>
|
||||||
|
[% END %]
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
[% END %]
|
|
@ -59,7 +59,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th><span [% IF inactiveJobs.$j %]class="muted override-link"[% END %]>[% INCLUDE renderJobName project=project.name jobset=jobset.name job=j %]</span></th>
|
<th><span [% IF inactiveJobs.$j %]class="muted override-link"[% END %]>[% INCLUDE renderJobName project=project.name jobset=jobset.name job=j %]</span></th>
|
||||||
[% FOREACH eval IN evalIds %]
|
[% FOREACH eval IN evalIds %]
|
||||||
<td>[% r = evals.$eval.jobs.$j; IF r.id %]<a href="[% c.uri_for('/build' r.id) %]">[% INCLUDE renderBuildStatusIcon size=16 build=r %]</a>[% END %]</td>
|
<td>[% r = evals.$eval.builds.$j; IF r.id %]<a href="[% c.uri_for('/build' r.id) %]">[% INCLUDE renderBuildStatusIcon size=16 build=r %]</a>[% END %]</td>
|
||||||
[% END %]
|
[% END %]
|
||||||
</tr>
|
</tr>
|
||||||
[% END %]
|
[% END %]
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
<li><a href="#tabs-jobs" data-toggle="tab">Jobs</a></li>
|
<li><a href="#tabs-jobs" data-toggle="tab">Jobs</a></li>
|
||||||
<li><a href="#tabs-configuration" data-toggle="tab">Configuration</a></li>
|
<li><a href="#tabs-configuration" data-toggle="tab">Configuration</a></li>
|
||||||
<li><a href="#tabs-links" data-toggle="tab">Links</a></li>
|
<li><a href="#tabs-links" data-toggle="tab">Links</a></li>
|
||||||
|
<li><a href="#tabs-channels" data-toggle="tab">Channels</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div id="generic-tabs" class="tab-content">
|
<div id="generic-tabs" class="tab-content">
|
||||||
|
@ -165,6 +166,8 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
[% INCLUDE makeLazyTab tabName="tabs-channels" uri=c.uri_for('/jobset' project.name jobset.name "channels-tab") %]
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -115,10 +115,9 @@
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
[% END %]
|
[% END %]
|
||||||
|
|
||||||
[% CASE "file" %]
|
[% CASE ["file", "channel"] %]
|
||||||
|
|
||||||
<tr class="product">
|
<tr class="product">
|
||||||
<td>
|
<td>
|
||||||
|
@ -137,8 +136,14 @@
|
||||||
[% CASE "binary-dist" %]
|
[% CASE "binary-dist" %]
|
||||||
<img src="[% c.uri_for("/static/images/binary-dist.png") %]" alt="Binary distribution" /> Binary distribution <tt>[% product.name %]</tt>
|
<img src="[% c.uri_for("/static/images/binary-dist.png") %]" alt="Binary distribution" /> Binary distribution <tt>[% product.name %]</tt>
|
||||||
[% CASE DEFAULT %]
|
[% CASE DEFAULT %]
|
||||||
|
[% IF product.type == "channel" %]
|
||||||
|
<img src="[% c.uri_for("/static/images/channel.png") %]" alt="Channel" />
|
||||||
|
Channel expression tarball <tt>[% product.name %]</tt>
|
||||||
|
[% IF product.subtype != "-" %]for <tt>[% product.subtype %]</tt>[% END %]
|
||||||
|
[% ELSE %]
|
||||||
File <tt>[% product.name %]</tt> of type <tt>[% product.subtype %]</tt>
|
File <tt>[% product.name %]</tt> of type <tt>[% product.subtype %]</tt>
|
||||||
[% END %]
|
[% END %]
|
||||||
|
[% END %]
|
||||||
</a>
|
</a>
|
||||||
[% WRAPPER makePopover title="Details" classes="btn-mini" %]
|
[% WRAPPER makePopover title="Details" classes="btn-mini" %]
|
||||||
<table class="info-table">
|
<table class="info-table">
|
||||||
|
|
BIN
src/root/static/images/channel.png
Normal file
BIN
src/root/static/images/channel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
|
@ -157,6 +157,7 @@ create table Builds (
|
||||||
maxsilent integer default 3600, -- meta.maxsilent
|
maxsilent integer default 3600, -- meta.maxsilent
|
||||||
timeout integer default 36000, -- meta.timeout
|
timeout integer default 36000, -- meta.timeout
|
||||||
|
|
||||||
|
isChannel integer not null default 0, -- meta.isHydraChannel
|
||||||
isCurrent integer default 0,
|
isCurrent integer default 0,
|
||||||
|
|
||||||
-- Copy of the nixExprInput/nixExprPath fields of the jobset that
|
-- Copy of the nixExprInput/nixExprPath fields of the jobset that
|
||||||
|
|
1
src/sql/upgrade-42.sql
Normal file
1
src/sql/upgrade-42.sql
Normal file
|
@ -0,0 +1 @@
|
||||||
|
alter table Builds add column isChannel integer not null default 0;
|
Loading…
Reference in a new issue