Skip to content

chore: standardize release process#171

Draft
tylerjroach wants to merge 4 commits into
masterfrom
release/standardize-release-process
Draft

chore: standardize release process#171
tylerjroach wants to merge 4 commits into
masterfrom
release/standardize-release-process

Conversation

@tylerjroach
Copy link
Copy Markdown

Summary

Standardizes this repo's release process to match the rest of the Mixpanel SDK fleet, per the SDK Release Process Standardization Effort.

After merge, releases follow a uniform two-step ceremony:

  1. Run the Prepare Release workflow (prepare-release.yml) — opens a release PR with the version bump, changelog section, and README header line updated.
  2. Push the release tag — release-pypi.yml validates, gates on the release GitHub environment for human approval, and publishes (where applicable for this ecosystem).

What's added

  • .github/modules.json — single source of truth for module config (paths, tag prefixes, package names)
  • .github/workflows/prepare-release.yml — manual dispatch, opens release PR
  • .github/workflows/release-pypi.yml — tag-triggered publish workflow
  • .github/workflows/pr-title-check.yml — conventional-commit enforcement (regex built from modules.json)
  • .github/scripts/generate-changelog.sh — shared changelog generator (verbatim from mixpanel-android)
  • README version-header line on each module's README, seeded with the current latest tag
  • CHANGELOG.md per module where missing
  • Two modules covered: analytics (mixpanel on PyPI) and openfeature (mixpanel-openfeature on PyPI)
  • The legacy CHANGES.txt is left in place for historical continuity; the new auto-generated section format goes into CHANGELOG.md
  • PyPI Trusted Publisher entries are required for both packages — see runbook

How releases work after this lands

Full ceremony, one-time setup, and PR title conventions: Python [PIP] Release Runbook

One-time setup before the first release

The runbook lists the full setup. The work that requires repo-admin access (cannot be done in this PR):

  • Create a GitHub Environment named release with required reviewer(s)
  • Branch protection on the default branch (require PR review + the new Validate PR title check)
  • Tag rulesets (restrict creation/update/deletion of release tags)
  • Workflow permissions: enable Read and write permissions and Allow GitHub Actions to create and approve pull requests (needed by prepare-release.yml's gh pr create)

Notes

  • This is a WIP draft to be reviewed alongside the equivalent PRs in the other SDK repos. The Flutter and React Native ports are tracked at mixpanel-flutter#238, mixpanel-flutter-session-replay#30, mixpanel-react-native#408, mixpanel-react-native-session-replay#64.
  • This PR does not change any source code or build behavior — only adds release infrastructure.
  • The standardization commit is followed by a small fix: commit correcting a jq tag-resolution snippet (the same bug exists in the WIP Flutter/RN PRs and should be back-ported there).

Adds the shared release infrastructure (prepare-release, release-pypi,
pr-title-check workflows + modules.json + generate-changelog.sh) so this
repo's release flow matches the other Mixpanel SDK repositories.

Notes specific to this repo:
- The analytics module's version source is dynamic (`pyproject.toml` declares
  `version = {attr = "mixpanel.__version__"}`), so `version_files` points at
  `mixpanel/__init__.py` where the literal `__version__` lives. The prepare
  workflow detects dynamic vs literal automatically.
- The legacy `CHANGES.txt` is preserved as-is for historical continuity. New
  releases will append to a new top-level `CHANGELOG.md` (and to
  `openfeature-provider/CHANGELOG.md`) so the auto-generated section format
  matches every other standardized repo.
- Publishing uses PyPI Trusted Publishing (OIDC); no long-lived API tokens.

See: https://www.notion.so/348e0ba925628029af63c779caa835f9
The previous form `select($t | startswith(.value.tag_prefix))` rebinds the
context inside `select` so `.value` is no longer the entry — jq errors with
"Cannot index string with string \"value\"" and every tag push fails.

Bind the prefix first via `.value.tag_prefix as $p` so the comparison runs
against the captured variable.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.50%. Comparing base (2c364ad) to head (54cc16c).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #171   +/-   ##
=======================================
  Coverage   94.50%   94.50%           
=======================================
  Files          12       12           
  Lines        1947     1947           
  Branches      116      116           
=======================================
  Hits         1840     1840           
  Misses         70       70           
  Partials       37       37           
Flag Coverage Δ
openfeature-provider 53.76% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Aligns the changelog-section extraction with the deployed mixpanel-android
release workflow, which uses a sed range. The Python regex implementation
was an accident of port-time authorship; sed is the proven approach in the
gold-standard Maven Central pipeline.

Uses `\@...@` as the sed address delimiter so tags containing `/` (e.g.
`openfeature/v0.1.0`) don't conflict with the default `/`. Behavior is
otherwise preserved: file-based release_notes.md output, fallback to
"Release $TAG" placeholder when the section is missing or empty, and the
two-step structure for log visibility in the workflow run.
Aligns with the Android fleet's convention of allowing `feat(all): ...`,
`fix(all): ...`, `chore(all): ...` for cross-cutting changes that should
appear in every module's changelog. The shared generate-changelog.sh
already matches `all` (it was copied verbatim from mixpanel-android), so
this regex change is the only piece needed to make the end-to-end flow
accept `all`-scoped PR titles.

For single-module repos, `feat(all): foo` is functionally equivalent to
`feat(<only-module>): foo` — kept for fleet-wide consistency.
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.

1 participant