diff options
Diffstat (limited to 'extensions/TryAutoLand')
13 files changed, 946 insertions, 0 deletions
diff --git a/extensions/TryAutoLand/Config.pm b/extensions/TryAutoLand/Config.pm new file mode 100644 index 000000000..8b299183b --- /dev/null +++ b/extensions/TryAutoLand/Config.pm @@ -0,0 +1,19 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::TryAutoLand; +use strict; + +use constant NAME => 'TryAutoLand'; + +use constant REQUIRED_MODULES => [ +]; + +use constant OPTIONAL_MODULES => [ +]; + +__PACKAGE__->NAME; diff --git a/extensions/TryAutoLand/Extension.pm b/extensions/TryAutoLand/Extension.pm new file mode 100644 index 000000000..40dbb70d9 --- /dev/null +++ b/extensions/TryAutoLand/Extension.pm @@ -0,0 +1,323 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::TryAutoLand; + +use strict; + +use base qw(Bugzilla::Extension); + +use Bugzilla::Bug; +use Bugzilla::Attachment; +use Bugzilla::User; +use Bugzilla::Util qw(trick_taint diff_arrays); +use Bugzilla::Error; + +use Bugzilla::Extension::TryAutoLand::Constants; + +our $VERSION = '0.01'; + +BEGIN { + *Bugzilla::Bug::autoland_branches = \&_autoland_branches; + *Bugzilla::Bug::autoland_try_syntax = \&_autoland_try_syntax; + *Bugzilla::Attachment::autoland_checked = \&_autoland_attachment_checked; + *Bugzilla::Attachment::autoland_who = \&_autoland_attachment_who; + *Bugzilla::Attachment::autoland_status = \&_autoland_attachment_status; + *Bugzilla::Attachment::autoland_status_when = \&_autoland_attachment_status_when; + *Bugzilla::Attachment::autoland_update_status = \&_autoland_attachment_update_status; + *Bugzilla::Attachment::autoland_remove = \&_autoland_attachment_remove; +} + +sub db_schema_abstract_schema { + my ($self, $args) = @_; + $args->{'schema'}->{'autoland_branches'} = { + FIELDS => [ + bug_id => { + TYPE => 'INT3', + NOTNULL => 1, + PRIMARYKEY => 1, + REFERENCES => { + TABLE => 'bugs', + COLUMN => 'bug_id', + DELETE => 'CASCADE' + } + }, + branches => { + TYPE => 'VARCHAR(255)', + NOTNULL => 1 + }, + try_syntax => { + TYPE => 'VARCHAR(255)', + NOTNULL => 1, + DEFAULT => "''", + } + ], + }; + + $args->{'schema'}->{'autoland_attachments'} = { + FIELDS => [ + attach_id => { + TYPE => 'INT3', + NOTNULL => 1, + PRIMARYKEY => 1, + REFERENCES => { + TABLE => 'attachments', + COLUMN => 'attach_id', + DELETE => 'CASCADE' + }, + }, + who => { + TYPE => 'INT3', + NOTNULL => 1, + REFERENCES => { + TABLE => 'profiles', + COLUMN => 'userid', + }, + }, + status => { + TYPE => 'varchar(64)', + NOTNULL => 1 + }, + status_when => { + TYPE => 'DATETIME', + NOTNULL => 1, + }, + ], + }; +} + +sub install_update_db { + my ($self) = @_; + my $dbh = Bugzilla->dbh; + + if (!$dbh->bz_column_info('autoland_branches', 'try_syntax')) { + $dbh->bz_add_column('autoland_branches', 'try_syntax', { + TYPE => 'VARCHAR(255)', + NOTNULL => 1, + DEFAULT => "''", + }); + } +} + +sub _autoland_branches { + my $self = shift; + return $self->{'autoland_branches'} if exists $self->{'autoland_branches'}; + _preload_bug_data($self); + return $self->{'autoland_branches'}; +} + +sub _autoland_try_syntax { + my $self = shift; + return $self->{'autoland_try_syntax'} if exists $self->{'autoland_try_syntax'}; + _preload_bug_data($self); + return $self->{'autoland_try_syntax'}; +} + +sub _preload_bug_data { + my ($self) = @_; + my $dbh = Bugzilla->dbh; + my $result = $dbh->selectrow_hashref("SELECT branches, try_syntax FROM autoland_branches + WHERE bug_id = ?", { Slice => {} }, $self->id); + if ($result) { + $self->{'autoland_branches'} = $result->{'branches'}; + $self->{'autoland_try_syntax'} = $result->{'try_syntax'}; + } + else { + $self->{'autoland_branches'} = undef; + $self->{'autoland_try_syntax'} = undef; + } +} + +sub _autoland_attachment_checked { + my $self = shift; + my $dbh = Bugzilla->dbh; + return $self->{'autoland_checked'} if exists $self->{'autoland_checked'}; + my $result = $dbh->selectrow_hashref("SELECT who, status, status_when + FROM autoland_attachments + WHERE attach_id = ?", { Slice => {} }, $self->id); + if ($result) { + $self->{'autoland_checked'} = 1; + $self->{'autoland_who'} = Bugzilla::User->new($result->{'who'}); + $self->{'autoland_status'} = $result->{'status'}; + $self->{'autoland_status_when'} = $result->{'status_when'}; + } + else { + $self->{'autoland_checked'} = 0; + $self->{'autoland_who'} = undef; + $self->{'autoland_status'} = undef; + $self->{'autoland_status_when'} = undef; + } + return $self->{'autoland_checked'}; +} + +sub _autoland_attachment_who { + my $self = shift; + return undef if !$self->autoland_checked; + return $self->{'autoland_who'}; +} + +sub _autoland_attachment_status { + my $self = shift; + return undef if !$self->autoland_checked; + return $self->{'autoland_status'}; +} + +sub _autoland_attachment_status_when { + my $self = shift; + return undef if !$self->autoland_checked; + return $self->{'autoland_status_when'}; +} + +sub _autoland_attachment_update_status { + my ($self, $status) = @_; + my $dbh = Bugzilla->dbh; + + return undef if !$self->autoland_checked; + + grep($_ eq $status, VALID_STATUSES) + || ThrowUserError('autoland_invalid_status', + { status => $status, + valid => [ VALID_STATUSES ] }); + + if ($self->autoland_status ne $status) { + my $timestamp = $dbh->selectrow_array("SELECT LOCALTIMESTAMP(0)"); + trick_taint($status); + $dbh->do("UPDATE autoland_attachments SET status = ?, status_when = ? + WHERE attach_id = ?", undef, $status, $timestamp, $self->id); + $self->{'autoland_status'} = $status; + $self->{'autoland_status_when'} = $timestamp; + } + + return 1; +} + +sub _autoland_attachment_remove { + my ($self) = @_; + my $dbh = Bugzilla->dbh; + return undef if !$self->autoland_checked; + $dbh->do("DELETE FROM autoland_attachments WHERE attach_id = ?", undef, $self->id); + delete $self->{'autoland_checked'}; + delete $self->{'autoland_who'}; + delete $self->{'autoland_status'}; + delete $self->{'autoland_status_when'}; +} + +sub object_end_of_update { + my ($self, $args) = @_; + my $object = $args->{'object'}; + my $user = Bugzilla->user; + my $dbh = Bugzilla->dbh; + my $cgi = Bugzilla->cgi; + my $params = Bugzilla->input_params; + + return if !$user->in_group('autoland'); + + if ($object->isa('Bugzilla::Bug')) { + # First make any needed changes to the branches and try_syntax fields + my $bug_id = $object->bug_id; + my $bug_result = $dbh->selectrow_hashref("SELECT branches, try_syntax + FROM autoland_branches + WHERE bug_id = ?", + { Slice => {} }, $bug_id); + + my $old_branches = ''; + my $old_try_syntax = ''; + if ($bug_result) { + $old_branches = $bug_result->{'branches'}; + $old_try_syntax = $bug_result->{'try_syntax'}; + } + + my $new_branches = $params->{'autoland_branches'} || ''; + my $new_try_syntax = $params->{'autoland_try_syntax'} || ''; + + my $set_attachments = []; + if (ref $params->{'autoland_attachments'}) { + $set_attachments = $params->{'autoland_attachments'}; + } elsif ($params->{'autoland_attachments'}) { + $set_attachments = [ $params->{'autoland_attachments'} ]; + } + + # Check for required values + (!$new_branches && @{$set_attachments}) + && ThrowUserError('autoland_empty_branches'); + ($new_branches && !$new_try_syntax) + && ThrowUserError('autoland_empty_try_syntax'); + + trick_taint($new_branches); + if (!$new_branches && $old_branches) { + $dbh->do("DELETE FROM autoland_branches WHERE bug_id = ?", + undef, $bug_id); + } + elsif ($new_branches && !$old_branches) { + $dbh->do("INSERT INTO autoland_branches (bug_id, branches) + VALUES (?, ?)", undef, $bug_id, $new_branches); + } + elsif ($old_branches ne $new_branches) { + $dbh->do("UPDATE autoland_branches SET branches = ? WHERE bug_id = ?", + undef, $new_branches, $bug_id); + } + + trick_taint($new_try_syntax); + if (($old_try_syntax ne $new_try_syntax) && $new_branches) { + $dbh->do("UPDATE autoland_branches SET try_syntax = ? WHERE bug_id = ?", + undef, $new_try_syntax, $bug_id); + } + + # Next make any changes needed to each of the attachments. + # 1. If an attachment is checked it has a row in the table, if + # there is no row in the table it is not checked. + # 2. Do not allow changes to checked state if status == 'running' or status == 'waiting' + my $check_attachments = ref $params->{'defined_autoland_attachments'} + ? $params->{'defined_autoland_attachments'} + : [ $params->{'defined_autoland_attachments'} ]; + my ($removed_attachments) = diff_arrays($check_attachments, $set_attachments); + foreach my $attachment (@{$object->attachments}) { + next if !$attachment->ispatch; + my $attach_id = $attachment->id; + + my $checked = (grep $_ == $attach_id, @$set_attachments) ? 1 : 0; + my $unchecked = (grep $_ == $attach_id, @$removed_attachments) ? 1 : 0; + my $old_checked = $dbh->selectrow_array("SELECT 1 FROM autoland_attachments + WHERE attach_id = ?", undef, $attach_id) || 0; + + next if $checked && $old_checked; + + if ($unchecked && $old_checked && $attachment->autoland_status =~ /^(failed|success)$/) { + $dbh->do("DELETE FROM autoland_attachments WHERE attach_id = ?", undef, $attach_id); + } + elsif ($checked && !$old_checked) { + $dbh->do("INSERT INTO autoland_attachments (attach_id, who, status, status_when) + VALUES (?, ?, 'waiting', now())", undef, $attach_id, $user->id); + } + } + + } +} + +sub template_before_process { + my ($self, $args) = @_; + my $file = $args->{'file'}; + my $vars = $args->{'vars'}; + + # in the header we just need to set the var to ensure the css gets included + if ($file eq 'bug/show-header.html.tmpl' && Bugzilla->user->in_group('autoland') ) { + $vars->{'autoland'} = 1; + } + + if ($file eq 'bug/edit.html.tmpl') { + $vars->{'autoland_default_try_syntax'} = DEFAULT_TRY_SYNTAX; + } +} + +sub webservice { + my ($self, $args) = @_; + + my $dispatch = $args->{dispatch}; + $dispatch->{TryAutoLand} = "Bugzilla::Extension::TryAutoLand::WebService"; +} + +__PACKAGE__->NAME; diff --git a/extensions/TryAutoLand/bin/TryAutoLand.getBugs.pl b/extensions/TryAutoLand/bin/TryAutoLand.getBugs.pl new file mode 100755 index 000000000..5d05831a8 --- /dev/null +++ b/extensions/TryAutoLand/bin/TryAutoLand.getBugs.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl -w +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use XMLRPC::Lite; +use Data::Dumper; +use HTTP::Cookies; + +################################### +# Need to login first # +################################### + +my $username = shift; +my $password = shift; + +my $cookie_jar = new HTTP::Cookies( file => "/tmp/lwp_cookies.dat" ); + +my $rpc = new XMLRPC::Lite; + +$rpc->proxy('http://fedora/726193/xmlrpc.cgi'); + +$rpc->encoding('UTF-8'); + +$rpc->transport->cookie_jar($cookie_jar); + +my $call = $rpc->call( 'User.login', + { login => $username, password => $password } ); + +if ( $call->faultstring ) { + print $call->faultstring . "\n"; + exit; +} + +# Save the cookies in the cookie file +$rpc->transport->cookie_jar->extract_cookies( + $rpc->transport->http_response ); +$rpc->transport->cookie_jar->save; + +print "Successfully logged in.\n"; + +################################### +# Main call here # +################################### + +$call = $rpc->call('TryAutoLand.getBugs', { status => [] }); + +my $result = ""; +if ( $call->faultstring ) { + print $call->faultstring . "\n"; + exit; +} +else { + $result = $call->result; +} + +print Dumper($result); diff --git a/extensions/TryAutoLand/bin/TryAutoLand.updateStatus.pl b/extensions/TryAutoLand/bin/TryAutoLand.updateStatus.pl new file mode 100755 index 000000000..4a8f92089 --- /dev/null +++ b/extensions/TryAutoLand/bin/TryAutoLand.updateStatus.pl @@ -0,0 +1,65 @@ +#!/usr/bin/perl -w +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +use XMLRPC::Lite; +use Data::Dumper; +use HTTP::Cookies; + +################################### +# Need to login first # +################################### + +my $username = shift; +my $password = shift; + +my $cookie_jar = new HTTP::Cookies( file => "/tmp/lwp_cookies.dat" ); + +my $rpc = new XMLRPC::Lite; + +$rpc->proxy('http://fedora/726193/xmlrpc.cgi'); + +$rpc->encoding('UTF-8'); + +$rpc->transport->cookie_jar($cookie_jar); + +my $call = $rpc->call( 'User.login', + { login => $username, password => $password } ); + +if ( $call->faultstring ) { + print $call->faultstring . "\n"; + exit; +} + +# Save the cookies in the cookie file +$rpc->transport->cookie_jar->extract_cookies( + $rpc->transport->http_response ); +$rpc->transport->cookie_jar->save; + +print "Successfully logged in.\n"; + +################################### +# Main call here # +################################### + +my $attach_id = shift; +my $action = shift; +my $status = shift; + +$call = $rpc->call('TryAutoLand.update', + { attach_id => $attach_id, action => $action, status => $status }); + +my $result = ""; +if ( $call->faultstring ) { + print $call->faultstring . "\n"; + exit; +} +else { + $result = $call->result; +} + +print Dumper($result); diff --git a/extensions/TryAutoLand/bin/TryAutoLand.updateStatus_json.pl b/extensions/TryAutoLand/bin/TryAutoLand.updateStatus_json.pl new file mode 100755 index 000000000..f39b55229 --- /dev/null +++ b/extensions/TryAutoLand/bin/TryAutoLand.updateStatus_json.pl @@ -0,0 +1,65 @@ +#!/usr/bin/perl -w + +use JSON::RPC::Client; +use Data::Dumper; +use HTTP::Cookies; + +################################### +# Need to login first # +################################### + +my $username = shift; +my $password = shift; + +my $cookie_jar = HTTP::Cookies->new( file => "/tmp/lwp_cookies.dat" ); + +my $rpc = new JSON::RPC::Client; + +$rpc->ua->ssl_opts(verify_hostname => 0); + +my $uri = "http://fedora/726193/jsonrpc.cgi"; + +#$rpc->ua->cookie_jar($cookie_jar); + +#my $result = $rpc->call($uri, { method => 'User.login', params => +# { login => $username, password => $password } }); + +#if ($result) { +# if ($result->is_error) { +# print "Error : ", $result->error_message; +# exit; +# } +# else { +# print "Successfully logged in.\n"; +# } +#} +#else { +# print $rpc->status_line; +#} + +################################### +# Main call here # +################################### + +my $attach_id = shift; +my $action = shift; +my $status = shift; + +$result = $rpc->call($uri, { method => 'TryAutoLand.update', + params => { attach_id => $attach_id, + action => $action, + status => $status, + Bugzilla_login => $username, + Bugzilla_password => $password } }); + +if ($result) { + if ($result->is_error) { + print "Error : ", $result->error_message; + exit; + } +} +else { + print $rpc->status_line; +} + +print Dumper($result->result); diff --git a/extensions/TryAutoLand/lib/Constants.pm b/extensions/TryAutoLand/lib/Constants.pm new file mode 100644 index 000000000..53bad630a --- /dev/null +++ b/extensions/TryAutoLand/lib/Constants.pm @@ -0,0 +1,31 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::TryAutoLand::Constants; + +use strict; + +use base qw(Exporter); + +our @EXPORT = qw( + VALID_STATUSES + WEBSERVICE_USER + DEFAULT_TRY_SYNTAX +); + +use constant VALID_STATUSES => qw( + waiting + running + failed + success +); + +use constant WEBSERVICE_USER => 'autoland-try@mozilla.bugs'; + +use constant DEFAULT_TRY_SYNTAX => '-b do -p all -u none -t none'; + +1; diff --git a/extensions/TryAutoLand/lib/WebService.pm b/extensions/TryAutoLand/lib/WebService.pm new file mode 100644 index 000000000..1088386dd --- /dev/null +++ b/extensions/TryAutoLand/lib/WebService.pm @@ -0,0 +1,189 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::TryAutoLand::WebService; + +use strict; +use warnings; + +use base qw(Bugzilla::WebService); + +use Bugzilla::Error; +use Bugzilla::Util qw(trick_taint); + +use Bugzilla::Extension::TryAutoLand::Constants; + +use constant READ_ONLY => qw( + getBugs +); + +# TryAutoLand.getBugs +# Params: status - List of statuses to filter attachments (only 'waiting' is default) +# Returns: List of bugs, each being a hash of data needed by the AutoLand polling server +# Params +# [ { bug_id => $bug_id1, attachments => [ $attach_id1, $attach_id2 ] }, branches => $branchListFromTextField ... ] + +sub getBugs { + my ($self, $params) = @_; + my $user = Bugzilla->user; + my $dbh = Bugzilla->dbh; + my %bugs; + + if ($user->login ne WEBSERVICE_USER) { + ThrowUserError("auth_failure", { action => "access", + object => "autoland_attachments" }); + } + + my $status_where = "AND status = 'waiting'"; + my $status_values = []; + if (exists $params->{'status'}) { + my $statuses = ref $params->{'status'} + ? $params->{'status'} + : [ $params->{'status'} ]; + foreach my $status (@$statuses) { + if (grep($_ eq $status, VALID_STATUSES)) { + trick_taint($status); + push(@$status_values, $status); + } + } + if (@$status_values) { + my @qmarks = ("?") x @$status_values; + $status_where = "AND " . $dbh->sql_in('status', \@qmarks); + } + + } + + my $attachments = $dbh->selectall_arrayref(" + SELECT attachments.bug_id, + attachments.attach_id, + autoland_attachments.who, + autoland_attachments.status, + autoland_attachments.status_when + FROM attachments, autoland_attachments + WHERE attachments.attach_id = autoland_attachments.attach_id + $status_where + ORDER BY attachments.bug_id", + undef, @$status_values); + + foreach my $row (@$attachments) { + my ($bug_id, $attach_id, $al_who, $al_status, $al_status_when) = @$row; + + my $al_user = Bugzilla::User->new($al_who); + + # Silent Permission checks + next if !$user->can_see_bug($bug_id); + my $attachment = Bugzilla::Attachment->new($attach_id); + next if !$attachment + || $attachment->isobsolete + || ($attachment->isprivate && !$user->is_insider); + + $bugs{$bug_id} = {} if !exists $bugs{$bug_id}; + + if (!$bugs{$bug_id}{'branches'}) { + my $bug_result = $dbh->selectrow_hashref("SELECT branches, try_syntax + FROM autoland_branches + WHERE bug_id = ?", + undef, $bug_id); + $bugs{$bug_id}{'branches'} = $bug_result->{'branches'}; + $bugs{$bug_id}{'try_syntax'} = $bug_result->{'try_syntax'}; + } + + $bugs{$bug_id}{'attachments'} = [] if !exists $bugs{$bug_id}{'attachments'}; + + push(@{$bugs{$bug_id}{'attachments'}}, { + id => $self->type('int', $attach_id), + who => $self->type('string', $al_user->login), + status => $self->type('string', $al_status), + status_when => $self->type('dateTime', $al_status_when), + }); + } + + return [ + map + { { bug_id => $_, attachments => $bugs{$_}{'attachments'}, + branches => $bugs{$_}{'branches'}, try_syntax => $bugs{$_}{'try_syntax'} } } + keys %bugs + ]; +} + +# TryAutoLand.update({ attach_id => $attach_id, action => $action, status => $status }) +# Let's BMO know if a patch has landed or not and BMO will update the auto_land table accordingly +# If $action eq 'status', $status will be a predetermined set of status values -- when waiting, +# the UI for submitting autoland will be locked and once complete status update occurs or the +# mapping is removed, the UI can be unlocked for the $attach_id +# Allowed statuses: waiting, running, failed, or success +# +# If $action eq 'remove', the attach_id will be removed from the mapping table and the UI +# will be unlocked for the $attach_id. + +sub update { + my ($self, $params) = @_; + my $user = Bugzilla->user; + my $dbh = Bugzilla->dbh; + + if ($user->login ne WEBSERVICE_USER) { + ThrowUserError("auth_failure", { action => "modify", + object => "autoland_attachments" }); + } + + foreach my $param ('attach_id', 'action') { + defined $params->{$param} + || ThrowCodeError('param_required', + { param => $param }); + } + + my $action = delete $params->{'action'}; + my $attach_id = delete $params->{'attach_id'}; + my $status = delete $params->{'status'}; + + if ($action eq 'status' && !$status) { + ThrowCodeError('param_required', { param => 'status' }); + } + + grep($_ eq $action, ('remove', 'status')) + || ThrowUserError('autoland_update_invalid_action', + { action => $action, + valid => ["remove", "status"] }); + + my $attachment = Bugzilla::Attachment->new($attach_id); + $attachment + || ThrowUserError('autoland_invalid_attach_id', + { attach_id => $attach_id }); + + # Loud Permission checks + if (!$user->can_see_bug($attachment->bug_id)) { + ThrowUserError("bug_access_denied", { bug_id => $attachment->bug_id }); + } + if ($attachment->isprivate && !$user->is_insider) { + ThrowUserError('auth_failure', { action => 'access', + object => 'attachment', + attach_id => $attachment->id }); + } + + $attachment->autoland_checked + || ThrowUserError('autoland_invalid_attach_id', + { attach_id => $attach_id }); + + if ($action eq 'status') { + # Update the status + $attachment->autoland_update_status($status); + + return { + id => $self->type('int', $attachment->id), + who => $self->type('string', $attachment->autoland_who->login), + status => $self->type('string', $attachment->autoland_status), + status_when => $self->type('dateTime', $attachment->autoland_status_when), + }; + } + elsif ($action eq 'remove') { + $attachment->autoland_remove(); + } + + return {}; +} + +1; diff --git a/extensions/TryAutoLand/template/en/default/hook/bug/edit-after_custom_fields.html.tmpl b/extensions/TryAutoLand/template/en/default/hook/bug/edit-after_custom_fields.html.tmpl new file mode 100644 index 000000000..ed6224afe --- /dev/null +++ b/extensions/TryAutoLand/template/en/default/hook/bug/edit-after_custom_fields.html.tmpl @@ -0,0 +1,101 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% IF user.in_group('autoland') %] + [% autoland_attachments = [] %] + [% autoland_waiting = 0 %] + [% autoland_running = 0 %] + [% autoland_finished = 0 %] + [% FOREACH attachment = bug.attachments %] + [% NEXT IF attachment.isprivate && !user.is_insider && attachment.attacher.id != user.id %] + [% NEXT IF attachment.isobsolete %] + [% NEXT IF !attachment.ispatch %] + [% autoland_attachments.push(attachment) %] + [% IF attachment.autoland_checked %] + [% IF attachment.autoland_status == 'waiting' %] + [% autoland_waiting = autoland_waiting + 1 %] + [% END %] + [% IF attachment.autoland_status == 'running' %] + [% autoland_running = autoland_running + 1 %] + [% END %] + [% IF attachment.autoland_status == 'success' || attachment.autoland_status == 'failed' %] + [% autoland_finished = autoland_finished + 1 %] + [% END %] + [% END %] + [% END %] + [% IF autoland_attachments.size %] + <tr> + <th class="field_label field_land_autoland"> + <a title="[% help_html.autoland FILTER txt FILTER collapse FILTER html %]" + class="field_help_link" href="https://wiki.mozilla.org/Build:Autoland"> + AutoLand:</a> + </th> + <td> + <span id="autoland_edit_container"> + (<a href="#" id="autoland_edit_action">edit</a>) + Total: [% autoland_attachments.size FILTER html %] - + <span class="autoland_waiting">Waiting:</span> [% autoland_waiting FILTER html %] - + <span class="autoland_running">Running:</span> [% autoland_running FILTER html %] - + <span class="autoland_success">Finished:</span> [% autoland_finished FILTER html %] + </span> + <div id="autoland_edit_input"> + Branches (required):<br> + <input type="text" id="autoland_branches" name="autoland_branches" + value="[% bug.autoland_branches FILTER html %]" size="40" + class="text_input"><br> + Try Syntax (required): (Default: [% autoland_default_try_syntax FILTER html %])<br> + <input type="text" id="autoland_try_syntax" name="autoland_try_syntax" + value="[% bug.autoland_try_syntax || autoland_default_try_syntax FILTER html %]" size="40" + class="text_input"><br> + Patches: + <br> + <table id="autoland_edit_table"> + [% FOREACH attachment = autoland_attachments %] + <tr> + <td> + [% IF attachment.autoland_checked %] + <input type="hidden" name="defined_autoland_attachments" + value="[% attachment.id FILTER html %]"> + [% END %] + <input type="checkbox" name="autoland_attachments" value="[% attachment.id FILTER html %]" + [% ' checked="checked"' IF attachment.autoland_checked %] + [% IF attachment.autoland_status == 'running' || attachment.autoland_status == 'waiting' %] + disabled="disabled" + [% END %]> + </td> + <td> + <span title="[% attachment.description FILTER html %]"> + [% attachment.filename FILTER html %] + </span> + <td> + [% IF attachment.autoland_checked %] + <span class="autoland_[% attachment.autoland_status FILTER html %]"> + [% attachment.autoland_status FILTER html %] + </span> + [% END %] + </td> + <td> + [% IF attachment.autoland_checked %] + [% attachment.autoland_status_when FILTER time('%Y-%m-%d %H:%M') %] + [% END %] + </td> + </tr> + [% END %] + </table> + </div> + <script type="text/javascript"> + hideEditableField('autoland_edit_container', + 'autoland_edit_input', + 'autoland_edit_action', + '', + ''); + </script> + </td> + </tr> + [% END %] +[% END %] diff --git a/extensions/TryAutoLand/template/en/default/hook/bug/field-help-end.none.tmpl b/extensions/TryAutoLand/template/en/default/hook/bug/field-help-end.none.tmpl new file mode 100644 index 000000000..899db60c4 --- /dev/null +++ b/extensions/TryAutoLand/template/en/default/hook/bug/field-help-end.none.tmpl @@ -0,0 +1,15 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% + vars.help_html.autoland = + "TryAutoLand is a BMO extension that allows integration with the $terms.Bugzilla + AutoLanding system. Select patches on a $terms.bug will be picked up + automatically and landed on the try build server for specified branches. + Results of the try build will be sent back to the bug report as comments." +%] diff --git a/extensions/TryAutoLand/template/en/default/hook/bug/show-header-end.html.tmpl b/extensions/TryAutoLand/template/en/default/hook/bug/show-header-end.html.tmpl new file mode 100644 index 000000000..c61f478ea --- /dev/null +++ b/extensions/TryAutoLand/template/en/default/hook/bug/show-header-end.html.tmpl @@ -0,0 +1,11 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% IF autoland %] + [% style_urls.push('extensions/TryAutoLand/web/style.css') %] +[% END %] diff --git a/extensions/TryAutoLand/template/en/default/hook/global/user-error-auth_failure_object.html.tmpl b/extensions/TryAutoLand/template/en/default/hook/global/user-error-auth_failure_object.html.tmpl new file mode 100644 index 000000000..50a1e48d5 --- /dev/null +++ b/extensions/TryAutoLand/template/en/default/hook/global/user-error-auth_failure_object.html.tmpl @@ -0,0 +1,11 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% IF object == 'autoland_attachments' %] + AutoLand attachments +[% END %] diff --git a/extensions/TryAutoLand/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/TryAutoLand/template/en/default/hook/global/user-error-errors.html.tmpl new file mode 100644 index 000000000..c12950dcf --- /dev/null +++ b/extensions/TryAutoLand/template/en/default/hook/global/user-error-errors.html.tmpl @@ -0,0 +1,33 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% IF error == "autoland_invalid_status" %] + [% title = "AutoLand Invalid Status" %] + The status '[% status FILTER html %]' is not a valid + status for the AutoLand extension. Valid statuses + are [% valid.join(', ') FILTER html %]. + +[% ELSIF error == "autoland_invalid_attach_id" %] + [% title = "AutoLand Invalid Attachment ID" %] + The attachment id '[% attach_id FILTER html %]' is not + a valid id for the AutoLand extension. + +[% ELSIF error == "autoland_empty_try_syntax" %] + [% title = "AutoLand Empty Try Syntax" %] + You cannot have a value for Branches and have an empty Try Syntax value. + +[% ELSIF error == "autoland_empty_branches" %] + [% title = "AutoLand Empty Branches" %] + You cannot check one or more patches for AutoLanding and have an empty + Branches value. + +[% ELSIF error == "autoland_update_invalid_action" %] + [% title = "AutoLand Update Invalid Action" %] + The action '[% action FILTER html %]' is not a valid action. + Valid actions are [% valid.join(', ') FILTER html %]. +[% END %] diff --git a/extensions/TryAutoLand/web/style.css b/extensions/TryAutoLand/web/style.css new file mode 100644 index 000000000..99409c0c0 --- /dev/null +++ b/extensions/TryAutoLand/web/style.css @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + */ + +.autoland_waiting { + color: blue; +} + +.autoland_running { + color: orange; +} + +.autoland_failed { + color: red; +} + +.autoland_success { + color: green; +} |