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 0000000000..46e23a7d80 --- /dev/null +++ b/.github/workflows/publish-to-pkg.pr.new.yml @@ -0,0 +1,150 @@ +name: Publish to pkg.pr.new + +# https://pkg.pr.new/~/voidzero-dev/vite-plus + +permissions: {} + +on: + workflow_dispatch: + push: + branches: + - ci/pkg-pr-new + pull_request: + types: [labeled] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + prepare: + if: >- + github.repository == 'voidzero-dev/vite-plus' && + (github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'pkg.pr.new'))) + name: Compute snapshot version + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + version: ${{ steps.version.outputs.version }} + steps: + - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 + + # pkg-pr-new rewrites the published version anyway, but we still need a + # unique snapshot version so `napi pre-publish` writes consistent + # optionalDependencies entries across the platform packages. + - name: Compute version + id: version + run: | + short_sha=$(git rev-parse --short=7 HEAD) + echo "version=0.0.0-pkg-pr-new.${short_sha}" >> "$GITHUB_OUTPUT" + + build-rust: + name: Build bindings and binaries + if: >- + github.repository == 'voidzero-dev/vite-plus' && + (github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'pkg.pr.new'))) + needs: prepare + permissions: + contents: read + uses: ./.github/workflows/reusable-release-build.yml + with: + version: ${{ needs.prepare.outputs.version }} + cache-key: pkg-pr-new + + publish: + if: >- + github.repository == 'voidzero-dev/vite-plus' && + (github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'pkg.pr.new'))) + name: Pkg Preview + runs-on: ubuntu-latest + needs: + - prepare + - build-rust + permissions: + # pkg-pr-new comments on PRs and posts run statuses with this token. + contents: read + pull-requests: write + env: + VERSION: ${{ needs.prepare.outputs.version }} + steps: + - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 + - uses: ./.github/actions/clone + + - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 + + - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version-file: .node-version + package-manager-cache: false + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install + + - name: Download cli dist + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: packages/cli/dist + pattern: cli + merge-multiple: true + + - name: Download cli docs + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: packages/cli/docs + pattern: cli-docs + merge-multiple: true + + - name: Download cli binding + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: packages/cli/artifacts + pattern: vite-plus-native-* + + - name: Download core dist + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: packages/core/dist + pattern: core + merge-multiple: true + + - name: Download prompts dist + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: packages/prompts/dist + pattern: prompts + merge-multiple: true + + - uses: ./.github/actions/download-rolldown-binaries + with: + github-token: ${{ github.token }} + target: x86_64-unknown-linux-gnu + upload: 'false' + + - name: Download Rust CLI binaries + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: rust-cli-artifacts + pattern: vite-global-cli-* + + # Stops short of `npm publish` and leaves packages/cli/{npm,cli-npm}/* + # on disk for pkg-pr-new to upload. + - name: Prepare native addon and CLI binary packages + run: node ./packages/cli/publish-native-addons.ts --mode pkg-pr-new + + - name: Publish to pkg.pr.new + run: | + pnpm dlx pkg-pr-new publish --compact --pnpm \ + './packages/cli/npm/*' \ + './packages/cli/cli-npm/*' \ + './packages/cli' \ + './packages/core' \ + './packages/prompts' \ + './packages/test' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 40b044c331..b533f42c4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,6 +36,7 @@ jobs: with: fetch-depth: 0 fetch-tags: true + persist-credentials: false - uses: ./.github/actions/set-snapshot-version if: ${{ inputs.version == '' }} id: computed @@ -44,138 +45,20 @@ jobs: - name: Set final version id: version - run: echo "version=${{ inputs.version || steps.computed.outputs.version }}" >> $GITHUB_OUTPUT + env: + INPUT_VERSION: ${{ inputs.version }} + COMPUTED_VERSION: ${{ steps.computed.outputs.version }} + run: echo "version=${INPUT_VERSION:-$COMPUTED_VERSION}" >> "$GITHUB_OUTPUT" build-rust: - runs-on: ${{ matrix.settings.os }} + name: Build bindings and binaries needs: prepare permissions: contents: read - env: - VERSION: ${{ needs.prepare.outputs.version }} - strategy: - fail-fast: false - matrix: - settings: - - target: aarch64-apple-darwin - os: macos-latest - - target: x86_64-apple-darwin - os: macos-latest - - target: aarch64-unknown-linux-gnu - os: ubuntu-latest - - target: aarch64-unknown-linux-musl - os: ubuntu-latest - - target: x86_64-unknown-linux-gnu - os: ubuntu-latest - - target: x86_64-unknown-linux-musl - os: ubuntu-latest - - target: x86_64-pc-windows-msvc - os: windows-latest - - target: aarch64-pc-windows-msvc - os: windows-latest - steps: - - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 - - uses: ./.github/actions/clone - - uses: oxc-project/setup-rust@23f38cfb0c04af97a055f76acee94d5be71c7c82 # v1.0.16 - with: - save-cache: ${{ github.ref_name == 'main' }} - cache-key: release - - - name: Rustup Adds Target - run: rustup target add ${{ matrix.settings.target }} - - - uses: oxc-project/setup-node@4c26e7cb3605b6bdef5450dacd02c434b10fd8ba # v1.2.0 - - - name: Set binding version - shell: bash - run: | - pnpm exec tool replace-file-content packages/cli/binding/Cargo.toml 'version = "0.0.0"' 'version = "${{ env.VERSION }}"' - pnpm exec tool replace-file-content crates/vite_global_cli/Cargo.toml 'version = "0.0.0"' 'version = "${{ env.VERSION }}"' - cat crates/vite_global_cli/Cargo.toml - - - name: Verify version replacement - shell: bash - run: | - if grep -q 'version = "0.0.0"' crates/vite_global_cli/Cargo.toml; then - echo "ERROR: Version replacement failed for crates/vite_global_cli/Cargo.toml" - head -5 crates/vite_global_cli/Cargo.toml - exit 1 - fi - if grep -q 'version = "0.0.0"' packages/cli/binding/Cargo.toml; then - echo "ERROR: Version replacement failed for packages/cli/binding/Cargo.toml" - head -5 packages/cli/binding/Cargo.toml - exit 1 - fi - echo "Version replacement verified successfully" - - - name: Build - uses: ./.github/actions/build-upstream - with: - target: ${{ matrix.settings.target }} - - - name: Upload Vite+ native artifact - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: vite-plus-native-${{ matrix.settings.target }} - path: ./packages/cli/binding/*.node - if-no-files-found: error - - - name: Upload Rust CLI binary artifact - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: vite-global-cli-${{ matrix.settings.target }} - path: | - ./target/${{ matrix.settings.target }}/release/vp - ./target/${{ matrix.settings.target }}/release/vp.exe - ./target/${{ matrix.settings.target }}/release/vp-shim.exe - if-no-files-found: error - - - name: Upload installer binary artifact (Windows only) - if: contains(matrix.settings.target, 'windows') - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: vp-setup-${{ matrix.settings.target }} - path: ./target/${{ matrix.settings.target }}/release/vp-setup.exe - if-no-files-found: error - - - name: Remove .node files before upload dist - if: ${{ matrix.settings.target == 'x86_64-unknown-linux-gnu' }} - run: | - rm ./packages/core/dist/**/*.node - - - name: Upload core dist - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - if: ${{ matrix.settings.target == 'x86_64-unknown-linux-gnu' }} - with: - name: core - path: ./packages/core/dist - if-no-files-found: error - - - name: Upload cli dist - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - if: ${{ matrix.settings.target == 'x86_64-unknown-linux-gnu' }} - with: - name: cli - path: ./packages/cli/dist - if-no-files-found: error - - - name: Upload cli docs - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - if: ${{ matrix.settings.target == 'x86_64-unknown-linux-gnu' }} - with: - name: cli-docs - path: ./packages/cli/docs - if-no-files-found: error - - - name: Upload LICENSE files - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - if: ${{ matrix.settings.target == 'x86_64-unknown-linux-gnu' }} - with: - name: licenses - path: | - ./packages/core/LICENSE - ./packages/cli/LICENSE - if-no-files-found: error + uses: ./.github/workflows/reusable-release-build.yml + with: + version: ${{ needs.prepare.outputs.version }} + cache-key: release Release: runs-on: ubuntu-latest @@ -254,30 +137,6 @@ jobs: path: installer-artifacts pattern: vp-setup-* - - name: Move Rust CLI binaries to target directories - run: | - # Move each artifact's binary to the correct target directory - for artifact_dir in rust-cli-artifacts/vite-global-cli-*/; do - if [ -d "$artifact_dir" ]; then - # Extract target name from directory (e.g., vite-global-cli-x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) - dir_name=$(basename "$artifact_dir") - target_name=${dir_name#vite-global-cli-} - # Create target directory and copy binary - mkdir -p "target/${target_name}/release" - cp -r "$artifact_dir"* "target/${target_name}/release/" - fi - done - # Show what we have (fail if no binaries found) - vp_files=$(find target -name "vp*" -type f 2>/dev/null || echo "") - if [ -z "$vp_files" ]; then - echo "Error: No vp binaries found in target directory" - echo "Artifact contents:" - find rust-cli-artifacts -type f || true - exit 1 - fi - echo "Found binaries:" - echo "$vp_files" - - name: Prepare installer binaries for release run: | mkdir -p installer-release @@ -291,46 +150,38 @@ jobs: echo "Installer binaries:" ls -la installer-release/ || echo "No installer binaries found" - - name: Set npm packages version - run: | - sed -i 's/"version": "0.0.0"/"version": "${{ env.VERSION }}"/' packages/core/package.json - sed -i 's/"version": "0.0.0"/"version": "${{ env.VERSION }}"/' packages/test/package.json - sed -i 's/"version": "0.0.0"/"version": "${{ env.VERSION }}"/' packages/cli/package.json - - - name: Build test - run: pnpm --filter=@voidzero-dev/vite-plus-test build - - name: 'Setup npm' - run: | - npm install -g npm@latest + run: npm install -g npm@latest - - name: Publish native addons - run: | - node ./packages/cli/publish-native-addons.ts + - name: Prepare and publish native addons + run: node ./packages/cli/publish-native-addons.ts --mode npm - name: Publish run: | - pnpm publish --filter=./packages/core --tag ${{ inputs.npm_tag }} --access public --no-git-checks - pnpm publish --filter=./packages/test --tag ${{ inputs.npm_tag }} --access public --no-git-checks - pnpm publish --filter=./packages/cli --tag ${{ inputs.npm_tag }} --access public --no-git-checks + pnpm publish --filter=./packages/core --tag "${NPM_TAG}" --access public --no-git-checks + pnpm publish --filter=./packages/test --tag "${NPM_TAG}" --access public --no-git-checks + pnpm publish --filter=./packages/cli --tag "${NPM_TAG}" --access public --no-git-checks - name: Create release body + env: + REPOSITORY: ${{ github.repository }} + COMMIT_SHA: ${{ github.sha }} run: | - if [[ "${{ inputs.npm_tag }}" == "latest" ]]; then + if [[ "${NPM_TAG}" == "latest" ]]; then INSTALL_BASH="curl -fsSL https://vite.plus | bash" INSTALL_PS1="irm https://vite.plus/ps1 | iex" else - INSTALL_BASH="curl -fsSL https://vite.plus | VP_VERSION=${{ env.VERSION }} bash" - INSTALL_PS1="\\\$env:VP_VERSION=\\\"${{ env.VERSION }}\\\"; irm https://vite.plus/ps1 | iex" + INSTALL_BASH="curl -fsSL https://vite.plus | VP_VERSION=${VERSION} bash" + INSTALL_PS1="\\\$env:VP_VERSION=\\\"${VERSION}\\\"; irm https://vite.plus/ps1 | iex" fi cat > ./RELEASE_BODY.md <= 0 ? args[modeIdx + 1] : null; +if (mode !== 'npm' && mode !== 'pkg-pr-new') { + console.error(`Usage: publish-native-addons.ts --mode `); + process.exit(1); +} +const skipNpmPublish = mode === 'pkg-pr-new'; + +const VERSION = process.env.VERSION; +if (!VERSION) { + console.error('VERSION env var must be set'); + process.exit(1); +} + +// Move downloaded Rust CLI binaries into target//release/ where the +// rest of this script (and napi-cli) expects them. +const rustCliArtifactsDir = join(repoRoot, 'rust-cli-artifacts'); +if (existsSync(rustCliArtifactsDir)) { + for (const dir of await readdir(rustCliArtifactsDir)) { + if (!dir.startsWith('vite-global-cli-')) { + continue; + } + const target = dir.slice('vite-global-cli-'.length); + const releaseDir = join(repoRoot, 'target', target, 'release'); + mkdirSync(releaseDir, { recursive: true }); + for (const file of await readdir(join(rustCliArtifactsDir, dir))) { + copyFileSync(join(rustCliArtifactsDir, dir, file), join(releaseDir, file)); + } + } +} + +// Stamp VERSION into the publishable package.json files. napi prePublish and +// the cli-binary packages below both read packages/cli/package.json#version. +for (const p of ['core', 'test', 'cli']) { + const pkgPath = join(repoRoot, 'packages', p, 'package.json'); + const content = readFileSync(pkgPath, 'utf-8'); + writeFileSync(pkgPath, content.replace('"version": "0.0.0"', `"version": "${VERSION}"`)); +} + +// Build test package against the just-stamped versions. +execSync('pnpm --filter=@voidzero-dev/vite-plus-test build', { + cwd: repoRoot, + stdio: 'inherit', +}); + // Create npm directories for NAPI bindings await cli.createNpmDirs({ cwd: currentDir, @@ -47,25 +93,27 @@ const platformDirs = await readdir(npmDir); // Publish each NAPI platform package (without vp binary) const npmTag = process.env.NPM_TAG || 'latest'; -for (const file of platformDirs) { - try { - const output = execSync(`npm publish --tag ${npmTag} --access public`, { - cwd: join(currentDir, 'npm', file), - env: process.env, - stdio: 'pipe', - }); - process.stdout.write(output); - } catch (e) { - if ( - e instanceof Error && - e.message.includes('You cannot publish over the previously published versions') - ) { - // eslint-disable-next-line no-console - console.info(e.message); - // eslint-disable-next-line no-console - console.warn(`${file} has been published, skipping`); - } else { - throw e; +if (!skipNpmPublish) { + for (const file of platformDirs) { + try { + const output = execSync(`npm publish --tag ${npmTag} --access public`, { + cwd: join(currentDir, 'npm', file), + env: process.env, + stdio: 'pipe', + }); + process.stdout.write(output); + } catch (e) { + if ( + e instanceof Error && + e.message.includes('You cannot publish over the previously published versions') + ) { + // eslint-disable-next-line no-console + console.info(e.message); + // eslint-disable-next-line no-console + console.warn(`${file} has been published, skipping`); + } else { + throw e; + } } } } @@ -130,6 +178,14 @@ for (const napiTarget of pkg.napi.targets) { }; writeFileSync(join(platformCliDir, 'package.json'), JSON.stringify(cliPackage, null, 2) + '\n'); + if (skipNpmPublish) { + // eslint-disable-next-line no-console + console.log( + `Prepared CLI package: @voidzero-dev/vite-plus-cli-${platformArchABI}@${cliVersion}`, + ); + continue; + } + // Publish CLI package execSync(`npm publish --tag ${npmTag} --access public`, { cwd: platformCliDir, @@ -141,5 +197,7 @@ for (const napiTarget of pkg.napi.targets) { console.log(`Published CLI package: @voidzero-dev/vite-plus-cli-${platform}@${cliVersion}`); } -// Clean up cli-npm directory -rmSync(cliNpmDir, { recursive: true, force: true }); +// Clean up cli-npm directory (skipped when caller still needs the prepared dirs). +if (!skipNpmPublish) { + rmSync(cliNpmDir, { recursive: true, force: true }); +}