Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@
"rolldown/**",
"vite/**"
],
"customManagers": [
{
"description": "Keep the exact setup-vp migration target current.",
"customType": "regex",
"managerFilePatterns": ["/^packages\\/cli\\/src\\/utils\\/constants\\.ts$/"],
"matchStrings": ["export const SETUP_VP_VERSION = '(?<currentValue>[^']+)';"],
"depNameTemplate": "voidzero-dev/setup-vp",
"datasourceTemplate": "github-releases",
"versioningTemplate": "semver-coerced"
}
],
"packageRules": [
{
"description": "Ignore upstream toolchain npm packages (vendored via sync-remote or bumped by the proactive catalog workflow); everything else stays enabled so security alerts get fixed.",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "migration-setup-vp-version",
"devDependencies": {
"vite": "npm:@voidzero-dev/vite-plus-core@0.0.0-commit.0c515e3fbf5c140db35280d700df0bd600838617",
"vite-plus": "0.0.0-commit.0c515e3fbf5c140db35280d700df0bd600838617"
},
"overrides": {
"vite": "npm:@voidzero-dev/vite-plus-core@0.0.0-commit.0c515e3fbf5c140db35280d700df0bd600838617"
},
"packageManager": "npm@11.11.1"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[[case]]
name = "migration_setup_vp_version"
vp = "global"
env = { VP_OVERRIDE_PACKAGES = "{\"vite\":\"npm:@voidzero-dev/vite-plus-core@0.0.0-commit.0c515e3fbf5c140db35280d700df0bd600838617\",\"vitest\":\"4.1.11\"}", VP_VERSION = "0.0.0-commit.0c515e3fbf5c140db35280d700df0bd600838617" }
steps = [
{ argv = ["vpt", "mkdir", "-p", ".github/workflows"], snapshot = false },
{ argv = ["vpt", "cp", "workflow.txt", ".github/workflows/ci.yml"], snapshot = false },
{ argv = ["vp", "migrate", "--no-interactive"], comment = "an existing Vite+ project upgrades the frozen setup-vp tag", continue-on-failure = true },
{ argv = ["vpt", "print-file", ".github/workflows/ci.yml"], comment = "the workflow uses the exact setup-vp release", continue-on-failure = true },
{ argv = ["vp", "migrate", "--no-interactive"], comment = "the setup-vp migration is idempotent", continue-on-failure = true },
{ argv = ["vpt", "print-file", ".github/workflows/ci.yml"], comment = "the exact setup-vp release remains unchanged", continue-on-failure = true },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# migration_setup_vp_version

## `vpt mkdir -p .github/workflows`


## `vpt cp workflow.txt .github/workflows/ci.yml`


## `vp migrate --no-interactive`

an existing Vite+ project upgrades the frozen setup-vp tag

```
VITE+ - The Unified Toolchain for the Web

◇ Updated . to Vite+ <version>
• Node <version> npm <version>
• Dependencies:
vite → <version>
• setup-vp updated to <version> in 1 GitHub Actions file
```

## `vpt print-file .github/workflows/ci.yml`

the workflow uses the exact setup-vp release

```
name: CI

on: [push]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: voidzero-dev/setup-vp@<version>
with:
cache: true
- run: vp test
```

## `vp migrate --no-interactive`

the setup-vp migration is idempotent

```
VITE+ - The Unified Toolchain for the Web

This project is already using Vite+! Happy coding!
```

## `vpt print-file .github/workflows/ci.yml`

the exact setup-vp release remains unchanged

```
name: CI

on: [push]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: voidzero-dev/setup-vp@<version>
with:
cache: true
- run: vp test
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: CI

on: [push]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: voidzero-dev/setup-vp@v1
with:
cache: true
- run: vp test
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Vite+
uses: voidzero-dev/setup-vp@v1
uses: voidzero-dev/setup-vp@<version>
with:
cache: true
run-install: true
Expand Down
5 changes: 5 additions & 0 deletions docs/guide/ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ You can use `voidzero-dev/setup-vp` to use Vite+ in CI environments.

Set `<setup-vp-version>` in each example to an exact version from the [`setup-vp` releases page](https://github.com/voidzero-dev/setup-vp/releases). You can use a commit SHA instead. Do not use the `v1` tag. The `v1` tag no longer receives updates.

Run `vp migrate` to replace exact `voidzero-dev/setup-vp@v1` references in
GitHub Actions workflows and composite actions under `.github` with the latest
exact release known to your Vite+ version. Existing exact versions and commit
SHAs remain unchanged.

### Automatic Version Updates

Dependabot and Renovate can update exact versions in GitHub Actions workflows.
Expand Down
13 changes: 11 additions & 2 deletions docs/guide/migrate-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,14 @@ as `run` or `--`:

Unrelated `bunx` commands and other package-executor forms remain unchanged.

## Continuous Integration Rules

Migration replaces exact `voidzero-dev/setup-vp@v1` references in GitHub
Actions workflows and composite actions under `.github` with the latest exact
`setup-vp` release known to that Vite+ version. The frozen `v1` tag does not
receive new releases. Existing exact versions and commit SHAs are left
unchanged.

## Node.js Version Rules

Migration converts legacy Node.js version-manager files to `.node-version`,
Expand All @@ -263,8 +271,9 @@ migrations run it unconditionally.
existing `.node-version` is kept.
- When `.nvmrc` is removed, any `actions/setup-node` `node-version-file:
.nvmrc` reference in `.github/workflows/*.{yml,yaml}` and composite actions
(`.github/actions/**/action.{yml,yaml}`) is repointed to `.node-version` so
CI does not fail with "node version file ... does not exist".
under `.github` (`.github/**/action.{yml,yaml}`) is repointed to
`.node-version` so CI does not fail with "node version file ... does not
exist".

## Package-Manager Rules

Expand Down
126 changes: 125 additions & 1 deletion packages/cli/src/migration/__tests__/migrator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { parseAllDocuments, parse as parseYaml } from 'yaml';

import { rewriteScripts } from '../../../binding/index.js';
import { PackageManager } from '../../types/index.js';
import { VITE_PLUS_OVERRIDE_PACKAGES, VITEST_VERSION } from '../../utils/constants.js';
import {
SETUP_VP_VERSION,
VITE_PLUS_OVERRIDE_PACKAGES,
VITEST_VERSION,
} from '../../utils/constants.js';
import { createMigrationReport } from '../report.js';

// Mock VITE_PLUS_VERSION to a stable value for snapshot tests.
Expand Down Expand Up @@ -40,6 +44,7 @@ const {
parseNvmrcVersion,
detectNodeVersionManagerFile,
migrateNodeVersionManagerFile,
migrateSetupVpVersion,
detectFramework,
hasFrameworkShim,
addFrameworkShim,
Expand Down Expand Up @@ -1446,6 +1451,125 @@ describe('setPackageManager', () => {
});
});

describe('migrateSetupVpVersion', () => {
let tmpDir: string;

beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vp-test-setup-vp-'));
});

afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});

it('updates exact v1 references in workflows and composite actions', () => {
const workflowsDir = path.join(tmpDir, '.github', 'workflows');
const actionDir = path.join(tmpDir, '.github', 'actions', 'setup');
fs.mkdirSync(path.join(workflowsDir, 'nested'), { recursive: true });
fs.mkdirSync(actionDir, { recursive: true });

const workflowPath = path.join(workflowsDir, 'ci.yml');
fs.writeFileSync(
workflowPath,
[
'steps:',
' - uses: voidzero-dev/setup-vp@v1',
" - uses: 'voidzero-dev/setup-vp@v1' # keep this comment",
' - uses: "voidzero-dev/setup-vp@v1"',
' - uses: voidzero-dev/setup-vp@v1.16.1',
' - uses: voidzero-dev/setup-vp@v10',
' - uses: voidzero-dev/setup-vp@313600b',
' # - uses: voidzero-dev/setup-vp@v1',
'',
].join('\r\n'),
);
const actionPath = path.join(actionDir, 'action.yaml');
fs.writeFileSync(
actionPath,
'runs:\n using: composite\n steps:\n - uses : voidzero-dev/setup-vp@v1\n',
);
const nestedWorkflowPath = path.join(workflowsDir, 'nested', 'ignored.yml');
fs.writeFileSync(nestedWorkflowPath, '- uses: voidzero-dev/setup-vp@v1\n');
const report = createMigrationReport();

const updatedFiles = migrateSetupVpVersion(tmpDir, report).map((filePath) =>
filePath.split(path.sep).join('/'),
);

expect(updatedFiles).toHaveLength(2);
expect(updatedFiles).toEqual(
expect.arrayContaining(['.github/workflows/ci.yml', '.github/actions/setup/action.yaml']),
);
expect(fs.readFileSync(workflowPath, 'utf8')).toBe(
[
'steps:',
` - uses: voidzero-dev/setup-vp@${SETUP_VP_VERSION}`,
` - uses: 'voidzero-dev/setup-vp@${SETUP_VP_VERSION}' # keep this comment`,
` - uses: "voidzero-dev/setup-vp@${SETUP_VP_VERSION}"`,
' - uses: voidzero-dev/setup-vp@v1.16.1',
' - uses: voidzero-dev/setup-vp@v10',
' - uses: voidzero-dev/setup-vp@313600b',
' # - uses: voidzero-dev/setup-vp@v1',
'',
].join('\r\n'),
);
expect(fs.readFileSync(actionPath, 'utf8')).toContain(
`uses : voidzero-dev/setup-vp@${SETUP_VP_VERSION}`,
);
expect(fs.readFileSync(nestedWorkflowPath, 'utf8')).toContain('setup-vp@v1');
expect(report.setupVpVersionUpdatedFileCount).toBe(2);

expect(migrateSetupVpVersion(tmpDir, report)).toEqual([]);
expect(report.setupVpVersionUpdatedFileCount).toBe(2);
});

