1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-20 19:51:08 +01:00

Allow projects to review revisions

Summary:
Ref T1279. No actual logical changes, but:

  - You can now add projects as reviewers from the revision view typeahead ("Add Reviewers" action).
  - You can now add projects as reviewers from the revision detail typeahead.
  - You can now add projects as reviewers from the CLI (`#yoloswag`).
  - Generated commit messages now list project reviewers (`Reviewers: #yoloswag`).

I'll separate projects from users in the "Reviewers" tables in the next revision.

Test Plan:
  - Added projects as reviewers using the web UI and CLI.
  - Used `arc amend --show --revision Dnnn` to generate commit messages.
  - Viewed revision with project reviewers in web UI.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T1279

Differential Revision: https://secure.phabricator.com/D7230
This commit is contained in:
epriestley 2013-10-04 19:57:15 -07:00
parent 370c7635a7
commit cf4eb3109e
9 changed files with 114 additions and 29 deletions

View file

@ -779,6 +779,14 @@ abstract class DifferentialFieldSpecification {
return $this->parseCommitMessageObjectList($value, $mailables = false);
}
protected function parseCommitMessageUserOrProjectList($value) {
return $this->parseCommitMessageObjectList(
$value,
$mailables = false,
$allow_partial = false,
$projects = true);
}
/**
* Parse a list of mailable objects into a canonical PHID list.
*
@ -813,36 +821,66 @@ abstract class DifferentialFieldSpecification {
$object_map = array();
$users = id(new PhabricatorUser())->loadAllWhere(
'(username IN (%Ls))',
$value);
$user_map = mpull($users, 'getPHID', 'getUsername');
foreach ($user_map as $username => $phid) {
// Usernames may have uppercase letters in them. Put both names in the
// map so we can try the original case first, so that username *always*
// works in weird edge cases where some other mailable object collides.
$object_map[$username] = $phid;
$object_map[strtolower($username)] = $phid;
$project_names = array();
$other_names = array();
foreach ($value as $item) {
if (preg_match('/^#/', $item)) {
$project_names[$item] = ltrim(phutil_utf8_strtolower($item), '#').'/';
} else {
$other_names[] = $item;
}
}
if ($include_mailables) {
$mailables = id(new PhabricatorMetaMTAMailingList())->loadAllWhere(
'(email IN (%Ls)) OR (name IN (%Ls))',
$value,
$value);
$object_map += mpull($mailables, 'getPHID', 'getName');
$object_map += mpull($mailables, 'getPHID', 'getEmail');
if ($project_names) {
// TODO: (T603) This should probably be policy-aware, although maybe not,
// since we generally don't want to destroy data and it doesn't leak
// anything?
$projects = id(new PhabricatorProjectQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPhrictionSlugs($project_names)
->execute();
$reverse_map = array_flip($project_names);
foreach ($projects as $project) {
$reverse_key = $project->getPhrictionSlug();
if (isset($reverse_map[$reverse_key])) {
$object_map[$reverse_map[$reverse_key]] = $project->getPHID();
}
}
}
if ($other_names) {
$users = id(new PhabricatorUser())->loadAllWhere(
'(username IN (%Ls))',
$other_names);
$user_map = mpull($users, 'getPHID', 'getUsername');
foreach ($user_map as $username => $phid) {
// Usernames may have uppercase letters in them. Put both names in the
// map so we can try the original case first, so that username *always*
// works in weird edge cases where some other mailable object collides.
$object_map[$username] = $phid;
$object_map[strtolower($username)] = $phid;
}
if ($include_mailables) {
$mailables = id(new PhabricatorMetaMTAMailingList())->loadAllWhere(
'(email IN (%Ls)) OR (name IN (%Ls))',
$other_names,
$other_names);
$object_map += mpull($mailables, 'getPHID', 'getName');
$object_map += mpull($mailables, 'getPHID', 'getEmail');
}
}
$invalid = array();
$results = array();
foreach ($value as $name) {
if (empty($object_map[$name])) {
if (empty($object_map[strtolower($name)])) {
if (empty($object_map[phutil_utf8_strtolower($name)])) {
$invalid[] = $name;
} else {
$results[] = $object_map[strtolower($name)];
$results[] = $object_map[phutil_utf8_strtolower($name)];
}
} else {
$results[] = $object_map[$name];

View file

@ -15,7 +15,7 @@ final class DifferentialReviewersFieldSpecification
}
public function renderLabelForRevisionView() {
return 'Reviewers:';
return pht('Reviewers');
}
public function renderValueForRevisionView() {
@ -144,7 +144,7 @@ final class DifferentialReviewersFieldSpecification
->setLabel(pht('Reviewers'))
->setName('reviewers')
->setUser($this->getUser())
->setDatasource('/typeahead/common/users/')
->setDatasource('/typeahead/common/usersorprojects/')
->setValue($reviewer_map)
->setError($this->error);
}
@ -179,9 +179,11 @@ final class DifferentialReviewersFieldSpecification
return null;
}
$project_type = PhabricatorProjectPHIDTypeProject::TYPECONST;
$names = array();
foreach ($this->reviewers as $phid) {
$names[] = $this->getHandle($phid)->getName();
$names[] = $this->getHandle($phid)->getObjectName();
}
return implode(', ', $names);
@ -195,7 +197,7 @@ final class DifferentialReviewersFieldSpecification
}
public function parseValueFromCommitMessage($value) {
return $this->parseCommitMessageUserList($value);
return $this->parseCommitMessageUserOrProjectList($value);
}
public function shouldAppearOnRevisionList() {
@ -242,7 +244,8 @@ final class DifferentialReviewersFieldSpecification
$handles = array_select_keys(
$handles,
array($this->getRevision()->getPrimaryReviewer())) + $handles;
$names = mpull($handles, 'getName');
$names = mpull($handles, 'getObjectName');
return 'Reviewers: '.implode(', ', $names);
}

View file

@ -914,6 +914,7 @@ final class DifferentialRevisionQuery
$edges = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(mpull($revisions, 'getPHID'))
->withEdgeTypes(array($type_reviewer))
->setOrder(PhabricatorEdgeQuery::ORDER_OLDEST_FIRST)
->execute();
foreach ($revisions as $revision) {
@ -923,6 +924,7 @@ final class DifferentialRevisionQuery
$data[] = array(
'relation' => DifferentialRevision::RELATION_REVIEWER,
'objectPHID' => $dst_phid,
'reasonPHID' => null,
);
}
@ -1024,11 +1026,11 @@ final class DifferentialRevisionQuery
->withSourcePHIDs(mpull($revisions, 'getPHID'))
->withEdgeTypes(array($edge_type))
->needEdgeData(true)
->setOrder(PhabricatorEdgeQuery::ORDER_OLDEST_FIRST)
->execute();
foreach ($revisions as $revision) {
$revision_edges = $edges[$revision->getPHID()][$edge_type];
$reviewers = array();
foreach ($revision_edges as $user_phid => $edge) {
$data = $edge['data'];

View file

@ -237,11 +237,13 @@ final class DifferentialRevision extends DifferentialDAO
$reviewer_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
$this->getPHID(),
PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER);
$reviewer_phids = array_reverse($reviewer_phids);
foreach ($reviewer_phids as $phid) {
$data[] = array(
'relation' => self::RELATION_REVIEWER,
'objectPHID' => $phid,
'reasonPHID' => null,
);
}

View file

@ -118,12 +118,12 @@ final class DifferentialAddCommentView extends AphrontView {
'add_reviewers' => 1,
'resign' => 1,
),
'src' => '/typeahead/common/users/',
'src' => '/typeahead/common/usersorprojects/',
'value' => $this->reviewers,
'row' => 'add-reviewers',
'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'),
'labels' => $add_reviewers_labels,
'placeholder' => pht('Type a user name...'),
'placeholder' => pht('Type a user or project name...'),
),
'add-ccs-tokenizer' => array(
'actions' => array('add_ccs' => 1),

View file

@ -107,4 +107,8 @@ final class PhabricatorNotificationQuery
return $this->formatWhereClause($where);
}
protected function getPagingValue($item) {
return $item->getChronologicalKey();
}
}

View file

@ -14,6 +14,19 @@ final class PhabricatorObjectHandle
private $status = PhabricatorObjectHandleStatus::STATUS_OPEN;
private $complete;
private $disabled;
private $objectName;
public function setObjectName($object_name) {
$this->objectName = $object_name;
return $this;
}
public function getObjectName() {
if (!$this->objectName) {
return $this->getName();
}
return $this->objectName;
}
public function setURI($uri) {
$this->uri = $uri;

View file

@ -39,6 +39,7 @@ final class PhabricatorProjectPHIDTypeProject extends PhabricatorPHIDType {
$id = $project->getID();
$handle->setName($name);
$handle->setObjectName('#'.rtrim($project->getPhrictionSlug(), '/'));
$handle->setURI("/project/view/{$id}/");
}
}

View file

@ -26,6 +26,10 @@ final class PhabricatorEdgeQuery extends PhabricatorQuery {
private $edgeTypes;
private $resultSet;
const ORDER_OLDEST_FIRST = 'order:oldest';
const ORDER_NEWEST_FIRST = 'order:newest';
private $order = self::ORDER_NEWEST_FIRST;
private $needEdgeData;
@ -74,6 +78,20 @@ final class PhabricatorEdgeQuery extends PhabricatorQuery {
}
/**
* Configure the order edge results are returned in.
*
* @param const Order constant.
* @return this
*
* @task config
*/
public function setOrder($order) {
$this->order = $order;
return $this;
}
/**
* When loading edges, also load edge data.
*
@ -303,7 +321,11 @@ final class PhabricatorEdgeQuery extends PhabricatorQuery {
* @task internal
*/
private function buildOrderClause($conn_r) {
return 'ORDER BY edge.dateCreated DESC, edge.seq ASC';
if ($this->order == self::ORDER_NEWEST_FIRST) {
return 'ORDER BY edge.dateCreated DESC, edge.seq DESC';
} else {
return 'ORDER BY edge.dateCreated ASC, edge.seq ASC';
}
}
}