Skip to content

fix: resolve GitHub URLs with slash-based branches and multi-dot filenames#2209

Open
tdnguyenND wants to merge 1 commit into
asyncapi:masterfrom
tdnguyenND:fix/github-url-slash-branches-and-multiext
Open

fix: resolve GitHub URLs with slash-based branches and multi-dot filenames#2209
tdnguyenND wants to merge 1 commit into
asyncapi:masterfrom
tdnguyenND:fix/github-url-slash-branches-and-multiext

Conversation

@tdnguyenND
Copy link
Copy Markdown

Summary

Fixes two parsing bugs from #1940.

Bug 1 — GitHub URL with slash-based branch names

Root cause: The previous implementation used a regex with ([^\/]+) for the
branch segment, which stops at the first /. A branch like feature/my-fix
was parsed as branch=feature and path=my-fix/spec.yaml, producing an
incorrect GitHub API URL that returned 404.

Why this is genuinely hard to fix with a simple regex change:
The URL https://github.com/org/repo/blob/feature/new-validation/spec.yaml
is structurally ambiguous — you cannot tell from the URL alone where the branch
ends and the file path begins. Changing ([^\/]+) to (.+?) (as done in several
other PRs) still uses a lazy match that resolves to the shortest branch, i.e. the
same broken behaviour.

Fix: Replace convertGitHubWebUrl with generateGitHubApiCandidates, which
produces every possible branch/path split ordered from shortest branch to longest.
The read() function tries each candidate and retries only on HTTP 404. Other
errors (authentication failures, server errors) propagate immediately without
retrying. This correctly handles all branch naming conventions without any
hard-coded heuristics.

URL: https://github.com/org/repo/blob/feature/my-fix/spec.yaml
Candidates tried:
  1. /repos/org/repo/contents/my-fix/spec.yaml?ref=feature        → 404, retry
  2. /repos/org/repo/contents/spec.yaml?ref=feature/my-fix        → 200 ✓

Bonus fix: Auth headers are now populated before the candidate-retry loop,
ensuring credentials are available on all retry attempts. The original code
fetched the auth config but applied it to headers after the blob URL had been
converted — a race that was benign before this change but is now important.

Bug 2 — Wrong extension for multi-dot filenames

Root cause: name.split('.')[1] returns the second segment, which is wrong
for filenames like my.asyncapi.yaml (returns asyncapi) and crashes for
filenames without a dot (returns undefined).

Fix: path.extname(name).slice(1).toLowerCase() correctly returns the
trailing extension in all cases. path is already imported.

Test plan

  • asyncapi validate https://github.com/org/repo/blob/feature/my-fix/spec.yaml resolves correctly
  • asyncapi validate my.asyncapi.yaml no longer rejects the file
  • Existing private-ref tests pass (npm run test:unit)
  • npm run build succeeds

…names

Bug 1 (validation.service.ts): The previous regex used `([^\/]+)` for the
branch segment, which stops at the first `/`. Branch names like
`feature/my-fix` were parsed incorrectly, causing 404 errors when fetching
the file. Replace single-URL conversion with `generateGitHubApiCandidates`
that produces every possible branch/path split and retries on 404, trying
the shortest branch first (most common case). Non-404 errors (auth, server)
propagate immediately without retrying.

Also moves auth-header population before the GitHub blob URL handling so
that credentials are available on all retry attempts.

Bug 2 (SpecificationFile.ts): `name.split('.')[1]` returns the second
dot-separated segment, which is wrong for filenames like `my.asyncapi.yaml`
(returns `asyncapi` instead of `yaml`). Replace with
`path.extname(name).slice(1).toLowerCase()` which always returns the true
file extension.

Fixes asyncapi#1940

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 22, 2026

🦋 Changeset detected

Latest commit: 1ba6f86

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@asyncapi/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: To Triage

Development

Successfully merging this pull request may close these issues.

1 participant