From 2834e9f6cef0b85fb00a89b6f89ebd008646d5f5 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sun, 3 Apr 2011 23:23:36 -0700 Subject: [PATCH] HeraldCommitAdapter and some related junk. --- src/__phutil_library_map__.php | 4 + .../adapter/commit/HeraldCommitAdapter.php | 211 ++++++++++++++++++ .../herald/adapter/commit/__init__.php | 24 ++ .../test/HeraldTestConsoleController.php | 9 +- .../herald/controller/test/__init__.php | 2 + .../herald/storage/rule/HeraldRule.php | 5 + .../storage/owner/PhabricatorOwnersOwner.php | 9 + .../owners/storage/owner/__init__.php | 2 + .../package/PhabricatorOwnersPackage.php | 38 ++++ .../owners/storage/package/__init__.php | 1 + ...habricatorRepositoryCommitHeraldWorker.php | 132 +++++++++++ .../repository/worker/herald/__init__.php | 22 ++ 12 files changed, 458 insertions(+), 1 deletion(-) create mode 100644 src/applications/herald/adapter/commit/HeraldCommitAdapter.php create mode 100644 src/applications/herald/adapter/commit/__init__.php create mode 100644 src/applications/repository/worker/herald/PhabricatorRepositoryCommitHeraldWorker.php create mode 100644 src/applications/repository/worker/herald/__init__.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 21be35b244..b064e729b8 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -196,6 +196,7 @@ phutil_register_library_map(array( 'HeraldAction' => 'applications/herald/storage/action', 'HeraldActionConfig' => 'applications/herald/config/action', 'HeraldApplyTranscript' => 'applications/herald/storage/transcript/apply', + 'HeraldCommitAdapter' => 'applications/herald/adapter/commit', 'HeraldCondition' => 'applications/herald/storage/condition', 'HeraldConditionConfig' => 'applications/herald/config/condition', 'HeraldConditionTranscript' => 'applications/herald/storage/transcript/condition', @@ -356,6 +357,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/base', 'PhabricatorRepositoryCommitData' => 'applications/repository/storage/commitdata', 'PhabricatorRepositoryCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/base', + 'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/herald', 'PhabricatorRepositoryCommitMessageDetailParser' => 'applications/repository/parser/base', 'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/base', 'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/base', @@ -584,6 +586,7 @@ phutil_register_library_map(array( 'DiffusionView' => 'AphrontView', 'HeraldAction' => 'HeraldDAO', 'HeraldApplyTranscript' => 'HeraldDAO', + 'HeraldCommitAdapter' => 'HeraldObjectAdapter', 'HeraldCondition' => 'HeraldDAO', 'HeraldController' => 'PhabricatorController', 'HeraldDAO' => 'PhabricatorLiskDAO', @@ -714,6 +717,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommitDiscoveryDaemon' => 'PhabricatorRepositoryDaemon', + 'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker', 'PhabricatorRepositoryCommitTaskDaemon' => 'PhabricatorRepositoryDaemon', diff --git a/src/applications/herald/adapter/commit/HeraldCommitAdapter.php b/src/applications/herald/adapter/commit/HeraldCommitAdapter.php new file mode 100644 index 0000000000..2939e26106 --- /dev/null +++ b/src/applications/herald/adapter/commit/HeraldCommitAdapter.php @@ -0,0 +1,211 @@ +repository = $repository; + $this->commit = $commit; + $this->commitData = $commit_data; + } + + public function getPHID() { + return $this->commit->getPHID(); + } + + public function getEmailPHIDs() { + return $this->emailPHIDs; + } + + public function getHeraldName() { + return + 'r'. + $this->repository->getCallsign(). + $this->commit->getCommitIdentifier(); + } + + public function getHeraldTypeName() { + return HeraldContentTypeConfig::CONTENT_TYPE_COMMIT; + } + + public function loadAffectedPaths() { + if ($this->affectedPaths === null) { + $drequest = $this->buildDiffusionRequest(); + $path_query = DiffusionPathChangeQuery::newFromDiffusionRequest( + $drequest); + $paths = $path_query->loadChanges(); + + $result = array(); + foreach ($paths as $path) { + $basic_path = '/'.$path->getPath(); + if ($path->getFileType() == DifferentialChangeType::FILE_DIRECTORY) { + $basic_path = rtrim($basic_path, '/').'/'; + } + $result[] = $basic_path; + } + $this->affectedPaths = $result; + } + return $this->affectedPaths; + } + + public function loadAffectedPackages() { + if ($this->affectedPackages === null) { + $packages = PhabricatorOwnersPackage::loadAffectedPackages( + $this->repository, + $this->loadAffectedPaths()); + $this->affectedPackages = $packages; + } + return $this->affectedPackages; + } + + public function loadDifferentialRevision() { + if ($this->affectedRevision === null) { + $this->affectedRevision = false; + $data = $this->commitData; + $revision_id = $data->getCommitDetail('differential.revisionID'); + if ($revision_id) { + $revision = id(new DifferentialRevision())->load($revision_id); + if ($revision) { + $revision->loadRelationships(); + $this->affectedRevision = $revision; + } + } + } + return $this->affectedRevision; + } + + private function buildDiffusionRequest() { + return DiffusionRequest::newFromAphrontRequestDictionary( + array( + 'callsign' => $this->repository->getCallsign(), + 'commit' => $this->commit->getCommitIdentifier(), + )); + } + + public function getHeraldField($field) { + $data = $this->commitData; + switch ($field) { + case HeraldFieldConfig::FIELD_BODY: + return $data->getCommitMessage(); + case HeraldFieldConfig::FIELD_AUTHOR: + return $data->getCommitDetail('authorPHID'); + case HeraldFieldConfig::FIELD_REVIEWER: + return $data->getCommitDetail('reviewerPHID'); + case HeraldFieldConfig::FIELD_DIFF_FILE: + return $this->loadAffectedPaths(); + case HeraldFieldConfig::FIELD_REPOSITORY: + return $this->repository->getPHID(); + case HeraldFieldConfig::FIELD_DIFF_CONTENT: + // TODO! + return null; +/* + try { + $diff = $this->loadDiff(); + } catch (Exception $ex) { + // See rE280053 for an example. + return array( + '<<< Failed to load diff, this usually means the change committed '. + 'a binary file as text. >>>', + ); + } + $dict = array(); + $changes = $diff->getChangesets(); + $lines = array(); + foreach ($changes as $change) { + $lines = array(); + foreach ($change->getHunks() as $hunk) { + $lines[] = $hunk->makeChanges(); + } + $dict[$change->getTrueFilename()] = implode("\n", $lines); + } + return $dict; +*/ + case HeraldFieldConfig::FIELD_AFFECTED_PACKAGE: + $packages = $this->loadAffectedPackages(); + return mpull($packages, 'getPHID'); + case HeraldFieldConfig::FIELD_AFFECTED_PACKAGE_OWNER: + $packages = $this->loadAffectedPackages(); + $owners = PhabricatorOwnersOwner::loadAllForPackages($packages); + return mpull($owners, 'getUserPHID'); + case HeraldFieldConfig::FIELD_DIFFERENTIAL_REVISION: + $revision = $this->loadDifferentialRevision(); + if (!$revision) { + return null; + } + return $revision->getID(); + case HeraldFieldConfig::FIELD_DIFFERENTIAL_REVIEWERS: + $revision = $this->loadDifferentialRevision(); + if (!$revision) { + return null; + } + return $revision->getReviewers(); + case HeraldFieldConfig::FIELD_DIFFERENTIAL_CCS: + $revision = $this->loadDifferentialRevision(); + if (!$revision) { + return null; + } + return $revision->getCCPHIDs(); + default: + throw new Exception("Invalid field '{$field}'."); + } + } + + public function applyHeraldEffects(array $effects) { + $result = array(); + foreach ($effects as $effect) { + $action = $effect->getAction(); + switch ($action) { + case HeraldActionConfig::ACTION_NOTHING: + $result[] = new HeraldApplyTranscript( + $effect, + true, + 'Great success at doing nothing.'); + break; + case HeraldActionConfig::ACTION_EMAIL: + foreach ($effect->getTarget() as $fbid) { + $this->emailPHIDs[] = $fbid; + } + $result[] = new HeraldApplyTranscript( + $effect, + true, + 'Added address to email targets.'); + break; + default: + throw new Exception("No rules to handle action '{$action}'."); + } + } + return $result; + } +} diff --git a/src/applications/herald/adapter/commit/__init__.php b/src/applications/herald/adapter/commit/__init__.php new file mode 100644 index 0000000000..01385ec1d0 --- /dev/null +++ b/src/applications/herald/adapter/commit/__init__.php @@ -0,0 +1,24 @@ +loadOneWhere( + 'commitID = %d', + $object->getID()); + $adapter = new HeraldCommitAdapter( + $repo, + $object, + $data); } else { throw new Exception("Can not build adapter for object!"); } diff --git a/src/applications/herald/controller/test/__init__.php b/src/applications/herald/controller/test/__init__.php index 72d995cbaf..d9bab6046b 100644 --- a/src/applications/herald/controller/test/__init__.php +++ b/src/applications/herald/controller/test/__init__.php @@ -8,12 +8,14 @@ phutil_require_module('phabricator', 'aphront/response/redirect'); phutil_require_module('phabricator', 'applications/differential/storage/revision'); +phutil_require_module('phabricator', 'applications/herald/adapter/commit'); phutil_require_module('phabricator', 'applications/herald/adapter/differential'); phutil_require_module('phabricator', 'applications/herald/adapter/dryrun'); phutil_require_module('phabricator', 'applications/herald/controller/base'); phutil_require_module('phabricator', 'applications/herald/engine/engine'); phutil_require_module('phabricator', 'applications/herald/storage/rule'); phutil_require_module('phabricator', 'applications/repository/storage/commit'); +phutil_require_module('phabricator', 'applications/repository/storage/commitdata'); phutil_require_module('phabricator', 'applications/repository/storage/repository'); phutil_require_module('phabricator', 'view/form/base'); phutil_require_module('phabricator', 'view/form/control/submit'); diff --git a/src/applications/herald/storage/rule/HeraldRule.php b/src/applications/herald/storage/rule/HeraldRule.php index f4a5849fdf..76b11a8aa3 100644 --- a/src/applications/herald/storage/rule/HeraldRule.php +++ b/src/applications/herald/storage/rule/HeraldRule.php @@ -30,6 +30,11 @@ class HeraldRule extends HeraldDAO { $rules = id(new HeraldRule())->loadAllWhere( 'contentType = %s', $content_type); + + if (!$rules) { + return array(); + } + $rule_ids = mpull($rules, 'getID'); $conditions = id(new HeraldCondition())->loadAllWhere( diff --git a/src/applications/owners/storage/owner/PhabricatorOwnersOwner.php b/src/applications/owners/storage/owner/PhabricatorOwnersOwner.php index 8c9d9827cf..dfdcbb7685 100644 --- a/src/applications/owners/storage/owner/PhabricatorOwnersOwner.php +++ b/src/applications/owners/storage/owner/PhabricatorOwnersOwner.php @@ -27,4 +27,13 @@ class PhabricatorOwnersOwner extends PhabricatorOwnersDAO { ) + parent::getConfiguration(); } + public static function loadAllForPackages(array $packages) { + if (!$packages) { + return array(); + } + return id(new PhabricatorOwnersOwner())->loadAllWhere( + 'packageID IN (%Ls)', + mpull($packages, 'getID')); + } + } diff --git a/src/applications/owners/storage/owner/__init__.php b/src/applications/owners/storage/owner/__init__.php index 2c5c082935..4336d4c323 100644 --- a/src/applications/owners/storage/owner/__init__.php +++ b/src/applications/owners/storage/owner/__init__.php @@ -8,5 +8,7 @@ phutil_require_module('phabricator', 'applications/owners/storage/base'); +phutil_require_module('phutil', 'utils'); + phutil_require_source('PhabricatorOwnersOwner.php'); diff --git a/src/applications/owners/storage/package/PhabricatorOwnersPackage.php b/src/applications/owners/storage/package/PhabricatorOwnersPackage.php index a720cb0888..463f03cf3c 100644 --- a/src/applications/owners/storage/package/PhabricatorOwnersPackage.php +++ b/src/applications/owners/storage/package/PhabricatorOwnersPackage.php @@ -66,6 +66,44 @@ class PhabricatorOwnersPackage extends PhabricatorOwnersDAO { $this->getID()); } + public static function loadAffectedPackages( + PhabricatorRepository $repository, + array $paths) { + + if (!$paths) { + return array(); + } + + $fragments = array( + '/' => true, + ); + + foreach ($paths as $path) { + $trailing_slash = preg_match('@/$@', $path) ? '/' : ''; + $path = trim($path, '/'); + $parts = explode('/', $path); + while (count($parts)) { + $fragments['/'.implode('/', $parts).$trailing_slash] = true; + $trailing_slash = '/'; + array_pop($parts); + } + } + + $package = new PhabricatorOwnersPackage(); + $path = new PhabricatorOwnersPath(); + $data = queryfx_all( + $package->establishConnection('r'), + 'SELECT pkg.* FROM %T pkg JOIN %T p ON p.packageID = pkg.id + WHERE p.repositoryPHID = %s + AND p.path IN (%Ls)', + $package->getTableName(), + $path->getTableName(), + $repository->getPHID(), + array_keys($fragments)); + + return $package->loadAllFromArray($data); + } + public function save() { // TODO: Transactions! diff --git a/src/applications/owners/storage/package/__init__.php b/src/applications/owners/storage/package/__init__.php index fb10ed296a..ea807df659 100644 --- a/src/applications/owners/storage/package/__init__.php +++ b/src/applications/owners/storage/package/__init__.php @@ -10,6 +10,7 @@ phutil_require_module('phabricator', 'applications/owners/storage/base'); phutil_require_module('phabricator', 'applications/owners/storage/owner'); phutil_require_module('phabricator', 'applications/owners/storage/path'); phutil_require_module('phabricator', 'applications/phid/storage/phid'); +phutil_require_module('phabricator', 'storage/queryfx'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/repository/worker/herald/PhabricatorRepositoryCommitHeraldWorker.php b/src/applications/repository/worker/herald/PhabricatorRepositoryCommitHeraldWorker.php new file mode 100644 index 0000000000..8a0b32b2f8 --- /dev/null +++ b/src/applications/repository/worker/herald/PhabricatorRepositoryCommitHeraldWorker.php @@ -0,0 +1,132 @@ +loadOneWhere( + 'commitID = %d', + $commit->getID()); + + $rules = HeraldRule::loadAllByContentTypeWithFullData( + HeraldContentTypeConfig::CONTENT_TYPE_COMMIT); + + $adapter = new HeraldCommitAdapter( + $repository, + $commit, + $data); + $engine = new HeraldEngine(); + + $effects = $engine->applyRules($this->rules, $adapter); + $engine->applyEffects($effects, $adapter); + + $phids = $adapter->getEmailPHIDs(); + if (!$phids) { + return; + } + + $xscript = $engine->getTranscript(); + + $commit_name = $adapter->getHeraldName(); + $revision = $adapter->loadDifferentialRevision(); + + $name = null; + if ($revision) { + $name = $revision->getName(); + } + + $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::getURI('/'.$commit_name); + $differential = $revision + ? PhabricatorEnv::getURI('/D'.$revision->getID()) + : 'No revision.'; + + $files = $adapter->loadAffectedPaths(); + sort($files); + $files = implode("\n ", $files); + + $xscript_id = $xscript->getID(); + + $manage_uri = PhabricatorEnv::getURI('/herald/view/commits/'); + $why_uri = PhabricatorEnv::getURI('/herald/transcript/'.$xscript_id.'/'); + + $body = <<addTos($phids); + $mailer->setSubject($subject); + $mailer->setBody($body); + + $mailer->addHeader('X-Herald-Rules', $xscript->getXHeraldRulesHeader()); + if ($author_phid) { + $mailer->setFrom($author_phid); + } + + $mailer->save(); + } +} diff --git a/src/applications/repository/worker/herald/__init__.php b/src/applications/repository/worker/herald/__init__.php new file mode 100644 index 0000000000..5e8c5e2880 --- /dev/null +++ b/src/applications/repository/worker/herald/__init__.php @@ -0,0 +1,22 @@ +