11use crate :: {
2- config:: { NotifyZulipConfig , NotifyZulipLabelConfig } ,
2+ config:: { NotifyZulipConfig , NotifyZulipLabelConfig , NotifyZulipNameConfig } ,
33 github:: { Issue , IssuesAction , IssuesEvent , Label } ,
44 handlers:: Context ,
55} ;
@@ -12,6 +12,8 @@ pub(super) struct NotifyZulipInput {
1212 /// For example, if an `I-prioritize` issue is closed,
1313 /// this field will be `I-prioritize`.
1414 label : Label ,
15+ is_default_valid : bool ,
16+ names : Vec < String > ,
1517}
1618
1719pub ( super ) enum NotificationType {
@@ -52,26 +54,71 @@ pub(super) async fn parse_input(
5254fn parse_label_change_input (
5355 event : & IssuesEvent ,
5456 label : Label ,
55- config : & NotifyZulipLabelConfig ,
57+ config : & NotifyZulipNameConfig ,
5658) -> 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
59106 return None ;
60107 }
61108
62109 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+ } ) ,
75122 _ => None ,
76123 }
77124}
@@ -92,24 +139,69 @@ fn parse_close_reopen_input(
92139 . map ( |config| ( label, config) )
93140 } )
94141 . 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
97189 return None ;
98190 }
99191
100192 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+ } ) ,
113205 _ => None ,
114206 }
115207 } )
@@ -140,41 +232,54 @@ pub(super) async fn handle_input<'a>(
140232 inputs : Vec < NotifyZulipInput > ,
141233) -> anyhow:: Result < ( ) > {
142234 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] ) ;
153244 }
154245
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;
161248
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+ }
166258
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+ } ;
171265
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 ?;
175282 }
176- . send ( & ctx. github . raw ( ) )
177- . await ?;
178283 }
179284 }
180285
0 commit comments