From 76f53d99c7fd9c77fedcf743601f27859b6fa73c Mon Sep 17 00:00:00 2001 From: Yuki Fujisaki Date: Thu, 14 May 2026 17:26:36 +0900 Subject: [PATCH 1/5] test: assert release manifest version stays in sync --- .release-please-manifest.json | 3 +++ src/__tests__/plugin.test.ts | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 .release-please-manifest.json diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..96f1cd9 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "1.3.0" +} diff --git a/src/__tests__/plugin.test.ts b/src/__tests__/plugin.test.ts index 9f5efd3..7333f10 100644 --- a/src/__tests__/plugin.test.ts +++ b/src/__tests__/plugin.test.ts @@ -187,3 +187,18 @@ describe("plugin/skills/ (slash commands)", () => { expect(content).toContain("upload_app"); }); }); + +describe("version sync across release manifests", () => { + it("package.json, both plugin.json files, and the release-please manifest share the same version", () => { + const pkg = loadJson("package.json"); + const codexPlugin = loadJson("plugin/.codex-plugin/plugin.json"); + const claudePlugin = loadJson("plugin/.claude-plugin/plugin.json"); + const manifest = loadJson(".release-please-manifest.json"); + + const version = pkg.version as string; + expect(version).toMatch(/^\d+\.\d+\.\d+$/); + expect(codexPlugin.version).toBe(version); + expect(claudePlugin.version).toBe(version); + expect(manifest["."]).toBe(version); + }); +}); From 7f9eeba6bc12f2ea6d2536e1c5fa7312adba8f24 Mon Sep 17 00:00:00 2001 From: Yuki Fujisaki Date: Thu, 14 May 2026 17:29:55 +0900 Subject: [PATCH 2/5] build: add release-please config for deploygate plugin --- .release-please-config.json | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .release-please-config.json diff --git a/.release-please-config.json b/.release-please-config.json new file mode 100644 index 0000000..a9b97e4 --- /dev/null +++ b/.release-please-config.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "packages": { + ".": { + "release-type": "node", + "package-name": "deploygate", + "include-component-in-tag": true, + "include-v-in-tag": true, + "tag-separator": "--", + "extra-files": [ + { + "type": "json", + "path": "plugin/.claude-plugin/plugin.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "plugin/.codex-plugin/plugin.json", + "jsonpath": "$.version" + } + ] + } + } +} From b4a63be9251da8cfb03bb9fed1f5990ceeb9cd51 Mon Sep 17 00:00:00 2001 From: Yuki Fujisaki Date: Thu, 14 May 2026 17:31:06 +0900 Subject: [PATCH 3/5] ci: add release-please workflow --- .github/workflows/release.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..aa4d0d9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,18 @@ +name: Release + +on: + push: + branches: [main] + +permissions: + contents: write + pull-requests: write + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: googleapis/release-please-action@v4 + with: + config-file: .release-please-config.json + manifest-file: .release-please-manifest.json From c9bdf06460b02ee612666c2d69500851b62e5e33 Mon Sep 17 00:00:00 2001 From: Yuki Fujisaki Date: Thu, 14 May 2026 17:33:37 +0900 Subject: [PATCH 4/5] docs: document release flow and conventional commits --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/README.md b/README.md index 7a53712..7490896 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,37 @@ npm run build # Compile TypeScript + bundle with esbuild npm test # Run tests ``` +## Releasing + +Releases are automated by [release-please](https://github.com/googleapis/release-please). + +### Branching and commits + +- All work lands on `main` via squash-merged pull requests. +- PR titles must follow [Conventional Commits](https://www.conventionalcommits.org/): + - `feat: …` → minor version bump + - `fix: …` → patch version bump + - `feat!: …` or a body containing `BREAKING CHANGE: …` → major version bump + - `chore:`, `docs:`, `refactor:`, `test:`, `build:`, `ci:` → no version bump (and, by default, do not appear in the changelog unless `changelog-sections` is configured in `.release-please-config.json`) +- Individual commits inside a PR can have any title; only the squash-merge title matters. + +### How a release happens + +1. Merge a `feat:` or `fix:` PR into `main`. +2. The `Release` workflow opens (or updates) a Release PR that bumps the version in `package.json`, both `plugin/.claude-plugin/plugin.json` and `plugin/.codex-plugin/plugin.json`, and `.release-please-manifest.json`, and appends to `CHANGELOG.md`. +3. Merge the Release PR. +4. The `Release` workflow runs again, creates the git tag `deploygate--vX.Y.Z`, and publishes a GitHub Release. + +### Installing a specific version + +End users can pin to a tag with: + +``` +/plugin install DeployGate/deploygate-agent-plugin@deploygate--v1.4.0 +``` + +Without a pin, `claude plugin install` follows `main`. Users can fetch the latest published tag with `claude plugin update deploygate`. + ## Support & Project Status This plugin is open-source software provided **as-is on a best-effort From 7a4201b6c2fe996dd61436fd40b44f40c5faadeb Mon Sep 17 00:00:00 2001 From: Yuki Fujisaki Date: Thu, 14 May 2026 17:45:54 +0900 Subject: [PATCH 5/5] fix: include .claude-plugin/marketplace.json in release-please version sync Without this, the deploygate plugin entry's version in .claude-plugin/marketplace.json would drift after the first release-please bump. Co-Authored-By: Claude Opus 4.7 (1M context) --- .release-please-config.json | 5 +++++ README.md | 2 +- src/__tests__/plugin.test.ts | 6 +++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.release-please-config.json b/.release-please-config.json index a9b97e4..94c1cdd 100644 --- a/.release-please-config.json +++ b/.release-please-config.json @@ -17,6 +17,11 @@ "type": "json", "path": "plugin/.codex-plugin/plugin.json", "jsonpath": "$.version" + }, + { + "type": "json", + "path": ".claude-plugin/marketplace.json", + "jsonpath": "$.plugins[0].version" } ] } diff --git a/README.md b/README.md index 7490896..f358512 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ Releases are automated by [release-please](https://github.com/googleapis/release ### How a release happens 1. Merge a `feat:` or `fix:` PR into `main`. -2. The `Release` workflow opens (or updates) a Release PR that bumps the version in `package.json`, both `plugin/.claude-plugin/plugin.json` and `plugin/.codex-plugin/plugin.json`, and `.release-please-manifest.json`, and appends to `CHANGELOG.md`. +2. The `Release` workflow opens (or updates) a Release PR that bumps the version in `package.json`, both `plugin/.claude-plugin/plugin.json` and `plugin/.codex-plugin/plugin.json`, the `deploygate` entry in `.claude-plugin/marketplace.json`, and `.release-please-manifest.json`, and appends to `CHANGELOG.md`. 3. Merge the Release PR. 4. The `Release` workflow runs again, creates the git tag `deploygate--vX.Y.Z`, and publishes a GitHub Release. diff --git a/src/__tests__/plugin.test.ts b/src/__tests__/plugin.test.ts index 7333f10..2d3df12 100644 --- a/src/__tests__/plugin.test.ts +++ b/src/__tests__/plugin.test.ts @@ -189,16 +189,20 @@ describe("plugin/skills/ (slash commands)", () => { }); describe("version sync across release manifests", () => { - it("package.json, both plugin.json files, and the release-please manifest share the same version", () => { + it("package.json, both plugin.json files, the marketplace entry, and the release-please manifest share the same version", () => { const pkg = loadJson("package.json"); const codexPlugin = loadJson("plugin/.codex-plugin/plugin.json"); const claudePlugin = loadJson("plugin/.claude-plugin/plugin.json"); + const marketplace = loadJson(".claude-plugin/marketplace.json"); const manifest = loadJson(".release-please-manifest.json"); const version = pkg.version as string; expect(version).toMatch(/^\d+\.\d+\.\d+$/); expect(codexPlugin.version).toBe(version); expect(claudePlugin.version).toBe(version); + const plugins = marketplace.plugins as Array<{ name: string; version: string }>; + const deploygateEntry = plugins.find((p) => p.name === "deploygate"); + expect(deploygateEntry?.version).toBe(version); expect(manifest["."]).toBe(version); }); });