Skip to content

fix: reject NIDs that are not issues or do not exist - #368

Merged
mglaman merged 1 commit into
mainfrom
reject-non-issue-nodes
Aug 28, 2026
Merged

fix: reject NIDs that are not issues or do not exist#368
mglaman merged 1 commit into
mainfrom
reject-non-issue-nodes

Conversation

@mglaman

@mglaman mglaman commented Aug 28, 2026

Copy link
Copy Markdown
Owner

What changed

Client::getNode() now throws when the NID is not an issue or does not exist. Every issue:* and mr:* command that resolves a NID surfaces the message and exits non-zero instead of printing empty fields.

Closes #367.

Why

Drupal.org serves every node type from node/{nid}.json, and getNode() mapped all of them to IssueNode:

$ drupalorg issue:get-fork 3000001   # a project_release
GitLab path: issue/-3000001

Unknown NIDs are worse: Drupal.org answers with HTTP 200 and {"comments":[],"body":[],...}, so issue:show 999999999 printed a blank issue with exit code 0.

How

$type = $data->type ?? null;
if (!is_string($type)) {
    throw new \RuntimeException(sprintf('Node %s was not found on Drupal.org.', $nid));
}
if ($type !== 'project_issue') {
    throw new \RuntimeException(sprintf('Node %s is a %s, not an issue.', $nid, $type));
}

The check lives in Client rather than IssueNode::fromStdClass() because the entity is intentionally lenient for partial data and the API response is the boundary where type is meaningful.

tests/src/ClientTest.php is new. Client builds its own Guzzle instance, so the test subclasses it and swaps $this->client for a MockHandler-backed one; no change to the public constructor.

Testing

  • vendor/bin/phpcs src tests, vendor/bin/phpstan analyse src, vendor/bin/phpunit (167 tests) all pass.
  • Live:
    • issue:show 3000001Node 3000001 is a project_release, not an issue.
    • issue:get-fork 3060Node 3060 is a project_core, not an issue.
    • mr:list 999999999Node 999999999 was not found on Drupal.org.
    • issue:show 3383637 → unchanged

🤖 Generated with Claude Code

Client::getNode() mapped any node type to IssueNode, so a release or
project NID produced empty issue fields and fork paths like
issue/-3000001. Drupal.org also answers unknown NIDs with HTTP 200 and
a stub body, which produced the same blank output.

getNode() now throws a RuntimeException naming the NID and its actual
type, or reporting that the node was not found.

Closes #367

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mglaman
mglaman merged commit 2a3cb13 into main Aug 28, 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.

issue:* and mr:* commands accept a non-issue NID and build empty fork paths from it

1 participant