From ef4bea7a786376e0b64e783bd7004e5ef1662665 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 24 Mar 2026 23:21:25 +0000
Subject: [PATCH 1/2] Initial plan
From 5b3d6bc784ed035a9bc36da410b248269a8e664e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 24 Mar 2026 23:33:01 +0000
Subject: [PATCH 2/2] Make mr-iid optional: auto-select single MR or prompt
interactively
Co-authored-by: mglaman <3698644+mglaman@users.noreply.github.com>
Agent-Logs-Url: https://github.com/mglaman/drupalorg-cli/sessions/dbee614d-7c46-457f-be68-7bc9979c9b16
---
.../Command/MergeRequest/MrCommandBase.php | 52 +++++++++++++++++--
.../MergeRequest/MrCommandBaseTest.php | 50 ++++++++++++++++++
2 files changed, 99 insertions(+), 3 deletions(-)
create mode 100644 tests/src/Command/MergeRequest/MrCommandBaseTest.php
diff --git a/src/Cli/Command/MergeRequest/MrCommandBase.php b/src/Cli/Command/MergeRequest/MrCommandBase.php
index 63ff407..69b3327 100644
--- a/src/Cli/Command/MergeRequest/MrCommandBase.php
+++ b/src/Cli/Command/MergeRequest/MrCommandBase.php
@@ -2,12 +2,17 @@
namespace mglaman\DrupalOrgCli\Command\MergeRequest;
+use mglaman\DrupalOrg\Action\MergeRequest\ListMergeRequestsAction;
+use mglaman\DrupalOrg\Enum\MergeRequestState;
+use mglaman\DrupalOrg\GitLab\Client as GitLabClient;
use mglaman\DrupalOrg\GitLab\MergeRequestRef;
+use mglaman\DrupalOrg\Result\MergeRequest\MergeRequestItem;
use mglaman\DrupalOrgCli\Command\Command;
use mglaman\DrupalOrgCli\Command\Issue\IssueCommandBase;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\ChoiceQuestion;
abstract class MrCommandBase extends IssueCommandBase
{
@@ -50,9 +55,50 @@ protected function initialize(InputInterface $input, OutputInterface $output): v
parent::initialize($input, $output);
$mrIid = $this->stdIn->getArgument('mr-iid');
- if ($mrIid === null || $mrIid === '') {
- throw new \RuntimeException('Argument mr-iid is required.');
+ if ($mrIid !== null && $mrIid !== '') {
+ $this->mrIid = (int) $mrIid;
+ return;
+ }
+
+ // mr-iid not provided — auto-select from open merge requests.
+ $listAction = new ListMergeRequestsAction($this->client, new GitLabClient());
+ $listResult = $listAction($this->nid, MergeRequestState::Opened);
+ $mergeRequests = $listResult->mergeRequests;
+
+ if ($mergeRequests === []) {
+ throw new \RuntimeException('No open merge requests found for this issue.');
+ }
+
+ if (count($mergeRequests) === 1) {
+ $this->mrIid = $mergeRequests[0]->iid;
+ $this->stdOut->writeln(sprintf(
+ 'Auto-selected MR !%d: %s',
+ $mergeRequests[0]->iid,
+ $mergeRequests[0]->title
+ ));
+ return;
+ }
+
+ // Multiple open MRs.
+ if (!self::$interactive) {
+ $this->stdErr->writeln('Multiple open merge requests found. Specify one of:');
+ foreach ($mergeRequests as $mr) {
+ $this->stdErr->writeln(sprintf(' !%d — %s', $mr->iid, $mr->title));
+ }
+ throw new \RuntimeException('Argument mr-iid is required when multiple merge requests are open.');
+ }
+
+ $choices = array_map(
+ static fn(MergeRequestItem $mr) => sprintf('!%d — %s', $mr->iid, $mr->title),
+ $mergeRequests
+ );
+ /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
+ $helper = $this->getHelper('question');
+ $question = new ChoiceQuestion('Select a merge request:', $choices);
+ $selected = (string) $helper->ask($input, $output, $question);
+ if (!preg_match('/^!(\d+)/', $selected, $matches)) {
+ throw new \RuntimeException('Failed to extract merge request IID from selection.');
}
- $this->mrIid = (int) $mrIid;
+ $this->mrIid = (int) $matches[1];
}
}
diff --git a/tests/src/Command/MergeRequest/MrCommandBaseTest.php b/tests/src/Command/MergeRequest/MrCommandBaseTest.php
new file mode 100644
index 0000000..90033c7
--- /dev/null
+++ b/tests/src/Command/MergeRequest/MrCommandBaseTest.php
@@ -0,0 +1,50 @@
+configureNidAndMrIid();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ return 0;
+ }
+ };
+ self::assertInstanceOf(MrCommandBase::class, $command);
+ }
+
+ public function testConfigureNidAndMrIidAddsArguments(): void
+ {
+ $command = new class ('test:mr-command') extends MrCommandBase {
+ protected function configure(): void
+ {
+ $this->configureNidAndMrIid();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ return 0;
+ }
+ };
+
+ $definition = $command->getDefinition();
+ self::assertTrue($definition->hasArgument('nid'));
+ self::assertTrue($definition->hasArgument('mr-iid'));
+ self::assertFalse($definition->getArgument('nid')->isRequired());
+ self::assertFalse($definition->getArgument('mr-iid')->isRequired());
+ }
+}