Skip to content
Merged
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
12 changes: 9 additions & 3 deletions .claude/skills/add-ecosystem-ci/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ gh api repos/OWNER/REPO/commits/BRANCH --jq '.sha'

Fetch the repository's root to check if the main package.json is in a subdirectory (like `web/`, `app/`, `frontend/`).

### 2.2 Auto-detect Commands from GitHub Workflows
### 2.2 Check if Project Already Uses Vite-Plus

Check the project's root `package.json` for `vite-plus` in `dependencies` or `devDependencies`. If the project already uses vite-plus, set `forceFreshMigration: true` in `repo.json`. This tells `patch-project.ts` to set `VITE_PLUS_FORCE_MIGRATE=1` so `vp migrate` forces full dependency rewriting instead of skipping with "already using Vite+".

### 2.3 Auto-detect Commands from GitHub Workflows

Fetch the project's GitHub workflow files to detect available commands:

Expand All @@ -43,7 +47,7 @@ Look for common patterns in workflow files:
- Commands like: `lint`, `build`, `test`, `type-check`, `typecheck`, `format`, `format:check`
- Map detected commands to `vp` equivalents: `vp run lint`, `vp run build`, etc.

### 2.3 Ask User to Confirm
### 2.4 Ask User to Confirm

Present the auto-detected configuration and ask user to confirm or modify:

