3 final class PhabricatorRepositoryManagementReparseWorkflow
4 extends PhabricatorRepositoryManagementWorkflow
{
6 protected function didConstruct() {
9 ->setExamples('**reparse** [options] __commit__')
12 '**reparse** __what__ __which_parts__ [--trace] [--force]'."\n\n".
13 'Rerun the Diffusion parser on specific commits and repositories. '.
14 'Mostly useful for debugging changes to Diffusion.'."\n\n".
15 'e.g. do same but exclude before yesterday (local time):'."\n".
16 'repository reparse --all TEST --change --min-date yesterday'."\n".
17 'repository reparse --all TEST --change --min-date "today -1 day".'.
19 'e.g. do same but exclude before 03/31/2013 (local time):'."\n".
20 'repository reparse --all TEST --change --min-date "03/31/2013"'))
29 'param' => 'repository',
31 'Reparse all commits in the specified repository.'),
37 "Must be used with __%s__, this will exclude commits which ".
38 "are earlier than __date__.\n".
40 " 'today', 'today 2pm', '-1 hour', '-2 hours', '-24 hours',\n".
41 " 'yesterday', 'today -1 day', 'yesterday 2pm', '2pm -1 day',\n".
42 " 'last Monday', 'last Monday 14:00', 'last Monday 2pm',\n".
43 " '31 March 2013', '31 Mar', '03/31', '03/31/2013',\n".
44 "See __%s__ for more.",
46 'http://www.php.net/manual/en/datetime.formats.php'),
50 'help' => pht('Reparse commit messages.'),
54 'help' => pht('Reparse source changes.'),
59 'Publish changes: send email, publish Feed stories, run '.
60 'Herald rules, etc.'),
65 'help' => pht('Act noninteractively, without prompting.'),
68 'name' => 'background',
70 'Queue tasks for the daemons instead of running them in the '.
74 'name' => 'importing',
75 'help' => pht('Reparse all steps which have not yet completed.'),
81 public function execute(PhutilArgumentParser
$args) {
82 $console = PhutilConsole
::getConsole();
84 $all_from_repo = $args->getArg('all');
85 $reparse_message = $args->getArg('message');
86 $reparse_change = $args->getArg('change');
87 $reparse_publish = $args->getArg('publish');
88 $reparse_what = $args->getArg('revision');
89 $force = $args->getArg('force');
90 $background = $args->getArg('background');
91 $min_date = $args->getArg('min-date');
92 $importing = $args->getArg('importing');
94 if (!$all_from_repo && !$reparse_what) {
95 throw new PhutilArgumentUsageException(
96 pht('Specify a commit or repository to reparse.'));
99 if ($all_from_repo && $reparse_what) {
100 $commits = implode(', ', $reparse_what);
101 throw new PhutilArgumentUsageException(
103 "Specify a commit or repository to reparse, not both:\n".
104 "All from repo: %s\n".
105 "Commit(s) to reparse: %s",
110 $any_step = ($reparse_message ||
$reparse_change ||
$reparse_publish);
112 if ($any_step && $importing) {
113 throw new PhutilArgumentUsageException(
115 'Choosing steps with "--importing" conflicts with flags which '.
116 'select specific steps.'));
117 } else if ($any_step) {
119 } else if ($importing) {
121 } else if (!$any_step && !$importing) {
122 throw new PhutilArgumentUsageException(
124 'Specify which steps to reparse with "--message", "--change", '.
125 'and/or "--publish"; or "--importing" to run all missing steps.'));
128 $min_timestamp = false;
130 $min_timestamp = strtotime($min_date);
132 if (!$all_from_repo) {
133 throw new PhutilArgumentUsageException(
135 'You must use "--all" if you specify "--min-date".'));
138 // previous to PHP 5.1.0 you would compare with -1, instead of false
139 if (false === $min_timestamp) {
140 throw new PhutilArgumentUsageException(
142 "Supplied --min-date is not valid. See help for valid examples.\n".
143 "Supplied value: '%s'\n",
149 if ($all_from_repo) {
150 $repository = id(new PhabricatorRepositoryQuery())
151 ->setViewer(PhabricatorUser
::getOmnipotentUser())
152 ->withIdentifiers(array($all_from_repo))
156 throw new PhutilArgumentUsageException(
157 pht('Unknown repository "%s"!', $all_from_repo));
160 $query = id(new DiffusionCommitQuery())
161 ->setViewer(PhabricatorUser
::getOmnipotentUser())
162 ->withRepository($repository);
164 if ($min_timestamp) {
165 $query->withEpochRange($min_timestamp, null);
169 $query->withImporting(true);
172 $commits = $query->execute();
175 throw new PhutilArgumentUsageException(
177 'No commits have been discovered in the "%s" repository!',
178 $repository->getDisplayName()));
181 $commits = $this->loadNamedCommits($reparse_what);
185 PhabricatorWorker
::setRunAllTasksInProcess(true);
188 $progress = new PhutilConsoleProgressBar();
189 $progress->setTotal(count($commits));
192 foreach ($commits as $commit) {
193 $repository = $commit->getRepository();
196 $status = $commit->getImportStatus();
197 // Find the first missing import step and queue that up.
198 $reparse_message = false;
199 $reparse_change = false;
200 $reparse_publish = false;
201 if (!($status & PhabricatorRepositoryCommit
::IMPORTED_MESSAGE
)) {
202 $reparse_message = true;
203 } else if (!($status & PhabricatorRepositoryCommit
::IMPORTED_CHANGE
)) {
204 $reparse_change = true;
205 } else if (!($status & PhabricatorRepositoryCommit
::IMPORTED_PUBLISH
)) {
206 $reparse_publish = true;
213 switch ($repository->getVersionControlSystem()) {
214 case PhabricatorRepositoryType
::REPOSITORY_TYPE_GIT
:
215 if ($reparse_message) {
216 $classes[] = 'PhabricatorRepositoryGitCommitMessageParserWorker';
218 if ($reparse_change) {
219 $classes[] = 'PhabricatorRepositoryGitCommitChangeParserWorker';
222 case PhabricatorRepositoryType
::REPOSITORY_TYPE_MERCURIAL
:
223 if ($reparse_message) {
225 'PhabricatorRepositoryMercurialCommitMessageParserWorker';
227 if ($reparse_change) {
228 $classes[] = 'PhabricatorRepositoryMercurialCommitChangeParserWorker';
231 case PhabricatorRepositoryType
::REPOSITORY_TYPE_SVN
:
232 if ($reparse_message) {
233 $classes[] = 'PhabricatorRepositorySvnCommitMessageParserWorker';
235 if ($reparse_change) {
236 $classes[] = 'PhabricatorRepositorySvnCommitChangeParserWorker';
241 if ($reparse_publish) {
242 $classes[] = 'PhabricatorRepositoryCommitPublishWorker';
245 // NOTE: With "--importing", we queue the first unparsed step and let
246 // it queue the other ones normally. Without "--importing", we queue
247 // all the requested steps explicitly.
250 'commitPHID' => $commit->getPHID(),
251 'only' => !$importing,
255 foreach ($classes as $class) {
257 PhabricatorWorker
::scheduleTask(
261 'priority' => PhabricatorWorker
::PRIORITY_IMPORT
,
262 'objectPHID' => $commit->getPHID(),
263 'containerPHID' => $repository->getPHID(),
265 } catch (PhabricatorWorkerPermanentFailureException
$ex) {
266 // See T13315. We expect some reparse steps to occasionally raise
267 // permanent failures: for example, because they are no longer
268 // reachable. This is a routine condition, not a catastrophic
269 // failure, so let the user know something happened but continue
270 // reparsing any remaining commits.
272 "<bg:yellow>** %s **</bg> %s\n",
278 $progress->update(1);