From 8b629e5e3e25b4d75c75ddf64a75192432645d1e Mon Sep 17 00:00:00 2001 From: Yoni Melki Date: Tue, 23 Jun 2026 21:59:43 +0300 Subject: [PATCH 1/4] [minor] Add tag/release mechanism and drift-prevention check (AX-1734) Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/release.yml | 81 ++++++++++++++++++++++++++ .github/workflows/validate-version.yml | 21 +++++++ VERSION | 1 + 3 files changed, 103 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/validate-version.yml create mode 100644 VERSION diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..de61de0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,81 @@ +name: Release + +on: + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Detect release tag in commit message + id: detect + run: | + MSG="${{ github.event.head_commit.message }}" + if echo "$MSG" | grep -qE '\[(major|minor|patch)\]'; then + TAG=$(echo "$MSG" | grep -oE '\[(major|minor|patch)\]' | head -1 | tr -d '[]') + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + echo "triggered=true" >> "$GITHUB_OUTPUT" + else + echo "triggered=false" >> "$GITHUB_OUTPUT" + fi + + - name: Compute next version + if: steps.detect.outputs.triggered == 'true' + id: version + run: | + VERSION=$(cat VERSION) + MAJOR=$(echo "$VERSION" | cut -d. -f1) + MINOR=$(echo "$VERSION" | cut -d. -f2) + PATCH=$(echo "$VERSION" | cut -d. -f3) + case "${{ steps.detect.outputs.tag }}" in + major) NEXT="$((MAJOR + 1)).0.0" ;; + minor) NEXT="${MAJOR}.$((MINOR + 1)).0" ;; + patch) NEXT="${MAJOR}.${MINOR}.$((PATCH + 1))" ;; + esac + echo "version=$NEXT" >> "$GITHUB_OUTPUT" + + - name: Update VERSION and JSON files + if: steps.detect.outputs.triggered == 'true' + run: | + VERSION="${{ steps.version.outputs.version }}" + echo "$VERSION" > VERSION + jq --arg v "$VERSION" '.version = $v' .claude-plugin/plugin.json > /tmp/plugin.json + mv /tmp/plugin.json .claude-plugin/plugin.json + + - name: Commit, tag, and push + if: steps.detect.outputs.triggered == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add VERSION .claude-plugin/plugin.json + git commit -m "Release v${{ steps.version.outputs.version }}" + git push origin main + git tag "v${{ steps.version.outputs.version }}" + git push origin "v${{ steps.version.outputs.version }}" + + - name: Package release artifact + if: steps.detect.outputs.triggered == 'true' + run: zip -r release.zip . --exclude ".git/*" --exclude ".github/*" + + - name: Create GitHub Release + if: steps.detect.outputs.triggered == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create "v${{ steps.version.outputs.version }}" \ + release.zip \ + --title "Release v${{ steps.version.outputs.version }}" \ + --generate-notes diff --git a/.github/workflows/validate-version.yml b/.github/workflows/validate-version.yml new file mode 100644 index 0000000..03ffaaf --- /dev/null +++ b/.github/workflows/validate-version.yml @@ -0,0 +1,21 @@ +name: Validate version + +on: + pull_request: + branches: [main] + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check version consistency + run: | + VERSION=$(cat VERSION) + PLUGIN_VERSION=$(jq -r '.version' .claude-plugin/plugin.json) + if [ "$VERSION" != "$PLUGIN_VERSION" ]; then + echo "::error::Version mismatch: VERSION=$VERSION but .claude-plugin/plugin.json.version=$PLUGIN_VERSION" + exit 1 + fi + echo "All versions consistent: $VERSION" diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..b003284 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.2.7 From 9510e2c85337f2767e6ee00193b5412af4498176 Mon Sep 17 00:00:00 2001 From: Yoni Melki <58732001+YoniMelki@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:34:03 +0300 Subject: [PATCH 2/4] docs: add Releasing section to CONTRIBUTING.md --- CONTRIBUTING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06018fd..72ffe21 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,6 +48,22 @@ This downloads the pinned upstream tarball and replaces the contents of `skills/ - [ ] If the skill tree changed: `pin` in `.github/scripts/sync-skills-vendor.json` matches the upstream tag the new tree was generated from. - [ ] Smoke-test: `claude --plugin-dir .` from the repo root. +## Releasing + +Releases are automated by `.github/workflows/release.yml`. To cut a release, push (or merge) a commit to `main` whose message contains `[major]`, `[minor]`, or `[patch]`: + +- `[patch]` — bug fixes; bumps `X.Y.Z` → `X.Y.Z+1` +- `[minor]` — new features; bumps `X.Y.Z` → `X.Y+1.0` +- `[major]` — breaking changes; bumps `X.Y.Z` → `X+1.0.0` + +The workflow: +1. Bumps `VERSION` and syncs the version in `.claude-plugin/plugin.json` +2. Commits and pushes the bump to `main` +3. Creates a `vX.Y.Z` git tag +4. Publishes a GitHub Release with a repo zip attached + +**Prerequisite:** `github-actions[bot]` must be allowed to push to `main`. In the repository's branch protection (or ruleset) settings, add `github-actions[bot]` to the bypass list. + ### Submitting to the Claude plugin directory Use [Submitting your plugin](https://claude.com/docs/plugins/submit). Submit the **public GitHub URL** of this repository — the **repository root** is the plugin root (manifest in `.claude-plugin/`, skills committed under `skills/`, vendored from [jfrog/jfrog-skills](https://github.com/jfrog/jfrog-skills)). From 64493d564cbc8ba609c9f2f6757ae6d67aba558e Mon Sep 17 00:00:00 2001 From: Yoni Melki <58732001+YoniMelki@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:32:38 +0300 Subject: [PATCH 3/4] fix: remove push-to-main from release workflow, read VERSION as-is --- .github/workflows/release.yml | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de61de0..468c804 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,6 @@ jobs: steps: - uses: actions/checkout@v4 with: - fetch-depth: 0 token: ${{ secrets.GITHUB_TOKEN }} - name: Detect release tag in commit message @@ -25,44 +24,19 @@ jobs: run: | MSG="${{ github.event.head_commit.message }}" if echo "$MSG" | grep -qE '\[(major|minor|patch)\]'; then - TAG=$(echo "$MSG" | grep -oE '\[(major|minor|patch)\]' | head -1 | tr -d '[]') - echo "tag=$TAG" >> "$GITHUB_OUTPUT" echo "triggered=true" >> "$GITHUB_OUTPUT" else echo "triggered=false" >> "$GITHUB_OUTPUT" fi - - name: Compute next version + - name: Read version if: steps.detect.outputs.triggered == 'true' id: version - run: | - VERSION=$(cat VERSION) - MAJOR=$(echo "$VERSION" | cut -d. -f1) - MINOR=$(echo "$VERSION" | cut -d. -f2) - PATCH=$(echo "$VERSION" | cut -d. -f3) - case "${{ steps.detect.outputs.tag }}" in - major) NEXT="$((MAJOR + 1)).0.0" ;; - minor) NEXT="${MAJOR}.$((MINOR + 1)).0" ;; - patch) NEXT="${MAJOR}.${MINOR}.$((PATCH + 1))" ;; - esac - echo "version=$NEXT" >> "$GITHUB_OUTPUT" - - - name: Update VERSION and JSON files - if: steps.detect.outputs.triggered == 'true' - run: | - VERSION="${{ steps.version.outputs.version }}" - echo "$VERSION" > VERSION - jq --arg v "$VERSION" '.version = $v' .claude-plugin/plugin.json > /tmp/plugin.json - mv /tmp/plugin.json .claude-plugin/plugin.json + run: echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT" - - name: Commit, tag, and push + - name: Create and push tag if: steps.detect.outputs.triggered == 'true' run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add VERSION .claude-plugin/plugin.json - git commit -m "Release v${{ steps.version.outputs.version }}" - git push origin main git tag "v${{ steps.version.outputs.version }}" git push origin "v${{ steps.version.outputs.version }}" From 20d637655ffcfbb53395a4bc18ecce734cd37c7b Mon Sep 17 00:00:00 2001 From: Yoni Melki <58732001+YoniMelki@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:33:22 +0300 Subject: [PATCH 4/4] docs: update Releasing section to reflect new developer-driven version bump flow --- CONTRIBUTING.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72ffe21..2d4b37f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,26 +43,18 @@ This downloads the pinned upstream tarball and replaces the contents of `skills/ - [ ] `node scripts/validate-claude-plugin.mjs` passes. - [ ] `claude plugin validate` passes (before directory submission or major releases). -- [ ] Version bumped in [`.claude-plugin/plugin.json`](.claude-plugin/plugin.json) when the plugin changes. - [ ] No secrets, credentials, or files under `**/local-cache/` committed. - [ ] If the skill tree changed: `pin` in `.github/scripts/sync-skills-vendor.json` matches the upstream tag the new tree was generated from. - [ ] Smoke-test: `claude --plugin-dir .` from the repo root. ## Releasing -Releases are automated by `.github/workflows/release.yml`. To cut a release, push (or merge) a commit to `main` whose message contains `[major]`, `[minor]`, or `[patch]`: +To cut a release: -- `[patch]` — bug fixes; bumps `X.Y.Z` → `X.Y.Z+1` -- `[minor]` — new features; bumps `X.Y.Z` → `X.Y+1.0` -- `[major]` — breaking changes; bumps `X.Y.Z` → `X+1.0.0` +1. In your PR, bump `VERSION` and sync `.claude-plugin/plugin.json` `.version` to match. The `validate-version` PR check enforces this. +2. Merge to `main` with `[major]`, `[minor]`, or `[patch]` anywhere in the commit message. -The workflow: -1. Bumps `VERSION` and syncs the version in `.claude-plugin/plugin.json` -2. Commits and pushes the bump to `main` -3. Creates a `vX.Y.Z` git tag -4. Publishes a GitHub Release with a repo zip attached - -**Prerequisite:** `github-actions[bot]` must be allowed to push to `main`. In the repository's branch protection (or ruleset) settings, add `github-actions[bot]` to the bypass list. +The release workflow reads `VERSION`, creates a `vX.Y.Z` git tag, and publishes a GitHub Release with a repo zip attached. No bot push to `main` — the version bump is part of the PR itself. ### Submitting to the Claude plugin directory