mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-09 16:32:39 +01:00
Allow bulk edits to be made silently if you have CLI access
Summary: Fixes T13042. This hooks up the new "silent" mode from D18882 and makes it actually work. The UI (where we tell you to go run some command and then reload the page) is pretty clumsy, but should solve some problems for now and can be cleaned up eventually. The actual mechanics (timeline aggregation, Herald interaction, etc.) are on firmer ground. Test Plan: - Made a normal bulk edit, got mail and feed stories. - Made a silent bulk edit, no mail and no feed. - Saw "Silent Edit" marker in timeline for silent edits: {F5386245} Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13042 Differential Revision: https://secure.phabricator.com/D18883
This commit is contained in:
parent
8b12fa6d6e
commit
3038d564a6
12 changed files with 165 additions and 5 deletions
1
bin/bulk
Symbolic link
1
bin/bulk
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../scripts/setup/manage_bulk.php
|
2
resources/sql/autopatches/20180119.bulk.01.silent.sql
Normal file
2
resources/sql/autopatches/20180119.bulk.01.silent.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_worker.worker_bulkjob
|
||||||
|
ADD isSilent BOOL NOT NULL;
|
1
scripts/manage_bulk.php
Symbolic link
1
scripts/manage_bulk.php
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../scripts/setup/manage_bulk.php
|
21
scripts/setup/manage_bulk.php
Executable file
21
scripts/setup/manage_bulk.php
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$root = dirname(dirname(dirname(__FILE__)));
|
||||||
|
require_once $root.'/scripts/__init_script__.php';
|
||||||
|
|
||||||
|
$args = new PhutilArgumentParser($argv);
|
||||||
|
$args->setTagline(pht('manage bulk jobs'));
|
||||||
|
$args->setSynopsis(<<<EOSYNOPSIS
|
||||||
|
**bulk** __command__ [__options__]
|
||||||
|
Manage and debug bulk jobs.
|
||||||
|
|
||||||
|
EOSYNOPSIS
|
||||||
|
);
|
||||||
|
$args->parseStandardArguments();
|
||||||
|
|
||||||
|
$workflows = id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass('PhabricatorBulkManagementWorkflow')
|
||||||
|
->execute();
|
||||||
|
$workflows[] = new PhutilHelpArgumentWorkflow();
|
||||||
|
$args->parseWorkflows($workflows);
|
|
@ -2206,6 +2206,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php',
|
'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php',
|
||||||
'PhabricatorBulkEditGroup' => 'applications/transactions/bulk/PhabricatorBulkEditGroup.php',
|
'PhabricatorBulkEditGroup' => 'applications/transactions/bulk/PhabricatorBulkEditGroup.php',
|
||||||
'PhabricatorBulkEngine' => 'applications/transactions/bulk/PhabricatorBulkEngine.php',
|
'PhabricatorBulkEngine' => 'applications/transactions/bulk/PhabricatorBulkEngine.php',
|
||||||
|
'PhabricatorBulkManagementMakeSilentWorkflow' => 'applications/transactions/bulk/management/PhabricatorBulkManagementMakeSilentWorkflow.php',
|
||||||
|
'PhabricatorBulkManagementWorkflow' => 'applications/transactions/bulk/management/PhabricatorBulkManagementWorkflow.php',
|
||||||
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
|
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
|
||||||
'PhabricatorCacheEngine' => 'applications/system/engine/PhabricatorCacheEngine.php',
|
'PhabricatorCacheEngine' => 'applications/system/engine/PhabricatorCacheEngine.php',
|
||||||
'PhabricatorCacheEngineExtension' => 'applications/system/engine/PhabricatorCacheEngineExtension.php',
|
'PhabricatorCacheEngineExtension' => 'applications/system/engine/PhabricatorCacheEngineExtension.php',
|
||||||
|
@ -7504,6 +7506,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorBulkContentSource' => 'PhabricatorContentSource',
|
'PhabricatorBulkContentSource' => 'PhabricatorContentSource',
|
||||||
'PhabricatorBulkEditGroup' => 'Phobject',
|
'PhabricatorBulkEditGroup' => 'Phobject',
|
||||||
'PhabricatorBulkEngine' => 'Phobject',
|
'PhabricatorBulkEngine' => 'Phobject',
|
||||||
|
'PhabricatorBulkManagementMakeSilentWorkflow' => 'PhabricatorBulkManagementWorkflow',
|
||||||
|
'PhabricatorBulkManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
|
||||||
'PhabricatorCacheEngine' => 'Phobject',
|
'PhabricatorCacheEngine' => 'Phobject',
|
||||||
'PhabricatorCacheEngineExtension' => 'Phobject',
|
'PhabricatorCacheEngineExtension' => 'Phobject',
|
||||||
|
|
|
@ -49,13 +49,22 @@ final class PhabricatorDaemonBulkJobMonitorController
|
||||||
return id(new AphrontRedirectResponse())
|
return id(new AphrontRedirectResponse())
|
||||||
->setURI($job->getMonitorURI());
|
->setURI($job->getMonitorURI());
|
||||||
} else {
|
} else {
|
||||||
return $this->newDialog()
|
$dialog = $this->newDialog()
|
||||||
->setTitle(pht('Confirm Bulk Job'))
|
->setTitle(pht('Confirm Bulk Job'));
|
||||||
->appendParagraph($job->getDescriptionForConfirm())
|
|
||||||
|
$confirm = $job->getDescriptionForConfirm();
|
||||||
|
$confirm = (array)$confirm;
|
||||||
|
foreach ($confirm as $paragraph) {
|
||||||
|
$dialog->appendParagraph($paragraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dialog
|
||||||
->appendParagraph(
|
->appendParagraph(
|
||||||
pht('Start work on this bulk job?'))
|
pht('Start work on this bulk job?'))
|
||||||
->addCancelButton($job->getManageURI(), pht('Details'))
|
->addCancelButton($job->getManageURI(), pht('Details'))
|
||||||
->addSubmitButton(pht('Start Work'));
|
->addSubmitButton(pht('Start Work'));
|
||||||
|
|
||||||
|
return $dialog;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return $this->newDialog()
|
return $this->newDialog()
|
||||||
|
|
|
@ -12,10 +12,36 @@ final class PhabricatorEditEngineBulkJobType
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDescriptionForConfirm(PhabricatorWorkerBulkJob $job) {
|
public function getDescriptionForConfirm(PhabricatorWorkerBulkJob $job) {
|
||||||
return pht(
|
$parts = array();
|
||||||
|
|
||||||
|
$parts[] = pht(
|
||||||
'You are about to apply a bulk edit which will affect '.
|
'You are about to apply a bulk edit which will affect '.
|
||||||
'%s object(s).',
|
'%s object(s).',
|
||||||
new PhutilNumber($job->getSize()));
|
new PhutilNumber($job->getSize()));
|
||||||
|
|
||||||
|
if ($job->getIsSilent()) {
|
||||||
|
$parts[] = pht(
|
||||||
|
'If you start work now, this edit will be applied silently: it will '.
|
||||||
|
'not send mail or publish notifications.');
|
||||||
|
} else {
|
||||||
|
$parts[] = pht(
|
||||||
|
'If you start work now, this edit will send mail and publish '.
|
||||||
|
'notifications normally.');
|
||||||
|
|
||||||
|
$parts[] = pht('To silence this edit, run this command:');
|
||||||
|
|
||||||
|
$command = csprintf(
|
||||||
|
'phabricator/ $ ./bin/bulk make-silent --id %R',
|
||||||
|
$job->getID());
|
||||||
|
$command = (string)$command;
|
||||||
|
|
||||||
|
$parts[] = phutil_tag('tt', array(), $command);
|
||||||
|
|
||||||
|
$parts[] = pht(
|
||||||
|
'After running this command, reload this page to see the new setting.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getJobSize(PhabricatorWorkerBulkJob $job) {
|
public function getJobSize(PhabricatorWorkerBulkJob $job) {
|
||||||
|
@ -56,12 +82,14 @@ final class PhabricatorEditEngineBulkJobType
|
||||||
|
|
||||||
$raw_xactions = $job->getParameter('xactions');
|
$raw_xactions = $job->getParameter('xactions');
|
||||||
$xactions = $this->buildTransactions($object, $raw_xactions);
|
$xactions = $this->buildTransactions($object, $raw_xactions);
|
||||||
|
$is_silent = $job->getIsSilent();
|
||||||
|
|
||||||
$editor = $object->getApplicationTransactionEditor()
|
$editor = $object->getApplicationTransactionEditor()
|
||||||
->setActor($actor)
|
->setActor($actor)
|
||||||
->setContentSource($job->newContentSource())
|
->setContentSource($job->newContentSource())
|
||||||
->setContinueOnNoEffect(true)
|
->setContinueOnNoEffect(true)
|
||||||
->setContinueOnMissingFields(true)
|
->setContinueOnMissingFields(true)
|
||||||
|
->setIsSilent($is_silent)
|
||||||
->applyTransactions($object, $xactions);
|
->applyTransactions($object, $xactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorBulkManagementMakeSilentWorkflow
|
||||||
|
extends PhabricatorBulkManagementWorkflow {
|
||||||
|
|
||||||
|
protected function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('make-silent')
|
||||||
|
->setExamples('**make-silent** [options]')
|
||||||
|
->setSynopsis(
|
||||||
|
pht('Configure a bulk job to execute silently.'))
|
||||||
|
->setArguments(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'name' => 'id',
|
||||||
|
'param' => 'id',
|
||||||
|
'help' => pht(
|
||||||
|
'Configure bulk job __id__ to run silently (without sending '.
|
||||||
|
'mail or publishing notifications).'),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$id = $args->getArg('id');
|
||||||
|
if (!$id) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht('Use "--id" to choose a bulk job to make silent.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$job = id(new PhabricatorWorkerBulkJobQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($id))
|
||||||
|
->executeOne();
|
||||||
|
if (!$job) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Unable to load bulk job with ID "%s".',
|
||||||
|
$id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($job->getIsSilent()) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht('This job is already configured to run silently.'));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($job->getStatus() !== PhabricatorWorkerBulkJob::STATUS_CONFIRM) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Work has already started on job "%s". Jobs can not be '.
|
||||||
|
'reconfigured after they have been started.',
|
||||||
|
$id));
|
||||||
|
}
|
||||||
|
|
||||||
|
$job
|
||||||
|
->setIsSilent(true)
|
||||||
|
->save();
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Configured job "%s" to run silently.',
|
||||||
|
$id));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorBulkManagementWorkflow
|
||||||
|
extends PhabricatorManagementWorkflow {}
|
|
@ -21,6 +21,7 @@ final class PhabricatorWorkerBulkJob
|
||||||
protected $status;
|
protected $status;
|
||||||
protected $parameters = array();
|
protected $parameters = array();
|
||||||
protected $size;
|
protected $size;
|
||||||
|
protected $isSilent;
|
||||||
|
|
||||||
private $jobImplementation = self::ATTACHABLE;
|
private $jobImplementation = self::ATTACHABLE;
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ final class PhabricatorWorkerBulkJob
|
||||||
'jobTypeKey' => 'text32',
|
'jobTypeKey' => 'text32',
|
||||||
'status' => 'text32',
|
'status' => 'text32',
|
||||||
'size' => 'uint32',
|
'size' => 'uint32',
|
||||||
|
'isSilent' => 'bool',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_type' => array(
|
'key_type' => array(
|
||||||
|
@ -58,7 +60,8 @@ final class PhabricatorWorkerBulkJob
|
||||||
->setAuthorPHID($actor->getPHID())
|
->setAuthorPHID($actor->getPHID())
|
||||||
->setJobTypeKey($type->getBulkJobTypeKey())
|
->setJobTypeKey($type->getBulkJobTypeKey())
|
||||||
->setParameters($parameters)
|
->setParameters($parameters)
|
||||||
->attachJobImplementation($type);
|
->attachJobImplementation($type)
|
||||||
|
->setIsSilent(0);
|
||||||
|
|
||||||
$job->setSize($job->computeSize());
|
$job->setSize($job->computeSize());
|
||||||
|
|
||||||
|
|
|
@ -1639,6 +1639,13 @@ final class PhabricatorUSEnglishTranslation
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
'You are about to apply a bulk edit which will affect '.
|
||||||
|
'%s object(s).' => array(
|
||||||
|
'You are about to apply a bulk edit to a single object.',
|
||||||
|
'You are about to apply a bulk edit which will affect '.
|
||||||
|
'%s objects.',
|
||||||
|
),
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -584,6 +584,14 @@ final class PHUITimelineEventView extends AphrontView {
|
||||||
}
|
}
|
||||||
$extra[] = $date;
|
$extra[] = $date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this edit was applied silently, give user a hint that they should
|
||||||
|
// not expect to have received any mail or notifications.
|
||||||
|
if ($this->getIsSilent()) {
|
||||||
|
$extra[] = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-bell-slash', 'red')
|
||||||
|
->setTooltip(pht('Silent Edit'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$extra = javelin_tag(
|
$extra = javelin_tag(
|
||||||
|
|
Loading…
Reference in a new issue