Skip to content

Commit 7dd540e

Browse files
committed
fix: make call reminder bots display dynamic time until meeting
Signed-off-by: ManmathX <manmath2006n@gmail.com>
1 parent 2f646a8 commit 7dd540e

4 files changed

Lines changed: 331 additions & 4 deletions

File tree

.github/scripts/cron-calls-community.sh

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ DRY_RUN="${DRY_RUN:-true}"
66
ANCHOR_DATE="2025-11-12"
77
MEETING_LINK="https://zoom-lfx.platform.linuxfoundation.org/meeting/92041330205?password=2f345bee-0c14-4dd5-9883-06fbc9c60581"
88
CALENDAR_LINK="https://zoom-lfx.platform.linuxfoundation.org/meetings/hiero?view=week"
9+
MEETING_HOUR="${MEETING_HOUR:-14}" # 14:00 UTC — change this to adjust the meeting time
10+
11+
if ! [[ "$MEETING_HOUR" =~ ^[0-9]+$ ]] || [ "$MEETING_HOUR" -lt 0 ] || [ "$MEETING_HOUR" -gt 23 ]; then
12+
echo "ERROR: MEETING_HOUR must be an integer between 0 and 23, got '$MEETING_HOUR'."
13+
exit 1
14+
fi
915

1016
CANCELLED_DATES=(
1117
"2025-12-24"
@@ -63,15 +69,18 @@ if [ -z "$ISSUE_DATA" ] || [ "$ISSUE_DATA" = "[]" ]; then
6369
exit 0
6470
fi
6571

72+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
73+
TIME_UNTIL_MEETING=$(python3 "$SCRIPT_DIR/utils/compute-time-until-meeting.py" "$MEETING_HOUR")
74+
6675
COMMENT_BODY=$(cat <<EOF
6776
Hello, this is CommunityCallBot.
6877
69-
This is a reminder that the Hiero Python SDK Community Call will begin in approximately 4 hours (14:00 UTC).
78+
This is a reminder that the Hiero Python SDK Community Call will begin in approximately $TIME_UNTIL_MEETING (${MEETING_HOUR}:00 UTC).
7079
7180
The call is an open forum where contributors and users can discuss topics, raise issues, and influence the direction of the Python SDK.
7281
7382
Details:
74-
- Time: 14:00 UTC
83+
- Time: ${MEETING_HOUR}:00 UTC
7584
- Join Link: [Zoom Meeting]($MEETING_LINK)
7685
7786
Disclaimer: This is an automated reminder. Please verify the schedule [here]($CALENDAR_LINK) for any changes.

.github/scripts/cron-calls-office-hours.sh

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ DRY_RUN="${DRY_RUN:-true}"
66
ANCHOR_DATE="2025-12-03"
77
MEETING_LINK="https://zoom-lfx.platform.linuxfoundation.org/meeting/99912667426?password=5b584a0e-1ed7-49d3-b2fc-dc5ddc888338"
88
CALENDAR_LINK="https://zoom-lfx.platform.linuxfoundation.org/meetings/hiero?view=week"
9+
MEETING_HOUR="${MEETING_HOUR:-14}" # 14:00 UTC — change this to adjust the meeting time
10+
11+
if ! [[ "$MEETING_HOUR" =~ ^[0-9]+$ ]] || [ "$MEETING_HOUR" -lt 0 ] || [ "$MEETING_HOUR" -gt 23 ]; then
12+
echo "ERROR: MEETING_HOUR must be an integer between 0 and 23, got '$MEETING_HOUR'."
13+
exit 1
14+
fi
915

1016
CANCELLED_DATES=(
1117
"2025-12-31"
@@ -63,15 +69,18 @@ if [ -z "$PR_DATA" ] || [ "$PR_DATA" = "[]" ]; then
6369
exit 0
6470
fi
6571

72+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
73+
TIME_UNTIL_MEETING=$(python3 "$SCRIPT_DIR/utils/compute-time-until-meeting.py" "$MEETING_HOUR")
74+
6675
COMMENT_BODY=$(cat <<EOF
6776
Hello, this is the OfficeHourBot.
6877
69-
This is a reminder that the Hiero Python SDK Office Hours are scheduled in approximately 4 hours (14:00 UTC).
78+
This is a reminder that the Hiero Python SDK Office Hours are scheduled in approximately $TIME_UNTIL_MEETING (${MEETING_HOUR}:00 UTC).
7079
7180
This session provides an opportunity to ask questions regarding this Pull Request.
7281
7382
Details:
74-
- Time: 14:00 UTC
83+
- Time: ${MEETING_HOUR}:00 UTC
7584
- Join Link: [Zoom Meeting]($MEETING_LINK)
7685
7786
Disclaimer: This is an automated reminder. Please verify the schedule [here]($CALENDAR_LINK) for any changes.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""Compute human-readable time remaining until a meeting.
2+
3+
Usage:
4+
python3 compute-time-until-meeting.py <MEETING_HOUR> [MOCK_TIME]
5+
6+
Arguments:
7+
MEETING_HOUR Meeting hour in UTC (0-23)
8+
MOCK_TIME Optional mock time in HH:MM or HH:MM:SS format (for testing)
9+
10+
Output:
11+
A human-readable string like "3 hours and 7 minutes" printed to stdout.
12+
"""
13+
14+
from __future__ import annotations
15+
16+
import sys
17+
from datetime import datetime, timezone
18+
from math import ceil
19+
20+
21+
def _parse_mock_time(mock_time):
22+
"""Parse a mock time string into (hour, minute, second) components."""
23+
parts = list(map(int, mock_time.split(":")))
24+
second = parts[2] if len(parts) > 2 else 0
25+
return parts[0], parts[1], second
26+
27+
28+
def _pluralize(value, singular):
29+
"""Return singular or plural form based on value."""
30+
return singular if value == 1 else f"{singular}s"
31+
32+
33+
def _format_duration(hours, minutes):
34+
"""Format hours and minutes into a human-readable string."""
35+
if hours > 0 and minutes > 0:
36+
return f"{hours} {_pluralize(hours, 'hour')} and {minutes} {_pluralize(minutes, 'minute')}"
37+
if hours > 0:
38+
return f"{hours} {_pluralize(hours, 'hour')}"
39+
return f"{minutes} {_pluralize(minutes, 'minute')}"
40+
41+
42+
def compute_time_until_meeting(meeting_hour, mock_time=None):
43+
"""Compute the human-readable time remaining until the meeting.
44+
45+
Args:
46+
meeting_hour: The meeting hour in UTC (0-23).
47+
mock_time: Optional mock time string in "HH:MM" or "HH:MM:SS" format.
48+
49+
Returns:
50+
A string like "3 hours and 7 minutes".
51+
"""
52+
now = datetime.now(timezone.utc)
53+
54+
if mock_time is not None:
55+
hour, minute, second = _parse_mock_time(mock_time)
56+
now = now.replace(hour=hour, minute=minute, second=second, microsecond=0)
57+
58+
meeting = now.replace(hour=meeting_hour, minute=0, second=0, microsecond=0)
59+
diff = meeting - now
60+
total_minutes = max(ceil(diff.total_seconds() / 60), 0)
61+
62+
return _format_duration(total_minutes // 60, total_minutes % 60)
63+
64+
65+
if __name__ == "__main__":
66+
if len(sys.argv) < 2:
67+
print("Usage: python3 compute-time-until-meeting.py <MEETING_HOUR> [MOCK_TIME]", file=sys.stderr)
68+
sys.exit(1)
69+
70+
meeting_hour = int(sys.argv[1])
71+
mock_time = sys.argv[2] if len(sys.argv) > 2 else None
72+
print(compute_time_until_meeting(meeting_hour, mock_time))
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# Test suite for cron-calls dynamic time computation
5+
# Validates the shared compute-time-until-meeting.py helper used in
6+
# cron-calls-community.sh and cron-calls-office-hours.sh
7+
8+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9+
HELPER="$SCRIPT_DIR/compute-time-until-meeting.py"
10+
11+
# Color codes for output
12+
RED='\033[0;31m'
13+
GREEN='\033[0;32m'
14+
YELLOW='\033[1;33m'
15+
NC='\033[0m'
16+
17+
# Test counters
18+
TESTS_RUN=0
19+
TESTS_PASSED=0
20+
TESTS_FAILED=0
21+
22+
print_result() {
23+
local test_name="$1"
24+
local result="$2"
25+
local message="${3:-}"
26+
27+
TESTS_RUN=$((TESTS_RUN + 1))
28+
29+
if [[ "$result" == "PASS" ]]; then
30+
TESTS_PASSED=$((TESTS_PASSED + 1))
31+
echo -e "${GREEN}✓ PASS${NC}: $test_name"
32+
else
33+
TESTS_FAILED=$((TESTS_FAILED + 1))
34+
echo -e "${RED}✗ FAIL${NC}: $test_name"
35+
if [[ -n "$message" ]]; then
36+
echo -e " ${YELLOW}${NC} $message"
37+
fi
38+
fi
39+
}
40+
41+
# Test 1: Standard case — 4 hours before meeting
42+
test_standard_4_hours() {
43+
echo ""
44+
echo "Test 1: Standard case — 4 hours before meeting (10:00 → 14:00)"
45+
echo "================================================================"
46+
47+
local result
48+
result=$(python3 "$HELPER" 14 "10:00")
49+
50+
if [[ "$result" == "4 hours" ]]; then
51+
print_result "4 hours before meeting" "PASS"
52+
else
53+
print_result "4 hours before meeting" "FAIL" "Expected '4 hours', got '$result'"
54+
fi
55+
}
56+
57+
# Test 2: Delayed run — 3 hours and 7 minutes remaining
58+
test_delayed_run() {
59+
echo ""
60+
echo "Test 2: Delayed run — 3 hours 7 minutes remaining (10:53 → 14:00)"
61+
echo "==================================================================="
62+
63+
local result
64+
result=$(python3 "$HELPER" 14 "10:53")
65+
66+
if [[ "$result" == "3 hours and 7 minutes" ]]; then
67+
print_result "Delayed run shows 3 hours and 7 minutes" "PASS"
68+
else
69+
print_result "Delayed run shows 3 hours and 7 minutes" "FAIL" "Expected '3 hours and 7 minutes', got '$result'"
70+
fi
71+
}
72+
73+
# Test 3: Just minutes remaining
74+
test_just_minutes() {
75+
echo ""
76+
echo "Test 3: Just minutes remaining (13:45 → 14:00)"
77+
echo "================================================"
78+
79+
local result
80+
result=$(python3 "$HELPER" 14 "13:45")
81+
82+
if [[ "$result" == "15 minutes" ]]; then
83+
print_result "15 minutes remaining" "PASS"
84+
else
85+
print_result "15 minutes remaining" "FAIL" "Expected '15 minutes', got '$result'"
86+
fi
87+
}
88+
89+
# Test 4: Exact whole hours
90+
test_exact_hours() {
91+
echo ""
92+
echo "Test 4: Exact whole hours (12:00 → 14:00)"
93+
echo "==========================================="
94+
95+
local result
96+
result=$(python3 "$HELPER" 14 "12:00")
97+
98+
if [[ "$result" == "2 hours" ]]; then
99+
print_result "Exactly 2 hours remaining" "PASS"
100+
else
101+
print_result "Exactly 2 hours remaining" "FAIL" "Expected '2 hours', got '$result'"
102+
fi
103+
}
104+
105+
# Test 5: Already past meeting time — clamped to 0
106+
test_past_meeting_time() {
107+
echo ""
108+
echo "Test 5: Already past meeting time (15:00 → 14:00)"
109+
echo "==================================================="
110+
111+
local result
112+
result=$(python3 "$HELPER" 14 "15:00")
113+
114+
if [[ "$result" == "0 minutes" ]]; then
115+
print_result "Past meeting time shows 0 minutes" "PASS"
116+
else
117+
print_result "Past meeting time shows 0 minutes" "FAIL" "Expected '0 minutes', got '$result'"
118+
fi
119+
}
120+
121+
# Test 6: Singular hour — 1 hour remaining
122+
test_singular_hour() {
123+
echo ""
124+
echo "Test 6: Singular hour (13:00 → 14:00)"
125+
echo "======================================="
126+
127+
local result
128+
result=$(python3 "$HELPER" 14 "13:00")
129+
130+
if [[ "$result" == "1 hour" ]]; then
131+
print_result "Singular hour formatting" "PASS"
132+
else
133+
print_result "Singular hour formatting" "FAIL" "Expected '1 hour', got '$result'"
134+
fi
135+
}
136+
137+
# Test 7: Singular minute — 1 hour and 1 minute
138+
test_singular_minute() {
139+
echo ""
140+
echo "Test 7: Singular minute (12:59 → 14:00)"
141+
echo "========================================="
142+
143+
local result
144+
result=$(python3 "$HELPER" 14 "12:59")
145+
146+
if [[ "$result" == "1 hour and 1 minute" ]]; then
147+
print_result "Singular hour and minute formatting" "PASS"
148+
else
149+
print_result "Singular hour and minute formatting" "FAIL" "Expected '1 hour and 1 minute', got '$result'"
150+
fi
151+
}
152+
153+
# Test 8: Different meeting hour
154+
test_different_meeting_hour() {
155+
echo ""
156+
echo "Test 8: Different meeting hour (08:30 → 12:00)"
157+
echo "================================================"
158+
159+
local result
160+
result=$(python3 "$HELPER" 12 "08:30")
161+
162+
if [[ "$result" == "3 hours and 30 minutes" ]]; then
163+
print_result "Different meeting hour works" "PASS"
164+
else
165+
print_result "Different meeting hour works" "FAIL" "Expected '3 hours and 30 minutes', got '$result'"
166+
fi
167+
}
168+
169+
# Test 9: Rounding with seconds — ceil rounds partial minutes up
170+
test_rounding_with_seconds() {
171+
echo ""
172+
echo "Test 9: Rounding with seconds (10:53:30 → 14:00) rounds up"
173+
echo "============================================================"
174+
175+
local result
176+
result=$(python3 "$HELPER" 14 "10:53:30")
177+
178+
if [[ "$result" == "3 hours and 7 minutes" ]]; then
179+
print_result "Partial minute rounds up correctly" "PASS"
180+
else
181+
print_result "Partial minute rounds up correctly" "FAIL" "Expected '3 hours and 7 minutes', got '$result'"
182+
fi
183+
}
184+
185+
# Test 10: Seconds just past the minute boundary
186+
test_seconds_just_past_boundary() {
187+
echo ""
188+
echo "Test 10: Seconds just past boundary (13:00:01 → 14:00) rounds up to 60 min"
189+
echo "============================================================================"
190+
191+
local result
192+
result=$(python3 "$HELPER" 14 "13:00:01")
193+
194+
if [[ "$result" == "1 hour" ]]; then
195+
print_result "Just past boundary rounds up to full hour" "PASS"
196+
else
197+
print_result "Just past boundary rounds up to full hour" "FAIL" "Expected '1 hour', got '$result'"
198+
fi
199+
}
200+
201+
main() {
202+
echo "=============================================="
203+
echo " Cron Calls Time Computation - Test Suite"
204+
echo "=============================================="
205+
206+
if [[ ! -f "$HELPER" ]]; then
207+
echo -e "${RED}ERROR: Helper script not found at $HELPER${NC}"
208+
exit 1
209+
fi
210+
211+
test_standard_4_hours
212+
test_delayed_run
213+
test_just_minutes
214+
test_exact_hours
215+
test_past_meeting_time
216+
test_singular_hour
217+
test_singular_minute
218+
test_different_meeting_hour
219+
test_rounding_with_seconds
220+
test_seconds_just_past_boundary
221+
222+
echo ""
223+
echo "=============================================="
224+
echo " Test Summary"
225+
echo "=============================================="
226+
echo "Total tests run: $TESTS_RUN"
227+
echo -e "${GREEN}Tests passed: $TESTS_PASSED${NC}"
228+
if [[ $TESTS_FAILED -gt 0 ]]; then
229+
echo -e "${RED}Tests failed: $TESTS_FAILED${NC}"
230+
exit 1
231+
else
232+
echo -e "${GREEN}All tests passed!${NC}"
233+
exit 0
234+
fi
235+
}
236+
237+
main "$@"

0 commit comments

Comments
 (0)