Skip to content

Commit d893c9d

Browse files
romtsnclaude
andauthored
feat(code-mappings): Add code-mappings upload command scaffold (#3207)
_#skip-changelog_ Add the `sentry-cli code-mappings upload` subcommand group and the `upload` subcommand with file parsing and validation. This is the first in a stack of 4 PRs to support bulk uploading code mappings from a JSON file — useful for Java/Android multi-module projects that need dozens of mappings. This PR adds: - Command scaffold following the `repos`/`deploys` pattern - JSON file reading and validation (empty arrays, empty stackRoot/sourceRoot) - CLI args: positional `PATH`, `--repo`, `--default-branch` - Help and no-subcommand trycmd integration tests Stack: **#3207** → #3208#3209#3210 Backend PRs: getsentry/sentry#109783, getsentry/sentry#109785, getsentry/sentry#109786 Closes getsentry/sentry-android-gradle-plugin#1076 Closes getsentry/sentry-android-gradle-plugin#1077 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d700ba3 commit d893c9d

10 files changed

Lines changed: 217 additions & 0 deletions

File tree

src/commands/code_mappings/mod.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use anyhow::Result;
2+
use clap::{ArgMatches, Command};
3+
4+
use crate::utils::args::ArgExt as _;
5+
6+
pub mod upload;
7+
8+
macro_rules! each_subcommand {
9+
($mac:ident) => {
10+
$mac!(upload);
11+
};
12+
}
13+
14+
pub fn make_command(mut command: Command) -> Command {
15+
macro_rules! add_subcommand {
16+
($name:ident) => {{
17+
command = command.subcommand(crate::commands::code_mappings::$name::make_command(
18+
Command::new(stringify!($name).replace('_', "-")),
19+
));
20+
}};
21+
}
22+
23+
command = command
24+
.about("Manage code mappings for Sentry. Code mappings link stack trace paths to source code paths in your repository, enabling source context and code linking in Sentry.")
25+
.subcommand_required(true)
26+
.arg_required_else_help(true)
27+
.org_arg()
28+
.project_arg(false);
29+
each_subcommand!(add_subcommand);
30+
command
31+
}
32+
33+
pub fn execute(matches: &ArgMatches) -> Result<()> {
34+
macro_rules! execute_subcommand {
35+
($name:ident) => {{
36+
if let Some(sub_matches) =
37+
matches.subcommand_matches(&stringify!($name).replace('_', "-"))
38+
{
39+
return crate::commands::code_mappings::$name::execute(&sub_matches);
40+
}
41+
}};
42+
}
43+
each_subcommand!(execute_subcommand);
44+
unreachable!();
45+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use std::fs;
2+
3+
use anyhow::{bail, Context as _, Result};
4+
use clap::{Arg, ArgMatches, Command};
5+
use serde::Deserialize;
6+
7+
#[derive(Debug, Deserialize)]
8+
#[serde(rename_all = "camelCase")]
9+
struct CodeMapping {
10+
stack_root: String,
11+
source_root: String,
12+
}
13+
14+
pub fn make_command(command: Command) -> Command {
15+
command
16+
.about("Upload code mappings for a project from a JSON file. Each mapping pairs a stack trace root (e.g. com/example/module) with the corresponding source path in your repository (e.g. modules/module/src/main/java/com/example/module).")
17+
.arg(
18+
Arg::new("path")
19+
.value_name("PATH")
20+
.required(true)
21+
.help("Path to a JSON file containing code mappings."),
22+
)
23+
.arg(
24+
Arg::new("repo")
25+
.long("repo")
26+
.value_name("REPO")
27+
.help("The repository name (e.g. owner/repo). Defaults to the git remote."),
28+
)
29+
.arg(
30+
Arg::new("default_branch")
31+
.long("default-branch")
32+
.value_name("BRANCH")
33+
.default_value("main")
34+
.help("The default branch name."),
35+
)
36+
}
37+
38+
pub fn execute(matches: &ArgMatches) -> Result<()> {
39+
let path = matches
40+
.get_one::<String>("path")
41+
.expect("path is a required argument");
42+
let data = fs::read(path).with_context(|| format!("Failed to read mappings file '{path}'"))?;
43+
44+
let mappings: Vec<CodeMapping> =
45+
serde_json::from_slice(&data).context("Failed to parse mappings JSON")?;
46+
47+
if mappings.is_empty() {
48+
bail!("Mappings file contains an empty array. Nothing to upload.");
49+
}
50+
51+
for (i, mapping) in mappings.iter().enumerate() {
52+
if mapping.stack_root.is_empty() {
53+
bail!("Mapping at index {i} has an empty stackRoot.");
54+
}
55+
if mapping.source_root.is_empty() {
56+
bail!("Mapping at index {i} has an empty sourceRoot.");
57+
}
58+
}
59+
60+
println!("Found {} code mapping(s) in {path}", mappings.len());
61+
62+
Ok(())
63+
}

src/commands/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::utils::value_parsers::auth_token_parser;
2121

2222
mod bash_hook;
2323
mod build;
24+
mod code_mappings;
2425
mod dart_symbol_map;
2526
mod debug_files;
2627
mod deploys;
@@ -52,6 +53,7 @@ macro_rules! each_subcommand {
5253
($mac:ident) => {
5354
$mac!(bash_hook);
5455
$mac!(build);
56+
$mac!(code_mappings);
5557
$mac!(debug_files);
5658
$mac!(deploys);
5759
$mac!(events);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
```
2+
$ sentry-cli code-mappings --help
3+
? success
4+
Manage code mappings for Sentry. Code mappings link stack trace paths to source code paths in your
5+
repository, enabling source context and code linking in Sentry.
6+
7+
Usage: sentry-cli[EXE] code-mappings [OPTIONS] <COMMAND>
8+
9+
Commands:
10+
upload Upload code mappings for a project from a JSON file. Each mapping pairs a stack trace root
11+
(e.g. com/example/module) with the corresponding source path in your repository (e.g.
12+
modules/module/src/main/java/com/example/module).
13+
help Print this message or the help of the given subcommand(s)
14+
15+
Options:
16+
-o, --org <ORG> The organization ID or slug.
17+
--header <KEY:VALUE> Custom headers that should be attached to all requests
18+
in key:value format.
19+
-p, --project <PROJECT> The project ID or slug.
20+
--auth-token <AUTH_TOKEN> Use the given Sentry auth token.
21+
--log-level <LOG_LEVEL> Set the log output verbosity. [possible values: trace, debug, info,
22+
warn, error]
23+
--quiet Do not print any output while preserving correct exit code. This
24+
flag is currently implemented only for selected subcommands.
25+
[aliases: --silent]
26+
-h, --help Print help
27+
28+
```
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
```
2+
$ sentry-cli code-mappings
3+
? failed
4+
Manage code mappings for Sentry. Code mappings link stack trace paths to source code paths in your
5+
repository, enabling source context and code linking in Sentry.
6+
7+
Usage: sentry-cli[EXE] code-mappings [OPTIONS] <COMMAND>
8+
9+
Commands:
10+
upload Upload code mappings for a project from a JSON file. Each mapping pairs a stack trace root
11+
(e.g. com/example/module) with the corresponding source path in your repository (e.g.
12+
modules/module/src/main/java/com/example/module).
13+
help Print this message or the help of the given subcommand(s)
14+
15+
Options:
16+
-o, --org <ORG> The organization ID or slug.
17+
--header <KEY:VALUE> Custom headers that should be attached to all requests
18+
in key:value format.
19+
-p, --project <PROJECT> The project ID or slug.
20+
--auth-token <AUTH_TOKEN> Use the given Sentry auth token.
21+
--log-level <LOG_LEVEL> Set the log output verbosity. [possible values: trace, debug, info,
22+
warn, error]
23+
--quiet Do not print any output while preserving correct exit code. This
24+
flag is currently implemented only for selected subcommands.
25+
[aliases: --silent]
26+
-h, --help Print help
27+
28+
```
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
```
2+
$ sentry-cli code-mappings upload --help
3+
? success
4+
Upload code mappings for a project from a JSON file. Each mapping pairs a stack trace root (e.g.
5+
com/example/module) with the corresponding source path in your repository (e.g.
6+
modules/module/src/main/java/com/example/module).
7+
8+
Usage: sentry-cli[EXE] code-mappings upload [OPTIONS] <PATH>
9+
10+
Arguments:
11+
<PATH> Path to a JSON file containing code mappings.
12+
13+
Options:
14+
-o, --org <ORG> The organization ID or slug.
15+
--repo <REPO> The repository name (e.g. owner/repo). Defaults to the git remote.
16+
--default-branch <BRANCH> The default branch name. [default: main]
17+
--header <KEY:VALUE> Custom headers that should be attached to all requests
18+
in key:value format.
19+
-p, --project <PROJECT> The project ID or slug.
20+
--auth-token <AUTH_TOKEN> Use the given Sentry auth token.
21+
--log-level <LOG_LEVEL> Set the log output verbosity. [possible values: trace, debug, info,
22+
warn, error]
23+
--quiet Do not print any output while preserving correct exit code. This
24+
flag is currently implemented only for selected subcommands.
25+
[aliases: --silent]
26+
-h, --help Print help
27+
28+
```

tests/integration/_cases/help/help-windows.trycmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ Usage: sentry-cli[EXE] [OPTIONS] <COMMAND>
1212
Commands:
1313
completions Generate completions for the specified shell.
1414
build Manage builds.
15+
code-mappings Manage code mappings for Sentry. Code mappings link stack trace paths to source
16+
code paths in your repository, enabling source context and code linking in
17+
Sentry.
1518
debug-files Locate, analyze or upload debug information files. [aliases: dif]
1619
deploys Manage deployments for Sentry releases.
1720
events Manage events on Sentry.

tests/integration/_cases/help/help.trycmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ Usage: sentry-cli[EXE] [OPTIONS] <COMMAND>
1212
Commands:
1313
completions Generate completions for the specified shell.
1414
build Manage builds.
15+
code-mappings Manage code mappings for Sentry. Code mappings link stack trace paths to source
16+
code paths in your repository, enabling source context and code linking in
17+
Sentry.
1518
debug-files Locate, analyze or upload debug information files. [aliases: dif]
1619
deploys Manage deployments for Sentry releases.
1720
events Manage events on Sentry.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use crate::integration::TestManager;
2+
3+
#[test]
4+
fn command_code_mappings_help() {
5+
TestManager::new().register_trycmd_test("code_mappings/code-mappings-help.trycmd");
6+
}
7+
8+
#[test]
9+
fn command_code_mappings_no_subcommand() {
10+
TestManager::new().register_trycmd_test("code_mappings/code-mappings-no-subcommand.trycmd");
11+
}
12+
13+
#[test]
14+
fn command_code_mappings_upload_help() {
15+
TestManager::new().register_trycmd_test("code_mappings/code-mappings-upload-help.trycmd");
16+
}

tests/integration/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod bash_hook;
22
mod build;
3+
mod code_mappings;
34
mod debug_files;
45
mod deploys;
56
mod events;

0 commit comments

Comments
 (0)