From 047e99f435c5d1a76ffd14f597d36228c014bf76 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 18 Aug 2025 09:23:18 +0200 Subject: [PATCH 1/8] chore: add version plan check --- .github/workflows/version-plan.yml | 177 +++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 .github/workflows/version-plan.yml diff --git a/.github/workflows/version-plan.yml b/.github/workflows/version-plan.yml new file mode 100644 index 00000000..2c62333d --- /dev/null +++ b/.github/workflows/version-plan.yml @@ -0,0 +1,177 @@ +name: Version Plan Check + +on: + pull_request: + pull_request_target: + types: [opened, synchronize] + +permissions: + contents: read + issues: write + +jobs: + check-version-plan: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4 + with: + persist-credentials: false + fetch-depth: 1 + + - name: Setup pnpm + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + + - name: Setup Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: 18 + cache: 'pnpm' + cache-dependency-path: pnpm-lock.yaml + + - name: Install dependencies (no lifecycle scripts) + run: pnpm install --frozen-lockfile --ignore-scripts + + - name: Run version plan check + id: plancheck + run: | + set -euo pipefail + if pnpm exec nx release plan:check; then + echo "result=success" >> $GITHUB_OUTPUT + else + echo "result=failure" >> $GITHUB_OUTPUT + fi + + - name: Detect affected projects + if: steps.plancheck.outputs.result == 'failure' + id: affected + run: | + set -euo pipefail + projects=$(pnpm exec nx print-affected --type=lib --select=projects) + echo "projects=$projects" >> $GITHUB_OUTPUT + + - name: Comment on PR if missing version plan + if: steps.plancheck.outputs.result == 'failure' && github.event.pull_request.head.repo.fork == false + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 + with: + projects: ${{ steps.affected.outputs.projects }} + script: | + const projects = core.getInput('projects') || ''; + const projectList = projects + ? projects.split(',').map(p => `- ${p}`).join('\n') + : '_(no specific projects detected)_'; + + const body = [ + `👋 Hey @${context.actor}, thanks for your contribution!`, + '', + 'It looks like this PR changes code but doesn\'t include a **version plan**.', + 'Version plans are required so we can properly bump package versions and generate changelogs.', + '', + '---', + '', + '### 🔍 Affected projects', + projectList, + '', + '---', + '', + '### 👉 What to do', + '1. Run the following command locally to create a version plan:', + ' ```bash', + ' npx nx release plan', + ' ```', + '', + ` _(You can also pass specific projects: \`npx nx release plan --projects=${projects}\`)`, + '', + '2. When prompted, choose the appropriate **version bump** (patch / minor / major / prerelease).', + '3. Write a **single-paragraph description** of the change.', + ' - This text will be shown in the changelog.', + ' - Keep it clear and concise, describing what changed and why.', + '4. Commit the generated file(s) under `.nx/version-plans/` and push to this branch.', + ' - ✅ It\'s okay to create **multiple version plans** if your PR includes unrelated changes.', + '', + '---', + '', + '⚡ Once you do that, this check will pass automatically. Thanks for keeping our releases tidy!' + ].join('\n'); + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body + }); + + - name: Fail job if missing version plan + if: steps.plancheck.outputs.result == 'failure' + run: exit 1 + + comment-on-fork: + if: github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork == true + permissions: + contents: read + issues: write + actions: read + runs-on: ubuntu-latest + steps: + - name: Comment when PR check failed (fork-safe) + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 + with: + script: | + const pr = context.payload.pull_request; + const headSha = pr.head.sha; + + // Poll for the PR workflow run to complete (max ~5 minutes) + async function findCompletedRun() { + for (let i = 0; i < 20; i++) { // 20 * 15s = 300s + const runsResp = await github.rest.actions.listWorkflowRunsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + event: 'pull_request', + per_page: 50 + }); + const targetRun = runsResp.data.workflow_runs.find(run => + run.name === 'Version Plan Check' && run.head_sha === headSha + ); + if (targetRun && targetRun.status === 'completed') { + return targetRun; + } + await new Promise(r => setTimeout(r, 15000)); + } + return null; + } + + const completedRun = await findCompletedRun(); + if (!completedRun || completedRun.conclusion !== 'failure') { + return; + } + + const body = [ + `👋 Hey @${context.actor}, thanks for your contribution!`, + '', + 'It looks like this PR changes code but doesn\'t include a **version plan**.', + 'Version plans are required so we can properly bump package versions and generate changelogs.', + '', + '---', + '', + '### 👉 What to do', + '1. Run the following command locally to create a version plan:', + ' ```bash', + ' pnpm nx release plan', + ' ```', + '', + '2. Choose the appropriate version bump (patch / minor / major / prerelease).', + '3. Write a single-paragraph description of the change.', + '4. Commit the generated file(s) under `.nx/version-plans/` and push to this branch.', + '', + '---', + '', + '⚡ Once you do that, this check will pass automatically. Thanks for keeping our releases tidy!' + ].join('\n'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + body + }); From 2d65aead9a4ca612311eafcb3b3be509568e645c Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 18 Aug 2025 09:28:12 +0200 Subject: [PATCH 2/8] chore: add missing nx-set-shas step --- .github/workflows/version-plan.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/version-plan.yml b/.github/workflows/version-plan.yml index 2c62333d..9d568d55 100644 --- a/.github/workflows/version-plan.yml +++ b/.github/workflows/version-plan.yml @@ -18,7 +18,10 @@ jobs: uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4 with: persist-credentials: false - fetch-depth: 1 + fetch-depth: 0 + + - name: Set base and head SHAs for Nx + uses: nrwl/nx-set-shas@826660b82addbef3abff5fa871492ebad618c9e1 # v4 - name: Setup pnpm uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 From 3a6c4fe40cb1b142cb950b6403cd491ed38a123f Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 18 Aug 2025 09:29:27 +0200 Subject: [PATCH 3/8] chore: test workflow --- packages/metro/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/metro/src/index.ts b/packages/metro/src/index.ts index f61e37af..e81e3b29 100644 --- a/packages/metro/src/index.ts +++ b/packages/metro/src/index.ts @@ -3,6 +3,8 @@ import { initializeRozenite, type RozeniteConfig } from '@rozenite/middleware'; import path from 'node:path'; import { isBundling } from './is-bundling.js'; +// Fake change + export type RozeniteMetroConfig = Omit< RozeniteConfig, 'projectRoot' From 074736875f7fc924afca3c9a71c5099534953634 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 18 Aug 2025 09:35:26 +0200 Subject: [PATCH 4/8] chore: fix affected --- .github/workflows/version-plan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/version-plan.yml b/.github/workflows/version-plan.yml index 9d568d55..e044504d 100644 --- a/.github/workflows/version-plan.yml +++ b/.github/workflows/version-plan.yml @@ -51,7 +51,7 @@ jobs: id: affected run: | set -euo pipefail - projects=$(pnpm exec nx print-affected --type=lib --select=projects) + projects=$(pnpm exec nx show projects --affected --projects "packages/*") echo "projects=$projects" >> $GITHUB_OUTPUT - name: Comment on PR if missing version plan From 1f235e1c46ce125ec19a2eba41417f7becff8f74 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 18 Aug 2025 09:37:32 +0200 Subject: [PATCH 5/8] chore: fix scope --- .github/workflows/version-plan.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/version-plan.yml b/.github/workflows/version-plan.yml index e044504d..0dcf5742 100644 --- a/.github/workflows/version-plan.yml +++ b/.github/workflows/version-plan.yml @@ -7,7 +7,7 @@ on: permissions: contents: read - issues: write + pull-requests: write jobs: check-version-plan: @@ -57,10 +57,11 @@ jobs: - name: Comment on PR if missing version plan if: steps.plancheck.outputs.result == 'failure' && github.event.pull_request.head.repo.fork == false uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 + env: + AFFECTED_PROJECTS: ${{ steps.affected.outputs.projects }} with: - projects: ${{ steps.affected.outputs.projects }} script: | - const projects = core.getInput('projects') || ''; + const projects = process.env.AFFECTED_PROJECTS || ''; const projectList = projects ? projects.split(',').map(p => `- ${p}`).join('\n') : '_(no specific projects detected)_'; From 80361083ae333dedc5debfdccd7afa2b02f85ba7 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 18 Aug 2025 09:41:17 +0200 Subject: [PATCH 6/8] chore: do not spam --- .github/workflows/version-plan.yml | 38 ++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/.github/workflows/version-plan.yml b/.github/workflows/version-plan.yml index 0dcf5742..711e5d79 100644 --- a/.github/workflows/version-plan.yml +++ b/.github/workflows/version-plan.yml @@ -66,6 +66,23 @@ jobs: ? projects.split(',').map(p => `- ${p}`).join('\n') : '_(no specific projects detected)_'; + // Check if we already commented about version plan + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const botComment = comments.data.find(comment => + comment.user.type === 'Bot' && + comment.body.includes('version plan') + ); + + if (botComment) { + console.log('Version plan comment already exists, skipping...'); + return; + } + const body = [ `👋 Hey @${context.actor}, thanks for your contribution!`, '', @@ -82,10 +99,10 @@ jobs: '### 👉 What to do', '1. Run the following command locally to create a version plan:', ' ```bash', - ' npx nx release plan', + ' pnpm nx release plan', ' ```', '', - ` _(You can also pass specific projects: \`npx nx release plan --projects=${projects}\`)`, + ` _(You can also pass specific projects: \`pnpm nx release plan --projects=${projects}\`)`, '', '2. When prompted, choose the appropriate **version bump** (patch / minor / major / prerelease).', '3. Write a **single-paragraph description** of the change.', @@ -150,6 +167,23 @@ jobs: return; } + // Check if we already commented about version plan + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + }); + + const botComment = comments.data.find(comment => + comment.user.type === 'Bot' && + comment.body.includes('version plan') + ); + + if (botComment) { + console.log('Version plan comment already exists, skipping...'); + return; + } + const body = [ `👋 Hey @${context.actor}, thanks for your contribution!`, '', From 1ab53d0097de0c921851c3dac1068d1ed780c411 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 18 Aug 2025 09:42:06 +0200 Subject: [PATCH 7/8] chore: fix broken comment line --- .github/workflows/version-plan.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/version-plan.yml b/.github/workflows/version-plan.yml index 711e5d79..6d673958 100644 --- a/.github/workflows/version-plan.yml +++ b/.github/workflows/version-plan.yml @@ -102,8 +102,6 @@ jobs: ' pnpm nx release plan', ' ```', '', - ` _(You can also pass specific projects: \`pnpm nx release plan --projects=${projects}\`)`, - '', '2. When prompted, choose the appropriate **version bump** (patch / minor / major / prerelease).', '3. Write a **single-paragraph description** of the change.', ' - This text will be shown in the changelog.', From 8fe099875b4434b2097df18068d0e20cdefb4ae1 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 18 Aug 2025 09:42:58 +0200 Subject: [PATCH 8/8] chore: revert change --- packages/metro/src/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/metro/src/index.ts b/packages/metro/src/index.ts index e81e3b29..f61e37af 100644 --- a/packages/metro/src/index.ts +++ b/packages/metro/src/index.ts @@ -3,8 +3,6 @@ import { initializeRozenite, type RozeniteConfig } from '@rozenite/middleware'; import path from 'node:path'; import { isBundling } from './is-bundling.js'; -// Fake change - export type RozeniteMetroConfig = Omit< RozeniteConfig, 'projectRoot'