1- use  crate :: db:: issue_data:: IssueData ; 
21use  crate :: { 
32    config:: AutolabelConfig , 
43    github:: { IssuesAction ,  IssuesEvent ,  Label } , 
@@ -7,16 +6,6 @@ use crate::{
76use  anyhow:: Context  as  _; 
87use  tracing as  log; 
98
10- /// Key for the state in the database 
11- const  AUTOLABEL_KEY :  & str  = "autolabel" ; 
12- 
13- /// State stored in the database 
14- #[ derive( Debug ,  Default ,  PartialEq ,  Clone ,  serde:: Deserialize ,  serde:: Serialize ) ]  
15- struct  AutolabelState  { 
16-     /// If true, then `autolabel.new_pr` labels have already been applied to this PR. 
17- new_pr_labels_applied :  bool , 
18- } 
19- 
209pub ( super )  struct  AutolabelInput  { 
2110    add :  Vec < Label > , 
2211    remove :  Vec < Label > , 
@@ -37,25 +26,35 @@ pub(super) async fn parse_input(
3726    // FIXME: This will re-apply labels after a push that the user had tried to 
3827    // remove. Not much can be done about that currently; the before/after on 
3928    // synchronize may be straddling a rebase, which will break diff generation. 
40-     if  matches ! ( 
29+     let  can_trigger_files =  matches ! ( 
4130        event. action, 
42-         IssuesAction :: Opened  | IssuesAction :: Synchronize  | IssuesAction :: ReadyForReview 
43-     )  { 
44-         let  mut  db = ctx. db . get ( ) . await ; 
45-         let  mut  state:  IssueData < ' _ ,  AutolabelState >  =
46-             IssueData :: load ( & mut  db,  & event. issue ,  AUTOLABEL_KEY ) 
31+         IssuesAction :: Opened  | IssuesAction :: Synchronize 
32+     ) ; 
33+ 
34+     if  can_trigger_files
35+         || matches ! ( 
36+             event. action, 
37+             IssuesAction :: Closed 
38+                 | IssuesAction :: Reopened 
39+                 | IssuesAction :: ReadyForReview 
40+                 | IssuesAction :: ConvertedToDraft 
41+         ) 
42+     { 
43+         let  files = if  can_trigger_files { 
44+             event
45+                 . issue 
46+                 . diff ( & ctx. github ) 
4747                . await 
48-                 . map_err ( |e| e. to_string ( ) ) ?; 
48+                 . map_err ( |e| { 
49+                     log:: error!( "failed to fetch diff: {:?}" ,  e) ; 
50+                 } ) 
51+                 . unwrap_or_default ( ) 
52+         }  else  { 
53+             Default :: default ( ) 
54+         } ; 
4955
50-         let  files = event
51-             . issue 
52-             . diff ( & ctx. github ) 
53-             . await 
54-             . map_err ( |e| { 
55-                 log:: error!( "failed to fetch diff: {:?}" ,  e) ; 
56-             } ) 
57-             . unwrap_or_default ( ) ; 
5856        let  mut  autolabels = Vec :: new ( ) ; 
57+         let  mut  to_remove = Vec :: new ( ) ; 
5958
6059        ' outer:  for  ( label,  cfg)  in  config. labels . iter ( )  { 
6160            let  exclude_patterns:  Vec < glob:: Pattern >  = cfg
@@ -96,17 +95,28 @@ pub(super) async fn parse_input(
9695                } 
9796
9897                // Treat the following situations as a "new PR": 
99-                 // 1) New  PRs opened as non- draft 
100-                 // 2) PRs opened as draft that are marked as  "ready for review" for the first time.  
101-                 let  is_new_non_draft_pr  =
102-                     event. action  ==  IssuesAction :: Opened  && !event . issue . draft ; 
103-                 let  is_first_time_ready_for_review = event . action  ==  IssuesAction :: ReadyForReview 
104-                     && !state . data . new_pr_labels_applied ; 
105-                 if  cfg. new_pr  && ( is_new_non_draft_pr  || is_first_time_ready_for_review )  { 
98+                 // 1) PRs that were (re) opened and are not  draft 
99+                 // 2) PRs that have been converted from a draft to being  "ready for review" 
100+                 let  is_opened_non_draft  =
101+                     matches ! ( event. action,   IssuesAction :: Opened  |  IssuesAction :: Reopened ) 
102+                         && !event . issue . draft ; 
103+                 let  is_ready_for_review = event . action  ==  IssuesAction :: ReadyForReview ; 
104+                 if  cfg. new_pr  && ( is_opened_non_draft  || is_ready_for_review )  { 
106105                    autolabels. push ( Label  { 
107106                        name :  label. to_owned ( ) , 
108107                    } ) ; 
109-                     state. data . new_pr_labels_applied  = true ; 
108+                 } 
109+ 
110+                 // If a PR is converted to draft or closed, remove all the "new PR" labels 
111+                 if  cfg. new_pr 
112+                     && matches ! ( 
113+                         event. action, 
114+                         IssuesAction :: ConvertedToDraft  | IssuesAction :: Closed 
115+                     ) 
116+                 { 
117+                     to_remove. push ( Label  { 
118+                         name :  label. to_owned ( ) , 
119+                     } ) ; 
110120                } 
111121            }  else  { 
112122                if  cfg. new_issue  && event. action  == IssuesAction :: Opened  { 
@@ -117,12 +127,10 @@ pub(super) async fn parse_input(
117127            } 
118128        } 
119129
120-         state. save ( ) . await . map_err ( |e| e. to_string ( ) ) ?; 
121- 
122-         if  !autolabels. is_empty ( )  { 
130+         if  !autolabels. is_empty ( )  || !to_remove. is_empty ( )  { 
123131            return  Ok ( Some ( AutolabelInput  { 
124132                add :  autolabels, 
125-                 remove :  vec ! [ ] , 
133+                 remove :  to_remove , 
126134            } ) ) ; 
127135        } 
128136    } 
0 commit comments