@@ -3,7 +3,6 @@ use tracing as log;
3
3
4
4
use async_trait:: async_trait;
5
5
use chrono:: { DateTime , FixedOffset , Utc } ;
6
- use futures:: stream:: { FuturesUnordered , StreamExt } ;
7
6
use futures:: { future:: BoxFuture , FutureExt } ;
8
7
use hyper:: header:: HeaderValue ;
9
8
use once_cell:: sync:: OnceCell ;
@@ -233,18 +232,6 @@ pub struct Label {
233
232
pub name : String ,
234
233
}
235
234
236
- impl Label {
237
- async fn exists < ' a > ( & ' a self , repo_api_prefix : & ' a str , client : & ' a GithubClient ) -> bool {
238
- #[ allow( clippy:: redundant_pattern_matching) ]
239
- let url = format ! ( "{}/labels/{}" , repo_api_prefix, self . name) ;
240
- match client. send_req ( client. get ( & url) ) . await {
241
- Ok ( _) => true ,
242
- // XXX: Error handling if the request failed for reasons beyond 'label didn't exist'
243
- Err ( _) => false ,
244
- }
245
- }
246
- }
247
-
248
235
#[ derive( Debug , serde:: Deserialize ) ]
249
236
pub struct PullRequestDetails {
250
237
// none for now
@@ -468,39 +455,68 @@ impl Issue {
468
455
Ok ( ( ) )
469
456
}
470
457
471
- pub async fn set_labels (
458
+ pub async fn remove_label ( & self , client : & GithubClient , label : & str ) -> anyhow:: Result < ( ) > {
459
+ log:: info!( "remove_label from {}: {:?}" , self . global_id( ) , label) ;
460
+ // DELETE /repos/:owner/:repo/issues/:number/labels/{name}
461
+ let url = format ! (
462
+ "{repo_url}/issues/{number}/labels/{name}" ,
463
+ repo_url = self . repository( ) . url( ) ,
464
+ number = self . number,
465
+ name = label,
466
+ ) ;
467
+
468
+ if !self . labels ( ) . iter ( ) . any ( |l| l. name == label) {
469
+ log:: info!(
470
+ "remove_label from {}: {:?} already not present, skipping" ,
471
+ self . global_id( ) ,
472
+ label
473
+ ) ;
474
+ return Ok ( ( ) ) ;
475
+ }
476
+
477
+ client
478
+ . _send_req ( client. delete ( & url) )
479
+ . await
480
+ . context ( "failed to delete label" ) ?;
481
+
482
+ Ok ( ( ) )
483
+ }
484
+
485
+ pub async fn add_labels (
472
486
& self ,
473
487
client : & GithubClient ,
474
488
labels : Vec < Label > ,
475
489
) -> anyhow:: Result < ( ) > {
476
- log:: info!( "set_labels {} to {:?}" , self . global_id( ) , labels) ;
477
- // PUT /repos/:owner/:repo/issues/:number/labels
490
+ log:: info!( "add_labels: {} + {:?}" , self . global_id( ) , labels) ;
491
+ // POST /repos/:owner/:repo/issues/:number/labels
478
492
// repo_url = https://api.github.com/repos/Codertocat/Hello-World
479
493
let url = format ! (
480
494
"{repo_url}/issues/{number}/labels" ,
481
495
repo_url = self . repository( ) . url( ) ,
482
496
number = self . number
483
497
) ;
484
498
485
- let mut stream = labels
499
+ // Don't try to add labels already present on this issue.
500
+ let labels = labels
486
501
. into_iter ( )
487
- . map ( |label| async { ( label. exists ( & self . repository ( ) . url ( ) , & client) . await , label) } )
488
- . collect :: < FuturesUnordered < _ > > ( ) ;
489
- let mut labels = Vec :: new ( ) ;
490
- while let Some ( ( true , label) ) = stream. next ( ) . await {
491
- labels. push ( label) ;
502
+ . filter ( |l| !self . labels ( ) . contains ( & l) )
503
+ . map ( |l| l. name )
504
+ . collect :: < Vec < _ > > ( ) ;
505
+
506
+ log:: info!( "add_labels: {} filtered to {:?}" , self . global_id( ) , labels) ;
507
+
508
+ if labels. is_empty ( ) {
509
+ return Ok ( ( ) ) ;
492
510
}
493
511
494
512
#[ derive( serde:: Serialize ) ]
495
513
struct LabelsReq {
496
514
labels : Vec < String > ,
497
515
}
498
516
client
499
- . _send_req ( client. put ( & url) . json ( & LabelsReq {
500
- labels : labels. iter ( ) . map ( |l| l. name . clone ( ) ) . collect ( ) ,
501
- } ) )
517
+ . _send_req ( client. post ( & url) . json ( & LabelsReq { labels } ) )
502
518
. await
503
- . context ( "failed to set labels" ) ?;
519
+ . context ( "failed to add labels" ) ?;
504
520
505
521
Ok ( ( ) )
506
522
}
@@ -659,6 +675,25 @@ impl Issue {
659
675
. context ( "failed to close issue" ) ?;
660
676
Ok ( ( ) )
661
677
}
678
+
679
+ /// Returns the diff in this event, for Open and Synchronize events for now.
680
+ pub async fn diff ( & self , client : & GithubClient ) -> anyhow:: Result < Option < String > > {
681
+ let ( before, after) = if let ( Some ( base) , Some ( head) ) = ( & self . base , & self . head ) {
682
+ ( base. sha . clone ( ) , head. sha . clone ( ) )
683
+ } else {
684
+ return Ok ( None ) ;
685
+ } ;
686
+
687
+ let mut req = client. get ( & format ! (
688
+ "{}/compare/{}...{}" ,
689
+ self . repository( ) . url( ) ,
690
+ before,
691
+ after
692
+ ) ) ;
693
+ req = req. header ( "Accept" , "application/vnd.github.v3.diff" ) ;
694
+ let diff = client. send_req ( req) . await ?;
695
+ Ok ( Some ( String :: from ( String :: from_utf8_lossy ( & diff) ) ) )
696
+ }
662
697
}
663
698
664
699
#[ derive( serde:: Serialize ) ]
@@ -762,13 +797,6 @@ pub struct IssuesEvent {
762
797
pub repository : Repository ,
763
798
/// Some if action is IssuesAction::Labeled, for example
764
799
pub label : Option < Label > ,
765
-
766
- // These fields are the sha fields before/after a synchronize operation,
767
- // used to compute the diff between these two commits.
768
- #[ serde( default ) ]
769
- before : Option < String > ,
770
- #[ serde( default ) ]
771
- after : Option < String > ,
772
800
}
773
801
774
802
#[ derive( Debug , serde:: Deserialize ) ]
@@ -794,37 +822,7 @@ pub fn files_changed(diff: &str) -> Vec<&str> {
794
822
files
795
823
}
796
824
797
- impl IssuesEvent {
798
- /// Returns the diff in this event, for Open and Synchronize events for now.
799
- pub async fn diff_between ( & self , client : & GithubClient ) -> anyhow:: Result < Option < String > > {
800
- let ( before, after) = if self . action == IssuesAction :: Synchronize {
801
- (
802
- self . before
803
- . clone ( )
804
- . expect ( "synchronize has before populated" ) ,
805
- self . after . clone ( ) . expect ( "synchronize has after populated" ) ,
806
- )
807
- } else if self . action == IssuesAction :: Opened {
808
- if let ( Some ( base) , Some ( head) ) = ( & self . issue . base , & self . issue . head ) {
809
- ( base. sha . clone ( ) , head. sha . clone ( ) )
810
- } else {
811
- return Ok ( None ) ;
812
- }
813
- } else {
814
- return Ok ( None ) ;
815
- } ;
816
-
817
- let mut req = client. get ( & format ! (
818
- "{}/compare/{}...{}" ,
819
- self . issue. repository( ) . url( ) ,
820
- before,
821
- after
822
- ) ) ;
823
- req = req. header ( "Accept" , "application/vnd.github.v3.diff" ) ;
824
- let diff = client. send_req ( req) . await ?;
825
- Ok ( Some ( String :: from ( String :: from_utf8_lossy ( & diff) ) ) )
826
- }
827
- }
825
+ impl IssuesEvent { }
828
826
829
827
#[ derive( Debug , serde:: Deserialize ) ]
830
828
pub struct IssueSearchResult {
@@ -1282,6 +1280,7 @@ impl GithubClient {
1282
1280
self . client . post ( url) . configure ( self )
1283
1281
}
1284
1282
1283
+ #[ allow( unused) ]
1285
1284
fn put ( & self , url : & str ) -> RequestBuilder {
1286
1285
log:: trace!( "put {:?}" , url) ;
1287
1286
self . client . put ( url) . configure ( self )
0 commit comments