JFZNAYJXKCMXYHGCLTRH7Q6TOFGJ4BT6332GONCWVYRLNMDDG3KAC
MR2C7EWCEDODE6FYBHOGTUFYXCJCEIG33R6LG5QAHYBCVLFVFIUQC
LQ5QEDVVHVGX67NJZQ46HOSY336VCLN63L3DT6QNSDV6ARVARITAC
FHF6IZJQPUQHY5QWQYRPZVDBRLHREWRHGNKVQDT7F3GQKKLZXJKQC
J5UVLXOK6EDIL5I7VKWH4V2QDS4DPD7FHRK6XBWSXFRQS4JKXFZQC
2AIIYGI54TEFYBCGWMUA7JG2DMJXBKMYUZ7CG6ETIXF4ENNP74CQC
IK53RV4VGOHLCZGQCCIKPB45M3C7M7YMNBOJFBGZJ4LWIZNU4QNQC
2GK5DOU7ODF4WBSN3QTD3WIO52VTL2LOAXKGCDEMMAQPTEO4A4HAC
WHAFVCEIHCWHKY2UVRGRQORERUAK6SZJI7ZENA367ZX4EXDIQMDQC
DVNWJXWWZAR4LGE3FGGY64EW5U6GWH6MXXAALWPO3EMI4NO42ZXAC
HJLYC7537T37E5AQ4Y4PYDBRLVIZVWYS4R7WPSLGO6SJPS6M6LMAC
MOCEUXZAS4CNZL2QDKGVTZCRZ6AMOO2WSFHJ4VPZPPPAXHANG4NAC
L5VIEXSC5R72SEDSWF7HWNXMSTAAADBUMCSREU5ITMRXLEJ6KZWQC
QVSQ4KXFP3YNGZHH3OZRYGKXLDBNI52MRTG5H5PA7TOA5GFZXLXQC
B72GLND4UQKSGNGIY4FA6HLQNFS42SKRXV5NHTHADUJRU73NELAAC
KOTB7BKVML6T6S5ZNTQ6456FMGCRZCP3E3KVWCOW7T6SPRHC53LAC
JLDUSNUOOQNL63BOPXIWZOWFRQ5X35RWG33PJB3J3KMR6QR7TN7QC
IE3SRMWZ4YT6EYKAOG2HH54MXG5TYYBW7OEBHNYJUGW7KILFXX2AC
H7CNGK4OJNRYZQGPLBGR72DULLEPFQ5UISF5J24D7IMA7SYW5LGQC
HCKFTNQ6J62JYGWKRSO2523L67JXRKG64NFHUMTHDO2JXIDVUIHQC
US27ZTX5HCH53SQN2KFSCV2GL2625XL5J3WCDR7D5HLPA7ZSPX5AC
2AUODJBTW2UJ47UB3SREZ7O7UTTJDQ4AGUQMPZAI4F3Y6BUF6LUQC
HK32XC42XOS7JKJMFT3XJKPXVSI44SFGKUUSJIL5VGPIHYNNWXLAC
W6DC6K4INJQOJYR553ISCKZV7YIOGHEM3FZQPOLAPSZQ3KSJDMRQC
TQKGQ5R36VOLLJ3SR2WWIQ6VSN245N3QG4JHI2ZCP5T6RXN3PJWAC
return error($c, "Release set $releaseName doesn't have a primary job.") if !defined $primaryJob;
die "Release set $releaseName doesn't have a primary job." if !defined $primaryJob;
$c->stash->{jobs} = [$releaseSet->releasesetjobs->search({},
{order_by => ["isprimary DESC", "job", "attrs"]})];
return ($project, $releaseSet, $primaryJob);
}
sub getRelease {
my ($c, $primaryBuild) = @_;
my @jobs = ();
my $status = 0; # = okay
foreach my $job (@{$c->stash->{jobs}}) {
my $thisBuild;
$c->stash->{jobs} = [$releaseSet->releasesetjobs->search({}, {order_by => "isprimary DESC"})];
if ($job->isprimary == 1) {
$thisBuild = $primaryBuild;
} else {
# Find a build of this job that had the primary build
# as input. If there are multiple, prefer successful
# ones, and then oldest. !!! order_by buildstatus is hacky
($thisBuild) = $primaryBuild->dependentBuilds->search(
{ attrname => $job->job, finished => 1 },
{ join => 'resultInfo', rows => 1
, order_by => ["buildstatus", "timestamp"]
, where => \ attrsToSQL($job->attrs, "build.id")
});
}
if ($job->mayfail != 1) {
if (!defined $thisBuild) {
$status = 2 if $status == 0; # = unfinished
} elsif ($thisBuild->resultInfo->buildstatus != 0) {
$status = 1; # = failed
}
}
push @jobs, { build => $thisBuild, job => $job };
}
return
{ id => $primaryBuild->id
, releasename => $primaryBuild->get_column('releasename')
, jobs => [@jobs]
, status => $status
};
}
sub releases :Local {
my ($self, $c, $projectName, $releaseName) = @_;
$c->stash->{template} = 'releases.tt';
my ($project, $releaseSet, $primaryJob) = getReleaseSet($c, $projectName, $releaseName);
my $status = 0; # = okay
foreach my $job (@{$c->stash->{jobs}}) {
my $thisBuild;
if ($job->isprimary == 1) {
$thisBuild = $primaryBuild;
} else {
# Find a build of this job that had the primary build
# as input. If there are multiple, prefer successful
# ones, and then oldest. !!! order_by buildstatus is hacky
($thisBuild) = $primaryBuild->dependentBuilds->search(
{ attrname => $job->job, finished => 1 },
{ join => 'resultInfo', rows => 1
, order_by => ["buildstatus", "timestamp"]
, where => \ attrsToSQL($job->attrs, "build.id")
});
}
if ($job->mayfail != 1) {
if (!defined $thisBuild) {
$status = 2 if $status == 0; # = unfinished
} elsif ($thisBuild->resultInfo->buildstatus != 0) {
$status = 1; # = failed
}
}
push @jobs, { build => $thisBuild };
}
push @releases,
{ id => $primaryBuild->id
, releasename => $primaryBuild->get_column('releasename')
, jobs => [@jobs]
, status => $status
};
}
sub release :Local {
my ($self, $c, $projectName, $releaseName, $releaseId) = @_;
$c->stash->{template} = 'release.tt';
my ($project, $releaseSet, $primaryJob) = getReleaseSet($c, $projectName, $releaseName);
$c->stash->{releases} = [@releases];
# Note: we don't actually check whether $releaseId is a primary
# build, but who cares?
my $primaryBuild = $project->builds->find($releaseId,
{ join => 'resultInfo', '+select' => ["resultInfo.releasename"], '+as' => ["releasename"] });
return error($c, "Release $releaseId doesn't exist.") if !defined $primaryBuild;
$c->stash->{release} = getRelease($c, $primaryBuild);
[% FOREACH product IN build.buildproducts -%]
<li class="product">
[% SWITCH product.type %]
[% CASE "nix-build" %]
<a href="[% c.uri_for('/closure' build.id product.productnr) %]">
<img src="/static/images/nix-build.png" alt="Source" />
Nix build of path <tt>[% product.path %]</tt>
</a>
[<a class="productDetailsToggle" href="javascript:">help</a>]
<div class="help productDetails">
<p>If you have Nix installed on your machine, this build and all
its dependencies can be unpacked into your local Nix store by
doing:</p>
<pre>$ gunzip < [% HTML.escape(build.nixname) %].closure.gz | nix-store --import</pre>
or to download and unpack in one command:
<pre>$ curl [% c.uri_for('/closure' build.id product.productnr) %] | gunzip | nix-store --import</pre>
<p>The package can then be found in the path <tt>[%
product.path %]</tt>. If you get the error message “imported
archive lacks a signature”, you should make sure that you have
sufficient access rights to the Nix store, e.g., run the
command as <tt>root</tt>.</p>
</div>
[% CASE "file" %]
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
[% SWITCH product.subtype %]
[% CASE "source-dist" %]
<img src="/static/images/source-dist.png" alt="Source" /> Source distribution <tt>[% product.name %]</tt>
[% CASE "rpm" %]
<img src="/static/images/rpm.png" alt="RPM" /> RPM package <tt>[% product.name %]</tt>
[% CASE "deb" %]
<img src="/static/images/debian.png" alt="RPM" /> Debian package <tt>[% product.name %]</tt>
[% CASE DEFAULT %]
File <tt>[% product.name %]</tt> of type <tt>[% product.subtype %]</tt>
[% END %]
</a>
[<a class="productDetailsToggle" href="javascript:">details</a>]
<div class="productDetails">
<table>
<tr>
<th>URL:</th>
<td>
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
<tt>[% c.uri_for('/download' build.id product.productnr product.name) %]</tt>
</a>
</td>
</tr>
<tr><th>File size:</th><td>[% product.filesize %] bytes ([% mibs(product.filesize / (1024 * 1024)) %] MiB)</td></tr>
<tr><th>SHA-1 hash:</th><td>[% product.sha1hash %]</td></tr>
<tr><th>SHA-256 hash:</th><td>[% product.sha256hash %]</td></tr>
<tr><th>Full path:</th><td><tt>[% product.path %]</tt></td></tr>
</table>
</div>
[% CASE "report" %]
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
<img src="/static/images/report.png" alt="Report" />
[% SWITCH product.subtype %]
[% CASE "coverage" %]
Code coverage analysis report
[% CASE DEFAULT %]
Report of type <tt>[% product.subtype %]</tt>
[% END %]
</a>
[% CASE "doc" %]
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
<img src="/static/images/document.png" alt="Document" />
[% SWITCH product.subtype %]
[% CASE "readme" %]
“README” file
[% CASE "manual" %]
Manual
[% CASE DEFAULT %]
Documentation of type <tt>[% product.subtype %]</tt>
[% END %]
</a>
[% CASE DEFAULT %]
Something of type <tt>[% product.type %]</tt>
[% END %]
</li>
[% END -%]
</ul>
<script>
$(document).ready(function() {
$('.productDetailsToggle').toggle(
function () { $(".productDetails", $(this).parents(".product")).fadeIn(); },
function () { $(".productDetails", $(this).parents(".product")).hide(); }
);
});
</script>
[% BLOCK renderProductList -%]
<ul class="productList">
[% FOREACH product IN build.buildproducts -%]
<li class="product">
[% SWITCH product.type %]
[% CASE "nix-build" %]
<a href="[% c.uri_for('/closure' build.id product.productnr) %]">
<img src="/static/images/nix-build.png" alt="Source" />
Nix build of path <tt>[% product.path %]</tt>
</a>
[<a class="productDetailsToggle" href="javascript:">help</a>]
<div class="help productDetails">
<p>If you have Nix installed on your machine, this build and all
its dependencies can be unpacked into your local Nix store by
doing:</p>
<pre>$ gunzip < [% HTML.escape(build.nixname) %].closure.gz | nix-store --import</pre>
or to download and unpack in one command:
<pre>$ curl [% c.uri_for('/closure' build.id product.productnr) %] | gunzip | nix-store --import</pre>
<p>The package can then be found in the path <tt>[%
product.path %]</tt>. If you get the error message “imported
archive lacks a signature”, you should make sure that you have
sufficient access rights to the Nix store, e.g., run the
command as <tt>root</tt>.</p>
</div>
[% CASE "file" %]
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
[% SWITCH product.subtype %]
[% CASE "source-dist" %]
<img src="/static/images/source-dist.png" alt="Source" /> Source distribution <tt>[% product.name %]</tt>
[% CASE "rpm" %]
<img src="/static/images/rpm.png" alt="RPM" /> RPM package <tt>[% product.name %]</tt>
[% CASE "deb" %]
<img src="/static/images/debian.png" alt="RPM" /> Debian package <tt>[% product.name %]</tt>
[% CASE DEFAULT %]
File <tt>[% product.name %]</tt> of type <tt>[% product.subtype %]</tt>
[% END %]
</a>
[<a class="productDetailsToggle" href="javascript:">details</a>]
<div class="productDetails">
<table>
<tr>
<th>URL:</th>
<td>
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
<tt>[% c.uri_for('/download' build.id product.productnr product.name) %]</tt>
</a>
</td>
</tr>
<tr><th>File size:</th><td>[% product.filesize %] bytes ([% mibs(product.filesize / (1024 * 1024)) %] MiB)</td></tr>
<tr><th>SHA-1 hash:</th><td>[% product.sha1hash %]</td></tr>
<tr><th>SHA-256 hash:</th><td>[% product.sha256hash %]</td></tr>
<tr><th>Full path:</th><td><tt>[% product.path %]</tt></td></tr>
</table>
</div>
[% CASE "report" %]
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
<img src="/static/images/report.png" alt="Report" />
[% SWITCH product.subtype %]
[% CASE "coverage" %]
Code coverage analysis report
[% CASE DEFAULT %]
Report of type <tt>[% product.subtype %]</tt>
[% END %]
</a>
[% CASE "doc" %]
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
<img src="/static/images/document.png" alt="Document" />
[% SWITCH product.subtype %]
[% CASE "readme" %]
“README” file
[% CASE "manual" %]
Manual
[% CASE DEFAULT %]
Documentation of type <tt>[% product.subtype %]</tt>
[% END %]
</a>
[% CASE DEFAULT %]
Something of type <tt>[% product.type %]</tt>
[% END %]
</li>
[% END -%]
</ul>
[% END %]
<script>
$(document).ready(function() {
$('.productDetailsToggle').toggle(
function () { $(".productDetails", $(this).parents(".product")).fadeIn(); },
function () { $(".productDetails", $(this).parents(".product")).hide(); }
);
});
</script>
[% releaseName = (release.releasename || "(No name)") -%]
[% WRAPPER layout.tt title="Release $releaseName" %]
[% PROCESS common.tt %]
[% PROCESS "product-list.tt" %]
[% USE HTML %]
<h1>Release <tt>[% releaseName %]</tt></h1>
[% IF release.status == 1 %]
<p class="error">This is a failed release. One of its jobs has failed. See below for details.</p>
[% ELSIF release.status == 2 %]
<p class="error">This is an incomplete release. One of its jobs has not been built (yet). See below for details.</p>
[% END %]
[% FOREACH job IN release.jobs %]
<h2>
[% IF job.build %]<a href="[% c.uri_for('/build' job.build.id) %]">[% END %]
[% INCLUDE renderReleaseJobName job=job.job %]
[% IF job.build %]</a>[% END %]
</h2>
[% IF job.build %]
[% IF job.build.resultInfo.buildstatus == 0 %]
[% INCLUDE renderProductList build=job.build %]
[% ELSE %]
<p class="error">Build failed</p>
[% END %]
[% ELSE %]
<p class="error">Build not (yet) performed.</p>
[% END %]
[% END %]
[% END %]
font-style: italic;
}
table.derivationList {
margin-left: 2em;
margin-right: 2em;
}
table.derivationList, table.derivationList td, table.derivationList th {
border: 1px solid #808080;
}
table.derivationList tr.odd {
background: #f0f0f0;
}
table.derivationList td {
vertical-align: top;
}
table.derivationList td.system {