1
1
use crate :: {
2
- config:: { NotifyZulipConfig , NotifyZulipLabelConfig } ,
2
+ config:: { NotifyZulipConfig , NotifyZulipLabelConfig , NotifyZulipNameConfig } ,
3
3
github:: { Issue , IssuesAction , IssuesEvent , Label } ,
4
4
handlers:: Context ,
5
5
} ;
@@ -12,6 +12,8 @@ pub(super) struct NotifyZulipInput {
12
12
/// For example, if an `I-prioritize` issue is closed,
13
13
/// this field will be `I-prioritize`.
14
14
label : Label ,
15
+ is_default_valid : bool ,
16
+ names : Vec < String > ,
15
17
}
16
18
17
19
pub ( super ) enum NotificationType {
@@ -52,26 +54,71 @@ pub(super) async fn parse_input(
52
54
fn parse_label_change_input (
53
55
event : & IssuesEvent ,
54
56
label : Label ,
55
- config : & NotifyZulipLabelConfig ,
57
+ config : & NotifyZulipNameConfig ,
56
58
) -> Option < NotifyZulipInput > {
57
- if !has_all_required_labels ( & event. issue , config) {
58
- // Issue misses a required label, ignore this event
59
+ let mut is_default_valid = false ;
60
+ let mut names: Vec < String > = vec ! [ ] ;
61
+
62
+ match & config. default {
63
+ Some ( label_config) => {
64
+ if has_all_required_labels ( & event. issue , & label_config) {
65
+ match event. action {
66
+ IssuesAction :: Labeled { .. } if !label_config. messages_on_add . is_empty ( ) => {
67
+ is_default_valid = true ;
68
+ }
69
+ IssuesAction :: Unlabeled { .. }
70
+ if !label_config. messages_on_remove . is_empty ( ) =>
71
+ {
72
+ is_default_valid = true ;
73
+ }
74
+ _ => ( ) ,
75
+ }
76
+ }
77
+ }
78
+ None => ( ) ,
79
+ }
80
+
81
+ match & config. others {
82
+ Some ( other_configs) => {
83
+ for ( name, label_config) in other_configs {
84
+ if has_all_required_labels ( & event. issue , & label_config) {
85
+ match event. action {
86
+ IssuesAction :: Labeled { .. }
87
+ if !label_config. messages_on_add . is_empty ( ) =>
88
+ {
89
+ names. push ( name. to_string ( ) ) ;
90
+ }
91
+ IssuesAction :: Unlabeled { .. }
92
+ if !label_config. messages_on_remove . is_empty ( ) =>
93
+ {
94
+ names. push ( name. to_string ( ) ) ;
95
+ }
96
+ _ => ( ) ,
97
+ }
98
+ }
99
+ }
100
+ }
101
+ None => ( ) ,
102
+ }
103
+
104
+ if !is_default_valid && names. is_empty ( ) {
105
+ // It seems that there is no match between this event and any notify-zulip config, ignore this event
59
106
return None ;
60
107
}
61
108
62
109
match event. action {
63
- IssuesAction :: Labeled { .. } if !config . messages_on_add . is_empty ( ) => {
64
- Some ( NotifyZulipInput {
65
- notification_type : NotificationType :: Labeled ,
66
- label ,
67
- } )
68
- }
69
- IssuesAction :: Unlabeled { .. } if !config . messages_on_remove . is_empty ( ) => {
70
- Some ( NotifyZulipInput {
71
- notification_type : NotificationType :: Unlabeled ,
72
- label ,
73
- } )
74
- }
110
+ IssuesAction :: Labeled { .. } => Some ( NotifyZulipInput {
111
+ notification_type : NotificationType :: Labeled ,
112
+ label ,
113
+ is_default_valid ,
114
+ names ,
115
+ } ) ,
116
+ IssuesAction :: Unlabeled { .. } => Some ( NotifyZulipInput {
117
+ notification_type : NotificationType :: Unlabeled ,
118
+ label ,
119
+ is_default_valid ,
120
+ names ,
121
+ } ) ,
75
122
_ => None ,
76
123
}
77
124
}
@@ -92,24 +139,69 @@ fn parse_close_reopen_input(
92
139
. map ( |config| ( label, config) )
93
140
} )
94
141
. flat_map ( |( label, config) | {
95
- if !has_all_required_labels ( & event. issue , config) {
96
- // Issue misses a required label, ignore this event
142
+ let mut is_default_valid = false ;
143
+ let mut names: Vec < String > = vec ! [ ] ;
144
+
145
+ match & config. default {
146
+ Some ( label_config) => {
147
+ if has_all_required_labels ( & event. issue , & label_config) {
148
+ match event. action {
149
+ IssuesAction :: Closed if !label_config. messages_on_close . is_empty ( ) => {
150
+ is_default_valid = true ;
151
+ }
152
+ IssuesAction :: Reopened
153
+ if !label_config. messages_on_reopen . is_empty ( ) =>
154
+ {
155
+ is_default_valid = true ;
156
+ }
157
+ _ => ( ) ,
158
+ }
159
+ }
160
+ }
161
+ None => ( ) ,
162
+ }
163
+
164
+ match & config. others {
165
+ Some ( other_configs) => {
166
+ for ( name, label_config) in other_configs {
167
+ if has_all_required_labels ( & event. issue , & label_config) {
168
+ match event. action {
169
+ IssuesAction :: Closed
170
+ if !label_config. messages_on_close . is_empty ( ) =>
171
+ {
172
+ names. push ( name. to_string ( ) ) ;
173
+ }
174
+ IssuesAction :: Reopened
175
+ if !label_config. messages_on_reopen . is_empty ( ) =>
176
+ {
177
+ names. push ( name. to_string ( ) ) ;
178
+ }
179
+ _ => ( ) ,
180
+ }
181
+ }
182
+ }
183
+ }
184
+ None => ( ) ,
185
+ }
186
+
187
+ if !is_default_valid && names. is_empty ( ) {
188
+ // It seems that there is no match between this event and any notify-zulip config, ignore this event
97
189
return None ;
98
190
}
99
191
100
192
match event. action {
101
- IssuesAction :: Closed if !config . messages_on_close . is_empty ( ) => {
102
- Some ( NotifyZulipInput {
103
- notification_type : NotificationType :: Closed ,
104
- label ,
105
- } )
106
- }
107
- IssuesAction :: Reopened if !config . messages_on_reopen . is_empty ( ) => {
108
- Some ( NotifyZulipInput {
109
- notification_type : NotificationType :: Reopened ,
110
- label ,
111
- } )
112
- }
193
+ IssuesAction :: Closed => Some ( NotifyZulipInput {
194
+ notification_type : NotificationType :: Closed ,
195
+ label ,
196
+ is_default_valid ,
197
+ names ,
198
+ } ) ,
199
+ IssuesAction :: Reopened => Some ( NotifyZulipInput {
200
+ notification_type : NotificationType :: Reopened ,
201
+ label ,
202
+ is_default_valid ,
203
+ names ,
204
+ } ) ,
113
205
_ => None ,
114
206
}
115
207
} )
@@ -140,41 +232,54 @@ pub(super) async fn handle_input<'a>(
140
232
inputs : Vec < NotifyZulipInput > ,
141
233
) -> anyhow:: Result < ( ) > {
142
234
for input in inputs {
143
- let config = & config. labels [ & input. label . name ] ;
144
-
145
- let topic = & config. topic ;
146
- let topic = topic. replace ( "{number}" , & event. issue . number . to_string ( ) ) ;
147
- let mut topic = topic. replace ( "{title}" , & event. issue . title ) ;
148
- // Truncate to 60 chars (a Zulip limitation)
149
- let mut chars = topic. char_indices ( ) . skip ( 59 ) ;
150
- if let ( Some ( ( len, _) ) , Some ( _) ) = ( chars. next ( ) , chars. next ( ) ) {
151
- topic. truncate ( len) ;
152
- topic. push ( '…' ) ;
235
+ let name_config = & config. labels [ & input. label . name ] ;
236
+
237
+ // Get valid label configs
238
+ let mut label_configs: Vec < & NotifyZulipLabelConfig > = vec ! [ ] ;
239
+ if input. is_default_valid {
240
+ label_configs. push ( name_config. default . as_ref ( ) . unwrap ( ) ) ;
241
+ }
242
+ for name in input. names {
243
+ label_configs. push ( & name_config. others . as_ref ( ) . unwrap ( ) [ & name] ) ;
153
244
}
154
245
155
- let msgs = match input. notification_type {
156
- NotificationType :: Labeled => & config. messages_on_add ,
157
- NotificationType :: Unlabeled => & config. messages_on_remove ,
158
- NotificationType :: Closed => & config. messages_on_close ,
159
- NotificationType :: Reopened => & config. messages_on_reopen ,
160
- } ;
246
+ for label_config in label_configs {
247
+ let config = label_config;
161
248
162
- let recipient = crate :: zulip:: Recipient :: Stream {
163
- id : config. zulip_stream ,
164
- topic : & topic,
165
- } ;
249
+ let topic = & config. topic ;
250
+ let topic = topic. replace ( "{number}" , & event. issue . number . to_string ( ) ) ;
251
+ let mut topic = topic. replace ( "{title}" , & event. issue . title ) ;
252
+ // Truncate to 60 chars (a Zulip limitation)
253
+ let mut chars = topic. char_indices ( ) . skip ( 59 ) ;
254
+ if let ( Some ( ( len, _) ) , Some ( _) ) = ( chars. next ( ) , chars. next ( ) ) {
255
+ topic. truncate ( len) ;
256
+ topic. push ( '…' ) ;
257
+ }
166
258
167
- for msg in msgs {
168
- let msg = msg. replace ( "{number}" , & event. issue . number . to_string ( ) ) ;
169
- let msg = msg. replace ( "{title}" , & event. issue . title ) ;
170
- let msg = replace_team_to_be_nominated ( & event. issue . labels , msg) ;
259
+ let msgs = match input. notification_type {
260
+ NotificationType :: Labeled => & config. messages_on_add ,
261
+ NotificationType :: Unlabeled => & config. messages_on_remove ,
262
+ NotificationType :: Closed => & config. messages_on_close ,
263
+ NotificationType :: Reopened => & config. messages_on_reopen ,
264
+ } ;
171
265
172
- crate :: zulip:: MessageApiRequest {
173
- recipient,
174
- content : & msg,
266
+ let recipient = crate :: zulip:: Recipient :: Stream {
267
+ id : config. zulip_stream ,
268
+ topic : & topic,
269
+ } ;
270
+
271
+ for msg in msgs {
272
+ let msg = msg. replace ( "{number}" , & event. issue . number . to_string ( ) ) ;
273
+ let msg = msg. replace ( "{title}" , & event. issue . title ) ;
274
+ let msg = replace_team_to_be_nominated ( & event. issue . labels , msg) ;
275
+
276
+ crate :: zulip:: MessageApiRequest {
277
+ recipient,
278
+ content : & msg,
279
+ }
280
+ . send ( & ctx. github . raw ( ) )
281
+ . await ?;
175
282
}
176
- . send ( & ctx. github . raw ( ) )
177
- . await ?;
178
283
}
179
284
}
180
285
0 commit comments