From 8260c29bfbe5adff373acc31191327fae90826ae Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Tue, 10 Mar 2026 17:55:38 +0100 Subject: [PATCH] ci: split CI and publish into separate workflows CI runs quality gates on PRs only. Publish handles canary (on push to main) and release (via workflow_dispatch) with OIDC provenance and auto-changelog. --- .github/workflows/ci.yml | 54 ++-------- .github/workflows/publish.yml | 194 ++++++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+), 45 deletions(-) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fb94f4..fd9447e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,16 +3,15 @@ name: CI on: pull_request: branches: [main] - push: - branches: [main] - tags: ["v*"] + +concurrency: + group: ci-${{ github.head_ref }} + cancel-in-progress: true jobs: - ci: + quality: + name: Quality Gates runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18, 20, 22] steps: - uses: actions/checkout@v4 @@ -20,7 +19,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 22 cache: pnpm - run: pnpm install --frozen-lockfile @@ -34,40 +33,5 @@ jobs: - name: Build run: pnpm build - - name: Test with coverage - run: pnpm test -- --coverage - - - name: Upload coverage - if: matrix.node-version == 22 - uses: actions/upload-artifact@v4 - with: - name: coverage-report - path: coverage/ - - publish: - needs: ci - if: startsWith(github.ref, 'refs/tags/v') - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - steps: - - uses: actions/checkout@v4 - - - uses: pnpm/action-setup@v4 - - - uses: actions/setup-node@v4 - with: - node-version: 22 - cache: pnpm - registry-url: https://registry.npmjs.org - - - run: pnpm install --frozen-lockfile - - - name: Build - run: pnpm build - - - name: Publish to npm - run: npm publish --access public --provenance - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Test + run: pnpm test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..321f1f2 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,194 @@ +name: Publish + +on: + push: + branches: [main] + paths: + - "src/**" + - "pnpm-lock.yaml" + - ".github/workflows/publish.yml" + workflow_dispatch: + inputs: + bump: + description: "Version bump type" + required: true + type: choice + options: + - patch + - minor + - major + +concurrency: + group: publish-${{ github.event_name }} + cancel-in-progress: true + +permissions: + contents: write + id-token: write + +jobs: + quality: + name: Quality Gates + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - name: Lint + run: pnpm lint + + - name: Typecheck + run: pnpm typecheck + + - name: Build + run: pnpm build + + - name: Test + run: pnpm test + + canary: + name: Publish Canary + needs: quality + if: github.event_name == 'push' + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + registry-url: https://registry.npmjs.org + + - run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build + + - name: Upgrade npm for OIDC support + run: npm install -g npm@latest + + - name: Publish canary + run: | + sed -i '/_authToken/d' "$NPM_CONFIG_USERCONFIG" + unset NODE_AUTH_TOKEN + BASE_VERSION=$(node -p "require('./package.json').version") + SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-7) + CANARY_VERSION="${BASE_VERSION}-canary.${SHORT_SHA}" + npm version "$CANARY_VERSION" --no-git-tag-version + TARBALL=$(pnpm pack --pack-destination /tmp | tail -1) + npm publish "$TARBALL" --tag canary --provenance --access public + + release: + name: Publish Release + needs: quality + if: github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + registry-url: https://registry.npmjs.org + + - run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build + + - name: Bump version + id: version + run: | + npm version ${{ inputs.bump }} --no-git-tag-version + VERSION=$(node -p "require('./package.json').version") + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - name: Generate changelog + id: changelog + run: | + LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") + if [ -z "$LAST_TAG" ]; then + RANGE="HEAD" + else + RANGE="${LAST_TAG}..HEAD" + fi + + { + echo "body</dev/null || true) + if [ -n "$FEATS" ]; then + echo "### Features" + echo "$FEATS" | sed 's/^/- /' + echo "" + fi + + FIXES=$(git log "$RANGE" --pretty=format:"%s" --grep="^fix" 2>/dev/null || true) + if [ -n "$FIXES" ]; then + echo "### Bug Fixes" + echo "$FIXES" | sed 's/^/- /' + echo "" + fi + + OTHERS=$(git log "$RANGE" --pretty=format:"%s" --invert-grep --grep="^feat" --grep="^fix" 2>/dev/null || true) + if [ -n "$OTHERS" ]; then + echo "### Other Changes" + echo "$OTHERS" | sed 's/^/- /' + echo "" + fi + + echo "CHANGELOG_EOF" + } >> "$GITHUB_OUTPUT" + + - name: Commit and tag + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add package.json + git commit -m "chore(release): v${{ steps.version.outputs.version }}" + git tag -a "v${{ steps.version.outputs.version }}" -m "v${{ steps.version.outputs.version }}" + git push origin main --follow-tags + + - name: Upgrade npm for OIDC support + run: npm install -g npm@latest + + - name: Publish to npm + run: | + sed -i '/_authToken/d' "$NPM_CONFIG_USERCONFIG" + unset NODE_AUTH_TOKEN + TARBALL=$(pnpm pack --pack-destination /tmp | tail -1) + npm publish "$TARBALL" --tag latest --provenance --access public + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cat <<'NOTES_EOF' > /tmp/release-notes.md + ${{ steps.changelog.outputs.body }} + NOTES_EOF + gh release create "v${{ steps.version.outputs.version }}" \ + --title "v${{ steps.version.outputs.version }}" \ + --notes-file /tmp/release-notes.md