fix(git-tools): git-cli issue/pr create reported wrong number on Gitea - #174
Open
calcorum wants to merge 1 commit into
Open
fix(git-tools): git-cli issue/pr create reported wrong number on Gitea#174calcorum wants to merge 1 commit into
calcorum wants to merge 1 commit into
Conversation
`emit_created_json` scraped the first issue/pull URL found anywhere in a create command's raw output. `tea issues create` / `tea pr create` render the whole created object — title, author, and the full body, indented — before the flush-left confirmation URL. When the body itself links to another issue in the same repo (e.g. "Child of ...St0nefish/issues/1", the normal shape for a ticket linking back to a parent), that embedded link matches the same URL pattern and appears earlier in the output, so the wrapper silently reported the linked issue's number instead of the one just created. Reproduced against a real Gitea repo: six sequential `issue create` calls, each with a body linking to issue St0nefish#1, all returned `{"number":1}` while the tracker actually assigned St0nefish#2-St0nefish#7. `pr create` shares the same normalizer and is fixed by the same change. - Anchor the primary match to a line containing nothing but the URL and take the last such match — tea's confirmation line is printed flush left with nothing else on it, while every title/body line is indented. gh's output is just the bare URL, so this is a no-op there. - Keep the old permissive "URL anywhere" scrape as a fallback (last match, not first) for any output shape the anchor doesn't recognize, so an unverified shape degrades to the old best-effort behavior instead of a hard failure on a write that already succeeded. - tests/git-cli/test-issue-write-json.sh: replace the synthetic one-line tea mocks with realistic multi-line output carrying two decoys per the design above, and confirm the suite fails against the pre-fix code and passes against the fix. - bump git-tools 2.2.1->2.2.2 and session 4.5.0->4.5.1 (both claude and copilot flavors; both vendor/reference git-cli); re-sync vendored copies Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
git-cli issue create(andpr create) against a Gitea remote reported the wrong issue/PR number and URL. The write itself always succeeded — only the JSON returned to the caller was wrong.emit_created_json()inutils/git-cli(line ~146, vendored intoplugins-claude/git-tools/scripts/git-cliandplugins-claude/session/scripts/git-cli) scraped the first.../issues/Nor.../pulls/NURL found anywhere in the create command's raw stdout.tea issues create/tea pr createdon't just print a confirmation URL — they render the whole created object first (title, author, and the full body, word-wrapped and indented two spaces), then print the real confirmation URL flush-left on its own line at the end. If the issue/PR body itself links to another issue in the same repo (extremely common — e.g. "Child of ..." for a ticket linking back to its parent), that embedded link is a URL of the exact same shape the old regex was hunting for, and it appears earlier in the output. The oldhead -n1scrape grabbed it instead of the real confirmation line.issue createcalls, each with a body linking to issue Refactor: issue-driven feature workflow (replace session files, absorb git-issues) #1, all returned{"number":1,...}while the tracker had actually assigned New: git-tools script — unified gh/tea abstraction with markdown body support and CI log access #2-feat(session): require tests and post-impl steps in plans #7. The one call that returned the correct number was the very first, creating the parent map ticket itself — its body had nothing to link to yet, so the old scrape had no decoy URL to grab and fell through correctly to the real trailing confirmation line. This isn't a coincidence that happens to fit the mechanism; it's what the mechanism predicts for that specific call.Fix
In
emit_created_json():^[[:space:]]*URL[[:space:]]*$), and take the last such match. tea's real confirmation line is reliably the only line printed flush-left with nothing else on it — every title/body line tea renders is indented, so this alone rejects a markdown-link decoy embedded mid-body. Taking the last match (not first) also correctly picks the true confirmation over a body that happens to end with a bare URL on its own line (e.g. a "See also " reference) — that shape does match the anchor, so only last-match position tells it apart.tea/gh), fall back to the old permissive "URL anywhere" scrape — but still take the last match, never the first. This keeps an unrecognized shape degrading to old best-effort behavior rather than a harddieon a write that already succeeded, which would be worse than the original bug.gh's output is just the bare URL with nothing else, so both paths are a no-op there — GitHub was never affected.pr createnormalizes through the sameemit_created_json()function for both platforms, so it shared the exact defect and is fixed by the same change. I did not independently observe realtea pr createoutput (creating a throwaway PR wasn't in scope for this fix) —tea's ownprintpackage sourcesIssueDetails/PullDetailsfrom the same table/markdown renderer (confirmed viastringson theteabinary), so the rendering shape should match, but this is inference rather than direct observation. The fallback path exists specifically so that if this inference is wrong, the wrapper degrades safely instead of breakingpr createoutright.Verification
tea issues createand captured its raw output — confirmed the body is rendered indented, before a flush-left confirmation URL.#1while the new one correctly grabs the created object's real number.utils/sync.sh) and confirmed correct output on: the real captured tea output, the simulated body-links-to-parent case, a decoy where the body itself ends with a bare URL on its own line, and the fallback path (URL only ever inline in prose, decoy first).cal/quasimorph-custom-clone-names(titledTEST — git-cli issue number repro (safe to close)) to establish ground truth for realteaoutput — both closed immediately after reading the result. Did not touch any of the repo's 12 existing real issues.tests/git-cli/test-issue-write-json.sh: replaced the suite's synthetic one-line tea mocks forissues create/pr createwith realistic multi-line output carrying two decoys (a markdown-link-in-body and a bare-URL body line). Confirmed this test fails against the pre-fix code (gitea issue createandgitea pr createboth report#1) and passes against the fix.tests/test.sh, 30 suites). Allgit-cli/git-tools/sessionsuites pass — including the threetests/session/*suites that referenceutils/git-cli(test-ci-poll.sh,test-pr-wait.sh,test-pr-auto-merge-status.sh), re-run at the final committed state. One pre-existing, unrelated failure inpermission-manager/test-classify(9 assertions): verified independently in a throwawaygit worktreechecked out at unmodifiedorigin/master— same 9 failures, so it's confirmed unrelated to this branch, not merely inferred from an unchanged-files argument.utils/sync.sh --checkand the repo's.githooks/pre-commitboth pass — vendored copies (git-tools,session) are in sync with canonicalutils/git-cli.git-tools2.2.1 → 2.2.2 andsession4.5.0 → 4.5.1 in bothplugins-claudeandplugins-copilot, matching the versioning convention used by priorgit-clibugfix commits (e.g.bc95efd,f52d049,45f84a4).Test plan
bash tests/test.sh— full suite, expect only the pre-existingpermission-manager/test-classifyfailurebash tests/git-cli/test-issue-write-json.sh— 18/18 pass