From ce080c6dcec309fa3bcfb922c834266166e57af4 Mon Sep 17 00:00:00 2001 From: David Walsh Date: Mon, 31 Jul 2017 16:44:31 -0500 Subject: Bug 1383108 - Sync security groups with Phabricator push connector r=dkl --- extensions/PhabBugz/lib/Util.pm | 34 ++++++++ extensions/PhabBugz/lib/WebService.pm | 3 +- extensions/Push/lib/Connector/Phabricator.pm | 126 ++++++++++++++++++++------- 3 files changed, 130 insertions(+), 33 deletions(-) (limited to 'extensions') diff --git a/extensions/PhabBugz/lib/Util.pm b/extensions/PhabBugz/lib/Util.pm index cbbca7eab..75c523ad5 100644 --- a/extensions/PhabBugz/lib/Util.pm +++ b/extensions/PhabBugz/lib/Util.pm @@ -20,6 +20,7 @@ use LWP::UserAgent; use base qw(Exporter); our @EXPORT = qw( + add_comment_to_revision create_revision_attachment create_private_revision_policy create_project @@ -29,6 +30,7 @@ our @EXPORT = qw( get_project_phid get_revisions_by_ids intersect + make_revision_private make_revision_public request set_project_members @@ -141,6 +143,23 @@ sub make_revision_public { }); } +sub make_revision_private { + my ($revision_phid) = @_; + return request('differential.revision.edit', { + transactions => [ + { + type => "view", + value => "admin" + }, + { + type => "edit", + value => "admin" + } + ], + objectIdentifier => $revision_phid + }); +} + sub edit_revision_policy { my ($revision_phid, $policy_phid, $subscribers) = @_; @@ -168,6 +187,21 @@ sub edit_revision_policy { return request('differential.revision.edit', $data); } +sub add_comment_to_revision { + my ($revision_phid, $comment) = @_; + + my $data = { + transactions => [ + { + type => 'comment', + value => $comment + } + ], + objectIdentifier => $revision_phid + }; + return request('differential.revision.edit', $data); +} + sub get_project_phid { my $project = shift; diff --git a/extensions/PhabBugz/lib/WebService.pm b/extensions/PhabBugz/lib/WebService.pm index 217ed18dc..11439ba70 100644 --- a/extensions/PhabBugz/lib/WebService.pm +++ b/extensions/PhabBugz/lib/WebService.pm @@ -17,6 +17,7 @@ use Bugzilla::Attachment; use Bugzilla::Bug; use Bugzilla::BugMail; use Bugzilla::Error; +use Bugzilla::Extension::Push::Util qw(is_public); use Bugzilla::User; use Bugzilla::Util qw(correct_urlbase detaint_natural); use Bugzilla::WebService::Constants; @@ -61,7 +62,7 @@ sub revision { # If bug is public then remove privacy policy my $result; - if (!@{ $bug->groups_in }) { + if (is_public($bug)) { $result = make_revision_public($revision_id); } # Else bug is private diff --git a/extensions/Push/lib/Connector/Phabricator.pm b/extensions/Push/lib/Connector/Phabricator.pm index be0ea9b58..092d63dd3 100644 --- a/extensions/Push/lib/Connector/Phabricator.pm +++ b/extensions/Push/lib/Connector/Phabricator.pm @@ -15,18 +15,22 @@ use base 'Bugzilla::Extension::Push::Connector::Base'; use Bugzilla::Bug; use Bugzilla::Constants; -use Bugzilla::Extension::PhabBugz::Util qw(intersect make_revision_public get_revisions_by_ids); +use Bugzilla::Error; +use Bugzilla::Extension::PhabBugz::Util qw(add_comment_to_revision + create_private_revision_policy edit_revision_policy get_bug_role_phids + get_revisions_by_ids intersect make_revision_public make_revision_private); use Bugzilla::Extension::Push::Constants; -use Bugzilla::Extension::Push::Util; +use Bugzilla::Extension::Push::Util qw(is_public); use Bugzilla::User; use List::Util qw(any); -use constant PHAB_CONTENT_TYPE => 'text/x-phabricator-request'; +use constant PHAB_CONTENT_TYPE => 'text/x-phabricator-request'; use constant PHAB_ATTACHMENT_PATTERN => qr/^phabricator-D(\d+)/; sub options { return ( - { name => 'phabricator_url', + { + name => 'phabricator_url', label => 'Phabricator URL', type => 'string', default => '', @@ -40,11 +44,11 @@ sub should_send { return 0 unless Bugzilla->params->{phabricator_enabled}; - return 0 unless $message->routing_key =~ /^(?:attachment|bug)\.modify:.*\bbug_group\b/; + return 0 + unless $message->routing_key =~ + /^(?:attachment|bug)\.modify:.*\bbug_group\b/; - my $data = $message->payload_decoded; - my $bug_data = $self->_get_bug_data($data) || return 0; - my $bug = Bugzilla::Bug->new( { id => $bug_data->{id}, cache => 1 } ); + my $bug = $self->_get_bug_by_data( $message->payload_decoded ) || return 0; return $bug->has_attachment_with_mimetype(PHAB_CONTENT_TYPE); } @@ -55,43 +59,101 @@ sub send { my $logger = Bugzilla->push_ext->logger; my $data = $message->payload_decoded; - my $bug_data = $self->_get_bug_data($data) || return 0; - my $bug = Bugzilla::Bug->new( { id => $bug_data->{id}, cache => 1 } ); + my $bug = $self->_get_bug_by_data($data) || return PUSH_RESULT_OK; + + my $is_public = is_public($bug); + + my $phab_sync_groups = Bugzilla->params->{phabricator_sync_groups}; + ThrowUserError('invalid_phabricator_sync_groups') unless $phab_sync_groups; + + my $sync_group_names = [ split( '[,\s]+', $phab_sync_groups ) ]; + + my $bug_groups = $bug->groups_in; + my $bug_group_names = [ map { $_->name } @$bug_groups ]; + + my @set_groups = intersect( $bug_group_names, $sync_group_names ); + + if ( !$is_public && !@set_groups ) { + my $phab_error_message = + 'Revision is being made private due to unknown Bugzilla groups.'; + + my @revisions = $self->_get_attachment_revisions($bug); + foreach my $revision (@revisions) { + add_comment_to_revision( $revision->{phid}, $phab_error_message ); + make_revision_private( $revision->{phid} ); + } + + my $num_revisions = 0 + @revisions; + my $bmo_error_message = + ( $num_revisions > 1 + ? 'Multiple revisions were' + : 'One revision was' ) + . ' made private due to unknown Bugzilla groups.'; + + my $user = + Bugzilla->set_user( + Bugzilla::User->new( { name => 'conduit@mozilla.bugs' } ) ); + $bug->add_comment( $bmo_error_message, { isprivate => 0 } ); + my $bug_changes = $bug->update(); + $bug->send_changes($bug_changes); - if(!is_public($bug)) { - $logger->info('Bailing on send because the bug is not public'); return PUSH_RESULT_OK; } + my $policy_phid; + my $subscribers; + if ( !$is_public ) { + $policy_phid = create_private_revision_policy( $bug, \@set_groups ); + $subscribers = get_bug_role_phids($bug); + } + + my @revisions = $self->_get_attachment_revisions($bug); + foreach my $revision (@revisions) { + my $revision_phid = $revision->{phid}; + + if ($is_public) { + make_revision_public($revision_phid); + } + else { + edit_revision_policy( $revision_phid, $policy_phid, $subscribers ); + } + } + + return PUSH_RESULT_OK; +} + +sub _get_attachment_revisions() { + my ( $self, $bug ) = @_; + + my @revisions; + my @attachments = grep { - $_->isobsolete == 0 && - $_->contenttype eq PHAB_CONTENT_TYPE && - $_->attacher->login eq 'phab-bot@bmo.tld' + $_->isobsolete == 0 + && $_->contenttype eq PHAB_CONTENT_TYPE + && $_->attacher->login ne 'phab-bot@bmo.tld' } @{ $bug->attachments() }; - if(@attachments){ - my @rev_ids; + if (@attachments) { + my @revision_ids; foreach my $attachment (@attachments) { - my ($rev_id) = ($attachment->filename =~ PHAB_ATTACHMENT_PATTERN); - next if !$rev_id; - push(@rev_ids, int($rev_id)); + my ($revision_id) = + ( $attachment->filename =~ PHAB_ATTACHMENT_PATTERN ); + next if !$revision_id; + push( @revision_ids, int($revision_id) ); } - if(@rev_ids) { - $logger->info('Getting info for revisions: '); - $logger->info(@rev_ids); - - my @rev_details = get_revisions_by_ids(\@rev_ids); - foreach my $rev_detail (@rev_details) { - my $rev_phid = $rev_detail->{phid}; - $logger->info('Making revision $rev_phid public:'); - $logger->info($rev_phid); - make_revision_public($rev_phid); - } + if (@revision_ids) { + @revisions = get_revisions_by_ids( \@revision_ids ); } } - return PUSH_RESULT_OK; + return @revisions; +} + +sub _get_bug_by_data { + my ( $self, $data ) = @_; + my $bug_data = $self->_get_bug_data($data) || return 0; + my $bug = Bugzilla::Bug->new( { id => $bug_data->{id} } ); } sub _get_bug_data { -- cgit v1.2.3-24-g4f1b