1
+ use crate :: db:: issue_data:: IssueData ;
1
2
use crate :: {
2
3
config:: AutolabelConfig ,
3
4
github:: { IssuesAction , IssuesEvent , Label } ,
@@ -6,6 +7,16 @@ use crate::{
6
7
use anyhow:: Context as _;
7
8
use tracing as log;
8
9
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
+
9
20
pub ( super ) struct AutolabelInput {
10
21
add : Vec < Label > ,
11
22
remove : Vec < Label > ,
@@ -26,7 +37,16 @@ pub(super) async fn parse_input(
26
37
// FIXME: This will re-apply labels after a push that the user had tried to
27
38
// remove. Not much can be done about that currently; the before/after on
28
39
// synchronize may be straddling a rebase, which will break diff generation.
29
- if event. action == IssuesAction :: Opened || event. action == IssuesAction :: Synchronize {
40
+ if matches ! (
41
+ 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 )
47
+ . await
48
+ . map_err ( |e| e. to_string ( ) ) ?;
49
+
30
50
let files = event
31
51
. issue
32
52
. diff ( & ctx. github )
@@ -69,11 +89,19 @@ pub(super) async fn parse_input(
69
89
name : label. to_owned ( ) ,
70
90
} ) ;
71
91
}
72
- if cfg. new_pr && event. action == IssuesAction :: Opened {
73
- autolabels. push ( Label {
74
- name : label. to_owned ( ) ,
75
- } ) ;
76
- }
92
+ }
93
+
94
+ // Treat the following situations as a "new PR":
95
+ // 1) New PRs opened as non-draft
96
+ // 2) PRs opened as draft that are marked as "ready for review" for the first time.
97
+ let is_new_non_draft_pr = event. action == IssuesAction :: Opened && !event. issue . draft ;
98
+ let is_first_time_ready_for_review =
99
+ event. action == IssuesAction :: ReadyForReview && !state. data . new_pr_labels_applied ;
100
+ if cfg. new_pr && ( is_new_non_draft_pr || is_first_time_ready_for_review) {
101
+ autolabels. push ( Label {
102
+ name : label. to_owned ( ) ,
103
+ } ) ;
104
+ state. data . new_pr_labels_applied = true ;
77
105
}
78
106
79
107
if event. issue . pull_request . is_none ( )
@@ -86,6 +114,8 @@ pub(super) async fn parse_input(
86
114
}
87
115
}
88
116
117
+ state. save ( ) . await . map_err ( |e| e. to_string ( ) ) ?;
118
+
89
119
if !autolabels. is_empty ( ) {
90
120
return Ok ( Some ( AutolabelInput {
91
121
add : autolabels,
0 commit comments