From 2f6784ee1c41d88d8cdab62ce1b791d9aa13d9db Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Thu, 10 May 2018 18:41:19 -0700 Subject: [PATCH] Add workflow to create repository identities Summary: Depends on D19443. Creates a workflow for populating the new identity table by iterating over commits, either one repo at a time or all at once. Locally caches identities to avoid fetching them `inf` times. An actual migration that invokes this workflow will come in another revision that won't land until at least next week. Performance is ~2k commits in 4.9s on my local machine. Test Plan: Ran locally a few times with a few different states of the `repository_identity` table. Reviewers: epriestley Reviewed By: epriestley Subscribers: jcox, Korvin, PHID-OPKG-gm6ozazyms6q6i22gyam Differential Revision: https://secure.phabricator.com/D19446 --- src/__phutil_library_map__.php | 2 + ...oryManagementRebuildIdentitiesWorkflow.php | 101 ++++++++++++++++++ ...torRepositoryManagementReparseWorkflow.php | 2 +- 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index a76247965e..1e9e4281f8 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4118,6 +4118,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryManagementMovePathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMovePathsWorkflow.php', 'PhabricatorRepositoryManagementParentsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementParentsWorkflow.php', 'PhabricatorRepositoryManagementPullWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php', + 'PhabricatorRepositoryManagementRebuildIdentitiesWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php', 'PhabricatorRepositoryManagementRefsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementRefsWorkflow.php', 'PhabricatorRepositoryManagementReparseWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php', 'PhabricatorRepositoryManagementThawWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementThawWorkflow.php', @@ -10031,6 +10032,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryManagementMovePathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementParentsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementPullWorkflow' => 'PhabricatorRepositoryManagementWorkflow', + 'PhabricatorRepositoryManagementRebuildIdentitiesWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementRefsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementReparseWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementThawWorkflow' => 'PhabricatorRepositoryManagementWorkflow', diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php new file mode 100644 index 0000000000..f7a0cf58f8 --- /dev/null +++ b/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php @@ -0,0 +1,101 @@ +setName('rebuild-identities') + ->setExamples( + '**rebuild-identities** [__options__] __repository__') + ->setSynopsis(pht('Rebuild repository identities from commits.')) + ->setArguments( + array( + array( + 'name' => 'repositories', + 'wildcard' => true, + ), + array( + 'name' => 'all', + 'help' => pht('Rebuild identities across all repositories.'), + ), + )); + } + + public function execute(PhutilArgumentParser $args) { + $console = PhutilConsole::getConsole(); + + $all = $args->getArg('all'); + $repositories = $args->getArg('repositories'); + + if ($all xor empty($repositories)) { + throw new PhutilArgumentUsageException( + pht('Specify --all or a list of repositories, but not both.')); + } + + $query = id(new DiffusionCommitQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->needCommitData(true); + + if ($repositories) { + $repos = $this->loadRepositories($args, 'repositories'); + $query->withRepositoryIDs(mpull($repos, 'getID')); + } + + $iterator = new PhabricatorQueryIterator($query); + foreach ($iterator as $commit) { + $data = $commit->getCommitData(); + $author_name = $data->getAuthorName(); + $author_identity = $this->getIdentityForCommit( + $commit, $author_name); + + $commit->setAuthorIdentityPHID($author_identity->getPHID()); + $data->setCommitDetail( + 'authorIdentityPHID', $author_identity->getPHID()); + + $committer_name = $data->getCommitDetail('committer', null); + if ($committer_name) { + $committer_identity = $this->getIdentityForCommit( + $commit, $committer_name); + + $commit->setCommitterIdentityPHID($committer_identity->getPHID()); + $data->setCommitDetail( + 'committerIdentityPHID', $committer_identity->getPHID()); + } + + $commit->save(); + $data->save(); + } + + } + + private function getIdentityForCommit( + PhabricatorRepositoryCommit $commit, $identity_name) { + + static $seen = array(); + $identity_key = PhabricatorHash::digestForIndex($identity_name); + if (empty($seen[$identity_key])) { + try { + $user_phid = id(new DiffusionResolveUserQuery()) + ->withCommit($commit) + ->withName($identity_name) + ->execute(); + + $identity = id(new PhabricatorRepositoryIdentity()) + ->setAuthorPHID($commit->getPHID()) + ->setIdentityName($identity_name) + ->setAutomaticGuessedUserPHID($user_phid) + ->save(); + } catch (AphrontDuplicateKeyQueryException $ex) { + // Somehow this identity already exists? + $identity = id(new PhabricatorRepositoryIdentityQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withIdentityNames(array($identity_name)) + ->executeOne(); + } + $seen[$identity_key] = $identity; + } + + return $seen[$identity_key]; + } +} diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php index 2067fdbd11..8b89075219 100644 --- a/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php +++ b/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php @@ -6,7 +6,7 @@ final class PhabricatorRepositoryManagementReparseWorkflow protected function didConstruct() { $this ->setName('reparse') - ->setExamples('**reparse** [options] __repository__') + ->setExamples('**reparse** [options] __commit__') ->setSynopsis( pht( '**reparse** __what__ __which_parts__ [--trace] [--force]'."\n\n".