it('updates composite actions elsewhere under .github and stays within that directory', () => {
const actionPath = path.join(tmpDir, '.github', 'ci', 'actions', 'setup', 'action.yml');
const nonCompositePath = path.join(
tmpDir,
'.github',
'ci',
'actions',
'javascript',
'action.yml',
);
const outsideScopePath = path.join(tmpDir, 'ci', 'actions', 'outside-scope', 'action.yml');
const compositeAction =
'runs:\n using: composite\n steps:\n - uses: voidzero-dev/setup-vp@v1\n';
const nonCompositeAction = [
'inputs:',
' example:',
' description: Example workflow text',
' default: |',
' - uses: voidzero-dev/setup-vp@v1',
'runs:',
' using: node20',
' main: index.js',
'',
].join('\n');

fs.mkdirSync(path.dirname(actionPath), { recursive: true });
fs.mkdirSync(path.dirname(nonCompositePath), { recursive: true });
fs.mkdirSync(path.dirname(outsideScopePath), { recursive: true });
fs.writeFileSync(actionPath, compositeAction);
fs.writeFileSync(nonCompositePath, nonCompositeAction);
fs.writeFileSync(outsideScopePath, compositeAction);
const report = createMigrationReport();

const updatedFiles = migrateSetupVpVersion(tmpDir, report).map((filePath) =>
filePath.split(path.sep).join('/'),
);

expect(updatedFiles).toEqual(['.github/ci/actions/setup/action.yml']);
expect(fs.readFileSync(actionPath, 'utf8')).toContain(
`uses: voidzero-dev/setup-vp@${SETUP_VP_VERSION}`,
);
expect(fs.readFileSync(nonCompositePath, 'utf8')).toBe(nonCompositeAction);
expect(fs.readFileSync(outsideScopePath, 'utf8')).toBe(compositeAction);
expect(report.setupVpVersionUpdatedFileCount).toBe(1);
});
});

