Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/api/data_types/chunking/mobile_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,24 @@ pub struct ChunkedMobileAppRequest<'a> {
pub checksum: Digest,
pub chunks: &'a [Digest],
#[serde(skip_serializing_if = "Option::is_none")]
pub build_configuration: Option<&'a str>,
// VCS fields
#[serde(skip_serializing_if = "Option::is_none")]
pub head_sha: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub build_configuration: Option<&'a str>,
pub base_sha: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub provider: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub head_repo_name: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub base_repo_name: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub head_ref: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub base_ref: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pr_number: Option<&'a u32>,
}

#[derive(Debug, Deserialize)]
Expand Down
25 changes: 23 additions & 2 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1036,8 +1036,8 @@ impl<'a> AuthenticatedApi<'a> {
project: &str,
checksum: Digest,
chunks: &[Digest],
head_sha: Option<&str>,
build_configuration: Option<&str>,
vcs_info: &VcsInfo<'_>,
) -> ApiResult<AssembleMobileAppResponse> {
let url = format!(
"/projects/{}/{}/files/preprodartifacts/assemble/",
Expand All @@ -1049,8 +1049,15 @@ impl<'a> AuthenticatedApi<'a> {
.with_json_body(&ChunkedMobileAppRequest {
checksum,
chunks,
head_sha,
build_configuration,
head_sha: vcs_info.head_sha,
base_sha: vcs_info.base_sha,
provider: vcs_info.vcs_provider,
head_repo_name: vcs_info.head_repo_name,
base_repo_name: vcs_info.base_repo_name,
head_ref: vcs_info.head_ref,
base_ref: vcs_info.base_ref,
pr_number: vcs_info.pr_number,
})?
.send()?
.convert_rnf(ApiErrorKind::ProjectNotFound)
Expand Down Expand Up @@ -2518,6 +2525,20 @@ struct LogsResponse {
data: Vec<LogEntry>,
}

/// VCS information for mobile app uploads
#[cfg(feature = "unstable-mobile-app")]
#[derive(Debug)]
pub struct VcsInfo<'a> {
pub head_sha: Option<&'a str>,
pub base_sha: Option<&'a str>,
pub vcs_provider: Option<&'a str>,
pub head_repo_name: Option<&'a str>,
pub base_repo_name: Option<&'a str>,
pub head_ref: Option<&'a str>,
pub base_ref: Option<&'a str>,
pub pr_number: Option<&'a u32>,
}

/// Log entry structure from the logs API
#[derive(Debug, Deserialize)]
pub struct LogEntry {
Expand Down
86 changes: 73 additions & 13 deletions src/commands/mobile_app/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use symbolic::common::ByteView;
use zip::write::SimpleFileOptions;
use zip::{DateTime, ZipWriter};

use crate::api::{Api, AuthenticatedApi, ChunkUploadCapability, ChunkedFileState};
use crate::api::{Api, AuthenticatedApi, ChunkUploadCapability, ChunkedFileState, VcsInfo};
use crate::config::Config;
use crate::utils::args::ArgExt as _;
use crate::utils::chunks::{upload_chunks, Chunk};
Expand Down Expand Up @@ -44,9 +44,45 @@ pub fn make_command(command: Command) -> Command {
.required(true),
)
.arg(
Arg::new("sha")
.long("sha")
.help("The git commit sha to use for the upload. If not provided, the current commit sha will be used.")
Arg::new("head_sha")
.long("head-sha")
.help("The VCS commit sha to use for the upload. If not provided, the current commit sha will be used.")
)
.arg(
Arg::new("base_sha")
.long("base-sha")
.help("The VCS commit's base sha to use for the upload. If not provided, the merge-base of the current and remote branch will be used.")
)
.arg(
Arg::new("vcs_provider")
.long("vcs-provider")
.help("The VCS provider to use for the upload. If not provided, the current provider will be used.")
)
.arg(
Arg::new("head_repo_name")
.long("head-repo-name")
.help("The name of the git repository to use for the upload (e.g. organization/repository). If not provided, the current repository will be used.")
)
.arg(
Arg::new("base_repo_name")
.long("base-repo-name")
.help("The name of the git repository to use for the upload (e.g. organization/repository). If not provided, the current repository will be used.")
)
.arg(
Arg::new("head_ref")
.long("head-ref")
.help("The reference (branch) to use for the upload. If not provided, the current reference will be used.")
)
.arg(
Arg::new("base_ref")
.long("base-ref")
.help("The reference (branch) to use for the upload. If not provided, the current reference will be used.")
)
.arg(
Arg::new("pr_number")
.long("pr-number")
.value_parser(clap::value_parser!(u32))
.help("The pull request number to use for the upload. If not provided, the current pull request number will be used.")
)
.arg(
Arg::new("build_configuration")
Expand All @@ -60,12 +96,20 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
.get_many::<String>("paths")
.expect("paths argument is required");

let sha = matches
.get_one("sha")
let head_sha = matches
.get_one("head_sha")
.map(String::as_str)
.map(Cow::Borrowed)
.or_else(|| vcs::find_head().ok().map(Cow::Owned));

let base_sha = matches.get_one("base_sha").map(String::as_str);
let vcs_provider = matches.get_one("vcs_provider").map(String::as_str);
let head_repo_name = matches.get_one("head_repo_name").map(String::as_str);
let base_repo_name = matches.get_one("base_repo_name").map(String::as_str);
let head_ref = matches.get_one("head_ref").map(String::as_str);
let base_ref = matches.get_one("base_ref").map(String::as_str);
let pr_number = matches.get_one::<u32>("pr_number");

let build_configuration = matches.get_one("build_configuration").map(String::as_str);

let api = Api::current();
Expand Down Expand Up @@ -124,13 +168,23 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
for (path, zip) in normalized_zips {
info!("Uploading file: {}", path.display());
let bytes = ByteView::open(zip.path())?;
let vcs_info = VcsInfo {
head_sha: head_sha.as_deref(),
base_sha,
vcs_provider,
head_repo_name,
base_repo_name,
head_ref,
base_ref,
pr_number,
};
match upload_file(
&authenticated_api,
&bytes,
&org,
&project,
sha.as_deref(),
build_configuration,
&vcs_info,
) {
Ok(artifact_id) => {
info!("Successfully uploaded file: {}", path.display());
Expand Down Expand Up @@ -289,18 +343,18 @@ fn upload_file(
bytes: &[u8],
org: &str,
project: &str,
sha: Option<&str>,
build_configuration: Option<&str>,
vcs_info: &VcsInfo<'_>,
) -> Result<String> {
const SELF_HOSTED_ERROR_HINT: &str = "If you are using a self-hosted Sentry server, \
update to the latest version of Sentry to use the mobile-app upload command.";

debug!(
"Uploading file to organization: {}, project: {}, sha: {}, build_configuration: {}",
"Uploading file to organization: {}, project: {}, build_configuration: {}, vcs_info: {:?}",
org,
project,
sha.unwrap_or("unknown"),
build_configuration.unwrap_or("unknown")
build_configuration.unwrap_or("unknown"),
vcs_info,
);

let chunk_upload_options = api.get_chunk_upload_options(org)?.ok_or_else(|| {
Expand Down Expand Up @@ -346,8 +400,14 @@ fn upload_file(
// iteration of the loop) we get:
// n. state=err, artifact_id unset
let result = loop {
let response =
api.assemble_mobile_app(org, project, checksum, &checksums, sha, build_configuration)?;
let response = api.assemble_mobile_app(
org,
project,
checksum,
&checksums,
build_configuration,
vcs_info,
)?;
chunks.retain(|Chunk((digest, _))| response.missing_chunks.contains(digest));

if !chunks.is_empty() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
```
$ sentry-cli mobile-app upload tests/integration/_fixtures/mobile_app/apk.apk --sha test_sha
$ sentry-cli mobile-app upload tests/integration/_fixtures/mobile_app/apk.apk --head-sha test_head_sha
? success
[..]WARN[..]EXPERIMENTAL: The mobile-app subcommand is experimental. The command is subject to breaking changes and may be removed without notice in any release.
Successfully uploaded 1 file to Sentry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,38 @@ Options:
The project ID or slug.
--auth-token <AUTH_TOKEN>
Use the given Sentry auth token.
--sha <sha>
The git commit sha to use for the upload. If not provided, the current commit sha will be
--head-sha <head_sha>
The VCS commit sha to use for the upload. If not provided, the current commit sha will be
used.
--build-configuration <build_configuration>
The build configuration to use for the upload. If not provided, the current version will
be used.
--base-sha <base_sha>
The VCS commit's base sha to use for the upload. If not provided, the merge-base of the
current and remote branch will be used.
--log-level <LOG_LEVEL>
Set the log output verbosity. [possible values: trace, debug, info, warn, error]
--vcs-provider <vcs_provider>
The VCS provider to use for the upload. If not provided, the current provider will be
used.
--head-repo-name <head_repo_name>
The name of the git repository to use for the upload (e.g. organization/repository). If
not provided, the current repository will be used.
--quiet
Do not print any output while preserving correct exit code. This flag is currently
implemented only for selected subcommands. [aliases: silent]
--base-repo-name <base_repo_name>
The name of the git repository to use for the upload (e.g. organization/repository). If
not provided, the current repository will be used.
--head-ref <head_ref>
The reference (branch) to use for the upload. If not provided, the current reference will
be used.
--base-ref <base_ref>
The reference (branch) to use for the upload. If not provided, the current reference will
be used.
--pr-number <pr_number>
The pull request number to use for the upload. If not provided, the current pull request
number will be used.
--build-configuration <build_configuration>
The build configuration to use for the upload. If not provided, the current version will
be used.
-h, --help
Print help

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
```
$ sentry-cli mobile-app upload --help
? success
[EXPERIMENTAL] Upload mobile app files to a project.

Usage: sentry-cli[EXE] mobile-app upload [OPTIONS] <PATH>...
Expand All @@ -18,17 +17,38 @@ Options:
The project ID or slug.
--auth-token <AUTH_TOKEN>
Use the given Sentry auth token.
--sha <sha>
The git commit sha to use for the upload. If not provided, the current commit sha will be
--head-sha <head_sha>
The VCS commit sha to use for the upload. If not provided, the current commit sha will be
used.
--build-configuration <build_configuration>
The build configuration to use for the upload. If not provided, the current version will
be used.
--base-sha <base_sha>
The VCS commit's base sha to use for the upload. If not provided, the merge-base of the
current and remote branch will be used.
--log-level <LOG_LEVEL>
Set the log output verbosity. [possible values: trace, debug, info, warn, error]
--vcs-provider <vcs_provider>
The VCS provider to use for the upload. If not provided, the current provider will be
used.
--head-repo-name <head_repo_name>
The name of the git repository to use for the upload (e.g. organization/repository). If
not provided, the current repository will be used.
--quiet
Do not print any output while preserving correct exit code. This flag is currently
implemented only for selected subcommands. [aliases: silent]
--base-repo-name <base_repo_name>
The name of the git repository to use for the upload (e.g. organization/repository). If
not provided, the current repository will be used.
--head-ref <head_ref>
The reference (branch) to use for the upload. If not provided, the current reference will
be used.
--base-ref <base_ref>
The reference (branch) to use for the upload. If not provided, the current reference will
be used.
--pr-number <pr_number>
The pull request number to use for the upload. If not provided, the current pull request
number will be used.
--build-configuration <build_configuration>
The build configuration to use for the upload. If not provided, the current version will
be used.
-h, --help
Print help

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
```
$ sentry-cli mobile-app upload tests/integration/_fixtures/mobile_app/ipa.ipa --sha test_sha
$ sentry-cli mobile-app upload tests/integration/_fixtures/mobile_app/ipa.ipa --head-sha test_head_sha
? success
[..]WARN[..]EXPERIMENTAL: The mobile-app subcommand is experimental. The command is subject to breaking changes and may be removed without notice in any release.
Successfully uploaded 1 file to Sentry
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/mobile_app/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ fn command_mobile_app_upload_apk_chunked() {
"/api/0/projects/wat-org/wat-project/files/preprodartifacts/assemble/",
)
.with_header_matcher("content-type", "application/json")
.with_matcher(r#"{"checksum":"18e40e6e932d0b622d631e887be454cc2003dbb5","chunks":["18e40e6e932d0b622d631e887be454cc2003dbb5"],"head_sha":"test_sha"}"#)
.with_matcher(r#"{"checksum":"18e40e6e932d0b622d631e887be454cc2003dbb5","chunks":["18e40e6e932d0b622d631e887be454cc2003dbb5"],"head_sha":"test_head_sha"}"#)
.with_response_fn(move |_| {
if is_first_assemble_call.swap(false, Ordering::Relaxed) {
r#"{
Expand Down Expand Up @@ -214,7 +214,7 @@ fn command_mobile_app_upload_ipa_chunked() {
"/api/0/projects/wat-org/wat-project/files/preprodartifacts/assemble/",
)
.with_header_matcher("content-type", "application/json")
.with_matcher(r#"{"checksum":"ed9da71e3688261875db21b266da84ffe004a8a4","chunks":["ed9da71e3688261875db21b266da84ffe004a8a4"],"head_sha":"test_sha"}"#)
.with_matcher(r#"{"checksum":"ed9da71e3688261875db21b266da84ffe004a8a4","chunks":["ed9da71e3688261875db21b266da84ffe004a8a4"],"head_sha":"test_head_sha"}"#)
.with_response_fn(move |_| {
if is_first_assemble_call.swap(false, Ordering::Relaxed) {
r#"{
Expand Down