mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-10 23:01:04 +01:00
Mark Owners package reviewers which own nothing in the current diff
Summary: Ref PHI91. When Owners (or Herald, or manual user action) adds package reviewers to a revision, later updates to the revision make some of them less relevant or irrelevant. Provide a hint when a package reviewer doesn't own any of the paths that a diff changes. Humans can then decide if the reviewer is obsolete/irrelevant or not. This is a rough cut to get the feature working, design could probably use some tweaking if it sticks. Test Plan: {F5204309} Reviewers: amckinley Reviewed By: amckinley Subscribers: jboning Differential Revision: https://secure.phabricator.com/D18663
This commit is contained in:
parent
a39f5e1113
commit
fe646ec328
5 changed files with 118 additions and 40 deletions
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
abstract class DifferentialController extends PhabricatorController {
|
abstract class DifferentialController extends PhabricatorController {
|
||||||
|
|
||||||
|
private $packageChangesetMap;
|
||||||
|
private $pathPackageMap;
|
||||||
|
private $authorityPackages;
|
||||||
|
|
||||||
public function buildSideNavView($for_app = false) {
|
public function buildSideNavView($for_app = false) {
|
||||||
$viewer = $this->getRequest()->getUser();
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
|
||||||
|
@ -21,6 +25,88 @@ abstract class DifferentialController extends PhabricatorController {
|
||||||
return $this->buildSideNavView(true)->getMenu();
|
return $this->buildSideNavView(true)->getMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function buildPackageMaps(array $changesets) {
|
||||||
|
assert_instances_of($changesets, 'DifferentialChangeset');
|
||||||
|
|
||||||
|
$this->packageChangesetMap = array();
|
||||||
|
$this->pathPackageMap = array();
|
||||||
|
$this->authorityPackages = array();
|
||||||
|
|
||||||
|
if (!$changesets) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$have_owners = PhabricatorApplication::isClassInstalledForViewer(
|
||||||
|
'PhabricatorOwnersApplication',
|
||||||
|
$viewer);
|
||||||
|
if (!$have_owners) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$changeset = head($changesets);
|
||||||
|
$diff = $changeset->getDiff();
|
||||||
|
$repository_phid = $diff->getRepositoryPHID();
|
||||||
|
if (!$repository_phid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($viewer->getPHID()) {
|
||||||
|
$packages = id(new PhabricatorOwnersPackageQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
|
||||||
|
->withAuthorityPHIDs(array($viewer->getPHID()))
|
||||||
|
->execute();
|
||||||
|
$this->authorityPackages = $packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
$paths = mpull($changesets, 'getOwnersFilename');
|
||||||
|
|
||||||
|
$control_query = id(new PhabricatorOwnersPackageQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
|
||||||
|
->withControl($repository_phid, $paths);
|
||||||
|
$control_query->execute();
|
||||||
|
|
||||||
|
foreach ($changesets as $changeset) {
|
||||||
|
$changeset_path = $changeset->getOwnersFilename();
|
||||||
|
|
||||||
|
$packages = $control_query->getControllingPackagesForPath(
|
||||||
|
$repository_phid,
|
||||||
|
$changeset_path);
|
||||||
|
|
||||||
|
$this->pathPackageMap[$changeset_path] = $packages;
|
||||||
|
foreach ($packages as $package) {
|
||||||
|
$this->packageChangesetMap[$package->getPHID()][] = $changeset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getAuthorityPackages() {
|
||||||
|
if ($this->authorityPackages === null) {
|
||||||
|
throw new PhutilInvalidStateException('buildPackageMaps');
|
||||||
|
}
|
||||||
|
return $this->authorityPackages;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getChangesetPackages(DifferentialChangeset $changeset) {
|
||||||
|
if ($this->pathPackageMap === null) {
|
||||||
|
throw new PhutilInvalidStateException('buildPackageMaps');
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $changeset->getOwnersFilename();
|
||||||
|
return idx($this->pathPackageMap, $path, array());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPackageChangesets($package_phid) {
|
||||||
|
if ($this->packageChangesetMap === null) {
|
||||||
|
throw new PhutilInvalidStateException('buildPackageMaps');
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx($this->packageChangesetMap, $package_phid, array());
|
||||||
|
}
|
||||||
|
|
||||||
protected function buildTableOfContents(
|
protected function buildTableOfContents(
|
||||||
array $changesets,
|
array $changesets,
|
||||||
array $visible_changesets,
|
array $visible_changesets,
|
||||||
|
@ -29,40 +115,8 @@ abstract class DifferentialController extends PhabricatorController {
|
||||||
|
|
||||||
$toc_view = id(new PHUIDiffTableOfContentsListView())
|
$toc_view = id(new PHUIDiffTableOfContentsListView())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->setBare(true);
|
->setBare(true)
|
||||||
|
->setAuthorityPackages($this->getAuthorityPackages());
|
||||||
$have_owners = PhabricatorApplication::isClassInstalledForViewer(
|
|
||||||
'PhabricatorOwnersApplication',
|
|
||||||
$viewer);
|
|
||||||
if ($have_owners) {
|
|
||||||
$repository_phid = null;
|
|
||||||
if ($changesets) {
|
|
||||||
$changeset = head($changesets);
|
|
||||||
$diff = $changeset->getDiff();
|
|
||||||
$repository_phid = $diff->getRepositoryPHID();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$repository_phid) {
|
|
||||||
$have_owners = false;
|
|
||||||
} else {
|
|
||||||
if ($viewer->getPHID()) {
|
|
||||||
$packages = id(new PhabricatorOwnersPackageQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
|
|
||||||
->withAuthorityPHIDs(array($viewer->getPHID()))
|
|
||||||
->execute();
|
|
||||||
$toc_view->setAuthorityPackages($packages);
|
|
||||||
}
|
|
||||||
|
|
||||||
$paths = mpull($changesets, 'getOwnersFilename');
|
|
||||||
|
|
||||||
$control_query = id(new PhabricatorOwnersPackageQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
|
|
||||||
->withControl($repository_phid, $paths);
|
|
||||||
$control_query->execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($changesets as $changeset_id => $changeset) {
|
foreach ($changesets as $changeset_id => $changeset) {
|
||||||
$is_visible = isset($visible_changesets[$changeset_id]);
|
$is_visible = isset($visible_changesets[$changeset_id]);
|
||||||
|
@ -78,12 +132,8 @@ abstract class DifferentialController extends PhabricatorController {
|
||||||
->setCoverage(idx($coverage, $filename))
|
->setCoverage(idx($coverage, $filename))
|
||||||
->setCoverageID($coverage_id);
|
->setCoverageID($coverage_id);
|
||||||
|
|
||||||
if ($have_owners) {
|
$packages = $this->getChangesetPackages($changeset);
|
||||||
$packages = $control_query->getControllingPackagesForPath(
|
$item->setPackages($packages);
|
||||||
$repository_phid,
|
|
||||||
$changeset->getOwnersFilename());
|
|
||||||
$item->setPackages($packages);
|
|
||||||
}
|
|
||||||
|
|
||||||
$toc_view->addItem($item);
|
$toc_view->addItem($item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,8 @@ final class DifferentialDiffViewController extends DifferentialController {
|
||||||
$changesets = $diff->loadChangesets();
|
$changesets = $diff->loadChangesets();
|
||||||
$changesets = msort($changesets, 'getSortKey');
|
$changesets = msort($changesets, 'getSortKey');
|
||||||
|
|
||||||
|
$this->buildPackageMaps($changesets);
|
||||||
|
|
||||||
$table_of_contents = $this->buildTableOfContents(
|
$table_of_contents = $this->buildTableOfContents(
|
||||||
$changesets,
|
$changesets,
|
||||||
$changesets,
|
$changesets,
|
||||||
|
|
|
@ -326,11 +326,21 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
||||||
$other_view = $this->renderOtherRevisions($other_revisions);
|
$other_view = $this->renderOtherRevisions($other_revisions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->buildPackageMaps($changesets);
|
||||||
|
|
||||||
$toc_view = $this->buildTableOfContents(
|
$toc_view = $this->buildTableOfContents(
|
||||||
$changesets,
|
$changesets,
|
||||||
$visible_changesets,
|
$visible_changesets,
|
||||||
$target->loadCoverageMap($viewer));
|
$target->loadCoverageMap($viewer));
|
||||||
|
|
||||||
|
// Attach changesets to each reviewer so we can show which Owners package
|
||||||
|
// reviewers own no files.
|
||||||
|
foreach ($revision->getReviewers() as $reviewer) {
|
||||||
|
$reviewer_phid = $reviewer->getReviewerPHID();
|
||||||
|
$reviewer_changesets = $this->getPackageChangesets($reviewer_phid);
|
||||||
|
$reviewer->attachChangesets($reviewer_changesets);
|
||||||
|
}
|
||||||
|
|
||||||
$tab_group = id(new PHUITabGroupView())
|
$tab_group = id(new PHUITabGroupView())
|
||||||
->addTab(
|
->addTab(
|
||||||
id(new PHUITabView())
|
id(new PHUITabView())
|
||||||
|
|
|
@ -12,6 +12,7 @@ final class DifferentialReviewer
|
||||||
protected $voidedPHID;
|
protected $voidedPHID;
|
||||||
|
|
||||||
private $authority = array();
|
private $authority = array();
|
||||||
|
private $changesets = self::ATTACHABLE;
|
||||||
|
|
||||||
protected function getConfiguration() {
|
protected function getConfiguration() {
|
||||||
return array(
|
return array(
|
||||||
|
@ -54,6 +55,15 @@ final class DifferentialReviewer
|
||||||
return $this->assertAttachedKey($this->authority, $cache_fragment);
|
return $this->assertAttachedKey($this->authority, $cache_fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function attachChangesets(array $changesets) {
|
||||||
|
$this->changesets = $changesets;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getChangesets() {
|
||||||
|
return $this->assertAttached($this->changesets);
|
||||||
|
}
|
||||||
|
|
||||||
public function isResigned() {
|
public function isResigned() {
|
||||||
$status_resigned = DifferentialReviewerStatus::STATUS_RESIGNED;
|
$status_resigned = DifferentialReviewerStatus::STATUS_RESIGNED;
|
||||||
return ($this->getReviewerStatus() == $status_resigned);
|
return ($this->getReviewerStatus() == $status_resigned);
|
||||||
|
|
|
@ -150,6 +150,12 @@ final class DifferentialReviewersView extends AphrontView {
|
||||||
$item->setIcon($icon, $color, $label);
|
$item->setIcon($icon, $color, $label);
|
||||||
$item->setTarget($handle->renderHovercardLink());
|
$item->setTarget($handle->renderHovercardLink());
|
||||||
|
|
||||||
|
if ($reviewer->isPackage()) {
|
||||||
|
if (!$reviewer->getChangesets()) {
|
||||||
|
$item->setNote(pht('(Owns No Changed Paths)'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$view->addItem($item);
|
$view->addItem($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue