Skip to content

Commit d667b12

Browse files
author
epriestley
committedDec 19, 2013
Provide a standalone query for resolution of commit author/committer into Phabricator users
Summary: Ref T4195. To implement the "Author" and "Committer" rules, I need to resolve author/committer strings into Phabricator users. The code to do this is currently buried in the daemons. Extract it into a standalone query. I also added `bin/repository lookup-users <commit>` to test this query, both to improve confidence I'm getting this right and to provide a diagnostic command for users, since there's occasionally some confusion over how author/committer strings resolve into valid users. Test Plan: I tested this using `bin/repository lookup-users` and `reparse.php --message` on Git, Mercurial and SVN commits. Here's the `lookup-users` output: >>> orbital ~/devtools/phabricator $ ./bin/repository lookup-users rINIS3 Examining commit rINIS3... Raw author string: epriestley Phabricator user: epriestley (Evan Priestley ) Raw committer string: null >>> orbital ~/devtools/phabricator $ ./bin/repository lookup-users rPOEMS165b6c54f487c8 Examining commit rPOEMS165b6c54f487... Raw author string: epriestley <git@epriestley.com> Phabricator user: epriestley (Evan Priestley ) Raw committer string: epriestley <git@epriestley.com> Phabricator user: epriestley (Evan Priestley ) >>> orbital ~/devtools/phabricator $ ./bin/repository lookup-users rINIH6d24c1aee7741e Examining commit rINIH6d24c1aee774... Raw author string: epriestley <hg@yghe.net> Phabricator user: epriestley (Evan Priestley ) Raw committer string: null >>> orbital ~/devtools/phabricator $ The `reparse.php` output was similar, and all VCSes resolved authors correctly. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T1731, T4195 Differential Revision: https://secure.phabricator.com/D7801
1 parent f750d5f commit d667b12

6 files changed

+265
-104
lines changed
 

‎scripts/repository/manage_repositories.php

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
new PhabricatorRepositoryManagementListWorkflow(),
2323
new PhabricatorRepositoryManagementDeleteWorkflow(),
2424
new PhabricatorRepositoryManagementMarkImportedWorkflow(),
25+
new PhabricatorRepositoryManagementLookupUsersWorkflow(),
2526
new PhabricatorRepositoryManagementImportingWorkflow(),
2627
new PhutilHelpArgumentWorkflow(),
2728
);

‎src/__phutil_library_map__.php

