Page MenuHomePhabricator

D20911.diff
No OneTemporary

D20911.diff

diff --git a/src/applications/config/check/PhabricatorManualActivitySetupCheck.php b/src/applications/config/check/PhabricatorManualActivitySetupCheck.php
--- a/src/applications/config/check/PhabricatorManualActivitySetupCheck.php
+++ b/src/applications/config/check/PhabricatorManualActivitySetupCheck.php
@@ -113,7 +113,8 @@
'pre',
array(),
(string)csprintf(
- 'phabricator/ $ ./bin/repository rebuild-identities --all'));
+ 'phabricator/ $ '.
+ './bin/repository rebuild-identities --all-repositories'));
$message[] = pht(
'You can find more information about this new identity mapping '.
diff --git a/src/applications/diffusion/identity/DiffusionRepositoryIdentityEngine.php b/src/applications/diffusion/identity/DiffusionRepositoryIdentityEngine.php
--- a/src/applications/diffusion/identity/DiffusionRepositoryIdentityEngine.php
+++ b/src/applications/diffusion/identity/DiffusionRepositoryIdentityEngine.php
@@ -68,6 +68,24 @@
}
private function updateIdentity(PhabricatorRepositoryIdentity $identity) {
+
+ // If we're updating an identity and it has a manual user PHID associated
+ // with it but the user is no longer valid, remove the value. This likely
+ // corresponds to a user that was destroyed.
+
+ $assigned_phid = $identity->getManuallySetUserPHID();
+ $unassigned = DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN;
+ if ($assigned_phid && ($assigned_phid !== $unassigned)) {
+ $viewer = $this->getViewer();
+ $user = id(new PhabricatorPeopleQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($assigned_phid))
+ ->executeOne();
+ if (!$user) {
+ $identity->setManuallySetUserPHID(null);
+ }
+ }
+
$resolved_phid = $this->resolveIdentity($identity);
$identity
diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php
--- a/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php
+++ b/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php
@@ -14,38 +14,172 @@
->setArguments(
array(
array(
- 'name' => 'repositories',
- 'wildcard' => true,
+ 'name' => 'all-repositories',
+ 'help' => pht('Rebuild identities across all repositories.'),
),
array(
- 'name' => 'all',
- 'help' => pht('Rebuild identities across all repositories.'),
- ),
+ 'name' => 'all-identities',
+ 'help' => pht('Rebuild all currently-known identities.'),
+ ),
+ array(
+ 'name' => 'repository',
+ 'param' => 'repository',
+ 'repeat' => true,
+ 'help' => pht('Rebuild identities in a repository.'),
+ ),
+ array(
+ 'name' => 'commit',
+ 'param' => 'commit',
+ 'repeat' => true,
+ 'help' => pht('Rebuild identities for a commit.'),
+ ),
+ array(
+ 'name' => 'user',
+ 'param' => 'user',
+ 'repeat' => true,
+ 'help' => pht('Rebuild identities for a user.'),
+ ),
+ array(
+ 'name' => 'email',
+ 'param' => 'email',
+ 'repeat' => true,
+ 'help' => pht('Rebuild identities for an email address.'),
+ ),
+ array(
+ 'name' => 'raw',
+ 'param' => 'raw',
+ 'repeat' => true,
+ 'help' => pht('Rebuild identities for a raw commit string.'),
+ ),
));
}
public function execute(PhutilArgumentParser $args) {
- $console = PhutilConsole::getConsole();
+ $viewer = $this->getViewer();
+
+ $rebuilt_anything = false;
- $all = $args->getArg('all');
- $repositories = $args->getArg('repositories');
- if ($all xor empty($repositories)) {
+ $all_repositories = $args->getArg('all-repositories');
+ $repositories = $args->getArg('repository');
+
+ if ($all_repositories && $repositories) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Flags "--all-repositories" and "--repository" are not '.
+ 'compatible.'));
+ }
+
+
+ $all_identities = $args->getArg('all-identities');
+ $raw = $args->getArg('raw');
+
+ if ($all_identities && $raw) {
throw new PhutilArgumentUsageException(
- pht('Specify --all or a list of repositories, but not both.'));
+ pht(
+ 'Flags "--all-identities" and "--raw" are not '.
+ 'compatible.'));
}
- $query = id(new DiffusionCommitQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
- ->needCommitData(true);
+ if ($all_repositories || $repositories) {
+ $rebuilt_anything = true;
- if ($repositories) {
- $repos = $this->loadRepositories($args, 'repositories');
- $query->withRepositoryIDs(mpull($repos, 'getID'));
+ if ($repositories) {
+ $repository_list = $this->loadRepositories($args, 'repository');
+ } else {
+ $repository_query = id(new PhabricatorRepositoryQuery())
+ ->setViewer($viewer);
+ $repository_list = new PhabricatorQueryIterator($repository_query);
+ }
+
+ foreach ($repository_list as $repository) {
+ $commit_query = id(new DiffusionCommitQuery())
+ ->setViewer($viewer)
+ ->needCommitData(true)
+ ->withRepositoryIDs(array($repository->getID()));
+
+ $commit_iterator = new PhabricatorQueryIterator($commit_query);
+
+ $this->rebuildCommits($commit_iterator);
+ }
+ }
+
+ $commits = $args->getArg('commit');
+ if ($commits) {
+ $rebuilt_anything = true;
+ $commit_list = $this->loadCommits($args, 'commit');
+
+ // Reload commits to get commit data.
+ $commit_list = id(new DiffusionCommitQuery())
+ ->setViewer($viewer)
+ ->needCommitData(true)
+ ->withIDs(mpull($commit_list, 'getID'))
+ ->execute();
+
+ $this->rebuildCommits($commit_list);
+ }
+
+ $users = $args->getArg('user');
+ if ($users) {
+ $rebuilt_anything = true;
+
+ $user_list = $this->loadUsersFromArguments($users);
+ $this->rebuildUsers($user_list);
+ }
+
+ $emails = $args->getArg('email');
+ if ($emails) {
+ $rebuilt_anything = true;
+ $this->rebuildEmails($emails);
+ }
+
+ if ($all_identities || $raw) {
+ $rebuilt_anything = true;
+
+ if ($raw) {
+ $identities = id(new PhabricatorRepositoryIdentityQuery())
+ ->setViewer($viewer)
+ ->withIdentityNames($raw)
+ ->execute();
+
+ $identities = mpull($identities, null, 'getIdentityNameRaw');
+ foreach ($raw as $raw_identity) {
+ if (!isset($identities[$raw_identity])) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'No identity "%s" exists. When selecting identities with '.
+ '"--raw", the entire identity must match exactly.',
+ $raw_identity));
+ }
+ }
+
+ $identity_list = $identities;
+ } else {
+ $identity_query = id(new PhabricatorRepositoryIdentityQuery())
+ ->setViewer($viewer);
+
+ $identity_list = new PhabricatorQueryIterator($identity_query);
+
+ $this->logInfo(
+ pht('REBUILD'),
+ pht('Rebuilding all existing identities.'));
+ }
+
+ $this->rebuildIdentities($identity_list);
+ }
+
+ if (!$rebuilt_anything) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Nothing specified to rebuild. Use flags to choose which '.
+ 'identities to rebuild, or "--help" for help.'));
}
- $iterator = new PhabricatorQueryIterator($query);
- foreach ($iterator as $commit) {
+ return 0;
+ }
+
+ private function rebuildCommits($commits) {
+ foreach ($commits as $commit) {
$needs_update = false;
$data = $commit->getCommitData();
@@ -57,6 +191,8 @@
$author_phid = $commit->getAuthorIdentityPHID();
$identity_phid = $author_identity->getPHID();
+
+ $aidentity_phid = $identity_phid;
if ($author_phid !== $identity_phid) {
$commit->setAuthorIdentityPHID($identity_phid);
$data->setCommitDetail('authorIdentityPHID', $identity_phid);
@@ -83,16 +219,20 @@
if ($needs_update) {
$commit->save();
$data->save();
- echo tsprintf(
- "Rebuilt identities for %s.\n",
- $commit->getDisplayName());
+
+ $this->logInfo(
+ pht('COMMIT'),
+ pht(
+ 'Rebuilt identities for "%s".',
+ $commit->getDisplayName()));
} else {
- echo tsprintf(
- "No changes for %s.\n",
- $commit->getDisplayName());
+ $this->logInfo(
+ pht('SKIP'),
+ pht(
+ 'No changes for commit "%s".',
+ $commit->getDisplayName()));
}
}
-
}
private function getIdentityForCommit(
@@ -113,4 +253,131 @@
return $this->identityCache[$raw_identity];
}
+
+ private function rebuildUsers($users) {
+ $viewer = $this->getViewer();
+
+ foreach ($users as $user) {
+ $this->logInfo(
+ pht('USER'),
+ pht(
+ 'Rebuilding identities for user "%s".',
+ $user->getMonogram()));
+
+ $emails = id(new PhabricatorUserEmail())->loadAllWhere(
+ 'userPHID = %s',
+ $user->getPHID());
+ if ($emails) {
+ $this->rebuildEmails(mpull($emails, 'getAddress'));
+ }
+
+ $identities = id(new PhabricatorRepositoryIdentityQuery())
+ ->setViewer($viewer)
+ ->withRelatedPHIDs(array($user->getPHID()))
+ ->execute();
+
+ if (!$identities) {
+ $this->logWarn(
+ pht('NO IDENTITIES'),
+ pht('Found no identities directly related to user.'));
+ continue;
+ }
+
+ $this->rebuildIdentities($identities);
+ }
+ }
+
+ private function rebuildEmails($emails) {
+ $viewer = $this->getViewer();
+
+ foreach ($emails as $email) {
+ $this->logInfo(
+ pht('EMAIL'),
+ pht('Rebuilding identities for email address "%s".', $email));
+
+ $identities = id(new PhabricatorRepositoryIdentityQuery())
+ ->setViewer($viewer)
+ ->withEmailAddresses(array($email))
+ ->execute();
+
+ if (!$identities) {
+ $this->logWarn(
+ pht('NO IDENTITIES'),
+ pht('Found no identities for email address "%s".', $email));
+ continue;
+ }
+
+ $this->rebuildIdentities($identities);
+ }
+ }
+
+ private function rebuildIdentities($identities) {
+ $viewer = $this->getViewer();
+
+ foreach ($identities as $identity) {
+ $raw_identity = $identity->getIdentityName();
+
+ if (isset($this->identityCache[$raw_identity])) {
+ $this->logInfo(
+ pht('SKIP'),
+ pht(
+ 'Identity "%s" has already been rebuilt.',
+ $raw_identity));
+ continue;
+ }
+
+ $this->logInfo(
+ pht('IDENTITY'),
+ pht(
+ 'Rebuilding identity "%s".',
+ $raw_identity));
+
+ $old_auto = $identity->getAutomaticGuessedUserPHID();
+ $old_assign = $identity->getManuallySetUserPHID();
+
+ $identity = id(new DiffusionRepositoryIdentityEngine())
+ ->setViewer($viewer)
+ ->newUpdatedIdentity($identity);
+
+ $this->identityCache[$raw_identity] = $identity;
+
+ $new_auto = $identity->getAutomaticGuessedUserPHID();
+ $new_assign = $identity->getManuallySetUserPHID();
+
+ $same_auto = ($old_auto === $new_auto);
+ $same_assign = ($old_assign === $new_assign);
+
+ if ($same_auto && $same_assign) {
+ $this->logInfo(
+ pht('UNCHANGED'),
+ pht('No changes to identity.'));
+ } else {
+ if (!$same_auto) {
+ $this->logWarn(
+ pht('AUTOMATIC PHID'),
+ pht(
+ 'Automatic user updated from "%s" to "%s".',
+ $this->renderPHID($old_auto),
+ $this->renderPHID($new_auto)));
+ }
+ if (!$same_assign) {
+ $this->logWarn(
+ pht('ASSIGNED PHID'),
+ pht(
+ 'Assigned user updated from "%s" to "%s".',
+ $this->renderPHID($old_assign),
+ $this->renderPHID($new_assign)));
+ }
+ }
+ }
+ }
+
+ private function renderPHID($phid) {
+ if ($phid == null) {
+ return pht('NULL');
+ } else {
+ return $phid;
+ }
+ }
+
}
diff --git a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
--- a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
+++ b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
@@ -11,6 +11,7 @@
private $effectivePHIDs;
private $identityNameLike;
private $hasEffectivePHID;
+ private $relatedPHIDs;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -47,6 +48,11 @@
return $this;
}
+ public function withRelatedPHIDs(array $related) {
+ $this->relatedPHIDs = $related;
+ return $this;
+ }
+
public function withHasEffectivePHID($has_effective_phid) {
$this->hasEffectivePHID = $has_effective_phid;
return $this;
@@ -57,7 +63,7 @@
}
protected function getPrimaryTableAlias() {
- return 'repository_identity';
+ return 'identity';
}
protected function loadPage() {
@@ -70,28 +76,28 @@
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.id IN (%Ld)',
+ 'identity.id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.phid IN (%Ls)',
+ 'identity.phid IN (%Ls)',
$this->phids);
}
if ($this->assignedPHIDs !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.manuallySetUserPHID IN (%Ls)',
+ 'identity.manuallySetUserPHID IN (%Ls)',
$this->assignedPHIDs);
}
if ($this->effectivePHIDs !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.currentEffectiveUserPHID IN (%Ls)',
+ 'identity.currentEffectiveUserPHID IN (%Ls)',
$this->effectivePHIDs);
}
@@ -99,11 +105,11 @@
if ($this->hasEffectivePHID) {
$where[] = qsprintf(
$conn,
- 'repository_identity.currentEffectiveUserPHID IS NOT NULL');
+ 'identity.currentEffectiveUserPHID IS NOT NULL');
} else {
$where[] = qsprintf(
$conn,
- 'repository_identity.currentEffectiveUserPHID IS NULL');
+ 'identity.currentEffectiveUserPHID IS NULL');
}
}
@@ -115,24 +121,35 @@
$where[] = qsprintf(
$conn,
- 'repository_identity.identityNameHash IN (%Ls)',
+ 'identity.identityNameHash IN (%Ls)',
$name_hashes);
}
if ($this->emailAddresses !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.emailAddress IN (%Ls)',
+ 'identity.emailAddress IN (%Ls)',
$this->emailAddresses);
}
if ($this->identityNameLike != null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.identityNameRaw LIKE %~',
+ 'identity.identityNameRaw LIKE %~',
$this->identityNameLike);
}
+ if ($this->relatedPHIDs !== null) {
+ $where[] = qsprintf(
+ $conn,
+ '(identity.manuallySetUserPHID IN (%Ls) OR
+ identity.currentEffectiveUserPHID IN (%Ls) OR
+ identity.automaticGuessedUserPHID IN (%Ls))',
+ $this->relatedPHIDs,
+ $this->relatedPHIDs,
+ $this->relatedPHIDs);
+ }
+
return $where;
}
diff --git a/src/infrastructure/management/PhabricatorManagementWorkflow.php b/src/infrastructure/management/PhabricatorManagementWorkflow.php
--- a/src/infrastructure/management/PhabricatorManagementWorkflow.php
+++ b/src/infrastructure/management/PhabricatorManagementWorkflow.php
@@ -67,4 +67,125 @@
fprintf(STDERR, '%s', $message);
}
+ final protected function loadUsersFromArguments(array $identifiers) {
+ if (!$identifiers) {
+ return array();
+ }
+
+ $ids = array();
+ $phids = array();
+ $usernames = array();
+
+ $user_type = PhabricatorPeopleUserPHIDType::TYPECONST;
+
+ foreach ($identifiers as $identifier) {
+ // If the value is a user PHID, treat as a PHID.
+ if (phid_get_type($identifier) === $user_type) {
+ $phids[$identifier] = $identifier;
+ continue;
+ }
+
+ // If the value is "@..." and then some text, treat it as a username.
+ if ((strlen($identifier) > 1) && ($identifier[0] == '@')) {
+ $usernames[$identifier] = substr($identifier, 1);
+ continue;
+ }
+
+ // If the value is digits, treat it as both an ID and a username.
+ // Entirely numeric usernames, like "1234", are valid.
+ if (ctype_digit($identifier)) {
+ $ids[$identifier] = $identifier;
+ $usernames[$identifier] = $identifier;
+ continue;
+ }
+
+ // Otherwise, treat it as an unescaped username.
+ $usernames[$identifier] = $identifier;
+ }
+
+ $viewer = $this->getViewer();
+ $results = array();
+
+ if ($phids) {
+ $users = id(new PhabricatorPeopleQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($phids)
+ ->execute();
+ foreach ($users as $user) {
+ $phid = $user->getPHID();
+ $results[$phid][] = $user;
+ }
+ }
+
+ if ($usernames) {
+ $users = id(new PhabricatorPeopleQuery())
+ ->setViewer($viewer)
+ ->withUsernames($usernames)
+ ->execute();
+
+ $reverse_map = array();
+ foreach ($usernames as $identifier => $username) {
+ $username = phutil_utf8_strtolower($username);
+ $reverse_map[$username][] = $identifier;
+ }
+
+ foreach ($users as $user) {
+ $username = $user->getUsername();
+ $username = phutil_utf8_strtolower($username);
+
+ $reverse_identifiers = idx($reverse_map, $username, array());
+
+ if (count($reverse_identifiers) > 1) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Multiple user identifiers (%s) correspond to the same user. '.
+ 'Identify each user exactly once.',
+ implode(', ', $reverse_identifiers)));
+ }
+
+ foreach ($reverse_identifiers as $reverse_identifier) {
+ $results[$reverse_identifier][] = $user;
+ }
+ }
+ }
+
+ if ($ids) {
+ $users = id(new PhabricatorPeopleQuery())
+ ->setViewer($viewer)
+ ->withIDs($ids)
+ ->execute();
+
+ foreach ($users as $user) {
+ $id = $user->getID();
+ $results[$id][] = $user;
+ }
+ }
+
+ $list = array();
+ foreach ($identifiers as $identifier) {
+ $users = idx($results, $identifier, array());
+ if (!$users) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'No user "%s" exists. Specify users by username, ID, or PHID.',
+ $identifier));
+ }
+
+ if (count($users) > 1) {
+ // This can happen if you have a user "@25", a user with ID 25, and
+ // specify "--user 25". You can disambiguate this by specifying
+ // "--user @25".
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Identifier "%s" matches multiple users. Specify each user '.
+ 'unambiguously with "@username" or by using user PHIDs.',
+ $identifier));
+ }
+
+ $list[] = head($users);
+ }
+
+ return $list;
+ }
+
}

File Metadata

Mime Type
text/plain
Expires
Sun, May 12, 4:13 AM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6288643
Default Alt Text
D20911.diff (19 KB)

Event Timeline