@@ -19,13 +19,17 @@ mod modified_submodule;
19
19
mod no_mentions;
20
20
mod no_merges;
21
21
mod non_default_branch;
22
+ mod validate_config;
22
23
23
24
/// Key for the state in the database
24
- const CHECK_COMMITS_WARNINGS_KEY : & str = "check-commits-warnings" ;
25
+ const CHECK_COMMITS_KEY : & str = "check-commits-warnings" ;
25
26
26
27
/// State stored in the database
27
28
#[ derive( Debug , Default , serde:: Deserialize , serde:: Serialize , Clone , PartialEq ) ]
28
- struct CheckCommitsWarningsState {
29
+ struct CheckCommitsState {
30
+ /// List of the last errors (comment body, comment node-id).
31
+ #[ serde( default ) ]
32
+ last_errors : Vec < ( String , String ) > ,
29
33
/// List of the last warnings in the most recent comment.
30
34
last_warnings : Vec < String > ,
31
35
/// ID of the most recent warning comment.
@@ -41,7 +45,10 @@ pub(super) async fn handle(ctx: &Context, event: &Event, config: &Config) -> any
41
45
42
46
if !matches ! (
43
47
event. action,
44
- IssuesAction :: Opened | IssuesAction :: Synchronize | IssuesAction :: ReadyForReview
48
+ IssuesAction :: Opened
49
+ | IssuesAction :: Reopened
50
+ | IssuesAction :: Synchronize
51
+ | IssuesAction :: ReadyForReview
45
52
) || !event. issue . is_pr ( )
46
53
{
47
54
return Ok ( ( ) ) ;
@@ -61,6 +68,7 @@ pub(super) async fn handle(ctx: &Context, event: &Event, config: &Config) -> any
61
68
let commits = event. issue . commits ( & ctx. github ) . await ?;
62
69
let diff = & compare. files ;
63
70
71
+ let mut errors = Vec :: new ( ) ;
64
72
let mut warnings = Vec :: new ( ) ;
65
73
let mut labels = Vec :: new ( ) ;
66
74
@@ -108,20 +116,51 @@ pub(super) async fn handle(ctx: &Context, event: &Event, config: &Config) -> any
108
116
}
109
117
}
110
118
111
- handle_warnings_and_labels ( ctx, event, warnings, labels) . await
119
+ // Check if the `triagebot.toml` config is valid
120
+ errors. extend (
121
+ validate_config:: validate_config ( ctx, & event, diff)
122
+ . await
123
+ . context ( "validating the the triagebot config" ) ?,
124
+ ) ;
125
+
126
+ handle_new_state ( ctx, event, errors, warnings, labels) . await
112
127
}
113
128
114
129
// Add, hide or hide&add a comment with the warnings.
115
- async fn handle_warnings_and_labels (
130
+ async fn handle_new_state (
116
131
ctx : & Context ,
117
132
event : & IssuesEvent ,
133
+ errors : Vec < String > ,
118
134
warnings : Vec < String > ,
119
135
labels : Vec < String > ,
120
136
) -> anyhow:: Result < ( ) > {
121
137
// Get the state of the warnings for this PR in the database.
122
138
let mut db = ctx. db . get ( ) . await ;
123
- let mut state: IssueData < ' _ , CheckCommitsWarningsState > =
124
- IssueData :: load ( & mut db, & event. issue , CHECK_COMMITS_WARNINGS_KEY ) . await ?;
139
+ let mut state: IssueData < ' _ , CheckCommitsState > =
140
+ IssueData :: load ( & mut db, & event. issue , CHECK_COMMITS_KEY ) . await ?;
141
+
142
+ // Handles the errors, post the new ones, hide resolved ones and don't touch the one still active
143
+ if !state. data . last_errors . is_empty ( ) || !errors. is_empty ( ) {
144
+ let ( errors_to_remove, errors_to_add) =
145
+ calculate_error_changes ( & state. data . last_errors , & errors) ;
146
+
147
+ for error_to_remove in errors_to_remove {
148
+ event
149
+ . issue
150
+ . hide_comment (
151
+ & ctx. github ,
152
+ & error_to_remove. 1 ,
153
+ ReportedContentClassifiers :: Resolved ,
154
+ )
155
+ . await ?;
156
+ state. data . last_errors . retain ( |e| e != & error_to_remove) ;
157
+ }
158
+
159
+ for error_to_add in errors_to_add {
160
+ let comment = event. issue . post_comment ( & ctx. github , & error_to_add) . await ?;
161
+ state. data . last_errors . push ( ( error_to_add, comment. node_id ) ) ;
162
+ }
163
+ }
125
164
126
165
// We only post a new comment when we haven't posted one with the same warnings before.
127
166
if !warnings. is_empty ( ) && state. data . last_warnings != warnings {
@@ -225,6 +264,28 @@ fn calculate_label_changes(
225
264
( removals, additions)
226
265
}
227
266
267
+ // Calculate the error changes
268
+ fn calculate_error_changes (
269
+ previous : & Vec < ( String , String ) > ,
270
+ current : & Vec < String > ,
271
+ ) -> ( Vec < ( String , String ) > , Vec < String > ) {
272
+ let previous_set: HashSet < ( String , String ) > = previous. into_iter ( ) . cloned ( ) . collect ( ) ;
273
+ let current_set: HashSet < String > = current. into_iter ( ) . cloned ( ) . collect ( ) ;
274
+
275
+ let removals = previous_set
276
+ . iter ( )
277
+ . filter ( |( e, _) | !current_set. contains ( e) )
278
+ . cloned ( )
279
+ . collect ( ) ;
280
+ let additions = current_set
281
+ . iter ( )
282
+ . filter ( |e| !previous_set. iter ( ) . any ( |( e2, _) | e == & e2) )
283
+ . cloned ( )
284
+ . collect ( ) ;
285
+
286
+ ( removals, additions)
287
+ }
288
+
228
289
#[ cfg( test) ]
229
290
fn dummy_commit_from_body ( sha : & str , body : & str ) -> GithubCommit {
230
291
use chrono:: { DateTime , FixedOffset } ;
0 commit comments