1
+ use std:: collections:: HashSet ;
2
+
1
3
use anyhow:: bail;
4
+ use anyhow:: Context as _;
2
5
3
6
use super :: Context ;
4
7
use crate :: {
5
8
config:: Config ,
6
9
db:: issue_data:: IssueData ,
7
- github:: { Event , IssuesAction , IssuesEvent , ReportedContentClassifiers } ,
10
+ github:: { Event , IssuesAction , IssuesEvent , Label , ReportedContentClassifiers } ,
8
11
} ;
9
12
10
13
#[ cfg( test) ]
@@ -25,6 +28,8 @@ struct CheckCommitsWarningsState {
25
28
last_warnings : Vec < String > ,
26
29
/// ID of the most recent warning comment.
27
30
last_warned_comment : Option < String > ,
31
+ /// List of the last labels added.
32
+ last_labels : Vec < String > ,
28
33
}
29
34
30
35
pub ( super ) async fn handle ( ctx : & Context , event : & Event , config : & Config ) -> anyhow:: Result < ( ) > {
@@ -49,6 +54,7 @@ pub(super) async fn handle(ctx: &Context, event: &Event, config: &Config) -> any
49
54
let commits = event. issue . commits ( & ctx. github ) . await ?;
50
55
51
56
let mut warnings = Vec :: new ( ) ;
57
+ let mut labels = Vec :: new ( ) ;
52
58
53
59
// Compute the warnings
54
60
if let Some ( assign_config) = & config. assign {
@@ -72,14 +78,15 @@ pub(super) async fn handle(ctx: &Context, event: &Event, config: &Config) -> any
72
78
warnings. extend ( issue_links:: issue_links_in_commits ( issue_links, & commits) ) ;
73
79
}
74
80
75
- handle_warnings ( ctx, event, warnings) . await
81
+ handle_warnings_and_labels ( ctx, event, warnings, labels ) . await
76
82
}
77
83
78
84
// Add, hide or hide&add a comment with the warnings.
79
- async fn handle_warnings (
85
+ async fn handle_warnings_and_labels (
80
86
ctx : & Context ,
81
87
event : & IssuesEvent ,
82
88
warnings : Vec < String > ,
89
+ labels : Vec < String > ,
83
90
) -> anyhow:: Result < ( ) > {
84
91
// Get the state of the warnings for this PR in the database.
85
92
let mut db = ctx. db . get ( ) . await ;
@@ -105,10 +112,8 @@ async fn handle_warnings(
105
112
let warning = warning_from_warnings ( & warnings) ;
106
113
let comment = event. issue . post_comment ( & ctx. github , & warning) . await ?;
107
114
108
- // Save new state in the database
109
115
state. data . last_warnings = warnings;
110
116
state. data . last_warned_comment = Some ( comment. node_id ) ;
111
- state. save ( ) . await ?;
112
117
} else if warnings. is_empty ( ) {
113
118
// No warnings to be shown, let's resolve a previous warnings comment, if there was one.
114
119
if let Some ( last_warned_comment_id) = state. data . last_warned_comment {
@@ -123,10 +128,46 @@ async fn handle_warnings(
123
128
124
129
state. data . last_warnings = Vec :: new ( ) ;
125
130
state. data . last_warned_comment = None ;
126
- state. save ( ) . await ?;
127
131
}
128
132
}
129
133
134
+ // Handle the labels, add the new ones, remove the one no longer required, or don't do anything
135
+ if !state. data . last_labels . is_empty ( ) || !labels. is_empty ( ) {
136
+ let ( labels_to_remove, labels_to_add) =
137
+ calculate_label_changes ( & state. data . last_labels , & labels) ;
138
+
139
+ // Remove the labels no longer required
140
+ if !labels_to_remove. is_empty ( ) {
141
+ for label in labels_to_remove {
142
+ event
143
+ . issue
144
+ . remove_label ( & ctx. github , & label)
145
+ . await
146
+ . context ( "failed to remove a label in check_commits" ) ?;
147
+ }
148
+ }
149
+
150
+ // Add the labels that are now required
151
+ if !labels_to_add. is_empty ( ) {
152
+ event
153
+ . issue
154
+ . add_labels (
155
+ & ctx. github ,
156
+ labels_to_add
157
+ . into_iter ( )
158
+ . map ( |name| Label { name } )
159
+ . collect ( ) ,
160
+ )
161
+ . await
162
+ . context ( "failed to add labels in check_commits" ) ?;
163
+ }
164
+
165
+ state. data . last_labels = labels;
166
+ }
167
+
168
+ // Save new state in the database
169
+ state. save ( ) . await ?;
170
+
130
171
Ok ( ( ) )
131
172
}
132
173
@@ -139,6 +180,20 @@ fn warning_from_warnings(warnings: &[String]) -> String {
139
180
format ! ( ":warning: **Warning** :warning:\n \n {}" , warnings. join( "\n " ) )
140
181
}
141
182
183
+ // Calculate the label changes
184
+ fn calculate_label_changes (
185
+ previous : & Vec < String > ,
186
+ current : & Vec < String > ,
187
+ ) -> ( Vec < String > , Vec < String > ) {
188
+ let previous_set: HashSet < String > = previous. into_iter ( ) . cloned ( ) . collect ( ) ;
189
+ let current_set: HashSet < String > = current. into_iter ( ) . cloned ( ) . collect ( ) ;
190
+
191
+ let removals = previous_set. difference ( & current_set) . cloned ( ) . collect ( ) ;
192
+ let additions = current_set. difference ( & previous_set) . cloned ( ) . collect ( ) ;
193
+
194
+ ( removals, additions)
195
+ }
196
+
142
197
#[ cfg( test) ]
143
198
fn dummy_commit_from_body ( sha : & str , body : & str ) -> GithubCommit {
144
199
use chrono:: { DateTime , FixedOffset } ;
0 commit comments