Expand All @@ -62,7 +66,8 @@ Present the auto-detected configuration and ask user to confirm or modify:
"repository": "https://github.com/owner/repo.git",
"branch": "main",
"hash": "full-commit-sha",
"directory": "web" // only if subdirectory is needed
"directory": "web", // only if subdirectory is needed
"forceFreshMigration": true // only if project already uses vite-plus
}
}
```
Expand Down Expand Up @@ -110,4 +115,5 @@ node ecosystem-ci/clone.ts project-name
- The `directory` field is optional - only add it if the package.json is not in the project root
- If `directory` is specified in repo.json, it must also be specified in the workflow matrix
- `patch-project.ts` automatically handles running `vp migrate` in the correct directory
- `forceFreshMigration` is required for projects that already have `vite-plus` in their package.json — it sets `VITE_PLUS_FORCE_MIGRATE=1` so `vp migrate` forces full dependency rewriting instead of skipping
- OS exclusions are added to the existing `exclude` section in the workflow matrix
16 changes: 16 additions & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,13 @@ jobs:
vp check
vp pack
vp test
- name: vinext
node-version: 24
command: |
vp run build
vp check --fix
vp run check
vp run test
exclude:
# frm-stack uses Docker (testcontainers) which doesn't work the same way on Windows
- os: windows-latest
Expand All @@ -266,6 +273,10 @@ jobs:
- os: windows-latest
project:
name: dify
# vinext uses workerd native deps that don't build on Windows
- os: windows-latest
project:
name: vinext

steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
Expand Down Expand Up @@ -310,6 +321,11 @@ jobs:
node $GITHUB_WORKSPACE/ecosystem-ci/patch-project.ts ${{ matrix.project.name }}
vp install --no-frozen-lockfile

- name: Verify local tgz packages installed
working-directory: ${{ runner.temp }}/vite-plus-ecosystem-ci/${{ matrix.project.name }}${{ matrix.project.directory && format('/{0}', matrix.project.directory) || '' }}
shell: bash
run: node $GITHUB_WORKSPACE/ecosystem-ci/verify-install.ts

- name: Run vite-plus commands in ${{ matrix.project.name }}
working-directory: ${{ runner.temp }}/vite-plus-ecosystem-ci/${{ matrix.project.name }}${{ matrix.project.directory && format('/{0}', matrix.project.directory) || '' }}
run: ${{ matrix.project.command }}
Expand Down
17 changes: 5 additions & 12 deletions ecosystem-ci/patch-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,6 @@ const cwd = directory ? join(repoRoot, directory) : repoRoot;
// run vp migrate
const cli = process.env.VITE_PLUS_CLI_BIN ?? 'vp';

// Projects that already have vite-plus need it removed before migration so
// vp migrate treats them as fresh and applies tgz overrides. Without this,
// vp migrate detects "already using Vite+" and skips override injection.
const forceFreshMigration = 'forceFreshMigration' in repoConfig && repoConfig.forceFreshMigration;
if (forceFreshMigration) {
const pkgPath = join(cwd, 'package.json');
const pkg = JSON.parse(await readFile(pkgPath, 'utf-8'));
delete pkg.devDependencies?.['vite-plus'];
delete pkg.dependencies?.['vite-plus'];
await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
}

if (project === 'rollipop') {
const oxfmtrc = await readFile(join(repoRoot, '.oxfmtrc.json'), 'utf-8');
await writeFile(
Expand All @@ -42,11 +30,16 @@ if (project === 'rollipop') {
);
}

// Projects that already use vite-plus need VITE_PLUS_FORCE_MIGRATE=1 so
// vp migrate runs full dependency rewriting instead of skipping.
const forceFreshMigration = 'forceFreshMigration' in repoConfig && repoConfig.forceFreshMigration;

execSync(`${cli} migrate --no-agent --no-interactive`, {
cwd,
stdio: 'inherit',
env: {
...process.env,
...(forceFreshMigration ? { VITE_PLUS_FORCE_MIGRATE: '1' } : {}),
VITE_PLUS_OVERRIDE_PACKAGES: JSON.stringify({
vite: `file:${tgzDir}/voidzero-dev-vite-plus-core-0.0.0.tgz`,
vitest: `file:${tgzDir}/voidzero-dev-vite-plus-test-0.0.0.tgz`,
Expand Down
12 changes: 10 additions & 2 deletions ecosystem-ci/repo.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"vibe-dashboard": {
"repository": "https://github.com/voidzero-dev/vibe-dashboard.git",
"branch": "main",
"hash": "fcb0518e75e0f05e09ac910dcc88090220dfd3ae"
"hash": "158e4a0c3d8a1801e330300a5deba4506fd5dfb9",
"forceFreshMigration": true
},
"rollipop": {
"repository": "https://github.com/leegeunhyeok/rollipop.git",
Expand Down Expand Up @@ -64,6 +65,13 @@
"vp-config": {
"repository": "https://github.com/kazupon/vp-config.git",
"branch": "main",
"hash": "b58c48d71a17c25dec71a003535e6312791ce2aa"
"hash": "b58c48d71a17c25dec71a003535e6312791ce2aa",
"forceFreshMigration": true
},
"vinext": {
"repository": "https://github.com/cloudflare/vinext.git",
"branch": "main",
"hash": "f78dd2b39f5b02242417e0a684b1f2f55d3dbdff",
"forceFreshMigration": true
}
}
17 changes: 17 additions & 0 deletions ecosystem-ci/verify-install.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { createRequire } from 'node:module';

const require = createRequire(`${process.cwd()}/`);

const expectedVersion = '0.0.0';

try {
const pkg = require('vite-plus/package.json') as { version: string; name: string };
if (pkg.version !== expectedVersion) {
console.error(`✗ vite-plus: expected version ${expectedVersion}, got ${pkg.version}`);
process.exit(1);
}
console.log(`✓ vite-plus@${pkg.version}`);
} catch {
console.error('✗ vite-plus: not installed');
process.exit(1);
}
4 changes: 3 additions & 1 deletion packages/cli/src/migration/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
selectAgentTargetPaths,
writeAgentInstructions,
} from '../utils/agent.js';
import { isForceOverrideMode } from '../utils/constants.js';
import {
detectEditorConflicts,
type EditorId,
Expand Down Expand Up @@ -747,8 +748,9 @@ async function main() {
const resolvedPackageManager = workspaceInfoOptional.packageManager ?? 'unknown';

// Early return if already using Vite+ (only ESLint/hooks migration may be needed)
// In force-override mode (file: tgz overrides), skip this check and run full migration
const rootPkg = readNearestPackageJson<PackageDependencies>(workspaceInfoOptional.rootDir);
if (hasVitePlusDependency(rootPkg)) {
if (hasVitePlusDependency(rootPkg) && !isForceOverrideMode()) {
let didMigrate = false;
let installDurationMs = 0;
const report = createMigrationReport();
Expand Down
35 changes: 25 additions & 10 deletions packages/cli/src/migration/migrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
VITE_PLUS_NAME,
VITE_PLUS_OVERRIDE_PACKAGES,
VITE_PLUS_VERSION,
isForceOverrideMode,
} from '../utils/constants.js';
import { editJsonFile, isJsonFile, readJsonFile } from '../utils/json.js';
import { detectPackageMetadata } from '../utils/package.js';
Expand Down Expand Up @@ -982,16 +983,30 @@ function rewriteRootWorkspacePackageJson(
...VITE_PLUS_OVERRIDE_PACKAGES,
};
} else if (packageManager === PackageManager.pnpm) {
// pnpm use overrides field at pnpm-workspace.yaml
// so we don't need to set overrides field at package.json
// remove packages from `resolutions` field and `pnpm.overrides` field if they exist
// https://pnpm.io/9.x/package_json#resolutions
for (const key of [...Object.keys(VITE_PLUS_OVERRIDE_PACKAGES), ...REMOVE_PACKAGES]) {
if (pkg.pnpm?.overrides?.[key]) {
delete pkg.pnpm.overrides[key];
}
if (pkg.resolutions?.[key]) {
delete pkg.resolutions[key];
if (isForceOverrideMode()) {
// In force-override mode, keep overrides in package.json pnpm.overrides
// because pnpm ignores pnpm-workspace.yaml overrides when pnpm.overrides
// exists in package.json (even with unrelated entries like rollup).
pkg.pnpm = {
...pkg.pnpm,
overrides: {
...pkg.pnpm?.overrides,
...VITE_PLUS_OVERRIDE_PACKAGES,
[VITE_PLUS_NAME]: VITE_PLUS_VERSION,
},
};
} else {
// pnpm use overrides field at pnpm-workspace.yaml
// so we don't need to set overrides field at package.json
// remove packages from `resolutions` field and `pnpm.overrides` field if they exist
// https://pnpm.io/9.x/package_json#resolutions
for (const key of [...Object.keys(VITE_PLUS_OVERRIDE_PACKAGES), ...REMOVE_PACKAGES]) {
if (pkg.pnpm?.overrides?.[key]) {
delete pkg.pnpm.overrides[key];
}
if (pkg.resolutions?.[key]) {
delete pkg.resolutions[key];
}
}
}
// remove dependency selector from vite, e.g. "vite-plugin-svgr>vite": "npm:vite@7.0.12"
Expand Down
9 changes: 9 additions & 0 deletions packages/cli/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ export const VITE_PLUS_OVERRIDE_PACKAGES: Record<string, string> = process.env
vitest: 'npm:@voidzero-dev/vite-plus-test@latest',
};

/**
* When VITE_PLUS_FORCE_MIGRATE is set, force full dependency rewriting
* even for projects already using vite-plus. Used by ecosystem CI to
* override dependencies with locally built tgz packages.
*/
export function isForceOverrideMode(): boolean {
return process.env.VITE_PLUS_FORCE_MIGRATE === '1';
}

const require = createRequire(import.meta.url);

export function resolve(path: string) {
Expand Down
Loading