describe('detectNodeVersionManagerFile', () => {
let tmpDir: string;

Expand Down
18 changes: 17 additions & 1 deletion packages/cli/src/migration/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
type WorkspacePackage,
} from '../types/index.ts';
import { writeAgentInstructions } from '../utils/agent.ts';
import { isForceOverrideMode, VITE_PLUS_VERSION } from '../utils/constants.ts';
import { isForceOverrideMode, SETUP_VP_VERSION, VITE_PLUS_VERSION } from '../utils/constants.ts';
import { writeEditorConfigs } from '../utils/editor.ts';
import { renderCliDoc } from '../utils/help.ts';
import { hasVitePlusDependency, readNearestPackageJson } from '../utils/package.ts';
Expand Down Expand Up @@ -61,6 +61,7 @@ import {
migrateEslintToOxlint,
migrateNodeVersionManagerFile,
migratePrettierToOxfmt,
migrateSetupVpVersion,
migrateTsupToTsdown,
configureYarnNodeModulesMode,
rewriteMonorepo,
Expand Down Expand Up @@ -717,6 +718,13 @@ function showMigrationSummary(options: {
if (report.nodeVersionFileMigrated) {
log(`${styleText('gray', '•')} Node version manager file migrated to .node-version`);
}
const setupVpFileCount = report.setupVpVersionUpdatedFileCount;
if (setupVpFileCount > 0) {
const fileLabel = setupVpFileCount === 1 ? 'file' : 'files';
log(
`${styleText('gray', '•')} setup-vp updated to ${SETUP_VP_VERSION} in ${setupVpFileCount} GitHub Actions ${fileLabel}`,
);
}
if (report.wrappedPluginConfigCount > 0) {
log(
`${styleText('gray', '•')} Inline Vite plugins wrapped with lazyPlugins for check/lint/fmt`,
Expand Down Expand Up @@ -869,6 +877,9 @@ async function executeMigrationPlan(
migrateNodeVersionManagerFile(workspaceInfo.rootDir, plan.nodeVersionDetection, report);
}

updateMigrationProgress('Updating setup-vp workflows');
migrateSetupVpVersion(workspaceInfo.rootDir, report);

// 4. Run vp install to ensure the project is ready
updateMigrationProgress('Installing dependencies');
const initialInstallSummary = await runViteInstall(
Expand Down Expand Up @@ -1146,6 +1157,11 @@ async function main() {
}
};

updateMigrationProgress('Updating setup-vp workflows');
if (migrateSetupVpVersion(workspaceInfoOptional.rootDir, report).length > 0) {
didMigrate = true;
}

const pendingCoreMigration = detectPendingCoreMigration(workspaceInfoOptional);
const vitePlusBootstrapPending = detectVitePlusBootstrapPending(
workspaceInfoOptional.rootDir,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/migration/migrator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Pick the file by what a function _does_, not by where it happens to be called.
| `tsconfig.ts` | `tsconfig.json` cleanup and `types` rewriting. |
| `framework-shim.ts` | Framework (Vue/Astro) shim detection and injection. |
| `git-hooks.ts` | Vite+ hook defaults, project-owned hook preservation, and conservative detection of existing hook tools. |
| `setup.ts` | `packageManager` pin and Node version-manager file (`.nvmrc`/`.node-version`/Volta) migration. |
| `setup.ts` | `packageManager` pin, `setup-vp` GitHub Actions version, and Node version-manager file (`.nvmrc`/`.node-version`/Volta) migration. |
| `core-finalization.ts` | Finalizing an existing-Vite+ core migration (rules YAML, core package scripts). |
| `shared.ts` | Cross-cutting constants, types, and tiny utilities used by **two or more** modules. The only module that other modules import from directly (see rules). |

Expand Down
Loading
Loading