Skip to content

feat: add issue:fork/assign/label commands for GitLab work item bot#342

Merged
mglaman merged 2 commits into
mainfrom
feat/gitlab-slash-commands
May 20, 2026
Merged

feat: add issue:fork/assign/label commands for GitLab work item bot#342
mglaman merged 2 commits into
mainfrom
feat/gitlab-slash-commands

Conversation

@mglaman
Copy link
Copy Markdown
Owner

@mglaman mglaman commented May 20, 2026

Summary

  • Adds eight new drupalorg commands that post Drupal.org bot slash commands as comments on a GitLab work item: issue:fork, issue:get-access, issue:assign, issue:unassign, issue:reassign, issue:label, issue:unlabel, issue:relabel. Closes the gap where the CLI/skills had no programmatic way to create a fork, self-assign, or move an issue between state::* labels for projects whose queue lives at git.drupalcode.org.
  • Adds Client::postIssueNote() to the GitLab HTTP client and falls back to glab config get token --host git.drupalcode.org when DRUPALORG_GITLAB_TOKEN is unset.
  • Wires the new commands into drupalorg-work-on-issue (fork creation when missing, self-assign, hand-off label + unassign) and into the personal drupalorg-mr-review skill (verdict label).

Only applies to projects migrated to GitLab work items; classic Drupal.org issue queues are unaffected (bot is not present there).

Refs upstream docs: https://new.drupal.org/drupalorg/gitlab-custom-commands

Test plan

  • vendor/bin/phpcs src clean
  • vendor/bin/phpstan analyse src clean
  • vendor/bin/phpunit — 149 tests, 505 assertions, all green (includes new PostWorkItemSlashCommandActionTest + SlashCommandTest)
  • End-to-end smoke on a real work item project: drupalorg issue:assign ai_context#<nid>, confirm bot picks it up
  • End-to-end: drupalorg issue:fork <new-issue-ref> on an issue without a fork, then drupalorg issue:get-fork --no-cache to confirm
  • Negative: classic D.o queue NID should surface the helpful error message

🤖 Generated with Claude Code

Wraps the new Drupal.org bot slash commands (/do:fork, /do:access,
/do:assign, /do:unassign, /do:reassign, /do:label, /do:unlabel,
/do:relabel) as drupalorg-cli commands. Each posts a comment on the
target GitLab work item via the GitLab issue notes endpoint, which the
upstream bot then acts on.

Token resolution falls back to `glab config get token` when
DRUPALORG_GITLAB_TOKEN is unset.

drupalorg-work-on-issue and drupalorg-mr-review skills updated to use
the new commands at the natural workflow points (fork creation, self
assign, verdict label).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class CLI support for posting Drupal.org bot “/do:*” slash commands as comments on GitLab work items (git.drupalcode.org), along with output formatting and skill/documentation updates so higher-level workflows can create forks, assign/unassign, and manage state labels programmatically.

Changes:

  • Introduces SlashCommand builders, a PostWorkItemSlashCommandAction, and Client::postIssueNote() for posting bot commands to GitLab work items.
  • Adds eight new drupalorg issue:* CLI commands (fork/access/assign/unassign/reassign/label/unlabel/relabel) plus formatter support (md, llm) for the new result type.
  • Updates skills/docs and adds unit tests for the slash-command builder + posting action.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/src/GitLab/SlashCommandTest.php Unit tests for building /do:* command strings.
tests/src/Action/GitLab/PostWorkItemSlashCommandActionTest.php Tests for parsing refs/NIDs and posting a note via the GitLab client.
src/Cli/Formatter/MarkdownFormatter.php Adds Markdown formatting for SlashCommandResult.
src/Cli/Formatter/LlmFormatter.php Adds LLM/XML formatting for SlashCommandResult.
src/Cli/Formatter/AbstractFormatter.php Routes SlashCommandResult to formatter implementations.
src/Cli/Command/Issue/Fork.php New issue:fork command posting /do:fork.
src/Cli/Command/Issue/GetAccess.php New issue:get-access command posting /do:access.
src/Cli/Command/Issue/Assign.php New issue:assign command posting /do:assign ….
src/Cli/Command/Issue/Unassign.php New issue:unassign command posting /do:unassign ….
src/Cli/Command/Issue/Reassign.php New issue:reassign command posting /do:reassign ….
src/Cli/Command/Issue/Label.php New issue:label command posting /do:label ….
src/Cli/Command/Issue/Unlabel.php New issue:unlabel command posting /do:unlabel ….
src/Cli/Command/Issue/Relabel.php New issue:relabel command posting /do:relabel ….
src/Cli/Application.php Registers the new CLI commands.
src/Api/GitLab/SlashCommand.php Adds the /do:* command string builder/validator.
src/Api/Action/GitLab/PostWorkItemSlashCommandAction.php New action to resolve refs/NIDs and post the slash command as a note.
src/Api/Result/Issue/SlashCommandResult.php New result DTO for posted command metadata + URL.
src/Api/GitLab/Client.php Adds token fallback via glab and implements postIssueNote().
skill-data/drupalorg-work-on-issue/SKILL.md Updates workflow guidance to use the new commands for forks/assign/hand-off.
skill-data/drupalorg-cli/SKILL.md Documents the new slash-command CLI surface and auth behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +61 to +65
$ref = WorkItemRef::tryParse($refOrNid);
if ($ref !== null) {
return $ref;
}
if (!ctype_digit($refOrNid)) {
Comment on lines +49 to +50
$noteId = isset($response->id) ? (int) $response->id : 0;

Comment on lines +21 to +25
return sprintf(
'https://git.drupalcode.org/%s/-/work_items/%d',
$this->projectPath,
$this->issueIid,
);
- Trim whitespace in PostWorkItemSlashCommandAction::resolveRef so a
  bare NID copied with surrounding whitespace is still accepted.
- Throw a descriptive RuntimeException when the GitLab notes response
  is missing an id, instead of silently returning noteId=0.
- Document why SlashCommandResult::workItemUrl() always emits the
  canonical /-/work_items/ path even when a caller supplies an
  /-/issues/ URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mglaman mglaman merged commit 69ba99c into main May 20, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants