diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 34104e2a..94ef0af7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,22 +1,57 @@ 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: - workflow_run: - workflows: ["Build and Test"] + push: branches: [master] - types: - - completed permissions: - id-token: write # Required for OIDC - contents: write # To create releases + contents: write + pull-requests: write jobs: - release: + release-please: runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} + outputs: + release_created: ${{ steps.release.outputs.release_created }} + tag_name: ${{ steps.release.outputs.tag_name }} steps: - - name: "Generate token" + # 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: @@ -26,8 +61,8 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 with: + ref: ${{ needs.release-please.outputs.tag_name }} persist-credentials: false - fetch-depth: 0 token: ${{ steps.generate_token.outputs.token }} - name: Set up Node.js @@ -57,7 +92,5 @@ jobs: npmRegistryServer: "https://registry.npmjs.org" EOF - - name: Semantic Release - env: - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} - run: npx semantic-release + - name: Publish packages + run: yarn workspaces foreach -A --no-private npm publish --access public --tag latest 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" } + ] + } + } +}