@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 upstream/main 290 lines 8.4 kB view raw
1<?php 2 3abstract class DifferentialController extends PhabricatorController { 4 5 private $packageChangesetMap; 6 private $pathPackageMap; 7 private $authorityPackages; 8 9 public function buildSideNavView($for_app = false) { 10 $viewer = $this->getRequest()->getUser(); 11 12 $nav = new AphrontSideNavFilterView(); 13 $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); 14 15 id(new DifferentialRevisionSearchEngine()) 16 ->setViewer($viewer) 17 ->addNavigationItems($nav->getMenu()); 18 19 $nav->selectFilter(null); 20 21 return $nav; 22 } 23 24 public function buildApplicationMenu() { 25 return $this->buildSideNavView(true)->getMenu(); 26 } 27 28 /** 29 * @param array<DifferentialChangeset> $changesets 30 */ 31 protected function buildPackageMaps(array $changesets) { 32 assert_instances_of($changesets, DifferentialChangeset::class); 33 34 $this->packageChangesetMap = array(); 35 $this->pathPackageMap = array(); 36 $this->authorityPackages = array(); 37 38 if (!$changesets) { 39 return; 40 } 41 42 $viewer = $this->getViewer(); 43 44 $have_owners = PhabricatorApplication::isClassInstalledForViewer( 45 PhabricatorOwnersApplication::class, 46 $viewer); 47 if (!$have_owners) { 48 return; 49 } 50 51 $changeset = head($changesets); 52 $diff = $changeset->getDiff(); 53 $repository_phid = $diff->getRepositoryPHID(); 54 if (!$repository_phid) { 55 return; 56 } 57 58 if ($viewer->getPHID()) { 59 $packages = id(new PhabricatorOwnersPackageQuery()) 60 ->setViewer($viewer) 61 ->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE)) 62 ->withAuthorityPHIDs(array($viewer->getPHID())) 63 ->execute(); 64 $this->authorityPackages = $packages; 65 } 66 67 $paths = mpull($changesets, 'getOwnersFilename'); 68 69 $control_query = id(new PhabricatorOwnersPackageQuery()) 70 ->setViewer($viewer) 71 ->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE)) 72 ->withControl($repository_phid, $paths); 73 $control_query->execute(); 74 75 foreach ($changesets as $changeset) { 76 $changeset_path = $changeset->getOwnersFilename(); 77 78 $packages = $control_query->getControllingPackagesForPath( 79 $repository_phid, 80 $changeset_path); 81 82 // If this particular changeset is generated code and the package does 83 // not match generated code, remove it from the list. 84 if ($changeset->isGeneratedChangeset()) { 85 foreach ($packages as $key => $package) { 86 if ($package->getMustMatchUngeneratedPaths()) { 87 unset($packages[$key]); 88 } 89 } 90 } 91 92 $this->pathPackageMap[$changeset_path] = $packages; 93 foreach ($packages as $package) { 94 $this->packageChangesetMap[$package->getPHID()][] = $changeset; 95 } 96 } 97 } 98 99 protected function getAuthorityPackages() { 100 if ($this->authorityPackages === null) { 101 throw new PhutilInvalidStateException('buildPackageMaps'); 102 } 103 return $this->authorityPackages; 104 } 105 106 protected function getChangesetPackages(DifferentialChangeset $changeset) { 107 if ($this->pathPackageMap === null) { 108 throw new PhutilInvalidStateException('buildPackageMaps'); 109 } 110 111 $path = $changeset->getOwnersFilename(); 112 return idx($this->pathPackageMap, $path, array()); 113 } 114 115 protected function getPackageChangesets($package_phid) { 116 if ($this->packageChangesetMap === null) { 117 throw new PhutilInvalidStateException('buildPackageMaps'); 118 } 119 120 return idx($this->packageChangesetMap, $package_phid, array()); 121 } 122 123 protected function buildTableOfContents( 124 array $changesets, 125 array $visible_changesets, 126 array $coverage) { 127 $viewer = $this->getViewer(); 128 129 $toc_view = id(new PHUIDiffTableOfContentsListView()) 130 ->setViewer($viewer) 131 ->setBare(true) 132 ->setAuthorityPackages($this->getAuthorityPackages()); 133 134 foreach ($changesets as $changeset_id => $changeset) { 135 $is_visible = isset($visible_changesets[$changeset_id]); 136 $anchor = $changeset->getAnchorName(); 137 138 $filename = $changeset->getFilename(); 139 $coverage_id = 'differential-mcoverage-'.md5($filename); 140 141 $item = id(new PHUIDiffTableOfContentsItemView()) 142 ->setChangeset($changeset) 143 ->setIsVisible($is_visible) 144 ->setAnchor($anchor) 145 ->setCoverage(idx($coverage, $filename)) 146 ->setCoverageID($coverage_id); 147 148 $packages = $this->getChangesetPackages($changeset); 149 $item->setPackages($packages); 150 151 $toc_view->addItem($item); 152 } 153 154 return $toc_view; 155 } 156 157 protected function loadDiffProperties(array $diffs) { 158 $diffs = mpull($diffs, null, 'getID'); 159 160 $properties = id(new DifferentialDiffProperty())->loadAllWhere( 161 'diffID IN (%Ld)', 162 array_keys($diffs)); 163 $properties = mgroup($properties, 'getDiffID'); 164 165 foreach ($diffs as $id => $diff) { 166 $values = idx($properties, $id, array()); 167 $values = mpull($values, 'getData', 'getName'); 168 $diff->attachDiffProperties($values); 169 } 170 } 171 172 173 protected function loadHarbormasterData(array $diffs) { 174 $viewer = $this->getViewer(); 175 176 $diffs = mpull($diffs, null, 'getPHID'); 177 178 $buildables = id(new HarbormasterBuildableQuery()) 179 ->setViewer($viewer) 180 ->withBuildablePHIDs(array_keys($diffs)) 181 ->withManualBuildables(false) 182 ->needBuilds(true) 183 ->needTargets(true) 184 ->execute(); 185 186 $buildables = mpull($buildables, null, 'getBuildablePHID'); 187 foreach ($diffs as $phid => $diff) { 188 $diff->attachBuildable(idx($buildables, $phid)); 189 } 190 191 $target_map = array(); 192 foreach ($diffs as $phid => $diff) { 193 $target_map[$phid] = $diff->getBuildTargetPHIDs(); 194 } 195 $all_target_phids = array_mergev($target_map); 196 197 if ($all_target_phids) { 198 $unit_messages = id(new HarbormasterBuildUnitMessageQuery()) 199 ->setViewer($viewer) 200 ->withBuildTargetPHIDs($all_target_phids) 201 ->execute(); 202 $unit_messages = mgroup($unit_messages, 'getBuildTargetPHID'); 203 } else { 204 $unit_messages = array(); 205 } 206 207 foreach ($diffs as $phid => $diff) { 208 $target_phids = idx($target_map, $phid, array()); 209 $messages = array_select_keys($unit_messages, $target_phids); 210 $messages = array_mergev($messages); 211 $diff->attachUnitMessages($messages); 212 } 213 214 // For diffs with no messages, look for legacy unit messages stored on the 215 // diff itself. 216 foreach ($diffs as $phid => $diff) { 217 if ($diff->getUnitMessages()) { 218 continue; 219 } 220 221 if (!$diff->hasDiffProperty('arc:unit')) { 222 continue; 223 } 224 225 $legacy_messages = $diff->getProperty('arc:unit'); 226 if (!$legacy_messages) { 227 continue; 228 } 229 230 // Show the top 100 legacy lint messages. Previously, we showed some 231 // by default and let the user toggle the rest. With modern messages, 232 // we can send the user to the Harbormaster detail page. Just show 233 // "a lot" of messages in legacy cases to try to strike a balance 234 // between implementation simplicity and compatibility. 235 $legacy_messages = array_slice($legacy_messages, 0, 100); 236 237 $messages = array(); 238 foreach ($legacy_messages as $message) { 239 $messages[] = HarbormasterBuildUnitMessage::newFromDictionary( 240 new HarbormasterBuildTarget(), 241 $this->getModernUnitMessageDictionary($message)); 242 } 243 244 $diff->attachUnitMessages($messages); 245 } 246 } 247 248 private function getModernUnitMessageDictionary(array $map) { 249 // Strip out `null` values to satisfy stricter typechecks. 250 foreach ($map as $key => $value) { 251 if ($value === null) { 252 unset($map[$key]); 253 } 254 } 255 256 // Cast duration to a float since it used to be a string in some 257 // cases. 258 if (isset($map['duration'])) { 259 $map['duration'] = (float)$map['duration']; 260 } 261 262 return $map; 263 } 264 265 protected function getDiffTabLabels(array $diffs) { 266 // Make sure we're only going to render unique diffs. 267 $diffs = mpull($diffs, null, 'getID'); 268 $labels = array(pht('Left'), pht('Right')); 269 270 $results = array(); 271 272 foreach ($diffs as $diff) { 273 if (count($diffs) == 2) { 274 $label = array_shift($labels); 275 $label = pht('%s (Diff %d)', $label, $diff->getID()); 276 } else { 277 $label = pht('Diff %d', $diff->getID()); 278 } 279 280 $results[] = array( 281 $label, 282 $diff, 283 ); 284 } 285 286 return $results; 287 } 288 289 290}