* Automatically keep all builds in the latest successful release in

[?]
Feb 6, 2009, 3:02 PM
IN272KZWHENW2TCR3LWQ6OZAEESJL5S7AEL3GYLJTWHJUDE6HADAC

Dependencies

  • [2] DR4F6YUT
  • [3] OIUIYIV2 * Give releases a timestamp.
  • [4] ZNFDFJHG * Provide a redirect to the latest successful release in a release set
  • [5] 4X6NS66Q * Keep the most recent builds for each job.
  • [6] JFZNAYJX * Showing releases.
  • [7] TMP2FRIW
  • [8] G6HJY2V4
  • [9] AFTXA575 * $HYDRA_DATA environment variable.
  • [10] HKWIDRO6 * I love untyped databases...
  • [11] 2AIIYGI5 * Show job status and all builds for a project.
  • [12] FHF6IZJQ * Basic release management: releases are now dynamically computed as
  • [13] LQ5QEDVV
  • [14] WZ3AEJ67 * hydra_update_gc_roots.pl registers build outputs that should be kept
  • [15] 2GK5DOU7 * Downloading closures.
  • [*] J5UVLXOK * Start of a basic Catalyst web interface.

Change contents

  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 181
    [6.2][6.2:3]()
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 182
    [6.4][6.4:83]()
    sub attrsToSQL {
    my ($attrs, $id) = @_;
    my @attrs = split / /, $attrs;
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 183
    [6.84][6.84:652](),[6.652][6.417:419](),[6.417][6.417:419](),[6.420][6.420:421](),[6.539][6.539:540]()
    my $query = "1 = 1";
    foreach my $attr (@attrs) {
    $attr =~ /^([\w-]+)=([\w-]*)$/ or die "invalid attribute in release set: $attr";
    my $name = $1;
    my $value = $2;
    # !!! Yes, this is horribly injection-prone... (though
    # name/value are filtered above). Should use SQL::Abstract,
    # but it can't deal with subqueries. At least we should use
    # placeholders.
    $query .= " and (select count(*) from buildinputs where build = $id and name = '$name' and value = '$value') = 1";
    }
    return $query;
    }
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 197
    [6.306][6.306:371]()
    $c->stash->{jobs} = [$releaseSet->releasesetjobs->search({},
    [6.306]
    [6.371]
    my $jobs = [$releaseSet->releasesetjobs->search({},
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 199
    [6.431][6.431:484]()
    return ($project, $releaseSet, $primaryJob);
    }
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 200
    [6.485][6.485:589]()
    sub getRelease {
    my ($c, $primaryBuild) = @_;
    my @jobs = ();
    my $status = 0; # = okay
    [6.485]
    [3.0]
    $c->stash->{jobs} = $jobs;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 202
    [3.1][3.1:118](),[3.118][6.589:666](),[6.589][6.589:666](),[6.666][6.1128:1129](),[6.1128][6.1128:1129](),[6.1129][2.0:31](),[2.31][6.703:1556](),[6.703][6.703:1556](),[6.1556][3.119:236](),[3.236][6.1556:1787](),[6.1556][6.1556:1787](),[6.1787][3.237:271](),[3.271][6.1787:1798](),[6.1787][6.1787:1798]()
    # The timestamp of the release is the highest timestamp of all
    # constitutent builds.
    my $timestamp = 0;
    foreach my $job (@{$c->stash->{jobs}}) {
    my $thisBuild;
    if ($job->isprimary) {
    $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
    }
    }
    $timestamp = $thisBuild->timestamp
    if defined $thisBuild && $thisBuild->timestamp > $timestamp;
    push @jobs, { build => $thisBuild, job => $job };
    }
    return
    { id => $primaryBuild->id
    , releasename => $primaryBuild->get_column('releasename')
    , jobs => [@jobs]
    , status => $status
    , timestamp => $timestamp
    };
    [3.1]
    [6.1798]
    return ($project, $releaseSet, $primaryJob, $jobs);
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 240
    [4.4][4.4:421](),[4.421][6.668:676](),[6.847][6.668:676](),[6.668][6.668:676]()
    sub getPrimaryBuildsForReleaseSet {
    my ($project, $primaryJob) = @_;
    my @primaryBuilds = $project->builds->search(
    { attrname => $primaryJob->job, finished => 1 },
    { join => 'resultInfo', order_by => "timestamp DESC"
    , '+select' => ["resultInfo.releasename"], '+as' => ["releasename"]
    , where => \ attrsToSQL($primaryJob->attrs, "me.id")
    });
    return @primaryBuilds;
    }
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 243
    [6.1921][6.747:843]()
    my ($project, $releaseSet, $primaryJob) = getReleaseSet($c, $projectName, $releaseSetName);
    [6.1921]
    [6.843]
    my ($project, $releaseSet, $primaryJob, $jobs) = getReleaseSet($c, $projectName, $releaseSetName);
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 277
    [6.1496][4.422:523]()
    push @releases, getRelease($c, $_) foreach getPrimaryBuildsForReleaseSet($project, $primaryJob);
    [6.1496]
    [6.2079]
    push @releases, getRelease($_, $jobs) foreach getPrimaryBuildsForReleaseSet($project, $primaryJob);
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 320
    [6.2252][6.1695:1791]()
    my ($project, $releaseSet, $primaryJob) = getReleaseSet($c, $projectName, $releaseSetName);
    [6.2252]
    [4.524]
    my ($project, $releaseSet, $primaryJob, $jobs) = getReleaseSet($c, $projectName, $releaseSetName);
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 324
    [4.612][4.612:858](),[4.858][6.2876:2877](),[6.1791][6.2876:2877](),[6.2345][6.2876:2877](),[6.2876][6.2876:2877]()
    my $latest;
    foreach my $release (getPrimaryBuildsForReleaseSet($project, $primaryJob)) {
    if (getRelease($c, $release)->{status} == 0) {
    $latest = $release;
    last;
    }
    }
    [4.612]
    [4.859]
    my $latest = getLatestSuccessfulRelease($project, $primaryJob, $jobs);
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 326
    [4.957][4.957:958]()
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 335
    [6.2692][6.2692:2750]()
    $c->stash->{release} = getRelease($c, $primaryBuild);
    [6.2692]
    [6.821]
    $c->stash->{release} = getRelease($primaryBuild, $jobs);
  • replacement in src/Hydra/lib/Hydra/Helper/Nix.pm at line 8
    [6.153][6.153:224]()
    our @EXPORT = qw(isValidPath getHydraPath getHydraDBPath openHydraDB);
    [6.153]
    [6.486]
    our @EXPORT = qw(
    isValidPath getHydraPath getHydraDBPath openHydraDB
    getPrimaryBuildsForReleaseSet getRelease getLatestSuccessfulRelease );
  • edit in src/Hydra/lib/Hydra/Helper/Nix.pm at line 42
    [6.846]
    [6.846]
    }
    sub attrsToSQL {
    my ($attrs, $id) = @_;
    my @attrs = split / /, $attrs;
    my $query = "1 = 1";
    foreach my $attr (@attrs) {
    $attr =~ /^([\w-]+)=([\w-]*)$/ or die "invalid attribute in release set: $attr";
    my $name = $1;
    my $value = $2;
    # !!! Yes, this is horribly injection-prone... (though
    # name/value are filtered above). Should use SQL::Abstract,
    # but it can't deal with subqueries. At least we should use
    # placeholders.
    $query .= " and (select count(*) from buildinputs where build = $id and name = '$name' and value = '$value') = 1";
    }
    return $query;
    }
    sub getPrimaryBuildsForReleaseSet {
    my ($project, $primaryJob) = @_;
    my @primaryBuilds = $project->builds->search(
    { attrname => $primaryJob->job, finished => 1 },
    { join => 'resultInfo', order_by => "timestamp DESC"
    , '+select' => ["resultInfo.releasename"], '+as' => ["releasename"]
    , where => \ attrsToSQL($primaryJob->attrs, "me.id")
    });
    return @primaryBuilds;
    }
    sub getRelease {
    my ($primaryBuild, $jobs) = @_;
    my @jobs = ();
    my $status = 0; # = okay
    # The timestamp of the release is the highest timestamp of all
    # constitutent builds.
    my $timestamp = 0;
    foreach my $job (@{$jobs}) {
    my $thisBuild;
    if ($job->isprimary) {
    $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
    }
    }
    $timestamp = $thisBuild->timestamp
    if defined $thisBuild && $thisBuild->timestamp > $timestamp;
    push @jobs, { build => $thisBuild, job => $job };
    }
    return
    { id => $primaryBuild->id
    , releasename => $primaryBuild->get_column('releasename')
    , jobs => [@jobs]
    , status => $status
    , timestamp => $timestamp
    };
  • edit in src/Hydra/lib/Hydra/Helper/Nix.pm at line 129
    [6.681]
    [6.849]
    sub getLatestSuccessfulRelease {
    my ($project, $primaryJob, $jobs) = @_;
    my $latest;
    foreach my $build (getPrimaryBuildsForReleaseSet($project, $primaryJob)) {
    return $build if getRelease($build, $jobs)->{status} == 0;
    }
    return undef;
    }
  • edit in src/Hydra/lib/Hydra/Helper/Nix.pm at line 140
    [6.850]
    [6.850]
  • replacement in src/Hydra/script/hydra_update_gc_roots.pl at line 47
    [6.1148][5.483:519]()
    # Go over all jobs in all projects.
    [6.1148]
    [6.1148]
    # Go over all projects.
  • edit in src/Hydra/script/hydra_update_gc_roots.pl at line 50
    [5.576]
    [5.576]
    # Go over all jobs in this project.
  • replacement in src/Hydra/script/hydra_update_gc_roots.pl at line 56
    [5.702][5.702:797]()
    print "*** looking for builds to keep in ", $project->name, ":", $job->attrname, "\n";
    [5.702]
    [5.797]
    print "*** looking for builds to keep in job ", $project->name, ":", $job->attrname, "\n";
  • edit in src/Hydra/script/hydra_update_gc_roots.pl at line 69
    [5.1221]
    [5.1221]
    keepBuild $_ foreach @recentBuilds;
    }
  • replacement in src/Hydra/script/hydra_update_gc_roots.pl at line 74
    [5.1222][5.1222:1266]()
    keepBuild $_ foreach @recentBuilds;
    [5.1222]
    [6.1610]
    # Go over all releases in this project.
    foreach my $releaseSet ($project->releasesets->all) {
    print "*** looking for builds to keep in release set ", $project->name, ":", $releaseSet->name, "\n";
    (my $primaryJob) = $releaseSet->releasesetjobs->search({isprimary => 1});
    my $jobs = [$releaseSet->releasesetjobs->all];
    # Keep all builds belonging to the most recent successful release.
    my $latest = getLatestSuccessfulRelease($project, $primaryJob, $jobs);
    if (defined $latest) {
    print "keeping latest successful release ", $latest->id, " (", $latest->get_column('releasename'), ")\n";
    my $release = getRelease($latest, $jobs);
    keepBuild $_->{build} foreach @{$release->{jobs}};
    }
  • edit in src/Hydra/script/hydra_update_gc_roots.pl at line 90
    [6.1616]
    [6.1616]