Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/audit/editor/PhabricatorAuditEditor.php
12256 views
1
<?php
2
3
final class PhabricatorAuditEditor
4
extends PhabricatorApplicationTransactionEditor {
5
6
const MAX_FILES_SHOWN_IN_EMAIL = 1000;
7
8
private $affectedFiles;
9
private $rawPatch;
10
private $auditorPHIDs = array();
11
12
private $didExpandInlineState = false;
13
private $oldAuditStatus = null;
14
15
public function setRawPatch($patch) {
16
$this->rawPatch = $patch;
17
return $this;
18
}
19
20
public function getRawPatch() {
21
return $this->rawPatch;
22
}
23
24
public function getEditorApplicationClass() {
25
return 'PhabricatorDiffusionApplication';
26
}
27
28
public function getEditorObjectsDescription() {
29
return pht('Audits');
30
}
31
32
public function getTransactionTypes() {
33
$types = parent::getTransactionTypes();
34
35
$types[] = PhabricatorTransactions::TYPE_COMMENT;
36
$types[] = PhabricatorTransactions::TYPE_EDGE;
37
$types[] = PhabricatorTransactions::TYPE_INLINESTATE;
38
39
$types[] = PhabricatorAuditTransaction::TYPE_COMMIT;
40
41
// TODO: These will get modernized eventually, but that can happen one
42
// at a time later on.
43
$types[] = PhabricatorAuditActionConstants::INLINE;
44
45
return $types;
46
}
47
48
protected function expandTransactions(
49
PhabricatorLiskDAO $object,
50
array $xactions) {
51
52
foreach ($xactions as $xaction) {
53
switch ($xaction->getTransactionType()) {
54
case PhabricatorTransactions::TYPE_INLINESTATE:
55
$this->didExpandInlineState = true;
56
break;
57
}
58
}
59
60
$this->oldAuditStatus = $object->getAuditStatus();
61
62
return parent::expandTransactions($object, $xactions);
63
}
64
65
protected function transactionHasEffect(
66
PhabricatorLiskDAO $object,
67
PhabricatorApplicationTransaction $xaction) {
68
69
switch ($xaction->getTransactionType()) {
70
case PhabricatorAuditActionConstants::INLINE:
71
return $xaction->hasComment();
72
}
73
74
return parent::transactionHasEffect($object, $xaction);
75
}
76
77
protected function getCustomTransactionOldValue(
78
PhabricatorLiskDAO $object,
79
PhabricatorApplicationTransaction $xaction) {
80
switch ($xaction->getTransactionType()) {
81
case PhabricatorAuditActionConstants::INLINE:
82
case PhabricatorAuditTransaction::TYPE_COMMIT:
83
return null;
84
}
85
86
return parent::getCustomTransactionOldValue($object, $xaction);
87
}
88
89
protected function getCustomTransactionNewValue(
90
PhabricatorLiskDAO $object,
91
PhabricatorApplicationTransaction $xaction) {
92
93
switch ($xaction->getTransactionType()) {
94
case PhabricatorAuditActionConstants::INLINE:
95
case PhabricatorAuditTransaction::TYPE_COMMIT:
96
return $xaction->getNewValue();
97
}
98
99
return parent::getCustomTransactionNewValue($object, $xaction);
100
}
101
102
protected function applyCustomInternalTransaction(
103
PhabricatorLiskDAO $object,
104
PhabricatorApplicationTransaction $xaction) {
105
106
switch ($xaction->getTransactionType()) {
107
case PhabricatorAuditActionConstants::INLINE:
108
$comment = $xaction->getComment();
109
110
$comment->setAttribute('editing', false);
111
112
PhabricatorVersionedDraft::purgeDrafts(
113
$comment->getPHID(),
114
$this->getActingAsPHID());
115
return;
116
case PhabricatorAuditTransaction::TYPE_COMMIT:
117
return;
118
}
119
120
return parent::applyCustomInternalTransaction($object, $xaction);
121
}
122
123
protected function applyCustomExternalTransaction(
124
PhabricatorLiskDAO $object,
125
PhabricatorApplicationTransaction $xaction) {
126
127
switch ($xaction->getTransactionType()) {
128
case PhabricatorAuditTransaction::TYPE_COMMIT:
129
return;
130
case PhabricatorAuditActionConstants::INLINE:
131
$reply = $xaction->getComment()->getReplyToComment();
132
if ($reply && !$reply->getHasReplies()) {
133
$reply->setHasReplies(1)->save();
134
}
135
return;
136
}
137
138
return parent::applyCustomExternalTransaction($object, $xaction);
139
}
140
141
protected function applyBuiltinExternalTransaction(
142
PhabricatorLiskDAO $object,
143
PhabricatorApplicationTransaction $xaction) {
144
145
switch ($xaction->getTransactionType()) {
146
case PhabricatorTransactions::TYPE_INLINESTATE:
147
$table = new PhabricatorAuditTransactionComment();
148
$conn_w = $table->establishConnection('w');
149
foreach ($xaction->getNewValue() as $phid => $state) {
150
queryfx(
151
$conn_w,
152
'UPDATE %T SET fixedState = %s WHERE phid = %s',
153
$table->getTableName(),
154
$state,
155
$phid);
156
}
157
break;
158
}
159
160
return parent::applyBuiltinExternalTransaction($object, $xaction);
161
}
162
163
protected function applyFinalEffects(
164
PhabricatorLiskDAO $object,
165
array $xactions) {
166
167
// Load auditors explicitly; we may not have them if the caller was a
168
// generic piece of infrastructure.
169
170
$commit = id(new DiffusionCommitQuery())
171
->setViewer($this->requireActor())
172
->withIDs(array($object->getID()))
173
->needAuditRequests(true)
174
->executeOne();
175
if (!$commit) {
176
throw new Exception(
177
pht('Failed to load commit during transaction finalization!'));
178
}
179
$object->attachAudits($commit->getAudits());
180
181
$actor_phid = $this->getActingAsPHID();
182
$actor_is_author = ($object->getAuthorPHID()) &&
183
($actor_phid == $object->getAuthorPHID());
184
185
$import_status_flag = null;
186
foreach ($xactions as $xaction) {
187
switch ($xaction->getTransactionType()) {
188
case PhabricatorAuditTransaction::TYPE_COMMIT:
189
$import_status_flag = PhabricatorRepositoryCommit::IMPORTED_PUBLISH;
190
break;
191
}
192
}
193
194
$old_status = $this->oldAuditStatus;
195
196
$requests = $object->getAudits();
197
$object->updateAuditStatus($requests);
198
199
$new_status = $object->getAuditStatus();
200
201
$object->save();
202
203
if ($import_status_flag) {
204
$object->writeImportStatusFlag($import_status_flag);
205
}
206
207
// If the commit has changed state after this edit, add an informational
208
// transaction about the state change.
209
if ($old_status != $new_status) {
210
if ($object->isAuditStatusPartiallyAudited()) {
211
// This state isn't interesting enough to get a transaction. The
212
// best way we could lead the user forward is something like "This
213
// commit still requires additional audits." but that's redundant and
214
// probably not very useful.
215
} else {
216
$xaction = $object->getApplicationTransactionTemplate()
217
->setTransactionType(DiffusionCommitStateTransaction::TRANSACTIONTYPE)
218
->setOldValue($old_status)
219
->setNewValue($new_status);
220
221
$xaction = $this->populateTransaction($object, $xaction);
222
223
$xaction->save();
224
}
225
}
226
227
// Collect auditor PHIDs for building mail.
228
$this->auditorPHIDs = mpull($object->getAudits(), 'getAuditorPHID');
229
230
return $xactions;
231
}
232
233
protected function expandTransaction(
234
PhabricatorLiskDAO $object,
235
PhabricatorApplicationTransaction $xaction) {
236
237
$auditors_type = DiffusionCommitAuditorsTransaction::TRANSACTIONTYPE;
238
239
$xactions = parent::expandTransaction($object, $xaction);
240
241
switch ($xaction->getTransactionType()) {
242
case PhabricatorAuditTransaction::TYPE_COMMIT:
243
$phids = $this->getAuditRequestTransactionPHIDsFromCommitMessage(
244
$object);
245
if ($phids) {
246
$xactions[] = $object->getApplicationTransactionTemplate()
247
->setTransactionType($auditors_type)
248
->setNewValue(
249
array(
250
'+' => array_fuse($phids),
251
));
252
$this->addUnmentionablePHIDs($phids);
253
}
254
break;
255
default:
256
break;
257
}
258
259
if (!$this->didExpandInlineState) {
260
switch ($xaction->getTransactionType()) {
261
case PhabricatorTransactions::TYPE_COMMENT:
262
$this->didExpandInlineState = true;
263
264
$query_template = id(new DiffusionDiffInlineCommentQuery())
265
->withCommitPHIDs(array($object->getPHID()));
266
267
$state_xaction = $this->newInlineStateTransaction(
268
$object,
269
$query_template);
270
271
if ($state_xaction) {
272
$xactions[] = $state_xaction;
273
}
274
break;
275
}
276
}
277
278
return $xactions;
279
}
280
281
private function getAuditRequestTransactionPHIDsFromCommitMessage(
282
PhabricatorRepositoryCommit $commit) {
283
284
$actor = $this->getActor();
285
$data = $commit->getCommitData();
286
$message = $data->getCommitMessage();
287
288
$result = DifferentialCommitMessageParser::newStandardParser($actor)
289
->setRaiseMissingFieldErrors(false)
290
->parseFields($message);
291
292
$field_key = DifferentialAuditorsCommitMessageField::FIELDKEY;
293
$phids = idx($result, $field_key, null);
294
295
if (!$phids) {
296
return array();
297
}
298
299
// If a commit lists its author as an auditor, just pretend it does not.
300
foreach ($phids as $key => $phid) {
301
if ($phid == $commit->getAuthorPHID()) {
302
unset($phids[$key]);
303
}
304
}
305
306
if (!$phids) {
307
return array();
308
}
309
310
return $phids;
311
}
312
313
protected function sortTransactions(array $xactions) {
314
$xactions = parent::sortTransactions($xactions);
315
316
$head = array();
317
$tail = array();
318
319
foreach ($xactions as $xaction) {
320
$type = $xaction->getTransactionType();
321
if ($type == PhabricatorAuditActionConstants::INLINE) {
322
$tail[] = $xaction;
323
} else {
324
$head[] = $xaction;
325
}
326
}
327
328
return array_values(array_merge($head, $tail));
329
}
330
331
protected function supportsSearch() {
332
return true;
333
}
334
335
protected function expandCustomRemarkupBlockTransactions(
336
PhabricatorLiskDAO $object,
337
array $xactions,
338
array $changes,
339
PhutilMarkupEngine $engine) {
340
341
$actor = $this->getActor();
342
$result = array();
343
344
// Some interactions (like "Fixes Txxx" interacting with Maniphest) have
345
// already been processed, so we're only re-parsing them here to avoid
346
// generating an extra redundant mention. Other interactions are being
347
// processed for the first time.
348
349
// We're only recognizing magic in the commit message itself, not in
350
// audit comments.
351
352
$is_commit = false;
353
foreach ($xactions as $xaction) {
354
switch ($xaction->getTransactionType()) {
355
case PhabricatorAuditTransaction::TYPE_COMMIT:
356
$is_commit = true;
357
break;
358
}
359
}
360
361
if (!$is_commit) {
362
return $result;
363
}
364
365
$flat_blocks = mpull($changes, 'getNewValue');
366
$huge_block = implode("\n\n", $flat_blocks);
367
$phid_map = array();
368
$monograms = array();
369
370
$task_refs = id(new ManiphestCustomFieldStatusParser())
371
->parseCorpus($huge_block);
372
foreach ($task_refs as $match) {
373
foreach ($match['monograms'] as $monogram) {
374
$monograms[] = $monogram;
375
}
376
}
377
378
$rev_refs = id(new DifferentialCustomFieldDependsOnParser())
379
->parseCorpus($huge_block);
380
foreach ($rev_refs as $match) {
381
foreach ($match['monograms'] as $monogram) {
382
$monograms[] = $monogram;
383
}
384
}
385
386
$objects = id(new PhabricatorObjectQuery())
387
->setViewer($this->getActor())
388
->withNames($monograms)
389
->execute();
390
$phid_map[] = mpull($objects, 'getPHID', 'getPHID');
391
392
$reverts_refs = id(new DifferentialCustomFieldRevertsParser())
393
->parseCorpus($huge_block);
394
$reverts = array_mergev(ipull($reverts_refs, 'monograms'));
395
if ($reverts) {
396
$reverted_objects = DiffusionCommitRevisionQuery::loadRevertedObjects(
397
$actor,
398
$object,
399
$reverts,
400
$object->getRepository());
401
402
$reverted_phids = mpull($reverted_objects, 'getPHID', 'getPHID');
403
404
$reverts_edge = DiffusionCommitRevertsCommitEdgeType::EDGECONST;
405
$result[] = id(new PhabricatorAuditTransaction())
406
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
407
->setMetadataValue('edge:type', $reverts_edge)
408
->setNewValue(array('+' => $reverted_phids));
409
410
$phid_map[] = $reverted_phids;
411
}
412
413
// See T13463. Copy "related task" edges from the associated revision, if
414
// one exists.
415
416
$revision = DiffusionCommitRevisionQuery::loadRevisionForCommit(
417
$actor,
418
$object);
419
if ($revision) {
420
$task_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
421
$revision->getPHID(),
422
DifferentialRevisionHasTaskEdgeType::EDGECONST);
423
$task_phids = array_fuse($task_phids);
424
425
if ($task_phids) {
426
$related_edge = DiffusionCommitHasTaskEdgeType::EDGECONST;
427
$result[] = id(new PhabricatorAuditTransaction())
428
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
429
->setMetadataValue('edge:type', $related_edge)
430
->setNewValue(array('+' => $task_phids));
431
}
432
433
// Mark these objects as unmentionable, since the explicit relationship
434
// is stronger and any mentions are redundant.
435
$phid_map[] = $task_phids;
436
}
437
438
$phid_map = array_mergev($phid_map);
439
$this->addUnmentionablePHIDs($phid_map);
440
441
return $result;
442
}
443
444
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
445
$reply_handler = new PhabricatorAuditReplyHandler();
446
$reply_handler->setMailReceiver($object);
447
return $reply_handler;
448
}
449
450
protected function getMailSubjectPrefix() {
451
return pht('[Diffusion]');
452
}
453
454
protected function getMailThreadID(PhabricatorLiskDAO $object) {
455
// For backward compatibility, use this legacy thread ID.
456
return 'diffusion-audit-'.$object->getPHID();
457
}
458
459
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
460
$identifier = $object->getCommitIdentifier();
461
$repository = $object->getRepository();
462
463
$summary = $object->getSummary();
464
$name = $repository->formatCommitName($identifier);
465
466
$subject = "{$name}: {$summary}";
467
468
$template = id(new PhabricatorMetaMTAMail())
469
->setSubject($subject);
470
471
$this->attachPatch(
472
$template,
473
$object);
474
475
return $template;
476
}
477
478
protected function getMailTo(PhabricatorLiskDAO $object) {
479
$this->requireAuditors($object);
480
481
$phids = array();
482
483
if ($object->getAuthorPHID()) {
484
$phids[] = $object->getAuthorPHID();
485
}
486
487
foreach ($object->getAudits() as $audit) {
488
if (!$audit->isResigned()) {
489
$phids[] = $audit->getAuditorPHID();
490
}
491
}
492
493
$phids[] = $this->getActingAsPHID();
494
495
return $phids;
496
}
497
498
protected function newMailUnexpandablePHIDs(PhabricatorLiskDAO $object) {
499
$this->requireAuditors($object);
500
501
$phids = array();
502
503
foreach ($object->getAudits() as $auditor) {
504
if ($auditor->isResigned()) {
505
$phids[] = $auditor->getAuditorPHID();
506
}
507
}
508
509
return $phids;
510
}
511
512
protected function getObjectLinkButtonLabelForMail(
513
PhabricatorLiskDAO $object) {
514
return pht('View Commit');
515
}
516
517
protected function buildMailBody(
518
PhabricatorLiskDAO $object,
519
array $xactions) {
520
521
$body = parent::buildMailBody($object, $xactions);
522
523
$type_inline = PhabricatorAuditActionConstants::INLINE;
524
$type_push = PhabricatorAuditTransaction::TYPE_COMMIT;
525
526
$is_commit = false;
527
$inlines = array();
528
foreach ($xactions as $xaction) {
529
if ($xaction->getTransactionType() == $type_inline) {
530
$inlines[] = $xaction;
531
}
532
if ($xaction->getTransactionType() == $type_push) {
533
$is_commit = true;
534
}
535
}
536
537
if ($inlines) {
538
$body->addTextSection(
539
pht('INLINE COMMENTS'),
540
$this->renderInlineCommentsForMail($object, $inlines));
541
}
542
543
if ($is_commit) {
544
$data = $object->getCommitData();
545
$body->addTextSection(pht('AFFECTED FILES'), $this->affectedFiles);
546
$this->inlinePatch(
547
$body,
548
$object);
549
}
550
551
$data = $object->getCommitData();
552
553
$user_phids = array();
554
555
$author_phid = $object->getAuthorPHID();
556
if ($author_phid) {
557
$user_phids[$author_phid][] = pht('Author');
558
}
559
560
$committer_phid = $data->getCommitDetail('committerPHID');
561
if ($committer_phid && ($committer_phid != $author_phid)) {
562
$user_phids[$committer_phid][] = pht('Committer');
563
}
564
565
foreach ($this->auditorPHIDs as $auditor_phid) {
566
$user_phids[$auditor_phid][] = pht('Auditor');
567
}
568
569
// TODO: It would be nice to show pusher here too, but that information
570
// is a little tricky to get at right now.
571
572
if ($user_phids) {
573
$handle_phids = array_keys($user_phids);
574
$handles = id(new PhabricatorHandleQuery())
575
->setViewer($this->requireActor())
576
->withPHIDs($handle_phids)
577
->execute();
578
579
$user_info = array();
580
foreach ($user_phids as $phid => $roles) {
581
$user_info[] = pht(
582
'%s (%s)',
583
$handles[$phid]->getName(),
584
implode(', ', $roles));
585
}
586
587
$body->addTextSection(
588
pht('USERS'),
589
implode("\n", $user_info));
590
}
591
592
$monogram = $object->getRepository()->formatCommitName(
593
$object->getCommitIdentifier());
594
595
$body->addLinkSection(
596
pht('COMMIT'),
597
PhabricatorEnv::getProductionURI('/'.$monogram));
598
599
return $body;
600
}
601
602
private function attachPatch(
603
PhabricatorMetaMTAMail $template,
604
PhabricatorRepositoryCommit $commit) {
605
606
if (!$this->getRawPatch()) {
607
return;
608
}
609
610
$attach_key = 'metamta.diffusion.attach-patches';
611
$attach_patches = PhabricatorEnv::getEnvConfig($attach_key);
612
if (!$attach_patches) {
613
return;
614
}
615
616
$repository = $commit->getRepository();
617
$encoding = $repository->getDetail('encoding', 'UTF-8');
618
619
$raw_patch = $this->getRawPatch();
620
$commit_name = $repository->formatCommitName(
621
$commit->getCommitIdentifier());
622
623
$template->addAttachment(
624
new PhabricatorMailAttachment(
625
$raw_patch,
626
$commit_name.'.patch',
627
'text/x-patch; charset='.$encoding));
628
}
629
630
private function inlinePatch(
631
PhabricatorMetaMTAMailBody $body,
632
PhabricatorRepositoryCommit $commit) {
633
634
if (!$this->getRawPatch()) {
635
return;
636
}
637
638
$inline_key = 'metamta.diffusion.inline-patches';
639
$inline_patches = PhabricatorEnv::getEnvConfig($inline_key);
640
if (!$inline_patches) {
641
return;
642
}
643
644
$repository = $commit->getRepository();
645
$raw_patch = $this->getRawPatch();
646
$result = null;
647
$len = substr_count($raw_patch, "\n");
648
if ($len <= $inline_patches) {
649
// We send email as utf8, so we need to convert the text to utf8 if
650
// we can.
651
$encoding = $repository->getDetail('encoding', 'UTF-8');
652
if ($encoding) {
653
$raw_patch = phutil_utf8_convert($raw_patch, 'UTF-8', $encoding);
654
}
655
$result = phutil_utf8ize($raw_patch);
656
}
657
658
if ($result) {
659
$result = "PATCH\n\n{$result}\n";
660
}
661
$body->addRawSection($result);
662
}
663
664
private function renderInlineCommentsForMail(
665
PhabricatorLiskDAO $object,
666
array $inline_xactions) {
667
668
$inlines = mpull($inline_xactions, 'getComment');
669
670
$block = array();
671
672
$path_map = id(new DiffusionPathQuery())
673
->withPathIDs(mpull($inlines, 'getPathID'))
674
->execute();
675
$path_map = ipull($path_map, 'path', 'id');
676
677
foreach ($inlines as $inline) {
678
$path = idx($path_map, $inline->getPathID());
679
if ($path === null) {
680
continue;
681
}
682
683
$start = $inline->getLineNumber();
684
$len = $inline->getLineLength();
685
if ($len) {
686
$range = $start.'-'.($start + $len);
687
} else {
688
$range = $start;
689
}
690
691
$content = $inline->getContent();
692
$block[] = "{$path}:{$range} {$content}";
693
}
694
695
return implode("\n", $block);
696
}
697
698
public function getMailTagsMap() {
699
return array(
700
PhabricatorAuditTransaction::MAILTAG_COMMIT =>
701
pht('A commit is created.'),
702
PhabricatorAuditTransaction::MAILTAG_ACTION_CONCERN =>
703
pht('A commit has a concerned raised against it.'),
704
PhabricatorAuditTransaction::MAILTAG_ACTION_ACCEPT =>
705
pht('A commit is accepted.'),
706
PhabricatorAuditTransaction::MAILTAG_ACTION_RESIGN =>
707
pht('A commit has an auditor resign.'),
708
PhabricatorAuditTransaction::MAILTAG_ACTION_CLOSE =>
709
pht('A commit is closed.'),
710
PhabricatorAuditTransaction::MAILTAG_ADD_AUDITORS =>
711
pht('A commit has auditors added.'),
712
PhabricatorAuditTransaction::MAILTAG_ADD_CCS =>
713
pht("A commit's subscribers change."),
714
PhabricatorAuditTransaction::MAILTAG_PROJECTS =>
715
pht("A commit's projects change."),
716
PhabricatorAuditTransaction::MAILTAG_COMMENT =>
717
pht('Someone comments on a commit.'),
718
PhabricatorAuditTransaction::MAILTAG_OTHER =>
719
pht('Other commit activity not listed above occurs.'),
720
);
721
}
722
723
protected function shouldApplyHeraldRules(
724
PhabricatorLiskDAO $object,
725
array $xactions) {
726
727
foreach ($xactions as $xaction) {
728
switch ($xaction->getTransactionType()) {
729
case PhabricatorAuditTransaction::TYPE_COMMIT:
730
$repository = $object->getRepository();
731
$publisher = $repository->newPublisher();
732
if (!$publisher->shouldPublishCommit($object)) {
733
return false;
734
}
735
return true;
736
default:
737
break;
738
}
739
}
740
return parent::shouldApplyHeraldRules($object, $xactions);
741
}
742
743
protected function buildHeraldAdapter(
744
PhabricatorLiskDAO $object,
745
array $xactions) {
746
return id(new HeraldCommitAdapter())
747
->setObject($object);
748
}
749
750
protected function didApplyHeraldRules(
751
PhabricatorLiskDAO $object,
752
HeraldAdapter $adapter,
753
HeraldTranscript $transcript) {
754
755
$limit = self::MAX_FILES_SHOWN_IN_EMAIL;
756
$files = $adapter->loadAffectedPaths();
757
sort($files);
758
if (count($files) > $limit) {
759
array_splice($files, $limit);
760
$files[] = pht(
761
'(This commit affected more than %d files. Only %d are shown here '.
762
'and additional ones are truncated.)',
763
$limit,
764
$limit);
765
}
766
$this->affectedFiles = implode("\n", $files);
767
768
return array();
769
}
770
771
private function isCommitMostlyImported(PhabricatorLiskDAO $object) {
772
$has_message = PhabricatorRepositoryCommit::IMPORTED_MESSAGE;
773
$has_changes = PhabricatorRepositoryCommit::IMPORTED_CHANGE;
774
775
// Don't publish feed stories or email about events which occur during
776
// import. In particular, this affects tasks being attached when they are
777
// closed by "Fixes Txxxx" in a commit message. See T5851.
778
779
$mask = ($has_message | $has_changes);
780
781
return $object->isPartiallyImported($mask);
782
}
783
784
785
private function shouldPublishRepositoryActivity(
786
PhabricatorLiskDAO $object,
787
array $xactions) {
788
789
// not every code path loads the repository so tread carefully
790
// TODO: They should, and then we should simplify this.
791
$repository = $object->getRepository($assert_attached = false);
792
if ($repository != PhabricatorLiskDAO::ATTACHABLE) {
793
$publisher = $repository->newPublisher();
794
if (!$publisher->shouldPublishCommit($object)) {
795
return false;
796
}
797
}
798
799
return $this->isCommitMostlyImported($object);
800
}
801
802
protected function shouldSendMail(
803
PhabricatorLiskDAO $object,
804
array $xactions) {
805
return $this->shouldPublishRepositoryActivity($object, $xactions);
806
}
807
808
protected function shouldEnableMentions(
809
PhabricatorLiskDAO $object,
810
array $xactions) {
811
return $this->shouldPublishRepositoryActivity($object, $xactions);
812
}
813
814
protected function shouldPublishFeedStory(
815
PhabricatorLiskDAO $object,
816
array $xactions) {
817
return $this->shouldPublishRepositoryActivity($object, $xactions);
818
}
819
820
protected function getCustomWorkerState() {
821
return array(
822
'rawPatch' => $this->rawPatch,
823
'affectedFiles' => $this->affectedFiles,
824
'auditorPHIDs' => $this->auditorPHIDs,
825
);
826
}
827
828
protected function getCustomWorkerStateEncoding() {
829
return array(
830
'rawPatch' => self::STORAGE_ENCODING_BINARY,
831
);
832
}
833
834
protected function loadCustomWorkerState(array $state) {
835
$this->rawPatch = idx($state, 'rawPatch');
836
$this->affectedFiles = idx($state, 'affectedFiles');
837
$this->auditorPHIDs = idx($state, 'auditorPHIDs');
838
return $this;
839
}
840
841
protected function willPublish(PhabricatorLiskDAO $object, array $xactions) {
842
return id(new DiffusionCommitQuery())
843
->setViewer($this->requireActor())
844
->withIDs(array($object->getID()))
845
->needAuditRequests(true)
846
->needCommitData(true)
847
->executeOne();
848
}
849
850
private function requireAuditors(PhabricatorRepositoryCommit $commit) {
851
if ($commit->hasAttachedAudits()) {
852
return;
853
}
854
855
$with_auditors = id(new DiffusionCommitQuery())
856
->setViewer($this->getActor())
857
->needAuditRequests(true)
858
->withPHIDs(array($commit->getPHID()))
859
->executeOne();
860
if (!$with_auditors) {
861
throw new Exception(
862
pht(
863
'Failed to reload commit ("%s").',
864
$commit->getPHID()));
865
}
866
867
$commit->attachAudits($with_auditors->getAudits());
868
}
869
870
}
871
872