We haven't used this in many years (it was really only used for nix and patchelf releases).
N74SRHS6XG3M4II7HDCJZKFF6RFXEVGBUN3DN4FUEMELHYCGMHLQC ZQS3ZNA33VLIZJV273K2PVSAL2BDGUVAXEQ43Q4BU3GMXD4LTFGAC SLBM7H4QGAX5J25YXYZL7APK5Y3TSB4KSWCEJPF3X3KF7UG7Y3GQC 6S3ZLOZL2QXJ2PUDVFFGO4PXXNLFGVNVFQXC6CLPP3UH6WGWDFXQC GRMV5GEWXL5HRCQ5AST22ATEPO3VNF4TSJWLYT3J5GPCM2CGRK4AC ICRGXEPIPD7RFHFMBKWD7ZOAUHARG47VQH3WK3HJFYCV5ZVBQGHQC 75BCCX2TABRXQFYV73D6QU3VCT7LZUZEOWUK4X5USPWWTBTVJTLQC CUFVKLLAL54OHDMYUHVJZK46LLX7RJMUJUE5HWYDCGIOQ5TIGXZQC UUGBVEGYV3FUNL7D3ECA2DIMFHE2S5UQF4ACSLESX3M3NRYYE57AC D5QIOJGPKQJIYBUCSC3MFJ3TXLPNZ2XMI37GXMFRVRFWWR2VMTFAC KXGOUX7PH4BOXPJRYRGDS4RY7RTXYWUXCRAB5JR3BLVS62PVKOQAC AS2OXLRMJGRI64FIEM4T7EV24NZYIMPPR2EQN3SR5A2JBHVXNYXAC SU566LI3TBPIEOOXKN3HWVUMGXCCHV3AX7QTYHCAMA5QGYAKUBAQC 3PNG7NIBQQURUUPRVQXYL342OT7JUUYOMY2JJNP6YDX7SYJDZMYAC JARRBLZDQ2JZWY7IUVPTOT7WJMBPMLFLF2MGLVGOYROAAISYGLSAC RJICSUYGE5RVDXYAPCOTS436V67HB222GG6GAWEATJEQAAKDU5SAC GPHLV42M5EGNMSMFVZ54H3LY6QD5R4FE43565A7HJMI3V23FPDCAC LZVO64YG43JD7YMZSCTZNOBS5ROZA4FMPKJW2YOMHX2V5PTGBVWQC OR5SJ42Y6HYDJL3UTEXMINLNY2T3LYSVJ6FSYFMHP4K4W2RZAMIQC AWMM5OGV5EM4ZA3T3SCCU6LMKVJHKI2JANCNA236MD3O7AELE5XAC WE5Q2NVIIK4R2DUUZYLJFQVYK5O26EDEJRPK3CPGWHU3SEAC2DQAC LBNVQXUBEZ45SOTGVXK5UEZXIAIZTJLWZNUYFI4JZ6J65N3KPDVQC Z6MDQIGODVE7RXX5U5D64EEC2ZDEZ36Z4ZMPFYIHWBG42IXUDYFQC GJFYEU3SVP7TDSYXVZEYGKN4NVWSZX4754PPPTOYPRHUO5RMDWPQC PMNWRTGJ4GVSMSSAWSUD57B26PCRAHMZIQ5SIWJIK7A74ENKEQLAC KRVD4EW7JPDBJJKOD7TM2PATKNKOFMEJESWP5RCISNAI2ZNK424QC UOINKJ2JBCRTZPFTAXDPRJOEUWWPJ43IGVWLRIRLIGHLBMWDOGDQC WRIU3S5EO3RB3IM5PUDNHLOOMUPD5UKWNUL4YMAKD3C6O4KELJCAC KQZQI2WNMXADNASI7OOMB56OOSBAARTI5ZWY52TUVHHJW6D2HMVAC U4TD3AIQXBJFFUORTMIC4IHZTVBORRKL2TZ2FSP4G665ECZOEMNAC K63JYJDHWZF2STHFTA2GLRQAGMHMATYBSLLGLJS7BTOP6YZPREDAC 6HWIUOSURE7QRA7AUY2Y6CSNWYV36CAXCZ6I6QU24U7GBZ3ODD5AC BKOIYITRBRVU4D7XFAZPV5QHAPCBMIO3SBNHYJ6TVT43WR32CTHQC FPK5LF53CFUEKFYJ3IYXT4UTVC6IITWJOCFATMC4PLHEUP5SIEAAC RBNQKATLSAKTGW2IRNB5CRV3SEH5F6E4BPVWX4BII7MH5TCIPINQC SB2V735VJ2CDHGCXRUA5FOYHDRXQFVOZ3KXC3YKXWRNW6DIX7RXQC 3HCBU2FAXZMSF4JJR5Q64BSN66MBOGVETNHK33V2WSNDGOF4HHQAC JM3DPYOMVNMCL5GMEYC3Y4NDRGTNIFBBFTPGPVT66GPENVPU7EVQC IGR322YPZG7IX33I6CSF4ZIHFKXCT4ERC2LC73MW6PN7W53D73BAC Y6AHH4THYQA43V77L43YM42DYRPCMDSWLUV4NKWAQYMPL4NTUIPQC JTRG7RDQXKPSO4ESGDLSVAT5WIFGKDL424MN6YYCVTKCOR2FTXRQC J5UVLXOK6EDIL5I7VKWH4V2QDS4DPD7FHRK6XBWSXFRQS4JKXFZQC CLJQCY2XHIDNNMFBJ5PK3GQEN6RFALEFKXBJRWZPEIKR4PR5ZQ5AC PHX2HIVGHHKCAX6VNN2WXD4LRGSA74KQMJCCTMHK7HS6JPELVECAC RFE6T5LGBFFNEPHZOPF4UNMFC2L4CGD5TPAMOXDLRPH3TZJ43UBAC FTPCV25MOLQUNR5CAR453W7T7QTUZRLPLEOSDZ5HSDFAXQZVHOYQC L2E6EVE2RVFVDCUNRJ4CZYSQNS2DZUA5DTBETHBDUQUV2KQQRAOQC ECBA3GQOGTF73Y7A5EFUXZ5PDIZ5NPJM3WMOUJTE3AEK2PZQX3MQC FHF6IZJQPUQHY5QWQYRPZVDBRLHREWRHGNKVQDT7F3GQKKLZXJKQC X27GNHDV5KPZ5GSH6DCAJMNCEMZLCP7M43JWF2X3O5QWXMOX273AC P5X4P6VKS5CJOOLJRVL66GRJLDLVC3EKAVAHP2RJOXQJ7WTYAUBQC KSBB33RE2PK5SFN7ZMOTZJQHZB4JYIIUUKWDSD3LSZ5GD465AJHQC 7ECJWNVXNO3BKM7B7FIFIRBE77QET5PK2C3XKVQUXCYKHDP3V4UQC PZL3SZM3U3BYJX2RGYXC6NMBG7WQHFWHSYDYXZ7Q5VZA3EDYVPIQC OW6XV2YSTYTBR5JO4FKCYAH44WX5UI2HUPIM6UIEQF7SPV7RLQFQC 2G63HKCHG7S6DGWDOHSDF7PXFPD6H4TRKDKIIFCXXAKET6FCWN2AC JIJDYWPYMZZNFBCWYSYR72RNEW5MSI26MJ5UXXIU7DDX25IBR3CQC JLICHVE674VIYYLAKDWYO7RZ7YREVPDYR3DRRJ57DXR2OVHP34CQC 2R7GHSA4NUXPRWRPVXYDYWFIVVJGSUWUI2IPJGFN6ILZIAZGXGCAC 2GUAKGTBTNFFER343SQWSLFYIXXHJLDSGH5JHF7QMC3AVZB7Q3TQC ZI535LI6PJMKSOBJE33B3RRZ5S2JVTR3XPUDTSXJW6BZNTAHS3GQC ASIRNHAHLLITDIL4T6OTHA3AERVAO2GP3SFFPLZGT63NGDW3ZLNQC XTKCALUAJ2EKYO6ZQDLRDCDLCM5NAMUJ5BB3N6XIY32Q6YOJTB5QC 6WRGCITDYP7JIBYP25QIWCHWRJWFPDP2D3TJS3WO3KUHQQJAWHMQC 77BG3TYKSKVV6C6VDJH7JDRJRPRNNBAO2OH4YZ6JY5Q5OP3VGXFQC 7YBYT2LQML2PKEO6UO4444AGSASS664UCDXW2YO3ALB7THQHCEBQC 225GEK4NN53NJ6EBDAJNECR76FILAHV7KNEG23TDQ2KYMG7NFEUAC JY7BXXOP3EZCDT5RSMVE4Y6IECXGYL4GEBJOZHR7H3Z35XZ3NIVQC W6DC6K4INJQOJYR553ISCKZV7YIOGHEM3FZQPOLAPSZQ3KSJDMRQC 2VBQRQ2QUNM3ZC7I7WAXYSUVPP52IY2KLE4CVS3E4MAHL2T42KKQC ODNCGFQ5FPKFI624BVMLW7PJ2EFJOR3TY66OCZM42UNNTWBCF2TQC VG4QG336SCZNWAXJERI3N5FO6PUAYFJV24CLI27ADUFPO74RVJKQC BIVZGPUTQ2C7X6NJQMVIDDO2OYNO4R3GROGQAWBVNSK2HSZ3REOQC ACFFJUAN5R2AFJVVJ5OBX6BQHT3M4SHO7QXILF5LURVIFPDORLIQC KJQWSRCCQEKF64L4NYYZ7VKAF2YEPYXXTRW6BI464P6Q6KU34TQAC WZ3AEJ67LOG5L335AAC2BDLIJPIU4VSCGBMATBHDZC26ECRS5A6AC SZPBGW2NVHOOW4E3VIB2B35V7YRF67DFVVGUK573LVD574IHSA6AC 6BLUKEQ2M5RGWMPXPYIFIEVEUBV4PYAZ75S2WSBIATMRGYFMQZHQC N22GPKYTOLZLBGTGDATQDVZ4R5APZEAOIA7L32X4UXBH4XNI7MWAC T2232OBSNVDGHY46RY5BBB2IET5LV5OLKSSBDYUF7KAEDBUOTC7QC 5SHCWE7XPQORSOLY7HGAIK2ODKBFPY4KVXRL2W7X6D4WALU544HQC E2TOU3L66CH5DA4XPATQM5YM63SFXX63V7SDOIGS4ND3GR7HQALAC 34DPX2ORV3XDB7M3NYVZLU6MYDIFCIC5NHPJW7N5ITS356GWVMCAC 4S5JF5JPKWTDYHFJMTXOFTDAMYHD5ON2UBTLMGVYPJCP6QYIM2EAC * Creating a release set:insert into ReleaseSets(project, name) values('patchelf', 'unstable');insert into ReleaseSetJobs(isPrimary, project, release, job, attrs, description) values(1, 'patchelf', 'unstable', 'tarball', 'officialRelease=false', 'Source distribution');insert into ReleaseSetJobs(project, release, job, attrs, description) values('patchelf', 'unstable', 'build', 'system=i686-linux', 'Build on i686-linux');insert into ReleaseSetJobs(project, release, job, attrs, description) values('patchelf', 'unstable', 'build', 'system=x86_64-linux', 'Build on x86_64-linux');insert into ReleaseSetJobs(project, release, job, attrs, description, mayFail) values('patchelf', 'unstable', 'rpm_fedora9i386', '', 'Fedora 9 (i386)', 1);insert into ReleaseSetJobs(project, release, job, attrs, description) values('patchelf', 'unstable', 'rpm_fedora10i386', '', 'Fedora 10 (i386)');insert into ReleaseSetJobs(project, release, job, attrs, description) values('patchelf', 'unstable', 'deb_ubuntu804i386', '', 'Ubuntu 8.04 (i386)');
insert into ReleaseSets(project, name) values('patchelf', 'stable');insert into ReleaseSetJobs(isPrimary, project, release, job, attrs, description) values(1, 'patchelf', 'stable', 'tarball', 'officialRelease=true', 'Source distribution');insert into ReleaseSetJobs(project, release, job, attrs, description) values('patchelf', 'stable', 'build', 'system=i686-linux', 'Build on i686-linux');insert into ReleaseSetJobs(project, release, job, attrs, description) values('patchelf', 'stable', 'build', 'system=x86_64-linux', 'Build on x86_64-linux');insert into ReleaseSetJobs(project, release, job, attrs, description, mayFail) values('patchelf', 'stable', 'rpm_fedora9i386', '', 'Fedora 9 (i386)', 1);insert into ReleaseSetJobs(project, release, job, attrs, description) values('patchelf', 'stable', 'rpm_fedora10i386', '', 'Fedora 10 (i386)');insert into ReleaseSetJobs(project, release, job, attrs, description) values('patchelf', 'stable', 'deb_ubuntu804i386', '', 'Ubuntu 8.04 (i386)');
package Hydra::Controller::Release;use strict;use warnings;use base 'Catalyst::Controller';use Hydra::Helper::Nix;use Hydra::Helper::CatalystUtils;sub release : Chained('/') PathPart('release') CaptureArgs(2) {my ($self, $c, $projectName, $releaseName) = @_;$c->stash->{project} = $c->model('DB::Projects')->find($projectName)or notFound($c, "Project $projectName doesn't exist.");$c->stash->{release} = $c->stash->{project}->releases->find({name => $releaseName})or notFound($c, "Release $releaseName doesn't exist.");}sub view : Chained('release') PathPart('') Args(0) {my ($self, $c) = @_;$c->stash->{template} = 'release.tt';}sub updateRelease {my ($c, $release) = @_;my $releaseName = trim $c->request->params->{name};error($c, "Invalid release name: $releaseName")unless $releaseName =~ /^$relNameRE$/;$release->update({ name => $releaseName, description => trim $c->request->params->{description}});}1;sub submit : Chained('release') PathPart('submit') Args(0) {my ($self, $c) = @_;requireProjectOwner($c, $c->stash->{project});if (($c->request->params->{action} || "") eq "delete") {$c->model('DB')->schema->txn_do(sub {$c->stash->{release}->delete;});$c->res->redirect($c->uri_for($c->controller('Project')->action_for('project'),[$c->stash->{project}->name]));} else {$c->model('DB')->schema->txn_do(sub {updateRelease($c, $c->stash->{release});});$c->res->redirect($c->uri_for($self->action_for("view"),[$c->stash->{project}->name, $c->stash->{release}->name]));}}}sub edit : Chained('release') PathPart('edit') Args(0) {my ($self, $c) = @_;requireProjectOwner($c, $c->stash->{project});$c->stash->{template} = 'edit-release.tt';$c->stash->{members} = [$c->stash->{release}->releasemembers->search({},{order_by => ["description"]})];$release->releasemembers->delete;foreach my $param (keys %{$c->request->params}) {next unless $param =~ /^member-(\d+)-description$/;my $buildId = $1;my $description = trim $c->request->params->{"member-$buildId-description"};$release->releasemembers->create({ build => $buildId, description => $description });}$c->stash->{members} = [$c->stash->{release}->releasemembers->search({},{order_by => ["description"]})];
my $releaseName = trim $c->request->params->{name};my $release = $build->project->releases->find({name => $releaseName});error($c, "This project has no release named `$releaseName'.") unless $release;error($c, "This build is already a part of release `$releaseName'.")if $release->releasemembers->find({build => $build->id});foreach my $output ($build->buildoutputs) {error($c, "This build is no longer available.") unless isValidPath $output->path;registerRoot $output->path;}$release->releasemembers->create({build => $build->id, description => $build->description});$c->flash->{successMsg} = "Build added to project <tt>$releaseName</tt>.";$c->res->redirect($c->uri_for($self->action_for("build"), $c->req->captures));}
}sub release : Chained('evalChain') PathPart('release') Args(0) {my ($self, $c) = @_;my $eval = $c->stash->{eval};requireProjectOwner($c, $c->stash->{project});my @builds = $eval->builds;my $releaseName;$releaseName ||= $_->releasename foreach @builds;# If no release name has been defined by any of the builds, compose one of the project name and evaluation id$releaseName = $eval->get_column('project') . "-" . $eval->id unless defined $releaseName;my $release;$c->model('DB')->schema->txn_do(sub {$release = $c->stash->{project}->releases->create({ name => $releaseName, timestamp => time});foreach my $build (@builds) {$release->releasemembers->create({ build => $build->id, description => $build->description}) if $build->buildstatus == 0;}});$c->res->redirect($c->uri_for($c->controller('Release')->action_for('view'),[$c->stash->{project}->name, $release->name]));
sub create_release : Chained('projectChain') PathPart('create-release') Args(0) {my ($self, $c) = @_;requireProjectOwner($c, $c->stash->{project});$c->stash->{template} = 'edit-release.tt';$c->stash->{create} = 1;}sub create_release_submit : Chained('projectChain') PathPart('create-release/submit') Args(0) {my ($self, $c) = @_;requireProjectOwner($c, $c->stash->{project});my $releaseName = $c->request->params->{name};my $release;$c->model('DB')->schema->txn_do(sub {# Note: $releaseName is validated in updateRelease, which will# abort the transaction if the name isn't valid.$release = $c->stash->{project}->releases->create({ name => $releaseName, timestamp => time});Hydra::Controller::Release::updateRelease($c, $release);});$c->res->redirect($c->uri_for($c->controller('Release')->action_for('view'),[$c->stash->{project}->name, $release->name]));}
use utf8;package Hydra::Schema::ReleaseMembers;# Created by DBIx::Class::Schema::Loader# DO NOT MODIFY THE FIRST PART OF THIS FILE=head1 NAMEHydra::Schema::ReleaseMembers=cutuse strict;use warnings;use base 'DBIx::Class::Core';=head1 COMPONENTS LOADED=over 4=item * L<Hydra::Component::ToJSON>=back=cut__PACKAGE__->load_components("+Hydra::Component::ToJSON");=head1 TABLE: C<releasemembers>=cut__PACKAGE__->table("releasemembers");=head1 ACCESSORS=head2 projectdata_type: 'text'is_foreign_key: 1is_nullable: 0=head2 release_data_type: 'text'is_foreign_key: 1is_nullable: 0=head2 builddata_type: 'integer'is_foreign_key: 1is_nullable: 0=head2 descriptiondata_type: 'text'is_nullable: 1=cut__PACKAGE__->add_columns("project",{ data_type => "text", is_foreign_key => 1, is_nullable => 0 },"release_",{ data_type => "text", is_foreign_key => 1, is_nullable => 0 },"build",{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },"description",{ data_type => "text", is_nullable => 1 },);=head1 PRIMARY KEY=over 4=item * L</project>=item * L</release_>=item * L</build>=back=cut__PACKAGE__->set_primary_key("project", "release_", "build");=head1 RELATIONS=head2 buildType: belongs_toRelated object: L<Hydra::Schema::Builds>=cut__PACKAGE__->belongs_to("build","Hydra::Schema::Builds",{ id => "build" },{ is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },);=head2 projectType: belongs_toRelated object: L<Hydra::Schema::Projects>=cut__PACKAGE__->belongs_to("project","Hydra::Schema::Projects",{ name => "project" },{ is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },);=head2 releaseType: belongs_toRelated object: L<Hydra::Schema::Releases>=cut__PACKAGE__->belongs_to("release","Hydra::Schema::Releases",{ name => "release_", project => "project" },{ is_deferrable => 0, on_delete => "CASCADE", on_update => "CASCADE" },);# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-02-06 12:22:36# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:k4z2YeB4gRAeAP6hmR93sQ1;
use utf8;package Hydra::Schema::Releases;# Created by DBIx::Class::Schema::Loader# DO NOT MODIFY THE FIRST PART OF THIS FILE=head1 NAMEHydra::Schema::Releases=cutuse strict;use warnings;use base 'DBIx::Class::Core';=head1 COMPONENTS LOADED=over 4=item * L<Hydra::Component::ToJSON>=back=cut__PACKAGE__->load_components("+Hydra::Component::ToJSON");=cut__PACKAGE__->table("releases");=head1 ACCESSORS=head2 projectdata_type: 'text'is_foreign_key: 1is_nullable: 0=head2 namedata_type: 'text'is_nullable: 0=head2 timestampdata_type: 'integer'is_nullable: 0=head2 descriptiondata_type: 'text'is_nullable: 1=cut__PACKAGE__->add_columns("project",{ data_type => "text", is_foreign_key => 1, is_nullable => 0 },"name",{ data_type => "text", is_nullable => 0 },"timestamp",{ data_type => "integer", is_nullable => 0 },"description",{ data_type => "text", is_nullable => 1 },);=head1 PRIMARY KEY=over 4=item * L</project>=item * L</name>=back=cut__PACKAGE__->set_primary_key("project", "name");=head1 RELATIONS=head2 projectType: belongs_toRelated object: L<Hydra::Schema::Projects>=cut__PACKAGE__->belongs_to("project","Hydra::Schema::Projects",{ name => "project" },{ is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },);=head2 releasemembersType: has_manyRelated object: L<Hydra::Schema::ReleaseMembers>=cut__PACKAGE__->has_many("releasemembers","Hydra::Schema::ReleaseMembers",{"foreign.project" => "self.project","foreign.release_" => "self.name",},undef,);# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-02-06 12:22:36# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:b4M/tHOhsy234tgTf+wqjQ1;=head1 TABLE: C<releases>
=head2 releasemembersType: has_manyRelated object: L<Hydra::Schema::ReleaseMembers>
=cut__PACKAGE__->has_many("releasemembers","Hydra::Schema::ReleaseMembers",{ "foreign.build" => "self.id" },undef,);
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-02-06 12:34:25# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:EEXlcKN/ydXJ129vT0jTUw
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-05-06 12:32:57# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:3IyFj/9Zf/hvmhBY4U/IBQ
{ "foreign.project" => "self.name" },undef,);=head2 releasemembersType: has_manyRelated object: L<Hydra::Schema::ReleaseMembers>=cut__PACKAGE__->has_many("releasemembers","Hydra::Schema::ReleaseMembers",
Type: has_manyRelated object: L<Hydra::Schema::Releases>=cut__PACKAGE__->has_many("releases","Hydra::Schema::Releases",{ "foreign.project" => "self.name" },undef,);
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-02-06 12:22:36# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:pcF/8351zyo9VL6N5eimdQ
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-05-06 12:32:57# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dEIVgrFGilPfITprs6nYuA
[% WRAPPER layout.tt title="Release $release.name" %][% PROCESS common.tt %][% USE HTML %]<p><em>Released on [% INCLUDE renderDateTime timestamp =release.timestamp %].</em> <a class="btn" href="[% c.uri_for('/release' project.name release.name "edit") %]"><i class="icon-edit"></i></a></p>[% IF !members %]<p><em>No builds have been added to this release yet.</em></p>[% ELSE %][% FOREACH m IN members %]<h3><a href="[% c.uri_for('/build' m.build.id) %]">[% HTML.escape(m.description) %]</a></h3>[% INCLUDE renderProductList build=m.build %][% END %][% END %][% END %][% PROCESS "product-list.tt" %]
[% WRAPPER layout.tt title=(create ? "New release" : "Edit release ${release.name}") %][% PROCESS common.tt %][% USE HTML %]<form class="form-horizontal" action="[% IF create %][% c.uri_for('/project' project.name 'create-release/submit') %][% ELSE %][% c.uri_for('/release' project.name release.name 'submit') %][% END %]" method="post"><fieldset><div class="control-group"><label class="control-label">Identifier</label><div class="controls"><input type="text" class="span3" name="name" [% HTML.attributes(value => release.name) %]/></div></div><div class="control-group"><label class="control-label">Description</label><div class="controls"><input type="text" class="span3" name="description" [% HTML.attributes(value => release.description) %]/></div></div><h3>Release members</h3><p><em>Note:</em> to add a build to this release, go to the build’sinformation page and click on “Add to release”.</p>[% FOREACH m IN members %]<div class="releaseMember control-group"><label class="control-label">Build [% m.build.id %] Label</label><div class="controls"><input type="text" class="span3" name="member-[% m.build.id %]-description" [% HTML.attributes(value => m.description) %]/><button class="btn btn-warning" type="button" onclick='$(this).parents(".releaseMember").remove()'><i class="icon-trash icon-white"></i></button></div></div>[% END %]<div class="form-actions"><button type="submit" class="btn btn-primary"><i class="icon-ok icon-white"></i>[%IF create %]Create[% ELSE %]Apply changes[% END %]</button>[% IF !create %]<button id="delete-release" type="submit" class="btn btn-danger" name="action" value="delete"><i class="icon-trash icon-white"></i>Delete this release</button><script type="text/javascript">$("#delete-release").click(function() {return confirm("Are you sure you want to delete this release?");});</script>[% END %]</div></fieldset></form>[% END %]
[% IF c.user_exists && available && project.releases %]<div id="add-to-release" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true"><form class="form-horizontal" action="[% c.uri_for('/build' build.id 'add-to-release') %]" method="post"><div class="modal-body"><div class="control-group"><label class="control-label">Add to release</label><div class="controls"><select class="span2" name="name">[% FOREACH r IN project.releases %]<option>[% HTML.escape(r.name) %]</option>[% END %]</select></div></div></div><div class="modal-footer"><button type="submit" class="btn btn-primary">Add</button><button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button></div></form>
<div id="tabs-releases" class="tab-pane">[% IF releases.size == 0 %]<p><em>This project has no releases yet.</em></p>[% ELSE %]<p>This project has made the following releases:</p><table class="table table-condensed table-striped clickable-rows"><thead><tr><th>Name</th><th>Date</th></tr></thead><tbody>[% FOREACH release IN releases %]<tr><td><a class="row-link" href="[% c.uri_for('/release' project.name release.name) %]"><tt>[% release.name %]</tt></a></td><td>[% INCLUDE renderDateTime timestamp = release.timestamp %]</td></tr>[% END %]</tbody></table>[% END %]</div>
# Keep every build in every release of every project.print STDERR "*** looking for release members\n";keepBuild($_, 0) foreach $db->resultset('Builds')->search_literal("exists (select 1 from releasemembers where build = me.id)",{ order_by => ["project", "jobset", "job", "id"], columns => [ @columns ] });
-- A release is a named set of builds. The ReleaseMembers table lists-- the builds that constitute each release.create table Releases (project text not null,name text not null,timestamp integer not null,description text,primary key (project, name),foreign key (project) references Projects(name) on delete cascade);create table ReleaseMembers (project text not null,release_ text not null,build integer not null,description text,primary key (project, release_, build),foreign key (project) references Projects(name) on delete cascade on update cascade,foreign key (project, release_) references Releases(project, name) on delete cascade on update cascade,foreign key (build) references Builds(id));