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

at recaptime-dev/main 331 lines 8.9 kB view raw
1<?php 2 3final class PhabricatorAuditManagementDeleteWorkflow 4 extends PhabricatorAuditManagementWorkflow { 5 6 protected function didConstruct() { 7 $this 8 ->setName('delete') 9 ->setExamples('**delete** [--dry-run] ...') 10 ->setSynopsis(pht('Delete audit requests matching parameters.')) 11 ->setArguments( 12 array( 13 array( 14 'name' => 'dry-run', 15 'help' => pht( 16 'Show what would be deleted, but do not actually delete '. 17 'anything.'), 18 ), 19 array( 20 'name' => 'users', 21 'param' => 'names', 22 'help' => pht('Select only audits by a given list of users.'), 23 ), 24 array( 25 'name' => 'repositories', 26 'param' => 'repos', 27 'help' => pht( 28 'Select only audits in a given list of repositories.'), 29 ), 30 array( 31 'name' => 'commits', 32 'param' => 'commits', 33 'help' => pht('Select only audits for the given commits.'), 34 ), 35 array( 36 'name' => 'min-commit-date', 37 'param' => 'date', 38 'help' => pht( 39 'Select only audits for commits on or after the given date.'), 40 ), 41 array( 42 'name' => 'max-commit-date', 43 'param' => 'date', 44 'help' => pht( 45 'Select only audits for commits on or before the given date.'), 46 ), 47 array( 48 'name' => 'status', 49 'param' => 'status', 50 'help' => pht( 51 'Select only audits in the given status. By default, '. 52 'only open audits are selected.'), 53 ), 54 array( 55 'name' => 'ids', 56 'param' => 'ids', 57 'help' => pht('Select only audits with the given IDs.'), 58 ), 59 )); 60 } 61 62 public function execute(PhutilArgumentParser $args) { 63 $viewer = $this->getViewer(); 64 $users = $this->loadUsers($args->getArg('users')); 65 $repos = $this->loadRepos($args->getArg('repositories')); 66 $commits = $this->loadCommits($args->getArg('commits')); 67 $ids = $this->parseList($args->getArg('ids')); 68 69 $status = $args->getArg('status'); 70 71 $min_date = $this->loadDate($args->getArg('min-commit-date')); 72 $max_date = $this->loadDate($args->getArg('max-commit-date')); 73 if ($min_date && $max_date && ($min_date > $max_date)) { 74 throw new PhutilArgumentUsageException( 75 pht('Specified maximum date must come after specified minimum date.')); 76 } 77 78 $is_dry_run = $args->getArg('dry-run'); 79 80 $query = id(new DiffusionCommitQuery()) 81 ->setViewer($this->getViewer()) 82 ->needAuditRequests(true); 83 84 if ($status) { 85 $query->withStatuses(array($status)); 86 } 87 88 $id_map = array(); 89 if ($ids) { 90 $id_map = array_fuse($ids); 91 $query->withAuditIDs($ids); 92 } 93 94 if ($repos) { 95 $query->withRepositoryIDs(mpull($repos, 'getID')); 96 97 // See T13457. If we're iterating over commits in a single large 98 // repository, the lack of a "<repositoryID, [id]>" key can slow things 99 // down. Iterate in a specific order to use a key which is present 100 // on the table ("<repositoryID, epoch, [id]>"). 101 $query->setOrderVector(array('-epoch', '-id')); 102 } 103 104 $auditor_map = array(); 105 if ($users) { 106 $auditor_map = array_fuse(mpull($users, 'getPHID')); 107 $query->withAuditorPHIDs($auditor_map); 108 } 109 110 if ($commits) { 111 $query->withPHIDs(mpull($commits, 'getPHID')); 112 } 113 114 $commit_iterator = new PhabricatorQueryIterator($query); 115 116 // See T13457. We may be examining many commits; each commit is small so 117 // we can safely increase the page size to improve performance a bit. 118 $commit_iterator->setPageSize(1000); 119 120 $audits = array(); 121 foreach ($commit_iterator as $commit) { 122 $commit_audits = $commit->getAudits(); 123 foreach ($commit_audits as $key => $audit) { 124 if ($id_map && empty($id_map[$audit->getID()])) { 125 unset($commit_audits[$key]); 126 continue; 127 } 128 129 if ($auditor_map && empty($auditor_map[$audit->getAuditorPHID()])) { 130 unset($commit_audits[$key]); 131 continue; 132 } 133 134 if ($min_date && $commit->getEpoch() < $min_date) { 135 unset($commit_audits[$key]); 136 continue; 137 } 138 139 if ($max_date && $commit->getEpoch() > $max_date) { 140 unset($commit_audits[$key]); 141 continue; 142 } 143 } 144 145 if (!$commit_audits) { 146 continue; 147 } 148 149 $handles = id(new PhabricatorHandleQuery()) 150 ->setViewer($viewer) 151 ->withPHIDs(mpull($commit_audits, 'getAuditorPHID')) 152 ->execute(); 153 154 foreach ($commit_audits as $audit) { 155 $audit_id = $audit->getID(); 156 $status = $audit->getAuditRequestStatusObject(); 157 158 $description = sprintf( 159 '%10d %-16s %-16s %s: %s', 160 $audit_id, 161 $handles[$audit->getAuditorPHID()]->getName(), 162 $status->getStatusName(), 163 $commit->getRepository()->formatCommitName( 164 $commit->getCommitIdentifier()), 165 trim($commit->getSummary())); 166 167 $audits[] = array( 168 'auditID' => $audit_id, 169 'commitPHID' => $commit->getPHID(), 170 'description' => $description, 171 ); 172 } 173 } 174 175 if (!$audits) { 176 echo tsprintf( 177 "%s\n", 178 pht('No audits match the query.')); 179 return 0; 180 } 181 182 foreach ($audits as $audit_spec) { 183 echo tsprintf( 184 "%s\n", 185 $audit_spec['description']); 186 } 187 188 if ($is_dry_run) { 189 echo tsprintf( 190 "%s\n", 191 pht('This is a dry run, so no changes will be made.')); 192 return 0; 193 } 194 195 $message = pht( 196 'Really delete these %s audit(s)? They will be permanently deleted '. 197 'and can not be recovered.', 198 phutil_count($audits)); 199 if (!phutil_console_confirm($message)) { 200 echo tsprintf( 201 "%s\n", 202 pht('User aborted the workflow.')); 203 return 1; 204 } 205 206 $audits_by_commit = igroup($audits, 'commitPHID'); 207 foreach ($audits_by_commit as $commit_phid => $audit_specs) { 208 $audit_ids = ipull($audit_specs, 'auditID'); 209 210 $audits = id(new PhabricatorRepositoryAuditRequest())->loadAllWhere( 211 'id IN (%Ld)', 212 $audit_ids); 213 214 foreach ($audits as $audit) { 215 $id = $audit->getID(); 216 217 echo tsprintf( 218 "%s\n", 219 pht('Deleting audit %d...', $id)); 220 221 $audit->delete(); 222 } 223 224 $this->synchronizeCommitAuditState($commit_phid); 225 } 226 227 return 0; 228 } 229 230 private function loadUsers($users) { 231 $users = $this->parseList($users); 232 if (!$users) { 233 return null; 234 } 235 236 $objects = id(new PhabricatorPeopleQuery()) 237 ->setViewer($this->getViewer()) 238 ->withUsernames($users) 239 ->execute(); 240 $objects = mpull($objects, null, 'getUsername'); 241 242 foreach ($users as $name) { 243 if (empty($objects[$name])) { 244 throw new PhutilArgumentUsageException( 245 pht('No such user with username "%s"!', $name)); 246 } 247 } 248 249 return $objects; 250 } 251 252 private function parseList($list) { 253 $list = preg_split('/\s*,\s*/', $list); 254 255 foreach ($list as $key => $item) { 256 $list[$key] = trim($item); 257 } 258 259 foreach ($list as $key => $item) { 260 if (!strlen($item)) { 261 unset($list[$key]); 262 } 263 } 264 265 return $list; 266 } 267 268 private function loadRepos($identifiers) { 269 $identifiers = $this->parseList($identifiers); 270 if (!$identifiers) { 271 return null; 272 } 273 274 $query = id(new PhabricatorRepositoryQuery()) 275 ->setViewer($this->getViewer()) 276 ->withIdentifiers($identifiers); 277 278 $repos = $query->execute(); 279 280 $map = $query->getIdentifierMap(); 281 foreach ($identifiers as $identifier) { 282 if (empty($map[$identifier])) { 283 throw new PhutilArgumentUsageException( 284 pht('No repository "%s" exists!', $identifier)); 285 } 286 } 287 288 return $repos; 289 } 290 291 private function loadDate($date) { 292 if (!$date) { 293 return null; 294 } 295 296 $epoch = strtotime($date); 297 if (!$epoch || $epoch < 1) { 298 throw new PhutilArgumentUsageException( 299 pht( 300 'Unable to parse date "%s". Use a format like "%s".', 301 $date, 302 '2000-01-01')); 303 } 304 305 return $epoch; 306 } 307 308 private function loadCommits($commits) { 309 $names = $this->parseList($commits); 310 if (!$names) { 311 return null; 312 } 313 314 $query = id(new DiffusionCommitQuery()) 315 ->setViewer($this->getViewer()) 316 ->withIdentifiers($names); 317 318 $commits = $query->execute(); 319 320 $map = $query->getIdentifierMap(); 321 foreach ($names as $name) { 322 if (empty($map[$name])) { 323 throw new PhutilArgumentUsageException( 324 pht('No such commit "%s"!', $name)); 325 } 326 } 327 328 return $commits; 329 } 330 331}