From 3b6b7308d33413ef3ff65a256990bab9972efeae Mon Sep 17 00:00:00 2001 From: Mara Averick Date: Mon, 4 May 2026 06:53:31 -0600 Subject: [PATCH 1/3] build: add weekly office hours workflow Assisted-by: claude-sonnet-4-6 --- .github/workflows/weekly_office_hours.yml | 170 ++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 .github/workflows/weekly_office_hours.yml diff --git a/.github/workflows/weekly_office_hours.yml b/.github/workflows/weekly_office_hours.yml new file mode 100644 index 0000000..029eea4 --- /dev/null +++ b/.github/workflows/weekly_office_hours.yml @@ -0,0 +1,170 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2026 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# Workflow name: +name: weekly_office_hours + +# Workflow triggers: +on: + # Run this workflow weekly after Tuesday's office hours session: + schedule: + # cron: ' ' + - cron: '30 17 * * 2' + + # Allow the workflow to be manually run: + workflow_dispatch: + +# Workflow jobs: +jobs: + + # Define a job for creating a weekly office hours issue... + weekly_office_hours: + + # Define a display name: + name: 'Weekly Office Hours' + + # Define the type of virtual host machine on which to run the job: + runs-on: ubuntu-latest + + # Define the sequence of job steps... + steps: + # Checkout the repository: + - name: 'Checkout repository' + + # Version 4.0 + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac + timeout-minutes: 10 + + # Generate the issue body with computed dates and timezone conversions: + - name: 'Generate office hours issue body' + id: generate + run: | + python3 << 'PYEOF' + import datetime + import zoneinfo + import os + + # Compute the date of the next Tuesday (7 days out when run on Tuesday): + today = datetime.date.today() + days_until_tuesday = (1 - today.weekday()) % 7 + if days_until_tuesday == 0: + days_until_tuesday = 7 + next_tuesday = today + datetime.timedelta(days=days_until_tuesday) + + # Meeting time is 9:30 AM US/Pacific; DST is handled automatically: + pacific_tz = zoneinfo.ZoneInfo('America/Los_Angeles') + meeting_dt = datetime.datetime( + next_tuesday.year, next_tuesday.month, next_tuesday.day, + 9, 30, 0, tzinfo=pacific_tz + ) + + utc_dt = meeting_dt.astimezone(datetime.timezone.utc) + + def fmt_time(dt): + return dt.strftime('%H:%M (%I:%M %p)') + + utc_header = '**UTC {} {}**:'.format( + utc_dt.strftime('%a %d-%b-%Y'), + fmt_time(utc_dt) + ) + + timezones = [ + ('US / Pacific', 'America/Los_Angeles'), + ('US / Mountain', 'America/Denver'), + ('US / Central', 'America/Chicago'), + ('US / Eastern', 'America/New_York'), + ('EU / Western', 'Europe/London'), + ('EU / Central', 'Europe/Paris'), + ('EU / Eastern', 'Europe/Helsinki'), + ('Moscow', 'Europe/Moscow'), + ('Chennai', 'Asia/Kolkata'), + ('Hangzhou', 'Asia/Shanghai'), + ('Tokyo', 'Asia/Tokyo'), + ('Sydney', 'Australia/Sydney'), + ] + + table_rows = [] + for tz_name, tz_id in timezones: + local_dt = meeting_dt.astimezone(zoneinfo.ZoneInfo(tz_id)) + table_rows.append('| {} | {} {} |'.format( + tz_name, + local_dt.strftime('%a %d-%b-%Y'), + fmt_time(local_dt) + )) + + date_str = next_tuesday.strftime('%Y-%m-%d') + iso_str = utc_dt.strftime('%Y%m%dT%H%M') + timeanddate_url = ( + 'https://www.timeanddate.com/worldclock/fixedtime.html' + '?msg=stdlib%20Office+Hours+{}&iso={}'.format(date_str, iso_str) + ) + + body = """\ +## \U0001f31f Join Us for Weekly Office Hours! \U0001f31f + +Have questions about [stdlib](https://github.com/stdlib-js/stdlib)? Need help fixing a bug, figuring out what to do next, or just looking for feedback? Join our weekly office hours to connect with project maintainers, stay updated on the latest project news, and chat with other community members. This is a great opportunity to ask questions, share ideas, and engage directly with the stdlib team. + +Everyone is welcome—drop in and say hello! + +## Time + +{utc_header} + +| Timezone | Date/Time | +| ---------- | ---------- | +{table} + +or in your local time: + +- <{url}> + +## Links + +- Public calendar: + +## Joining the meeting + +- Google Meet link: + +## Agenda + +- Have specific things to discuss? Please comment in the issue thread below to add specific items to the agenda. +""".format( + utc_header=utc_header, + table='\n'.join(table_rows), + url=timeanddate_url + ) + + with open('office_hours_body.md', 'w') as f: + f.write(body) + + with open(os.environ['GITHUB_OUTPUT'], 'a') as f: + f.write('meeting_date={}\n'.format(date_str)) + + PYEOF + + # Create an issue: + - name: 'Create issue' + + # Version 4.0.1 + uses: peter-evans/create-issue-from-file@d60bea1e77c1b5c523216f7c31493883d76ffad7 + with: + title: Office Hours (${{ steps.generate.outputs.meeting_date }}) + content-filepath: ./office_hours_body.md + labels: | + Office Hours From 9ff7e0efd7fdafd47002cf83556f03685dc17075 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 5 May 2026 03:52:22 -0700 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Athan Signed-off-by: Athan --- .github/workflows/weekly_office_hours.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/weekly_office_hours.yml b/.github/workflows/weekly_office_hours.yml index 029eea4..af7122b 100644 --- a/.github/workflows/weekly_office_hours.yml +++ b/.github/workflows/weekly_office_hours.yml @@ -46,8 +46,8 @@ jobs: # Checkout the repository: - name: 'Checkout repository' - # Version 4.0 - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac + # Pin action to full length commit SHA + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0 timeout-minutes: 10 # Generate the issue body with computed dates and timezone conversions: @@ -161,8 +161,8 @@ or in your local time: # Create an issue: - name: 'Create issue' - # Version 4.0.1 - uses: peter-evans/create-issue-from-file@d60bea1e77c1b5c523216f7c31493883d76ffad7 + # Pin action to full length commit SHA + uses: peter-evans/create-issue-from-file@d60bea1e77c1b5c523216f7c31493883d76ffad7 # v4.0.1 with: title: Office Hours (${{ steps.generate.outputs.meeting_date }}) content-filepath: ./office_hours_body.md From cd16560d424866adad29f5be192ca6a01bb2d062 Mon Sep 17 00:00:00 2001 From: Mara Averick Date: Tue, 5 May 2026 07:13:53 -0600 Subject: [PATCH 3/3] refactor: extract Python logic to separate script Extract Python logic to script file. Add explicit permissions as is done in stdlib workflows. Assisted-by: claude-sonnet-4-6 --- .../workflows/scripts/weekly_office_hours/run | 141 ++++++++++++++++++ .github/workflows/weekly_office_hours.yml | 114 ++------------ 2 files changed, 151 insertions(+), 104 deletions(-) create mode 100644 .github/workflows/scripts/weekly_office_hours/run diff --git a/.github/workflows/scripts/weekly_office_hours/run b/.github/workflows/scripts/weekly_office_hours/run new file mode 100644 index 0000000..87af2ff --- /dev/null +++ b/.github/workflows/scripts/weekly_office_hours/run @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 +# +# @license Apache-2.0 +# +# Copyright (c) 2026 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Script to generate an office hours GitHub issue body for the next Tuesday. +# +# Environment variables: +# +# GITHUB_OUTPUT Path to the GitHub Actions output file. +# +# Outputs: +# +# office_hours_body.md Markdown file containing the issue body. +# meeting_date GitHub Actions step output with the meeting date (YYYY-MM-DD). + +import datetime +import os +import zoneinfo + + +# VARIABLES # + +# Compute the date of the next Tuesday (7 days out when run on Tuesday): +today = datetime.date.today() +days_until_tuesday = (1 - today.weekday()) % 7 +if days_until_tuesday == 0: + days_until_tuesday = 7 +next_tuesday = today + datetime.timedelta(days=days_until_tuesday) + +# Meeting time is 9:30 AM US/Pacific; DST is handled automatically: +pacific_tz = zoneinfo.ZoneInfo('America/Los_Angeles') +meeting_dt = datetime.datetime( + next_tuesday.year, next_tuesday.month, next_tuesday.day, + 9, 30, 0, tzinfo=pacific_tz +) + +utc_dt = meeting_dt.astimezone(datetime.timezone.utc) + +timezones = [ + ('US / Pacific', 'America/Los_Angeles'), + ('US / Mountain', 'America/Denver'), + ('US / Central', 'America/Chicago'), + ('US / Eastern', 'America/New_York'), + ('EU / Western', 'Europe/London'), + ('EU / Central', 'Europe/Paris'), + ('EU / Eastern', 'Europe/Helsinki'), + ('Moscow', 'Europe/Moscow'), + ('Chennai', 'Asia/Kolkata'), + ('Hangzhou', 'Asia/Shanghai'), + ('Tokyo', 'Asia/Tokyo'), + ('Sydney', 'Australia/Sydney'), +] + +date_str = next_tuesday.strftime('%Y-%m-%d') +iso_str = utc_dt.strftime('%Y%m%dT%H%M') + + +# FUNCTIONS # + +def fmt_time(dt): + return dt.strftime('%H:%M (%I:%M %p)') + + +# MAIN # + +utc_header = '**UTC {} {}**:'.format( + utc_dt.strftime('%a %d-%b-%Y'), + fmt_time(utc_dt) +) + +table_rows = [] +for tz_name, tz_id in timezones: + local_dt = meeting_dt.astimezone(zoneinfo.ZoneInfo(tz_id)) + table_rows.append('| {} | {} {} |'.format( + tz_name, + local_dt.strftime('%a %d-%b-%Y'), + fmt_time(local_dt) + )) + +timeanddate_url = ( + 'https://www.timeanddate.com/worldclock/fixedtime.html' + '?msg=stdlib%20Office+Hours+{}&iso={}'.format(date_str, iso_str) +) + +body = """\ +## \U0001f31f Join Us for Weekly Office Hours! \U0001f31f + +Have questions about [stdlib](https://github.com/stdlib-js/stdlib)? Need help fixing a bug, figuring out what to do next, or just looking for feedback? Join our weekly office hours to connect with project maintainers, stay updated on the latest project news, and chat with other community members. This is a great opportunity to ask questions, share ideas, and engage directly with the stdlib team. + +Everyone is welcome—drop in and say hello! + +## Time + +{utc_header} + +| Timezone | Date/Time | +| ---------- | ---------- | +{table} + +or in your local time: + +- <{url}> + +## Links + +- Public calendar: + +## Joining the meeting + +- Google Meet link: + +## Agenda + +- Have specific things to discuss? Please comment in the issue thread below to add specific items to the agenda. +""".format( + utc_header=utc_header, + table='\n'.join(table_rows), + url=timeanddate_url +) + +with open('office_hours_body.md', 'w') as f: + f.write(body) + +github_output = os.environ.get('GITHUB_OUTPUT') +if github_output: + with open(github_output, 'a') as f: + f.write('meeting_date={}\n'.format(date_str)) diff --git a/.github/workflows/weekly_office_hours.yml b/.github/workflows/weekly_office_hours.yml index af7122b..301ad38 100644 --- a/.github/workflows/weekly_office_hours.yml +++ b/.github/workflows/weekly_office_hours.yml @@ -29,6 +29,13 @@ on: # Allow the workflow to be manually run: workflow_dispatch: +# Global permissions: +permissions: + # Allow read-only access to the repository contents: + contents: read + # Allow write access to issues: + issues: write + # Workflow jobs: jobs: @@ -53,116 +60,15 @@ jobs: # Generate the issue body with computed dates and timezone conversions: - name: 'Generate office hours issue body' id: generate - run: | - python3 << 'PYEOF' - import datetime - import zoneinfo - import os - - # Compute the date of the next Tuesday (7 days out when run on Tuesday): - today = datetime.date.today() - days_until_tuesday = (1 - today.weekday()) % 7 - if days_until_tuesday == 0: - days_until_tuesday = 7 - next_tuesday = today + datetime.timedelta(days=days_until_tuesday) - - # Meeting time is 9:30 AM US/Pacific; DST is handled automatically: - pacific_tz = zoneinfo.ZoneInfo('America/Los_Angeles') - meeting_dt = datetime.datetime( - next_tuesday.year, next_tuesday.month, next_tuesday.day, - 9, 30, 0, tzinfo=pacific_tz - ) - - utc_dt = meeting_dt.astimezone(datetime.timezone.utc) - - def fmt_time(dt): - return dt.strftime('%H:%M (%I:%M %p)') - - utc_header = '**UTC {} {}**:'.format( - utc_dt.strftime('%a %d-%b-%Y'), - fmt_time(utc_dt) - ) - - timezones = [ - ('US / Pacific', 'America/Los_Angeles'), - ('US / Mountain', 'America/Denver'), - ('US / Central', 'America/Chicago'), - ('US / Eastern', 'America/New_York'), - ('EU / Western', 'Europe/London'), - ('EU / Central', 'Europe/Paris'), - ('EU / Eastern', 'Europe/Helsinki'), - ('Moscow', 'Europe/Moscow'), - ('Chennai', 'Asia/Kolkata'), - ('Hangzhou', 'Asia/Shanghai'), - ('Tokyo', 'Asia/Tokyo'), - ('Sydney', 'Australia/Sydney'), - ] - - table_rows = [] - for tz_name, tz_id in timezones: - local_dt = meeting_dt.astimezone(zoneinfo.ZoneInfo(tz_id)) - table_rows.append('| {} | {} {} |'.format( - tz_name, - local_dt.strftime('%a %d-%b-%Y'), - fmt_time(local_dt) - )) - - date_str = next_tuesday.strftime('%Y-%m-%d') - iso_str = utc_dt.strftime('%Y%m%dT%H%M') - timeanddate_url = ( - 'https://www.timeanddate.com/worldclock/fixedtime.html' - '?msg=stdlib%20Office+Hours+{}&iso={}'.format(date_str, iso_str) - ) - - body = """\ -## \U0001f31f Join Us for Weekly Office Hours! \U0001f31f - -Have questions about [stdlib](https://github.com/stdlib-js/stdlib)? Need help fixing a bug, figuring out what to do next, or just looking for feedback? Join our weekly office hours to connect with project maintainers, stay updated on the latest project news, and chat with other community members. This is a great opportunity to ask questions, share ideas, and engage directly with the stdlib team. - -Everyone is welcome—drop in and say hello! - -## Time - -{utc_header} - -| Timezone | Date/Time | -| ---------- | ---------- | -{table} - -or in your local time: - -- <{url}> - -## Links - -- Public calendar: - -## Joining the meeting - -- Google Meet link: - -## Agenda - -- Have specific things to discuss? Please comment in the issue thread below to add specific items to the agenda. -""".format( - utc_header=utc_header, - table='\n'.join(table_rows), - url=timeanddate_url - ) - - with open('office_hours_body.md', 'w') as f: - f.write(body) - - with open(os.environ['GITHUB_OUTPUT'], 'a') as f: - f.write('meeting_date={}\n'.format(date_str)) - - PYEOF + run: python3 .github/workflows/scripts/weekly_office_hours/run + timeout-minutes: 5 # Create an issue: - name: 'Create issue' # Pin action to full length commit SHA uses: peter-evans/create-issue-from-file@d60bea1e77c1b5c523216f7c31493883d76ffad7 # v4.0.1 + timeout-minutes: 5 with: title: Office Hours (${{ steps.generate.outputs.meeting_date }}) content-filepath: ./office_hours_body.md