@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
at recaptime-dev/main 144 lines 4.3 kB view raw
1<?php 2 3final class DiffusionLowLevelCommitFieldsQuery 4 extends DiffusionLowLevelQuery { 5 6 private $ref; 7 private $revisionMatchData = array( 8 'usedURI' => null, 9 'foundURI' => null, 10 'validDomain' => null, 11 'matchHashType' => null, 12 'matchHashValue' => null, 13 ); 14 15 public function withCommitRef(DiffusionCommitRef $ref) { 16 $this->ref = $ref; 17 return $this; 18 } 19 20 public function getRevisionMatchData() { 21 return $this->revisionMatchData; 22 } 23 24 private function setRevisionMatchData($key, $value) { 25 $this->revisionMatchData[$key] = $value; 26 return $this; 27 } 28 29 protected function executeQuery() { 30 $ref = $this->ref; 31 $message = $ref->getMessage(); 32 $hashes = $ref->getHashes(); 33 34 $params = array( 35 'corpus' => $message, 36 'partial' => true, 37 ); 38 39 $result = id(new ConduitCall('differential.parsecommitmessage', $params)) 40 ->setUser(PhabricatorUser::getOmnipotentUser()) 41 ->execute(); 42 $fields = $result['fields']; 43 44 $revision_id = idx($fields, 'revisionID'); 45 if ($revision_id) { 46 $this->setRevisionMatchData('usedURI', true); 47 } else { 48 $this->setRevisionMatchData('usedURI', false); 49 } 50 $revision_id_info = $result['revisionIDFieldInfo']; 51 $this->setRevisionMatchData('foundURI', $revision_id_info['value']); 52 $this->setRevisionMatchData( 53 'validDomain', 54 $revision_id_info['validDomain']); 55 56 // If there is no "Differential Revision:" field in the message, try to 57 // identify the revision by doing a hash lookup. 58 59 if (!$revision_id && $hashes) { 60 $hash_list = array(); 61 foreach ($hashes as $hash) { 62 $hash_list[] = array($hash->getHashType(), $hash->getHashValue()); 63 } 64 $revisions = id(new DifferentialRevisionQuery()) 65 ->setViewer(PhabricatorUser::getOmnipotentUser()) 66 ->needHashes(true) 67 ->withCommitHashes($hash_list) 68 ->execute(); 69 70 if ($revisions) { 71 $revision = $this->pickBestRevision($revisions); 72 73 $fields['revisionID'] = $revision->getID(); 74 $revision_hashes = $revision->getHashes(); 75 76 $revision_hashes = DiffusionCommitHash::convertArrayToObjects( 77 $revision_hashes); 78 $revision_hashes = mpull($revision_hashes, null, 'getHashType'); 79 80 // sort the hashes in the order the mighty 81 // @{class:ArcanstDifferentialRevisionHash} does; probably unnecessary 82 // but should future proof things nicely. 83 $revision_hashes = array_select_keys( 84 $revision_hashes, 85 ArcanistDifferentialRevisionHash::getTypes()); 86 87 foreach ($hashes as $hash) { 88 $revision_hash = idx($revision_hashes, $hash->getHashType()); 89 if (!$revision_hash) { 90 continue; 91 } 92 if ($revision_hash->getHashValue() == $hash->getHashValue()) { 93 $this->setRevisionMatchData( 94 'matchHashType', 95 $hash->getHashType()); 96 $this->setRevisionMatchData( 97 'matchHashValue', 98 $hash->getHashValue()); 99 break; 100 } 101 } 102 } 103 } 104 105 return $fields; 106 } 107 108 109 /** 110 * When querying for revisions by hash, more than one revision may be found. 111 * This function identifies the "best" revision from such a set. Typically, 112 * there is only one revision found. Otherwise, we try to pick an accepted 113 * revision first, followed by an open revision, and otherwise we go with a 114 * closed or abandoned revision as a last resort. 115 * 116 * @param array<DifferentialRevision> $revisions 117 */ 118 private function pickBestRevision(array $revisions) { 119 assert_instances_of($revisions, DifferentialRevision::class); 120 121 // If we have more than one revision of a given status, choose the most 122 // recently updated one. 123 $revisions = msort($revisions, 'getDateModified'); 124 $revisions = array_reverse($revisions); 125 126 // Try to find an accepted revision first. 127 foreach ($revisions as $revision) { 128 if ($revision->isAccepted()) { 129 return $revision; 130 } 131 } 132 133 // Try to find an open revision. 134 foreach ($revisions as $revision) { 135 if (!$revision->isClosed()) { 136 return $revision; 137 } 138 } 139 140 // Settle for whatever's left. 141 return head($revisions); 142 } 143 144}