Skip to content

Adding milestone release calendar sync workflow#48593

Merged
georgekarrv merged 3 commits into
mainfrom
gkarr-release-calendar-sync
Jul 22, 2026
Merged

Adding milestone release calendar sync workflow#48593
georgekarrv merged 3 commits into
mainfrom
gkarr-release-calendar-sync

Conversation

@georgekarrv

@georgekarrv georgekarrv commented Jul 1, 2026

Copy link
Copy Markdown
Member

This is a calendar sync workflow to trigger off of milestones being created or due dates being updated to keep the release calendar automatically in sync

example of me running it locally

❯ python sync.py --oauth --client-secret ./gcal-releases-oauth.json --apply
# Fleet release calendar sync — 2026-07-01 14:50

Calendar: <redacted>@group.calendar.google.com
Repo:     fleetdm/fleet

## Milestones
  4.88.0  due 2026-07-01
  4.89.0  due 2026-07-10
  4.90.0  due 2026-07-31
  4.91.0  due 2026-08-21
  4.92.0  due 2026-09-11
  4.93.0  due 2026-10-02
  4.94.0  due 2026-10-23
  4.95.0  due 2026-11-13
  4.96.0  due 2026-12-04
  4.97.0  due 2026-12-25
  4.98.0  due 2027-01-15
  4.99.0  due 2027-02-05
  4.100.0  due 2027-02-26
  4.101.0  due 2027-03-19
  4.102.0  due 2027-04-09

## Events scanned
  [develop    ] 'Develop (next release - 4.87.0)'  start=2026-05-18  end=2026-06-06
  [develop    ] 'Develop (next release - 4.89.0)'  start=2026-06-08  end=2026-06-27
  [rc         ] 'Release candidate (next release - 4.87.0)'  start=2026-06-08  end=2026-06-20
  [release_day] 'Release day: minor release - 4.87.0'  start=2026-06-19  end=2026-06-20
  [develop    ] 'Develop (next release - 4.90.0)'  start=2026-06-29  end=2026-07-18
  [rc         ] 'Release candidate (next release - 4.89.0)'  start=2026-06-29  end=2026-07-11
  [release_day] 'Release day: minor release - 4.89.0'  start=2026-07-10  end=2026-07-11
  [develop    ] 'Develop (next release - 4.91.0)'  start=2026-07-20  end=2026-08-08
  [rc         ] 'Release candidate (next release - 4.90.0)'  start=2026-07-20  end=2026-08-01
  [release_day] 'Release day: minor release - 4.90.0'  start=2026-07-31  end=2026-08-01
  [develop    ] 'Develop (next release - 4.92.0)'  start=2026-08-10  end=2026-08-29
  [rc         ] 'Release candidate (next release - 4.91.0)'  start=2026-08-10  end=2026-08-22
  [release_day] 'Release day: minor release - 4.91.0'  start=2026-08-21  end=2026-08-22
  [develop    ] 'Develop (next release - 4.93.0)'  start=2026-08-31  end=2026-09-19
  [rc         ] 'Release candidate (next release - 4.92.0)'  start=2026-08-31  end=2026-09-12
  [release_day] 'Release day: minor release - 4.92.0'  start=2026-09-11  end=2026-09-12
  [develop    ] 'Develop (next release - 4.94.0)'  start=2026-09-21  end=2026-10-10
  [rc         ] 'Release candidate (next release - 4.93.0)'  start=2026-09-21  end=2026-10-03
  [release_day] 'Release day: minor release - 4.93.0'  start=2026-10-02  end=2026-10-03
  [develop    ] 'Develop (next release - 4.95.0)'  start=2026-10-12  end=2026-10-31
  [rc         ] 'Release candidate (next release - 4.94.0)'  start=2026-10-12  end=2026-10-24
  [release_day] 'Release day: minor release - 4.94.0'  start=2026-10-23  end=2026-10-24
  [develop    ] 'Develop (next release - 4.96.0)'  start=2026-11-02  end=2026-11-21
  [rc         ] 'Release candidate (next release - 4.95.0)'  start=2026-11-02  end=2026-11-14
  [release_day] 'Release day: minor release - 4.95.0'  start=2026-11-13  end=2026-11-14
  [develop    ] 'Develop (next release - 4.97.0)'  start=2026-11-23  end=2026-12-12
  [rc         ] 'Release candidate (next release - 4.96.0)'  start=2026-11-23  end=2026-12-05
  [release_day] 'Release day: minor release - 4.96.0'  start=2026-12-04  end=2026-12-05
  [develop    ] 'Develop (next release - 4.98.0)'  start=2026-12-14  end=2027-01-02
  [rc         ] 'Release candidate (next release - 4.97.0)'  start=2026-12-14  end=2026-12-26
  [release_day] 'Release day: minor release - 4.97.0'  start=2026-12-25  end=2026-12-26
  [rc         ] 'Release candidate (next release - 4.90.0)'  start=2027-01-04  end=2027-01-16

