diff --git a/src/applications/repository/daemon/commitdiscovery/git/PhabricatorRepositoryGitCommitDiscoveryDaemon.php b/src/applications/repository/daemon/commitdiscovery/git/PhabricatorRepositoryGitCommitDiscoveryDaemon.php index c76729b64..ee6d09fbb 100644 --- a/src/applications/repository/daemon/commitdiscovery/git/PhabricatorRepositoryGitCommitDiscoveryDaemon.php +++ b/src/applications/repository/daemon/commitdiscovery/git/PhabricatorRepositoryGitCommitDiscoveryDaemon.php @@ -1,162 +1,162 @@ getRepository(); $vcs = $repository->getVersionControlSystem(); if ($vcs != PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) { throw new Exception("Repository is not a git repository."); } list($remotes) = $repository->execxLocalCommand( 'remote show -n origin'); $matches = null; if (!preg_match('/^\s*Fetch URL:\s*(.*?)\s*$/m', $remotes, $matches)) { throw new Exception( "Expected 'Fetch URL' in 'git remote show -n origin'."); } self::verifySameGitOrigin( $matches[1], $repository->getRemoteURI(), $repository->getLocalPath()); list($stdout) = $repository->execxLocalCommand( 'branch -r --verbose --no-abbrev'); $branches = DiffusionGitBranchQuery::parseGitRemoteBranchOutput( $stdout, $only_this_remote = DiffusionBranchInformation::DEFAULT_GIT_REMOTE); $got_something = false; $tracked_something = false; foreach ($branches as $name => $commit) { if (!$repository->shouldTrackBranch($name)) { continue; } $tracked_something = true; if ($this->isKnownCommit($commit)) { continue; } else { $this->discoverCommit($commit); $got_something = true; } } if (!$tracked_something) { $repo_name = $repository->getName(); $repo_callsign = $repository->getCallsign(); throw new Exception( "Repository r{$repo_callsign} '{$repo_name}' has no tracked branches! ". "Verify that your branch filtering settings are correct."); } return $got_something; } private function discoverCommit($commit) { $discover = array(); $insert = array(); $repository = $this->getRepository(); $discover[] = $commit; $insert[] = $commit; $seen_parent = array(); while (true) { $target = array_pop($discover); list($parents) = $repository->execxLocalCommand( 'log -n1 --pretty="%%P" %s', $target); $parents = array_filter(explode(' ', trim($parents))); foreach ($parents as $parent) { if (isset($seen_parent[$parent])) { // We end up in a loop here somehow when we parse Arcanist if we // don't do this. TODO: Figure out why and draw a pretty diagram // since it's not evident how parsing a DAG with this causes the // loop to stop terminating. continue; } $seen_parent[$parent] = true; if (!$this->isKnownCommit($parent)) { $discover[] = $parent; $insert[] = $parent; } } if (empty($discover)) { break; } $this->stillWorking(); } while (true) { $target = array_pop($insert); list($epoch) = $repository->execxLocalCommand( - 'log -n1 --pretty="%%at" %s', + 'log -n1 --pretty="%%ct" %s', $target); $epoch = trim($epoch); $this->recordCommit($target, $epoch); if (empty($insert)) { break; } } } public static function verifySameGitOrigin($remote, $expect, $where) { $remote_uri = PhabricatorRepository::newPhutilURIFromGitURI($remote); $expect_uri = PhabricatorRepository::newPhutilURIFromGitURI($expect); $remote_path = $remote_uri->getPath(); $expect_path = $expect_uri->getPath(); $remote_match = self::normalizeGitPath($remote_path); $expect_match = self::normalizeGitPath($expect_path); if ($remote_match != $expect_match) { throw new Exception( "Working copy at '{$where}' has a mismatched origin URL. It has ". "origin URL '{$remote}' (with remote path '{$remote_path}'), but the ". "configured URL '{$expect}' (with remote path '{$expect_path}') is ". "expected. Refusing to proceed because this may indicate that the ". "working copy is actually some other repository."); } } private static function normalizeGitPath($path) { // Strip away trailing "/" and ".git", so similar paths correctly match. $path = rtrim($path, '/'); $path = preg_replace('/\.git$/', '', $path); return $path; } } diff --git a/src/applications/repository/worker/commitmessageparser/base/PhabricatorRepositoryCommitMessageParserWorker.php b/src/applications/repository/worker/commitmessageparser/base/PhabricatorRepositoryCommitMessageParserWorker.php index 3c54d4f7a..eeab1b273 100644 --- a/src/applications/repository/worker/commitmessageparser/base/PhabricatorRepositoryCommitMessageParserWorker.php +++ b/src/applications/repository/worker/commitmessageparser/base/PhabricatorRepositoryCommitMessageParserWorker.php @@ -1,183 +1,176 @@ commit; $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere( 'commitID = %d', $commit->getID()); if (!$data) { $data = new PhabricatorRepositoryCommitData(); } $data->setCommitID($commit->getID()); $data->setAuthorName($author); $data->setCommitMessage($message); $repository = $this->repository; $detail_parser = $repository->getDetail( 'detail-parser', 'PhabricatorRepositoryDefaultCommitMessageDetailParser'); if ($detail_parser) { PhutilSymbolLoader::loadClass($detail_parser); $parser_obj = newv($detail_parser, array($commit, $data)); $parser_obj->parseCommitDetails(); } $author_phid = $data->getCommitDetail('authorPHID'); if ($author_phid) { $commit->setAuthorPHID($author_phid); $commit->save(); } $data->save(); $conn_w = id(new DifferentialRevision())->establishConnection('w'); // NOTE: The `differential_commit` table has a unique ID on `commitPHID`, // preventing more than one revision from being associated with a commit. // Generally this is good and desirable, but with the advent of hash // tracking we may end up in a situation where we match several different // revisions. We just kind of ignore this and pick one, we might want to // revisit this and do something differently. (If we match several revisions // someone probably did something very silly, though.) $revision_id = $data->getCommitDetail('differential.revisionID'); if (!$revision_id) { $hashes = $this->getCommitHashes( $this->repository, $this->commit); if ($hashes) { $query = new DifferentialRevisionQuery(); $query->withCommitHashes($hashes); $revisions = $query->execute(); if (!empty($revisions)) { $revision = $this->identifyBestRevision($revisions); $revision_id = $revision->getID(); } } } if ($revision_id) { $revision = id(new DifferentialRevision())->load($revision_id); if ($revision) { queryfx( $conn_w, 'INSERT IGNORE INTO %T (revisionID, commitPHID) VALUES (%d, %s)', DifferentialRevision::TABLE_COMMIT, $revision->getID(), $commit->getPHID()); if ($revision->getStatus() != ArcanistDifferentialRevisionStatus::CLOSED) { - $date_committed = $this->getDateCommitted($commit); - if ($date_committed) { - $revision->setDateCommitted($date_committed); - } + $revision->setDateCommitted($commit->getEpoch()); $message = null; $committer = $data->getCommitDetail('authorPHID'); if (!$committer) { $committer = $revision->getAuthorPHID(); $message = 'Closed by '.$data->getAuthorName().'.'; } $editor = new DifferentialCommentEditor( $revision, $committer, DifferentialAction::ACTION_CLOSE); $editor->setIsDaemonWorkflow(true); $editor->setMessage($message)->save(); } } } } - protected function getDateCommitted(PhabricatorRepositoryCommit $commit) { - return null; - } - /** * When querying for revisions by hash, more than one revision may be found. * This function identifies the "best" revision from such a set. Typically, * there is only one revision found. Otherwise, we try to pick an accepted * revision first, followed by an open revision, and otherwise we go with a * closed or abandoned revision as a last resort. */ private function identifyBestRevision(array $revisions) { assert_instances_of($revisions, 'DifferentialRevision'); // get the simplest, common case out of the way if (count($revisions) == 1) { return reset($revisions); } $first_choice = array(); $second_choice = array(); $third_choice = array(); foreach ($revisions as $revision) { switch ($revision->getStatus()) { // "Accepted" revisions -- ostensibly what we're looking for! case ArcanistDifferentialRevisionStatus::ACCEPTED: $first_choice[] = $revision; break; // "Open" revisions case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: $second_choice[] = $revision; break; // default is a wtf? here default: case ArcanistDifferentialRevisionStatus::ABANDONED: case ArcanistDifferentialRevisionStatus::CLOSED: $third_choice[] = $revision; break; } } // go down the ladder like a bro at last call if (!empty($first_choice)) { return $this->identifyMostRecentRevision($first_choice); } if (!empty($second_choice)) { return $this->identifyMostRecentRevision($second_choice); } if (!empty($third_choice)) { return $this->identifyMostRecentRevision($third_choice); } } /** * Given a set of revisions, returns the revision with the latest * updated time. This is ostensibly the most recent revision. */ private function identifyMostRecentRevision(array $revisions) { assert_instances_of($revisions, 'DifferentialRevision'); $revisions = msort($revisions, 'getDateModified'); return end($revisions); } } diff --git a/src/applications/repository/worker/commitmessageparser/svn/PhabricatorRepositorySvnCommitMessageParserWorker.php b/src/applications/repository/worker/commitmessageparser/svn/PhabricatorRepositorySvnCommitMessageParserWorker.php index bd295c0f7..fafcbf6f4 100644 --- a/src/applications/repository/worker/commitmessageparser/svn/PhabricatorRepositorySvnCommitMessageParserWorker.php +++ b/src/applications/repository/worker/commitmessageparser/svn/PhabricatorRepositorySvnCommitMessageParserWorker.php @@ -1,61 +1,57 @@ getDetail('remote-uri'); $log = $this->getSVNLogXMLObject( $uri, $commit->getCommitIdentifier(), $verbose = false); $entry = $log->logentry[0]; $author = (string)$entry->author; $message = (string)$entry->msg; $this->updateCommitData($author, $message); if ($this->shouldQueueFollowupTasks()) { $task = new PhabricatorWorkerTask(); $task->setTaskClass('PhabricatorRepositorySvnCommitChangeParserWorker'); $task->setData( array( 'commitID' => $commit->getID(), )); $task->save(); } } protected function getCommitHashes( PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit) { return array(); } - protected function getDateCommitted(PhabricatorRepositoryCommit $commit) { - return $commit->getEpoch(); - } - }