Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 69 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,24 @@ name: Release
on:
push:
branches: [main]
# Retries npm publish for a release whose tag already exists. Keep this in
# release.yml: npm trusted publishing is bound to this workflow file.
workflow_dispatch:
inputs:
tag:
description: 'Existing release tag to publish, e.g. deploygate--v1.5.2'
required: true
type: string

jobs:
release-please:
if: ${{ github.event_name == 'push' }}
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- uses: actions/create-github-app-token@v3
id: app-token
Expand Down Expand Up @@ -55,24 +66,72 @@ jobs:
git push origin "HEAD:${BRANCH}"
fi

- if: ${{ steps.release.outputs.release_created == 'true' }}
uses: actions/checkout@v7
publish:
needs: release-please
if: ${{ !cancelled() && (github.event_name == 'workflow_dispatch' || (needs.release-please.result == 'success' && needs.release-please.outputs.release_created == 'true')) }}
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
env:
TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || needs.release-please.outputs.tag_name }}
steps:
- run: |
if ! printf '%s' "$TAG" | grep -Eq '^deploygate--v[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Invalid release tag (expected deploygate--vX.Y.Z)"
exit 1
fi

- uses: actions/checkout@v7
with:
ref: refs/tags/${{ env.TAG }}
fetch-depth: 0

- if: ${{ steps.release.outputs.release_created == 'true' }}
# Only publish commits that went through main, so a manual run cannot
# publish a tag pointing at unreviewed code.
- run: |
if ! git merge-base --is-ancestor HEAD origin/main; then
echo "::error::${TAG} is not reachable from main; refusing to publish"
exit 1
fi

- id: check
run: |
VERSION="${TAG#deploygate--v}"
PKG_VERSION=$(node -p "require('./package.json').version")
if [ "$PKG_VERSION" != "$VERSION" ]; then
echo "::error::package.json version ${PKG_VERSION} does not match tag ${TAG}"
exit 1
fi
# Only an explicit E404 means "not published yet". Any other registry
# error stops the run instead of attempting a publish.
if PUBLISHED=$(npm view "@deploygate/mcp@${VERSION}" version 2>"$RUNNER_TEMP/npm-view.err"); then
if [ "$PUBLISHED" = "$VERSION" ]; then
echo "::notice::@deploygate/mcp@${VERSION} is already on npm; skipping publish"
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
elif ! grep -q E404 "$RUNNER_TEMP/npm-view.err"; then
cat "$RUNNER_TEMP/npm-view.err"
echo "::error::Could not check npm for @deploygate/mcp@${VERSION}"
exit 1
fi
echo "skip=false" >> "$GITHUB_OUTPUT"

- if: ${{ steps.check.outputs.skip == 'false' }}
uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
registry-url: 'https://registry.npmjs.org'

- if: ${{ steps.release.outputs.release_created == 'true' }}
- if: ${{ steps.check.outputs.skip == 'false' }}
run: npm install -g npm@latest

- if: ${{ steps.release.outputs.release_created == 'true' }}
- if: ${{ steps.check.outputs.skip == 'false' }}
run: npm ci

- if: ${{ steps.release.outputs.release_created == 'true' }}
run: npm run bundle

- if: ${{ steps.release.outputs.release_created == 'true' }}
# No `npm run bundle` here: the plugin/scripts/bundle.js committed at the
# tag is published as-is, so npm and git ship the same file.
- if: ${{ steps.check.outputs.skip == 'false' }}
run: npm publish
Comment thread
satsukies marked this conversation as resolved.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ End users can pin to a tag with:

Without a pin, `claude plugin install` follows `main`. Users can fetch the latest published tag with `claude plugin update deploygate`.

### Retrying a failed npm publish

If the tag `deploygate--vX.Y.Z` and its GitHub Release exist but `npm publish` failed, do not delete the tag: that breaks release-please's baseline.

- If the failure was transient or outside the repository (an npm outage, a registry or trusted-publisher setting), fix it and go to Actions → Release → Run workflow, then enter the tag. The workflow checks out the tag and publishes the files committed there, including `plugin/scripts/bundle.js`. It refuses tags that are not reachable from `main`, and does nothing if that version is already on npm.
- If the failure was caused by the tagged files themselves (for example a broken `package-lock.json`), a retry fails again because the tag cannot change. Merge a `fix:` PR to `main` and ship it as the next release instead.

## Support & Project Status

This plugin is open-source software provided **as-is on a best-effort
Expand Down
Loading