1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 08:12:40 +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:
epriestley 2013-11-13 11:26:05 -08:00
parent 626b3dab3b
commit f5ca647d2c
5 changed files with 128 additions and 1 deletions

View file

@ -18,6 +18,7 @@ $args->parseStandardArguments();
$workflows = array(
new PhabricatorRepositoryManagementPullWorkflow(),
new PhabricatorRepositoryManagementDiscoverWorkflow(),
new PhabricatorRepositoryManagementEditWorkflow(),
new PhabricatorRepositoryManagementListWorkflow(),
new PhabricatorRepositoryManagementDeleteWorkflow(),
new PhabricatorRepositoryManagementMarkImportedWorkflow(),

View file

@ -1731,6 +1731,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryListController' => 'applications/repository/controller/PhabricatorRepositoryListController.php',
'PhabricatorRepositoryManagementDeleteWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDeleteWorkflow.php',
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php',
'PhabricatorRepositoryManagementEditWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementEditWorkflow.php',
'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php',
'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php',
'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkImportedWorkflow.php',
@ -4174,6 +4175,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryListController' => 'PhabricatorRepositoryController',
'PhabricatorRepositoryManagementDeleteWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementEditWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'PhabricatorRepositoryManagementWorkflow',

View file

@ -9,6 +9,7 @@ final class PhabricatorContentSource {
const SOURCE_MOBILE = 'mobile';
const SOURCE_TABLET = 'tablet';
const SOURCE_FAX = 'fax';
const SOURCE_CONSOLE = 'console';
const SOURCE_LEGACY = 'legacy';
private $source;
@ -39,6 +40,12 @@ final class PhabricatorContentSource {
return $obj;
}
public static function newConsoleSource() {
return self::newForSource(
PhabricatorContentSource::SOURCE_CONSOLE,
array());
}
public static function newFromRequest(AphrontRequest $request) {
return self::newForSource(
PhabricatorContentSource::SOURCE_WEB,
@ -61,6 +68,7 @@ final class PhabricatorContentSource {
self::SOURCE_MOBILE => pht('Mobile'),
self::SOURCE_TABLET => pht('Tablet'),
self::SOURCE_FAX => pht('Fax'),
self::SOURCE_CONSOLE => pht('Console'),
self::SOURCE_LEGACY => pht('Legacy'),
self::SOURCE_UNKNOWN => pht('Other'),
);

View file

@ -14,6 +14,10 @@ final class PhabricatorRepositoryManagementDeleteWorkflow
'name' => 'verbose',
'help' => 'Show additional debugging information.',
),
array(
'name' => 'force',
'help' => 'Do not prompt for confirmation.',
),
array(
'name' => 'repos',
'wildcard' => true,
@ -30,9 +34,25 @@ final class PhabricatorRepositoryManagementDeleteWorkflow
}
$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) {
$console->writeOut("Deleting '%s'...\n", $repo->getCallsign());
$repo->delete();
}

View file

@ -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;
}
}