Release #97
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to release (e.g., 2.6.0) - leave empty to use existing tag' | |
| required: false | |
| type: string | |
| dry_run: | |
| description: 'Dry run (skip actual publish)' | |
| required: false | |
| type: boolean | |
| default: false | |
| concurrency: | |
| group: release-${{ github.ref_name }} | |
| cancel-in-progress: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| validate: | |
| name: Validate Release | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| tag: ${{ steps.version.outputs.tag }} | |
| npm_tag: ${{ steps.version.outputs.npm_tag }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Determine version | |
| id: version | |
| run: | | |
| if [ "${{ github.event_name }}" = "push" ]; then | |
| # Tag push - extract version from tag | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| VERSION="${TAG#v}" | |
| elif [ -n "${{ inputs.version }}" ]; then | |
| # Manual dispatch with version input | |
| VERSION="${{ inputs.version }}" | |
| TAG="v${VERSION}" | |
| else | |
| # Manual dispatch without version - use package.json | |
| VERSION=$(node -p "require('./package.json').version") | |
| TAG="v${VERSION}" | |
| fi | |
| if [[ "$VERSION" == *"-"* ]]; then | |
| PRE_ID="${VERSION#*-}" | |
| PRE_ID="${PRE_ID%%.*}" | |
| case "$PRE_ID" in | |
| beta) NPM_TAG="beta";; | |
| rc) NPM_TAG="rc";; | |
| *) NPM_TAG="next";; | |
| esac | |
| else | |
| NPM_TAG="latest" | |
| fi | |
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
| echo "tag=${TAG}" >> $GITHUB_OUTPUT | |
| echo "npm_tag=${NPM_TAG}" >> $GITHUB_OUTPUT | |
| echo "[PKG] Release version: ${VERSION} (tag: ${TAG})" | |
| echo "[PKG] npm tag: ${NPM_TAG}" | |
| - name: Validate version format | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then | |
| echo "[ERROR] Invalid version format: $VERSION" | |
| echo "Expected: X.Y.Z or X.Y.Z-prerelease" | |
| exit 1 | |
| fi | |
| echo "[OK] Version format valid: $VERSION" | |
| - name: Enforce release source ref | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${GITHUB_REF}" != "refs/heads/main" ]; then | |
| echo "[ERROR] workflow_dispatch releases must run from refs/heads/main (got ${GITHUB_REF})" | |
| exit 1 | |
| fi | |
| if [ "${{ github.event_name }}" = "push" ]; then | |
| git fetch origin main | |
| if ! git merge-base --is-ancestor "${GITHUB_SHA}" "origin/main"; then | |
| echo "[ERROR] Release tag commit is not reachable from origin/main" | |
| exit 1 | |
| fi | |
| fi | |
| echo "[OK] Release source ref is valid" | |
| - name: Verify version consistency | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| echo "Checking version consistency across all files..." | |
| # Check package.json | |
| PKG_VERSION=$(node -p "require('./package.json').version") | |
| if [ "$PKG_VERSION" != "$VERSION" ]; then | |
| echo "[ERROR] package.json version ($PKG_VERSION) doesn't match release version ($VERSION)" | |
| exit 1 | |
| fi | |
| # Check root plugin.json (plugin repos have independent versions) | |
| PLUGIN_VERSION=$(node -p "require('./.claude-plugin/plugin.json').version") | |
| if [ "$PLUGIN_VERSION" != "$VERSION" ]; then | |
| echo "[ERROR] .claude-plugin/plugin.json version ($PLUGIN_VERSION) doesn't match release version ($VERSION)" | |
| exit 1 | |
| fi | |
| echo "[OK] All version numbers match: $VERSION" | |
| test: | |
| name: Run Tests | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - run: npm ci | |
| - name: Run tests | |
| run: npm test | |
| - name: Validate plugin structure | |
| run: node scripts/validate-plugins.js | |
| - name: Validate repo consistency | |
| run: npm run validate | |
| - name: Validate agent templates | |
| run: node scripts/expand-templates.js --check | |
| - name: Validate adapter freshness | |
| run: node scripts/gen-adapters.js --check | |
| publish-npm: | |
| name: Publish to npm | |
| runs-on: ubuntu-latest | |
| needs: [validate, test] | |
| environment: npm | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| registry-url: 'https://registry.npmjs.org' | |
| - run: npm ci | |
| - name: Publish to npm | |
| if: ${{ !inputs.dry_run }} | |
| run: npm publish --provenance --access public --tag "${{ needs.validate.outputs.npm_tag }}" | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| - name: Dry run publish | |
| if: ${{ inputs.dry_run }} | |
| run: | | |
| echo "[DRY-RUN] Skipping actual publish" | |
| npm publish --dry-run --tag "${{ needs.validate.outputs.npm_tag }}" | |
| create-release: | |
| name: Create GitHub Release | |
| runs-on: ubuntu-latest | |
| needs: [validate, publish-npm] | |
| if: ${{ !inputs.dry_run }} | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Create tag if needed | |
| if: ${{ github.event_name == 'workflow_dispatch' }} | |
| run: | | |
| TAG="${{ needs.validate.outputs.tag }}" | |
| if ! git rev-parse "$TAG" >/dev/null 2>&1; then | |
| echo "Creating tag: $TAG" | |
| git tag "$TAG" | |
| git push origin "$TAG" | |
| else | |
| echo "Tag $TAG already exists" | |
| fi | |
| - name: Extract changelog for version | |
| id: changelog | |
| run: | | |
| VERSION="${{ needs.validate.outputs.version }}" | |
| # Extract changelog section for this version | |
| CHANGELOG=$(awk "/^## \\[${VERSION}\\]/{flag=1; next} /^## \\[/{flag=0} flag" CHANGELOG.md) | |
| if [ -z "$CHANGELOG" ]; then | |
| CHANGELOG="See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md) for details." | |
| fi | |
| # Write to file to preserve formatting | |
| echo "$CHANGELOG" > release_notes.md | |
| echo "Generated release notes:" | |
| cat release_notes.md | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 | |
| with: | |
| tag_name: ${{ needs.validate.outputs.tag }} | |
| name: ${{ needs.validate.outputs.tag }} | |
| body_path: release_notes.md | |
| draft: false | |
| prerelease: ${{ contains(needs.validate.outputs.version, '-') }} | |
| generate_release_notes: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| notify: | |
| name: Release Summary | |
| runs-on: ubuntu-latest | |
| needs: [validate, publish-npm, create-release] | |
| if: always() | |
| steps: | |
| - name: Summary | |
| run: | | |
| echo "## Release Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version:** ${{ needs.validate.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Tag:** ${{ needs.validate.outputs.tag }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ needs.publish-npm.result }}" = "success" ]; then | |
| echo "[OK] **npm:** Published successfully" >> $GITHUB_STEP_SUMMARY | |
| echo " - https://www.npmjs.com/package/agentsys" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "[ERROR] **npm:** ${{ needs.publish-npm.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ needs.create-release.result }}" = "success" ]; then | |
| echo "[OK] **GitHub Release:** Created successfully" >> $GITHUB_STEP_SUMMARY | |
| echo " - https://github.com/${{ github.repository }}/releases/tag/${{ needs.validate.outputs.tag }}" >> $GITHUB_STEP_SUMMARY | |
| elif [ "${{ needs.create-release.result }}" = "skipped" ]; then | |
| echo "[SKIP] **GitHub Release:** Skipped (dry run)" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "[ERROR] **GitHub Release:** ${{ needs.create-release.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi |