@@ -6,7 +6,7 @@ use std::sync::{Arc, RwLock};
66use std:: time:: { Duration , Instant } ;
77use tracing as log;
88
9- static CONFIG_FILE_NAME : & str = "triagebot.toml" ;
9+ pub ( crate ) static CONFIG_FILE_NAME : & str = "triagebot.toml" ;
1010const REFRESH_EVERY : Duration = Duration :: from_secs ( 2 * 60 ) ; // Every two minutes
1111
1212lazy_static:: lazy_static! {
@@ -17,6 +17,7 @@ lazy_static::lazy_static! {
1717
1818#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
1919#[ serde( rename_all = "kebab-case" ) ]
20+ #[ serde( deny_unknown_fields) ]
2021pub ( crate ) struct Config {
2122 pub ( crate ) relabel : Option < RelabelConfig > ,
2223 pub ( crate ) assign : Option < AssignConfig > ,
@@ -35,9 +36,13 @@ pub(crate) struct Config {
3536 pub ( crate ) note : Option < NoteConfig > ,
3637 pub ( crate ) mentions : Option < MentionsConfig > ,
3738 pub ( crate ) no_merges : Option < NoMergesConfig > ,
39+ // We want this validation to run even without the entry in the config file
40+ #[ serde( default = "ValidateConfig::default" ) ]
41+ pub ( crate ) validate_config : Option < ValidateConfig > ,
3842}
3943
4044#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
45+ #[ serde( deny_unknown_fields) ]
4146pub ( crate ) struct NominateConfig {
4247 // team name -> label
4348 pub ( crate ) teams : HashMap < String , String > ,
@@ -68,6 +73,7 @@ impl PingConfig {
6873}
6974
7075#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
76+ #[ serde( deny_unknown_fields) ]
7177pub ( crate ) struct PingTeamConfig {
7278 pub ( crate ) message : String ,
7379 #[ serde( default ) ]
@@ -76,6 +82,7 @@ pub(crate) struct PingTeamConfig {
7682}
7783
7884#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
85+ #[ serde( deny_unknown_fields) ]
7986pub ( crate ) struct AssignConfig {
8087 /// If `true`, then posts a warning comment if the PR is opened against a
8188 /// different branch than the default (usually master or main).
@@ -105,6 +112,7 @@ impl AssignConfig {
105112}
106113
107114#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
115+ #[ serde( deny_unknown_fields) ]
108116pub ( crate ) struct NoMergesConfig {
109117 /// No action will be taken on PRs with these substrings in the title.
110118 #[ serde( default ) ]
@@ -121,6 +129,7 @@ pub(crate) struct NoMergesConfig {
121129}
122130
123131#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
132+ #[ serde( deny_unknown_fields) ]
124133pub ( crate ) struct NoteConfig {
125134 #[ serde( default ) ]
126135 _empty : ( ) ,
@@ -133,6 +142,7 @@ pub(crate) struct MentionsConfig {
133142}
134143
135144#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
145+ #[ serde( deny_unknown_fields) ]
136146pub ( crate ) struct MentionsPathConfig {
137147 pub ( crate ) message : Option < String > ,
138148 #[ serde( default ) ]
@@ -141,22 +151,34 @@ pub(crate) struct MentionsPathConfig {
141151
142152#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
143153#[ serde( rename_all = "kebab-case" ) ]
154+ #[ serde( deny_unknown_fields) ]
144155pub ( crate ) struct RelabelConfig {
145156 #[ serde( default ) ]
146157 pub ( crate ) allow_unauthenticated : Vec < String > ,
147158}
148159
149160#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
161+ #[ serde( deny_unknown_fields) ]
150162pub ( crate ) struct ShortcutConfig {
151163 #[ serde( default ) ]
152164 _empty : ( ) ,
153165}
154166
155167#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
168+ #[ serde( deny_unknown_fields) ]
156169pub ( crate ) struct PrioritizeConfig {
157170 pub ( crate ) label : String ,
158171}
159172
173+ #[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
174+ pub ( crate ) struct ValidateConfig { }
175+
176+ impl ValidateConfig {
177+ fn default ( ) -> Option < Self > {
178+ Some ( ValidateConfig { } )
179+ }
180+ }
181+
160182#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
161183pub ( crate ) struct AutolabelConfig {
162184 #[ serde( flatten) ]
@@ -176,6 +198,7 @@ impl AutolabelConfig {
176198}
177199
178200#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
201+ #[ serde( deny_unknown_fields) ]
179202pub ( crate ) struct AutolabelLabelConfig {
180203 #[ serde( default ) ]
181204 pub ( crate ) trigger_labels : Vec < String > ,
@@ -196,6 +219,7 @@ pub(crate) struct NotifyZulipConfig {
196219}
197220
198221#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
222+ #[ serde( deny_unknown_fields) ]
199223pub ( crate ) struct NotifyZulipLabelConfig {
200224 pub ( crate ) zulip_stream : u64 ,
201225 pub ( crate ) topic : String ,
@@ -208,6 +232,7 @@ pub(crate) struct NotifyZulipLabelConfig {
208232}
209233
210234#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
235+ #[ serde( deny_unknown_fields) ]
211236pub ( crate ) struct MajorChangeConfig {
212237 /// A username (typically a group, e.g. T-lang) to ping on Zulip for newly
213238 /// opened proposals.
@@ -243,18 +268,22 @@ impl MajorChangeConfig {
243268}
244269
245270#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
271+ #[ serde( deny_unknown_fields) ]
246272pub ( crate ) struct GlacierConfig { }
247273
248274#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
275+ #[ serde( deny_unknown_fields) ]
249276pub ( crate ) struct CloseConfig { }
250277
251278#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
279+ #[ serde( deny_unknown_fields) ]
252280pub ( crate ) struct ReviewSubmittedConfig {
253281 pub ( crate ) review_labels : Vec < String > ,
254282 pub ( crate ) reviewed_label : String ,
255283}
256284
257285#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
286+ #[ serde( deny_unknown_fields) ]
258287pub ( crate ) struct ReviewRequestedConfig {
259288 pub ( crate ) remove_labels : Vec < String > ,
260289 pub ( crate ) add_labels : Vec < String > ,
@@ -280,6 +309,7 @@ pub(crate) async fn get(
280309
281310#[ derive( PartialEq , Eq , Debug , serde:: Deserialize ) ]
282311#[ serde( rename_all = "kebab-case" ) ]
312+ #[ serde( deny_unknown_fields) ]
283313pub ( crate ) struct GitHubReleasesConfig {
284314 pub ( crate ) format : ChangelogFormat ,
285315 pub ( crate ) project_name : String ,
@@ -307,7 +337,8 @@ async fn get_fresh_config(
307337 . await
308338 . map_err ( |e| ConfigurationError :: Http ( Arc :: new ( e) ) ) ?
309339 . ok_or ( ConfigurationError :: Missing ) ?;
310- let config = Arc :: new ( toml:: from_slice :: < Config > ( & contents) . map_err ( ConfigurationError :: Toml ) ?) ;
340+ let contents = String :: from_utf8_lossy ( & * contents) ;
341+ let config = Arc :: new ( toml:: from_str :: < Config > ( & contents) . map_err ( ConfigurationError :: Toml ) ?) ;
311342 log:: debug!( "fresh configuration for {}: {:?}" , repo. full_name, config) ;
312343 Ok ( config)
313344}
@@ -431,6 +462,7 @@ mod tests {
431462 review_requested: None ,
432463 mentions: None ,
433464 no_merges: None ,
465+ validate_config: Some ( ValidateConfig { } ) ,
434466 }
435467 ) ;
436468 }
0 commit comments