From 9421f20b69783264b69c78cb038d2de1d23b4970 Mon Sep 17 00:00:00 2001 From: Alex Verkhovsky Date: Mon, 9 Mar 2026 14:23:02 -0600 Subject: [PATCH] ci: add continuous delivery workflows for npm publishing (#1872) Add publish-next (auto-prerelease on push to main) and publish-latest (manual stable release with Discord notification). Update CONTRIBUTING.md to describe the trunk-based CD model. --- .github/workflows/publish-latest.yaml | 82 +++++++++++++++++++++++++++ .github/workflows/publish-next.yaml | 65 +++++++++++++++++++++ CONTRIBUTING.md | 2 +- 3 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish-latest.yaml create mode 100644 .github/workflows/publish-next.yaml diff --git a/.github/workflows/publish-latest.yaml b/.github/workflows/publish-latest.yaml new file mode 100644 index 000000000..a70dc5738 --- /dev/null +++ b/.github/workflows/publish-latest.yaml @@ -0,0 +1,82 @@ +name: Publish Latest + +on: + workflow_dispatch: + inputs: + bump: + description: "Version bump type" + required: true + default: "patch" + type: choice + options: + - patch + - minor + - major + +concurrency: + group: publish-latest + +permissions: + id-token: write + contents: write + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version-file: ".nvmrc" + cache: "npm" + registry-url: "https://registry.npmjs.org" + + - name: Configure git user + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test + + - name: Bump version + run: 'npm version ${{ inputs.bump }} -m "chore(release): v%s [skip ci]"' + + - name: Publish to npm + run: npm publish --tag latest --provenance + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Push version commit and tag + run: git push origin main --follow-tags + + - name: Create GitHub Release + run: | + TAG="v$(node -p 'require("./package.json").version')" + gh release create "$TAG" --generate-notes + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Notify Discord + continue-on-error: true + run: | + set -o pipefail + source .github/scripts/discord-helpers.sh + [ -z "$WEBHOOK" ] && exit 0 + + VERSION=$(node -p 'require("./package.json").version') + RELEASE_URL="${{ github.server_url }}/${{ github.repository }}/releases/tag/v${VERSION}" + MSG=$(printf '📦 **[bmad-method v%s released](<%s>)**' "$VERSION" "$RELEASE_URL" | esc) + + jq -n --arg content "$MSG" '{content: $content}' | curl -sf --retry 2 -X POST "$WEBHOOK" -H "Content-Type: application/json" -d @- + env: + WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} diff --git a/.github/workflows/publish-next.yaml b/.github/workflows/publish-next.yaml new file mode 100644 index 000000000..7bf0a4b18 --- /dev/null +++ b/.github/workflows/publish-next.yaml @@ -0,0 +1,65 @@ +name: Publish Next + +on: + push: + branches: [main] + paths: + - "src/**" + - "tools/cli/**" + - "package.json" + +concurrency: + group: publish-next + cancel-in-progress: true + +permissions: + id-token: write + contents: read + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version-file: ".nvmrc" + cache: "npm" + registry-url: "https://registry.npmjs.org" + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test + + - name: Derive next prerelease version + run: | + NEXT_VER=$(npm view bmad-method@next version 2>/dev/null || echo "") + LATEST_VER=$(npm view bmad-method@latest version 2>/dev/null || echo "") + + # Determine the best base version for the next prerelease + BASE=$(node -e " + const semver = require('semver'); + const next = process.argv[1] || null; + const latest = process.argv[2] || null; + if (!next && !latest) process.exit(0); + if (!next) { console.log(latest); process.exit(0); } + if (!latest) { console.log(next); process.exit(0); } + // If latest is newer than next's base, use latest (next prerelease will be based on it) + const nextBase = next.replace(/-next\.\d+$/, ''); + console.log(semver.gt(latest, nextBase) ? latest : next); + " "$NEXT_VER" "$LATEST_VER") + + if [ -n "$BASE" ]; then + npm version "$BASE" --no-git-tag-version --allow-same-version + fi + npm version prerelease --preid=next --no-git-tag-version + + - name: Publish to npm + run: npm publish --tag next --provenance + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d9c12655f..459195916 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,7 +73,7 @@ After searching, use the [feature request template](https://github.com/bmad-code ### Target Branch -Submit PRs to the `main` branch. We use [trunk-based development](https://trunkbaseddevelopment.com/branch-for-release/): `main` is the trunk where all work lands, and stable release branches receive only cherry-picked fixes. +Submit PRs to the `main` branch. We use trunk-based development. Every push to `main` auto-publishes to `npm` under the `next` tag. Stable releases are cut ~weekly to the `latest` tag. ### PR Size