chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:12:00 +08:00
commit 3de48288cb
2986 changed files with 1131193 additions and 0 deletions
+203
View File
@@ -0,0 +1,203 @@
#!/usr/bin/env python3
"""Daily Discord-watch rotation reminder.
Picks the person on watch for the current day and pings them in Slack on the
morning of *their* local timezone. The rotation is deterministic — the
assignee is a function of the date and the person's position in the list — so
there is no state to store anywhere.
The GitHub Actions workflow wakes at a couple of fixed UTC times (one per
timezone's morning). On each run the day's assignee is pinged only if it's
currently morning where they live; if not, the run for their timezone's
morning handles them. Our timezones are far enough apart that only one is ever
in its morning at a time, so at most one person is pinged per run.
Set SLACK_WEBHOOK_URL to post for real. Leave it unset for a dry run that just
prints what it would do — handy for testing the rotation order without Slack.
"""
from __future__ import annotations
import datetime
import json
import os
import urllib.error
import urllib.request
from dataclasses import dataclass
from zoneinfo import ZoneInfo
# Each cron run is one timezone's morning scan: we ping today's assignee only
# if it's currently morning where they are. A run that's morning in SF is night
# in Singapore and vice versa, so at most one timezone matches per run. Morning
# is a band rather than an exact hour, which absorbs both daylight saving and
# GitHub's frequently-delayed cron schedule — a run that fires a few hours late
# still counts as that person's morning. The band starts at 05:00 (not
# midnight) so a delayed *other* timezone's cron spilling past local midnight
# isn't mistaken for this timezone's morning, which would double-ping.
MORNING_START_HOUR = 5
MORNING_END_HOUR = 12
# Skip Saturdays and Sundays (in each person's local time). The rotation also
# advances by workdays only, so Friday hands off straight to Monday.
WEEKDAYS_ONLY = True
# Rotation anchor: workday 0 is this date. Any Monday works; it only sets the
# phase of the cycle, not who is in it.
EPOCH = datetime.date(2026, 1, 5) # a Monday
@dataclass(frozen=True)
class Person:
name: str # for logs / dry-run output only
slack_id: str # Slack member ID, e.g. "U01ABC2DEF" (NOT the display name)
tz: str # IANA timezone name, e.g. "America/Los_Angeles"
# Out-of-office spans as inclusive (start, end) ISO date pairs, e.g.
# (("2026-07-13", "2026-07-17"),). On any OOO day the person is skipped and
# the next available person covers; the OOO person keeps their later slots.
ooo: tuple[tuple[str, str], ...] = ()
# Rotation order. Slack member IDs (profile -> ⋮ More -> Copy member ID) and
# each person's IANA timezone.
PEOPLE: list[Person] = [
Person("Aravind Segu", "U01A12R8NUR", "America/Los_Angeles"),
Person("Bryan Qiu", "U05KA5T983Y", "America/Los_Angeles"),
Person("Daniel Lok", "U060CNWNHSQ", "Asia/Singapore"),
Person("Dhruv Gupta", "U0A76097E1F", "America/Los_Angeles"),
Person("Edwin He", "U077B1V6WQJ", "America/Los_Angeles"),
Person("Pat Sukprasert", "U05HRKWFY81", "Asia/Singapore"),
Person("Sabhya Chhabria", "U07A1KQDXAB", "America/Los_Angeles"),
Person("Serena Ruan", "U0571L5KNLR", "Asia/Singapore"),
Person("Shivam Mittal", "U09FZKX9S6B", "America/Los_Angeles"),
Person("Tomu Hirata", "U07TX4PR5MZ", "Asia/Singapore"),
Person("Zeyi (Rice) Fan", "U09L5HT4CH0", "America/Los_Angeles"),
]
def _workdays_between(start: datetime.date, end: datetime.date) -> int:
"""Number of MonFri days in [start, end). Negative if end precedes start."""
if end < start:
return -_workdays_between(end, start)
full_weeks, extra = divmod((end - start).days, 7)
count = full_weeks * 5
for i in range(extra):
if (start + datetime.timedelta(days=full_weeks * 7 + i)).weekday() < 5:
count += 1
return count
def is_ooo(person: Person, local_date: datetime.date) -> bool:
"""Whether person is out of office on local_date (inclusive spans)."""
for start, end in person.ooo:
if datetime.date.fromisoformat(start) <= local_date <= datetime.date.fromisoformat(end):
return True
return False
def assignee_for(local_date: datetime.date) -> Person | None:
"""The person on watch for a given local workday, or None if all are OOO.
Indexed by the number of workdays since EPOCH (which is itself a Monday),
so weekends advance nobody and Friday hands off directly to Monday. If the
slot's person is OOO, the next available person covers — probing forward so
coverage stays a pure function of the date (no stored state). Only
meaningful for weekdays; weekends are filtered out before this is called.
"""
workday_number = _workdays_between(EPOCH, local_date)
for offset in range(len(PEOPLE)):
person = PEOPLE[(workday_number + offset) % len(PEOPLE)]
if not is_ooo(person, local_date):
return person
return None # everyone is OOO that day
def whose_turn_now(now_utc: datetime.datetime) -> Person | None:
"""Return the person to ping right now, or None if it isn't anyone's morning.
Each person is evaluated in their own timezone: it must be a weekday morning
(before noon) there, and today's rotation slot must land on them. Since our
timezones are far enough apart that only one is ever in its morning at a
time, at most one person matches. A person missed by a late/early run is
picked up by the next run that lands in their morning.
"""
for person in PEOPLE:
local = now_utc.astimezone(ZoneInfo(person.tz))
if not (MORNING_START_HOUR <= local.hour < MORNING_END_HOUR):
continue
if WEEKDAYS_ONLY and local.weekday() >= 5: # 5=Sat, 6=Sun
continue
if assignee_for(local.date()) == person:
return person
return None
class SlackPostError(RuntimeError):
"""Raised when the Slack POST fails, without exposing the webhook URL."""
def post_to_slack(webhook_url: str, person: Person) -> None:
text = (
f"<@{person.slack_id}> you're on *Discord watch* today \U0001f440 "
f"— please keep an eye on the channel."
)
payload = json.dumps({"text": text}).encode()
req = urllib.request.Request(
webhook_url,
data=payload,
headers={"Content-Type": "application/json"},
)
# Catch and re-raise without the URL: urllib errors stringify the full
# webhook URL, which must never reach the Actions log or error output.
try:
with urllib.request.urlopen(req, timeout=30) as resp:
resp.read()
except urllib.error.HTTPError as exc:
raise SlackPostError(f"Slack returned HTTP {exc.code} {exc.reason}") from None
except urllib.error.URLError as exc:
raise SlackPostError(f"could not reach Slack: {exc.reason}") from None
def _report_todays_assignees(now_utc: datetime.datetime) -> None:
"""Log who's on watch for each timezone's current local date.
Runs regardless of the morning window so a manual run is always
informative, even outside anyone's ping window.
"""
for tz in sorted({p.tz for p in PEOPLE}):
local = now_utc.astimezone(ZoneInfo(tz))
if local.weekday() >= 5: # 5=Sat, 6=Sun
who = "nobody (weekend)"
else:
person = assignee_for(local.date())
who = person.name if person else "nobody (all OOO)"
print(f" {tz}: {local:%Y-%m-%d %a} -> {who}")
def main() -> None:
now_utc = datetime.datetime.now(datetime.timezone.utc)
print(f"Today's watch by timezone (as of {now_utc:%Y-%m-%d %H:%M UTC}):")
_report_todays_assignees(now_utc)
person = whose_turn_now(now_utc)
if person is None:
print(f"{now_utc:%Y-%m-%d %H:%M UTC}: nobody's on watch right now, nothing to do.")
return
local = now_utc.astimezone(ZoneInfo(person.tz))
webhook_url = os.environ.get("SLACK_WEBHOOK_URL")
if not webhook_url:
print(
f"[dry run] Would ping {person.name} ({person.slack_id}) "
f"— it's {local:%Y-%m-%d %H:%M} in {person.tz}. "
f"Set SLACK_WEBHOOK_URL to post for real."
)
return
post_to_slack(webhook_url, person)
print(f"Pinged {person.name} ({person.slack_id}) at {local:%Y-%m-%d %H:%M %Z}.")
if __name__ == "__main__":
main()