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

Make Owners behavior when multiple packages own the same path with different dominion rules more consistent

Summary:
Fixes T12789. See that task for discussion. Currently, when multiple packages own the same path but have different dominion rules we get some weird/aribtrary/inconsistent results.

Instead, implement these rules:

  - If zero or more weak and one or more strong packages claim a path, the strong packages (exactly) all own it.
  - If one or more weak packages and zero strong packages claim a path, the weak packages all own it.

The major change here is that instead of keeping the //first// weak package we run into, we keep all the weak packages with the longest claim that we run into.

This needs to be implemented twice because Owners has two different near-copies of this logic, only one of which has test coverage. Some day maybe this will get fixed.

Test Plan:
  - Added failing unit tests, made them pass.
  - Viewed all A/B strong/weak combinations in Diffusion, saw sensible ownership results.

Reviewers: chad, lvital

Reviewed By: lvital

Subscribers: lvital

Maniphest Tasks: T12789

Differential Revision: https://secure.phabricator.com/D18064
This commit is contained in:
epriestley 2017-06-01 13:00:16 -07:00
parent b66bf6af92
commit 9f8907ccf7
3 changed files with 156 additions and 17 deletions

View file

@ -398,13 +398,36 @@ final class PhabricatorOwnersPackageQuery
}
}
// At each strength level, drop weak packages if there are also strong
// packages of the same strength.
$strength_map = igroup($matches, 'strength');
foreach ($strength_map as $strength => $package_list) {
$any_strong = false;
foreach ($package_list as $package_id => $package) {
if (!$package['weak']) {
$any_strong = true;
break;
}
}
if ($any_strong) {
foreach ($package_list as $package_id => $package) {
if ($package['weak']) {
unset($matches[$package_id]);
}
}
}
}
$matches = isort($matches, 'strength');
$matches = array_reverse($matches);
$first_id = null;
$strongest = null;
foreach ($matches as $package_id => $match) {
if ($first_id === null) {
$first_id = $package_id;
if ($strongest === null) {
$strongest = $match['strength'];
}
if ($match['strength'] === $strongest) {
continue;
}

View file

@ -297,27 +297,54 @@ final class PhabricatorOwnersPackage
// a more specific package.
if ($weak) {
foreach ($path_packages as $match => $packages) {
// Group packages by length.
$length_map = array();
foreach ($packages as $package_id => $package) {
$length_map[$package['length']][$package_id] = $package;
}
// For each path length, remove all weak packages if there are any
// strong packages of the same length. This makes sure that if there
// are one or more strong claims on a particular path, only those
// claims stand.
foreach ($length_map as $package_list) {
$any_strong = false;
foreach ($package_list as $package_id => $package) {
if (!isset($weak[$package_id])) {
$any_strong = true;
break;
}
}
if ($any_strong) {
foreach ($package_list as $package_id => $package) {
if (isset($weak[$package_id])) {
unset($packages[$package_id]);
}
}
}
}
$packages = isort($packages, 'length');
$packages = array_reverse($packages, true);
$first = null;
$best_length = null;
foreach ($packages as $package_id => $package) {
// If this is the first package we've encountered, note it and
// continue. We're iterating over the packages from longest to
// shortest match, so this package always has the strongest claim
// on the path.
if ($first === null) {
$first = $package_id;
// If this is the first package we've encountered, note its length.
// We're iterating over the packages from longest to shortest match,
// so packages of this length always have the best claim on the path.
if ($best_length === null) {
$best_length = $package['length'];
}
// If this package has the same length as the best length, its claim
// stands.
if ($package['length'] === $best_length) {
continue;
}
// If this is the first package we saw, its claim stands even if it
// is a weak package.
if ($first === $package_id) {
continue;
}
// If this is a weak package and not the first package we saw,
// If this is a weak package and does not have the best length,
// cede its claim to the stronger package.
if (isset($weak[$package_id])) {
unset($packages[$package_id]);

View file

@ -100,6 +100,95 @@ final class PhabricatorOwnersPackageTestCase extends PhabricatorTestCase {
PhabricatorOwnersPackage::findLongestPathsPerPackage($rows, $paths));
// Test cases where multiple packages own the same path, with various
// dominion rules.
$main_c = 'src/applications/main/main.c';
$rules = array(
// All claims strong.
array(
PhabricatorOwnersPackage::DOMINION_STRONG,
PhabricatorOwnersPackage::DOMINION_STRONG,
PhabricatorOwnersPackage::DOMINION_STRONG,
),
// All claims weak.
array(
PhabricatorOwnersPackage::DOMINION_WEAK,
PhabricatorOwnersPackage::DOMINION_WEAK,
PhabricatorOwnersPackage::DOMINION_WEAK,
),
// Mixture of strong and weak claims, strong first.
array(
PhabricatorOwnersPackage::DOMINION_STRONG,
PhabricatorOwnersPackage::DOMINION_STRONG,
PhabricatorOwnersPackage::DOMINION_WEAK,
),
// Mixture of strong and weak claims, weak first.
array(
PhabricatorOwnersPackage::DOMINION_WEAK,
PhabricatorOwnersPackage::DOMINION_STRONG,
PhabricatorOwnersPackage::DOMINION_STRONG,
),
);
foreach ($rules as $rule_idx => $rule) {
$rows = array(
array(
'id' => 1,
'excluded' => 0,
'dominion' => $rule[0],
'path' => $main_c,
),
array(
'id' => 2,
'excluded' => 0,
'dominion' => $rule[1],
'path' => $main_c,
),
array(
'id' => 3,
'excluded' => 0,
'dominion' => $rule[2],
'path' => $main_c,
),
);
$paths = array(
$main_c => $pvalue,
);
// If one or more packages have strong dominion, they should own the
// path. If not, all the packages with weak dominion should own the
// path.
$strong = array();
$weak = array();
foreach ($rule as $idx => $dominion) {
if ($dominion == PhabricatorOwnersPackage::DOMINION_STRONG) {
$strong[] = $idx + 1;
} else {
$weak[] = $idx + 1;
}
}
if ($strong) {
$expect = $strong;
} else {
$expect = $weak;
}
$expect = array_fill_keys($expect, strlen($main_c));
$actual = PhabricatorOwnersPackage::findLongestPathsPerPackage(
$rows,
$paths);
ksort($actual);
$this->assertEqual(
$expect,
$actual,
pht('Ruleset "%s" for Identical Ownership', $rule_idx));
}
}
}