From 13f9ba0bb047e7c8f97dda5cdace88c5f586ea4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=C4=9Bzslav=20Dvo=C5=99=C3=A1k?= Date: Wed, 12 Aug 2026 12:45:38 +0200 Subject: [PATCH] Add run-template:clone command Mirrors the web UI's clone action: copies a run template's config, saved env values, and credential assignments into a new run template via RunTemplate::cloneAs() (core). The clone is always created disabled, so a copied config can't be picked up by the scheduler before it's reviewed. Co-Authored-By: Claude Sonnet 5 --- src/Command/RunTemplate/CloneCommand.php | 85 ++++++++++++++++++++++++ src/multiflexi-cli.php | 2 + 2 files changed, 87 insertions(+) create mode 100644 src/Command/RunTemplate/CloneCommand.php diff --git a/src/Command/RunTemplate/CloneCommand.php b/src/Command/RunTemplate/CloneCommand.php new file mode 100644 index 0000000..1c6aa92 --- /dev/null +++ b/src/Command/RunTemplate/CloneCommand.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace MultiFlexi\Cli\Command\RunTemplate; + +use MultiFlexi\RunTemplate; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class CloneCommand extends BaseCommand +{ + protected static $defaultName = 'run-template:clone'; + + protected function configure(): void + { + $this + ->setName('run-template:clone') + ->setDescription('Clone a run template; the clone is always created disabled') + ->addOption('format', 'f', InputOption::VALUE_OPTIONAL, 'Output format: text or json', 'text') + ->addOption('id', null, InputOption::VALUE_REQUIRED, 'Source RunTemplate ID') + ->addOption('name', null, InputOption::VALUE_OPTIONAL, 'Name for the clone (default: " Clone")'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $format = strtolower($input->getOption('format')); + $id = $input->getOption('id'); + + if (empty($id)) { + if ($format === 'json') { + $output->writeln(json_encode(['status' => 'error', 'message' => 'Missing --id'], \JSON_PRETTY_PRINT)); + } else { + $output->writeln('Missing --id'); + } + + return self::FAILURE; + } + + $source = new RunTemplate((int) $id); + + if (empty($source->getMyKey())) { + if ($format === 'json') { + $output->writeln(json_encode(['status' => 'error', 'message' => 'RunTemplate not found'], \JSON_PRETTY_PRINT)); + } else { + $output->writeln('RunTemplate not found: '.$id.''); + } + + return self::FAILURE; + } + + $newName = $input->getOption('name') ?: $source->getRecordName().' '._('Clone'); + $newId = $source->cloneAs($newName); + + if (!$newId) { + if ($format === 'json') { + $output->writeln(json_encode(['status' => 'error', 'message' => 'Failed to create clone'], \JSON_PRETTY_PRINT)); + } else { + $output->writeln('Failed to create clone'); + } + + return self::FAILURE; + } + + if ($format === 'json') { + $output->writeln(json_encode(['runtemplate_id' => $newId, 'name' => $newName, 'active' => false], \JSON_PRETTY_PRINT)); + } else { + $output->writeln("RunTemplate cloned as ID: {$newId} (disabled — review and enable when ready)"); + } + + return self::SUCCESS; + } +} diff --git a/src/multiflexi-cli.php b/src/multiflexi-cli.php index 6a0634b..e38e091 100755 --- a/src/multiflexi-cli.php +++ b/src/multiflexi-cli.php @@ -89,6 +89,7 @@ use MultiFlexi\Cli\Command\Queue\OverviewCommand as QueueOverviewCommand; use MultiFlexi\Cli\Command\Queue\TruncateCommand as QueueTruncateCommand; use MultiFlexi\Cli\Command\RunTemplate\AssignCredentialCommand as RunTemplateAssignCredentialCommand; +use MultiFlexi\Cli\Command\RunTemplate\CloneCommand as RunTemplateCloneCommand; use MultiFlexi\Cli\Command\RunTemplate\CreateCommand as RunTemplateCreateCommand; use MultiFlexi\Cli\Command\RunTemplate\DeleteCommand as RunTemplateDeleteCommand; use MultiFlexi\Cli\Command\RunTemplate\GetCommand as RunTemplateGetCommand; @@ -254,6 +255,7 @@ ConsoleCompat::addCommand($application, new RunTemplateListCommand()); ConsoleCompat::addCommand($application, new RunTemplateGetCommand()); ConsoleCompat::addCommand($application, new RunTemplateCreateCommand()); +ConsoleCompat::addCommand($application, new RunTemplateCloneCommand()); ConsoleCompat::addCommand($application, new RunTemplateUpdateCommand()); ConsoleCompat::addCommand($application, new RunTemplateDeleteCommand()); ConsoleCompat::addCommand($application, new RunTemplateScheduleCommand());