feat(HAI-081): add changesets-based automated versioning and release workflow
- Install and configure @changesets/cli with commit/access settings - Create version PR workflow (.github/workflows/version.yml) for automated version bumps - Update existing release and test-release workflows with version validation - Add example changeset and version tests for CI verification - Add RELEASING.md guide and update README with versioning documentation
This commit is contained in:
8
.changeset/README.md
Normal file
8
.changeset/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Changesets
|
||||
|
||||
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
||||
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
||||
find the full documentation for it [in our repository](https://github.com/changesets/changesets).
|
||||
|
||||
We have a quick list of common questions to get you started engaging with this project in
|
||||
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md).
|
||||
5
.changeset/add-auto-versioning.md
Normal file
5
.changeset/add-auto-versioning.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"hai": minor
|
||||
---
|
||||
|
||||
Add automated versioning pipeline using changesets. Developers now add changeset files to describe changes, and a CI workflow automatically opens version PRs that bump versions and generate changelogs.
|
||||
11
.changeset/config.json
Normal file
11
.changeset/config.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config@3.1.3/schema.json",
|
||||
"changelog": "@changesets/cli/changelog",
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
"access": "restricted",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": []
|
||||
}
|
||||
15
.github/workflows/release.yml
vendored
15
.github/workflows/release.yml
vendored
@@ -45,6 +45,21 @@ jobs:
|
||||
- name: Install Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Extract version from tag
|
||||
run: |
|
||||
VERSION="${GITHUB_REF#refs/tags/v}"
|
||||
echo "RELEASE_VERSION=${VERSION}" >> $GITHUB_ENV
|
||||
echo "Releasing version: ${VERSION}"
|
||||
|
||||
- name: Verify tag matches package version
|
||||
run: |
|
||||
PKG_VERSION=$(node -p "require('./packages/cli/package.json').version")
|
||||
if [ "$RELEASE_VERSION" != "$PKG_VERSION" ]; then
|
||||
echo "ERROR: Tag version ($RELEASE_VERSION) does not match packages/cli/package.json version ($PKG_VERSION)"
|
||||
exit 1
|
||||
fi
|
||||
echo "Version check passed: $RELEASE_VERSION"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
|
||||
56
.github/workflows/version.yml
vendored
Normal file
56
.github/workflows/version.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: Version Packages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
version:
|
||||
name: Version Packages
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22"
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --no-frozen-lockfile
|
||||
|
||||
- name: Create Release Pull Request or Tag
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
version: pnpm release:version
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Push version tag
|
||||
if: steps.changesets.outputs.hasChangesets == 'false'
|
||||
run: |
|
||||
VERSION=$(node -p "require('./packages/cli/package.json').version")
|
||||
TAG="v${VERSION}"
|
||||
|
||||
# Check if tag already exists
|
||||
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
echo "Tag $TAG already exists, skipping"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git tag "$TAG"
|
||||
git push origin "$TAG"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -216,7 +216,11 @@ Download the latest binary from the [GitHub Releases](../../releases) page. Each
|
||||
|
||||
### Triggering a release
|
||||
|
||||
To create a new release, tag a version and push the tag:
|
||||
Releases are automated via [changesets](https://github.com/changesets/changesets). See [RELEASING.md](./RELEASING.md) for the full workflow.
|
||||
|
||||
In short: add a changeset with `pnpm changeset`, merge to main, then merge the auto-generated Version Packages PR to trigger a release.
|
||||
|
||||
Manual fallback — tag a version and push:
|
||||
|
||||
```bash
|
||||
git tag v0.1.0
|
||||
|
||||
62
RELEASING.md
Normal file
62
RELEASING.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Releasing
|
||||
|
||||
This project uses [changesets](https://github.com/changesets/changesets) for automated versioning and release management.
|
||||
|
||||
## How it works
|
||||
|
||||
### 1. Add a changeset
|
||||
|
||||
When you make a change that should be included in a release, add a changeset:
|
||||
|
||||
```bash
|
||||
pnpm changeset
|
||||
```
|
||||
|
||||
This will prompt you to:
|
||||
- Select which packages are affected
|
||||
- Choose the semver bump type (patch, minor, major)
|
||||
- Write a summary of the change
|
||||
|
||||
A markdown file will be created in the `.changeset/` directory. Commit this file along with your code changes.
|
||||
|
||||
### 2. Version PR is created automatically
|
||||
|
||||
When changesets are merged to `main`, a GitHub Actions workflow automatically opens (or updates) a **"Version Packages"** pull request. This PR:
|
||||
|
||||
- Consumes all pending changeset files
|
||||
- Bumps package versions according to the changeset declarations
|
||||
- Generates/updates `CHANGELOG.md` files for affected packages
|
||||
|
||||
### 3. Merge the Version PR to release
|
||||
|
||||
When you merge the Version Packages PR:
|
||||
|
||||
- The workflow detects that all changesets have been consumed
|
||||
- It creates a git tag `v{version}` based on the `hai` CLI package version
|
||||
- The tag push triggers the existing release workflow (`.github/workflows/release.yml`)
|
||||
- The release workflow builds binaries and creates a GitHub Release
|
||||
|
||||
## Manual release (fallback)
|
||||
|
||||
If you need to release manually, you can still push a version tag directly:
|
||||
|
||||
```bash
|
||||
git tag v0.2.0
|
||||
git push origin v0.2.0
|
||||
```
|
||||
|
||||
This will trigger the release workflow. Note: the workflow validates that the tag version matches `packages/cli/package.json`, so make sure they're in sync.
|
||||
|
||||
## Available scripts
|
||||
|
||||
| Script | Description |
|
||||
|--------|-------------|
|
||||
| `pnpm changeset` | Add a new changeset |
|
||||
| `pnpm changeset status` | Check pending changesets |
|
||||
| `pnpm release:version` | Apply changesets and bump versions (used by CI) |
|
||||
|
||||
## Tips
|
||||
|
||||
- Every user-facing change should have a changeset — CI will remind you if one is missing
|
||||
- You can add multiple changesets per PR if you're making changes to multiple packages
|
||||
- Changeset files are automatically deleted when versions are bumped
|
||||
12
package.json
12
package.json
@@ -10,12 +10,20 @@
|
||||
"build": "pnpm -r build",
|
||||
"build:exe": "pnpm build && pnpm --filter hai build:exe",
|
||||
"build:exe:all": "pnpm build && pnpm --filter hai build:exe:all",
|
||||
"typecheck": "pnpm -r typecheck"
|
||||
"typecheck": "pnpm -r typecheck",
|
||||
"changeset": "changeset",
|
||||
"version": "changeset version",
|
||||
"release:version": "changeset version"
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": ["esbuild", "koffi", "protobufjs"]
|
||||
"onlyBuiltDependencies": [
|
||||
"esbuild",
|
||||
"koffi",
|
||||
"protobufjs"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.30.0",
|
||||
"tsx": "^4.19.0",
|
||||
"typescript": "^5.7.0"
|
||||
}
|
||||
|
||||
46
packages/cli/src/__tests__/version.test.ts
Normal file
46
packages/cli/src/__tests__/version.test.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { readFileSync, existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
const repoRoot = join(import.meta.dirname!, "..", "..", "..", "..");
|
||||
|
||||
describe("Changeset configuration", () => {
|
||||
it("should have a valid .changeset/config.json", () => {
|
||||
const configPath = join(repoRoot, ".changeset", "config.json");
|
||||
expect(existsSync(configPath)).toBe(true);
|
||||
|
||||
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
||||
expect(config).toBeDefined();
|
||||
expect(typeof config).toBe("object");
|
||||
});
|
||||
|
||||
it("should have baseBranch set to main", () => {
|
||||
const configPath = join(repoRoot, ".changeset", "config.json");
|
||||
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
||||
expect(config.baseBranch).toBe("main");
|
||||
});
|
||||
|
||||
it("should have changeset scripts in root package.json", () => {
|
||||
const pkgPath = join(repoRoot, "package.json");
|
||||
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
||||
|
||||
expect(pkg.scripts.changeset).toBe("changeset");
|
||||
expect(pkg.scripts.version).toBe("changeset version");
|
||||
expect(pkg.scripts["release:version"]).toBe("changeset version");
|
||||
});
|
||||
|
||||
it("should have .github/workflows/version.yml with expected content", () => {
|
||||
const workflowPath = join(
|
||||
repoRoot,
|
||||
".github",
|
||||
"workflows",
|
||||
"version.yml",
|
||||
);
|
||||
expect(existsSync(workflowPath)).toBe(true);
|
||||
|
||||
const content = readFileSync(workflowPath, "utf-8");
|
||||
expect(content).toContain("changesets/action");
|
||||
expect(content).toContain("push");
|
||||
expect(content).toContain("main");
|
||||
});
|
||||
});
|
||||
743
pnpm-lock.yaml
generated
743
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user