1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-18 21:02:41 +01:00

Implement "Auto Review" in packages with a "Subscribe" option

Summary:
Ref T10939. Ref T8887. This moves toward letting packages automatically become reviewers or blocking reviewers of owned code.

This change adds an "Auto Review" option to packages. Because adding reviewers/blocking reviewers is a little tricky, it doesn't actually have these options yet -- just a "subscribe" option. I'll do the reviewer work in the next update.

Test Plan:
Created a revision in a package with "Auto Review: Subscribe to Changes". The package got subscribed.

{F1311677}

{F1311678}

{F1311679}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T8887, T10939

Differential Revision: https://secure.phabricator.com/D15915
This commit is contained in:
epriestley 2016-05-13 06:26:54 -07:00
parent 70ddb1c45f
commit 52ac242eb3
10 changed files with 182 additions and 9 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_owners.owners_package
ADD autoReview VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,2 @@
UPDATE {$NAMESPACE}_owners.owners_package
SET autoReview = 'none' WHERE autoReview = '';

View file

@ -8,7 +8,7 @@ final class DifferentialProjectReviewersField
} }
public function getFieldName() { public function getFieldName() {
return pht('Coalition Reviewers'); return pht('Group Reviewers');
} }
public function getFieldDescription() { public function getFieldDescription() {

View file

@ -7,6 +7,7 @@ final class DifferentialTransactionEditor
private $isCloseByCommit; private $isCloseByCommit;
private $repositoryPHIDOverride = false; private $repositoryPHIDOverride = false;
private $didExpandInlineState = false; private $didExpandInlineState = false;
private $affectedPaths;
public function getEditorApplicationClass() { public function getEditorApplicationClass() {
return 'PhabricatorDifferentialApplication'; return 'PhabricatorDifferentialApplication';
@ -1481,6 +1482,75 @@ final class DifferentialTransactionEditor
return parent::shouldApplyHeraldRules($object, $xactions); return parent::shouldApplyHeraldRules($object, $xactions);
} }
protected function didApplyHeraldRules(
PhabricatorLiskDAO $object,
HeraldAdapter $adapter,
HeraldTranscript $transcript) {
$repository = $object->getRepository();
if (!$repository) {
return array();
}
if (!$this->affectedPaths) {
return array();
}
$packages = PhabricatorOwnersPackage::loadAffectedPackages(
$repository,
$this->affectedPaths);
foreach ($packages as $key => $package) {
if ($package->isArchived()) {
unset($packages[$key]);
}
}
if (!$packages) {
return array();
}
$auto_subscribe = array();
$auto_review = array();
$auto_block = array();
foreach ($packages as $package) {
switch ($package->getAutoReview()) {
case PhabricatorOwnersPackage::AUTOREVIEW_SUBSCRIBE:
$auto_subscribe[] = $package;
break;
case PhabricatorOwnersPackage::AUTOREVIEW_REVIEW:
$auto_review[] = $package;
break;
case PhabricatorOwnersPackage::AUTOREVIEW_BLOCK:
$auto_block[] = $package;
break;
case PhabricatorOwnersPackage::AUTOREVIEW_NONE:
default:
break;
}
}
$owners_phid = id(new PhabricatorOwnersApplication())
->getPHID();
$xactions = array();
if ($auto_subscribe) {
$xactions[] = $object->getApplicationTransactionTemplate()
->setAuthorPHID($owners_phid)
->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
->setNewValue(
array(
'+' => mpull($auto_subscribe, 'getPHID'),
));
}
// TODO: Implement autoreview and autoblock, but these are more invovled.
return $xactions;
}
protected function buildHeraldAdapter( protected function buildHeraldAdapter(
PhabricatorLiskDAO $object, PhabricatorLiskDAO $object,
array $xactions) { array $xactions) {
@ -1557,6 +1627,9 @@ final class DifferentialTransactionEditor
} }
$all_paths = array_keys($all_paths); $all_paths = array_keys($all_paths);
// Save the affected paths; we'll use them later to query Owners.
$this->affectedPaths = $all_paths;
$path_ids = $path_ids =
PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths( PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths(
$all_paths); $all_paths);

View file

@ -184,6 +184,12 @@ final class PhabricatorOwnersDetailController
} }
$view->addProperty(pht('Owners'), $owner_list); $view->addProperty(pht('Owners'), $owner_list);
$auto = $package->getAutoReview();
$autoreview_map = PhabricatorOwnersPackage::getAutoreviewOptionsMap();
$spec = idx($autoreview_map, $auto, array());
$name = idx($spec, 'name', $auto);
$view->addProperty(pht('Auto Review'), $name);
if ($package->getAuditingEnabled()) { if ($package->getAuditingEnabled()) {
$auditing = pht('Enabled'); $auditing = pht('Enabled');
} else { } else {

View file

@ -84,6 +84,9 @@ applying a transaction of this type.
EOTEXT EOTEXT
); );
$autoreview_map = PhabricatorOwnersPackage::getAutoreviewOptionsMap();
$autoreview_map = ipull($autoreview_map, 'name');
return array( return array(
id(new PhabricatorTextEditField()) id(new PhabricatorTextEditField())
->setKey('name') ->setKey('name')
@ -100,6 +103,18 @@ EOTEXT
->setDatasource(new PhabricatorProjectOrUserDatasource()) ->setDatasource(new PhabricatorProjectOrUserDatasource())
->setIsCopyable(true) ->setIsCopyable(true)
->setValue($object->getOwnerPHIDs()), ->setValue($object->getOwnerPHIDs()),
id(new PhabricatorSelectEditField())
->setKey('autoReview')
->setLabel(pht('Auto Review'))
->setDescription(
pht(
'Automatically trigger reviews for commits affecting files in '.
'this package.'))
->setTransactionType(
PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW)
->setIsCopyable(true)
->setValue($object->getAutoReview())
->setOptions($autoreview_map),
id(new PhabricatorSelectEditField()) id(new PhabricatorSelectEditField())
->setKey('auditing') ->setKey('auditing')
->setLabel(pht('Auditing')) ->setLabel(pht('Auditing'))

View file

@ -20,6 +20,7 @@ final class PhabricatorOwnersPackageTransactionEditor
$types[] = PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION; $types[] = PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION;
$types[] = PhabricatorOwnersPackageTransaction::TYPE_PATHS; $types[] = PhabricatorOwnersPackageTransaction::TYPE_PATHS;
$types[] = PhabricatorOwnersPackageTransaction::TYPE_STATUS; $types[] = PhabricatorOwnersPackageTransaction::TYPE_STATUS;
$types[] = PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
@ -47,6 +48,8 @@ final class PhabricatorOwnersPackageTransactionEditor
return mpull($paths, 'getRef'); return mpull($paths, 'getRef');
case PhabricatorOwnersPackageTransaction::TYPE_STATUS: case PhabricatorOwnersPackageTransaction::TYPE_STATUS:
return $object->getStatus(); return $object->getStatus();
case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW:
return $object->getAutoReview();
} }
} }
@ -58,6 +61,7 @@ final class PhabricatorOwnersPackageTransactionEditor
case PhabricatorOwnersPackageTransaction::TYPE_NAME: case PhabricatorOwnersPackageTransaction::TYPE_NAME:
case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION:
case PhabricatorOwnersPackageTransaction::TYPE_STATUS: case PhabricatorOwnersPackageTransaction::TYPE_STATUS:
case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW:
return $xaction->getNewValue(); return $xaction->getNewValue();
case PhabricatorOwnersPackageTransaction::TYPE_PATHS: case PhabricatorOwnersPackageTransaction::TYPE_PATHS:
$new = $xaction->getNewValue(); $new = $xaction->getNewValue();
@ -113,6 +117,9 @@ final class PhabricatorOwnersPackageTransactionEditor
case PhabricatorOwnersPackageTransaction::TYPE_STATUS: case PhabricatorOwnersPackageTransaction::TYPE_STATUS:
$object->setStatus($xaction->getNewValue()); $object->setStatus($xaction->getNewValue());
return; return;
case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW:
$object->setAutoReview($xaction->getNewValue());
return;
} }
return parent::applyCustomInternalTransaction($object, $xaction); return parent::applyCustomInternalTransaction($object, $xaction);
@ -127,6 +134,7 @@ final class PhabricatorOwnersPackageTransactionEditor
case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION:
case PhabricatorOwnersPackageTransaction::TYPE_AUDITING: case PhabricatorOwnersPackageTransaction::TYPE_AUDITING:
case PhabricatorOwnersPackageTransaction::TYPE_STATUS: case PhabricatorOwnersPackageTransaction::TYPE_STATUS:
case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW:
return; return;
case PhabricatorOwnersPackageTransaction::TYPE_OWNERS: case PhabricatorOwnersPackageTransaction::TYPE_OWNERS:
$old = $xaction->getOldValue(); $old = $xaction->getOldValue();
@ -220,6 +228,26 @@ final class PhabricatorOwnersPackageTransactionEditor
} }
} }
break;
case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW:
$map = PhabricatorOwnersPackage::getAutoreviewOptionsMap();
foreach ($xactions as $xaction) {
$new = $xaction->getNewValue();
if (empty($map[$new])) {
$valid = array_keys($map);
$errors[] = new PhabricatorApplicationTransactionValidationError(
$type,
pht('Invalid'),
pht(
'Autoreview setting "%s" is not valid. '.
'Valid settings are: %s.',
$new,
implode(', ', $valid)),
$xaction);
}
}
break; break;
case PhabricatorOwnersPackageTransaction::TYPE_PATHS: case PhabricatorOwnersPackageTransaction::TYPE_PATHS:
if (!$xactions) { if (!$xactions) {

View file

@ -14,6 +14,7 @@ final class PhabricatorOwnersPackage
protected $name; protected $name;
protected $originalName; protected $originalName;
protected $auditingEnabled; protected $auditingEnabled;
protected $autoReview;
protected $description; protected $description;
protected $primaryOwnerPHID; protected $primaryOwnerPHID;
protected $mailKey; protected $mailKey;
@ -28,6 +29,11 @@ final class PhabricatorOwnersPackage
const STATUS_ACTIVE = 'active'; const STATUS_ACTIVE = 'active';
const STATUS_ARCHIVED = 'archived'; const STATUS_ARCHIVED = 'archived';
const AUTOREVIEW_NONE = 'none';
const AUTOREVIEW_SUBSCRIBE = 'subscribe';
const AUTOREVIEW_REVIEW = 'review';
const AUTOREVIEW_BLOCK = 'block';
public static function initializeNewPackage(PhabricatorUser $actor) { public static function initializeNewPackage(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery()) $app = id(new PhabricatorApplicationQuery())
->setViewer($actor) ->setViewer($actor)
@ -41,6 +47,7 @@ final class PhabricatorOwnersPackage
return id(new PhabricatorOwnersPackage()) return id(new PhabricatorOwnersPackage())
->setAuditingEnabled(0) ->setAuditingEnabled(0)
->setAutoReview(self::AUTOREVIEW_NONE)
->setViewPolicy($view_policy) ->setViewPolicy($view_policy)
->setEditPolicy($edit_policy) ->setEditPolicy($edit_policy)
->attachPaths(array()) ->attachPaths(array())
@ -56,6 +63,24 @@ final class PhabricatorOwnersPackage
); );
} }
public static function getAutoreviewOptionsMap() {
return array(
self::AUTOREVIEW_NONE => array(
'name' => pht('No Autoreview'),
),
self::AUTOREVIEW_SUBSCRIBE => array(
'name' => pht('Subscribe to Changes'),
),
// TODO: Implement these.
// self::AUTOREVIEW_REVIEW => array(
// 'name' => pht('Review Changes'),
// ),
// self::AUTOREVIEW_BLOCK => array(
// 'name' => pht('Review Changes (Blocking)'),
// ),
);
}
protected function getConfiguration() { protected function getConfiguration() {
return array( return array(
// This information is better available from the history table. // This information is better available from the history table.
@ -69,6 +94,7 @@ final class PhabricatorOwnersPackage
'auditingEnabled' => 'bool', 'auditingEnabled' => 'bool',
'mailKey' => 'bytes20', 'mailKey' => 'bytes20',
'status' => 'text32', 'status' => 'text32',
'autoReview' => 'text32',
), ),
) + parent::getConfiguration(); ) + parent::getConfiguration();
} }