## Proposed actions
  RC 4.98.0: title 'Release candidate (next release - 4.90.0)' -> 'Release candidate (next release - 4.98.0)'
  + CREATE Release day 4.88.0 on 2026-07-01
  + CREATE RC 4.88.0 2026-06-27..2026-07-02
  + CREATE Release day 4.98.0 on 2027-01-15
  + CREATE Release day 4.99.0 on 2027-02-05
  + CREATE RC 4.99.0 2027-02-01..2027-02-06
  + CREATE Develop 4.99.0 2027-01-04..2027-01-23
  + CREATE Release day 4.100.0 on 2027-02-26
  + CREATE RC 4.100.0 2027-02-22..2027-02-27
  + CREATE Develop 4.100.0 2027-01-25..2027-02-13
  + CREATE Release day 4.101.0 on 2027-03-19
  + CREATE RC 4.101.0 2027-03-15..2027-03-20
  + CREATE Develop 4.101.0 2027-02-15..2027-03-06
  + CREATE Release day 4.102.0 on 2027-04-09
  + CREATE RC 4.102.0 2027-04-05..2027-04-10
  + CREATE Develop 4.102.0 2027-03-08..2027-03-27

## Warnings / skipped
  ! Develop event 'Develop (next release - 4.87.0)' ending 2026-06-05 has no matching minor milestone — skipped
  ! RC event 'Release candidate (next release - 4.87.0)' ending 2026-06-19 has no matching milestone — skipped
  ! Release day event 'Release day: minor release - 4.87.0' on 2026-06-19 has no matching milestone (within 5d) — skipped
  ! Skipping Develop create for 4.88.0: sprint ended 2026-06-17 (past)

Total: 1 rename, 0 move, 15 create, 4 warning

Applying 16 change(s)...
  ok: RC 4.98.0: title 'Release candidate (next release - 4.90.0)' -> 'Release candidate (next release - 4.98.0)'
  ok: + CREATE Release day 4.88.0 on 2026-07-01
  ok: + CREATE RC 4.88.0 2026-06-27..2026-07-02
  ok: + CREATE Release day 4.98.0 on 2027-01-15
  ok: + CREATE Release day 4.99.0 on 2027-02-05
  ok: + CREATE RC 4.99.0 2027-02-01..2027-02-06
  ok: + CREATE Develop 4.99.0 2027-01-04..2027-01-23
  ok: + CREATE Release day 4.100.0 on 2027-02-26
  ok: + CREATE RC 4.100.0 2027-02-22..2027-02-27
  ok: + CREATE Develop 4.100.0 2027-01-25..2027-02-13
  ok: + CREATE Release day 4.101.0 on 2027-03-19
  ok: + CREATE RC 4.101.0 2027-03-15..2027-03-20
  ok: + CREATE Develop 4.101.0 2027-02-15..2027-03-06
  ok: + CREATE Release day 4.102.0 on 2027-04-09
  ok: + CREATE RC 4.102.0 2027-04-05..2027-04-10
  ok: + CREATE Develop 4.102.0 2027-03-08..2027-03-27

We can now get rid of the recurring unnamed events and just rely on this once it's merged and added to milestone updates to trigger automatically

Summary by CodeRabbit

  • New Features
    • Added a release calendar synchronization tool that aligns Google Calendar events with open release milestone dates.
    • Supports dry-run previews and an optional apply mode to create, update, and delete events.
    • Categorizes and matches release-day, release-candidate, and development entries, including duplicate and stale event cleanup.
    • Added a manually triggered workflow to run the sync securely with configurable apply behavior.
    • Added support for service-account authentication and optional interactive OAuth.

Copilot AI review requested due to automatic review settings July 1, 2026 19:53

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds a Python CLI that synchronizes Google Calendar release events with open GitHub milestone due dates. It supports service-account and OAuth authentication, event matching, duplicate and stale-event handling, dry-run plan rendering, and applying calendar changes. It also adds dependency declarations and a manually triggered GitHub Actions workflow with selectable dry-run or apply execution modes.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the feature, but it omits required template sections like Related issue, checklist items, and Testing/QA details. Add the template sections, including a Related issue line and filled-out checklist/testing notes for validation, tests, and QA.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: a milestone-driven release calendar sync workflow.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gkarr-release-calendar-sync

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread tools/release/calendar-sync/sync.py Fixed
working-directory: tools/release/calendar-sync
env:
GCAL_SERVICE_ACCOUNT_JSON: ${{ secrets.GCAL_SERVICE_ACCOUNT_JSON }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lukeheath @allenhouchins before we merge this it would be good to add these to manage reading the milestones and updating the release calendar.

I tested locally with an oauth client and my gh auth token and tested dry-run and --apply to create the next milestone calendar events in 2027.

Let me know if you have any questions.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also fine if we want to just check this in and run it manually if the calendar ever de-syncs and remove this action. Just thought it would be easier if the workflow automation happened w/o anyone needing to remember

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@georgekarrv sorry for the delay on this. I can set up the service account if you can shoot me over what permissions it needs.

Also, should we change 4.100 to 5.0 to help force our hand?! :-)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Google Cloud (the service account itself):

  1. In the project, enable the Google Calendar API.
  2. Create a service account and generate a JSON key. No project-level IAM roles needed — it doesn't touch any GCP resources.

