2011-04-14 01:39:08 +02:00
|
|
|
<?php
|
|
|
|
|
Rename Conduit classes
Summary: Ref T5655. Rename Conduit classes and provide a `getAPIMethodName` method to declare the API method.
Test Plan:
```
> echo '{}' | arc --conduit-uri='http://phabricator.joshuaspence.com' call-conduit user.whoami
Waiting for JSON parameters on stdin...
{"error":null,"errorMessage":null,"response":{"phid":"PHID-USER-lioqffnwn6y475mu5ndb","userName":"josh","realName":"Joshua Spence","image":"http:\/\/phabricator.joshuaspence.com\/res\/1404425321T\/phabricator\/3eb28cd9\/rsrc\/image\/avatar.png","uri":"http:\/\/phabricator.joshuaspence.com\/p\/josh\/","roles":["admin","verified","approved","activated"]}}
```
Reviewers: epriestley, #blessed_reviewers
Reviewed By: epriestley, #blessed_reviewers
Subscribers: epriestley, Korvin, hach-que
Maniphest Tasks: T5655
Differential Revision: https://secure.phabricator.com/D9991
2014-07-25 02:54:15 +02:00
|
|
|
final class DiffusionGetCommitsConduitAPIMethod
|
|
|
|
extends DiffusionConduitAPIMethod {
|
|
|
|
|
|
|
|
public function getAPIMethodName() {
|
|
|
|
return 'diffusion.getcommits';
|
|
|
|
}
|
2011-04-14 01:39:08 +02:00
|
|
|
|
|
|
|
public function getMethodDescription() {
|
2014-01-28 02:14:21 +01:00
|
|
|
return pht('Retrieve Diffusion commit information.');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getMethodStatus() {
|
|
|
|
return self::METHOD_STATUS_DEPRECATED;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getMethodStatusDescription() {
|
|
|
|
return pht('Obsoleted by diffusion.querycommits.');
|
2011-04-14 01:39:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function defineParamTypes() {
|
|
|
|
return array(
|
|
|
|
'commits' => 'required list<string>',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function defineReturnType() {
|
|
|
|
return 'nonempty list<dict<string, wild>>';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function defineErrorTypes() {
|
2014-07-10 00:12:48 +02:00
|
|
|
return array();
|
2011-04-14 01:39:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function execute(ConduitAPIRequest $request) {
|
|
|
|
$results = array();
|
|
|
|
|
|
|
|
$commits = $request->getValue('commits');
|
|
|
|
$commits = array_fill_keys($commits, array());
|
|
|
|
foreach ($commits as $name => $info) {
|
|
|
|
$matches = null;
|
2014-03-13 20:42:41 +01:00
|
|
|
if (!preg_match('/^r([A-Z]+)([0-9a-f]+)\z/', $name, $matches)) {
|
2011-04-14 01:39:08 +02:00
|
|
|
$results[$name] = array(
|
|
|
|
'error' => 'ERR-UNPARSEABLE',
|
|
|
|
);
|
|
|
|
unset($commits[$name]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$commits[$name] = array(
|
|
|
|
'callsign' => $matches[1],
|
|
|
|
'commitIdentifier' => $matches[2],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$commits) {
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
|
|
|
$callsigns = ipull($commits, 'callsign');
|
|
|
|
$callsigns = array_unique($callsigns);
|
2013-09-26 01:54:48 +02:00
|
|
|
$repos = id(new PhabricatorRepositoryQuery())
|
|
|
|
->setViewer($request->getUser())
|
|
|
|
->withCallsigns($callsigns)
|
|
|
|
->execute();
|
2011-04-14 01:39:08 +02:00
|
|
|
$repos = mpull($repos, null, 'getCallsign');
|
|
|
|
|
|
|
|
foreach ($commits as $name => $info) {
|
|
|
|
$repo = idx($repos, $info['callsign']);
|
|
|
|
if (!$repo) {
|
|
|
|
$results[$name] = $info + array(
|
|
|
|
'error' => 'ERR-UNKNOWN-REPOSITORY',
|
|
|
|
);
|
|
|
|
unset($commits[$name]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$commits[$name] += array(
|
|
|
|
'repositoryPHID' => $repo->getPHID(),
|
|
|
|
'repositoryID' => $repo->getID(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$commits) {
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
2011-05-18 17:08:42 +02:00
|
|
|
// Execute a complicated query to figure out the primary commit information
|
|
|
|
// for each referenced commit.
|
|
|
|
$cdata = $this->queryCommitInformation($commits, $repos);
|
2011-04-14 01:39:08 +02:00
|
|
|
|
2011-05-18 17:08:42 +02:00
|
|
|
// We've built the queries so that each row also has the identifier we used
|
|
|
|
// to select it, which might be a git prefix rather than a full identifier.
|
|
|
|
$ref_map = ipull($cdata, 'commitIdentifier', 'commitRef');
|
2011-04-14 01:39:08 +02:00
|
|
|
|
|
|
|
$cobjs = id(new PhabricatorRepositoryCommit())->loadAllFromArray($cdata);
|
|
|
|
$cobjs = mgroup($cobjs, 'getRepositoryID', 'getCommitIdentifier');
|
|
|
|
foreach ($commits as $name => $commit) {
|
2011-05-18 17:08:42 +02:00
|
|
|
|
|
|
|
// Expand short git names into full identifiers. For SVN this map is just
|
|
|
|
// the identity.
|
|
|
|
$full_identifier = idx($ref_map, $commit['commitIdentifier']);
|
|
|
|
|
2011-04-14 01:39:08 +02:00
|
|
|
$repo_id = $commit['repositoryID'];
|
|
|
|
unset($commits[$name]['repositoryID']);
|
|
|
|
|
2011-05-18 17:08:42 +02:00
|
|
|
if (empty($full_identifier) ||
|
|
|
|
empty($cobjs[$commit['repositoryID']][$full_identifier])) {
|
2011-04-14 01:39:08 +02:00
|
|
|
$results[$name] = $commit + array(
|
|
|
|
'error' => 'ERR-UNKNOWN-COMMIT',
|
|
|
|
);
|
|
|
|
unset($commits[$name]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-05-18 17:08:42 +02:00
|
|
|
$cobj_arr = $cobjs[$commit['repositoryID']][$full_identifier];
|
2011-04-14 01:39:08 +02:00
|
|
|
$cobj = head($cobj_arr);
|
|
|
|
|
|
|
|
$commits[$name] += array(
|
2011-05-18 17:08:42 +02:00
|
|
|
'epoch' => $cobj->getEpoch(),
|
|
|
|
'commitPHID' => $cobj->getPHID(),
|
|
|
|
'commitID' => $cobj->getID(),
|
2011-04-14 01:39:08 +02:00
|
|
|
);
|
2011-05-18 17:08:42 +02:00
|
|
|
|
|
|
|
// Upgrade git short references into full commit identifiers.
|
2011-05-30 21:04:15 +02:00
|
|
|
$identifier = $cobj->getCommitIdentifier();
|
|
|
|
$commits[$name]['commitIdentifier'] = $identifier;
|
|
|
|
|
|
|
|
$callsign = $commits[$name]['callsign'];
|
|
|
|
$uri = "/r{$callsign}{$identifier}";
|
|
|
|
$commits[$name]['uri'] = PhabricatorEnv::getProductionURI($uri);
|
2011-04-14 01:39:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!$commits) {
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
2011-05-18 17:08:42 +02:00
|
|
|
$commits = $this->addRepositoryCommitDataInformation($commits);
|
|
|
|
$commits = $this->addDifferentialInformation($commits);
|
2013-11-27 23:35:55 +01:00
|
|
|
$commits = $this->addManiphestInformation($commits);
|
2011-05-18 17:08:42 +02:00
|
|
|
|
|
|
|
foreach ($commits as $name => $commit) {
|
|
|
|
$results[$name] = $commit;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve primary commit information for all referenced commits.
|
|
|
|
*/
|
|
|
|
private function queryCommitInformation(array $commits, array $repos) {
|
2012-04-03 21:10:45 +02:00
|
|
|
assert_instances_of($repos, 'PhabricatorRepository');
|
2011-05-18 17:08:42 +02:00
|
|
|
$conn_r = id(new PhabricatorRepositoryCommit())->establishConnection('r');
|
|
|
|
$repos = mpull($repos, null, 'getID');
|
|
|
|
|
|
|
|
$groups = array();
|
|
|
|
foreach ($commits as $name => $commit) {
|
|
|
|
$groups[$commit['repositoryID']][] = $commit['commitIdentifier'];
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: MySQL goes crazy and does a massive table scan if we build a more
|
|
|
|
// sensible version of this query. Make sure the query plan is OK if you
|
|
|
|
// attempt to reduce the craziness here. METANOTE: The addition of prefix
|
|
|
|
// selection for Git further complicates matters.
|
|
|
|
$query = array();
|
|
|
|
$commit_table = id(new PhabricatorRepositoryCommit())->getTableName();
|
|
|
|
|
|
|
|
foreach ($groups as $repository_id => $identifiers) {
|
|
|
|
$vcs = $repos[$repository_id]->getVersionControlSystem();
|
|
|
|
$is_git = ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
|
|
|
|
if ($is_git) {
|
|
|
|
foreach ($identifiers as $identifier) {
|
|
|
|
if (strlen($identifier) < 7) {
|
|
|
|
// Don't bother with silly stuff like 'rX2', which will select
|
|
|
|
// 1/16th of all commits. Note that with length 7 we'll still get
|
|
|
|
// collisions in repositories at the tens-of-thousands-of-commits
|
|
|
|
// scale.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$query[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'SELECT %T.*, %s commitRef
|
|
|
|
FROM %T WHERE repositoryID = %d
|
|
|
|
AND commitIdentifier LIKE %>',
|
|
|
|
$commit_table,
|
|
|
|
$identifier,
|
|
|
|
$commit_table,
|
|
|
|
$repository_id,
|
|
|
|
$identifier);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$query[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'SELECT %T.*, commitIdentifier commitRef
|
|
|
|
FROM %T WHERE repositoryID = %d
|
|
|
|
AND commitIdentifier IN (%Ls)',
|
|
|
|
$commit_table,
|
|
|
|
$commit_table,
|
|
|
|
$repository_id,
|
|
|
|
$identifiers);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return queryfx_all(
|
|
|
|
$conn_r,
|
|
|
|
'%Q',
|
|
|
|
implode(' UNION ALL ', $query));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enhance the commit list with RepositoryCommitData information.
|
|
|
|
*/
|
|
|
|
private function addRepositoryCommitDataInformation(array $commits) {
|
2011-04-14 01:39:08 +02:00
|
|
|
$commit_ids = ipull($commits, 'commitID');
|
2011-05-18 17:08:42 +02:00
|
|
|
|
2011-04-14 01:39:08 +02:00
|
|
|
$data = id(new PhabricatorRepositoryCommitData())->loadAllWhere(
|
|
|
|
'commitID in (%Ld)',
|
|
|
|
$commit_ids);
|
|
|
|
$data = mpull($data, null, 'getCommitID');
|
|
|
|
|
|
|
|
foreach ($commits as $name => $commit) {
|
|
|
|
if (isset($data[$commit['commitID']])) {
|
|
|
|
$dobj = $data[$commit['commitID']];
|
|
|
|
$commits[$name] += array(
|
|
|
|
'commitMessage' => $dobj->getCommitMessage(),
|
|
|
|
'commitDetails' => $dobj->getCommitDetails(),
|
|
|
|
);
|
|
|
|
}
|
2011-05-18 17:08:42 +02:00
|
|
|
|
|
|
|
// Remove this information so we don't expose it via the API since
|
|
|
|
// external services shouldn't be storing internal Commit IDs.
|
2011-04-14 01:39:08 +02:00
|
|
|
unset($commits[$name]['commitID']);
|
|
|
|
}
|
|
|
|
|
2011-05-18 17:08:42 +02:00
|
|
|
return $commits;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enhance the commit list with Differential information.
|
|
|
|
*/
|
|
|
|
private function addDifferentialInformation(array $commits) {
|
2011-04-14 01:39:08 +02:00
|
|
|
$commit_phids = ipull($commits, 'commitPHID');
|
2011-05-18 17:08:42 +02:00
|
|
|
|
2013-09-26 21:37:19 +02:00
|
|
|
// TODO: (T603) This should be policy checked, either by moving to
|
|
|
|
// DifferentialRevisionQuery or by doing a followup query to make sure
|
|
|
|
// the matched objects are visible.
|
|
|
|
|
2011-04-14 01:39:08 +02:00
|
|
|
$rev_conn_r = id(new DifferentialRevision())->establishConnection('r');
|
|
|
|
$revs = queryfx_all(
|
|
|
|
$rev_conn_r,
|
|
|
|
'SELECT r.id id, r.phid phid, c.commitPHID commitPHID FROM %T r JOIN %T c
|
|
|
|
ON r.id = c.revisionID
|
|
|
|
WHERE c.commitPHID in (%Ls)',
|
|
|
|
id(new DifferentialRevision())->getTableName(),
|
|
|
|
DifferentialRevision::TABLE_COMMIT,
|
|
|
|
$commit_phids);
|
|
|
|
|
|
|
|
$revs = ipull($revs, null, 'commitPHID');
|
|
|
|
foreach ($commits as $name => $commit) {
|
|
|
|
if (isset($revs[$commit['commitPHID']])) {
|
|
|
|
$rev = $revs[$commit['commitPHID']];
|
|
|
|
$commits[$name] += array(
|
|
|
|
'differentialRevisionID' => 'D'.$rev['id'],
|
|
|
|
'differentialRevisionPHID' => $rev['phid'],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-18 17:08:42 +02:00
|
|
|
return $commits;
|
2011-04-14 01:39:08 +02:00
|
|
|
}
|
|
|
|
|
2013-11-27 23:35:55 +01:00
|
|
|
/**
|
|
|
|
* Enhances the commits list with Maniphest information.
|
|
|
|
*/
|
|
|
|
private function addManiphestInformation(array $commits) {
|
2014-07-18 00:42:06 +02:00
|
|
|
$task_type = DiffusionCommitHasTaskEdgeType::EDGECONST;
|
2013-11-27 23:35:55 +01:00
|
|
|
|
|
|
|
$commit_phids = ipull($commits, 'commitPHID');
|
|
|
|
|
|
|
|
$edge_query = id(new PhabricatorEdgeQuery())
|
|
|
|
->withSourcePHIDs($commit_phids)
|
|
|
|
->withEdgeTypes(array($task_type));
|
|
|
|
|
|
|
|
$edges = $edge_query->execute();
|
|
|
|
|
|
|
|
foreach ($commits as $name => $commit) {
|
|
|
|
$task_phids = $edge_query->getDestinationPHIDs(
|
|
|
|
array($commit['commitPHID']),
|
|
|
|
array($task_type));
|
|
|
|
|
|
|
|
$commits[$name] += array(
|
|
|
|
'taskPHIDs' => $task_phids,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $commits;
|
|
|
|
}
|
|
|
|
|
2011-04-14 01:39:08 +02:00
|
|
|
}
|