* Showing releases.

[?]
Nov 27, 2008, 6:27 PM
JFZNAYJXKCMXYHGCLTRH7Q6TOFGJ4BT6332GONCWVYRLNMDDG3KAC

Dependencies

  • [2] MR2C7EWC
  • [3] LQ5QEDVV
  • [4] QVSQ4KXF
  • [5] B72GLND4
  • [6] L5VIEXSC * Allow downloading of build products.
  • [7] IK53RV4V
  • [8] 2AIIYGI5 * Show job status and all builds for a project.
  • [9] SZZ3PFYF
  • [10] KOTB7BKV
  • [11] HK32XC42
  • [12] 2AUODJBT
  • [13] H7CNGK4O * Log evaluation errors etc. in the DB.
  • [14] JLDUSNUO * Unify rendering of finished and scheduled builds.
  • [15] PHX2HIVG * Store info about the build inputs in the build record.
  • [16] FHF6IZJQ * Basic release management: releases are now dynamically computed as
  • [17] W6DC6K4I * Happy Javascript hacking.
  • [18] J5UVLXOK * Start of a basic Catalyst web interface.
  • [19] CLJQCY2X * Store info about all the build actions and allow them to be
  • [20] IE3SRMWZ * Show global and per-project statistics.
  • [21] BD3GRK4B * Get rid of "positive failures" and separate log phases.
  • [22] 2GK5DOU7 * Downloading closures.
  • [23] HJLYC753 * Adding input value alternatives.
  • [24] DVNWJXWW * Generic declaration of build products.
  • [25] WHAFVCEI
  • [26] MOCEUXZA * Support serving products that are directories (such as manuals or
  • [*] HCKFTNQ6
  • [*] US27ZTX5 * HydraFrontend -> Hydra.
  • [*] TQKGQ5R3

Change contents

  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 202
    [4.419][4.419:420]()
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 203
    [4.421][4.421:539]()
    sub releases :Local {
    my ($self, $c, $projectName, $releaseName) = @_;
    $c->stash->{template} = 'releases.tt';
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 204
    [4.540]
    [4.540]
    sub getReleaseSet {
    my ($c, $projectName, $releaseName) = @_;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 208
    [4.605][4.605:687]()
    return error($c, "Project $projectName doesn't exist.") if !defined $project;
    [4.605]
    [4.687]
    die "Project $projectName doesn't exist." if !defined $project;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 212
    [4.815][4.815:904]()
    return error($c, "Release set $releaseName doesn't exist.") if !defined $releaseSet;
    [4.815]
    [4.904]
    die "Release set $releaseName doesn't exist." if !defined $releaseSet;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 216
    [4.1026][4.1026:1128]()
    return error($c, "Release set $releaseName doesn't have a primary job.") if !defined $primaryJob;
    [4.1026]
    [4.1128]
    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;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 235
    [4.1129][4.1129:1228]()
    $c->stash->{jobs} = [$releaseSet->releasesetjobs->search({}, {order_by => "isprimary DESC"})];
    [4.1129]
    [3.653]
    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);
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 283
    [4.1496]
    [4.1496]
    push @releases, getRelease($c, $_) foreach @primaryBuilds;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 285
    [4.1497][4.1497:1568]()
    foreach my $primaryBuild (@primaryBuilds) {
    my @jobs = ();
    [4.1497]
    [4.1568]
    $c->stash->{releases} = [@releases];
    }
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 288
    [4.1569][4.1569:2208](),[4.2208][3.866:1022](),[3.1022][4.2275:2289](),[4.2275][4.2275:2289]()
    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")
    });
    }
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 289
    [4.2290][4.2290:2876]()
    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
    };
    }
    [4.2290]
    [4.2876]
    sub release :Local {
    my ($self, $c, $projectName, $releaseName, $releaseId) = @_;
    $c->stash->{template} = 'release.tt';
    my ($project, $releaseSet, $primaryJob) = getReleaseSet($c, $projectName, $releaseName);
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 295
    [4.2877][4.2877:2918]()
    $c->stash->{releases} = [@releases];
    [4.2877]
    [4.821]
    # 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);
  • edit in src/Hydra/root/build.tt at line 3
    [4.2304]
    [4.1425]
    [% PROCESS "product-list.tt" %]
  • edit in src/Hydra/root/build.tt at line 234
    [4.1138][4.1138:1139]()
  • replacement in src/Hydra/root/build.tt at line 237
    [4.8008][4.1421:1446]()
    <ul class="productList">
    [4.8008]
    [4.8013]
    [% PROCESS renderProductList %]
  • edit in src/Hydra/root/build.tt at line 239
    [4.8014][4.8014:8062](),[4.8062][4.0:23](),[4.23][4.8069:8099](),[4.8069][4.8069:8099](),[4.8099][4.809:814](),[4.814][4.8099:8126](),[4.8099][4.8099:8126](),[4.8126][4.2374:2575](),[4.2575][4.1441:2308](),[4.2308][4.815:822](),[4.2575][4.815:822](),[4.8178][4.815:822](),[4.822][4.1447:1469](),[4.8178][4.1447:1469](),[4.1469][4.511:808](),[4.808][4.2576:2673](),[4.2673][4.0:128](),[4.128][4.912:1050](),[4.2673][4.912:1050](),[4.912][4.912:1050](),[4.1050][4.24:130](),[4.130][4.2840:3533](),[4.2840][4.2840:3533](),[4.3533][4.823:941](),[4.941][4.2674:2735](),[4.2735][4.941:1165](),[4.941][4.941:1165](),[4.1165][4.2364:2472](),[4.2472][4.2736:2801](),[4.2801][4.2472:2565](),[4.2472][4.2472:2565](),[4.2565][2.0:45](),[2.45][4.2565:2689](),[4.2565][4.2565:2689](),[4.1165][4.1895:1970](),[4.2689][4.1895:1970](),[4.3533][4.1895:1970](),[4.1895][4.1895:1970](),[4.1970][4.1166:1173](),[4.1173][4.8178:8222](),[4.1970][4.8178:8222](),[4.8178][4.8178:8222](),[4.8222][4.1140:1141](),[4.1141][4.131:399]()
    [% 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>
  • edit in src/Hydra/root/common.tt at line 96
    [4.2201]
    [4.1508]
    [% END %]
  • replacement in src/Hydra/root/common.tt at line 100
    [4.1509][4.5301:5310](),[4.2201][4.5301:5310](),[4.5301][4.5301:5310]()
    [% END %]
    [4.1509]
    [% BLOCK renderReleaseJobName -%]
    [% IF job.description; HTML.escape(job.description); ELSE %]<tt>[% job.job %]</tt> ([% job.attrs %])[% END -%]
    [% END -%]
  • edit in src/Hydra/root/layout.tt at line 104
    [28.1868]
    [4.8138]
    [% INCLUDE makeLink uri = c.uri_for('/releasesets' project.name) title = "Releases" %]
  • file addition: product-list.tt (----------)
    [29.857]
    [% 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>
  • file addition: release.tt (----------)
    [29.857]
    [% 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 %]
  • replacement in src/Hydra/root/releases.tt at line 14
    [4.8730][4.8730:8857]()
    <th>[% IF job.description; HTML.escape(job.description); ELSE %]<tt>[% job.job %]</tt> ([% job.attrs %])[% END %]</th>
    [4.8730]
    [4.8857]
    <th class="releaseSetJobName">[% PROCESS renderReleaseJobName %]</th>
  • replacement in src/Hydra/root/releases.tt at line 20
    [4.8907][4.8907:8957]()
    [% FOREACH release IN releases %]
    <tr>
    [4.8907]
    [4.8957]
    [% FOREACH release IN releases %]
    [% link = c.uri_for('/release' releaseSet.project.name releaseSet.name release.id) %]
    <tr class="clickable" onclick="window.location = '[% link %]'">
  • replacement in src/Hydra/root/releases.tt at line 32
    [4.9292][4.9292:9326]()
    <td>[% release.id %]</td>
    [4.9292]
    [4.9326]
    <td><a href="[% link %]">[% release.id %]</a></td>
  • replacement in src/Hydra/root/releases.tt at line 41
    [4.9551][4.9551:9566]()
    <td>
    [4.9551]
    [4.9566]
    <td class="centered">
  • edit in src/Hydra/root/releases.tt at line 49
    [4.9895][4.9895:9930]()
    [% job.build.id %]
  • edit in src/Hydra/root/static/css/hydra.css at line 53
    [4.2599]
    [4.9134]
    }
    td.centered {
    text-align: center;
  • edit in src/Hydra/root/static/css/hydra.css at line 59
    [4.9137]
    [4.9137]
    .layoutTable th {
    vertical-align: top;
    }
  • replacement in src/Hydra/root/static/css/hydra.css at line 64
    [4.9142][4.5627:5652]()
    vertical-align: top;
    [4.9142]
    [4.9142]
    vertical-align: center;
  • edit in src/Hydra/root/static/css/hydra.css at line 124
    [4.9915][4.9915:10265]()
    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 {
  • edit in src/Hydra/root/static/css/hydra.css at line 137
    [4.10419][4.10419:10573]()
    }
    table.buildfarmResults td, table.buildfarmResults th {
    border: none;
    }
    td.buildfarmMainColumn {
    background-color: #E0E0E0;
    border: solid;
  • edit in src/Hydra/root/static/css/hydra.css at line 191
    [4.431][4.432:444](),[4.444][4.446:465](),[4.446][4.446:465](),[4.465][4.1948:1951](),[4.3711][4.1948:1951]()
    .template {
    display: none;
    }
  • edit in src/Hydra/root/static/css/hydra.css at line 250
    [30.1978]
    [30.1978]
    /* Overriding tablesorter... */
    th.releaseSetJobName {
    font-size: 60%;
    padding: 0 0 0 0;
    }