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