Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/audit/editor/comment/PhabricatorAuditCommentEditor.php b/src/applications/audit/editor/comment/PhabricatorAuditCommentEditor.php
index b014938000..898c0b4718 100644
--- a/src/applications/audit/editor/comment/PhabricatorAuditCommentEditor.php
+++ b/src/applications/audit/editor/comment/PhabricatorAuditCommentEditor.php
@@ -1,265 +1,282 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorAuditCommentEditor {
private $commit;
private $user;
public function __construct(PhabricatorRepositoryCommit $commit) {
$this->commit = $commit;
return $this;
}
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
public function addComment(PhabricatorAuditComment $comment) {
$commit = $this->commit;
$user = $this->user;
$other_comments = id(new PhabricatorAuditComment())->loadAllWhere(
'targetPHID = %s',
$commit->getPHID());
$comment
->setActorPHID($user->getPHID())
->setTargetPHID($commit->getPHID())
->save();
// When a user submits an audit comment, we update all the audit requests
// they have authority over to reflect the most recent status. The general
// idea here is that if audit has triggered for, e.g., several packages, but
// a user owns all of them, they can clear the audit requirement in one go
// without auditing the commit for each trigger.
$audit_phids = self::loadAuditPHIDsForUser($this->user);
$audit_phids = array_fill_keys($audit_phids, true);
$relationships = id(new PhabricatorOwnersPackageCommitRelationship())
->loadAllWhere(
'commitPHID = %s',
$commit->getPHID());
$action = $comment->getAction();
$status_map = PhabricatorAuditActionConstants::getStatusNameMap();
$status = idx($status_map, $action, null);
// Status may be empty for updates which don't affect status, like
// "comment".
$have_any_relationship = false;
foreach ($relationships as $relationship) {
if (empty($audit_phids[$relationship->getPackagePHID()])) {
continue;
}
$have_any_relationship = true;
if ($status) {
$relationship->setAuditStatus($status);
$relationship->save();
}
}
if (!$have_any_relationship) {
// If the user has no current authority over any audit trigger, make a
// new one to represent their audit state.
$relationship = id(new PhabricatorOwnersPackageCommitRelationship())
->setCommitPHID($commit->getPHID())
->setPackagePHID($user->getPHID())
->setAuditStatus(
$status
? $status
: PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED)
->setAuditReasons(array("Voluntary Participant"))
->save();
$relationships[] = $relationship;
}
$commit->updateAuditStatus($relationships);
$commit->save();
$this->publishFeedStory($comment, array_keys($audit_phids));
PhabricatorSearchCommitIndexer::indexCommit($commit);
$this->sendMail($comment, $other_comments);
}
/**
* Load the PHIDs for all objects the user has the authority to act as an
* audit for. This includes themselves, and any packages they are an owner
* of.
*/
public static function loadAuditPHIDsForUser(PhabricatorUser $user) {
$phids = array();
// The user can audit on their own behalf.
$phids[$user->getPHID()] = true;
// The user can audit on behalf of all packages they own.
$owned_packages = id(new PhabricatorOwnersOwner())->loadAllWhere(
'userPHID = %s',
$user->getPHID());
if ($owned_packages) {
$packages = id(new PhabricatorOwnersPackage())->loadAllWhere(
'id IN (%Ld)',
mpull($owned_packages, 'getPackageID'));
foreach (mpull($packages, 'getPHID') as $phid) {
$phids[$phid] = true;
}
}
// The user can audit on behalf of all projects they are a member of.
$query = new PhabricatorProjectQuery();
$query->setMembers(array($user->getPHID()));
$projects = $query->execute();
foreach ($projects as $project) {
$phids[$project->getPHID()] = true;
}
return array_keys($phids);
}
private function publishFeedStory(
PhabricatorAuditComment $comment,
array $more_phids) {
$commit = $this->commit;
$user = $this->user;
$related_phids = array_merge(
array(
$user->getPHID(),
$commit->getPHID(),
),
$more_phids);
id(new PhabricatorFeedStoryPublisher())
->setRelatedPHIDs($related_phids)
->setStoryAuthorPHID($user->getPHID())
->setStoryTime(time())
->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_AUDIT)
->setStoryData(
array(
'commitPHID' => $commit->getPHID(),
'action' => $comment->getAction(),
'content' => $comment->getContent(),
))
->publish();
}
private function sendMail(
PhabricatorAuditComment $comment,
array $other_comments) {
$commit = $this->commit;
$data = $commit->loadCommitData();
$summary = $data->getSummary();
$commit_phid = $commit->getPHID();
$phids = array($commit_phid);
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
$handle = $handles[$commit_phid];
$name = $handle->getName();
$map = array(
PhabricatorAuditActionConstants::CONCERN => 'Raised Concern',
PhabricatorAuditActionConstants::ACCEPT => 'Accepted',
);
$verb = idx($map, $comment->getAction(), 'Commented On');
+ $reply_handler = self::newReplyHandlerForCommit($commit);
+
$prefix = PhabricatorEnv::getEnvConfig('metamta.diffusion.subject-prefix');
$subject = "{$prefix} [{$verb}] {$name}: {$summary}";
- $thread_id = '<diffusion-audit-'.$commit->getPHID().'>';
+
+ $threading = self::getMailThreading($commit->getPHID());
+ list($thread_id, $thread_topic) = $threading;
+
$is_new = !count($other_comments);
$body = $this->renderMailBody(
$comment,
"{$name}: {$summary}",
- $handle);
+ $handle,
+ $reply_handler);
$email_to = array();
$author_phid = $data->getCommitDetail('authorPHID');
if ($author_phid) {
$email_to[] = $author_phid;
}
$email_cc = array();
foreach ($other_comments as $comment) {
$email_cc[] = $comment->getActorPHID();
}
$phids = array_merge($email_to, $email_cc);
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
$template = id(new PhabricatorMetaMTAMail())
->setSubject($subject)
->setFrom($comment->getActorPHID())
- ->addHeader('Thread-Topic', 'Diffusion Audit '.$commit->getPHID())
->setThreadID($thread_id, $is_new)
+ ->addHeader('Thread-Topic', $thread_topic)
->setRelatedPHID($commit->getPHID())
->setIsBulk(true)
->setBody($body);
- $reply_handler = self::newReplyHandlerForCommit($commit);
-
$mails = $reply_handler->multiplexMail(
$template,
array_select_keys($handles, $email_to),
array_select_keys($handles, $email_cc));
foreach ($mails as $mail) {
$mail->saveAndSend();
}
}
+ public static function getMailThreading($phid) {
+ return array(
+ '<diffusion-audit-'.$phid.'>',
+ 'Diffusion Audit '.$phid,
+ );
+ }
+
public static function newReplyHandlerForCommit($commit) {
$handler_class = PhabricatorEnv::getEnvConfig(
'metamta.diffusion.reply-handler');
$reply_handler = newv($handler_class, array());
$reply_handler->setMailReceiver($commit);
return $reply_handler;
}
private function renderMailBody(
PhabricatorAuditComment $comment,
$cname,
- PhabricatorObjectHandle $handle) {
+ PhabricatorObjectHandle $handle,
+ PhabricatorMailReplyHandler $reply_handler) {
$commit = $this->commit;
$user = $this->user;
$name = $user->getUsername();
$verb = PhabricatorAuditActionConstants::getActionPastTenseVerb(
$comment->getAction());
$body = array();
$body[] = "{$name} {$verb} commit {$cname}.";
if ($comment->getContent()) {
$body[] = $comment->getContent();
}
$body[] = "COMMIT\n ".PhabricatorEnv::getProductionURI($handle->getURI());
+ $reply_instructions = $reply_handler->getReplyHandlerInstructions();
+ if ($reply_instructions) {
+ $body[] = "REPLY HANDLER ACTIONS\n ".$reply_instructions;
+ }
+
return implode("\n\n", $body)."\n";
}
}
diff --git a/src/applications/repository/worker/herald/PhabricatorRepositoryCommitHeraldWorker.php b/src/applications/repository/worker/herald/PhabricatorRepositoryCommitHeraldWorker.php
index 20173916e4..78a1b43e8b 100644
--- a/src/applications/repository/worker/herald/PhabricatorRepositoryCommitHeraldWorker.php
+++ b/src/applications/repository/worker/herald/PhabricatorRepositoryCommitHeraldWorker.php
@@ -1,184 +1,208 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorRepositoryCommitHeraldWorker
extends PhabricatorRepositoryCommitParserWorker {
public function parseCommit(
PhabricatorRepository $repository,
PhabricatorRepositoryCommit $commit) {
$data = id(new PhabricatorRepositoryCommitData())->loadOneWhere(
'commitID = %d',
$commit->getID());
$rules = HeraldRule::loadAllByContentTypeWithFullData(
HeraldContentTypeConfig::CONTENT_TYPE_COMMIT,
$commit->getPHID());
$adapter = new HeraldCommitAdapter(
$repository,
$commit,
$data);
$engine = new HeraldEngine();
$effects = $engine->applyRules($rules, $adapter);
$engine->applyEffects($effects, $adapter, $rules);
$audit_phids = $adapter->getAuditMap();
if ($audit_phids) {
$this->createAudits($commit, $audit_phids, $rules);
}
$email_phids = $adapter->getEmailPHIDs();
if (!$email_phids) {
return;
}
if ($repository->getDetail('herald-disabled')) {
// This just means "disable email"; audits are (mostly) idempotent.
return;
}
$xscript = $engine->getTranscript();
$commit_name = $adapter->getHeraldName();
$revision = $adapter->loadDifferentialRevision();
$name = null;
if ($revision) {
$name = ' '.$revision->getTitle();
}
$author_phid = $data->getCommitDetail('authorPHID');
$reviewer_phid = $data->getCommitDetail('reviewerPHID');
$phids = array_filter(array($author_phid, $reviewer_phid));
$handles = array();
if ($phids) {
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
}
if ($author_phid) {
$author_name = $handles[$author_phid]->getName();
} else {
$author_name = $data->getAuthorName();
}
if ($reviewer_phid) {
$reviewer_name = $handles[$reviewer_phid]->getName();
} else {
$reviewer_name = null;
}
$who = implode(', ', array_filter(array($author_name, $reviewer_name)));
$description = $data->getCommitMessage();
$details = PhabricatorEnv::getProductionURI('/'.$commit_name);
$differential = $revision
? PhabricatorEnv::getProductionURI('/D'.$revision->getID())
: 'No revision.';
$files = $adapter->loadAffectedPaths();
sort($files);
$files = implode("\n ", $files);
$xscript_id = $xscript->getID();
$manage_uri = PhabricatorEnv::getProductionURI('/herald/view/commits/');
$why_uri = PhabricatorEnv::getProductionURI(
'/herald/transcript/'.$xscript_id.'/');
+ $reply_handler = PhabricatorAuditCommentEditor::newReplyHandlerForCommit(
+ $commit);
+
+ $reply_instructions = $reply_handler->getReplyHandlerInstructions();
+ if ($reply_instructions) {
+ $reply_instructions =
+ "\n".
+ "REPLY HANDLER ACTIONS\n".
+ " ".$reply_instructions."\n";
+ }
+
+
$body = <<<EOBODY
DESCRIPTION
{$description}
DETAILS
{$details}
DIFFERENTIAL REVISION
{$differential}
AFFECTED FILES
{$files}
-
+{$reply_instructions}
MANAGE HERALD COMMIT RULES
{$manage_uri}
WHY DID I GET THIS EMAIL?
{$why_uri}
EOBODY;
$subject = "[Herald/Commit] {$commit_name} ({$who}){$name}";
- $mailer = new PhabricatorMetaMTAMail();
- $mailer->setRelatedPHID($commit->getPHID());
- $mailer->addTos($email_phids);
- $mailer->setSubject($subject);
- $mailer->setBody($body);
- $mailer->setIsBulk(true);
+ $threading = PhabricatorAuditCommentEditor::getMailThreading(
+ $commit->getPHID());
+ list($thread_id, $thread_topic) = $threading;
+
+ $template = new PhabricatorMetaMTAMail();
+ $template->setRelatedPHID($commit->getPHID());
+ $template->setSubject($subject);
+ $template->setBody($body);
+ $template->setThreadID($thread_id, $is_new = true);
+ $template->addHeader('Thread-Topic', $thread_topic);
+ $template->setIsBulk(true);
- $mailer->addHeader('X-Herald-Rules', $xscript->getXHeraldRulesHeader());
+ $template->addHeader('X-Herald-Rules', $xscript->getXHeraldRulesHeader());
if ($author_phid) {
- $mailer->setFrom($author_phid);
+ $template->setFrom($author_phid);
}
- $mailer->saveAndSend();
+ $mails = $reply_handler->multiplexMail(
+ $template,
+ id(new PhabricatorObjectHandleData($email_phids))->loadHandles(),
+ array());
+
+ foreach ($mails as $mail) {
+ $mail->saveAndSend();
+ }
}
private function createAudits(
PhabricatorRepositoryCommit $commit,
array $map,
array $rules) {
$table = new PhabricatorOwnersPackageCommitRelationship();
$rships = $table->loadAllWhere(
'commitPHID = %s',
$commit->getPHID());
$rships = mpull($rships, null, 'getPackagePHID');
$rules = mpull($rules, null, 'getID');
foreach ($map as $phid => $rule_ids) {
$rship = idx($rships, $phid);
if ($rship) {
continue;
}
$reasons = array();
foreach ($rule_ids as $id) {
$rule_name = '?';
if ($rules[$id]) {
$rule_name = $rules[$id]->getName();
}
$reasons[] = 'Herald Rule #'.$id.' "'.$rule_name.'" Triggered Audit';
}
$rship = new PhabricatorOwnersPackageCommitRelationship();
$rship->setCommitPHID($commit->getPHID());
$rship->setPackagePHID($phid);
$rship->setAuditStatus(PhabricatorAuditStatusConstants::AUDIT_REQUIRED);
$rship->setAuditReasons($reasons);
$rship->save();
}
$commit->updateAuditStatus($rships);
$commit->save();
}
}
diff --git a/src/applications/repository/worker/herald/__init__.php b/src/applications/repository/worker/herald/__init__.php
index 270ca6f457..39c8eb9e3c 100644
--- a/src/applications/repository/worker/herald/__init__.php
+++ b/src/applications/repository/worker/herald/__init__.php
@@ -1,24 +1,25 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/audit/constants/status');
+phutil_require_module('phabricator', 'applications/audit/editor/comment');
phutil_require_module('phabricator', 'applications/herald/adapter/commit');
phutil_require_module('phabricator', 'applications/herald/config/contenttype');
phutil_require_module('phabricator', 'applications/herald/engine/engine');
phutil_require_module('phabricator', 'applications/herald/storage/rule');
phutil_require_module('phabricator', 'applications/metamta/storage/mail');
phutil_require_module('phabricator', 'applications/owners/storage/packagecommitrelationship');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'applications/repository/storage/commitdata');
phutil_require_module('phabricator', 'applications/repository/worker/base');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorRepositoryCommitHeraldWorker.php');

File Metadata

Mime Type
text/x-diff
Expires
Sat, Sep 20, 9:47 AM (1 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
241629
Default Alt Text
(17 KB)

Event Timeline