diff --git a/src/lib/Hydra/View/TT.pm b/src/lib/Hydra/View/TT.pm index c6176231..84fcf3e9 100644 --- a/src/lib/Hydra/View/TT.pm +++ b/src/lib/Hydra/View/TT.pm @@ -3,6 +3,7 @@ package Hydra::View::TT; use strict; use warnings; use base 'Catalyst::View::TT'; +use Template::Plugin::HTML; use Hydra::Helper::Nix; use Time::Seconds; @@ -11,7 +12,20 @@ __PACKAGE__->config( ENCODING => 'utf-8', PRE_CHOMP => 1, POST_CHOMP => 1, - expose_methods => [qw/buildLogExists buildStepLogExists jobExists relativeDuration stripSSHUser/]); + expose_methods => [qw/ + buildLogExists + buildStepLogExists + jobExists + linkToJob + linkToJobset + linkToProject + makeNameLinksForJob + makeNameLinksForJobset + makeNameTextForJob + makeNameTextForJobset + relativeDuration + stripSSHUser + /]); sub buildLogExists { my ($self, $c, $build) = @_; @@ -64,4 +78,250 @@ sub jobExists { return defined $jobset->builds->search({ job => $jobName, iscurrent => 1 })->single; } +=head2 linkToProject + +Given a L<Hydra::Schema::Result::Project>, return a link to the project. + +Arguments: + +=over 3 + +=item C<$self> +=back + +=item C<$c> +Catalyst Context +=back + +=item C<$project> + +The L<Hydra::Schema::Result::Project> to link to. + +=back + +=cut +sub linkToProject { + my ($self, $c, $project) = @_; + + my $html = Template::Plugin::HTML->new(); + + my $projectName = $project->name; + my $escapedProjectName = $html->escape($projectName); + + return '<a href="' . $c->uri_for('/project', $projectName) . '">' . $escapedProjectName . '</a>'; +} + +=head2 linkToJobset + +Given a L<Hydra::Schema::Result::Jobset>, return a link to the jobset +and its project in project:jobset notation. + +Arguments: + +=over 3 + +=item C<$self> +=back + +=item C<$c> +Catalyst Context +=back + +=item C<$jobset> + +The L<Hydra::Schema::Result::Jobset> to link to. + +=back + +=cut +sub linkToJobset { + my ($self, $c, $jobset) = @_; + + my $html = Template::Plugin::HTML->new(); + + my $jobsetName = $jobset->name; + my $escapedJobsetName = $html->escape($jobsetName); + + return linkToProject($self, $c, $jobset->project) . + ':<a href="' . $c->uri_for('/jobset', $jobset->project->name, $jobsetName) . '">' . $escapedJobsetName . '</a>'; +} + +=head2 linkToJobset + +Given a L<Hydra::Schema::Result::Jobset> and L<String> Job name, return +a link to the job, jobset, and project in project:jobset:job notation. + +Arguments: + +=over 4 + +=item C<$self> +=back + +=item C<$c> +Catalyst Context +=back + +=item C<$jobset> + +The L<Hydra::Schema::Result::Jobset> to link to. +=back + +=item C<$jobName> + +The L<String> job name to link to. + +=back + +=cut +sub linkToJob { + my ($self, $c, $jobset, $jobName) = @_; + + my $html = Template::Plugin::HTML->new(); + + my $escapedJobName = $html->escape($jobName); + + return linkToJobset($self, $c, $jobset) . + ':<a href="' . $c->uri_for('/job', $jobset->project->name, $jobset->name, $jobName) . '">' . $escapedJobName . '</a>'; +} + +=head2 makeNameLinksForJobset + +Given a L<Hydra::Schema::Result::Jobset>, return a link to the jobset's +project and a non-link to the jobset in project:jobset notation. + +Arguments: + +=over 3 + +=item C<$self> +=back + +=item C<$c> +Catalyst Context +=back + +=item C<$jobset> + +The L<Hydra::Schema::Result::Jobset> to link to. + +=back + +=cut +sub makeNameLinksForJobset { + my ($self, $c, $jobset) = @_; + + my $html = Template::Plugin::HTML->new(); + + my $escapedJobsetName = $html->escape($jobset->name); + + return linkToProject($self, $c, $jobset->project) . ':' . $escapedJobsetName; +} + +=head2 makeNameLinksForJob + +Given a L<Hydra::Schema::Result::Jobset> and L<String> Job name, return +a link to the jobset and project, and a non-link to the job in +project:jobset:job notation. + +Arguments: + +=over 4 + +=item C<$self> +=back + +=item C<$c> +Catalyst Context +=back + +=item C<$jobset> + +The L<Hydra::Schema::Result::Jobset> to link to. + +=back + + +=item C<$jobName> + +The L<String> job name to link to. + +=back + +=cut +sub makeNameLinksForJob { + my ($self, $c, $jobset, $jobName) = @_; + + my $html = Template::Plugin::HTML->new(); + + my $escapedJobName = $html->escape($jobName); + + return linkToJobset($self, $c, $jobset) . ':' . $escapedJobName; +} + +=head2 makeNameTextForJobset + +Given a L<Hydra::Schema::Result::Jobset>, return the project and +jobset in project:jobset notation. + +Arguments: + +=over 3 + +=item C<$self> +=back + +=item C<$c> +Catalyst Context +=back + +=item C<$jobset> + +The L<Hydra::Schema::Result::Jobset> to link to. + +=back + +=cut +sub makeNameTextForJobset { + my ($self, $c, $jobset) = @_; + + return $jobset->project->name . ":" . $jobset->name; +} + +=head2 makeNameTextForJob + +Given a L<Hydra::Schema::Result::Jobset> and L<String> Job name, return +the job, jobset, and project in project:jobset:job notation. + +Arguments: + +=over 4 + +=item C<$self> +=back + +=item C<$c> +Catalyst Context +=back + +=item C<$jobset> + +The L<Hydra::Schema::Result::Jobset> to link to. + +=back + + +=item C<$jobName> + +The L<String> job name to link to. + +=back + +=cut +sub makeNameTextForJob { + my ($self, $c, $jobset, $jobName) = @_; + + return $jobset->project->name . ":" . $jobset->name . ":" . $jobName; +} + 1; diff --git a/src/root/all.tt b/src/root/all.tt index a4517349..e877f5b5 100644 --- a/src/root/all.tt +++ b/src/root/all.tt @@ -1,7 +1,14 @@ -[% WRAPPER layout.tt title="Latest builds" _ - (job ? " for job $project.name:$jobset.name:$job" : - jobset ? " for jobset $project.name:$jobset.name" : - project ? " for project $project.name" : "") %] +[% WRAPPER layout.tt +titleHTML="Latest builds" _ + (job ? " for job " _ linkToJob(jobset, job) : + jobset ? " for jobset " _ linkToJobset(jobset) : + project ? " for project " _ linkToProject(project) : + "") + title="Latest builds" _ + (job ? " for job " _ makeNameTextForJob(jobset, job) : + jobset ? " for jobset " _ makeNameTextForJobset(jobset) : + project ? " for project $project.name" : + "") %] [% PROCESS common.tt %] <p>Showing builds [% (page - 1) * resultsPerPage + 1 %] - [% (page - 1) * resultsPerPage + builds.size %] out of [% total %] in order of descending finish time.</p> diff --git a/src/root/build.tt b/src/root/build.tt index f9f442f6..ea3b75c4 100644 --- a/src/root/build.tt +++ b/src/root/build.tt @@ -1,4 +1,7 @@ -[% WRAPPER layout.tt title="Build $id of job $project.name:$jobset.name:$job" %] +[% WRAPPER layout.tt + title="Build $id of job " _ makeNameTextForJob(jobset, job) + titleHTML="Build $id of job " _ linkToJob(jobset, job) +%] [% PROCESS common.tt %] [% PROCESS "product-list.tt" %] [% USE HTML %] diff --git a/src/root/edit-jobset.tt b/src/root/edit-jobset.tt index 22874815..dbd26dcc 100644 --- a/src/root/edit-jobset.tt +++ b/src/root/edit-jobset.tt @@ -1,8 +1,8 @@ [% WRAPPER layout.tt title= (create ? "Creating jobset in project $project.name" : - createFromEval ? "Creating jobset from evaluation $eval.id of $project.name:$jobset.name" : - cloneJobset ? "Cloning jobset $project.name:$jobset.name" : - "Editing jobset $project.name:$jobset.name") %] + createFromEval ? "Creating jobset from evaluation $eval.id of " _ makeNameTextForJobset(jobset) : + cloneJobset ? "Cloning jobset " _ makeNameTextForJobset(jobset) : + "Editing jobset " _ makeNameTextForJobset(jobset)) %] [% PROCESS common.tt %] [% USE format %] diff --git a/src/root/evals.tt b/src/root/evals.tt index 977441b3..c12079d1 100644 --- a/src/root/evals.tt +++ b/src/root/evals.tt @@ -1,6 +1,11 @@ -[% WRAPPER layout.tt title= +[% WRAPPER layout.tt + title= (build ? "Evaluations containing build $build.id" : - jobset ? "Evaluations of jobset $project.name:$jobset.name" : + jobset ? "Evaluations of jobset " _ makeNameTextForJobset(jobset) : + "Latest evaluations") + titleHTML = + (build ? "Evaluations containing build $build.id" : + jobset ? "Evaluations of jobset " _ linkToJobset(jobset) : "Latest evaluations") %] [% PROCESS common.tt %] diff --git a/src/root/job.tt b/src/root/job.tt index e8a56569..7e475f69 100644 --- a/src/root/job.tt +++ b/src/root/job.tt @@ -1,5 +1,6 @@ [% WRAPPER layout.tt - title="Job $project.name:$jobset.name:$job" + title=makeNameTextForJob(jobset, job) + titleHTML=makeNameLinksForJob(jobset, job) starUri=c.uri_for(c.controller('Job').action_for('star'), c.req.captures) %] [% PROCESS common.tt %] diff --git a/src/root/jobset-eval.tt b/src/root/jobset-eval.tt index d6f2b6d1..e1d25af1 100644 --- a/src/root/jobset-eval.tt +++ b/src/root/jobset-eval.tt @@ -1,4 +1,6 @@ -[% WRAPPER layout.tt title="Evaluation $eval.id of jobset $project.name:$jobset.name " %] +[% WRAPPER layout.tt + title="Evaluation $eval.id of jobset " _ makeNameTextForJobset(jobset) + titleHTML="Evaluation $eval.id of jobset " _ linkToJobset(jobset) %] [% PROCESS common.tt %] <div class="dropdown"> diff --git a/src/root/jobset.tt b/src/root/jobset.tt index fa85c31c..55aaf094 100644 --- a/src/root/jobset.tt +++ b/src/root/jobset.tt @@ -1,4 +1,6 @@ -[% WRAPPER layout.tt title="Jobset $project.name:$jobset.name" %] +[% WRAPPER layout.tt + titleHTML=makeNameLinksForJobset(jobset) + title=makeNameTextForJobset(jobset) %] [% PROCESS common.tt %] [% USE format %] diff --git a/src/root/layout.tt b/src/root/layout.tt index e5331ddd..8eb1f119 100644 --- a/src/root/layout.tt +++ b/src/root/layout.tt @@ -81,7 +81,8 @@ [% IF !hideHeader %] <div class="page-header"> - [% IF c.user_exists && starUri; INCLUDE makeStar; " "; END; HTML.escape(title) %] + [% IF c.user_exists && starUri; INCLUDE makeStar; " "; END %] + [% IF titleHTML != ""; titleHTML; ELSE; HTML.escape(title); END %] </div> [% ELSE %] [% IF first %]<br />[% first = 0; END; %] diff --git a/src/root/log.tt b/src/root/log.tt index fcc07d97..8bb4954d 100644 --- a/src/root/log.tt +++ b/src/root/log.tt @@ -1,4 +1,7 @@ -[% WRAPPER layout.tt title="Log of " _ (step ? " step $step.stepnr of " : "") _ "build ${build.id} of job $build.project.name:$build.jobset.name:$build.job.name" %] +[% WRAPPER layout.tt + titleHTML="Log of " _ (step ? " step $step.stepnr of " : "") _ "build ${build.id} of job " _ linkToJob(build.jobset, job) + title="Log of " _ (step ? " step $step.stepnr of " : "") _ "build ${build.id} of job " _ makeNameTextForJob(build.jobset, job) +%] [% PROCESS common.tt %] <p> diff --git a/t/View/TT.t b/t/View/TT.t new file mode 100644 index 00000000..118654fc --- /dev/null +++ b/t/View/TT.t @@ -0,0 +1,77 @@ +use feature 'unicode_strings'; +use strict; +use warnings; +use Setup; + +my %ctx = test_init(); + +require Hydra::Schema; +require Hydra::Model::DB; + +use Test2::V0; + +require Hydra; # calls setup() + + +my $db = Hydra::Model::DB->new; +hydra_setup($db); + +require Hydra::View::TT; + +# The following lines are a cheap and hacky trick to get $c, +# there is no other reason to call /. +require Catalyst::Test; +Catalyst::Test->import('Hydra'); +my($_, $c) = ctx_request('/'); + + +my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"}); +my $jobset = createBaseJobset("example", "bogus.nix", $ctx{jobsdir}); +my $job = "myjob"; + + +is( + Hydra::View::TT::linkToProject(undef, $c, $project), + '<a href="http://localhost/project/tests">tests</a>', + "linkToProject" +); +is( + Hydra::View::TT::linkToJobset(undef, $c, $jobset), + '<a href="http://localhost/project/tests">tests</a>' + . ':<a href="http://localhost/jobset/tests/example">example</a>', + "linkToJobset" +); +is( + Hydra::View::TT::linkToJob(undef, $c, $jobset, $job), + '<a href="http://localhost/project/tests">tests</a>' + . ':<a href="http://localhost/jobset/tests/example">example</a>' + . ':<a href="http://localhost/job/tests/example/myjob">myjob</a>', + "linkToJob" +); + +is( + Hydra::View::TT::makeNameLinksForJobset(undef, $c, $jobset), + '<a href="http://localhost/project/tests">tests</a>' + . ':example', + "makeNameLinksForJobset" +); +is( + Hydra::View::TT::makeNameLinksForJob(undef, $c, $jobset, $job), + '<a href="http://localhost/project/tests">tests</a>' + . ':<a href="http://localhost/jobset/tests/example">example</a>' + . ':myjob', + "makeNameLinksForJob" +); + +is( + Hydra::View::TT::makeNameTextForJobset(undef, $c, $jobset), + 'tests:example', + "makeNameTextForJobset" +); +is( + Hydra::View::TT::makeNameTextForJob(undef, $c, $jobset, $job), + 'tests:example:myjob', + "makeNameTextForJob" +); + +done_testing;