diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 000000000..3e1dc82e5 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,121 @@ +name: Publish + +on: + push: + branches: [main] + paths: + - "src/**" + - "tools/cli/**" + - "package.json" + workflow_dispatch: + inputs: + bump: + description: "Version bump type" + required: true + default: "patch" + type: choice + options: + - patch + - minor + - major + +concurrency: + group: publish + cancel-in-progress: ${{ github.event_name == 'push' }} + +permissions: + id-token: write + contents: write + +jobs: + publish: + if: github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main' + 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 + if: github.event_name == 'workflow_dispatch' + 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: Derive next prerelease version + if: github.event_name == 'push' + 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); } + 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: Bump stable version + if: github.event_name == 'workflow_dispatch' + run: 'npm version ${{ inputs.bump }} -m "chore(release): v%s [skip ci]"' + + - name: Publish prerelease to npm + if: github.event_name == 'push' + run: npm publish --tag next --provenance + + - name: Publish stable release to npm + if: github.event_name == 'workflow_dispatch' + run: npm publish --tag latest --provenance + + - name: Push version commit and tag + if: github.event_name == 'workflow_dispatch' + run: git push origin main --follow-tags + + - name: Create GitHub Release + if: github.event_name == 'workflow_dispatch' + run: | + TAG="v$(node -p 'require("./package.json").version')" + gh release create "$TAG" --generate-notes + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Notify Discord + if: github.event_name == 'workflow_dispatch' + 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 }}