@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.

make repo callsigns optional

Summary:
Ref T4245 Make repo callsigns optional
This is far from done and still very ugly. I'm just submitting it to check if i'm solving this in the right places.
Right now there's three places with duplicate code and building the identifierMap in the CommitQuery is very ugly.
If we only want to support this in the user frontend then i could hack it into the Markup rule itself and not touch the CommitQuery. Even uglier but more limited in scope...

Generally this approach will need a lot of "check this first and then try the other" in a few places.
I could move the Repository queries into a specialised PhabricatorRepositoryQuery method (withCallsignOrID) but i'm not sure about that.

Test Plan:
- phid.lookup works with R1 and rTEST (which is the same repo)
- R1 and rTEST euqally work in remarkup (tested in comments).
- Reviewed the following syntax also all works:
rTEST
rTESTd773137a7cb9
rTEST:d773137a7cb9
R1
R1:d773137a7cb9
d773137a7cb9
{rTEST}
{rTESTd773137a7cb9}
{rTEST:d773137a7cb9}
{R1}
{R1:d773137a7cb9}
{d773137a7cb9}

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin, epriestley

Maniphest Tasks: T4245

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

authored by

Fabian Stelzer and committed by
epriestley
f33e2de0 cd677161

+262 -46
+2
src/__phutil_library_map__.php
··· 552 552 'DiffusionRefNotFoundException' => 'applications/diffusion/exception/DiffusionRefNotFoundException.php', 553 553 'DiffusionRefsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php', 554 554 'DiffusionRenameHistoryQuery' => 'applications/diffusion/query/DiffusionRenameHistoryQuery.php', 555 + 'DiffusionRepositoryByIDRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryByIDRemarkupRule.php', 555 556 'DiffusionRepositoryController' => 'applications/diffusion/controller/DiffusionRepositoryController.php', 556 557 'DiffusionRepositoryCreateController' => 'applications/diffusion/controller/DiffusionRepositoryCreateController.php', 557 558 'DiffusionRepositoryDatasource' => 'applications/diffusion/typeahead/DiffusionRepositoryDatasource.php', ··· 3595 3596 'DiffusionReadmeView' => 'DiffusionView', 3596 3597 'DiffusionRefNotFoundException' => 'Exception', 3597 3598 'DiffusionRefsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 3599 + 'DiffusionRepositoryByIDRemarkupRule' => 'PhabricatorObjectRemarkupRule', 3598 3600 'DiffusionRepositoryController' => 'DiffusionController', 3599 3601 'DiffusionRepositoryCreateController' => 'DiffusionRepositoryEditController', 3600 3602 'DiffusionRepositoryDatasource' => 'PhabricatorTypeaheadDatasource',
+2 -1
src/applications/diffusion/application/PhabricatorDiffusionApplication.php
··· 40 40 41 41 public function getRemarkupRules() { 42 42 return array( 43 + new DiffusionCommitRemarkupRule(), 43 44 new DiffusionRepositoryRemarkupRule(), 44 - new DiffusionCommitRemarkupRule(), 45 + new DiffusionRepositoryByIDRemarkupRule(), 45 46 ); 46 47 } 47 48
+35 -25
src/applications/diffusion/query/DiffusionCommitQuery.php
··· 183 183 ->withIDs($repository_ids) 184 184 ->execute(); 185 185 186 + $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; 187 + $result = array(); 188 + 186 189 foreach ($commits as $key => $commit) { 187 190 $repo = idx($repos, $commit->getRepositoryID()); 188 191 if ($repo) { ··· 190 193 } else { 191 194 unset($commits[$key]); 192 195 } 193 - } 194 196 195 - if ($this->identifiers !== null) { 196 - $ids = array_fuse($this->identifiers); 197 - $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; 198 - 199 - $result = array(); 200 - foreach ($commits as $commit) { 201 - $prefix = 'r'.$commit->getRepository()->getCallsign(); 197 + // Build the identifierMap 198 + if ($this->identifiers !== null) { 199 + $ids = array_fuse($this->identifiers); 200 + $prefixes = array( 201 + 'r'.$commit->getRepository()->getCallsign(), 202 + 'r'.$commit->getRepository()->getCallsign().':', 203 + 'R'.$commit->getRepository()->getID().':', 204 + '', // No prefix is valid too and will only match the commitIdentifier 205 + ); 202 206 $suffix = $commit->getCommitIdentifier(); 203 207 204 208 if ($commit->getRepository()->isSVN()) { 205 - if (isset($ids[$prefix.$suffix])) { 206 - $result[$prefix.$suffix][] = $commit; 209 + foreach ($prefixes as $prefix) { 210 + if (isset($ids[$prefix.$suffix])) { 211 + $result[$prefix.$suffix][] = $commit; 212 + } 207 213 } 208 214 } else { 209 215 // This awkward construction is so we can link the commits up in O(N) 210 216 // time instead of O(N^2). 211 217 for ($ii = $min_qualified; $ii <= strlen($suffix); $ii++) { 212 218 $part = substr($suffix, 0, $ii); 213 - if (isset($ids[$prefix.$part])) { 214 - $result[$prefix.$part][] = $commit; 215 - } 216 - if (isset($ids[$part])) { 217 - $result[$part][] = $commit; 219 + foreach ($prefixes as $prefix) { 220 + if (isset($ids[$prefix.$part])) { 221 + $result[$prefix.$part][] = $commit; 222 + } 218 223 } 219 224 } 220 225 } 221 226 } 227 + } 222 228 229 + if ($result) { 223 230 foreach ($result as $identifier => $matching_commits) { 224 231 if (count($matching_commits) == 1) { 225 232 $result[$identifier] = head($matching_commits); ··· 229 236 unset($result[$identifier]); 230 237 } 231 238 } 232 - 233 239 $this->identifierMap += $result; 234 240 } 235 241 ··· 327 333 $bare = array(); 328 334 foreach ($this->identifiers as $identifier) { 329 335 $matches = null; 330 - preg_match('/^(?:r([A-Z]+))?(.*)$/', $identifier, $matches); 331 - $repo = nonempty($matches[1], null); 332 - $identifier = nonempty($matches[2], null); 336 + preg_match('/^(?:[rR]([A-Z]+:?|[0-9]+:))?(.*)$/', 337 + $identifier, $matches); 338 + $repo = nonempty(rtrim($matches[1], ':'), null); 339 + $commit_identifier = nonempty($matches[2], null); 333 340 334 341 if ($repo === null) { 335 342 if ($this->defaultRepository) { ··· 338 345 } 339 346 340 347 if ($repo === null) { 341 - if (strlen($identifier) < $min_unqualified) { 348 + if (strlen($commit_identifier) < $min_unqualified) { 342 349 continue; 343 350 } 344 - $bare[] = $identifier; 351 + $bare[] = $commit_identifier; 345 352 } else { 346 353 $refs[] = array( 347 354 'callsign' => $repo, 348 - 'identifier' => $identifier, 355 + 'identifier' => $commit_identifier, 349 356 ); 350 357 } 351 358 } ··· 362 369 363 370 if ($refs) { 364 371 $callsigns = ipull($refs, 'callsign'); 372 + 365 373 $repos = id(new PhabricatorRepositoryQuery()) 366 374 ->setViewer($this->getViewer()) 367 - ->withCallsigns($callsigns) 368 - ->execute(); 369 - $repos = mpull($repos, null, 'getCallsign'); 375 + ->withIdentifiers($callsigns); 376 + $repos->execute(); 377 + 378 + $repos = $repos->getIdentifierMap(); 370 379 371 380 foreach ($refs as $key => $ref) { 372 381 $repo = idx($repos, $ref['callsign']); 382 + 373 383 if (!$repo) { 374 384 continue; 375 385 }
-1
src/applications/diffusion/remarkup/DiffusionCommitRemarkupRule.php
··· 22 22 ->withIdentifiers($ids); 23 23 24 24 $query->execute(); 25 - 26 25 return $query->getIdentifierMap(); 27 26 } 28 27
+29
src/applications/diffusion/remarkup/DiffusionRepositoryByIDRemarkupRule.php
··· 1 + <?php 2 + 3 + final class DiffusionRepositoryByIDRemarkupRule 4 + extends PhabricatorObjectRemarkupRule { 5 + 6 + protected function getObjectNamePrefix() { 7 + return 'R'; 8 + } 9 + 10 + protected function getObjectIDPattern() { 11 + return '[0-9]+'; 12 + } 13 + 14 + public function getPriority() { 15 + return 460.0; 16 + } 17 + 18 + protected function loadObjects(array $ids) { 19 + $viewer = $this->getEngine()->getConfig('viewer'); 20 + 21 + $repos = id(new PhabricatorRepositoryQuery()) 22 + ->setViewer($viewer) 23 + ->withIdentifiers($ids); 24 + 25 + $repos->execute(); 26 + return $repos->getIdentifierMap(); 27 + } 28 + 29 + }
+8 -4
src/applications/diffusion/remarkup/DiffusionRepositoryRemarkupRule.php
··· 11 11 return '[A-Z]+'; 12 12 } 13 13 14 + public function getPriority() { 15 + return 460.0; 16 + } 17 + 14 18 protected function loadObjects(array $ids) { 15 19 $viewer = $this->getEngine()->getConfig('viewer'); 16 20 17 - $repositories = id(new PhabricatorRepositoryQuery()) 21 + $repos = id(new PhabricatorRepositoryQuery()) 18 22 ->setViewer($viewer) 19 - ->withCallsigns($ids) 20 - ->execute(); 23 + ->withIdentifiers($ids); 21 24 22 - return mpull($repositories, null, 'getCallsign'); 25 + $repos->execute(); 26 + return $repos->getIdentifierMap(); 23 27 } 24 28 25 29 }
+73
src/applications/diffusion/remarkup/__tests__/DiffusionCommitRemarkupRuleTestCase.php
··· 48 48 ), 49 49 ), 50 50 ), 51 + '{rP:1234 key=value}' => array( 52 + 'embed' => array( 53 + array( 54 + 'offset' => 1, 55 + 'id' => 'rP:1234', 56 + 'tail' => ' key=value', 57 + ), 58 + ), 59 + 'ref' => array( 60 + array( 61 + 'offset' => 1, 62 + 'id' => 'rP:1234', 63 + ), 64 + ), 65 + ), 66 + '{R123:1234 key=value}' => array( 67 + 'embed' => array( 68 + array( 69 + 'offset' => 1, 70 + 'id' => 'R123:1234', 71 + 'tail' => ' key=value', 72 + ), 73 + ), 74 + 'ref' => array( 75 + array( 76 + 'offset' => 1, 77 + 'id' => 'R123:1234', 78 + ), 79 + ), 80 + ), 81 + '{rP:12f3f6d3a9ef9c7731051815846810cb3c4cd248}' => array( 82 + 'embed' => array( 83 + array( 84 + 'offset' => 1, 85 + 'id' => 'rP:12f3f6d3a9ef9c7731051815846810cb3c4cd248', 86 + ), 87 + ), 88 + 'ref' => array( 89 + array( 90 + 'offset' => 1, 91 + 'id' => 'rP:12f3f6d3a9ef9c7731051815846810cb3c4cd248', 92 + ), 93 + ), 94 + ), 95 + '{R123:12f3f6d3a9ef9c7731051815846810cb3c4cd248}' => array( 96 + 'embed' => array( 97 + array( 98 + 'offset' => 1, 99 + 'id' => 'R123:12f3f6d3a9ef9c7731051815846810cb3c4cd248', 100 + ), 101 + ), 102 + 'ref' => array( 103 + array( 104 + 'offset' => 1, 105 + 'id' => 'R123:12f3f6d3a9ef9c7731051815846810cb3c4cd248', 106 + ), 107 + ), 108 + ), 109 + '{R123:12f3f6d3a9ef9c7731051815846810cb3c4cd248, key=value}' => array( 110 + 'embed' => array( 111 + array( 112 + 'offset' => 1, 113 + 'id' => 'R123:12f3f6d3a9ef9c7731051815846810cb3c4cd248', 114 + 'tail' => ', key=value', 115 + ), 116 + ), 117 + 'ref' => array( 118 + array( 119 + 'offset' => 1, 120 + 'id' => 'R123:12f3f6d3a9ef9c7731051815846810cb3c4cd248', 121 + ), 122 + ), 123 + ), 51 124 ); 52 125 53 126 foreach ($cases as $input => $expect) {
+2 -2
src/applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php
··· 54 54 $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; 55 55 56 56 return 57 - 'r[A-Z]+[1-9]\d*'. 57 + '(?:r[A-Z]+:?|R[0-9]+:)[1-9]\d*'. 58 58 '|'. 59 - 'r[A-Z]+[a-f0-9]{'.$min_qualified.',40}'. 59 + '(?:r[A-Z]+:?|R[0-9]+:)[a-f0-9]{'.$min_qualified.',40}'. 60 60 '|'. 61 61 '[a-f0-9]{'.$min_unqualified.',40}'; 62 62 }
+14 -12
src/applications/repository/phid/PhabricatorRepositoryRepositoryPHIDType.php
··· 44 44 } 45 45 46 46 public function canLoadNamedObject($name) { 47 - return preg_match('/^r[A-Z]+$/', $name); 47 + return preg_match('/^r[A-Z]+|R[0-9]+$/', $name); 48 48 } 49 49 50 50 public function loadNamedObjects( 51 51 PhabricatorObjectQuery $query, 52 52 array $names) { 53 53 54 + $results = array(); 54 55 $id_map = array(); 55 - foreach ($names as $name) { 56 + foreach ($names as $key => $name) { 56 57 $id = substr($name, 1); 57 58 $id_map[$id][] = $name; 59 + $names[$key] = substr($name, 1); 58 60 } 59 61 60 - $objects = id(new PhabricatorRepositoryQuery()) 62 + $query = id(new PhabricatorRepositoryQuery()) 61 63 ->setViewer($query->getViewer()) 62 - ->withCallsigns(array_keys($id_map)) 63 - ->execute(); 64 + ->withIdentifiers($names); 64 65 65 - $results = array(); 66 - foreach ($objects as $object) { 67 - $callsign = $object->getCallsign(); 68 - foreach (idx($id_map, $callsign, array()) as $name) { 69 - $results[$name] = $object; 66 + if ($query->execute()) { 67 + $objects = $query->getIdentifierMap(); 68 + foreach ($objects as $key => $object) { 69 + foreach (idx($id_map, $key, array()) as $name) 70 + $results[$name] = $object; 70 71 } 72 + return $results; 73 + } else { 74 + return array(); 71 75 } 72 - 73 - return $results; 74 76 } 75 77 76 78 }
+97 -1
src/applications/repository/query/PhabricatorRepositoryQuery.php
··· 12 12 private $remoteURIs; 13 13 private $anyProjectPHIDs; 14 14 15 + private $numericIdentifiers; 16 + private $callsignIdentifiers; 17 + private $phidIdentifiers; 18 + 19 + private $identifierMap; 20 + 15 21 const STATUS_OPEN = 'status-open'; 16 22 const STATUS_CLOSED = 'status-closed'; 17 23 const STATUS_ALL = 'status-all'; ··· 47 53 return $this; 48 54 } 49 55 56 + public function withIdentifiers(array $identifiers) { 57 + $ids = array(); $callsigns = array(); $phids = array(); 58 + foreach ($identifiers as $identifier) { 59 + if (ctype_digit($identifier)) { 60 + $ids[$identifier] = $identifier; 61 + } else { 62 + $repository_type = PhabricatorRepositoryRepositoryPHIDType::TYPECONST; 63 + if (phid_get_type($identifier) === $repository_type) { 64 + $phids[$identifier] = $identifier; 65 + } else { 66 + $callsigns[$identifier] = $identifier; 67 + } 68 + } 69 + } 70 + 71 + $this->numericIdentifiers = $ids; 72 + $this->callsignIdentifiers = $callsigns; 73 + $this->phidIdentifiers = $phids; 74 + return $this; 75 + } 76 + 50 77 public function withStatus($status) { 51 78 $this->status = $status; 52 79 return $this; ··· 102 129 return $this; 103 130 } 104 131 132 + public function getIdentifierMap() { 133 + if ($this->identifierMap === null) { 134 + throw new Exception( 135 + 'You must execute() the query before accessing the identifier map.'); 136 + } 137 + return $this->identifierMap; 138 + } 139 + 105 140 protected function loadPage() { 106 141 $table = new PhabricatorRepository(); 107 142 $conn_r = $table->establishConnection('r'); 143 + 144 + if ($this->identifierMap === null) { 145 + $this->identifierMap = array(); 146 + } 108 147 109 148 $data = queryfx_all( 110 149 $conn_r, ··· 202 241 } 203 242 } 204 243 244 + // Build the identifierMap 245 + if ($this->numericIdentifiers) { 246 + foreach ($this->numericIdentifiers as $id) { 247 + if (isset($repositories[$id])) { 248 + $this->identifierMap[$id] = $repositories[$id]; 249 + } 250 + } 251 + } 252 + 253 + if ($this->callsignIdentifiers) { 254 + $repository_callsigns = mpull($repositories, null, 'getCallsign'); 255 + 256 + foreach ($this->callsignIdentifiers as $callsign) { 257 + if (isset($repository_callsigns[$callsign])) { 258 + $this->identifierMap[$callsign] = $repository_callsigns[$callsign]; 259 + } 260 + } 261 + } 262 + 263 + if ($this->phidIdentifiers) { 264 + $repository_phids = mpull($repositories, null, 'getPHID'); 265 + 266 + foreach ($this->phidIdentifiers as $phid) { 267 + if (isset($repository_phids[$phid])) { 268 + $this->identifierMap[$phid] = $repository_phids[$phid]; 269 + } 270 + } 271 + } 272 + 205 273 return $repositories; 206 274 } 207 275 ··· 387 455 $this->callsigns); 388 456 } 389 457 458 + if ($this->numericIdentifiers || 459 + $this->callsignIdentifiers || 460 + $this->phidIdentifiers) { 461 + $identifier_clause = array(); 462 + 463 + if ($this->numericIdentifiers) { 464 + $identifier_clause[] = qsprintf( 465 + $conn_r, 466 + 'r.id IN (%Ld)', 467 + $this->numericIdentifiers); 468 + } 469 + 470 + if ($this->callsignIdentifiers) { 471 + $identifier_clause[] = qsprintf( 472 + $conn_r, 473 + 'r.callsign IN (%Ls)', 474 + $this->callsignIdentifiers); 475 + } 476 + 477 + if ($this->phidIdentifiers) { 478 + $identifier_clause[] = qsprintf( 479 + $conn_r, 480 + 'r.phid IN (%Ls)', 481 + $this->phidIdentifiers); 482 + } 483 + 484 + $where = array('('.implode(' OR ', $identifier_clause).')'); 485 + } 486 + 390 487 if ($this->types) { 391 488 $where[] = qsprintf( 392 489 $conn_r, ··· 419 516 420 517 return $this->formatWhereClause($where); 421 518 } 422 - 423 519 424 520 public function getQueryApplicationClass() { 425 521 return 'PhabricatorDiffusionApplication';