From f0fab39f6bd0a63b10979f901502dc77321321de Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Sun, 26 Jul 2026 17:56:25 -0500 Subject: [PATCH 1/3] chore: add publish workflow and script for pkg.pr.new integration --- .github/scripts/publish-to-pkg-pr-new.mjs | 127 ++++++++++++++++++++ .github/workflows/publish-to-pkg-pr-new.yml | 64 ++++++++++ package-lock.json | 11 ++ package.json | 1 + 4 files changed, 203 insertions(+) create mode 100644 .github/scripts/publish-to-pkg-pr-new.mjs create mode 100644 .github/workflows/publish-to-pkg-pr-new.yml diff --git a/.github/scripts/publish-to-pkg-pr-new.mjs b/.github/scripts/publish-to-pkg-pr-new.mjs new file mode 100644 index 00000000000..be9bba47873 --- /dev/null +++ b/.github/scripts/publish-to-pkg-pr-new.mjs @@ -0,0 +1,127 @@ +/* eslint-disable no-console */ + +import fs from "fs"; + +/** + * @param {{ github: any, context: any }} params params + */ +export async function run({ github, context }) { + const output = JSON.parse(fs.readFileSync("output.json", "utf8")); + + const sha = + context.eventName === "pull_request" ? context.payload.pull_request.head.sha : context.sha; + + const commitUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${sha}`; + + const packages = output.packages.map((p) => `${p.name}@${p.url}`).join(" "); + + const botCommentIdentifier = ""; + const body = `${botCommentIdentifier} +This PR is packaged and the instant preview is available (${commitUrl}). + +Install it locally: + +- npm + +\`\`\`shell +npm i -D ${packages} +\`\`\` + +- yarn + +\`\`\`shell +yarn add -D ${packages} +\`\`\` + +- pnpm + +\`\`\`shell +pnpm add -D ${packages} +\`\`\` +`; + + /** + * @param {number=} issueNumber PR number + * @returns {Promise} the existing bot comment, if any + */ + async function findBotComment(issueNumber) { + if (!issueNumber) return null; + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + }); + return comments.data.find( + (comment) => + // Prevent unintentional overwriting + comment.user && + comment.user.login === "github-actions[bot]" && + comment.body.includes(botCommentIdentifier), + ); + } + + /** + * @param {number=} issueNumber issue number + * @returns {Promise} + */ + async function createOrUpdateComment(issueNumber) { + if (!issueNumber) { + console.log("No issue number provided. Cannot post or update comment."); + return; + } + + const existingComment = await findBotComment(issueNumber); + + if (existingComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existingComment.id, + body, + }); + } else { + await github.rest.issues.createComment({ + issue_number: issueNumber, + owner: context.repo.owner, + repo: context.repo.repo, + body, + }); + } + } + + /** + * @returns {void} + */ + function logPublishInfo() { + console.log(`\n${"=".repeat(50)}`); + console.log("Publish Information"); + console.log("=".repeat(50)); + console.log("\nPublished Packages:"); + console.log(output.packages); + console.log("\nTemplates:"); + console.log(output.templates); + console.log(`\nCommit URL: ${commitUrl}`); + console.log(`\n${"=".repeat(50)}`); + } + + if (context.eventName === "pull_request") { + if (context.issue.number) { + await createOrUpdateComment(context.issue.number); + } + } else if (context.eventName === "push") { + const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({ + owner: context.repo.owner, + repo: context.repo.repo, + commit_sha: sha, + }); + + if (prs.length > 0) { + await createOrUpdateComment(prs[0].number); + } else { + console.log( + "No open pull request found for this push. Logging publish information to console:", + ); + logPublishInfo(); + } + } +} diff --git a/.github/workflows/publish-to-pkg-pr-new.yml b/.github/workflows/publish-to-pkg-pr-new.yml new file mode 100644 index 00000000000..0f4f967aa28 --- /dev/null +++ b/.github/workflows/publish-to-pkg-pr-new.yml @@ -0,0 +1,64 @@ +name: Publish to pkg.pr.new + +on: + pull_request: + branches: [main] + push: + branches: [main] + tags: ["!**"] + +permissions: + issues: write + pull-requests: write + +jobs: + publish: + if: | + github.repository == 'webpack/webpack-cli' && + (github.event_name != 'pull_request' || + github.event.pull_request.head.repo.full_name == github.repository) + name: Publish to pkg.pr.new + runs-on: ubuntu-latest + outputs: + sha: ${{ steps.publish.outputs.sha }} + urls: ${{ steps.publish.outputs.urls }} + steps: + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # Changeset needs access to the main branch to find pending changesets + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: lts/* + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Compute affected packages + id: affected + run: | + npx changeset status --output changes.json || true + npm query .workspace > workspaces.json + packages=$(jq -r --slurpfile ws workspaces.json '[.releases[] | select(.type != "none") | .name] as $names | $ws[0][] | select(.name | IN($names[])) | "./" + .location' changes.json 2>/dev/null | tr '\n' ' ' || true) + echo "packages=$packages" >> "$GITHUB_OUTPUT" + echo "Affected packages: ${packages:-none}" + + - name: Publish + if: steps.affected.outputs.packages != '' + run: npx pkg-pr-new publish --compact --json output.json --comment=off ${{ steps.affected.outputs.packages }} + + - name: Add metadata to output + if: steps.affected.outputs.packages != '' + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { run } = await import('${{ github.workspace }}/.github/scripts/publish-to-pkg-pr-new.mjs'); + await run({ github, context }); diff --git a/package-lock.json b/package-lock.json index efe3c891722..c8d27d8175b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,7 @@ "json5": "^2.2.3", "lint-staged": "^17.0.8", "mini-css-extract-plugin": "^2.10.2", + "pkg-pr-new": "^0.0.79", "prettier": "^3.8.4", "readable-stream": "^4.7.0", "sass": "^1.101.0", @@ -20017,6 +20018,16 @@ "node": ">= 6" } }, + "node_modules/pkg-pr-new": { + "version": "0.0.79", + "resolved": "https://registry.npmjs.org/pkg-pr-new/-/pkg-pr-new-0.0.79.tgz", + "integrity": "sha512-ip74NzaakGZha5s/X1T7j+Ez9/bRNDhzxQZTfnzAzoI7zO9JnMRdoiIfCLyy+ZzxxXg8WXRW2WcdvdORI0O30w==", + "dev": true, + "license": "MIT", + "bin": { + "pkg-pr-new": "bin/cli.js" + } + }, "node_modules/pkijs": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.3.3.tgz", diff --git a/package.json b/package.json index 4eeda8d9271..e58f7c1342e 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "json5": "^2.2.3", "lint-staged": "^17.0.8", "mini-css-extract-plugin": "^2.10.2", + "pkg-pr-new": "^0.0.79", "prettier": "^3.8.4", "readable-stream": "^4.7.0", "sass": "^1.101.0", From 60afea9df37bc4f80bf43e395280b0fe9e301031 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Sun, 26 Jul 2026 18:04:18 -0500 Subject: [PATCH 2/3] chore: update baseBranch in config.json to use origin/main --- .changeset/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/config.json b/.changeset/config.json index b9eb7d7c516..b496b1d453a 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -4,7 +4,7 @@ "fixed": [], "linked": [], "access": "public", - "baseBranch": "main", + "baseBranch": "origin/main", "updateInternalDependencies": "patch", "ignore": [] } From 19484a57f513f6e2347483e8ba53dc96baefdf80 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Sun, 26 Jul 2026 18:17:04 -0500 Subject: [PATCH 3/3] fixup! --- .github/scripts/publish-to-pkg-pr-new.mjs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/scripts/publish-to-pkg-pr-new.mjs b/.github/scripts/publish-to-pkg-pr-new.mjs index be9bba47873..9872c00b685 100644 --- a/.github/scripts/publish-to-pkg-pr-new.mjs +++ b/.github/scripts/publish-to-pkg-pr-new.mjs @@ -1,9 +1,9 @@ -/* eslint-disable no-console */ +/* eslint-disable camelcase */ -import fs from "fs"; +import fs from "node:fs"; /** - * @param {{ github: any, context: any }} params params + * @param {{ github: EXPECTED_ANY, context: EXPECTED_ANY }} params params */ export async function run({ github, context }) { const output = JSON.parse(fs.readFileSync("output.json", "utf8")); @@ -13,7 +13,7 @@ export async function run({ github, context }) { const commitUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${sha}`; - const packages = output.packages.map((p) => `${p.name}@${p.url}`).join(" "); + const packages = output.packages.map((pkg) => `${pkg.name}@${pkg.url}`).join(" "); const botCommentIdentifier = ""; const body = `${botCommentIdentifier} @@ -42,7 +42,7 @@ pnpm add -D ${packages} /** * @param {number=} issueNumber PR number - * @returns {Promise} the existing bot comment, if any + * @returns {Promise} the existing bot comment, if any */ async function findBotComment(issueNumber) { if (!issueNumber) return null;