feat: implement code-mappings upload command#1086
Conversation
|
| if (httpsMatch?.[1]) { | ||
| return httpsMatch[1]; | ||
| } | ||
| return null; |
There was a problem hiding this comment.
HTTPS remotes parse incorrectly
High Severity
extractRepoName tries the SCP-style SSH_REMOTE_RE before the HTTPS pattern. On typical https:// remote URLs that regex still matches (on the https: colon) and yields a path like //host/owner/repo instead of owner/repo, so auto-detected --repo values sent to the bulk API are wrong.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 2c28a26. Configure here.
| } | ||
| } | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Git inference ignores context cwd
Medium Severity
inferRepo and inferDefaultBranch invoke execSync without cwd, while org/project resolution uses this.cwd. When those differ (SDK cwd option or tests), git remote and default-branch detection can read the wrong repository or miss remotes entirely.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 2c28a26. Configure here.
c3ae7ad to
0607fae
Compare
Port the legacy `sentry-cli code-mappings upload` command. Uploads code
mappings (stack trace root → source code root) via the bulk endpoint
for enabling source context and stack trace linking in Sentry.
Key features:
- Reads a JSON file with [{stackRoot, sourceRoot}] entries
- Batches at 300 mappings per API request
- Auto-detects repository name from git remotes (upstream → origin)
- Auto-detects default branch from git remote HEAD (fallback: main)
- Reports created/updated/errors counts with per-mapping error details
- Sets process.exitCode = 1 on partial failures
- Requires org:ci scope
Files:
- src/lib/api/code-mappings.ts — bulk upload API with batching
- src/commands/code-mappings/upload.ts — command implementation
- src/commands/code-mappings/index.ts — route map
- src/app.ts — route registration
- test/commands/code-mappings/upload.test.ts — 9 tests
| const SSH_REMOTE_RE = /:(.+?)(?:\.git)?$/; | ||
| /** HTTPS remote URL pattern: https://host/path.git — captures the path after the host */ |
There was a problem hiding this comment.
Bug: The extractRepoName function's SSH regex is too broad and incorrectly matches HTTPS remotes, leading to a malformed repository name being extracted and causing API requests to fail.
Severity: HIGH
Suggested Fix
The SSH regex should be made more specific to avoid matching HTTPS URLs. For example, it could be anchored to the start of the string or require a format like git@.... Alternatively, the order of regex checks could be swapped, checking for HTTPS before SSH, as an HTTPS URL is less likely to be misidentified as an SSH URL.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/commands/code-mappings/upload.ts#L86-L87
Potential issue: The `extractRepoName` function attempts to parse a repository name from
a git remote URL. It first tries to match an SSH remote URL using the regex
`/:(.+?)(?:�.git)?$/`. However, this regex is too broad and incorrectly matches HTTPS
URLs (e.g., `https://github.com/owner/repo.git`) at the protocol's colon (`:`). This
results in an incorrect repository name like `//github.com/owner/repo` being extracted.
Because a match is found, the function returns this malformed string without ever
attempting to use the correct HTTPS regex. When `sentry code-mappings upload` is run
without an explicit `--repo` flag, this incorrect repository name is sent to the Sentry
API, causing the upload to fail.
Also affects:
src/commands/code-mappings/upload.ts:113~119
Codecov Results 📊❌ Patch coverage is 41.75%. Project has 5030 uncovered lines. Files with missing lines (2)
Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
- Coverage 81.29% 81.14% -0.15%
==========================================
Files 380 383 +3
Lines 26567 26671 +104
Branches 17295 17340 +45
==========================================
+ Hits 21596 21641 +45
- Misses 4971 5030 +59
- Partials 1794 1796 +2Generated by Codecov Action |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9df55c9. Configure here.
| return httpsMatch[1]; | ||
| } | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Duplicates existing parseRemoteUrl
Medium Severity
New extractRepoName reimplements remote URL parsing already provided by parseRemoteUrl in src/lib/git.ts, including upstream-then-origin logic that could extend getRepositoryName. The duplicate diverges in behavior and omits established URL handling.
Reviewed by Cursor Bugbot for commit 9df55c9. Configure here.
## Summary Follow-up fix for #1086 — replaces buggy custom git helpers in `code-mappings upload` with the well-tested shared helpers from `src/lib/git.ts`. ## What was broken The `SSH_REMOTE_RE` regex (`:(.+?)(?:\.git)?$`) in `upload.ts` incorrectly matched HTTPS URLs because they contain `:` (in `https:`). This produced garbage repo names: | Remote URL | Expected | Got | |-----------|----------|-----| | `https://github.com/owner/repo.git` | `owner/repo` | `//github.com/owner/repo` | | `ssh://git@github.com:22/owner/repo.git` | `owner/repo` | `//git@github.com:22/owner/repo` | The corrupted name was sent to the Sentry API as the `repository` field. ## What this fixes 1. **Buggy regex replaced** — Uses `parseRemoteUrl()` from `src/lib/git.ts` which correctly tries `new URL()` first (handles https/ssh/git protocols) and only falls back to SCP-style regex when URL parsing fails. 2. **Shell injection risk removed** — Replaced `execSync` (shell) with `execFileSync` (no shell) via the shared `git()` helper. 3. **Code consolidated** — New `inferRepositoryName()` and `inferDefaultBranch()` functions in `git.ts` replace the duplicated logic in `upload.ts`. Both use `this.cwd` for correct working directory. 4. **ASCII art dividers removed** — Per AGENTS.md prohibited comment styles, replaced `// ── Section ───` dividers with plain `// Section` in code-mappings and dart-symbol-map files. ## Files changed | File | Change | |------|--------| | `src/lib/git.ts` | Added `inferRepositoryName()` and `inferDefaultBranch()` | | `src/commands/code-mappings/upload.ts` | Removed custom git helpers, imported from git.ts | | `src/lib/api/code-mappings.ts` | Removed ASCII art dividers | | `src/commands/dart-symbol-map/upload.ts` | Removed ASCII art dividers | | `src/lib/api/dart-symbols.ts` | Removed ASCII art dividers | Net: **66 insertions, 96 deletions** (less code, more correct)


Summary
Part of #1055 — implements
sentry code-mappings upload, porting the legacy Rust sentry-cli's code-mappings upload functionality.What it does
Bulk-uploads code mappings (stack trace root → source code root) for a Sentry project. Code mappings link stack trace paths to source code paths in your repository, enabling source context, suspect commits, and stack trace linking.
Input format
JSON array of objects with
stackRootandsourceRootfields:[ { "stackRoot": "com/example/module", "sourceRoot": "modules/module/src/main/java/com/example/module" }, { "stackRoot": "com/example/other", "sourceRoot": "modules/other/src/main/java/com/example/other" } ]Features
stackRoot/sourceRootrequired, non-empty)process.exitCode = 1on partial failurePOST /organizations/{org}/code-mappings/bulk/(simple JSON, no chunk upload)org:ciscopeFlags
--repoowner/repo). Auto-detected from git remote if omitted--default-branch--jsonFiles
src/lib/api/code-mappings.tssrc/commands/code-mappings/upload.tssrc/commands/code-mappings/index.tssrc/app.tstest/commands/code-mappings/upload.test.tsTesting
9 tests covering:
stackRoot/sourceRootrejectionstackRootrejection