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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

- (snapshots) Compress preprod snapshot manifest with zstd ([#3336](https://github.com/getsentry/sentry-cli/pull/3336))

### Fixes

- (snapshots) Show a clear "project was renamed" error instead of a cryptic JSON parse failure when uploading to a renamed project slug ([#3341](https://github.com/getsentry/sentry-cli/pull/3341))

## 3.5.1

### Internal Changes 🔧
Expand Down
62 changes: 52 additions & 10 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1015,15 +1015,16 @@ impl AuthenticatedApi<'_> {
org: &str,
project: &str,
body: &S,
) -> ApiResult<ApiResponse> {
) -> ApiResult<CreateSnapshotResponse> {
let path = format!(
"/projects/{}/{}/preprodartifacts/snapshots/",
PathArg(org),
PathArg(project)
);
self.request(Method::Post, &path)?
.with_zstd_json_body(body)?
.send()
.send()?
.convert_rnf(ApiErrorKind::ProjectNotFound)
}

/// Fetches upload options for snapshots.
Expand All @@ -1037,7 +1038,7 @@ impl AuthenticatedApi<'_> {
PathArg(org),
PathArg(project)
);
self.get(&path)?.convert()
self.get(&path)?.convert_rnf(ApiErrorKind::ProjectNotFound)
}

pub fn get_latest_base_snapshot(
Expand Down Expand Up @@ -1605,20 +1606,15 @@ impl ApiResponse {
fn convert_rnf<T: DeserializeOwned>(self, res_err: ApiErrorKind) -> ApiResult<T> {
match self.status() {
301 | 302 if res_err == ApiErrorKind::ProjectNotFound => {
#[derive(Deserialize, Debug)]
struct ErrorDetail {
slug: String,
}

Comment thread
szokeasaurusrex marked this conversation as resolved.
#[derive(Deserialize, Debug)]
struct ErrorInfo {
detail: ErrorDetail,
slug: String,
}

match self.convert::<ErrorInfo>() {
Ok(info) => Err(ApiError::with_source(
res_err,
ProjectRenamedError(info.detail.slug),
ProjectRenamedError(info.slug),
)),
Err(_) => Err(res_err.into()),
}
Expand Down Expand Up @@ -2143,3 +2139,49 @@ pub struct ObjectstoreUploadOptions {
pub auth_token: Option<SecretString>,
pub expiration_policy: String,
}

#[cfg(test)]
mod tests {
use std::error::Error as _;

use super::*;

fn project_renamed_response() -> ApiResponse {
ApiResponse {
status: 302,
headers: vec!["content-type: application/json".to_owned()],
body: Some(
br#"{"slug":"new-project-slug","detail":{"extra":{"url":"/api/0/projects/wat-org/new-project-slug/preprodartifacts/snapshots/upload-options/","slug":"new-project-slug"}}}"#
.to_vec(),
),
}
}

#[test]
fn convert_rnf_reports_project_rename() {
let err = project_renamed_response()
.convert_rnf::<SnapshotsUploadOptions>(ApiErrorKind::ProjectNotFound)
.expect_err("expected a project-renamed error");

let source = err.source().map(|s| s.to_string()).unwrap_or_default();

assert!(
source.contains("project was renamed to 'new-project-slug'"),
"expected rename message in error source, got: {err:?} / source: {source}"
);
}

#[test]
fn convert_rnf_reports_project_rename_for_create_response() {
let err = project_renamed_response()
.convert_rnf::<CreateSnapshotResponse>(ApiErrorKind::ProjectNotFound)
.expect_err("expected a project-renamed error");

let source = err.source().map(|s| s.to_string()).unwrap_or_default();

assert!(
source.contains("project was renamed to 'new-project-slug'"),
"expected rename message in error source, got: {err:?} / source: {source}"
);
}
}
7 changes: 3 additions & 4 deletions src/commands/snapshots/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use serde_json::Value;
use sha2::{Digest as _, Sha256};
use walkdir::WalkDir;

use crate::api::{Api, CreateSnapshotResponse, ImageMetadata, SnapshotsManifest};
use crate::api::{Api, ImageMetadata, SnapshotsManifest};
use crate::config::Config;
use crate::utils::args::ArgExt as _;
use crate::utils::build_vcs::collect_git_metadata;
Expand Down Expand Up @@ -207,10 +207,9 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
// POST manifest to API
println!("{} Creating snapshot...", style(">").dim());
let api = Api::current();
let response: CreateSnapshotResponse = api
let response = api
.authenticated()?
.create_preprod_snapshot(&org, &project, &manifest)?
.convert()?;
.create_preprod_snapshot(&org, &project, &manifest)?;

println!(
"{} Created snapshot {} with {} {}",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
```
$ sentry-cli snapshots upload tests/integration/_fixtures/snapshots --app-id test-app --no-git-metadata
? failed
> Found 1 image file
> Processing 1 image file
error: Project not found. Ensure that you configured the correct project and organization.

Caused by:
project was renamed to 'new-project-slug'
Please use this slug in your .sentryclirc file, sentry.properties file or in the CLI --project parameter

Add --log-level=[info|debug] or export SENTRY_LOG_LEVEL=[info|debug] to see more output.
Please attach the full debug log to all bug reports.

```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 18 additions & 1 deletion tests/integration/snapshots.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::integration::TestManager;
use crate::integration::{MockEndpointBuilder, TestManager};

#[test]
fn command_snapshots_diff_help() {
Expand All @@ -19,3 +19,20 @@ fn command_snapshots_download_help() {
fn command_snapshots_upload_help() {
TestManager::new().register_trycmd_test("snapshots/snapshots-upload-help.trycmd");
}

#[test]
fn command_snapshots_upload_renamed_project() {
TestManager::new()
.mock_endpoint(
MockEndpointBuilder::new(
"GET",
"/api/0/projects/wat-org/wat-project/preprodartifacts/snapshots/upload-options/",
)
.with_status(302)
.with_response_body(
r#"{"slug":"new-project-slug","detail":{"extra":{"url":"/api/0/projects/wat-org/new-project-slug/preprodartifacts/snapshots/upload-options/","slug":"new-project-slug"}}}"#,
),
)
.register_trycmd_test("snapshots/snapshots-upload-renamed-project.trycmd")
.with_default_token();
}
Loading