Calendar access (this is what scopes it to just our calendar):
4. Open the Fleet releases calendar → Settings and sharing → Share with specific people or groups.
5. Add the service account's email (…@…iam.gserviceaccount.com) with "Make changes to events."

  • Not "Make changes and manage sharing" — it never touches ACLs.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/calendar-sync.yml:
- Around line 23-26: Update the Harden Runner step in the calendar sync workflow
to use blocked egress instead of audit, and configure an allowlist containing
only the GitHub and Google API endpoints required by the job. Preserve the
existing secret-bearing steps and ensure their outbound requests remain
functional under the restricted policy.
- Around line 15-16: Update the workflow permissions block to grant read access
to issues in addition to contents, so the milestone API calls made by sync.py
can succeed.
- Around line 28-35: Upgrade the action references in the workflow: replace the
v3.6.0 pin for actions/checkout and the v4.7.1 pin for actions/setup-python with
current releases, and update each to its corresponding immutable commit SHA
while retaining the version comments.

In `@tools/release/calendar-sync/sync.py`:
- Around line 60-62: Update RELEASE_DAY_RE, RC_RE, and DEVELOP_RE to match both
legacy unversioned event titles and their current versioned forms by making the
version suffix optional while preserving existing whitespace and summary
constraints. Ensure the matching logic at the planner and replacement-handling
references also recognizes these legacy recurring events before creating
replacements.
- Around line 488-516: Prevent duplicate creation of overdue milestone events in
the unmatched-event handling for release-day and RC actions. Update the scan
range to include the earliest open milestone, or add a release-date check before
appending create actions in the relevant milestone loop and the corresponding
logic around lines 666–688, skipping events whose release date has passed. Use
the existing milestone date helpers and matching logic consistently.
- Around line 147-172: Update oauth_credentials to persist token_path with
owner-only permissions (0600). Ensure this applies both when creating the file
and when replacing an existing token, using an appropriate secure file-writing
or chmod approach around the existing open/write logic.
- Around line 207-221: Update apply_action to handle timed events consistently
with fetch_events: when applying a move or date change, patch the event’s
start.dateTime and end.dateTime fields, preserving the appropriate time and
timezone information, or explicitly reject timed events before they enter the
action plan. Use the existing fetch_events and apply_action symbols to locate
both sides of the behavior.
- Around line 291-299: Update desired_rc() so the PATCH_RC_DURATION_DAYS
short-window fallback is used only when m.out_of_band is true; for normal
milestones without current_start, preserve the appropriate standard RC start
behavior. Ensure plan_actions() missing-RC creation via desired_rc(m, None) no
longer assigns the short patch window to regular milestones.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ac04358a-edd1-47fa-8cde-0acccf62216f

📥 Commits

Reviewing files that changed from the base of the PR and between 8cf4a7c and c56c23a.

⛔ Files ignored due to path filters (1)
  • tools/release/calendar-sync/README.md is excluded by !**/*.md
📒 Files selected for processing (3)
  • .github/workflows/calendar-sync.yml
  • tools/release/calendar-sync/requirements.txt
  • tools/release/calendar-sync/sync.py

Comment thread .github/workflows/calendar-sync.yml
Comment thread .github/workflows/calendar-sync.yml Outdated
Comment thread .github/workflows/calendar-sync.yml Outdated
Comment thread tools/release/calendar-sync/sync.py
Comment thread tools/release/calendar-sync/sync.py
Comment thread tools/release/calendar-sync/sync.py
Comment thread tools/release/calendar-sync/sync.py
Comment thread tools/release/calendar-sync/sync.py
@georgekarrv

Copy link
Copy Markdown
Member Author

Just marking as Draft until @lukeheath and @allenhouchins get a chance to look. It's ready for review but has already been open a while.

@georgekarrv
georgekarrv marked this pull request as draft July 10, 2026 17:29
@georgekarrv
georgekarrv marked this pull request as ready for review July 22, 2026 19:57
@georgekarrv
georgekarrv merged commit 6d68bd6 into main Jul 22, 2026
10 checks passed
@georgekarrv
georgekarrv deleted the gkarr-release-calendar-sync branch July 22, 2026 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants