diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml new file mode 100644 index 00000000000000..51a06fdd92f345 --- /dev/null +++ b/.github/workflows/prepare-release.yml @@ -0,0 +1,85 @@ +name: Prepare Release + +on: + workflow_dispatch: + inputs: + package: + description: Package to release + required: true + default: vite + type: choice + options: + - vite + - create-vite + - plugin-legacy + release: + description: Release type + required: true + default: next + type: choice + options: + - next + - patch + - minor + - major + - prepatch + - preminor + - premajor + version: + description: Specify exact version instead of release type + required: false + type: string + +concurrency: + group: ${{ github.workflow }}-${{ inputs.package }}-${{ inputs.version || inputs.release }} + cancel-in-progress: false + +permissions: {} + +jobs: + prepare: + if: github.repository == 'vitejs/vite' + name: Prepare release PR + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + ref: main + fetch-depth: 0 + persist-credentials: false + + - name: Install pnpm + uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + + - name: Set node version to 24 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 + with: + node-version: 24 + package-manager-cache: false + + - name: Install deps + run: pnpm install + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" + + - name: Prepare release + id: prepare + env: + RELEASE: ${{ inputs.version || inputs.release }} + RELEASE_PACKAGE: ${{ inputs.package }} + run: | + node scripts/prepare-release.ts "$RELEASE_PACKAGE" "$RELEASE" >> "$GITHUB_OUTPUT" + + - name: Open release PR + uses: vitejs/release-scripts/action/release-pr@005dab4c647ff12519bfd076a595b2be33be8f6b # v1.9.2 + with: + token: ${{ github.token }} + package-name: ${{ inputs.package }} + package-path: packages/${{ inputs.package }} + pr-body: ${{ steps.prepare.outputs.pr_body }} + tag: ${{ steps.prepare.outputs.tag }} + version: ${{ steps.prepare.outputs.version }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d49504ada79361..94d70da248c715 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,26 +2,70 @@ name: Publish Package on: push: - tags: - - "v*" # Push events to matching v*, i.e. v1.0, v20.15.10 - - "plugin-*" # Push events to matching plugin-*, i.e. plugin-(vue|vue-jsx|react|legacy)@1.0.0 - - "create-vite*" # # Push events to matching create-vite*, i.e. create-vite@1.0.0 + branches: + - main + +permissions: {} jobs: - publish: - # prevents this action from running on forks + detect-release: if: github.repository == 'vitejs/vite' + name: Detect release commit + runs-on: ubuntu-slim + outputs: + package: ${{ steps.detect.outputs.package }} + release: ${{ steps.detect.outputs.release }} + tag: ${{ steps.detect.outputs.tag }} + version: ${{ steps.detect.outputs.version }} + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + + - name: Install pnpm + uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + + - name: Set node version to 24 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 + with: + node-version: 24 + package-manager-cache: false + + - name: Install deps + run: pnpm install + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" + + - name: Detect release + id: detect + run: node scripts/detect-release.ts "$(git log -1 --format=%s)" >> "$GITHUB_OUTPUT" + + publish-release: + if: needs.detect-release.outputs.release == 'true' + needs: detect-release + name: Publish ${{ needs.detect-release.outputs.tag }} runs-on: ubuntu-latest permissions: - contents: read + contents: write id-token: write environment: Release steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: + fetch-depth: 0 persist-credentials: false + - name: Check release tag + env: + TAG: ${{ needs.detect-release.outputs.tag }} + run: | + if git rev-parse --verify --quiet "refs/tags/$TAG"; then + echo "Tag $TAG already exists" + exit 1 + fi + - name: Install pnpm uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10 @@ -42,6 +86,29 @@ jobs: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" - name: Publish package - run: npm i -g npm@^11.5.2 && pnpm run ci-publish "$REF_NAME" env: - REF_NAME: ${{ github.ref_name }} + TAG: ${{ needs.detect-release.outputs.tag }} + # npm 11.5.2+ is required for trusted publishing. + # zizmor: ignore[adhoc-packages] + run: npm i -g npm@^11.5.2 && pnpm run ci-publish "$TAG" + + - name: Create GitHub release + env: + GH_TOKEN: ${{ github.token }} + NOTES_FILE: ${{ runner.temp }}/release-notes.md + PACKAGE: ${{ needs.detect-release.outputs.package }} + TAG: ${{ needs.detect-release.outputs.tag }} + VERSION: ${{ needs.detect-release.outputs.version }} + run: | + node scripts/extract-changelog.ts "packages/$PACKAGE/CHANGELOG.md" "$VERSION" > "$NOTES_FILE" + + prerelease=() + if [[ "${VERSION%%+*}" == *-* ]]; then + prerelease+=(--prerelease) + fi + + gh release create "$TAG" \ + --target "$GITHUB_SHA" \ + --title "$TAG" \ + --notes-file "$NOTES_FILE" \ + "${prerelease[@]}" diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml deleted file mode 100644 index 24274cd72b4393..00000000000000 --- a/.github/workflows/release-tag.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Add GitHub Release Tag - -on: - push: - tags: - - "v*" # Push events to matching v*, i.e. v1.0, v20.15.10 - - "plugin-*" # Push events to matching plugin-*, i.e. plugin-(vue|vue-jsx|react|legacy)@1.0.0 - - "create-vite*" # # Push events to matching create-vite*, i.e. create-vite@1.0.0 - -# $GITHUB_REF_NAME - https://docs.github.com/en/actions/reference/workflows-and-actions/variables#default-environment-variables - -jobs: - release: - if: github.repository == 'vitejs/vite' - runs-on: ubuntu-slim - permissions: - contents: write # for yyx990803/release-tag to create a release tag - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - with: - persist-credentials: false - - - name: Get pkgName for tag - id: tag - run: | - # skip if alpha - if [[ $GITHUB_REF_NAME =~ alpha ]]; then - exit 0 - fi - - # matching v2.0.0 / v2.0.0-beta.8 etc - if [[ $GITHUB_REF_NAME =~ ^v.+ ]]; then - pkgName="vite" - else - # `%@*` truncates @ and version number from the right side. - # https://stackoverflow.com/questions/9532654/expression-after-last-specific-character - pkgName=${GITHUB_REF_NAME%@*} - fi - - echo "pkgName=$pkgName" >> $GITHUB_OUTPUT - - - name: Create Release for Tag - # only run if tag is not alpha - if: steps.tag.outputs.pkgName - id: release_tag - uses: yyx990803/release-tag@8cccf7c5aa332d71d222df46677f70f77a8d2dc0 # v1.0.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - body: | - Please refer to [CHANGELOG.md](https://github.com/vitejs/vite/blob/${{ github.ref_name }}/packages/${{ steps.tag.outputs.pkgName }}/CHANGELOG.md) for details. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6ec3ab6f8eae22..59ceee7771a153 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -336,22 +336,35 @@ flowchart TD ### Release -If you have publish access, the steps below explain how to cut a release for a package. There are two phases for the release step: "Release" and "Publish". +All publishable packages in this repository use a pull-request-driven release flow. GitHub Actions prepares a release PR containing the version bump and changelog, and merging that PR triggers publishing. -"Release" is done locally to generate the changelogs and git tags: +#### Prepare a Release -1. Make sure the git remote for https://github.com/vitejs/vite is set as `origin`. -2. In the `vite` project root `main` branch, run `git pull` and `pnpm i` to get it up-to-date. Then run `pnpm build`. -3. Run `pnpm release` and follow the prompts to cut a release for a package. It will generate the changelog, a git release tag, and push them to `origin`. You can run with the `--dry` flag to test it out. -4. When the command finishes, it will provide a link to https://github.com/vitejs/vite/actions/workflows/publish.yml. -5. Click the link to visit the page, and follow the next steps below. +1. Run the [Prepare Release](.github/workflows/prepare-release.yml) workflow from the `main` branch. +2. Select `vite`, `create-vite`, or `plugin-legacy`. +3. Select a `release` type. The default `next` creates the next patch for a stable version or advances an existing prerelease. Alternatively, select another supported release type or enter an exact `version`, which takes precedence over `release`. +4. Wait for the action to open the release PR. The PR contains the selected package's version bump and changelog entry. A `create-vite` release also updates template Vite dependency versions when appropriate. -"Publish" is done on GitHub Actions to publish the package to npm: +#### Review and Publish -1. Shortly in the workflows page, a new workflow will appear for the released package and is waiting for approval to publish to npm. -2. Click on the workflow to open its page. -3. Click on the "Review deployments" button in the yellow box, a popup will appear. -4. Check "Release" and click "Approve and deploy". -5. The package will start publishing to npm. +1. Review the generated version and changelog, and wait for the release PR checks to pass. +2. Merge the PR while retaining its `release: ` commit subject. Vite uses `release: v`; other packages use `release: @`. A matching commit at the tip of `main` triggers the publish job. +3. Open the [Publish Package](.github/workflows/publish.yml) run and approve its `Release` environment deployment. +4. Wait for the workflow to publish the package, create its tag, and create the corresponding GitHub release. +5. Verify the new version on npm. + +#### Repository Configuration + +The release flow depends on configuration outside this repository: + +- The `Release` environment must require maintainer approval before publishing. +- The npm trusted publishers for `vite`, `create-vite`, and `@vitejs/plugin-legacy` must be restricted to `vitejs/vite`, `.github/workflows/publish.yml`, and the `Release` environment. + +#### Recovery + +- If release preparation fails, fix the cause and rerun the preparation workflow. Each run creates a uniquely named branch. +- If publishing fails before npm accepts the package, fix the cause and rerun the failed workflow. +- If npm publishing succeeds but tag or GitHub release creation fails, do not rerun the entire publish job blindly because npm versions are immutable. Confirm the package state first, then manually create the tag at the original release commit and create the GitHub release from the corresponding changelog entry. +- If the release tag already exists, investigate whether the package was previously published before retrying or changing any release state. To learn more about how and when Vite does releases, check out the [Releases](https://vite.dev/releases) documentation. diff --git a/package.json b/package.json index 95a5b293d9b7a1..ac0a4d6c3d15b8 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "docs-serve": "pnpm --filter=./docs run docs-serve", "build": "pnpm -r --filter='./packages/*' run build", "dev": "pnpm -r --parallel --filter='./packages/*' run dev", - "release": "tsx scripts/release.ts", "ci-publish": "tsx scripts/publishCI.ts", "ci-docs": "pnpm build && pnpm docs-build", "merge-changelog": "tsx scripts/mergeChangelog.ts" @@ -54,7 +53,7 @@ "@types/picomatch": "^4.0.3", "@types/stylus": "^0.48.43", "@types/ws": "^8.18.1", - "@vitejs/release-scripts": "^1.9.1", + "@vitejs/release-scripts": "^1.9.2", "eslint": "^9.39.5", "eslint-plugin-import-x": "^4.17.1", "eslint-plugin-n": "^18.3.0", diff --git a/packages/create-vite/src/index.ts b/packages/create-vite/src/index.ts index be300738573fa3..cbc27b7f9a01f1 100755 --- a/packages/create-vite/src/index.ts +++ b/packages/create-vite/src/index.ts @@ -36,7 +36,7 @@ const argv = mri<{ }) const cwd = process.cwd() -// prettier-ignore +// oxfmt-ignore const helpMessage = `\ Usage: create-vite [OPTION]... [DIRECTORY] diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index b9f516d2a9829e..4340bc84dff6f7 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -20,6 +20,7 @@ import { type OutputChunk, type PluginContextMeta, type RolldownOptions, + type RolldownOutput, rolldown, } from 'rolldown' import { isDynamicPattern } from 'tinyglobby' @@ -2652,16 +2653,20 @@ export async function bundleConfigFile( }, ], }) - const result = await bundle.generate({ - format: isESM ? 'esm' : 'cjs', - sourcemap: 'inline', - sourcemapPathTransform(relative, sourcemapPath) { - return path.resolve(path.dirname(sourcemapPath), relative) - }, - // we want to generate a single chunk like esbuild does with `splitting: false` - codeSplitting: false, - }) - await bundle.close() + let result: RolldownOutput + try { + result = await bundle.generate({ + format: isESM ? 'esm' : 'cjs', + sourcemap: 'inline', + sourcemapPathTransform(relative, sourcemapPath) { + return path.resolve(path.dirname(sourcemapPath), relative) + }, + // we want to generate a single chunk like esbuild does with `splitting: false` + codeSplitting: false, + }) + } finally { + await bundle.close() + } const entryChunk = result.output.find( (chunk): chunk is OutputChunk => chunk.type === 'chunk' && chunk.isEntry, diff --git a/playground/test-utils.ts b/playground/test-utils.ts index a9f0c903935513..9be84221de297b 100644 --- a/playground/test-utils.ts +++ b/playground/test-utils.ts @@ -430,7 +430,7 @@ export const formatSourcemapForSnapshot = ( } const normalized = Object.fromEntries( Object.keys(m) - .filter((key) => m[key] !== null) + .filter((key) => m[key] != null) .sort() .map((key) => [key, m[key]]), ) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac6fbd3e203c5d..f6a6e3f091cb36 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -64,8 +64,8 @@ importers: specifier: ^8.18.1 version: 8.18.1 '@vitejs/release-scripts': - specifier: ^1.9.1 - version: 1.9.1(conventional-commits-filter@6.0.1) + specifier: ^1.9.2 + version: 1.9.2 eslint: specifier: ^9.39.5 version: 9.39.5(jiti@2.7.0)(ms@2.1.3) @@ -179,7 +179,7 @@ importers: version: 1.2.0 tsdown: specifier: ^0.22.14 - version: 0.22.14(@vitejs/devtools@0.4.12)(@volar/typescript@2.4.28)(publint@0.3.21)(tsx@4.23.12)(typescript@6.0.3)(unrun@0.3.1)(vue-tsc@3.3.10) + version: 0.22.14(@vitejs/devtools@0.4.12)(@volar/typescript@2.4.28)(publint@0.3.23)(tsx@4.23.12)(typescript@6.0.3)(unrun@0.3.1)(vue-tsc@3.3.10) unrun: specifier: ^0.3.1 version: 0.3.1 @@ -231,7 +231,7 @@ importers: version: 1.1.1 tsdown: specifier: ^0.22.14 - version: 0.22.14(@vitejs/devtools@0.4.12)(@volar/typescript@2.4.28)(publint@0.3.21)(tsx@4.23.12)(typescript@6.0.3)(unrun@0.3.1)(vue-tsc@3.3.10) + version: 0.22.14(@vitejs/devtools@0.4.12)(@volar/typescript@2.4.28)(publint@0.3.23)(tsx@4.23.12)(typescript@6.0.3)(unrun@0.3.1)(vue-tsc@3.3.10) unrun: specifier: ^0.3.1 version: 0.3.1 @@ -2450,20 +2450,20 @@ packages: cpu: [x64] os: [win32] - '@conventional-changelog/git-client@3.1.0': - resolution: {integrity: sha512-Tqa/gHco2WJWa740NRjOrfKVvzIqxkZpecb8bemaQ8sKM5PXb1UK4uTyTb/1wIqNuOVaDOFxyBdhTIQZn6gdjQ==} + '@conventional-changelog/git-client@3.1.2': + resolution: {integrity: sha512-jZqwnJwf7nboIlAcw/mkOjVa6DexCcUOgT2oOQgkoi3z9vR8tGFkcMy2BFcYwjhL9sYcDDXkRQDayiDieCoW7A==} engines: {node: '>=22'} peerDependencies: conventional-commits-filter: ^6.0.1 - conventional-commits-parser: ^7.0.1 + conventional-commits-parser: ^7.1.2 peerDependenciesMeta: conventional-commits-filter: optional: true conventional-commits-parser: optional: true - '@conventional-changelog/template@1.2.1': - resolution: {integrity: sha512-TzlTVpKPjaqW6qOYjQcYUDuGsLCNsvFHVBXkYGTAnf5V37jCWrE5haKNXzz0WZUtVHjrpV76L1buANjwXMfT8w==} + '@conventional-changelog/template@1.4.0': + resolution: {integrity: sha512-aalGyl7dbB5PArRebDIX43ZvBlXrYm9uWzGJ26t+4SzJVPsOuvfILGGbw5X4yX7i50YEmJ8zvbiWnqH/AAnZqg==} engines: {node: '>=22'} '@cspotcode/source-map-support@0.8.1': @@ -3565,8 +3565,8 @@ packages: '@poppinss/exception@1.2.3': resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} - '@publint/pack@0.1.4': - resolution: {integrity: sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ==} + '@publint/pack@0.1.6': + resolution: {integrity: sha512-3uVNyGcVplhPZSLVyeIpL7+cIRn1YCSNHLG/rUIlBQMVH8YuN9++YF+5+UDIIO9RW98dujiUoTltO7RDB5bFJA==} engines: {node: '>=18'} '@quansync/fs@1.0.0': @@ -4380,8 +4380,8 @@ packages: vite: workspace:* vue: ^3.2.25 - '@vitejs/release-scripts@1.9.1': - resolution: {integrity: sha512-QWtOm5A9JPRqmfMhVv+zgppLwNwxq+FTPP8ibIV65WxclzNQ76tvQtML/DOstiDv4SJac/9IDpYQQKyNCdOoTw==} + '@vitejs/release-scripts@1.9.2': + resolution: {integrity: sha512-MIvAic70ulFycMdhJiXLBQS8xcsjOcD2kZMtYzPYPfWI+2ruhEzFYbAbdFLUZ82zXGReqQBRn04tWfS4as63+g==} '@vitejs/require@file:playground/json/dep-json-require': resolution: {directory: playground/json/dep-json-require, type: directory} @@ -5332,21 +5332,21 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - conventional-changelog-conventionalcommits@10.2.1: - resolution: {integrity: sha512-n4Kr1HFMTf3iMbES0TMxKIcYtUUv4rKqyQQp2JwfOEfFCOfGT3Tq4mCyJ8S9/YPyWhydjfKrrvnyl+gCjA+mJQ==} + conventional-changelog-conventionalcommits@10.4.0: + resolution: {integrity: sha512-Rriac6ZrAlVm6cy9Bz4NSp+WMHpwNXoPIYex+HjCgduAVUSbnew29DQjQw0C4g9u3HtSYzGiGY+pdBXAZo+4aA==} engines: {node: '>=22'} conventional-changelog-preset-loader@6.0.1: resolution: {integrity: sha512-GZ8E3RQzXQb3JFy0pKl8oeSf7ENIhvAMvJr+PlWkavZOesLHHdhkfNJ4SvW35eo1Fu2+EyVxWQ1tVvtzAG2iWg==} engines: {node: '>=22'} - conventional-changelog-writer@9.2.0: - resolution: {integrity: sha512-eACD5BaAQCYjeI3RExkCZopNaaIuXzCP4kaAb2lEFXcGa/KOuxJfj8v/SnjhvF6377pYn0A2Gji+6GhwUK8rEA==} + conventional-changelog-writer@9.2.1: + resolution: {integrity: sha512-StlYSmW3wLedRaqohJMpP3YuWiAqtgD0/cpsai9frdDkXv7rxj0hRbpJrubPYvJxJsjplONsOobEQnPuS9UgCg==} engines: {node: '>=22'} hasBin: true - conventional-changelog@8.1.0: - resolution: {integrity: sha512-idt1JK+3+Nt7gqH/d/sEYWdDeR+5XPov/jssmFN6XxmYSRlonTWSDWhWUPkmm0zbwYjtVdt+4My5aiPkKyvocw==} + conventional-changelog@8.1.3: + resolution: {integrity: sha512-fOMwLCxm46znJKPB08jLxl1FD8SOZOQHktlzCVhvhhVUfq0KgQSryoYXsRRHs1aRlZPR1/QK5wztnY8sBNC2AA==} engines: {node: '>=22'} hasBin: true @@ -5354,8 +5354,8 @@ packages: resolution: {integrity: sha512-cs+LadpH7Kpw0M3k8wurk+sOVVDAENA0iK4OBOrkL94j5lEVYRJ4j3zd2bhY9qgzyrPqthdcYT3axzRN7AliMg==} engines: {node: '>=22'} - conventional-commits-parser@7.1.0: - resolution: {integrity: sha512-DPp6hkUjvwIivxbkrTiLXeRswNv1A/4GFA2X6scXma0AMa9632V3TwxmrlkUIEtUktiM3Ln+RrSH2xlP3/jUTw==} + conventional-commits-parser@7.1.2: + resolution: {integrity: sha512-O+x4N2yH+ijvqWlIyTHsXTAP+algNWgGbjY2duCe8w2vUMvUB95cLRslCPfTMQyLAKlet3bhZTdu6ozn4M+QJQ==} engines: {node: '>=22'} hasBin: true @@ -6803,6 +6803,9 @@ packages: package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + package-manager-detector@1.8.0: + resolution: {integrity: sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==} + package-name-regex@2.0.6: resolution: {integrity: sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==} engines: {node: '>=12'} @@ -7035,8 +7038,8 @@ packages: prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} - publint@0.3.21: - resolution: {integrity: sha512-OqejcnMV6E9zel2oCrUOJEiiFkGiAAni0A6ibfQNh1k9Gu5z4F+Yso8lllam7AzmV6Do0vp7u3UpZNRBwuXaHQ==} + publint@0.3.23: + resolution: {integrity: sha512-5MQipUPcB7MWw84zLUkHrg/H/UBtk3LL+A0GngTTBSsiNJLQurMUaSIRG3edlOrRz4UFe0AOKK9TZdIWviV+jQ==} engines: {node: '>=18'} hasBin: true @@ -8945,16 +8948,16 @@ snapshots: '@cloudflare/workerd-windows-64@1.20260730.1': optional: true - '@conventional-changelog/git-client@3.1.0(conventional-commits-filter@6.0.1)(conventional-commits-parser@7.1.0)': + '@conventional-changelog/git-client@3.1.2(conventional-commits-filter@6.0.1)(conventional-commits-parser@7.1.2)': dependencies: '@simple-libs/child-process-utils': 2.0.0 '@simple-libs/stream-utils': 2.0.0 semver: 7.8.5 optionalDependencies: conventional-commits-filter: 6.0.1 - conventional-commits-parser: 7.1.0 + conventional-commits-parser: 7.1.2 - '@conventional-changelog/template@1.2.1': {} + '@conventional-changelog/template@1.4.0': {} '@cspotcode/source-map-support@0.8.1': dependencies: @@ -9708,7 +9711,9 @@ snapshots: '@poppinss/exception@1.2.3': {} - '@publint/pack@0.1.4': {} + '@publint/pack@0.1.6': + dependencies: + tinyexec: 1.3.0 '@quansync/fs@1.0.0': dependencies: @@ -10426,19 +10431,17 @@ snapshots: vite: link:packages/vite vue: 3.5.41(typescript@6.0.3) - '@vitejs/release-scripts@1.9.1(conventional-commits-filter@6.0.1)': + '@vitejs/release-scripts@1.9.2': dependencies: - '@conventional-changelog/template': 1.2.1 - conventional-changelog: 8.1.0(conventional-commits-filter@6.0.1) - conventional-changelog-conventionalcommits: 10.2.1 + '@conventional-changelog/template': 1.4.0 + conventional-changelog: 8.1.3 + conventional-changelog-conventionalcommits: 10.4.0 mri: 1.2.0 picocolors: 1.1.1 prompts: 2.4.2 - publint: 0.3.21 + publint: 0.3.23 semver: 7.8.5 tinyexec: 1.3.0 - transitivePeerDependencies: - - conventional-commits-filter '@vitejs/require@file:playground/json/dep-json-require': {} @@ -11308,36 +11311,35 @@ snapshots: content-type@1.0.5: {} - conventional-changelog-conventionalcommits@10.2.1: + conventional-changelog-conventionalcommits@10.4.0: dependencies: - '@conventional-changelog/template': 1.2.1 + '@conventional-changelog/template': 1.4.0 conventional-changelog-preset-loader@6.0.1: {} - conventional-changelog-writer@9.2.0: + conventional-changelog-writer@9.2.1: dependencies: - '@conventional-changelog/template': 1.2.1 + '@conventional-changelog/template': 1.4.0 '@simple-libs/stream-utils': 2.0.0 argue-cli: 3.1.0 conventional-commits-filter: 6.0.1 semver: 7.8.5 - conventional-changelog@8.1.0(conventional-commits-filter@6.0.1): + conventional-changelog@8.1.3: dependencies: - '@conventional-changelog/git-client': 3.1.0(conventional-commits-filter@6.0.1)(conventional-commits-parser@7.1.0) + '@conventional-changelog/git-client': 3.1.2(conventional-commits-filter@6.0.1)(conventional-commits-parser@7.1.2) '@simple-libs/hosted-git-info': 2.0.0 '@simple-libs/normalize-package-data': 1.0.0 argue-cli: 3.1.0 conventional-changelog-preset-loader: 6.0.1 - conventional-changelog-writer: 9.2.0 - conventional-commits-parser: 7.1.0 + conventional-changelog-writer: 9.2.1 + conventional-commits-filter: 6.0.1 + conventional-commits-parser: 7.1.2 fd-package-json: 2.0.0 - transitivePeerDependencies: - - conventional-commits-filter conventional-commits-filter@6.0.1: {} - conventional-commits-parser@7.1.0: + conventional-commits-parser@7.1.2: dependencies: '@simple-libs/stream-utils': 2.0.0 argue-cli: 3.1.0 @@ -12917,6 +12919,8 @@ snapshots: package-manager-detector@1.6.0: {} + package-manager-detector@1.8.0: {} + package-name-regex@2.0.6: {} parent-module@1.0.1: @@ -13133,10 +13137,10 @@ snapshots: prr@1.0.1: optional: true - publint@0.3.21: + publint@0.3.23: dependencies: - '@publint/pack': 0.1.4 - package-manager-detector: 1.6.0 + '@publint/pack': 0.1.6 + package-manager-detector: 1.8.0 picocolors: 1.1.1 sade: 1.8.1 @@ -13969,7 +13973,7 @@ snapshots: ts-interface-checker@0.1.13: {} - tsdown@0.22.14(@vitejs/devtools@0.4.12)(@volar/typescript@2.4.28)(publint@0.3.21)(tsx@4.23.12)(typescript@6.0.3)(unrun@0.3.1)(vue-tsc@3.3.10): + tsdown@0.22.14(@vitejs/devtools@0.4.12)(@volar/typescript@2.4.28)(publint@0.3.23)(tsx@4.23.12)(typescript@6.0.3)(unrun@0.3.1)(vue-tsc@3.3.10): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -13988,7 +13992,7 @@ snapshots: verkit: 0.3.1 optionalDependencies: '@vitejs/devtools': 0.4.12(crossws@0.4.10)(srvx@0.12.5)(typescript@6.0.3)(vite@packages+vite) - publint: 0.3.21 + publint: 0.3.23 tsx: 4.23.12 typescript: 6.0.3 unrun: 0.3.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 3a62aa17a31ee6..28ac9d33641986 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -51,6 +51,7 @@ minimumReleaseAge: 1440 minimumReleaseAgeExclude: - rolldown - '@rolldown/binding-*' + - '@vitejs/release-scripts@1.9.2' - '@voidzero-dev/vitepress-theme@5.0.6' blockExoticSubdeps: true trustPolicy: no-downgrade diff --git a/scripts/detect-release.ts b/scripts/detect-release.ts new file mode 100644 index 00000000000000..19b95ef5ee9760 --- /dev/null +++ b/scripts/detect-release.ts @@ -0,0 +1,19 @@ +import { detectReleaseCommit } from '@vitejs/release-scripts' +import { releasePackages } from './releaseUtils.ts' + +const subject = process.argv[2] +if (!subject) throw new Error('Release commit subject is required') + +const release = detectReleaseCommit({ + subject, + packages: releasePackages, + defaultPackage: 'vite', +}) + +if (release) { + console.log( + `package=${release.pkg}\nrelease=true\ntag=${release.tag}\nversion=${release.version}`, + ) +} else { + console.log('release=false') +} diff --git a/scripts/extract-changelog.ts b/scripts/extract-changelog.ts new file mode 100644 index 00000000000000..c2bf0f187747ea --- /dev/null +++ b/scripts/extract-changelog.ts @@ -0,0 +1,9 @@ +import { extractChangelogEntry } from '@vitejs/release-scripts' + +const [path, version] = process.argv.slice(2) +if (!path || !version) { + throw new Error('Usage: node scripts/extract-changelog.ts ') +} + +const notes = extractChangelogEntry({ changelogPath: path, version }) +process.stdout.write(`${notes}\n`) diff --git a/scripts/prepare-release.ts b/scripts/prepare-release.ts new file mode 100644 index 00000000000000..428bf08edd977c --- /dev/null +++ b/scripts/prepare-release.ts @@ -0,0 +1,50 @@ +import { + extractChangelogEntry, + generateChangelog, + getReleaseTag, + prepareRelease, +} from '@vitejs/release-scripts' +import { releasePackages, updateTemplateVersions } from './releaseUtils.ts' + +function getRequiredEnv(name: string): string { + const value = process.env[name] + if (!value) throw new Error(`${name} is required`) + return value +} + +const pkg = process.argv[2] +const githubServerUrl = getRequiredEnv('GITHUB_SERVER_URL') +const githubRepository = getRequiredEnv('GITHUB_REPOSITORY') +const githubRunId = getRequiredEnv('GITHUB_RUN_ID') + +const { tag, version } = await prepareRelease({ + packages: releasePackages, + pkg, + release: process.argv[3], + toTag: (pkg, version) => getReleaseTag(pkg, version, 'vite'), + generateChangelog: async (pkg) => { + if (pkg === 'create-vite') await updateTemplateVersions() + + await generateChangelog({ + getPkgDir: () => `packages/${pkg}`, + tagPrefix: pkg === 'vite' ? undefined : `${pkg}@`, + }) + }, +}) + +const changelog = extractChangelogEntry({ + changelogPath: `packages/${pkg}/CHANGELOG.md`, + version, +}) +const prBody = [ + `${pkg} release PR generated by the Prepare Release workflow: ${githubServerUrl}/${githubRepository}/actions/runs/${githubRunId}`, + '', + '## Changelog', + '', + changelog, +].join('\n') +const delimiter = '__VITE_RELEASE_PR_BODY_EOF__' + +console.log( + `tag=${tag}\nversion=${version}\npr_body<<${delimiter}\n${prBody}\n${delimiter}`, +) diff --git a/scripts/release.ts b/scripts/release.ts deleted file mode 100644 index bdfc32bf224e79..00000000000000 --- a/scripts/release.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { generateChangelog, release } from '@vitejs/release-scripts' -import colors from 'picocolors' -import { logRecentCommits, updateTemplateVersions } from './releaseUtils' - -release({ - repo: 'vite', - packages: ['vite', 'create-vite', 'plugin-legacy'], - toTag: (pkg, version) => - pkg === 'vite' ? `v${version}` : `${pkg}@${version}`, - logChangelog: (pkg) => logRecentCommits(pkg), - generateChangelog: async (pkgName) => { - if (pkgName === 'create-vite') await updateTemplateVersions() - - console.log(colors.cyan('\nGenerating changelog...')) - - await generateChangelog({ - getPkgDir: () => `packages/${pkgName}`, - tagPrefix: pkgName === 'vite' ? undefined : `${pkgName}@`, - }) - }, -}) diff --git a/scripts/releaseUtils.ts b/scripts/releaseUtils.ts index 6a7654960a753a..b9b8a0c21c3e56 100644 --- a/scripts/releaseUtils.ts +++ b/scripts/releaseUtils.ts @@ -1,54 +1,7 @@ import fs from 'node:fs/promises' import path from 'node:path' -import colors from 'picocolors' -import type { Options as ExecaOptions, ResultPromise } from 'execa' -import { execa } from 'execa' -function run( - bin: string, - args: string[], - opts?: EO, -): ResultPromise< - EO & (keyof EO extends 'stdio' ? object : { stdio: 'inherit' }) -> { - return execa(bin, args, { stdio: 'inherit', ...opts }) as any -} - -export async function getLatestTag(pkgName: string): Promise { - const pkgJson = JSON.parse( - await fs.readFile(`packages/${pkgName}/package.json`, 'utf-8'), - ) - const version = pkgJson.version - return pkgName === 'vite' ? `v${version}` : `${pkgName}@${version}` -} - -export async function logRecentCommits(pkgName: string): Promise { - const tag = await getLatestTag(pkgName) - if (!tag) return - const sha = await run('git', ['rev-list', '-n', '1', tag], { - stdio: 'pipe', - }).then((res) => res.stdout.trim()) - console.log( - colors.bold( - `\n${colors.blue(`i`)} Commits of ${colors.green( - pkgName, - )} since ${colors.green(tag)} ${colors.gray(`(${sha.slice(0, 5)})`)}`, - ), - ) - await run( - 'git', - [ - '--no-pager', - 'log', - `${sha}..HEAD`, - '--oneline', - '--', - `packages/${pkgName}`, - ], - { stdio: 'inherit' }, - ) - console.log() -} +export const releasePackages = ['vite', 'create-vite', 'plugin-legacy'] as const export async function updateTemplateVersions(): Promise { const vitePkgJson = JSON.parse( diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json index 339127f7d0296a..f94bc3c7a98adb 100644 --- a/scripts/tsconfig.json +++ b/scripts/tsconfig.json @@ -5,6 +5,7 @@ "module": "preserve", "target": "es2023", "moduleResolution": "bundler", + "allowImportingTsExtensions": true, "types": ["node"], "noEmit": true, "erasableSyntaxOnly": true,