Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php
12256 views
1
<?php
2
3
final 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 = id(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
}
332
333