View file

@ -10,6 +10,7 @@ final class PhabricatorOwnersPackageTransaction
const TYPE_DESCRIPTION = 'owners.description'; const TYPE_DESCRIPTION = 'owners.description';
const TYPE_PATHS = 'owners.paths'; const TYPE_PATHS = 'owners.paths';
const TYPE_STATUS = 'owners.status'; const TYPE_STATUS = 'owners.status';
const TYPE_AUTOREVIEW = 'owners.autoreview';
public function getApplicationName() { public function getApplicationName() {
return 'owners'; return 'owners';
@ -143,6 +144,18 @@ final class PhabricatorOwnersPackageTransaction
'%s archived this package.', '%s archived this package.',
$this->renderHandleLink($author_phid)); $this->renderHandleLink($author_phid));
} }
case self::TYPE_AUTOREVIEW:
$map = PhabricatorOwnersPackage::getAutoreviewOptionsMap();
$map = ipull($map, 'name');
$old = idx($map, $old, $old);
$new = idx($map, $new, $new);
return pht(
'%s adjusted autoreview from "%s" to "%s".',
$this->renderHandleLink($author_phid),
$old,
$new);
} }
return parent::getTitle(); return parent::getTitle();

View file

@ -703,7 +703,13 @@ abstract class PhabricatorApplicationTransactionEditor
$xaction->setEditPolicy($this->getActingAsPHID()); $xaction->setEditPolicy($this->getActingAsPHID());
} }
$xaction->setAuthorPHID($this->getActingAsPHID()); // If the transaction already has an explicit author PHID, allow it to
// stand. This is used by applications like Owners that hook into the
// post-apply change pipeline.
if (!$xaction->getAuthorPHID()) {
$xaction->setAuthorPHID($this->getActingAsPHID());
}
$xaction->setContentSource($this->getContentSource()); $xaction->setContentSource($this->getContentSource());
$xaction->attachViewer($actor); $xaction->attachViewer($actor);
$xaction->attachObject($object); $xaction->attachObject($object);
@ -957,6 +963,12 @@ abstract class PhabricatorApplicationTransactionEditor
if ($herald_xactions) { if ($herald_xactions) {
$xscript_id = $this->getHeraldTranscript()->getID(); $xscript_id = $this->getHeraldTranscript()->getID();
foreach ($herald_xactions as $herald_xaction) { foreach ($herald_xactions as $herald_xaction) {
// Don't set a transcript ID if this is a transaction from another
// application or source, like Owners.
if ($herald_xaction->getAuthorPHID()) {
continue;
}
$herald_xaction->setMetadataValue('herald:transcriptID', $xscript_id); $herald_xaction->setMetadataValue('herald:transcriptID', $xscript_id);
} }
@ -1217,6 +1229,7 @@ abstract class PhabricatorApplicationTransactionEditor
$xaction, $xaction,
pht('You can not apply transactions which already have IDs/PHIDs!')); pht('You can not apply transactions which already have IDs/PHIDs!'));
} }
if ($xaction->getObjectPHID()) { if ($xaction->getObjectPHID()) {
throw new PhabricatorApplicationTransactionStructureException( throw new PhabricatorApplicationTransactionStructureException(
$xaction, $xaction,
@ -1224,13 +1237,7 @@ abstract class PhabricatorApplicationTransactionEditor
'You can not apply transactions which already have %s!', 'You can not apply transactions which already have %s!',
'objectPHIDs')); 'objectPHIDs'));
} }
if ($xaction->getAuthorPHID()) {
throw new PhabricatorApplicationTransactionStructureException(
$xaction,
pht(
'You can not apply transactions which already have %s!',
'authorPHIDs'));
}
if ($xaction->getCommentPHID()) { if ($xaction->getCommentPHID()) {
throw new PhabricatorApplicationTransactionStructureException( throw new PhabricatorApplicationTransactionStructureException(
$xaction, $xaction,
@ -1238,6 +1245,7 @@ abstract class PhabricatorApplicationTransactionEditor
'You can not apply transactions which already have %s!', 'You can not apply transactions which already have %s!',
'commentPHIDs')); 'commentPHIDs'));
} }
if ($xaction->getCommentVersion() !== 0) { if ($xaction->getCommentVersion() !== 0) {
throw new PhabricatorApplicationTransactionStructureException( throw new PhabricatorApplicationTransactionStructureException(
$xaction, $xaction,