+4
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@
554554
'DiffusionRepositoryRef' => 'applications/diffusion/data/DiffusionRepositoryRef.php',
555555
'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php',
556556
'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php',
557+
'DiffusionResolveUserQuery' => 'applications/diffusion/query/DiffusionResolveUserQuery.php',
557558
'DiffusionSSHGitReceivePackWorkflow' => 'applications/diffusion/ssh/DiffusionSSHGitReceivePackWorkflow.php',
558559
'DiffusionSSHGitUploadPackWorkflow' => 'applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php',
559560
'DiffusionSSHGitWorkflow' => 'applications/diffusion/ssh/DiffusionSSHGitWorkflow.php',
@@ -1794,6 +1795,7 @@
17941795
'PhabricatorRepositoryManagementEditWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementEditWorkflow.php',
17951796
'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php',
17961797
'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php',
1798+
'PhabricatorRepositoryManagementLookupUsersWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementLookupUsersWorkflow.php',
17971799
'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkImportedWorkflow.php',
17981800
'PhabricatorRepositoryManagementPullWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php',
17991801
'PhabricatorRepositoryManagementWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementWorkflow.php',
@@ -2935,6 +2937,7 @@
29352937
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
29362938
),
29372939
'DiffusionRepositoryNewController' => 'DiffusionController',
2940+
'DiffusionResolveUserQuery' => 'Phobject',
29382941
'DiffusionSSHGitReceivePackWorkflow' => 'DiffusionSSHGitWorkflow',
29392942
'DiffusionSSHGitUploadPackWorkflow' => 'DiffusionSSHGitWorkflow',
29402943
'DiffusionSSHGitWorkflow' => 'DiffusionSSHWorkflow',
@@ -4362,6 +4365,7 @@
43624365
'PhabricatorRepositoryManagementEditWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
43634366
'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
43644367
'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
4368+
'PhabricatorRepositoryManagementLookupUsersWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
43654369
'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
43664370
'PhabricatorRepositoryManagementPullWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
43674371
'PhabricatorRepositoryManagementWorkflow' => 'PhutilArgumentWorkflow',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
/**
4+
* Resolve an author or committer name, like
5+
* `"Abraham Lincoln <alincoln@logcab.in>"`, into a valid Phabricator user
6+
* account, like `@alincoln`.
7+
*/
8+
final class DiffusionResolveUserQuery extends Phobject {
9+
10+
private $name;
11+
private $commit;
12+
13+
public function withName($name) {
14+
$this->name = $name;
15+
return $this;
16+
}
17+
18+
public function withCommit($commit) {
19+
$this->commit = $commit;
20+
return $this;
21+
}
22+
23+
public function execute() {
24+
$user_name = $this->name;
25+
26+
$phid = $this->findUserPHID($this->name);
27+
$phid = $this->fireLookupEvent($phid);
28+
29+
return $phid;
30+
}
31+
32+
private function findUserPHID($user_name) {
33+
if (!strlen($user_name)) {
34+
return null;
35+
}
36+
37+
$phid = $this->findUserByUserName($user_name);
38+
if ($phid) {
39+
return $phid;
40+
}
41+
42+
$phid = $this->findUserByEmailAddress($user_name);
43+
if ($phid) {
44+
return $phid;
45+
}
46+
47+
$phid = $this->findUserByRealName($user_name);
48+
if ($phid) {
49+
return $phid;
50+
}
51+
52+
// No hits yet, try to parse it as an email address.
53+
54+
$email = new PhutilEmailAddress($user_name);
55+
56+
$phid = $this->findUserByEmailAddress($email->getAddress());
57+
if ($phid) {
58+
return $phid;
59+
}
60+
61+
$display_name = $email->getDisplayName();
62+
if ($display_name) {
63+
$phid = $this->findUserByUserName($display_name);
64+
if ($phid) {
65+
return $phid;
66+
}
67+
68+
$phid = $this->findUserByRealName($display_name);
69+
if ($phid) {
70+
return $phid;
71+
}
72+
}
73+
74+
return null;
75+
}
76+
77+
78+
/**
79+
* Emit an event so installs can do custom lookup of commit authors who may
80+
* not be naturally resolvable.
81+
*/
82+
private function fireLookupEvent($guess) {
83+
84+
$type = PhabricatorEventType::TYPE_DIFFUSION_LOOKUPUSER;
85+
$data = array(
86+
'commit' => $this->commit,
87+
'query' => $this->name,
88+
'result' => $guess,
89+
);
90+
91+
$event = new PhabricatorEvent($type, $data);
92+
PhutilEventEngine::dispatchEvent($event);
93+
94+
return $event->getValue('result');
95+
}
96+
97+
98+
private function findUserByUserName($user_name) {
99+
$by_username = id(new PhabricatorUser())->loadOneWhere(
100+
'userName = %s',
101+
$user_name);
102+
if ($by_username) {
103+
return $by_username->getPHID();
104+
}
105+
return null;
106+
}
107+
108+
109+
private function findUserByRealName($real_name) {
110+
// Note, real names are not guaranteed unique, which is why we do it this
111+
// way.
112+
$by_realname = id(new PhabricatorUser())->loadAllWhere(
113+
'realName = %s',
114+
$real_name);
115+
if (count($by_realname) == 1) {
116+
return reset($by_realname)->getPHID();
117+
}
118+
return null;
119+
}
120+
121+
122+
private function findUserByEmailAddress($email_address) {
123+
$by_email = PhabricatorUser::loadOneWithEmailAddress($email_address);
124+
if ($by_email) {
125+
return $by_email->getPHID();
126+
}
127+
return null;
128+
}
129+
130+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
final class PhabricatorRepositoryManagementLookupUsersWorkflow
4+
extends PhabricatorRepositoryManagementWorkflow {
5+
6+
public function didConstruct() {
7+
$this
8+
->setName('lookup-users')
9+
->setExamples('**lookup-users** __commit__ ...')
10+
->setSynopsis('Resolve user accounts for users attached to __commit__.')
11+
->setArguments(
12+
array(
13+
array(
14+
'name' => 'commits',
15+
'wildcard' => true,
16+
),
17+
));
18+
}
19+
20+
public function execute(PhutilArgumentParser $args) {
21+
$commits = $this->loadCommits($args, 'commits');
22+
if (!$commits) {
23+
throw new PhutilArgumentUsageException(
24+
"Specify one or more commits to resolve users for.");
25+
}
26+
27+
$console = PhutilConsole::getConsole();
28+
foreach ($commits as $commit) {
29+
$repo = $commit->getRepository();
30+
$name = $repo->formatCommitName($commit->getCommitIdentifier());
31+
32+
$console->writeOut(
33+
"%s\n",
34+
pht("Examining commit %s...", $name));
35+
36+
$ref = id(new DiffusionLowLevelCommitQuery())
37+
->setRepository($repo)
38+
->withIdentifier($commit->getCommitIdentifier())
39+
->execute();
40+
41+
$author = $ref->getAuthor();
42+
$console->writeOut(
43+
"%s\n",
44+
pht('Raw author string: %s', coalesce($author, 'null')));
45+
46+
if ($author !== null) {
47+
$handle = $this->resolveUser($commit, $author);
48+
if ($handle) {
49+
$console->writeOut(
50+
"%s\n",
51+
pht('Phabricator user: %s', $handle->getFullName()));
52+
} else {
53+
$console->writeOut(
54+
"%s\n",
55+
pht('Unable to resolve a corresponding Phabricator user.'));
56+
}
57+
}
58+
59+
$committer = $ref->getCommitter();
60+
$console->writeOut(
61+
"%s\n",
62+
pht('Raw committer string: %s', coalesce($committer, 'null')));
63+
64+
if ($committer !== null) {
65+
$handle = $this->resolveUser($commit, $committer);
66+
if ($handle) {
67+
$console->writeOut(
68+
"%s\n",
69+
pht('Phabricator user: %s', $handle->getFullName()));
70+
} else {
71+
$console->writeOut(
72+
"%s\n",
73+
pht('Unable to resolve a corresponding Phabricator user.'));
74+
}
75+
}
76+
}
77+
78+
return 0;
79+
}
80+
81+
private function resolveUser(PhabricatorRepositoryCommit $commit, $name) {
82+
$phid = id(new DiffusionResolveUserQuery())
83+
->withCommit($commit)
84+
->withName($name)
85+
->execute();
86+
87+
if (!$phid) {
88+
return null;
89+
}
90+
91+
return id(new PhabricatorHandleQuery())
92+
->setViewer(PhabricatorUser::getOmnipotentUser())
93+
->withPHIDs(array($phid))
94+
->executeOne();
95+
}
96+
97+
}

‎src/applications/repository/management/PhabricatorRepositoryManagementWorkflow.php

+22
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,27 @@ protected function loadRepositories(PhutilArgumentParser $args, $param) {
3030
return $repos;
3131
}
3232

33+
protected function loadCommits(PhutilArgumentParser $args, $param) {
34+
$names = $args->getArg($param);
35+
if (!$names) {
36+
return null;
37+
}
38+
39+
$query = id(new DiffusionCommitQuery())
40+
->setViewer(PhabricatorUser::getOmnipotentUser())
41+
->withIdentifiers($names);
42+
43+
$query->execute();
44+
$map = $query->getIdentifierMap();
45+
46+
foreach ($names as $name) {
47+
if (empty($map[$name])) {
48+
throw new PhutilArgumentUsageException(
49+
pht('Commit "%s" does not exist or is ambiguous.', $name));
50+
}
51+
}
52+
53+
return $map;
54+
}
3355

3456
}

0 commit comments

Comments
 (0)
Failed to load comments.