88from . import bluesky , mastodon , rss , webhooks
99from .messages import STATUS_MESSAGES
1010
11+ VALID_STATUSES = {'green' , 'yellow' , 'red' }
12+ ALL_CHANNELS = {'bluesky' , 'mastodon' , 'rss' , 'webhooks' }
1113
12- def notify_status_change (status , previous_status , delay_summaries = None , timestamp = None ):
14+
15+ def notify_status_change (status , previous_status , delay_summaries = None ,
16+ timestamp = None , channels = None ):
1317 """
1418 Dispatch status change notification to all enabled channels.
1519
@@ -18,6 +22,9 @@ def notify_status_change(status, previous_status, delay_summaries=None, timestam
1822 previous_status: Previous status for context
1923 delay_summaries: List of delay summary strings (optional)
2024 timestamp: ISO timestamp string (optional)
25+ channels: Set of channel names to dispatch to (optional).
26+ When None, dispatches to all channels. When provided,
27+ only dispatches to channels in the intersection with ALL_CHANNELS.
2128
2229 Returns:
2330 dict: Results from each notifier channel
@@ -28,11 +35,20 @@ def notify_status_change(status, previous_status, delay_summaries=None, timestam
2835 'webhooks': {'success': bool, 'skipped': bool, 'sent': int, 'failed': int, 'error': str}
2936 }
3037 'skipped' is True when the channel is not configured (no credentials/URLs set).
38+
39+ Raises:
40+ ValueError: If status is not one of VALID_STATUSES
3141 """
42+ if not isinstance (status , str ) or status not in VALID_STATUSES :
43+ raise ValueError (f"Invalid status { status !r} ; must be one of { sorted (VALID_STATUSES )} " )
44+
45+ dispatch_channels = ALL_CHANNELS if channels is None else channels & ALL_CHANNELS
3246 results = {}
3347
3448 # Bluesky (if credentials configured)
35- if os .getenv ('BLUESKY_HANDLE' ) and os .getenv ('BLUESKY_APP_PASSWORD' ):
49+ if 'bluesky' not in dispatch_channels :
50+ pass
51+ elif os .getenv ('BLUESKY_HANDLE' ) and os .getenv ('BLUESKY_APP_PASSWORD' ):
3652 results ['bluesky' ] = bluesky .post_to_bluesky (
3753 status = status ,
3854 previous_status = previous_status ,
@@ -47,7 +63,9 @@ def notify_status_change(status, previous_status, delay_summaries=None, timestam
4763 }
4864
4965 # Mastodon (if credentials configured)
50- if os .getenv ('MASTODON_INSTANCE' ) and os .getenv ('MASTODON_ACCESS_TOKEN' ):
66+ if 'mastodon' not in dispatch_channels :
67+ pass
68+ elif os .getenv ('MASTODON_INSTANCE' ) and os .getenv ('MASTODON_ACCESS_TOKEN' ):
5169 results ['mastodon' ] = mastodon .post_to_mastodon (
5270 status = status ,
5371 previous_status = previous_status ,
@@ -62,21 +80,25 @@ def notify_status_change(status, previous_status, delay_summaries=None, timestam
6280 }
6381
6482 # RSS feed (always enabled - no credentials needed)
65- # Use same status message as Bluesky/Mastodon
66- description = STATUS_MESSAGES .get (status , f'Status: { status } ' )
67- results ['rss' ] = rss .update_rss_feed (
68- status = status ,
69- description = description ,
70- delay_summaries = delay_summaries ,
71- timestamp = timestamp
72- )
83+ if 'rss' in dispatch_channels :
84+ # Use same status message as Bluesky/Mastodon
85+ description = STATUS_MESSAGES .get (status , f'Status: { status } ' )
86+ results ['rss' ] = rss .update_rss_feed (
87+ status = status ,
88+ description = description ,
89+ delay_summaries = delay_summaries ,
90+ timestamp = timestamp
91+ )
7392
7493 # Webhooks (if URLs configured)
75- results ['webhooks' ] = webhooks .send_webhooks (
76- status = status ,
77- previous_status = previous_status ,
78- delay_summaries = delay_summaries ,
79- timestamp = timestamp
80- )
94+ if 'webhooks' not in dispatch_channels :
95+ pass
96+ else :
97+ results ['webhooks' ] = webhooks .send_webhooks (
98+ status = status ,
99+ previous_status = previous_status ,
100+ delay_summaries = delay_summaries ,
101+ timestamp = timestamp
102+ )
81103
82104 return results
0 commit comments