@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Allow monogrammed objects to be parsed from the `arc` command line in "Reviewers" and similar fields

Summary:
Ref T10939. This allows the CLI to parse reviewers and subscribers like this:

```Reviewers: epriestley, O123 Some Package Name```

The rule goes:

- If a reviewer or subscriber starts with a monogram (like `X111`), just look that up and ignore everything until the next comma.
- Otherwise, split it on spaces and look up each part.

This means that these are valid:

```
alincoln htaft
alincoln, htaft
#a #b epriestley
O123 Some Package, epriestley, #b
```

I think the only real downside is that this:

```
O123 Some Package epriestley
```

...ignores the "epriestley" part. However, I don't expect users to be typing package monograms manually -- they just need to be representable by `arc land` and `arc diff --edit` and such. Those flows will always add commas and make the parse unambiguous.

Test Plan:
- Added test coverage.
- `amend --show`'d a revision with a package subscriber (this isn't currently possible to produce using the web UI, it came from a future change) and saw `Subscribers: O123 package name, usera, userb`.
- Updated a revision with a package subscriber.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10939

Differential Revision: https://secure.phabricator.com/D15911

+96 -9
+1 -1
src/applications/differential/customfield/DifferentialCustomField.php
··· 54 54 if ($handle->getPolicyFiltered()) { 55 55 $out[] = $handle->getPHID(); 56 56 } else if ($handle->isComplete()) { 57 - $out[] = $handle->getObjectName(); 57 + $out[] = $handle->getCommandLineObjectName(); 58 58 } 59 59 } 60 60
+1
src/applications/differential/customfield/DifferentialReviewersField.php
··· 146 146 array( 147 147 PhabricatorPeopleUserPHIDType::TYPECONST, 148 148 PhabricatorProjectProjectPHIDType::TYPECONST, 149 + PhabricatorOwnersPackagePHIDType::TYPECONST, 149 150 )); 150 151 } 151 152
+1
src/applications/differential/customfield/DifferentialSubscribersField.php
··· 78 78 array( 79 79 PhabricatorPeopleUserPHIDType::TYPECONST, 80 80 PhabricatorProjectProjectPHIDType::TYPECONST, 81 + PhabricatorOwnersPackagePHIDType::TYPECONST, 81 82 )); 82 83 } 83 84
+15
src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php
··· 205 205 $error->setIsMissingFieldError(true); 206 206 $errors[] = $error; 207 207 } 208 + 209 + foreach ($xactions as $xaction) { 210 + $new = $xaction->getNewValue(); 211 + if (preg_match('([,!])', $new)) { 212 + $errors[] = new PhabricatorApplicationTransactionValidationError( 213 + $type, 214 + pht('Invalid'), 215 + pht( 216 + 'Package names may not contain commas (",") or exclamation '. 217 + 'marks ("!"). These characters are ambiguous when package '. 218 + 'names are parsed from the command line.'), 219 + $xaction); 220 + } 221 + } 222 + 208 223 break; 209 224 case PhabricatorOwnersPackageTransaction::TYPE_PATHS: 210 225 if (!$xactions) {
+5 -3
src/applications/owners/phid/PhabricatorOwnersPackagePHIDType.php
··· 40 40 $name = $package->getName(); 41 41 $id = $package->getID(); 42 42 43 - $handle->setName($monogram); 44 - $handle->setFullName("{$monogram}: {$name}"); 45 - $handle->setURI("/owners/package/{$id}/"); 43 + $handle 44 + ->setName($monogram) 45 + ->setFullName("{$monogram}: {$name}") 46 + ->setCommandLineObjectName("{$monogram} {$name}") 47 + ->setURI("/owners/package/{$id}/"); 46 48 47 49 if ($package->isArchived()) { 48 50 $handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED);
+14
src/applications/phid/PhabricatorObjectHandle.php
··· 29 29 private $policyFiltered; 30 30 private $subtitle; 31 31 private $tokenIcon; 32 + private $commandLineObjectName; 32 33 33 34 public function setIcon($icon) { 34 35 $this->icon = $icon; ··· 194 195 return $this->fullName; 195 196 } 196 197 return $this->getName(); 198 + } 199 + 200 + public function setCommandLineObjectName($command_line_object_name) { 201 + $this->commandLineObjectName = $command_line_object_name; 202 + return $this; 203 + } 204 + 205 + public function getCommandLineObjectName() { 206 + if ($this->commandLineObjectName !== null) { 207 + return $this->commandLineObjectName; 208 + } 209 + 210 + return $this->getObjectName(); 197 211 } 198 212 199 213 public function setTitle($title) {
+44 -4
src/applications/phid/query/PhabricatorObjectListQuery.php
··· 45 45 46 46 public function execute() { 47 47 $names = $this->getObjectList(); 48 - $names = array_unique(array_filter(preg_split('/[\s,]+/', $names))); 49 48 50 - $objects = $this->loadObjects($names); 49 + // First, normalize any internal whitespace so we don't get weird results 50 + // if linebreaks hit in weird spots. 51 + $names = preg_replace('/\s+/', ' ', $names); 52 + 53 + // Split the list on commas. 54 + $names = explode(',', $names); 55 + 56 + // Trim and remove empty tokens. 57 + foreach ($names as $key => $name) { 58 + $name = trim($name); 59 + 60 + if (!strlen($name)) { 61 + unset($names[$key]); 62 + continue; 63 + } 64 + 65 + $names[$key] = $name; 66 + } 67 + 68 + // Remove duplicates. 69 + $names = array_unique($names); 70 + 71 + $name_map = array(); 72 + foreach ($names as $name) { 73 + $parts = explode(' ', $name); 74 + 75 + // If this looks like a monogram, ignore anything after the first token. 76 + // This allows us to parse "O123 Package Name" as though it was "O123", 77 + // which we can look up. 78 + if (preg_match('/^[A-Z]\d+\z/', $parts[0])) { 79 + $name_map[$parts[0]] = $name; 80 + } else { 81 + // For anything else, split it on spaces and use each token as a 82 + // value. This means "alincoln htaft", separated with a space instead 83 + // of with a comma, is two different users. 84 + foreach ($parts as $part) { 85 + $name_map[$part] = $part; 86 + } 87 + } 88 + } 89 + 90 + $objects = $this->loadObjects(array_keys($name_map)); 51 91 52 92 $types = array(); 53 93 foreach ($objects as $name => $object) { ··· 66 106 $invalid = array_mergev($invalid); 67 107 68 108 $missing = array(); 69 - foreach ($names as $name) { 70 - if (empty($objects[$name])) { 109 + foreach ($name_map as $key => $name) { 110 + if (empty($objects[$key])) { 71 111 $missing[] = $name; 72 112 } 73 113 }
+15 -1
src/applications/phid/query/__tests__/PhabricatorObjectListQueryTestCase.php
··· 13 13 $name = $user->getUsername(); 14 14 $phid = $user->getPHID(); 15 15 16 - 17 16 $result = $this->parseObjectList("@{$name}"); 18 17 $this->assertEqual(array($phid), $result); 19 18 ··· 28 27 29 28 $result = $this->parseObjectList(''); 30 29 $this->assertEqual(array(), $result); 30 + 31 + 32 + $package = PhabricatorOwnersPackage::initializeNewPackage($user) 33 + ->setName(pht('Query Test Package')) 34 + ->save(); 35 + 36 + $package_phid = $package->getPHID(); 37 + $package_mono = $package->getMonogram(); 38 + 39 + $result = $this->parseObjectList("{$package_mono} Any Ignored Text"); 40 + $this->assertEqual(array($package_phid), $result); 41 + 42 + $result = $this->parseObjectList("{$package_mono} Any Text, {$name}"); 43 + $this->assertEqual(array($package_phid, $phid), $result); 44 + 31 45 32 46 // Expect failure when loading a user if objects must be of type "DUCK". 33 47 $caught = null;