mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 00:32:42 +01:00
Add bin/repository edit
for CLI repository editing
Summary: Ref T4039. This is mostly to deal with that, to prevent the security issues associated with mutable local paths. The next diff will lock them in the web UI. I also added a confirmation prompt to `bin/repository delete`, which was a little scary without one. See one comment inline about the `--as` flag. I don't love this, but when I started adding all the stuff we'd need to let this transaction show up as "Administrator" it quickly got pretty big. Test Plan: Ran `bin/repository edit ...`, saw an edit with a transaction show up on the web UI. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T4039 Differential Revision: https://secure.phabricator.com/D7579
This commit is contained in:
parent
626b3dab3b
commit
f5ca647d2c
5 changed files with 128 additions and 1 deletions
|
@ -18,6 +18,7 @@ $args->parseStandardArguments();
|
||||||
$workflows = array(
|
$workflows = array(
|
||||||
new PhabricatorRepositoryManagementPullWorkflow(),
|
new PhabricatorRepositoryManagementPullWorkflow(),
|
||||||
new PhabricatorRepositoryManagementDiscoverWorkflow(),
|
new PhabricatorRepositoryManagementDiscoverWorkflow(),
|
||||||
|
new PhabricatorRepositoryManagementEditWorkflow(),
|
||||||
new PhabricatorRepositoryManagementListWorkflow(),
|
new PhabricatorRepositoryManagementListWorkflow(),
|
||||||
new PhabricatorRepositoryManagementDeleteWorkflow(),
|
new PhabricatorRepositoryManagementDeleteWorkflow(),
|
||||||
new PhabricatorRepositoryManagementMarkImportedWorkflow(),
|
new PhabricatorRepositoryManagementMarkImportedWorkflow(),
|
||||||
|
|
|
@ -1731,6 +1731,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryListController' => 'applications/repository/controller/PhabricatorRepositoryListController.php',
|
'PhabricatorRepositoryListController' => 'applications/repository/controller/PhabricatorRepositoryListController.php',
|
||||||
'PhabricatorRepositoryManagementDeleteWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDeleteWorkflow.php',
|
'PhabricatorRepositoryManagementDeleteWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDeleteWorkflow.php',
|
||||||
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php',
|
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php',
|
||||||
|
'PhabricatorRepositoryManagementEditWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementEditWorkflow.php',
|
||||||
'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php',
|
'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php',
|
||||||
'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php',
|
'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php',
|
||||||
'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkImportedWorkflow.php',
|
'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkImportedWorkflow.php',
|
||||||
|
@ -4174,6 +4175,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryListController' => 'PhabricatorRepositoryController',
|
'PhabricatorRepositoryListController' => 'PhabricatorRepositoryController',
|
||||||
'PhabricatorRepositoryManagementDeleteWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementDeleteWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
|
'PhabricatorRepositoryManagementEditWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||||
|
|
|
@ -9,6 +9,7 @@ final class PhabricatorContentSource {
|
||||||
const SOURCE_MOBILE = 'mobile';
|
const SOURCE_MOBILE = 'mobile';
|
||||||
const SOURCE_TABLET = 'tablet';
|
const SOURCE_TABLET = 'tablet';
|
||||||
const SOURCE_FAX = 'fax';
|
const SOURCE_FAX = 'fax';
|
||||||
|
const SOURCE_CONSOLE = 'console';
|
||||||
const SOURCE_LEGACY = 'legacy';
|
const SOURCE_LEGACY = 'legacy';
|
||||||
|
|
||||||
private $source;
|
private $source;
|
||||||
|
@ -39,6 +40,12 @@ final class PhabricatorContentSource {
|
||||||
return $obj;
|
return $obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function newConsoleSource() {
|
||||||
|
return self::newForSource(
|
||||||
|
PhabricatorContentSource::SOURCE_CONSOLE,
|
||||||
|
array());
|
||||||
|
}
|
||||||
|
|
||||||
public static function newFromRequest(AphrontRequest $request) {
|
public static function newFromRequest(AphrontRequest $request) {
|
||||||
return self::newForSource(
|
return self::newForSource(
|
||||||
PhabricatorContentSource::SOURCE_WEB,
|
PhabricatorContentSource::SOURCE_WEB,
|
||||||
|
@ -61,6 +68,7 @@ final class PhabricatorContentSource {
|
||||||
self::SOURCE_MOBILE => pht('Mobile'),
|
self::SOURCE_MOBILE => pht('Mobile'),
|
||||||
self::SOURCE_TABLET => pht('Tablet'),
|
self::SOURCE_TABLET => pht('Tablet'),
|
||||||
self::SOURCE_FAX => pht('Fax'),
|
self::SOURCE_FAX => pht('Fax'),
|
||||||
|
self::SOURCE_CONSOLE => pht('Console'),
|
||||||
self::SOURCE_LEGACY => pht('Legacy'),
|
self::SOURCE_LEGACY => pht('Legacy'),
|
||||||
self::SOURCE_UNKNOWN => pht('Other'),
|
self::SOURCE_UNKNOWN => pht('Other'),
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,6 +14,10 @@ final class PhabricatorRepositoryManagementDeleteWorkflow
|
||||||
'name' => 'verbose',
|
'name' => 'verbose',
|
||||||
'help' => 'Show additional debugging information.',
|
'help' => 'Show additional debugging information.',
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'force',
|
||||||
|
'help' => 'Do not prompt for confirmation.',
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'name' => 'repos',
|
'name' => 'repos',
|
||||||
'wildcard' => true,
|
'wildcard' => true,
|
||||||
|
@ -30,9 +34,25 @@ final class PhabricatorRepositoryManagementDeleteWorkflow
|
||||||
}
|
}
|
||||||
|
|
||||||
$console = PhutilConsole::getConsole();
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
|
if (!$args->getArg('force')) {
|
||||||
|
$console->writeOut("%s\n\n", pht('These repositories will be deleted:'));
|
||||||
|
|
||||||
|
foreach ($repos as $repo) {
|
||||||
|
$console->writeOut(
|
||||||
|
" %s %s\n",
|
||||||
|
'r'.$repo->getCallsign(),
|
||||||
|
$repo->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
$prompt = pht('Permanently delete these repositories?');
|
||||||
|
if (!$console->confirm($prompt)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($repos as $repo) {
|
foreach ($repos as $repo) {
|
||||||
$console->writeOut("Deleting '%s'...\n", $repo->getCallsign());
|
$console->writeOut("Deleting '%s'...\n", $repo->getCallsign());
|
||||||
|
|
||||||
$repo->delete();
|
$repo->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorRepositoryManagementEditWorkflow
|
||||||
|
extends PhabricatorRepositoryManagementWorkflow {
|
||||||
|
|
||||||
|
public function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('edit')
|
||||||
|
->setExamples('**edit** --as __username__ __repository__ ...')
|
||||||
|
->setSynopsis('Edit __repository__, named by callsign.')
|
||||||
|
->setArguments(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'name' => 'repos',
|
||||||
|
'wildcard' => true,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'as',
|
||||||
|
'param' => 'user',
|
||||||
|
'help' => 'Edit as user.',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'local-path',
|
||||||
|
'param' => 'path',
|
||||||
|
'help' => 'Edit the local path.',
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$repos = $this->loadRepositories($args, 'repos');
|
||||||
|
|
||||||
|
if (!$repos) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Specify one or more repositories to edit, by callsign.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
|
// TODO: It would be nice to just take this action as "Administrator" or
|
||||||
|
// similar, since that would make it easier to use this script, harder to
|
||||||
|
// impersonate users, and more clear to viewers what happened. However,
|
||||||
|
// the omnipotent user doesn't have a PHID right now, can't be loaded,
|
||||||
|
// doesn't have a handle, etc. Adding all of that is fairly involved, and
|
||||||
|
// I want to wait for stronger use cases first.
|
||||||
|
|
||||||
|
$username = $args->getArg('as');
|
||||||
|
if (!$username) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht("Specify a user to edit as with --as <username>."));
|
||||||
|
}
|
||||||
|
|
||||||
|
$actor = id(new PhabricatorPeopleQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withUsernames(array($username))
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
if (!$actor) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht("No such user '%s'!", $username));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($repos as $repo) {
|
||||||
|
$console->writeOut("Editing '%s'...\n", $repo->getCallsign());
|
||||||
|
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$type_local_path = PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH;
|
||||||
|
|
||||||
|
if ($args->getArg('local-path')) {
|
||||||
|
$xactions[] = id(new PhabricatorRepositoryTransaction())
|
||||||
|
->setTransactionType($type_local_path)
|
||||||
|
->setNewValue($args->getArg('local-path'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$xactions) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht("Specify one or more fields to edit!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$content_source = PhabricatorContentSource::newConsoleSource();
|
||||||
|
|
||||||
|
$editor = id(new PhabricatorRepositoryEditor())
|
||||||
|
->setActor($actor)
|
||||||
|
->setContentSource($content_source)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->applyTransactions($repo, $xactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
$console->writeOut("Done.\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue