@@ -16,7 +16,7 @@ use symbolic::common::ByteView;
1616use zip:: write:: SimpleFileOptions ;
1717use zip:: { DateTime , ZipWriter } ;
1818
19- use crate :: api:: { Api , AuthenticatedApi , ChunkUploadCapability } ;
19+ use crate :: api:: { Api , AssembleMobileAppResponse , AuthenticatedApi , ChunkUploadCapability } ;
2020use crate :: config:: Config ;
2121use crate :: utils:: args:: ArgExt as _;
2222use crate :: utils:: chunks:: { upload_chunks, Chunk , ASSEMBLE_POLL_INTERVAL } ;
@@ -129,9 +129,10 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
129129
130130 let config = Config :: current ( ) ;
131131 let ( org, project) = config. get_org_and_project ( matches) ?;
132+ let base_url = config. get_base_url ( ) ?;
132133
133- let mut uploaded_paths = vec ! [ ] ;
134- let mut errored_paths = vec ! [ ] ;
134+ let mut uploaded_paths_and_ids = vec ! [ ] ;
135+ let mut errored_paths_and_reasons = vec ! [ ] ;
135136 for ( path, zip) in normalized_zips {
136137 info ! ( "Uploading file: {}" , path. display( ) ) ;
137138 let bytes = ByteView :: open ( zip. path ( ) ) ?;
@@ -143,41 +144,50 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
143144 sha. as_deref ( ) ,
144145 build_configuration,
145146 ) {
146- Ok ( _ ) => {
147+ Ok ( artifact_id ) => {
147148 info ! ( "Successfully uploaded file: {}" , path. display( ) ) ;
148- uploaded_paths . push ( path. to_path_buf ( ) ) ;
149+ uploaded_paths_and_ids . push ( ( path. to_path_buf ( ) , artifact_id ) ) ;
149150 }
150151 Err ( e) => {
151152 debug ! ( "Failed to upload file at path {}: {}" , path. display( ) , e) ;
152- errored_paths . push ( path. to_path_buf ( ) ) ;
153+ errored_paths_and_reasons . push ( ( path. to_path_buf ( ) , e ) ) ;
153154 }
154155 }
155156 }
156157
157- if !errored_paths . is_empty ( ) {
158+ if !errored_paths_and_reasons . is_empty ( ) {
158159 warn ! (
159160 "Failed to upload {} file{}:" ,
160- errored_paths. len( ) ,
161- if errored_paths. len( ) == 1 { "" } else { "s" }
161+ errored_paths_and_reasons. len( ) ,
162+ if errored_paths_and_reasons. len( ) == 1 {
163+ ""
164+ } else {
165+ "s"
166+ }
162167 ) ;
163- for path in errored_paths {
164- warn ! ( " - {}" , path. display( ) ) ;
168+ for ( path, reason ) in errored_paths_and_reasons {
169+ warn ! ( " - {} ({}) " , path. display( ) , reason ) ;
165170 }
166171 }
167172
168- println ! (
169- "Successfully uploaded {} file{} to Sentry" ,
170- uploaded_paths. len( ) ,
171- if uploaded_paths. len( ) == 1 { "" } else { "s" }
172- ) ;
173- if uploaded_paths. len ( ) < 3 {
174- for path in & uploaded_paths {
175- println ! ( " - {}" , path. display( ) ) ;
176- }
177- }
178-
179- if uploaded_paths. is_empty ( ) {
173+ if uploaded_paths_and_ids. is_empty ( ) {
180174 bail ! ( "Failed to upload any files" ) ;
175+ } else {
176+ println ! (
177+ "Successfully uploaded {} file{} to Sentry" ,
178+ uploaded_paths_and_ids. len( ) ,
179+ if uploaded_paths_and_ids. len( ) == 1 {
180+ ""
181+ } else {
182+ "s"
183+ }
184+ ) ;
185+ if uploaded_paths_and_ids. len ( ) < 3 {
186+ for ( path, artifact_id) in & uploaded_paths_and_ids {
187+ let url = format ! ( "{base_url}/{org}/preprod/{project}/{artifact_id}" ) ;
188+ println ! ( " - {} {url}" , path. display( ) ) ;
189+ }
190+ }
181191 }
182192 Ok ( ( ) )
183193}
@@ -337,14 +347,15 @@ fn normalize_directory(path: &Path) -> Result<TempFile> {
337347 Ok ( temp_file)
338348}
339349
350+ /// Returns artifact id if upload was successful.
340351fn upload_file (
341352 api : & AuthenticatedApi ,
342353 bytes : & [ u8 ] ,
343354 org : & str ,
344355 project : & str ,
345356 sha : Option < & str > ,
346357 build_configuration : Option < & str > ,
347- ) -> Result < ( ) > {
358+ ) -> Result < String > {
348359 const SELF_HOSTED_ERROR_HINT : & str = "If you are using a self-hosted Sentry server, \
349360 update to the latest version of Sentry to use the mobile-app upload command.";
350361
@@ -400,7 +411,7 @@ fn upload_file(
400411 println ! ( "Nothing to upload, all files are on the server" ) ;
401412 }
402413
403- poll_assemble (
414+ let response = poll_assemble (
404415 api,
405416 checksum,
406417 & checksums,
@@ -409,7 +420,10 @@ fn upload_file(
409420 sha,
410421 build_configuration,
411422 ) ?;
412- Ok ( ( ) )
423+
424+ response
425+ . artifact_id
426+ . ok_or ( anyhow ! ( "Missing artifactId in response" ) )
413427}
414428
415429fn poll_assemble (
@@ -420,7 +434,7 @@ fn poll_assemble(
420434 project : & str ,
421435 sha : Option < & str > ,
422436 build_configuration : Option < & str > ,
423- ) -> Result < ( ) > {
437+ ) -> Result < AssembleMobileAppResponse > {
424438 debug ! ( "Polling assemble for checksum: {}" , checksum) ;
425439
426440 let progress_style = ProgressStyle :: default_spinner ( ) . template ( "{spinner} Processing files..." ) ;
@@ -453,7 +467,7 @@ fn poll_assemble(
453467 info ! ( "File processing complete" ) ;
454468 }
455469
456- Ok ( ( ) )
470+ Ok ( response )
457471}
458472
459473#[ cfg( not( windows) ) ]
0 commit comments