@@ -17,7 +17,7 @@ use tracing::{info, warn};
1717use crate :: {
1818 cli:: PublishArgs ,
1919 commands:: { print_output, targeting} ,
20- errors:: { message_with_hint , CargoMonoError , ErrorKind , Result } ,
20+ errors:: { message_with_details , CargoMonoError , ErrorKind , Result } ,
2121 types:: { OutputFormat , PublishSkipReason } ,
2222 workspace:: Workspace ,
2323 CargoMonoApp ,
@@ -324,8 +324,11 @@ pub fn execute(args: &PublishArgs, output: OutputFormat, app: &CargoMonoApp) ->
324324 attempts,
325325 error : format_publish_failure (
326326 & package_name,
327+ attempts,
327328 & publish_output. status . to_string ( ) ,
328329 & details,
330+ args. dry_run ,
331+ args. registry . as_deref ( ) ,
329332 ) ,
330333 } ) ;
331334 published_or_skipped = true ;
@@ -338,7 +341,12 @@ pub fn execute(args: &PublishArgs, output: OutputFormat, app: &CargoMonoApp) ->
338341 failed. push ( FailedPackage {
339342 name : package_name. clone ( ) ,
340343 attempts,
341- error : format_publish_retry_limit_failure ( & package_name, attempts) ,
344+ error : format_publish_retry_limit_failure (
345+ & package_name,
346+ attempts,
347+ args. dry_run ,
348+ args. registry . as_deref ( ) ,
349+ ) ,
342350 } ) ;
343351 }
344352 }
@@ -390,9 +398,10 @@ pub fn execute(args: &PublishArgs, output: OutputFormat, app: &CargoMonoApp) ->
390398
391399 for item in & result. failed {
392400 human_lines. push ( format ! (
393- "- failed {} (attempts={}): {} " ,
394- item. name, item. attempts, item . error
401+ "- failed {} (attempts={}):" ,
402+ item. name, item. attempts
395403 ) ) ;
404+ human_lines. push ( indent_multiline ( & item. error , " " ) ) ;
396405 }
397406
398407 print_output ( output, & human_lines. join ( "\n " ) , & result) ?;
@@ -852,33 +861,63 @@ fn run_publish_command(package: &str, dry_run: bool, registry: Option<&str>) ->
852861 }
853862
854863 command. output ( ) . map_err ( |error| {
855- CargoMonoError :: with_hint (
864+ CargoMonoError :: with_details (
856865 ErrorKind :: Cargo ,
857- format ! ( "Failed to start `cargo publish` for package `{package}`: {error}" ) ,
866+ "Failed to start `cargo publish` command." ,
867+ vec ! [
868+ ( "package" , package. to_string( ) ) ,
869+ ( "dry_run" , dry_run. to_string( ) ) ,
870+ ( "registry" , registry. unwrap_or( "default" ) . to_string( ) ) ,
871+ ( "error" , error. to_string( ) ) ,
872+ ] ,
858873 "Ensure Cargo is installed, the package exists, and registry credentials are \
859874 configured before retrying.",
860875 )
861876 } )
862877}
863878
864- fn format_publish_failure ( package : & str , status : & str , raw_details : & str ) -> String {
879+ fn format_publish_failure (
880+ package : & str ,
881+ attempts : usize ,
882+ status : & str ,
883+ raw_details : & str ,
884+ dry_run : bool ,
885+ registry : Option < & str > ,
886+ ) -> String {
865887 let details = compact_error_details ( raw_details) ;
866- let summary = if details. is_empty ( ) {
867- format ! ( "`cargo publish` failed for package `{package}` with status {status}." )
868- } else {
869- format ! ( "`cargo publish` failed for package `{package}`: {details}" )
870- } ;
871- message_with_hint (
872- summary,
888+ let mut context = vec ! [
889+ ( "package" , package. to_string( ) ) ,
890+ ( "attempt" , attempts. to_string( ) ) ,
891+ ( "status" , status. to_string( ) ) ,
892+ ( "dry_run" , dry_run. to_string( ) ) ,
893+ ( "registry" , registry. unwrap_or( "default" ) . to_string( ) ) ,
894+ ] ;
895+ if !details. is_empty ( ) {
896+ context. push ( ( "details_excerpt" , details) ) ;
897+ }
898+
899+ message_with_details (
900+ "`cargo publish` failed for package." ,
901+ & context,
873902 "Verify package metadata, registry access, and network connectivity, then retry." ,
874903 )
875904}
876905
877- fn format_publish_retry_limit_failure ( package : & str , attempts : usize ) -> String {
878- message_with_hint (
879- format ! (
880- "`cargo publish` did not complete for package `{package}` within {attempts} attempts."
881- ) ,
906+ fn format_publish_retry_limit_failure (
907+ package : & str ,
908+ attempts : usize ,
909+ dry_run : bool ,
910+ registry : Option < & str > ,
911+ ) -> String {
912+ message_with_details (
913+ "`cargo publish` did not complete within retry attempts." ,
914+ & [
915+ ( "package" , package. to_string ( ) ) ,
916+ ( "attempts" , attempts. to_string ( ) ) ,
917+ ( "max_attempts" , MAX_PUBLISH_ATTEMPTS . to_string ( ) ) ,
918+ ( "dry_run" , dry_run. to_string ( ) ) ,
919+ ( "registry" , registry. unwrap_or ( "default" ) . to_string ( ) ) ,
920+ ] ,
882921 "Wait for index propagation or rate limits to clear, then rerun publish." ,
883922 )
884923}
@@ -887,6 +926,13 @@ fn compact_error_details(raw: &str) -> String {
887926 raw. split_whitespace ( ) . collect :: < Vec < _ > > ( ) . join ( " " )
888927}
889928
929+ fn indent_multiline ( raw : & str , prefix : & str ) -> String {
930+ raw. lines ( )
931+ . map ( |line| format ! ( "{prefix}{line}" ) )
932+ . collect :: < Vec < _ > > ( )
933+ . join ( "\n " )
934+ }
935+
890936fn retry_delay ( attempt : usize ) -> Duration {
891937 match attempt {
892938 1 => Duration :: from_secs ( 2 ) ,
@@ -994,25 +1040,40 @@ mod tests {
9941040
9951041 #[ test]
9961042 fn format_publish_failure_uses_status_when_no_details_exist ( ) {
997- let message = format_publish_failure ( "alpha" , "exit status: 101" , "" ) ;
998- assert ! ( message
999- . contains( "`cargo publish` failed for package `alpha` with status exit status: 101." ) ) ;
1043+ let message =
1044+ format_publish_failure ( "alpha" , 1 , "exit status: 101" , "" , false , Some ( "crates-io" ) ) ;
1045+ assert ! ( message. contains( "Summary: `cargo publish` failed for package." ) ) ;
1046+ assert ! ( message. contains( "package=alpha" ) ) ;
1047+ assert ! ( message. contains( "attempt=1" ) ) ;
1048+ assert ! ( message. contains( "status=exit status: 101" ) ) ;
10001049 assert ! ( message. contains( "Hint: " ) ) ;
10011050 }
10021051
10031052 #[ test]
10041053 fn format_publish_failure_compacts_multiline_details ( ) {
1005- let message = format_publish_failure ( "alpha" , "ignored" , "error:\n network timeout\n " ) ;
1006- assert ! (
1007- message. contains( "`cargo publish` failed for package `alpha`: error: network timeout" )
1054+ let message = format_publish_failure (
1055+ "alpha" ,
1056+ 2 ,
1057+ "exit status: 101" ,
1058+ "error:\n network timeout\n " ,
1059+ true ,
1060+ None ,
10081061 ) ;
1062+ assert ! ( message. contains( "details_excerpt=error: network timeout" ) ) ;
1063+ assert ! ( message. contains( "dry_run=true" ) ) ;
1064+ assert ! ( message. contains( "registry=default" ) ) ;
10091065 assert ! ( message. contains( "Hint: " ) ) ;
10101066 }
10111067
10121068 #[ test]
10131069 fn format_publish_retry_limit_failure_includes_hint ( ) {
1014- let message = format_publish_retry_limit_failure ( "alpha" , 3 ) ;
1015- assert ! ( message. contains( "within 3 attempts." ) ) ;
1070+ let message = format_publish_retry_limit_failure ( "alpha" , 3 , false , Some ( "internal" ) ) ;
1071+ assert ! (
1072+ message. contains( "Summary: `cargo publish` did not complete within retry attempts." )
1073+ ) ;
1074+ assert ! ( message. contains( "attempts=3" ) ) ;
1075+ assert ! ( message. contains( "max_attempts=3" ) ) ;
1076+ assert ! ( message. contains( "registry=internal" ) ) ;
10161077 assert ! ( message. contains( "Hint: " ) ) ;
10171078 }
10181079
0 commit comments