diff --git a/src/applications/diffusion/query/DiffusionCommitQuery.php b/src/applications/diffusion/query/DiffusionCommitQuery.php index 75913ba37e..7098e7416f 100644 --- a/src/applications/diffusion/query/DiffusionCommitQuery.php +++ b/src/applications/diffusion/query/DiffusionCommitQuery.php @@ -1,571 +1,615 @@ ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withAuthorPHIDs(array $phids) { $this->authorPHIDs = $phids; return $this; } /** * Load commits by partial or full identifiers, e.g. "rXab82393", "rX1234", * or "a9caf12". When an identifier matches multiple commits, they will all * be returned; callers should be prepared to deal with more results than * they queried for. */ public function withIdentifiers(array $identifiers) { $this->identifiers = $identifiers; return $this; } /** * Look up commits in a specific repository. This is a shorthand for calling * @{method:withDefaultRepository} and @{method:withRepositoryIDs}. */ public function withRepository(PhabricatorRepository $repository) { $this->withDefaultRepository($repository); $this->withRepositoryIDs(array($repository->getID())); return $this; } /** * Look up commits in a specific repository. Prefer * @{method:withRepositoryIDs}; the underyling table is keyed by ID such * that this method requires a separate initial query to map PHID to ID. */ public function withRepositoryPHIDs(array $phids) { $this->repositoryPHIDs = $phids; } /** * If a default repository is provided, ambiguous commit identifiers will * be assumed to belong to the default repository. * * For example, "r123" appearing in a commit message in repository X is * likely to be unambiguously "rX123". Normally the reference would be * considered ambiguous, but if you provide a default repository it will * be correctly resolved. */ public function withDefaultRepository(PhabricatorRepository $repository) { $this->defaultRepository = $repository; return $this; } public function withRepositoryIDs(array $repository_ids) { $this->repositoryIDs = $repository_ids; return $this; } public function needCommitData($need) { $this->needCommitData = $need; return $this; } public function needAuditRequests($need) { $this->needAuditRequests = $need; return $this; } /** * Returns true if we should join the audit table, either because we're * interested in the information if it's available or because matching rows * must always have it. */ private function shouldJoinAudits() { return $this->auditStatus || $this->rowsMustHaveAudits(); } /** * Return true if we should `JOIN` (vs `LEFT JOIN`) the audit table, because * matching commits will always have audit rows. */ private function rowsMustHaveAudits() { return $this->auditIDs || $this->auditorPHIDs || $this->auditAwaitingUser; } public function withAuditIDs(array $ids) { $this->auditIDs = $ids; return $this; } public function withAuditorPHIDs(array $auditor_phids) { $this->auditorPHIDs = $auditor_phids; return $this; } public function withAuditAwaitingUser(PhabricatorUser $user) { $this->auditAwaitingUser = $user; return $this; } public function withAuditStatus($status) { $this->auditStatus = $status; return $this; } + public function withEpochRange($min, $max) { + $this->epochMin = $min; + $this->epochMax = $max; + return $this; + } + + public function withImporting($importing) { + $this->importing = $importing; + return $this; + } + public function getIdentifierMap() { if ($this->identifierMap === null) { throw new Exception( pht( 'You must %s the query before accessing the identifier map.', 'execute()')); } return $this->identifierMap; } protected function getPrimaryTableAlias() { return 'commit'; } protected function willExecute() { if ($this->identifierMap === null) { $this->identifierMap = array(); } } protected function loadPage() { $table = new PhabricatorRepositoryCommit(); $conn_r = $table->establishConnection('r'); $data = queryfx_all( $conn_r, 'SELECT commit.* FROM %T commit %Q %Q %Q %Q %Q', $table->getTableName(), $this->buildJoinClause($conn_r), $this->buildWhereClause($conn_r), $this->buildGroupClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); return $table->loadAllFromArray($data); } protected function willFilterPage(array $commits) { $repository_ids = mpull($commits, 'getRepositoryID', 'getRepositoryID'); $repos = id(new PhabricatorRepositoryQuery()) ->setViewer($this->getViewer()) ->withIDs($repository_ids) ->execute(); $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; $result = array(); foreach ($commits as $key => $commit) { $repo = idx($repos, $commit->getRepositoryID()); if ($repo) { $commit->attachRepository($repo); } else { $this->didRejectResult($commit); unset($commits[$key]); continue; } // Build the identifierMap if ($this->identifiers !== null) { $ids = array_fuse($this->identifiers); $prefixes = array( 'r'.$commit->getRepository()->getCallsign(), 'r'.$commit->getRepository()->getCallsign().':', 'R'.$commit->getRepository()->getID().':', '', // No prefix is valid too and will only match the commitIdentifier ); $suffix = $commit->getCommitIdentifier(); if ($commit->getRepository()->isSVN()) { foreach ($prefixes as $prefix) { if (isset($ids[$prefix.$suffix])) { $result[$prefix.$suffix][] = $commit; } } } else { // This awkward construction is so we can link the commits up in O(N) // time instead of O(N^2). for ($ii = $min_qualified; $ii <= strlen($suffix); $ii++) { $part = substr($suffix, 0, $ii); foreach ($prefixes as $prefix) { if (isset($ids[$prefix.$part])) { $result[$prefix.$part][] = $commit; } } } } } } if ($result) { foreach ($result as $identifier => $matching_commits) { if (count($matching_commits) == 1) { $result[$identifier] = head($matching_commits); } else { // This reference is ambiguous (it matches more than one commit) so // don't link it. unset($result[$identifier]); } } $this->identifierMap += $result; } return $commits; } protected function didFilterPage(array $commits) { if ($this->needCommitData) { $data = id(new PhabricatorRepositoryCommitData())->loadAllWhere( 'commitID in (%Ld)', mpull($commits, 'getID')); $data = mpull($data, null, 'getCommitID'); foreach ($commits as $commit) { $commit_data = idx($data, $commit->getID()); if (!$commit_data) { $commit_data = new PhabricatorRepositoryCommitData(); } $commit->attachCommitData($commit_data); } } // TODO: This should just be `needAuditRequests`, not `shouldJoinAudits()`, // but leave that for a future diff. if ($this->needAuditRequests || $this->shouldJoinAudits()) { $requests = id(new PhabricatorRepositoryAuditRequest())->loadAllWhere( 'commitPHID IN (%Ls)', mpull($commits, 'getPHID')); $requests = mgroup($requests, 'getCommitPHID'); foreach ($commits as $commit) { $audit_requests = idx($requests, $commit->getPHID(), array()); $commit->attachAudits($audit_requests); foreach ($audit_requests as $audit_request) { $audit_request->attachCommit($commit); } } } return $commits; } protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { $where = array(); if ($this->repositoryPHIDs !== null) { $map_repositories = id (new PhabricatorRepositoryQuery()) ->setViewer($this->getViewer()) ->withPHIDs($this->repositoryPHIDs) ->execute(); if (!$map_repositories) { throw new PhabricatorEmptyQueryException(); } $repository_ids = mpull($map_repositories, 'getID'); if ($this->repositoryIDs !== null) { $repository_ids = array_merge($repository_ids, $this->repositoryIDs); } $this->withRepositoryIDs($repository_ids); } if ($this->ids !== null) { $where[] = qsprintf( $conn_r, 'commit.id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn_r, 'commit.phid IN (%Ls)', $this->phids); } if ($this->repositoryIDs !== null) { $where[] = qsprintf( $conn_r, 'commit.repositoryID IN (%Ld)', $this->repositoryIDs); } if ($this->authorPHIDs !== null) { $where[] = qsprintf( $conn_r, 'commit.authorPHID IN (%Ls)', $this->authorPHIDs); } + if ($this->epochMin !== null) { + $where[] = qsprintf( + $conn_r, + 'commit.epoch >= %d', + $this->epochMin); + } + + if ($this->epochMax !== null) { + $where[] = qsprintf( + $conn_r, + 'commit.epoch <= %d', + $this->epochMax); + } + + if ($this->importing !== null) { + if ($this->importing) { + $where[] = qsprintf( + $conn_r, + '(commit.importStatus & %d) != %d', + PhabricatorRepositoryCommit::IMPORTED_ALL, + PhabricatorRepositoryCommit::IMPORTED_ALL); + } else { + $where[] = qsprintf( + $conn_r, + '(commit.importStatus & %d) = %d', + PhabricatorRepositoryCommit::IMPORTED_ALL, + PhabricatorRepositoryCommit::IMPORTED_ALL); + } + } + if ($this->identifiers !== null) { $min_unqualified = PhabricatorRepository::MINIMUM_UNQUALIFIED_HASH; $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; $refs = array(); $bare = array(); foreach ($this->identifiers as $identifier) { $matches = null; preg_match('/^(?:[rR]([A-Z]+:?|[0-9]+:))?(.*)$/', $identifier, $matches); $repo = nonempty(rtrim($matches[1], ':'), null); $commit_identifier = nonempty($matches[2], null); if ($repo === null) { if ($this->defaultRepository) { $repo = $this->defaultRepository->getCallsign(); } } if ($repo === null) { if (strlen($commit_identifier) < $min_unqualified) { continue; } $bare[] = $commit_identifier; } else { $refs[] = array( 'callsign' => $repo, 'identifier' => $commit_identifier, ); } } $sql = array(); foreach ($bare as $identifier) { $sql[] = qsprintf( $conn_r, '(commit.commitIdentifier LIKE %> AND '. 'LENGTH(commit.commitIdentifier) = 40)', $identifier); } if ($refs) { $callsigns = ipull($refs, 'callsign'); $repos = id(new PhabricatorRepositoryQuery()) ->setViewer($this->getViewer()) ->withIdentifiers($callsigns); $repos->execute(); $repos = $repos->getIdentifierMap(); foreach ($refs as $key => $ref) { $repo = idx($repos, $ref['callsign']); if (!$repo) { continue; } if ($repo->isSVN()) { if (!ctype_digit($ref['identifier'])) { continue; } $sql[] = qsprintf( $conn_r, '(commit.repositoryID = %d AND commit.commitIdentifier = %s)', $repo->getID(), // NOTE: Because the 'commitIdentifier' column is a string, MySQL // ignores the index if we hand it an integer. Hand it a string. // See T3377. (int)$ref['identifier']); } else { if (strlen($ref['identifier']) < $min_qualified) { continue; } $sql[] = qsprintf( $conn_r, '(commit.repositoryID = %d AND commit.commitIdentifier LIKE %>)', $repo->getID(), $ref['identifier']); } } } if (!$sql) { // If we discarded all possible identifiers (e.g., they all referenced // bogus repositories or were all too short), make sure the query finds // nothing. throw new PhabricatorEmptyQueryException( pht('No commit identifiers.')); } $where[] = '('.implode(' OR ', $sql).')'; } if ($this->auditIDs !== null) { $where[] = qsprintf( $conn_r, 'audit.id IN (%Ld)', $this->auditIDs); } if ($this->auditorPHIDs !== null) { $where[] = qsprintf( $conn_r, 'audit.auditorPHID IN (%Ls)', $this->auditorPHIDs); } if ($this->auditAwaitingUser) { $awaiting_user_phid = $this->auditAwaitingUser->getPHID(); // Exclude package and project audits associated with commits where // the user is the author. $where[] = qsprintf( $conn_r, '(commit.authorPHID IS NULL OR commit.authorPHID != %s) OR (audit.auditorPHID = %s)', $awaiting_user_phid, $awaiting_user_phid); } $status = $this->auditStatus; if ($status !== null) { switch ($status) { case self::AUDIT_STATUS_PARTIAL: $where[] = qsprintf( $conn_r, 'commit.auditStatus = %d', PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED); break; case self::AUDIT_STATUS_ACCEPTED: $where[] = qsprintf( $conn_r, 'commit.auditStatus = %d', PhabricatorAuditCommitStatusConstants::FULLY_AUDITED); break; case self::AUDIT_STATUS_CONCERN: $where[] = qsprintf( $conn_r, 'audit.auditStatus = %s', PhabricatorAuditStatusConstants::CONCERNED); break; case self::AUDIT_STATUS_OPEN: $where[] = qsprintf( $conn_r, 'audit.auditStatus in (%Ls)', PhabricatorAuditStatusConstants::getOpenStatusConstants()); if ($this->auditAwaitingUser) { $where[] = qsprintf( $conn_r, 'awaiting.auditStatus IS NULL OR awaiting.auditStatus != %s', PhabricatorAuditStatusConstants::RESIGNED); } break; case self::AUDIT_STATUS_ANY: break; default: $valid = array( self::AUDIT_STATUS_ANY, self::AUDIT_STATUS_OPEN, self::AUDIT_STATUS_CONCERN, self::AUDIT_STATUS_ACCEPTED, self::AUDIT_STATUS_PARTIAL, ); throw new Exception( pht( "Unknown audit status '%s'! Valid statuses are: %s.", $status, implode(', ', $valid))); } } $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); } protected function didFilterResults(array $filtered) { if ($this->identifierMap) { foreach ($this->identifierMap as $name => $commit) { if (isset($filtered[$commit->getPHID()])) { unset($this->identifierMap[$name]); } } } } protected function buildJoinClause(AphrontDatabaseConnection $conn_r) { $joins = array(); $audit_request = new PhabricatorRepositoryAuditRequest(); if ($this->shouldJoinAudits()) { $joins[] = qsprintf( $conn_r, '%Q %T audit ON commit.phid = audit.commitPHID', ($this->rowsMustHaveAudits() ? 'JOIN' : 'LEFT JOIN'), $audit_request->getTableName()); } if ($this->auditAwaitingUser) { // Join the request table on the awaiting user's requests, so we can // filter out package and project requests which the user has resigned // from. $joins[] = qsprintf( $conn_r, 'LEFT JOIN %T awaiting ON audit.commitPHID = awaiting.commitPHID AND awaiting.auditorPHID = %s', $audit_request->getTableName(), $this->auditAwaitingUser->getPHID()); } if ($joins) { return implode(' ', $joins); } else { return ''; } } protected function buildGroupClause(AphrontDatabaseConnection $conn_r) { $should_group = $this->shouldJoinAudits(); // TODO: Currently, the audit table is missing a unique key, so we may // require a GROUP BY if we perform this join. See T1768. This can be // removed once the table has the key. if ($this->auditAwaitingUser) { $should_group = true; } if ($should_group) { return 'GROUP BY commit.id'; } else { return ''; } } public function getQueryApplicationClass() { return 'PhabricatorDiffusionApplication'; } } diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php index e06c6ca089..d36fb3f4ee 100644 --- a/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php +++ b/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php @@ -1,320 +1,366 @@ setName('reparse') ->setExamples('**reparse** [options] __repository__') ->setSynopsis( pht( '**reparse** __what__ __which_parts__ [--trace] [--force]'."\n\n". 'Rerun the Diffusion parser on specific commits and repositories. '. 'Mostly useful for debugging changes to Diffusion.'."\n\n". 'e.g. enqueue reparse owners in the TEST repo for all commits:'."\n". 'repository reparse --all TEST --owners'."\n\n". 'e.g. do same but exclude before yesterday (local time):'."\n". 'repository reparse --all TEST --owners --min-date yesterday'."\n". 'repository reparse --all TEST --owners --min-date "today -1 day".'. "\n\n". 'e.g. do same but exclude before 03/31/2013 (local time):'."\n". 'repository reparse --all TEST --owners --min-date "03/31/2013"')) ->setArguments( array( array( 'name' => 'revision', 'wildcard' => true, ), array( 'name' => 'all', 'param' => 'callsign or phid', 'help' => pht( 'Reparse all commits in the specified repository. This mode '. 'queues parsers into the task queue; you must run taskmasters '. 'to actually do the parses. Use with __%s__ to run '. 'the tasks locally instead of with taskmasters.', '--force-local'), ), array( 'name' => 'min-date', 'param' => 'date', 'help' => pht( "Must be used with __%s__, this will exclude commits which ". "are earlier than __date__.\n". "Valid examples:\n". " 'today', 'today 2pm', '-1 hour', '-2 hours', '-24 hours',\n". " 'yesterday', 'today -1 day', 'yesterday 2pm', '2pm -1 day',\n". " 'last Monday', 'last Monday 14:00', 'last Monday 2pm',\n". " '31 March 2013', '31 Mar', '03/31', '03/31/2013',\n". "See __%s__ for more.", '--all', 'http://www.php.net/manual/en/datetime.formats.php'), ), array( 'name' => 'message', 'help' => pht('Reparse commit messages.'), ), array( 'name' => 'change', 'help' => pht('Reparse changes.'), ), array( 'name' => 'herald', 'help' => pht( 'Reevaluate Herald rules (may send huge amounts of email!)'), ), array( 'name' => 'owners', 'help' => pht( 'Reevaluate related commits for owners packages (may delete '. 'existing relationship entries between your package and some '. 'old commits!)'), ), array( 'name' => 'force', 'short' => 'f', 'help' => pht('Act noninteractively, without prompting.'), ), array( 'name' => 'force-local', 'help' => pht( 'Only used with __%s__, use this to run the tasks locally '. 'instead of deferring them to taskmaster daemons.', '--all'), ), + array( + 'name' => 'importing', + 'help' => pht( + 'Reparse all steps which have not yet completed.'), + ), array( 'name' => 'force-autoclose', 'help' => pht( - 'Only used with __%s, use this to make sure any '. + 'Only used with __%s__, use this to make sure any '. 'pertinent diffs are closed regardless of configuration.', - '--message__'), + '--message'), ), )); } public function execute(PhutilArgumentParser $args) { $console = PhutilConsole::getConsole(); $all_from_repo = $args->getArg('all'); $reparse_message = $args->getArg('message'); $reparse_change = $args->getArg('change'); $reparse_herald = $args->getArg('herald'); $reparse_owners = $args->getArg('owners'); $reparse_what = $args->getArg('revision'); $force = $args->getArg('force'); $force_local = $args->getArg('force-local'); $min_date = $args->getArg('min-date'); + $importing = $args->getArg('importing'); if (!$all_from_repo && !$reparse_what) { throw new PhutilArgumentUsageException( pht('Specify a commit or repository to reparse.')); } if ($all_from_repo && $reparse_what) { $commits = implode(', ', $reparse_what); throw new PhutilArgumentUsageException( pht( "Specify a commit or repository to reparse, not both:\n". "All from repo: %s\n". "Commit(s) to reparse: %s", $all_from_repo, $commits)); } - if (!$reparse_message && !$reparse_change && !$reparse_herald && - !$reparse_owners) { + $any_step = ($reparse_message || + $reparse_change || + $reparse_herald || + $reparse_owners); + + if ($any_step && $importing) { throw new PhutilArgumentUsageException( pht( - 'Specify what information to reparse with %s, %s, %s, and/or %s.', + 'Choosing steps with %s conflicts with flags which select '. + 'specific steps.', + '--importing')); + } else if ($any_step) { + // OK. + } else if ($importing) { + // OK. + } else if (!$any_step && !$importing) { + throw new PhutilArgumentUsageException( + pht( + 'Specify which steps to reparse with %s, or %s, %s, %s, or %s.', + '--importing', '--message', '--change', '--herald', '--owners')); - } + } $min_timestamp = false; if ($min_date) { $min_timestamp = strtotime($min_date); if (!$all_from_repo) { throw new PhutilArgumentUsageException( pht( "You must use --all if you specify --min-date\n". "e.g.\n". " repository reparse --all TEST --owners --min-date yesterday")); } // previous to PHP 5.1.0 you would compare with -1, instead of false if (false === $min_timestamp) { throw new PhutilArgumentUsageException( pht( "Supplied --min-date is not valid. See help for valid examples.\n". "Supplied value: '%s'\n", $min_date)); } } if ($reparse_owners && !$force) { $console->writeOut( "%s\n", pht( 'You are about to recreate the relationship entries between the '. 'commits and the packages they touch. This might delete some '. 'existing relationship entries for some old commits.')); if (!phutil_console_confirm(pht('Are you ready to continue?'))) { throw new PhutilArgumentUsageException(pht('Cancelled.')); } } $commits = array(); if ($all_from_repo) { $repository = id(new PhabricatorRepository())->loadOneWhere( 'callsign = %s OR phid = %s', $all_from_repo, $all_from_repo); if (!$repository) { throw new PhutilArgumentUsageException( pht('Unknown repository %s!', $all_from_repo)); } - $constraint = ''; + + + $query = id(new DiffusionCommitQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withRepository($repository); + if ($min_timestamp) { - $console->writeOut("%s\n", pht( - 'Excluding entries before UNIX timestamp: %s', - $min_timestamp)); - $table = new PhabricatorRepositoryCommit(); - $conn_r = $table->establishConnection('r'); - $constraint = qsprintf( - $conn_r, - 'AND epoch >= %d', - $min_timestamp); + $query->withEpochRange($min_timestamp, null); } - $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere( - 'repositoryID = %d %Q', - $repository->getID(), - $constraint); + + if ($importing) { + $query->withImporting(true); + } + + $commits = $query->execute(); + $callsign = $repository->getCallsign(); if (!$commits) { - throw new PhutilArgumentUsageException(pht( - "No commits have been discovered in %s repository!\n", - $callsign)); + throw new PhutilArgumentUsageException( + pht( + 'No commits have been discovered in %s repository!', + $callsign)); } } else { $commits = array(); foreach ($reparse_what as $identifier) { $matches = null; if (!preg_match('/r([A-Z]+)([a-z0-9]+)/', $identifier, $matches)) { throw new PhutilArgumentUsageException(pht( "Can't parse commit identifier: %s", $identifier)); } $callsign = $matches[1]; $commit_identifier = $matches[2]; $repository = id(new PhabricatorRepository())->loadOneWhere( 'callsign = %s', $callsign); if (!$repository) { throw new PhutilArgumentUsageException(pht( "No repository with callsign '%s'!", $callsign)); } $commit = id(new PhabricatorRepositoryCommit())->loadOneWhere( 'repositoryID = %d AND commitIdentifier = %s', $repository->getID(), $commit_identifier); if (!$commit) { throw new PhutilArgumentUsageException(pht( "No matching commit '%s' in repository '%s'. ". "(For git and mercurial repositories, you must specify the entire ". "commit hash.)", $commit_identifier, $callsign)); } $commits[] = $commit; } } if ($all_from_repo && !$force_local) { $console->writeOut("%s\n", pht( '**NOTE**: This script will queue tasks to reparse the data. Once the '. 'tasks have been queued, you need to run Taskmaster daemons to '. 'execute them.'."\n\n". "QUEUEING TASKS (%s Commits):", new PhutilNumber(count($commits)))); } $progress = new PhutilConsoleProgressBar(); $progress->setTotal(count($commits)); $tasks = array(); foreach ($commits as $commit) { + if ($importing) { + $status = $commit->getImportStatus(); + // Find the first missing import step and queue that up. + $reparse_message = false; + $reparse_change = false; + $reparse_owners = false; + $reparse_herald = false; + if (!($status & PhabricatorRepositoryCommit::IMPORTED_MESSAGE)) { + $reparse_message = true; + } else if (!($status & PhabricatorRepositoryCommit::IMPORTED_CHANGE)) { + $reparse_change = true; + } else if (!($status & PhabricatorRepositoryCommit::IMPORTED_OWNERS)) { + $reparse_owners = true; + } else if (!($status & PhabricatorRepositoryCommit::IMPORTED_HERALD)) { + $reparse_herald = true; + } else { + continue; + } + } + $classes = array(); switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: if ($reparse_message) { $classes[] = 'PhabricatorRepositoryGitCommitMessageParserWorker'; } if ($reparse_change) { $classes[] = 'PhabricatorRepositoryGitCommitChangeParserWorker'; } break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: if ($reparse_message) { $classes[] = 'PhabricatorRepositoryMercurialCommitMessageParserWorker'; } if ($reparse_change) { $classes[] = 'PhabricatorRepositoryMercurialCommitChangeParserWorker'; } break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: if ($reparse_message) { $classes[] = 'PhabricatorRepositorySvnCommitMessageParserWorker'; } if ($reparse_change) { $classes[] = 'PhabricatorRepositorySvnCommitChangeParserWorker'; } break; } if ($reparse_herald) { $classes[] = 'PhabricatorRepositoryCommitHeraldWorker'; } if ($reparse_owners) { $classes[] = 'PhabricatorRepositoryCommitOwnersWorker'; } + // NOTE: With "--importing", we queue the first unparsed step and let + // it queue the other ones normally. Without "--importing", we queue + // all the requested steps explicitly. + $spec = array( 'commitID' => $commit->getID(), - 'only' => true, + 'only' => !$importing, 'forceAutoclose' => $args->getArg('force-autoclose'), ); if ($all_from_repo && !$force_local) { foreach ($classes as $class) { PhabricatorWorker::scheduleTask( $class, $spec, array( 'priority' => PhabricatorWorker::PRIORITY_IMPORT, )); } } else { foreach ($classes as $class) { $worker = newv($class, array($spec)); $worker->executeTask(); } } $progress->update(1); } $progress->done(); return 0; } }