* Put the project-related actions in a separate controller. Put the

[?]
Mar 4, 2009, 10:59 AM
FPK5LF53CFUEKFYJ3IYXT4UTVC6IITWJOCFATMC4PLHEUP5SIEAAC

Dependencies

Change contents

  • file addition: ListBuilds.pm (----------)
    [10.19]
    package Hydra::Base::Controller::ListBuilds;
    use strict;
    use warnings;
    use base 'Catalyst::Controller';
    use Hydra::Helper::Nix;
    use Hydra::Helper::CatalystUtils;
    sub jobstatus : Chained('get_builds') PathPart Args(0) {
    my ($self, $c) = @_;
    $c->stash->{latestBuilds} = getLatestBuilds($c, $c->stash->{allBuilds}, {});
    }
    sub all : Chained('get_builds') PathPart {
    my ($self, $c, $page) = @_;
    $c->stash->{template} = 'all.tt';
    $page = (defined $page ? int($page) : 1) || 1;
    my $resultsPerPage = 50;
    my $nrBuilds = scalar($c->stash->{allBuilds}->search({finished => 1}));
    $c->stash->{baseUri} = $c->uri_for($self->action_for("all"), $c->req->captures);
    $c->stash->{page} = $page;
    $c->stash->{resultsPerPage} = $resultsPerPage;
    $c->stash->{totalBuilds} = $nrBuilds;
    $c->stash->{builds} = [$c->stash->{allBuilds}->search(
    {finished => 1}, {order_by => "timestamp DESC", rows => $resultsPerPage, page => $page})];
    }
    1;
  • replacement in src/Hydra/lib/Hydra/Base/Controller/Nix.pm at line 5
    [10.109][10.109:144]()
    use parent 'Catalyst::Controller';
    [10.109]
    [10.144]
    use base 'Catalyst::Controller';
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 122
    [10.527][10.527:578]()
    $c->response->content_type('image/png'); # !!!
    [10.527]
    [10.578]
    $c->res->content_type('image/png'); # !!!
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 137
    [10.956][10.956:1007]()
    $c->response->content_type('image/png'); # !!!
    [10.956]
    [10.1007]
    $c->res->content_type('image/png'); # !!!
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 186
    [7.823][7.823:916]()
    $c->response->redirect($c->uri_for($self->action_for("view_build"), $c->req->captures));
    [7.823]
    [10.3293]
    $c->res->redirect($c->uri_for($self->action_for("view_build"), $c->req->captures));
  • file addition: Project.pm (----------)
    [57.54]
    package Hydra::Controller::Project;
    use strict;
    use warnings;
    use base 'Hydra::Base::Controller::ListBuilds';
    use Hydra::Helper::Nix;
    use Hydra::Helper::CatalystUtils;
    __PACKAGE__->config->{namespace} = '';
    sub project : Chained('/') PathPart('project') CaptureArgs(1) {
    my ($self, $c, $projectName) = @_;
    my $project = $c->model('DB::Projects')->find($projectName);
    notFound($c, "Project $projectName doesn't exist.") unless defined $project;
    $c->stash->{curProject} = $project;
    }
    sub view : Chained('project') PathPart('') Args(0) {
    my ($self, $c) = @_;
    $c->stash->{template} = 'project.tt';
    getBuildStats($c, scalar $c->stash->{curProject}->builds);
    }
    sub edit : Chained('project') PathPart Args(0) {
    my ($self, $c) = @_;
    requireProjectOwner($c, $c->stash->{curProject});
    $c->stash->{template} = 'project.tt';
    $c->stash->{edit} = 1;
    }
    sub submit : Chained('project') PathPart Args(0) {
    my ($self, $c) = @_;
    requireProjectOwner($c, $c->stash->{curProject});
    error($c, "Request must be POSTed.") if $c->request->method ne "POST";
    $c->model('DB')->schema->txn_do(sub {
    updateProject($c, $c->stash->{curProject});
    });
    $c->res->redirect($c->uri_for($self->action_for("view"), $c->req->captures));
    }
    sub delete : Chained('project') PathPart Args(0) {
    my ($self, $c) = @_;
    requireProjectOwner($c, $c->stash->{curProject});
    error($c, "Request must be POSTed.") if $c->request->method ne "POST";
    $c->model('DB')->schema->txn_do(sub {
    $c->stash->{curProject}->delete;
    });
    $c->res->redirect($c->uri_for("/"));
    }
    sub create : Path('create-project') {
    my ($self, $c) = @_;
    requireAdmin($c);
    $c->stash->{template} = 'project.tt';
    $c->stash->{create} = 1;
    $c->stash->{edit} = 1;
    }
    sub create_submit : Path('create-project/submit') {
    my ($self, $c) = @_;
    requireAdmin($c);
    my $projectName = trim $c->request->params->{name};
    $c->model('DB')->schema->txn_do(sub {
    # Note: $projectName is validated in updateProject,
    # which will abort the transaction if the name isn't
    # valid. Idem for the owner.
    my $project = $c->model('DB::Projects')->create(
    {name => $projectName, displayname => "", owner => trim $c->request->params->{owner}});
    updateProject($c, $project);
    });
    $c->res->redirect($c->uri_for($self->action_for("view"), [$projectName]));
    }
    sub updateProject {
    my ($c, $project) = @_;
    my $projectName = trim $c->request->params->{name};
    error($c, "Invalid project name: " . ($projectName || "(empty)")) unless $projectName =~ /^[[:alpha:]]\w*$/;
    my $displayName = trim $c->request->params->{displayname};
    error($c, "Invalid display name: $displayName") if $displayName eq "";
    $project->name($projectName);
    $project->displayname($displayName);
    $project->description(trim $c->request->params->{description});
    $project->homepage(trim $c->request->params->{homepage});
    $project->enabled(trim($c->request->params->{enabled}) eq "1" ? 1 : 0);
    if ($c->check_user_roles('admin')) {
    my $owner = trim $c->request->params->{owner};
    error($c, "Invalid owner: $owner")
    unless defined $c->model('DB::Users')->find({username => $owner});
    $project->owner($owner);
    }
    $project->update;
    my %jobsetNames;
    foreach my $param (keys %{$c->request->params}) {
    next unless $param =~ /^jobset-(\w+)-name$/;
    my $baseName = $1;
    next if $baseName eq "template";
    my $jobsetName = trim $c->request->params->{"jobset-$baseName-name"};
    error($c, "Invalid jobset name: $jobsetName") unless $jobsetName =~ /^[[:alpha:]]\w*$/;
    # The Nix expression path must be relative and can't contain ".." elements.
    my $nixExprPath = trim $c->request->params->{"jobset-$baseName-nixexprpath"};
    error($c, "Invalid Nix expression path: $nixExprPath") if $nixExprPath !~ /^$relPathRE$/;
    my $nixExprInput = trim $c->request->params->{"jobset-$baseName-nixexprinput"};
    error($c, "Invalid Nix expression input name: $nixExprInput") unless $nixExprInput =~ /^\w+$/;
    $jobsetNames{$jobsetName} = 1;
    my $jobset;
    my $description = trim $c->request->params->{"jobset-$baseName-description"};
    if ($baseName =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entry
    $jobset = $project->jobsets->create(
    { name => $jobsetName
    , description => $description
    , nixexprpath => $nixExprPath
    , nixexprinput => $nixExprInput
    });
    } else { # it's an existing jobset
    $jobset = ($project->jobsets->search({name => $baseName}))[0];
    die unless defined $jobset;
    $jobset->name($jobsetName);
    $jobset->description($description);
    $jobset->nixexprpath($nixExprPath);
    $jobset->nixexprinput($nixExprInput);
    $jobset->update;
    }
    my %inputNames;
    # Process the inputs of this jobset.
    foreach my $param (keys %{$c->request->params}) {
    next unless $param =~ /^jobset-$baseName-input-(\w+)-name$/;
    my $baseName2 = $1;
    next if $baseName2 eq "template";
    print STDERR "GOT INPUT: $baseName2\n";
    my $inputName = trim $c->request->params->{"jobset-$baseName-input-$baseName2-name"};
    error($c, "Invalid input name: $inputName") unless $inputName =~ /^[[:alpha:]]\w*$/;
    my $inputType = trim $c->request->params->{"jobset-$baseName-input-$baseName2-type"};
    error($c, "Invalid input type: $inputType") unless
    $inputType eq "svn" || $inputType eq "cvs" || $inputType eq "tarball" ||
    $inputType eq "string" || $inputType eq "path" || $inputType eq "boolean";
    $inputNames{$inputName} = 1;
    my $input;
    if ($baseName2 =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entry
    $input = $jobset->jobsetinputs->create(
    { name => $inputName
    , type => $inputType
    });
    } else { # it's an existing jobset
    $input = ($jobset->jobsetinputs->search({name => $baseName2}))[0];
    die unless defined $input;
    $input->name($inputName);
    $input->type($inputType);
    $input->update;
    }
    # Update the values for this input. Just delete all the
    # current ones, then create the new values.
    $input->jobsetinputalts->delete_all;
    my $values = $c->request->params->{"jobset-$baseName-input-$baseName2-values"};
    $values = [] unless defined $values;
    $values = [$values] unless ref($values) eq 'ARRAY';
    my $altnr = 0;
    foreach my $value (@{$values}) {
    print STDERR "VALUE: $value\n";
    my $value = trim $value;
    error($c, "Invalid Boolean value: $value") if
    $inputType eq "boolean" && !($value eq "true" || $value eq "false");
    $input->jobsetinputalts->create({altnr => $altnr++, value => $value});
    }
    }
    # Get rid of deleted inputs.
    my @inputs = $jobset->jobsetinputs->all;
    foreach my $input (@inputs) {
    $input->delete unless defined $inputNames{$input->name};
    }
    }
    # Get rid of deleted jobsets, i.e., ones that are no longer submitted in the parameters.
    my @jobsets = $project->jobsets->all;
    foreach my $jobset (@jobsets) {
    $jobset->delete unless defined $jobsetNames{$jobset->name};
    }
    }
    # Hydra::Base::Controller::ListBuilds needs this.
    sub get_builds : Chained('project') PathPart('') CaptureArgs(0) {
    my ($self, $c) = @_;
    $c->stash->{allBuilds} = $c->stash->{curProject}->builds;
    }
    1;
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 6
    [10.47]
    [58.86]
    use base 'Hydra::Base::Controller::ListBuilds';
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 19
    [10.75][10.1224:1226](),[10.1224][10.1224:1226](),[10.1226][10.0:1](),[10.1][10.1226:1227](),[10.1226][10.1226:1227](),[10.1227][10.2:73]()
    }
    sub trim {
    my $s = shift;
    $s =~ s/^\s+|\s+$//g;
    return $s;
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 22
    [10.1355][10.0:678]()
    sub getBuildStats {
    my ($c, $builds) = @_;
    $c->stash->{finishedBuilds} = $builds->search({finished => 1}) || 0;
    $c->stash->{succeededBuilds} = $builds->search(
    {finished => 1, buildStatus => 0},
    {join => 'resultInfo'}) || 0;
    $c->stash->{scheduledBuilds} = $builds->search({finished => 0}) || 0;
    $c->stash->{busyBuilds} = $builds->search(
    {finished => 0, busy => 1},
    {join => 'schedulingInfo'}) || 0;
    $c->stash->{totalBuildTime} = $builds->search({},
    {join => 'resultInfo', select => {sum => 'stoptime - starttime'}, as => ['sum']})
    ->first->get_column('sum') || 0;
    }
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 63
    [10.299][10.0:4](),[10.4][10.48:110](),[10.110][8.0:576](),[8.576][10.155:308](),[10.155][10.155:308](),[10.308][8.577:643](),[10.372][10.522:526](),[8.643][10.522:526](),[10.522][10.522:526](),[10.526][10.386:550](),[10.550][10.575:614](),[10.575][10.575:614](),[10.614][10.0:51](),[10.51][10.643:674](),[10.643][10.643:674](),[10.674][10.551:612](),[10.612][10.751:752](),[10.751][10.751:752](),[10.752][10.613:650](),[10.650][10.752:877](),[10.752][10.752:877](),[10.877][10.651:695](),[10.695][10.937:1036](),[10.937][10.937:1036](),[10.299][10.0:4](),[10.1036][10.0:4](),[10.604][10.0:4](),[10.4][10.696:821]()
    }
    # Return the latest build for each job.
    sub getLatestBuilds {
    my ($c, $builds, $extraAttrs) = @_;
    my @res = ();
    foreach my $job ($builds->search({},
    {group_by => ['project', 'attrname', 'system']}))
    {
    my $attrs =
    { project => $job->get_column('project')
    , attrname => $job->attrname
    , system => $job->system
    , finished => 1
    };
    my ($build) = $builds->search({ %$attrs, %$extraAttrs },
    { join => 'resultInfo', order_by => 'timestamp DESC', rows => 1 } );
    push @res, $build if defined $build;
    }
    return [@res];
    }
    sub showJobStatus {
    my ($c, $builds) = @_;
    $c->stash->{template} = 'jobstatus.tt';
    # Get the latest finished build for each unique job.
    $c->stash->{latestBuilds} = getLatestBuilds($c, $builds, {});
    }
    sub jobstatus :Local {
    my ($self, $c) = @_;
    showJobStatus($c, $c->model('DB::Builds'));
    }
    sub showAllBuilds {
    my ($c, $baseUri, $page, $builds) = @_;
    $c->stash->{template} = 'all.tt';
    $page = (defined $page ? int($page) : 1) || 1;
    my $resultsPerPage = 50;
    my $nrBuilds = scalar($builds->search({finished => 1}));
    $c->stash->{baseUri} = $baseUri;
    $c->stash->{page} = $page;
    $c->stash->{resultsPerPage} = $resultsPerPage;
    $c->stash->{totalBuilds} = $nrBuilds;
    $c->stash->{builds} = [$builds->search(
    {finished => 1}, {order_by => "timestamp DESC", rows => $resultsPerPage, page => $page})];
    }
    sub all :Local {
    my ($self, $c, $page) = @_;
    showAllBuilds($c, $c->uri_for("/all"), $page, $c->model('DB::Builds'));
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 221
    [10.823][10.823:825](),[10.825][10.4:52](),[10.4][10.4:52](),[10.53][10.78:134](),[10.134][10.104:197](),[10.104][10.104:197](),[10.197][10.135:266](),[10.163][10.335:415](),[10.266][10.335:415](),[10.335][10.335:415](),[10.415][10.267:335](),[10.335][6.0:62](),[6.62][10.335:411](),[10.335][10.335:411](),[10.411][5.0:251](),[10.70][10.0:23](),[10.182][10.0:23](),[10.226][10.0:23](),[5.251][10.0:23](),[10.411][10.0:23](),[10.478][10.0:23](),[10.23][10.478:483](),[10.478][10.478:483](),[10.483][10.24:222](),[10.222][10.412:490](),[10.490][10.295:385](),[10.295][10.295:385](),[10.385][10.147:231](),[10.231][10.491:577](),[10.577][10.0:91]()
    sub updateProject {
    my ($c, $project) = @_;
    my $projectName = trim $c->request->params->{name};
    die "Invalid project name: $projectName" unless $projectName =~ /^[[:alpha:]]\w*$/;
    my $displayName = trim $c->request->params->{displayname};
    die "Invalid display name: $displayName" if $displayName eq "";
    $project->name($projectName);
    $project->displayname($displayName);
    $project->description(trim $c->request->params->{description});
    $project->homepage(trim $c->request->params->{homepage});
    $project->enabled(trim($c->request->params->{enabled}) eq "1" ? 1 : 0);
    if ($c->check_user_roles('admin')) {
    my $owner = trim $c->request->params->{owner};
    die "Invalid owner: $owner"
    unless defined $c->model('DB::Users')->find({username => $owner});
    $project->owner($owner);
    }
    $project->update;
    my %jobsetNames;
    foreach my $param (keys %{$c->request->params}) {
    next unless $param =~ /^jobset-(\w+)-name$/;
    my $baseName = $1;
    next if $baseName eq "template";
    my $jobsetName = trim $c->request->params->{"jobset-$baseName-name"};
    die "Invalid jobset name: $jobsetName" unless $jobsetName =~ /^[[:alpha:]]\w*$/;
    # The Nix expression path must be relative and can't contain ".." elements.
    my $nixExprPath = trim $c->request->params->{"jobset-$baseName-nixexprpath"};
    die "Invalid Nix expression path: $nixExprPath" if $nixExprPath !~ /^$relPathRE$/;
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 222
    [10.571][10.578:666](),[10.666][10.654:750](),[10.654][10.654:750]()
    my $nixExprInput = trim $c->request->params->{"jobset-$baseName-nixexprinput"};
    die "Invalid Nix expression input name: $nixExprInput" unless $nixExprInput =~ /^\w+$/;
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 223
    [10.751][10.751:790](),[10.790][10.0:21](),[10.21][4.0:87](),[10.21][10.790:883](),[4.87][10.790:883](),[10.790][10.790:883](),[10.883][10.22:109](),[10.109][4.88:134](),[4.134][10.1111:1268](),[10.759][10.1111:1268](),[10.1111][10.1111:1268](),[10.1268][10.110:185](),[10.185][10.1343:1423](),[10.1343][10.1343:1423](),[10.1423][4.135:183](),[4.183][10.1512:1639](),[10.854][10.1512:1639](),[10.1512][10.1512:1639](),[10.1639][10.186:196](),[10.196][10.0:25](),[10.25][10.196:512](),[10.196][10.196:512](),[10.512][10.855:953](),[10.953][10.605:696](),[10.605][10.605:696](),[10.696][10.954:1052](),[10.1052][10.789:934](),[10.789][10.789:934](),[10.934][10.0:91](),[10.91][10.998:999](),[10.998][10.998:999](),[10.999][10.26:80](),[10.80][10.999:1119](),[10.999][10.999:1119](),[10.1119][10.81:243](),[10.243][10.1119:1689](),[10.1119][10.1119:1689](),[10.1689][2.0:49](),[2.49][10.1689:1873](),[10.1689][10.1689:1873](),[10.1873][10.92:364](),[10.364][10.1960:1974](),[10.1145][10.1960:1974](),[10.1960][10.1960:1974](),[10.1974][10.1639:1649](),[10.1639][10.1639:1649](),[10.1649][10.244:245](),[10.245][3.0:37](),[3.37][10.282:448](),[10.282][10.282:448](),[10.448][10.1649:1901](),[10.1649][10.1649:1901](),[10.505][10.0:25](),[10.604][10.0:25](),[10.1901][10.0:25](),[10.226][10.0:25](),[10.25][10.826:884](),[10.352][10.66:108](),[10.560][10.66:108](),[10.884][10.66:108](),[10.66][10.66:108](),[10.108][10.0:5](),[10.5][10.2919:2984](),[10.2984][10.2903:2981](),[10.1228][10.561:613](),[10.2981][10.561:613](),[10.280][10.561:613](),[10.613][10.885:930](),[10.930][10.613:662](),[10.613][10.613:662](),[10.662][10.931:1035](),[10.1035][10.183:184](),[10.662][10.183:184](),[10.184][10.1036:1233](),[10.267][10.227:228](),[10.228][7.1001:1044](),[10.301][10.267:276](),[10.419][10.267:276](),[7.1044][10.267:276](),[10.267][10.267:276](),[10.487][10.487:736](),[10.736][10.1792:1871](),[10.1871][10.833:843](),[10.833][10.833:843](),[10.843][10.662:663](),[10.662][10.662:663](),[10.663][10.844:1081](),[10.1081][10.3076:3134](),[10.3134][10.1146:1156](),[10.1146][10.1146:1156](),[10.1156][10.1253:1260](),[10.1253][10.1253:1260](),[10.141][10.744:792](),[10.125][10.972:977](),[10.792][10.972:977](),[10.972][10.972:977](),[10.977][10.317:475](),[10.317][10.317:475](),[10.226][10.0:3](),[10.303][10.0:3](),[10.475][10.0:3](),[10.397][10.0:3](),[10.3][10.1261:1289](),[10.1289][10.353:391](),[10.391][10.3:4](),[10.1329][10.3:4](),[10.3][10.3:4](),[10.4][7.1045:1087](),[7.1087][10.420:421](),[10.1206][10.420:421](),[10.421][10.3135:3193](),[10.3193][10.486:532](),[10.486][10.486:532](),[10.532][10.1329:1330](),[10.1329][10.1329:1330](),[10.1330][10.1330:1388](),[10.4][10.1330:1388](),[10.1388][10.3194:3762](),[10.3762][10.1993:2106](),[10.1993][10.1993:2106]()
    $jobsetNames{$jobsetName} = 1;
    my $jobset;
    my $description = trim $c->request->params->{"jobset-$baseName-description"};
    if ($baseName =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entry
    $jobset = $project->jobsets->create(
    { name => $jobsetName
    , description => $description
    , nixexprpath => $nixExprPath
    , nixexprinput => $nixExprInput
    });
    } else { # it's an existing jobset
    $jobset = ($project->jobsets->search({name => $baseName}))[0];
    die unless defined $jobset;
    $jobset->name($jobsetName);
    $jobset->description($description);
    $jobset->nixexprpath($nixExprPath);
    $jobset->nixexprinput($nixExprInput);
    $jobset->update;
    }
    my %inputNames;
    # Process the inputs of this jobset.
    foreach my $param (keys %{$c->request->params}) {
    next unless $param =~ /^jobset-$baseName-input-(\w+)-name$/;
    my $baseName2 = $1;
    next if $baseName2 eq "template";
    print STDERR "GOT INPUT: $baseName2\n";
    my $inputName = trim $c->request->params->{"jobset-$baseName-input-$baseName2-name"};
    die "Invalid input name: $inputName" unless $inputName =~ /^[[:alpha:]]\w*$/;
    my $inputType = trim $c->request->params->{"jobset-$baseName-input-$baseName2-type"};
    die "Invalid input type: $inputType" unless
    $inputType eq "svn" || $inputType eq "cvs" || $inputType eq "tarball" ||
    $inputType eq "string" || $inputType eq "path" || $inputType eq "boolean";
    $inputNames{$inputName} = 1;
    my $input;
    if ($baseName2 =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entry
    $input = $jobset->jobsetinputs->create(
    { name => $inputName
    , type => $inputType
    });
    } else { # it's an existing jobset
    $input = ($jobset->jobsetinputs->search({name => $baseName2}))[0];
    die unless defined $input;
    $input->name($inputName);
    $input->type($inputType);
    $input->update;
    }
    # Update the values for this input. Just delete all the
    # current ones, then create the new values.
    $input->jobsetinputalts->delete_all;
    my $values = $c->request->params->{"jobset-$baseName-input-$baseName2-values"};
    $values = [] unless defined $values;
    $values = [$values] unless ref($values) eq 'ARRAY';
    my $altnr = 0;
    foreach my $value (@{$values}) {
    print STDERR "VALUE: $value\n";
    my $value = trim $value;
    die "Invalid Boolean value: $value" if
    $inputType eq "boolean" && !($value eq "true" || $value eq "false");
    $input->jobsetinputalts->create({altnr => $altnr++, value => $value});
    }
    }
    # Get rid of deleted inputs.
    my @inputs = $jobset->jobsetinputs->all;
    foreach my $input (@inputs) {
    $input->delete unless defined $inputNames{$input->name};
    }
    }
    # Get rid of deleted jobsets, i.e., ones that are no longer submitted in the parameters.
    my @jobsets = $project->jobsets->all;
    foreach my $jobset (@jobsets) {
    $jobset->delete unless defined $jobsetNames{$jobset->name};
    }
    }
    sub project :Local {
    my ($self, $c, $projectName, $subcommand, $arg) = @_;
    $c->stash->{template} = 'project.tt';
    my $project = $c->model('DB::Projects')->find($projectName);
    notFound($c, "Project $projectName doesn't exist.") if !defined $project;
    my $isPosted = $c->request->method eq "POST";
    $c->stash->{curProject} = $project;
    $subcommand = "" unless defined $subcommand;
    if ($subcommand eq "jobstatus") {
    return showJobStatus($c, scalar $project->builds);
    }
    elsif ($subcommand eq "all") {
    return showAllBuilds($c, $c->uri_for("/project", $projectName, "all"),
    $arg, scalar $project->builds);
    }
    elsif ($subcommand ne "") {
    requireProjectOwner($c, $project);
    if ($subcommand eq "edit") {
    $c->stash->{edit} = 1;
    }
    elsif ($subcommand eq "submit" && $isPosted) {
    $c->model('DB')->schema->txn_do(sub {
    updateProject($c, $project);
    });
    return $c->res->redirect($c->uri_for("/project", $project->name));
    }
    elsif ($subcommand eq "delete" && $isPosted) {
    $c->model('DB')->schema->txn_do(sub {
    $project->delete;
    });
    return $c->res->redirect($c->uri_for("/"));
    }
    else {
    error($c, "Unknown subcommand $subcommand.");
    }
    }
    getBuildStats($c, scalar $project->builds);
    $c->stash->{jobNames} =
    [$c->model('DB::Builds')->search({project => $projectName}, {select => [{distinct => 'attrname'}], as => ['attrname']})];
    }
    sub createproject :Local {
    my ($self, $c, $subcommand) = @_;
    requireLogin($c) if !$c->user_exists;
    error($c, "Only administrators can create projects.")
    unless $c->check_user_roles('admin');
    if (defined $subcommand && $subcommand eq "submit") {
    my $projectName = trim $c->request->params->{name};
    $c->model('DB')->schema->txn_do(sub {
    # Note: $projectName is validated in updateProject,
    # which will abort the transaction if the name isn't
    # valid. Idem for the owner.
    my $project = $c->model('DB::Projects')->create(
    {name => $projectName, displayname => "", owner => trim $c->request->params->{owner}});
    updateProject($c, $project);
    });
    return $c->res->redirect($c->uri_for("/project", $projectName));
    }
    $c->stash->{template} = 'project.tt';
    $c->stash->{create} = 1;
    $c->stash->{edit} = 1;
    }
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 259
    [10.712]
    [10.1511]
    # Hydra::Base::Controller::ListBuilds needs this.
    sub get_builds : Chained('/') PathPart('') CaptureArgs(0) {
    my ($self, $c) = @_;
    $c->stash->{allBuilds} = $c->model('DB::Builds');
    }
  • replacement in src/Hydra/lib/Hydra/Helper/CatalystUtils.pm at line 9
    [10.125][10.125:153](),[10.153][7.1088:1125]()
    getBuild error notFound
    requireLogin requireProjectOwner
    [10.125]
    [10.153]
    getBuild getBuildStats getLatestBuilds
    error notFound
    requireLogin requireProjectOwner requireAdmin
    trim
  • edit in src/Hydra/lib/Hydra/Helper/CatalystUtils.pm at line 21
    [10.3706]
    [10.3706]
    }
    sub getBuildStats {
    my ($c, $builds) = @_;
    $c->stash->{finishedBuilds} = $builds->search({finished => 1}) || 0;
    $c->stash->{succeededBuilds} = $builds->search(
    {finished => 1, buildStatus => 0},
    {join => 'resultInfo'}) || 0;
    $c->stash->{scheduledBuilds} = $builds->search({finished => 0}) || 0;
    $c->stash->{busyBuilds} = $builds->search(
    {finished => 0, busy => 1},
    {join => 'schedulingInfo'}) || 0;
    $c->stash->{totalBuildTime} = $builds->search({},
    {join => 'resultInfo', select => {sum => 'stoptime - starttime'}, as => ['sum']})
    ->first->get_column('sum') || 0;
    }
    # Return the latest build for each job.
    sub getLatestBuilds {
    my ($c, $builds, $extraAttrs) = @_;
    my @res = ();
    foreach my $job ($builds->search({},
    {group_by => ['project', 'attrname', 'system']}))
    {
    my $attrs =
    { project => $job->get_column('project')
    , attrname => $job->attrname
    , system => $job->system
    , finished => 1
    };
    my ($build) = $builds->search({ %$attrs, %$extraAttrs },
    { join => 'resultInfo', order_by => 'timestamp DESC', rows => 1 } );
    push @res, $build if defined $build;
    }
    return [@res];
  • replacement in src/Hydra/lib/Hydra/Helper/CatalystUtils.pm at line 96
    [7.1439][7.1439:1528]()
    error($c, "Only the project owner or the administrator can perform this operation.")
    [7.1439]
    [7.1528]
    error($c, "Only the project owner or administrators can perform this operation.")
  • edit in src/Hydra/lib/Hydra/Helper/CatalystUtils.pm at line 101
    [7.1629]
    [10.184]
    sub requireAdmin {
    my ($c) = @_;
    requireLogin($c) if !$c->user_exists;
    error($c, "Only administrators can perform this operation.")
    unless $c->check_user_roles('admin');
    }
    sub trim {
    my $s = shift;
    $s =~ s/^\s+|\s+$//g;
    return $s;
    }
  • replacement in src/Hydra/root/error.tt at line 6
    [10.8555][9.76:216]()
    <p>I'm very sorry, but an error occurred: <span class="error-msg">[% FOREACH error IN errors %][% HTML.escape(error) %][% END %]</span></p>
    [10.8555]
    [10.8645]
    <p>I'm very sorry, but the following error(s) occurred:</p>
    <ul>
    [% FOREACH error IN errors %]
    <li><div class="error-msg">[% HTML.escape(error) %]</div></li>
    [% END %]
    </ul>
  • replacement in src/Hydra/root/layout.tt at line 135
    [10.4611][10.4611:4707]()
    [% INCLUDE makeLink uri = c.uri_for('/createproject') title = "Create project" %]
    [10.4611]
    [10.4682]
    [% INCLUDE makeLink uri = c.uri_for('/create-project') title = "Create project" %]
  • replacement in src/Hydra/root/project.tt at line 142
    [10.2884][10.2884:3043]()
    <form action="[% IF create %][% c.uri_for('/createproject/submit') %][% ELSE %][% c.uri_for('/project' curProject.name 'submit') %][% END %]" method="post">
    [10.2884]
    [10.3043]
    <form action="[% IF create %][% c.uri_for('/create-project/submit') %][% ELSE %][% c.uri_for('/project' curProject.name 'submit') %][% END %]" method="post">