diff --git a/src/lib/Hydra/Controller/Job.pm b/src/lib/Hydra/Controller/Job.pm index c7965d9a..44349043 100644 --- a/src/lib/Hydra/Controller/Job.pm +++ b/src/lib/Hydra/Controller/Job.pm @@ -17,7 +17,16 @@ sub job : Chained('/') PathPart('job') CaptureArgs(3) { } -sub index : Chained('job') PathPart('') Args(0) { +sub overview : Chained('job') PathPart('') Args(0) { + my ($self, $c) = @_; + + $c->stash->{template} = 'job.tt'; + + getBuildStats($c, scalar $c->stash->{job}->builds); +} + + +sub all : Chained('job') PathPart Args(0) { my ($self, $c) = @_; $c->go($self->action_for("all")); } diff --git a/src/lib/Hydra/Controller/Jobset.pm b/src/lib/Hydra/Controller/Jobset.pm index 65bc31d3..4cfd8de3 100644 --- a/src/lib/Hydra/Controller/Jobset.pm +++ b/src/lib/Hydra/Controller/Jobset.pm @@ -22,7 +22,13 @@ sub jobset : Chained('/') PathPart('jobset') CaptureArgs(2) { sub index : Chained('jobset') PathPart('') Args(0) { my ($self, $c) = @_; - $c->go($self->action_for("all")); + + $c->stash->{template} = 'jobset.tt'; + + getBuildStats($c, scalar $c->stash->{jobset}->builds); + + $c->stash->{activeJobs} = [$c->stash->{jobset}->jobs->search({active => 1})]; + $c->stash->{inactiveJobs} = [$c->stash->{jobset}->jobs->search({active => 0})]; } @@ -36,4 +42,120 @@ sub get_builds : Chained('jobset') PathPart('') CaptureArgs(0) { } +sub edit : Chained('jobset') PathPart Args(0) { + my ($self, $c) = @_; + + requireProjectOwner($c, $c->stash->{project}); + + $c->stash->{template} = 'jobset.tt'; + $c->stash->{edit} = 1; +} + + +sub submit : Chained('jobset') PathPart Args(0) { + my ($self, $c) = @_; + + requireProjectOwner($c, $c->stash->{project}); + requirePost($c); + + $c->model('DB')->schema->txn_do(sub { + updateJobset($c, $c->stash->{jobset}); + }); + + $c->res->redirect($c->uri_for($self->action_for("index"), + [$c->stash->{project}->name, $c->stash->{jobset}->name])); +} + + +sub delete : Chained('jobset') PathPart Args(0) { + my ($self, $c) = @_; + + requireProjectOwner($c, $c->stash->{project}); + requirePost($c); + + $c->model('DB')->schema->txn_do(sub { + $c->stash->{jobset}->delete; + }); + + $c->res->redirect($c->uri_for($c->controller('Project')->action_for("view"), + [$c->stash->{project}->name])); +} + + +sub updateJobset { + my ($c, $jobset) = @_; + + my $jobsetName = trim $c->request->params->{"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->{"nixexprpath"}; + error($c, "Invalid Nix expression path: $nixExprPath") if $nixExprPath !~ /^$relPathRE$/; + + my $nixExprInput = trim $c->request->params->{"nixexprinput"}; + error($c, "Invalid Nix expression input name: $nixExprInput") unless $nixExprInput =~ /^\w+$/; + + $jobset->update( + { name => $jobsetName + , description => trim($c->request->params->{"description"}) + , nixexprpath => $nixExprPath + , nixexprinput => $nixExprInput + }); + + my %inputNames; + + # Process the inputs of this jobset. + foreach my $param (keys %{$c->request->params}) { + next unless $param =~ /^input-(\w+)-name$/; + my $baseName2 = $1; + next if $baseName2 eq "template"; + print STDERR "GOT INPUT: $baseName2\n"; + + my $inputName = trim $c->request->params->{"input-$baseName2-name"}; + error($c, "Invalid input name: $inputName") unless $inputName =~ /^[[:alpha:]]\w*$/; + + my $inputType = trim $c->request->params->{"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" || + $inputType eq "build"; + + $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 input + $input = ($jobset->jobsetinputs->search({name => $baseName2}))[0]; + die unless defined $input; + $input->update({name => $inputName, type => $inputType}); + } + + # 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->{"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}; + } +} + + 1; diff --git a/src/lib/Hydra/Controller/Project.pm b/src/lib/Hydra/Controller/Project.pm index 78e3761e..ebe73a0d 100644 --- a/src/lib/Hydra/Controller/Project.pm +++ b/src/lib/Hydra/Controller/Project.pm @@ -23,6 +23,8 @@ sub view : Chained('project') PathPart('') Args(0) { $c->stash->{template} = 'project.tt'; getBuildStats($c, scalar $c->stash->{project}->builds); + + $c->stash->{releaseSets} = [$c->stash->{project}->releasesets->all]; } @@ -40,14 +42,13 @@ sub submit : Chained('project') PathPart Args(0) { my ($self, $c) = @_; requireProjectOwner($c, $c->stash->{project}); - - error($c, "Request must be POSTed.") if $c->request->method ne "POST"; + requirePost($c); $c->model('DB')->schema->txn_do(sub { updateProject($c, $c->stash->{project}); }); - $c->res->redirect($c->uri_for($self->action_for("view"), $c->req->captures)); + $c->res->redirect($c->uri_for($self->action_for("view"), [$c->stash->{project}->name])); } @@ -55,8 +56,7 @@ sub delete : Chained('project') PathPart Args(0) { my ($self, $c) = @_; requireProjectOwner($c, $c->stash->{project}); - - error($c, "Request must be POSTed.") if $c->request->method ne "POST"; + requirePost($c); $c->model('DB')->schema->txn_do(sub { $c->stash->{project}->delete; @@ -109,6 +109,37 @@ sub create_submit : Path('/create-project/submit') { } +sub create_jobset : Chained('project') PathPart('create-jobset') Args(0) { + my ($self, $c) = @_; + + requireProjectOwner($c, $c->stash->{project}); + + $c->stash->{template} = 'jobset.tt'; + $c->stash->{create} = 1; + $c->stash->{edit} = 1; +} + + +sub create_jobset_submit : Chained('project') PathPart('create-jobset/submit') Args(0) { + my ($self, $c) = @_; + + requireProjectOwner($c, $c->stash->{project}); + + my $jobsetName = trim $c->request->params->{name}; + + $c->model('DB')->schema->txn_do(sub { + # Note: $jobsetName is validated in updateProject, which will + # abort the transaction if the name isn't valid. + my $jobset = $c->stash->{project}->jobsets->create( + {name => $jobsetName, nixexprinput => "", nixexprpath => ""}); + Hydra::Controller::Jobset::updateJobset($c, $jobset); + }); + + $c->res->redirect($c->uri_for($c->controller('Jobset')->action_for("index"), + [$c->stash->{project}->name, $jobsetName])); +} + + sub updateProject { my ($c, $project) = @_; my $projectName = trim $c->request->params->{name}; @@ -116,120 +147,22 @@ sub updateProject { 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); + my $owner = $project->owner; if ($c->check_user_roles('admin')) { - my $owner = trim $c->request->params->{owner}; + $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 - my $oldName = trim $c->request->params->{"jobset-$baseName-oldName"}; - $jobset = ($project->jobsets->search({name => $oldName}))[0] or die; - $jobset->update( - { name => $jobsetName, description => $description - , nixexprpath => $nixExprPath, nixexprinput => $nixExprInput }); - } - - 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" || - $inputType eq "build"; - - $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->update({name => $inputName, type => $inputType}); - } - - # 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}; - } + $project->update( + { name => $projectName + , displayname => $displayName + , description => trim($c->request->params->{description}) + , homepage => trim($c->request->params->{homepage}) + , enabled => trim($c->request->params->{enabled}) eq "1" ? 1 : 0 + , owner => $owner + }); } diff --git a/src/lib/Hydra/Controller/Root.pm b/src/lib/Hydra/Controller/Root.pm index 77e8c87c..3fefd8c2 100644 --- a/src/lib/Hydra/Controller/Root.pm +++ b/src/lib/Hydra/Controller/Root.pm @@ -13,7 +13,6 @@ __PACKAGE__->config->{namespace} = ''; sub begin :Private { my ($self, $c) = @_; - $c->stash->{projects} = [$c->model('DB::Projects')->search({}, {order_by => 'displayname'})]; $c->stash->{curUri} = $c->request->uri; $c->stash->{version} = $ENV{"HYDRA_RELEASE"} || ""; } @@ -21,8 +20,8 @@ sub begin :Private { sub index :Path :Args(0) { my ($self, $c) = @_; - $c->stash->{template} = 'index.tt'; - + $c->stash->{template} = 'overview.tt'; + $c->stash->{projects} = [$c->model('DB::Projects')->search({}, {order_by => 'displayname'})]; getBuildStats($c, $c->model('DB::Builds')); } @@ -63,18 +62,6 @@ sub queue :Local { } -sub releasesets :Local { - my ($self, $c, $projectName) = @_; - $c->stash->{template} = 'releasesets.tt'; - - my $project = $c->model('DB::Projects')->find($projectName); - notFound($c, "Project $projectName doesn't exist.") if !defined $project; - $c->stash->{project} = $project; - - $c->stash->{releaseSets} = [$project->releasesets->all]; -} - - sub getReleaseSet { my ($c, $projectName, $releaseSetName) = @_; diff --git a/src/lib/Hydra/Helper/CatalystUtils.pm b/src/lib/Hydra/Helper/CatalystUtils.pm index bb8bf942..2e9b403c 100644 --- a/src/lib/Hydra/Helper/CatalystUtils.pm +++ b/src/lib/Hydra/Helper/CatalystUtils.pm @@ -9,7 +9,7 @@ our @ISA = qw(Exporter); our @EXPORT = qw( getBuild getBuildStats getLatestBuilds getChannelData error notFound - requireLogin requireProjectOwner requireAdmin + requireLogin requireProjectOwner requireAdmin requirePost trim $pathCompRE $relPathRE ); @@ -126,6 +126,12 @@ sub requireAdmin { } +sub requirePost { + my ($c) = @_; + error($c, "Request must be POSTed.") if $c->request->method ne "POST"; +} + + sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; diff --git a/src/root/build.tt b/src/root/build.tt index 06fdf7b7..8c85f596 100644 --- a/src/root/build.tt +++ b/src/root/build.tt @@ -3,12 +3,12 @@ [% PROCESS "product-list.tt" %] [% USE HTML %] -[% project = build.get_column('project') %] -[% jobset = build.get_column('jobset') %] -[% job = build.get_column('job') %] +[% project = build.project %] +[% jobset = build.jobset %] +[% job = build.job %]

- Job [% project %]:[% jobset %]:[% job %] build [% id %] + Job [% project.name %]:[% jobset.name %]:[% job.name %] build [% id %] [% IF !build.finished %] [% IF build.schedulingInfo.busy %] (currently building) @@ -77,15 +77,15 @@ Project: - [% INCLUDE renderProjectName %] + [% INCLUDE renderProjectName project=project.name %] Jobset: - [% INCLUDE renderJobsetName %] + [% INCLUDE renderJobsetName project=project.name jobset=jobset.name %] Job name: - [% INCLUDE renderJobName %] + [% INCLUDE renderJobName project=project.name jobset=jobset.name job=job.name %] Nix name: diff --git a/src/root/common.tt b/src/root/common.tt index 9796b679..9a460d45 100644 --- a/src/root/common.tt +++ b/src/root/common.tt @@ -1,4 +1,5 @@ [% USE date %] +[% USE HTML %] [% inputTypes = @@ -140,3 +141,30 @@ [% BLOCK renderReleaseJobName -%] [% IF job.description; HTML.escape(job.description); ELSE %][% job.job %] ([% job.attrs %])[% END -%] [% END -%] + + +[% BLOCK maybeLink -%] + [% IF uri %] uri) %]>[% content %][% ELSE; content; END -%] +[% END -%] + + +[% BLOCK renderSelection %] + [% IF edit %] + + [% ELSE %] + [% options.$curValue %] + [% END %] +[% END %] + + +[% BLOCK maybeEditString; + IF edit -%] + param, name => param, value => value) %] /> + [% ELSE; + HTML.escape(value); + END -%] +[% END -%] diff --git a/src/root/index.tt b/src/root/index.tt deleted file mode 100644 index c2b2f4a6..00000000 --- a/src/root/index.tt +++ /dev/null @@ -1,13 +0,0 @@ -[% WRAPPER layout.tt title="Overview" %] -[% PROCESS common.tt %] - - -

Hydra Overview

- - -

Statistics

- -[% INCLUDE showBuildStats %] - - -[% END %] diff --git a/src/root/job.tt b/src/root/job.tt new file mode 100644 index 00000000..89c44ddf --- /dev/null +++ b/src/root/job.tt @@ -0,0 +1,31 @@ +[% WRAPPER layout.tt title="Job ‘$project.name:$jobset.name:$job.name’" %] +[% PROCESS common.tt %] + + +

Job [% project.name %]:[% jobset.name %]:[% job.name %]

+ + +

Channels

+ +

This job provides the following Nix channels:

+ + + + +

Statistics

+ +[% INCLUDE showBuildStats %] + + +[% END %] diff --git a/src/root/jobset.tt b/src/root/jobset.tt new file mode 100644 index 00000000..41342239 --- /dev/null +++ b/src/root/jobset.tt @@ -0,0 +1,212 @@ +[% WRAPPER layout.tt title=(edit ? (create ? "New Jobset in Project ‘$project.name’" : "Editing Jobset ‘$project.name:$jobset.name’") : "Jobset ‘$project.name:$jobset.name’") %] +[% PROCESS common.tt %] + + +[% IF edit %] +
+[% END %] + + +[% IF create %] +

New Jobset in Project [% project.name %]

+[% ELSE %] +

Jobset [% project.name %]:[% jobset.name %]

+[% END %] + + +[% BLOCK renderInputAlt %] + [% IF edit %] + + [% INCLUDE maybeEditString param=param value=alt.value %] +
+ [% ELSE %] + [% INCLUDE maybeEditString param=param value=alt.value %] + [% END %] +[% END %] + + +[% BLOCK renderInput %] + + + + [% IF edit %][% END -%] + [% INCLUDE maybeEditString param="$baseName-name" value=input.name extraClass="shortString" %] + + + [% INCLUDE renderSelection curValue=input.type param="$baseName-type" options=inputTypes %] + + + [% FOREACH alt IN input.jobsetinputalts -%] + + [% IF input.type == "string" && !edit %] + "[% HTML.escape(alt.value) %]" + [% ELSE %] + [% INCLUDE renderInputAlt alt=alt param="$baseName-values" %] + [% END %] + + [% END %] + [% IF edit %][% END %] + + + +[% END %] + + +

Information[% IF !edit %] [Edit][% END %]

+ + + [% IF edit %] + + + + + [% END %] + + + + + + + + + [% IF !edit %] + + + + + [% END %] +
Identifier:[% INCLUDE maybeEditString param="name" value=jobset.name %]
Description:[% INCLUDE maybeEditString param="description" value=jobset.description %]
Nix expression: + [% INCLUDE maybeEditString param="nixexprpath" value=jobset.nixexprpath extraClass="shortString" %] in input + [% INCLUDE maybeEditString param="nixexprinput" value=jobset.nixexprinput extraClass="shortString" %] +
Last checked: + [% IF jobset.lastcheckedtime %] + [% INCLUDE renderDateTime timestamp = jobset.lastcheckedtime -%][% IF jobset.errormsg -%], evaluation error: +
[% HTML.escape(jobset.errormsg) %]
+ [% ELSE %], no errors + [% END %] + [% ELSE %] + never + [% END %] +
+ + +

Inputs

+ + + + + + + [% FOREACH input IN jobset.jobsetinputs -%] + [% INCLUDE renderInput input=input baseName="input-$input.name" %] + [% END %] + [% IF edit %] + + + + [% END %] + +
Input nameTypeValues
+ + +[% IF !edit %] + + +

Jobs

+ +

This jobset currently contains the following [% activeJobs.size %] jobs: + +

+ [% IF activeJobs.size == 0 %](none)[% END %] + [% FOREACH j IN activeJobs %] [% INCLUDE renderJobName project=project.name jobset=jobset.name job=j.name %] [% END %] +
+

+ +

This jobset used to contain the following [% inactiveJobs.size %] jobs: + +

+ [% IF inactiveJobs.size == 0 %](none)[% END %] + [% FOREACH j IN inactiveJobs %] [% INCLUDE renderJobName project=project.name jobset=jobset.name job=j.name %] [% END %] +
+ +

+ + +

Channels

+ +

This jobset provides the following Nix channels:

+ + + + +

Statistics

+ +[% INCLUDE showBuildStats %] + + +[% END %] + + +[% IF edit %] + + + [% INCLUDE renderInput input="" extraClass="template" id="input-template" baseName="input-template" %] +
+ + + [% INCLUDE renderInputAlt alt=alt %] + + + + +

+ +
+ + [% IF !create %] + +
+

+
+ + + + [% END %] + +[% END %] + + +[% END %] diff --git a/src/root/layout.tt b/src/root/layout.tt index acd1fc6d..bcc406a3 100644 --- a/src/root/layout.tt +++ b/src/root/layout.tt @@ -4,17 +4,6 @@ [% PROCESS common.tt %] -[% BLOCK makeLinkWrapped %] -
  • - - [% content %] -
  • -[% END %] - -[% BLOCK makeLink -%] -[% INCLUDE makeLinkWrapped content="" -%] -[% END %] - @@ -83,63 +72,8 @@
    - - - + + [% PROCESS navbar.tt %]
    diff --git a/src/root/navbar.tt b/src/root/navbar.tt new file mode 100644 index 00000000..e1afd13d --- /dev/null +++ b/src/root/navbar.tt @@ -0,0 +1,119 @@ +[% BLOCK makeLinkWrapped %] +
  • + + [% content %] +
  • +[% END %] + +[% BLOCK makeLink -%] +[% INCLUDE makeLinkWrapped content="" -%] +[% END %] + +[% BLOCK makeSubMenu %] + [% extra = collapsed ? "collapsed" : "" %] + +[% END %] + + + + + + diff --git a/src/root/overview.tt b/src/root/overview.tt new file mode 100644 index 00000000..c6feda2d --- /dev/null +++ b/src/root/overview.tt @@ -0,0 +1,59 @@ +[% WRAPPER layout.tt title="Overview" %] +[% PROCESS common.tt %] + + +

    Hydra Overview

    + +

    Welcome to Hydra, the Nix-based +continuous build system. Hydra continuously builds, tests and +releases software packages from source repositories. [Read more...]

    + + +

    Projects

    + +

    The following projects are hosted on this server:

    + + + + + + + + + + + [% FOREACH p IN projects %] + + + + + + [% END %] + +
    IdNameDescription
    [% INCLUDE renderProjectName project = p.name %][% HTML.escape(p.displayname) %][% WRAPPER maybeLink uri=p.homepage %][% HTML.escape(p.description) %][% END %]
    + + +

    Channels

    + +

    This server provides the following global Nix channels:

    + +
      +
    • + latest — + contains the latest successful build of every job. +
    • +
    • + all — + contains every successful, non-garbage-collected build of every job. +
    • +
    + + +

    Statistics

    + +[% INCLUDE showBuildStats %] + + +[% END %] diff --git a/src/root/project.tt b/src/root/project.tt index ff2efd66..8d4cbaf3 100644 --- a/src/root/project.tt +++ b/src/root/project.tt @@ -1,137 +1,5 @@ [% WRAPPER layout.tt title=(edit ? (create ? "New Project" : "Editing Project ‘$project.name’") : "Project ‘$project.name’") %] [% PROCESS common.tt %] -[% USE HTML %] - - -[% BLOCK renderSelection %] - [% IF edit %] - - [% ELSE %] - [% options.$curValue %] - [% END %] -[% END %] - - -[% BLOCK maybeEditString; - IF edit -%] - param, name => param, value => value) %] /> - [% ELSE; - HTML.escape(value); - END -%] -[% END -%] - - -[% BLOCK renderInputAlt %] - [% IF edit %] - - [% INCLUDE maybeEditString param=param value=alt.value %] -
    - [% ELSE %] - [% INCLUDE maybeEditString param=param value=alt.value %] - [% END %] -[% END %] - - -[% BLOCK renderInput %] - - - - [% IF edit %][% END -%] - [% INCLUDE maybeEditString param="$baseName-name" value=input.name extraClass="shortString" %] - - - [% INCLUDE renderSelection curValue=input.type param="$baseName-type" options=inputTypes %] - - - [% FOREACH alt IN input.jobsetinputalts -%] - - [% IF input.type == "string" && !edit %] - "[% HTML.escape(alt.value) %]" - [% ELSE %] - [% INCLUDE renderInputAlt alt=alt param="$baseName-values" %] - [% END %] - - [% END %] - [% IF edit %][% END %] - - - -[% END %] - - -[% BLOCK renderJobset %] - -
    - - "jobset-$baseName-oldName", value => jobset.name) %] /> - -

    - [% IF edit %][% END %] - [% IF jobset %]Jobset [% jobset.name %][% ELSE %]New jobset[% END %] -

    - -

    Information

    - - - [% IF edit %] - - - - - [% END %] - - - - - - - - - [% IF !edit %] - - - - - [% END %] -
    Identifier:[% INCLUDE maybeEditString param="jobset-$baseName-name" value=jobset.name %]
    Description:[% INCLUDE maybeEditString param="jobset-$baseName-description" value=jobset.description %]
    Nix expression: - [% INCLUDE maybeEditString param="jobset-$baseName-nixexprpath" value=jobset.nixexprpath extraClass="shortString" %] in input - [% INCLUDE maybeEditString param="jobset-$baseName-nixexprinput" value=jobset.nixexprinput extraClass="shortString" %] -
    Last checked: - [% IF jobset.lastcheckedtime %] - [% INCLUDE renderDateTime timestamp = jobset.lastcheckedtime -%][% IF jobset.errormsg -%], evaluation error: -
    [% HTML.escape(jobset.errormsg) %]
    - [% ELSE %], no errors - [% END %] - [% ELSE %] - never - [% END %] -
    - -

    Inputs

    - - - - - - - [% FOREACH input IN jobset.jobsetinputs -%] - [% INCLUDE renderInput input=input baseName="jobset-$baseName-input-$input.name" %] - [% END %] - [% IF edit %] - - - - [% END %] - -
    Input nameTypeValues
    - -
    - -[% END %] [% IF edit %] @@ -146,7 +14,7 @@ [% END %] -

    General information

    +

    Information[% IF !edit %] [Edit][% END %]

    [% IF edit %] @@ -190,83 +58,98 @@
    + [% IF !edit %] -

    Statistics

    - -[% INCLUDE showBuildStats %] - -[% END %] -

    Jobsets

    -[% IF project.jobsets && project.jobsets.size > 0 || edit %] +[% IF project.jobsets.size > 0 %] - [% IF edit %] -

    +

    This project has the following jobsets:

    -
    - [% INCLUDE renderJobset jobset="" baseName="template" %] -
    + + + + + + + + + + [% FOREACH j IN project.jobsets %] + + + + + + [% END %] + +
    IdDescriptionLast evaluated
    [% INCLUDE renderJobsetName project = project.name jobset = j.name %][% HTML.escape(j.description) %][% INCLUDE renderDateTime timestamp = j.lastcheckedtime %]
    - - [% INCLUDE renderInput input="" extraClass="template" id="input-template" baseName="input-template" %] -
    - - - [% INCLUDE renderInputAlt alt=alt %] - - - - [% END %] - - [% n = 0; FOREACH jobset IN project.jobsets -%] - [% INCLUDE renderJobset jobset=jobset baseName="e$n"; n = n + 1 %] - [% END -%] [% ELSE %]

    No jobsets have been defined yet.

    +[% END %] + +[Create a new jobset] + + + +

    Releases

    + +[% IF releaseSets.size > 0 %] + +

    Project [% project.name %] has the following release sets:

    + + + +[% ELSE %] + +

    Project [% project.name %] has no release sets.

    + +[% END %] + +

    [Create a new release set]

    + + +

    Channels

    + +

    This project provides the following Nix channels:

    + +
      +
    • + latest — + contains the latest successful build of every job in this project. +
    • +
    • + all — + contains every successful, non-garbage-collected build of every + job in this project. +
    • +
    + + +

    Statistics

    + +[% INCLUDE showBuildStats %] + + [% END %] [% IF edit %] -
    -

    diff --git a/src/root/release.tt b/src/root/release.tt index 266fde90..b794c287 100644 --- a/src/root/release.tt +++ b/src/root/release.tt @@ -14,19 +14,19 @@

    This is an incomplete release. One of its jobs has not been built (yet). See below for details.

    [% END %] -[% FOREACH job IN release.jobs %] +[% FOREACH j IN release.jobs %]

    - [% IF job.build %][% END %] - [% INCLUDE renderReleaseJobName job=job.job %] - [% IF job.build %][% END %] + [% IF j.build %][% END %] + [% INCLUDE renderReleaseJobName job=j.job %] + [% IF j.build %][% END %]

    - [% IF job.build %] + [% IF j.build %] - [% IF job.build.resultInfo.buildstatus == 0 %] + [% IF j.build.resultInfo.buildstatus == 0 %] - [% INCLUDE renderProductList build=job.build %] + [% INCLUDE renderProductList build=j.build %] [% ELSE %] diff --git a/src/root/releases.tt b/src/root/releases.tt index af5f7a8d..a0e266a0 100644 --- a/src/root/releases.tt +++ b/src/root/releases.tt @@ -16,8 +16,8 @@ # Release Date - [% FOREACH job IN jobs %] - [% INCLUDE renderReleaseJobName %] + [% FOREACH j IN jobs %] + [% INCLUDE renderReleaseJobName job=j %] [% END %] @@ -44,11 +44,11 @@ [% END %] [% INCLUDE renderDateTime timestamp=release.timestamp %] - [% FOREACH job IN release.jobs %] + [% FOREACH j IN release.jobs %] - [% IF job.build %] - - [% IF job.build.get_column('buildstatus') == 0 %] + [% IF j.build %] + + [% IF j.build.get_column('buildstatus') == 0 %] [% ELSE %] diff --git a/src/root/releasesets.tt b/src/root/releasesets.tt deleted file mode 100644 index d9a096a3..00000000 --- a/src/root/releasesets.tt +++ /dev/null @@ -1,28 +0,0 @@ -[% WRAPPER layout.tt title="Release Sets" %] -[% PROCESS common.tt %] - -

    Release Sets

    - -[% IF releaseSets.size > 0 %] - -

    Project [% project.name %] has the following release sets:

    - -
    - -[% ELSE %] - -

    Project [% project.name %] has no release sets.

    - -[% END %] - - -

    [Create a new release set]

    - -[% END %] diff --git a/src/root/static/css/hydra.css b/src/root/static/css/hydra.css index 9a99e0f0..ab3acce9 100644 --- a/src/root/static/css/hydra.css +++ b/src/root/static/css/hydra.css @@ -65,7 +65,6 @@ td.centered { } th { - vertical-align: center; background: #ffffc0; } @@ -101,6 +100,7 @@ td.date, span.date, span.svnrev { a:link { color: #0048b3; } a:visited { color: #002a6a; } a:hover { background: #ffffcd; } +a.no-hover:hover { background: none; } span.relname { font-weight: bold; @@ -136,6 +136,11 @@ a:hover, a:visited:hover { text-decoration: underline; } +a.smallLink { + font-size: 60%; + vertical-align: top; +} + img { border-style: none; } @@ -196,23 +201,6 @@ ul.productList li { display: none; } -div.jobset { - border: solid black 1px; - -moz-border-radius: 1em; - border-radius: 1em; - padding-left: 1em; - padding-right: 1em; - margin-bottom: 1em; -} - -div.jobset-edit { - background-color: #f8f8f8; -} - -div.jobset-edit h3, div.jobset h3 { - margin-top: 0.5em; -} - div.help { border: solid black 1px; padding-left: 1em; @@ -314,11 +302,25 @@ h1 { #leftnavbar ul.menu > li > div.title { text-align: center; font-weight: bold; + color: black; border-width: 0px; border-bottom-width: 1px; border-style: solid; border-color: #c0c0c0; padding-bottom: 0.5em; + background-image: url(/static/images/arrow-down.gif); + background-repeat: no-repeat; + background-position: 0.3em center; +} + +#leftnavbar ul.menu > li > div.title > a { + display: block; + background: none; + color: black; +} + +#leftnavbar ul.menu > li > div.title > a:focus { + outline: none; } #leftnavbar ul.submenu { @@ -327,6 +329,10 @@ h1 { margin-right: 0em; } +#leftnavbar ul.collapsed { + display: none; +} + #leftnavbar ul.submenu > li { font-size: 90%; list-style: none; @@ -416,6 +422,10 @@ h1 { color: #606060; } +.hidden { + display: none; +} + #footer { font-size: 80%; }