From 3ce6bda3e117b1acf5f2764435bd6c97a438f640 Mon Sep 17 00:00:00 2001 From: merencia Date: Tue, 23 Jun 2026 15:14:39 -0300 Subject: [PATCH 1/2] ci: migrate release pipeline from semantic-release to release-please Switches releases from per-merge auto-publish (semantic-release) to an accumulating, PR-gated model (release-please): merges land on master, a single Release PR maintains the next version + CHANGELOG, and merging it cuts the tag and triggers publish. - add release-please-config.json + .release-please-manifest.json: lockstep monorepo (root '.' drives one version/tag/CHANGELOG; extra-files bump all 11 published packages to the same version) - add .github/workflows/release-please.yml: maintains the Release PR (via the bot App token so it triggers CI) and, on release, publishes with the same 'yarn workspaces foreach npm publish' step used before (handles workspace:* ) - add root package.json version (source of truth for release-please) - remove semantic-release: release.yml workflow + .releaserc.json - allow 'revert' and 'ci' PR-title prefixes (release-please understands them) Note: keeps the existing yarn-based publish/auth as-is. npm trusted publishing + provenance is a deliberate follow-up (needs per-package npm config and a yarn pack step for workspace:* ). --- .github/workflows/release-please.yml | 96 +++++++++++++++++++++++++++ .github/workflows/release.yml | 63 ------------------ .github/workflows/validate-branch.yml | 2 +- .release-please-manifest.json | 3 + .releaserc.json | 35 ---------- package.json | 1 + release-please-config.json | 38 +++++++++++ 7 files changed, 139 insertions(+), 99 deletions(-) create mode 100644 .github/workflows/release-please.yml delete mode 100644 .github/workflows/release.yml create mode 100644 .release-please-manifest.json delete mode 100644 .releaserc.json create mode 100644 release-please-config.json diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 00000000..94ef0af7 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,96 @@ +name: Release + +# Replaces semantic-release. Instead of publishing on every qualifying merge, +# release-please maintains a single "Release PR" that accumulates the Conventional +# Commits landing on master (bumping every package to the same version and updating +# CHANGELOG.md). Merging that PR creates the git tag (vX.Y.Z) and GitHub Release, +# which then triggers the publish job below. +on: + push: + branches: [master] + +permissions: + contents: write + pull-requests: write + +jobs: + release-please: + runs-on: ubuntu-latest + outputs: + release_created: ${{ steps.release.outputs.release_created }} + tag_name: ${{ steps.release.outputs.tag_name }} + steps: + # App token (not GITHUB_TOKEN) so the Release PR triggers the Build and Test + # checks; PRs opened by GITHUB_TOKEN do not start workflows. + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v1 + with: + app_id: ${{ secrets.BOT_APP_ID }} + private_key: ${{ secrets.BOT_PRIVATE_KEY }} + + - name: Run release-please + id: release + uses: googleapis/release-please-action@v4 + with: + # Reads release-please-config.json and .release-please-manifest.json from + # the repo root. The root package drives one version/tag/changelog and the + # config's extra-files bump every published package in lockstep. + token: ${{ steps.generate_token.outputs.token }} + + # Runs only when merging the Release PR just cut a release. Publishing reuses the + # exact steps from the previous semantic-release setup (yarn npm publish, which + # rewrites the workspace:* dependency ranges to concrete versions). At this point + # the package versions are already bumped by the merged Release PR, so there is no + # version step here. + publish: + needs: release-please + if: ${{ needs.release-please.outputs.release_created == 'true' }} + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v1 + with: + app_id: ${{ secrets.BOT_APP_ID }} + private_key: ${{ secrets.BOT_PRIVATE_KEY }} + + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ needs.release-please.outputs.tag_name }} + persist-credentials: false + token: ${{ steps.generate_token.outputs.token }} + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + registry-url: "https://registry.npmjs.org" + + - name: Enable Corepack + run: corepack enable + + - name: Install dependencies + run: yarn install --immutable + + - name: Build + run: yarn build + + - name: Configure Yarn authentication and settings + run: | + cat < .yarnrc.yml + nodeLinker: node-modules + + npmRegistryServer: "https://registry.npmjs.org" + + npmScopes: + sidequest: + npmRegistryServer: "https://registry.npmjs.org" + EOF + + - name: Publish packages + run: yarn workspaces foreach -A --no-private npm publish --access public --tag latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 34104e2a..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Release - -on: - workflow_run: - workflows: ["Build and Test"] - branches: [master] - types: - - completed - -permissions: - id-token: write # Required for OIDC - contents: write # To create releases - -jobs: - release: - runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} - steps: - - name: "Generate token" - id: generate_token - uses: tibdex/github-app-token@v1 - with: - app_id: ${{ secrets.BOT_APP_ID }} - private_key: ${{ secrets.BOT_PRIVATE_KEY }} - - - name: Checkout repository - uses: actions/checkout@v4 - with: - persist-credentials: false - fetch-depth: 0 - token: ${{ steps.generate_token.outputs.token }} - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: "22" - registry-url: "https://registry.npmjs.org" - - - name: Enable Corepack - run: corepack enable - - - name: Install dependencies - run: yarn install --immutable - - - name: Build - run: yarn build - - - name: Configure Yarn authentication and settings - run: | - cat < .yarnrc.yml - nodeLinker: node-modules - - npmRegistryServer: "https://registry.npmjs.org" - - npmScopes: - sidequest: - npmRegistryServer: "https://registry.npmjs.org" - EOF - - - name: Semantic Release - env: - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} - run: npx semantic-release diff --git a/.github/workflows/validate-branch.yml b/.github/workflows/validate-branch.yml index ea08b8ca..40d42069 100644 --- a/.github/workflows/validate-branch.yml +++ b/.github/workflows/validate-branch.yml @@ -15,7 +15,7 @@ jobs: run: | PR_TITLE=$(printf "%s" "${{ github.event.pull_request.title }}") echo "PR title: $PR_TITLE" - if [[ ! "$PR_TITLE" =~ ^(feat|fix|chore|docs|refactor|style|test|tests|perf|build)(\(.+\))?:\ .+ ]]; then + if [[ ! "$PR_TITLE" =~ ^(feat|fix|chore|docs|refactor|style|test|tests|perf|build|revert|ci)(\(.+\))?:\ .+ ]]; then echo "::error::Invalid PR title: $PR_TITLE" echo "::error::PR title must follow Conventional Commits, e.g., 'feat(api): add user login'" exit 1 diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..5677a32d --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "1.16.0" +} diff --git a/.releaserc.json b/.releaserc.json deleted file mode 100644 index 7aae5023..00000000 --- a/.releaserc.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "branches": [ - "master", - { - "name": "develop", - "prerelease": "next", - "channel": "next" - } - ], - "plugins": [ - "@semantic-release/commit-analyzer", - "@semantic-release/release-notes-generator", - "@semantic-release/changelog", - [ - "@semantic-release/exec", - { - "prepareCmd": "yarn workspaces foreach -A --no-private version ${nextRelease.version}" - } - ], - [ - "@semantic-release/exec", - { - "publishCmd": "yarn workspaces foreach -A --no-private npm publish --access public --tag $( [ \"${nextRelease.channel}\" = \"next\" ] && echo next || echo latest )" - } - ], - [ - "@semantic-release/git", - { - "assets": ["CHANGELOG.md", "package.json", "packages/**/package.json"], - "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" - } - ], - "@semantic-release/github" - ] -} diff --git a/package.json b/package.json index 2e4de9da..810efb0b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "sidequest-monorepo", "private": true, + "version": "1.16.0", "type": "module", "description": "Monorepo for Sidequest.js", "engines": { diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 00000000..54e37cbe --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "packages": { + ".": { + "release-type": "node", + "package-name": "sidequest", + "changelog-path": "CHANGELOG.md", + "include-component-in-tag": false, + "include-v-in-tag": true, + "changelog-sections": [ + { "type": "feat", "section": "Features" }, + { "type": "fix", "section": "Bug Fixes" }, + { "type": "perf", "section": "Performance Improvements" }, + { "type": "refactor", "section": "Code Refactoring" }, + { "type": "revert", "section": "Reverts" }, + { "type": "docs", "section": "Documentation", "hidden": true }, + { "type": "chore", "hidden": true }, + { "type": "ci", "hidden": true }, + { "type": "test", "hidden": true }, + { "type": "build", "hidden": true }, + { "type": "style", "hidden": true } + ], + "extra-files": [ + { "type": "json", "path": "packages/sidequest/package.json", "jsonpath": "$.version" }, + { "type": "json", "path": "packages/engine/package.json", "jsonpath": "$.version" }, + { "type": "json", "path": "packages/core/package.json", "jsonpath": "$.version" }, + { "type": "json", "path": "packages/dashboard/package.json", "jsonpath": "$.version" }, + { "type": "json", "path": "packages/cli/package.json", "jsonpath": "$.version" }, + { "type": "json", "path": "packages/backends/backend/package.json", "jsonpath": "$.version" }, + { "type": "json", "path": "packages/backends/backend-test/package.json", "jsonpath": "$.version" }, + { "type": "json", "path": "packages/backends/postgres/package.json", "jsonpath": "$.version" }, + { "type": "json", "path": "packages/backends/mysql/package.json", "jsonpath": "$.version" }, + { "type": "json", "path": "packages/backends/sqlite/package.json", "jsonpath": "$.version" }, + { "type": "json", "path": "packages/backends/mongo/package.json", "jsonpath": "$.version" } + ] + } + } +} From 3b77abb0646972bad98480b4234c6ae1db489a7e Mon Sep 17 00:00:00 2001 From: merencia Date: Tue, 23 Jun 2026 15:25:38 -0300 Subject: [PATCH 2/2] ci: keep the workflow file named release.yml for npm OIDC The npm trusted publisher (OIDC) is configured against the workflow file .github/workflows/release.yml. Keep the release-please + publish workflow under that filename so the OIDC exchange keeps matching; the publish job stays the entry workflow's job, so its OIDC subject is release.yml. --- .github/workflows/{release-please.yml => release.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{release-please.yml => release.yml} (100%) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release.yml similarity index 100% rename from .github/workflows/release-please.yml rename to .github/workflows/release.yml