From 029aeaf330652dc5896e5784c4648862b1770814 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 11 Mar 2026 23:04:18 +0100 Subject: [PATCH 1/6] feat(cli): Add `code-mappings upload` command scaffold with file parsing Add a new `code-mappings` subcommand group with an `upload` subcommand that reads and validates a JSON file of code mappings. This is the first step toward CLI support for bulk code mapping uploads to Sentry. --- src/commands/code_mappings/mod.rs | 45 ++++++++++++++ src/commands/code_mappings/upload.rs | 62 +++++++++++++++++++ src/commands/mod.rs | 2 + .../code_mappings/code-mappings-help.trycmd | 25 ++++++++ .../code-mappings-no-subcommand.trycmd | 25 ++++++++ .../code-mappings-upload-help.trycmd | 26 ++++++++ tests/integration/code_mappings/mod.rs | 16 +++++ tests/integration/mod.rs | 1 + 8 files changed, 202 insertions(+) create mode 100644 src/commands/code_mappings/mod.rs create mode 100644 src/commands/code_mappings/upload.rs create mode 100644 tests/integration/_cases/code_mappings/code-mappings-help.trycmd create mode 100644 tests/integration/_cases/code_mappings/code-mappings-no-subcommand.trycmd create mode 100644 tests/integration/_cases/code_mappings/code-mappings-upload-help.trycmd create mode 100644 tests/integration/code_mappings/mod.rs diff --git a/src/commands/code_mappings/mod.rs b/src/commands/code_mappings/mod.rs new file mode 100644 index 0000000000..4c2583bd61 --- /dev/null +++ b/src/commands/code_mappings/mod.rs @@ -0,0 +1,45 @@ +use anyhow::Result; +use clap::{ArgMatches, Command}; + +use crate::utils::args::ArgExt as _; + +pub mod upload; + +macro_rules! each_subcommand { + ($mac:ident) => { + $mac!(upload); + }; +} + +pub fn make_command(mut command: Command) -> Command { + macro_rules! add_subcommand { + ($name:ident) => {{ + command = command.subcommand(crate::commands::code_mappings::$name::make_command( + Command::new(stringify!($name).replace('_', "-")), + )); + }}; + } + + command = command + .about("Manage code mappings for Sentry.") + .subcommand_required(true) + .arg_required_else_help(true) + .org_arg() + .project_arg(false); + each_subcommand!(add_subcommand); + command +} + +pub fn execute(matches: &ArgMatches) -> Result<()> { + macro_rules! execute_subcommand { + ($name:ident) => {{ + if let Some(sub_matches) = + matches.subcommand_matches(&stringify!($name).replace('_', "-")) + { + return crate::commands::code_mappings::$name::execute(&sub_matches); + } + }}; + } + each_subcommand!(execute_subcommand); + unreachable!(); +} diff --git a/src/commands/code_mappings/upload.rs b/src/commands/code_mappings/upload.rs new file mode 100644 index 0000000000..f0141c7d42 --- /dev/null +++ b/src/commands/code_mappings/upload.rs @@ -0,0 +1,62 @@ +use std::fs; + +use anyhow::{bail, Context as _, Result}; +use clap::{Arg, ArgMatches, Command}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +struct CodeMapping { + stack_root: String, + source_root: String, +} + +pub fn make_command(command: Command) -> Command { + command + .about("Upload code mappings for a project from a JSON file.") + .arg( + Arg::new("path") + .value_name("PATH") + .required(true) + .help("Path to a JSON file containing code mappings."), + ) + .arg( + Arg::new("repo") + .long("repo") + .value_name("REPO") + .help("The repository name (e.g. owner/repo). Defaults to the git remote."), + ) + .arg( + Arg::new("default_branch") + .long("default-branch") + .value_name("BRANCH") + .default_value("main") + .help("The default branch name."), + ) +} + +pub fn execute(matches: &ArgMatches) -> Result<()> { + #[expect(clippy::unwrap_used, reason = "path is a required argument")] + let path = matches.get_one::("path").unwrap(); + let data = fs::read(path).with_context(|| format!("Failed to read mappings file '{path}'"))?; + + let mappings: Vec = + serde_json::from_slice(&data).context("Failed to parse mappings JSON")?; + + if mappings.is_empty() { + bail!("Mappings file contains an empty array. Nothing to upload."); + } + + for (i, mapping) in mappings.iter().enumerate() { + if mapping.stack_root.is_empty() { + bail!("Mapping at index {i} has an empty stackRoot."); + } + if mapping.source_root.is_empty() { + bail!("Mapping at index {i} has an empty sourceRoot."); + } + } + + println!("Found {} code mapping(s) in {path}", mappings.len()); + + Ok(()) +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index bf74f76d42..65ca7573b4 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -21,6 +21,7 @@ use crate::utils::value_parsers::auth_token_parser; mod bash_hook; mod build; +mod code_mappings; mod dart_symbol_map; mod debug_files; mod deploys; @@ -52,6 +53,7 @@ macro_rules! each_subcommand { ($mac:ident) => { $mac!(bash_hook); $mac!(build); + $mac!(code_mappings); $mac!(debug_files); $mac!(deploys); $mac!(events); diff --git a/tests/integration/_cases/code_mappings/code-mappings-help.trycmd b/tests/integration/_cases/code_mappings/code-mappings-help.trycmd new file mode 100644 index 0000000000..0d29b3dd63 --- /dev/null +++ b/tests/integration/_cases/code_mappings/code-mappings-help.trycmd @@ -0,0 +1,25 @@ +``` +$ sentry-cli code-mappings --help +? success +Manage code mappings for Sentry. + +Usage: sentry-cli[EXE] code-mappings [OPTIONS] + +Commands: + upload Upload code mappings for a project from a JSON file. + help Print this message or the help of the given subcommand(s) + +Options: + -o, --org The organization ID or slug. + --header Custom headers that should be attached to all requests + in key:value format. + -p, --project The project ID or slug. + --auth-token Use the given Sentry auth token. + --log-level Set the log output verbosity. [possible values: trace, debug, info, + warn, error] + --quiet Do not print any output while preserving correct exit code. This + flag is currently implemented only for selected subcommands. + [aliases: --silent] + -h, --help Print help + +``` diff --git a/tests/integration/_cases/code_mappings/code-mappings-no-subcommand.trycmd b/tests/integration/_cases/code_mappings/code-mappings-no-subcommand.trycmd new file mode 100644 index 0000000000..36df45fa6f --- /dev/null +++ b/tests/integration/_cases/code_mappings/code-mappings-no-subcommand.trycmd @@ -0,0 +1,25 @@ +``` +$ sentry-cli code-mappings +? failed +Manage code mappings for Sentry. + +Usage: sentry-cli[EXE] code-mappings [OPTIONS] + +Commands: + upload Upload code mappings for a project from a JSON file. + help Print this message or the help of the given subcommand(s) + +Options: + -o, --org The organization ID or slug. + --header Custom headers that should be attached to all requests + in key:value format. + -p, --project The project ID or slug. + --auth-token Use the given Sentry auth token. + --log-level Set the log output verbosity. [possible values: trace, debug, info, + warn, error] + --quiet Do not print any output while preserving correct exit code. This + flag is currently implemented only for selected subcommands. + [aliases: --silent] + -h, --help Print help + +``` diff --git a/tests/integration/_cases/code_mappings/code-mappings-upload-help.trycmd b/tests/integration/_cases/code_mappings/code-mappings-upload-help.trycmd new file mode 100644 index 0000000000..cf46abe2c2 --- /dev/null +++ b/tests/integration/_cases/code_mappings/code-mappings-upload-help.trycmd @@ -0,0 +1,26 @@ +``` +$ sentry-cli code-mappings upload --help +? success +Upload code mappings for a project from a JSON file. + +Usage: sentry-cli[EXE] code-mappings upload [OPTIONS] + +Arguments: + Path to a JSON file containing code mappings. + +Options: + -o, --org The organization ID or slug. + --repo The repository name (e.g. owner/repo). Defaults to the git remote. + --default-branch The default branch name. [default: main] + --header Custom headers that should be attached to all requests + in key:value format. + -p, --project The project ID or slug. + --auth-token Use the given Sentry auth token. + --log-level Set the log output verbosity. [possible values: trace, debug, info, + warn, error] + --quiet Do not print any output while preserving correct exit code. This + flag is currently implemented only for selected subcommands. + [aliases: --silent] + -h, --help Print help + +``` diff --git a/tests/integration/code_mappings/mod.rs b/tests/integration/code_mappings/mod.rs new file mode 100644 index 0000000000..bcfc6ec6a5 --- /dev/null +++ b/tests/integration/code_mappings/mod.rs @@ -0,0 +1,16 @@ +use crate::integration::TestManager; + +#[test] +fn command_code_mappings_help() { + TestManager::new().register_trycmd_test("code_mappings/code-mappings-help.trycmd"); +} + +#[test] +fn command_code_mappings_no_subcommand() { + TestManager::new().register_trycmd_test("code_mappings/code-mappings-no-subcommand.trycmd"); +} + +#[test] +fn command_code_mappings_upload_help() { + TestManager::new().register_trycmd_test("code_mappings/code-mappings-upload-help.trycmd"); +} diff --git a/tests/integration/mod.rs b/tests/integration/mod.rs index fde0647603..ba5828049d 100644 --- a/tests/integration/mod.rs +++ b/tests/integration/mod.rs @@ -1,5 +1,6 @@ mod bash_hook; mod build; +mod code_mappings; mod debug_files; mod deploys; mod events; From 072fa6b480d1eae74b18d4f0044a348c196329a6 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 12 Mar 2026 12:05:54 +0100 Subject: [PATCH 2/6] fix(test): Update help snapshots with code-mappings subcommand --- tests/integration/_cases/help/help-windows.trycmd | 1 + tests/integration/_cases/help/help.trycmd | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/integration/_cases/help/help-windows.trycmd b/tests/integration/_cases/help/help-windows.trycmd index e634561ea7..34213e9438 100644 --- a/tests/integration/_cases/help/help-windows.trycmd +++ b/tests/integration/_cases/help/help-windows.trycmd @@ -12,6 +12,7 @@ Usage: sentry-cli[EXE] [OPTIONS] Commands: completions Generate completions for the specified shell. build Manage builds. + code-mappings Manage code mappings for Sentry. debug-files Locate, analyze or upload debug information files. [aliases: dif] deploys Manage deployments for Sentry releases. events Manage events on Sentry. diff --git a/tests/integration/_cases/help/help.trycmd b/tests/integration/_cases/help/help.trycmd index aa51cd0222..fcc5302ea7 100644 --- a/tests/integration/_cases/help/help.trycmd +++ b/tests/integration/_cases/help/help.trycmd @@ -12,6 +12,7 @@ Usage: sentry-cli[EXE] [OPTIONS] Commands: completions Generate completions for the specified shell. build Manage builds. + code-mappings Manage code mappings for Sentry. debug-files Locate, analyze or upload debug information files. [aliases: dif] deploys Manage deployments for Sentry releases. events Manage events on Sentry. From 8acfdbe7e9c64bef0a45e4c977a4eeb6039f745e Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 18 Mar 2026 17:52:30 +0100 Subject: [PATCH 3/6] fix(code-mappings): Address PR feedback on help text and unwrap usage Add descriptive help text explaining what code mappings are and how they work. Replace unwrap with expect for the required path argument. Co-Authored-By: Claude Opus 4.6 --- src/commands/code_mappings/mod.rs | 2 +- src/commands/code_mappings/upload.rs | 7 ++++--- .../_cases/code_mappings/code-mappings-help.trycmd | 7 +++++-- .../code_mappings/code-mappings-no-subcommand.trycmd | 7 +++++-- .../_cases/code_mappings/code-mappings-upload-help.trycmd | 4 +++- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/commands/code_mappings/mod.rs b/src/commands/code_mappings/mod.rs index 4c2583bd61..47511a8e5a 100644 --- a/src/commands/code_mappings/mod.rs +++ b/src/commands/code_mappings/mod.rs @@ -21,7 +21,7 @@ pub fn make_command(mut command: Command) -> Command { } command = command - .about("Manage code mappings for Sentry.") + .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.") .subcommand_required(true) .arg_required_else_help(true) .org_arg() diff --git a/src/commands/code_mappings/upload.rs b/src/commands/code_mappings/upload.rs index f0141c7d42..3e6582f27e 100644 --- a/src/commands/code_mappings/upload.rs +++ b/src/commands/code_mappings/upload.rs @@ -13,7 +13,7 @@ struct CodeMapping { pub fn make_command(command: Command) -> Command { command - .about("Upload code mappings for a project from a JSON file.") + .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).") .arg( Arg::new("path") .value_name("PATH") @@ -36,8 +36,9 @@ pub fn make_command(command: Command) -> Command { } pub fn execute(matches: &ArgMatches) -> Result<()> { - #[expect(clippy::unwrap_used, reason = "path is a required argument")] - let path = matches.get_one::("path").unwrap(); + let path = matches + .get_one::("path") + .expect("path is a required argument"); let data = fs::read(path).with_context(|| format!("Failed to read mappings file '{path}'"))?; let mappings: Vec = diff --git a/tests/integration/_cases/code_mappings/code-mappings-help.trycmd b/tests/integration/_cases/code_mappings/code-mappings-help.trycmd index 0d29b3dd63..759ddda529 100644 --- a/tests/integration/_cases/code_mappings/code-mappings-help.trycmd +++ b/tests/integration/_cases/code_mappings/code-mappings-help.trycmd @@ -1,12 +1,15 @@ ``` $ sentry-cli code-mappings --help ? success -Manage code mappings for Sentry. +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. Usage: sentry-cli[EXE] code-mappings [OPTIONS] Commands: - upload Upload code mappings for a project from a JSON file. + upload 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). help Print this message or the help of the given subcommand(s) Options: diff --git a/tests/integration/_cases/code_mappings/code-mappings-no-subcommand.trycmd b/tests/integration/_cases/code_mappings/code-mappings-no-subcommand.trycmd index 36df45fa6f..64f98301c4 100644 --- a/tests/integration/_cases/code_mappings/code-mappings-no-subcommand.trycmd +++ b/tests/integration/_cases/code_mappings/code-mappings-no-subcommand.trycmd @@ -1,12 +1,15 @@ ``` $ sentry-cli code-mappings ? failed -Manage code mappings for Sentry. +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. Usage: sentry-cli[EXE] code-mappings [OPTIONS] Commands: - upload Upload code mappings for a project from a JSON file. + upload 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). help Print this message or the help of the given subcommand(s) Options: diff --git a/tests/integration/_cases/code_mappings/code-mappings-upload-help.trycmd b/tests/integration/_cases/code_mappings/code-mappings-upload-help.trycmd index cf46abe2c2..01033d6915 100644 --- a/tests/integration/_cases/code_mappings/code-mappings-upload-help.trycmd +++ b/tests/integration/_cases/code_mappings/code-mappings-upload-help.trycmd @@ -1,7 +1,9 @@ ``` $ sentry-cli code-mappings upload --help ? success -Upload code mappings for a project from a JSON file. +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). Usage: sentry-cli[EXE] code-mappings upload [OPTIONS] From 1015af15b5d43b7fe5e1ffe43ed47e01ee9d266a Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 18 Mar 2026 17:57:41 +0100 Subject: [PATCH 4/6] fix(code-mappings): Update top-level help snapshot for new description Co-Authored-By: Claude Opus 4.6 --- tests/integration/_cases/help/help.trycmd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/_cases/help/help.trycmd b/tests/integration/_cases/help/help.trycmd index fcc5302ea7..41537a2fa9 100644 --- a/tests/integration/_cases/help/help.trycmd +++ b/tests/integration/_cases/help/help.trycmd @@ -12,7 +12,9 @@ Usage: sentry-cli[EXE] [OPTIONS] Commands: completions Generate completions for the specified shell. build Manage builds. - code-mappings Manage code mappings for Sentry. + code-mappings 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. debug-files Locate, analyze or upload debug information files. [aliases: dif] deploys Manage deployments for Sentry releases. events Manage events on Sentry. From 811bb94f5a17ec45f5dca65e3e94342f67ad8360 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 18 Mar 2026 18:06:22 +0100 Subject: [PATCH 5/6] fix(code-mappings): Update Windows help snapshot for new description Co-Authored-By: Claude Opus 4.6 --- tests/integration/_cases/help/help-windows.trycmd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/_cases/help/help-windows.trycmd b/tests/integration/_cases/help/help-windows.trycmd index 34213e9438..71fc427292 100644 --- a/tests/integration/_cases/help/help-windows.trycmd +++ b/tests/integration/_cases/help/help-windows.trycmd @@ -12,7 +12,9 @@ Usage: sentry-cli[EXE] [OPTIONS] Commands: completions Generate completions for the specified shell. build Manage builds. - code-mappings Manage code mappings for Sentry. + code-mappings 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. debug-files Locate, analyze or upload debug information files. [aliases: dif] deploys Manage deployments for Sentry releases. events Manage events on Sentry. From 387d6058d007eeb6e2f31f8961af6441e0dd45a8 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 20 Mar 2026 22:21:51 +0100 Subject: [PATCH 6/6] ref(code-mappings): Remove unused Serialize derive from CodeMapping CodeMapping is only deserialized from the input JSON file in this PR. Serialize will be added back when needed in the API integration PR. Co-Authored-By: Claude Opus 4.6 --- src/commands/code_mappings/upload.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/code_mappings/upload.rs b/src/commands/code_mappings/upload.rs index 3e6582f27e..d40d6427c3 100644 --- a/src/commands/code_mappings/upload.rs +++ b/src/commands/code_mappings/upload.rs @@ -2,9 +2,9 @@ use std::fs; use anyhow::{bail, Context as _, Result}; use clap::{Arg, ArgMatches, Command}; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct CodeMapping { stack_root: String,