@@ -366,17 +366,36 @@ impl IssueRepository {
366
366
)
367
367
}
368
368
369
- async fn has_label ( & self , client : & GithubClient , label : & str ) -> bool {
369
+ async fn has_label ( & self , client : & GithubClient , label : & str ) -> anyhow :: Result < bool > {
370
370
#[ allow( clippy:: redundant_pattern_matching) ]
371
371
let url = format ! ( "{}/labels/{}" , self . url( ) , label) ;
372
- match client. send_req ( client. get ( & url) ) . await {
373
- Ok ( _) => true ,
374
- // XXX: Error handling if the request failed for reasons beyond 'label didn't exist'
375
- Err ( _) => false ,
372
+ match client. _send_req ( client. get ( & url) ) . await {
373
+ Ok ( ( _, _) ) => Ok ( true ) ,
374
+ Err ( e) => {
375
+ if e. downcast_ref :: < reqwest:: Error > ( ) . map_or ( false , |e| e. status ( ) == Some ( StatusCode :: NOT_FOUND ) ) {
376
+ Ok ( false )
377
+ } else {
378
+ Err ( e)
379
+ }
380
+ }
376
381
}
377
382
}
378
383
}
379
384
385
+ #[ derive( Debug ) ]
386
+ pub ( crate ) struct UnknownLabels {
387
+ labels : Vec < String > ,
388
+ }
389
+
390
+ impl fmt:: Display for UnknownLabels {
391
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
392
+ f. write_str ( "Unknown labels:\n - " ) ?;
393
+ write ! ( f, "{}" , & self . labels. join( "\n - " ) )
394
+ }
395
+ }
396
+
397
+ impl std:: error:: Error for UnknownLabels { }
398
+
380
399
impl Issue {
381
400
pub fn to_zulip_github_reference ( & self ) -> ZulipGitHubReference {
382
401
ZulipGitHubReference {
@@ -519,18 +538,27 @@ impl Issue {
519
538
return Ok ( ( ) ) ;
520
539
}
521
540
522
- for label in & labels {
523
- if !self . repository ( ) . has_label ( client, & label) . await {
524
- anyhow:: bail!( "Label {} does not exist in {}" , label, self . global_id( ) ) ;
541
+ let mut unknown_labels = vec ! [ ] ;
542
+ let mut known_labels = vec ! [ ] ;
543
+ for label in labels {
544
+ if !self . repository ( ) . has_label ( client, & label) . await ? {
545
+ unknown_labels. push ( label) ;
546
+ } else {
547
+ known_labels. push ( label) ;
525
548
}
526
549
}
527
550
551
+ if !unknown_labels. is_empty ( ) {
552
+ return Err ( UnknownLabels { labels : unknown_labels } . into ( ) ) ;
553
+ }
554
+
528
555
#[ derive( serde:: Serialize ) ]
529
556
struct LabelsReq {
530
557
labels : Vec < String > ,
531
558
}
559
+
532
560
client
533
- . _send_req ( client. post ( & url) . json ( & LabelsReq { labels } ) )
561
+ . _send_req ( client. post ( & url) . json ( & LabelsReq { labels : known_labels } ) )
534
562
. await
535
563
. context ( "failed to add labels" ) ?;
536
564
@@ -1382,6 +1410,12 @@ pub trait IssuesQuery {
1382
1410
mod tests {
1383
1411
use super :: * ;
1384
1412
1413
+ #[ test]
1414
+ fn display_labels ( ) {
1415
+ let x = UnknownLabels { labels : vec ! [ "A-bootstrap" . into( ) , "xxx" . into( ) ] } ;
1416
+ assert_eq ! ( x. to_string( ) , "Unknown labels:\n - A-bootstrap\n - xxx" ) ;
1417
+ }
1418
+
1385
1419
#[ test]
1386
1420
fn extract_one_file ( ) {
1387
1421
let input = r##"\
0 commit comments