-
Notifications
You must be signed in to change notification settings - Fork 20
ci: automate versioning and releases with changesets #60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
023e91b
de7cce9
cc9845b
eb2f10a
bd3f325
ce0edf6
31c18f0
2bfbc2c
bb733a8
4848fb9
1e066a8
0d3c3cd
a7e1075
d3db59c
4d7821c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # Changesets | ||
|
|
||
| This directory contains [**Changesets**](https://github.com/changesets/changesets) which are markdown files that describe package changes for the next release. | ||
|
|
||
| For guidance on when and how to add changesets, checkout the [Maintainer's Guide](../.github/maintainers_guide.md#-updating-changesets). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", | ||
| "changelog": "@changesets/cli/changelog", | ||
| "commit": false, | ||
| "fixed": [], | ||
| "linked": [], | ||
| "access": "restricted", | ||
| "baseBranch": "main", | ||
| "updateInternalDependencies": "patch", | ||
| "ignore": [], | ||
| "privatePackages": { | ||
| "version": true, | ||
| "tag": true | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,7 @@ brew update | |
| brew install pyenv | ||
| ``` | ||
|
|
||
| Install necessary Python runtimes for development/testing. You can rely on GitHub Actions workflows for testing with various major versions. <https://github.com/slackapi/bolt-python/tree/main/.github/workflows> | ||
| Install necessary Python runtime for development/testing. | ||
|
|
||
| ```sh | ||
| $ pyenv install 3.14 # select the latest patch version | ||
|
|
@@ -46,14 +46,50 @@ source .venv/bin/activate | |
|
|
||
| ## Versioning | ||
|
|
||
| Follow the [conventional commit specification][conv-commits]. PR titles and | ||
| commit messages use prefixes like `feat:`, `fix:`, `chore:`, `docs:`, etc. | ||
| First letter after the prefix is lowercase unless it's a proper noun. | ||
| Follow the [conventional commit specification][conv-commits]. PR titles and commit messages use prefixes like `feat:`, `fix:`, `chore:`, `docs:`, etc. First letter after the prefix is lowercase unless it's a proper noun. | ||
|
|
||
| ### Plugin version bumps | ||
| ### 🎁 Updating Changesets | ||
|
|
||
| Every release must bump the `version` field in | ||
| `.claude-plugin/plugin.json` and `.cursor-plugin/plugin.json` following [semver][semver]. | ||
| This project uses [Changesets](https://github.com/changesets/changesets) to track changes and automate releases. | ||
|
|
||
| Each changeset describes a change to the package and its [semver][semver] impact, and a new changeset should be added when updating the package with some change that affects consumers: | ||
|
|
||
| ```sh | ||
| npx changeset add | ||
| ``` | ||
|
|
||
| Alternatively, hand-write a file named `.changeset/<anything>.md`, with this format: | ||
|
|
||
| ```md | ||
| --- | ||
| "slack": minor | ||
| --- | ||
|
|
||
| Add the channel-digest command | ||
| ``` | ||
|
|
||
| The frontmatter key is always `"slack"`; the value is the [semver][semver] bump level, like `patch`, `minor`, or `major`. The body becomes the changelog entry, so write it for a reader of the release notes. | ||
|
|
||
| Updates to documentation, tests, or CI might not require new entries. | ||
|
|
||
| When a PR containing changesets is merged to `main`, a different PR is opened or updated using [changesets/action](https://github.com/changesets/action) which consumes the pending changesets, bumps the package version, and updates the `CHANGELOG` in preparation to release. | ||
|
|
||
| ### 🚀 Releases | ||
|
|
||
| Releasing can feel intimidating at first, but don't fret! Venture on! | ||
|
|
||
| New official package versions are published when the release PR created from changesets is merged. Follow these steps to build confidence: | ||
|
|
||
| 1. **Run the tests locally**: Before merging the release PR please run all the tests especially the eval ones. If they no longer pass we may need fix it before releasing the changes. | ||
|
|
||
| 2. **Check GitHub**: Please check if issues or pull requests are still open either decide to postpone the release or save those changes for a future update. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔮 question: Are milestones something we want to introduce here, either now or later?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd want to refrain from using milestones 🤔 I find they tend to clutter our release process and Its not clear to me what our users gain from them
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have to agree with @WilliamBergamin - Milestones feel like a forgotten feature of GitHub and GitHub Releases serve as a way of documenting what landed in a release. Milestones have benefit when changes land across multiple versions ("Next Release" vs "Next Major Release"). But this project doesn't need that complexity.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @WilliamBergamin @mwbrooks I agree in the overhead without obvious benefit. No problem omitting these for the project! Some PRs might find a moment of confusion without a milestone to add but this isn't meaningful enough to change for 📠 |
||
|
|
||
| 3. **Review the release PR**: Verify that the version bump matches expectations, `CHANGELOG` entries are clear, and CI checks pass. | ||
|
|
||
| 4. **Merge and approve**: Merge the release PR. It may take up to 24 hours before you see you release in the [Claude Plugins](https://claude.com/plugins/slack) directory. | ||
|
|
||
| 5. **Communicate the release**: | ||
| - **External**: Post in relevant channels (e.g. #lang-javascript, #tools-bolt) on [Slack Community](https://community.slack.com/). Include a link to the release notes. | ||
|
|
||
| ## Everything Else | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| name: Release | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| workflow_dispatch: | ||
|
|
||
| # Don't let two release runs race on the same branch. | ||
| concurrency: ${{ github.workflow }}-${{ github.ref }} | ||
|
|
||
| env: | ||
| PY_VERSION: "3.14" | ||
| NODE_VERSION: "26" | ||
|
|
||
| jobs: | ||
| release: | ||
| name: Release | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 10 | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| steps: | ||
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | ||
| with: | ||
| fetch-depth: 0 | ||
|
WilliamBergamin marked this conversation as resolved.
|
||
| persist-credentials: false | ||
| - name: Set up Node ${{ env.NODE_VERSION }} | ||
| uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | ||
| with: | ||
| node-version: ${{ env.NODE_VERSION }} | ||
| - name: Set up Python ${{ env.PY_VERSION }} | ||
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | ||
| with: | ||
| python-version: ${{ env.PY_VERSION }} | ||
| - name: Install Node dependencies | ||
| run: npm install | ||
| - name: Changesets release | ||
| uses: changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d # v1.9.0 | ||
| with: | ||
| version: bash scripts/changeset_version.sh | ||
| publish: npx changeset publish | ||
| commit: "chore: release" | ||
| title: "chore: release" | ||
| prDraft: create | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎁 suggestion: I think we should include the 🍰 ramble: I'm not wanting to add separate documentation for this either! I'm curious if the |
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,11 @@ | ||||||||||||
| { | ||||||||||||
| "name": "slack", | ||||||||||||
| "version": "1.1.0", | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: Let's add the required Node.js verson to the package.json. While testing on my local machine, my
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch 💯 |
||||||||||||
| "private": true, | ||||||||||||
| "engines": { | ||||||||||||
| "node": ">=26" | ||||||||||||
| }, | ||||||||||||
| "devDependencies": { | ||||||||||||
| "@changesets/cli": "^2.31.0" | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🌟 praise: Great to see these scripts extended so well!
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bash, Node, and Python all for a project that only needs markdown 😆 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| npx changeset version | ||
| python scripts/sync_versions.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import json | ||
| import logging | ||
| from pathlib import Path | ||
|
|
||
| logger = logging.getLogger(Path(__file__).stem) | ||
|
|
||
| REPO_ROOT = Path(__file__).resolve().parent.parent | ||
|
|
||
| # package.json (committed at the repo root) is the version source of truth; changesets | ||
| # bumps it, then this script synchronizes the version out to everywhere else its defined. | ||
| PACKAGE_JSON_PATH = REPO_ROOT / "package.json" | ||
| CLAUDE_PLUGIN_PATH = REPO_ROOT / ".claude-plugin" / "plugin.json" | ||
| CURSOR_PLUGIN_PATH = REPO_ROOT / ".cursor-plugin" / "plugin.json" | ||
|
|
||
|
|
||
| def read_version(package_path: Path) -> str: | ||
| """Return the ``version`` field from ``package.json``.""" | ||
| return json.loads(package_path.read_text())["version"] | ||
|
|
||
|
|
||
| def write_version(plugin_path: Path, version: str) -> None: | ||
| """Set the ``version`` field of a JSON plugin manifest.""" | ||
| manifest = json.loads(plugin_path.read_text()) | ||
| manifest["version"] = version | ||
|
Comment on lines
+22
to
+24
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👁️🗨️ thought: I'm curious if separate functions for different targets might improve maintenance but not a blocker whatsoever- |
||
| plugin_path.write_text(json.dumps(manifest, indent=2) + "\n") | ||
| logger.info(f"Set {plugin_path} version to {version}") | ||
|
|
||
|
|
||
| def main() -> None: | ||
| logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") | ||
| version = read_version(PACKAGE_JSON_PATH) | ||
| write_version(CLAUDE_PLUGIN_PATH, version) | ||
| write_version(CURSOR_PLUGIN_PATH, version) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🦠 note: I'm finding the
npxversion of "changesets" returns a different version🔬 ramble: I'm leaving a comment with
package.jsontowards this so am holding off on a suggestion!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point I added this to the
package.json