@@ -119,6 +119,156 @@ pub fn make_command(command: Command) -> Command {
119119 )
120120}
121121
122+ pub fn execute ( matches : & ArgMatches ) -> Result < ( ) > {
123+ let config = Config :: current ( ) ;
124+ let path_strings = matches
125+ . get_many :: < String > ( "paths" )
126+ . expect ( "paths argument is required" ) ;
127+
128+ // Determine if we should collect git metadata
129+ let should_collect_git_metadata =
130+ if let Some ( & git_metadata) = matches. get_one :: < bool > ( "git_metadata" ) {
131+ // --git-metadata or --git-metadata=true/false was specified
132+ git_metadata
133+ } else {
134+ // Default behavior: auto-detect CI
135+ is_ci ( )
136+ } ;
137+
138+ debug ! (
139+ "Git metadata collection: {}" ,
140+ if should_collect_git_metadata {
141+ "enabled"
142+ } else {
143+ "disabled (use --git-metadata to enable)"
144+ }
145+ ) ;
146+
147+ // Always collect git metadata, but only perform automatic inference when enabled
148+ let git_metadata = collect_git_metadata ( matches, & config, should_collect_git_metadata) ;
149+
150+ let build_configuration = matches. get_one ( "build_configuration" ) . map ( String :: as_str) ;
151+ let release_notes = matches. get_one ( "release_notes" ) . map ( String :: as_str) ;
152+
153+ let api = Api :: current ( ) ;
154+ let authenticated_api = api. authenticated ( ) ?;
155+
156+ debug ! ( "Starting upload for {} paths" , path_strings. len( ) ) ;
157+
158+ let mut normalized_zips = vec ! [ ] ;
159+ for path_string in path_strings {
160+ let path: & Path = path_string. as_ref ( ) ;
161+ debug ! ( "Processing artifact at path: {}" , path. display( ) ) ;
162+
163+ if !path. exists ( ) {
164+ return Err ( anyhow ! ( "Path does not exist: {}" , path. display( ) ) ) ;
165+ }
166+
167+ let byteview = ByteView :: open ( path) ?;
168+ debug ! ( "Loaded file with {} bytes" , byteview. len( ) ) ;
169+
170+ validate_is_supported_build ( path, & byteview) ?;
171+
172+ let normalized_zip = if path. is_file ( ) {
173+ debug ! ( "Normalizing file: {}" , path. display( ) ) ;
174+ handle_file ( path, & byteview) ?
175+ } else if path. is_dir ( ) {
176+ debug ! ( "Normalizing directory: {}" , path. display( ) ) ;
177+ handle_directory ( path) . with_context ( || {
178+ format ! (
179+ "Failed to generate uploadable bundle for directory {}" ,
180+ path. display( )
181+ )
182+ } ) ?
183+ } else {
184+ Err ( anyhow ! (
185+ "Path {} is neither a file nor a directory, cannot upload" ,
186+ path. display( )
187+ ) ) ?
188+ } ;
189+
190+ debug ! (
191+ "Successfully normalized to: {}" ,
192+ normalized_zip. path( ) . display( )
193+ ) ;
194+ normalized_zips. push ( ( path, normalized_zip) ) ;
195+ }
196+
197+ let config = Config :: current ( ) ;
198+ let ( org, project) = config. get_org_and_project ( matches) ?;
199+
200+ let mut uploaded_paths_and_urls = vec ! [ ] ;
201+ let mut errored_paths_and_reasons = vec ! [ ] ;
202+ for ( path, zip) in normalized_zips {
203+ info ! ( "Uploading file: {}" , path. display( ) ) ;
204+ let bytes = ByteView :: open ( zip. path ( ) ) ?;
205+ let vcs_info = VcsInfo {
206+ head_sha : git_metadata. head_sha ,
207+ base_sha : git_metadata. base_sha ,
208+ vcs_provider : & git_metadata. vcs_provider ,
209+ head_repo_name : & git_metadata. head_repo_name ,
210+ base_repo_name : & git_metadata. base_repo_name ,
211+ head_ref : & git_metadata. head_ref ,
212+ base_ref : & git_metadata. base_ref ,
213+ pr_number : git_metadata. pr_number . as_ref ( ) ,
214+ } ;
215+ match upload_file (
216+ & authenticated_api,
217+ & bytes,
218+ & org,
219+ & project,
220+ build_configuration,
221+ release_notes,
222+ & vcs_info,
223+ ) {
224+ Ok ( artifact_url) => {
225+ info ! ( "Successfully uploaded file: {}" , path. display( ) ) ;
226+ uploaded_paths_and_urls. push ( ( path. to_path_buf ( ) , artifact_url) ) ;
227+ }
228+ Err ( e) => {
229+ debug ! ( "Failed to upload file at path {}: {e}" , path. display( ) ) ;
230+ errored_paths_and_reasons. push ( ( path. to_path_buf ( ) , e) ) ;
231+ }
232+ }
233+ }
234+
235+ if !errored_paths_and_reasons. is_empty ( ) {
236+ warn ! (
237+ "Failed to upload {} file{}:" ,
238+ errored_paths_and_reasons. len( ) ,
239+ if errored_paths_and_reasons. len( ) == 1 {
240+ ""
241+ } else {
242+ "s"
243+ }
244+ ) ;
245+ for ( path, reason) in errored_paths_and_reasons {
246+ warn ! ( " - {}" , path. display( ) ) ;
247+ warn ! ( " Error: {reason:#}" ) ;
248+ }
249+ }
250+
251+ if uploaded_paths_and_urls. is_empty ( ) {
252+ bail ! ( "Failed to upload any files" ) ;
253+ } else {
254+ println ! (
255+ "Successfully uploaded {} file{} to Sentry" ,
256+ uploaded_paths_and_urls. len( ) ,
257+ if uploaded_paths_and_urls. len( ) == 1 {
258+ ""
259+ } else {
260+ "s"
261+ }
262+ ) ;
263+ if uploaded_paths_and_urls. len ( ) < 3 {
264+ for ( path, artifact_url) in & uploaded_paths_and_urls {
265+ println ! ( " - {} ({artifact_url})" , path. display( ) ) ;
266+ }
267+ }
268+ }
269+ Ok ( ( ) )
270+ }
271+
122272/// Holds git metadata collected for build uploads.
123273#[ derive( Debug , Default ) ]
124274struct GitMetadata {
@@ -354,156 +504,6 @@ fn collect_git_metadata(matches: &ArgMatches, config: &Config, auto_collect: boo
354504 }
355505}
356506
357- pub fn execute ( matches : & ArgMatches ) -> Result < ( ) > {
358- let config = Config :: current ( ) ;
359- let path_strings = matches
360- . get_many :: < String > ( "paths" )
361- . expect ( "paths argument is required" ) ;
362-
363- // Determine if we should collect git metadata
364- let should_collect_git_metadata =
365- if let Some ( & git_metadata) = matches. get_one :: < bool > ( "git_metadata" ) {
366- // --git-metadata or --git-metadata=true/false was specified
367- git_metadata
368- } else {
369- // Default behavior: auto-detect CI
370- is_ci ( )
371- } ;
372-
373- debug ! (
374- "Git metadata collection: {}" ,
375- if should_collect_git_metadata {
376- "enabled"
377- } else {
378- "disabled (use --git-metadata to enable)"
379- }
380- ) ;
381-
382- // Always collect git metadata, but only perform automatic inference when enabled
383- let git_metadata = collect_git_metadata ( matches, & config, should_collect_git_metadata) ;
384-
385- let build_configuration = matches. get_one ( "build_configuration" ) . map ( String :: as_str) ;
386- let release_notes = matches. get_one ( "release_notes" ) . map ( String :: as_str) ;
387-
388- let api = Api :: current ( ) ;
389- let authenticated_api = api. authenticated ( ) ?;
390-
391- debug ! ( "Starting upload for {} paths" , path_strings. len( ) ) ;
392-
393- let mut normalized_zips = vec ! [ ] ;
394- for path_string in path_strings {
395- let path: & Path = path_string. as_ref ( ) ;
396- debug ! ( "Processing artifact at path: {}" , path. display( ) ) ;
397-
398- if !path. exists ( ) {
399- return Err ( anyhow ! ( "Path does not exist: {}" , path. display( ) ) ) ;
400- }
401-
402- let byteview = ByteView :: open ( path) ?;
403- debug ! ( "Loaded file with {} bytes" , byteview. len( ) ) ;
404-
405- validate_is_supported_build ( path, & byteview) ?;
406-
407- let normalized_zip = if path. is_file ( ) {
408- debug ! ( "Normalizing file: {}" , path. display( ) ) ;
409- handle_file ( path, & byteview) ?
410- } else if path. is_dir ( ) {
411- debug ! ( "Normalizing directory: {}" , path. display( ) ) ;
412- handle_directory ( path) . with_context ( || {
413- format ! (
414- "Failed to generate uploadable bundle for directory {}" ,
415- path. display( )
416- )
417- } ) ?
418- } else {
419- Err ( anyhow ! (
420- "Path {} is neither a file nor a directory, cannot upload" ,
421- path. display( )
422- ) ) ?
423- } ;
424-
425- debug ! (
426- "Successfully normalized to: {}" ,
427- normalized_zip. path( ) . display( )
428- ) ;
429- normalized_zips. push ( ( path, normalized_zip) ) ;
430- }
431-
432- let config = Config :: current ( ) ;
433- let ( org, project) = config. get_org_and_project ( matches) ?;
434-
435- let mut uploaded_paths_and_urls = vec ! [ ] ;
436- let mut errored_paths_and_reasons = vec ! [ ] ;
437- for ( path, zip) in normalized_zips {
438- info ! ( "Uploading file: {}" , path. display( ) ) ;
439- let bytes = ByteView :: open ( zip. path ( ) ) ?;
440- let vcs_info = VcsInfo {
441- head_sha : git_metadata. head_sha ,
442- base_sha : git_metadata. base_sha ,
443- vcs_provider : & git_metadata. vcs_provider ,
444- head_repo_name : & git_metadata. head_repo_name ,
445- base_repo_name : & git_metadata. base_repo_name ,
446- head_ref : & git_metadata. head_ref ,
447- base_ref : & git_metadata. base_ref ,
448- pr_number : git_metadata. pr_number . as_ref ( ) ,
449- } ;
450- match upload_file (
451- & authenticated_api,
452- & bytes,
453- & org,
454- & project,
455- build_configuration,
456- release_notes,
457- & vcs_info,
458- ) {
459- Ok ( artifact_url) => {
460- info ! ( "Successfully uploaded file: {}" , path. display( ) ) ;
461- uploaded_paths_and_urls. push ( ( path. to_path_buf ( ) , artifact_url) ) ;
462- }
463- Err ( e) => {
464- debug ! ( "Failed to upload file at path {}: {e}" , path. display( ) ) ;
465- errored_paths_and_reasons. push ( ( path. to_path_buf ( ) , e) ) ;
466- }
467- }
468- }
469-
470- if !errored_paths_and_reasons. is_empty ( ) {
471- warn ! (
472- "Failed to upload {} file{}:" ,
473- errored_paths_and_reasons. len( ) ,
474- if errored_paths_and_reasons. len( ) == 1 {
475- ""
476- } else {
477- "s"
478- }
479- ) ;
480- for ( path, reason) in errored_paths_and_reasons {
481- warn ! ( " - {}" , path. display( ) ) ;
482- warn ! ( " Error: {reason:#}" ) ;
483- }
484- }
485-
486- if uploaded_paths_and_urls. is_empty ( ) {
487- bail ! ( "Failed to upload any files" ) ;
488- } else {
489- println ! (
490- "Successfully uploaded {} file{} to Sentry" ,
491- uploaded_paths_and_urls. len( ) ,
492- if uploaded_paths_and_urls. len( ) == 1 {
493- ""
494- } else {
495- "s"
496- }
497- ) ;
498- if uploaded_paths_and_urls. len ( ) < 3 {
499- for ( path, artifact_url) in & uploaded_paths_and_urls {
500- println ! ( " - {} ({artifact_url})" , path. display( ) ) ;
501- }
502- }
503- }
504- Ok ( ( ) )
505- }
506-
507507fn handle_file ( path : & Path , byteview : & ByteView ) -> Result < TempFile > {
508508 // Handle IPA files by converting them to XCArchive
509509 #[ cfg( all( target_os = "macos" , target_arch = "aarch64" ) ) ]
0 commit comments