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
43 changes: 31 additions & 12 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,47 @@ jobs:
project:
- name: vibe-dashboard
node-version: 24
command: vite run ready
- name: skeleton
node-version: 22
command: |
pnpm run --filter="@skeletonlabs/*" --filter="!*skeleton.dev" --sequential build
pnpm test
pnpm playwright install --with-deps
# FIXME: Failed to load JS plugin: ./plugins/debugger.js
# vite run ready
vite fmt
vite test
vite run build
# FIXME: TypeError: Failed to fetch dynamically imported module
# - name: skeleton
# node-version: 24
# command: |
# vite run format
# vite run lint:check
# vite run check
# pnpm exec playwright install chromium
# vite run test
- name: rollipop
node-version: 22
skip-install: true
command: |
vite install --no-frozen-lockfile
vite run -r build
vite run lint
vite run -r typecheck
vite run format
vite run @rollipop/common#test
vite run @rollipop/core#test
vite run @rollipop/dev-server#test
- name: frm-stack
node-version: 24
command: |
vite run lint:check
vite run format:check
vite run typecheck
vite run @yourcompany/api#test
vite run @yourcompany/backend-core#test
- name: vue-mini
node-version: 24
command: |
vite run format
vite run lint
vite run type
vite run test -- --coverage

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Expand Down Expand Up @@ -116,11 +139,7 @@ jobs:
# avoid the vite migration using the wrong ignore file
rm -f ../.gitignore
node ../patch-project.ts ${{ matrix.project.name }}
if [ -n "${{ matrix.project.skip-install }}" ]; then
exit 0
fi
pnpm install --no-frozen-lockfile
pnpm playwright install --with-deps
vite install --no-frozen-lockfile

- name: Run vite-plus commands in ${{ matrix.project.name }}
working-directory: ecosystem-ci/${{ matrix.project.name }}
Expand Down
4 changes: 3 additions & 1 deletion ecosystem-ci/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
vibe-dashboard
skeleton
rollipop
rollipop
frm-stack
vue-mini
207 changes: 1 addition & 206 deletions ecosystem-ci/patch-project.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { execSync } from 'node:child_process';
import fs from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';

import vitestPackageJson from '../packages/test/package.json' with { type: 'json' };
import repos from './repo.json' with { type: 'json' };

const projectDir = dirname(fileURLToPath(import.meta.url));
Expand All @@ -19,196 +17,6 @@ if (!projects.includes(project)) {

const tgzPath = join(projectDir, '..', 'tmp', 'tgz');

async function patchVibeDashboard() {
const pnpmWorkspacePath = join(projectDir, 'vibe-dashboard', 'pnpm-workspace.yaml');
const pnpmWorkspaceFile = fs
.readFileSync(pnpmWorkspacePath, 'utf8')
.replace(
'"vite": "npm:@voidzero-dev/vite-plus-core"',
`"vite": "file:${tgzPath}/voidzero-dev-vite-plus-core-0.0.0.tgz"`,
)
.replace(
'"vitest": "npm:@voidzero-dev/vite-plus-test"',
`"vitest": "file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz"
"@vitest/browser": "file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz"
"@vitest/browser-playwright": "file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz"
"@voidzero-dev/vite-plus": "file:${tgzPath}/voidzero-dev-vite-plus-0.0.0.tgz"
"@voidzero-dev/vite-plus-core": "file:${tgzPath}/voidzero-dev-vite-plus-core-0.0.0.tgz"
"@voidzero-dev/vite-plus-test": "file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz"`,
);
fs.writeFileSync(pnpmWorkspacePath, pnpmWorkspaceFile);

// Remove @vitest/* packages from apps/dashboard/package.json
// These are bundled into our vitest package and shouldn't be installed separately
const dashboardPackageJsonPath = join(
projectDir,
'vibe-dashboard',
'apps',
'dashboard',
'package.json',
);
const dashboardPackageJson = JSON.parse(fs.readFileSync(dashboardPackageJsonPath, 'utf8'));
if (dashboardPackageJson.devDependencies) {
// Remove @vitest/browser, @vitest/ui, and @vitest/browser-playwright
// They're all bundled in our vitest package now
const vitestPackagesToRemove = ['@vitest/browser', '@vitest/ui', '@vitest/browser-playwright'];
for (const pkg of vitestPackagesToRemove) {
delete dashboardPackageJson.devDependencies[pkg];
}
}

// Note: @vitest/* packages are now bundled into our vitest package, so we don't need
// to add them as separate devDependencies anymore.

// Write the updated package.json
fs.writeFileSync(dashboardPackageJsonPath, JSON.stringify(dashboardPackageJson, null, 2) + '\n');

// Update vite.config.ts to import from vitest/browser-playwright instead of @vitest/browser-playwright
// This is needed because pnpm overrides don't affect Node.js module resolution at config load time
const viteConfigPath = join(projectDir, 'vibe-dashboard', 'apps', 'dashboard', 'vite.config.ts');
const viteConfigContent = fs
.readFileSync(viteConfigPath, 'utf8')
.replace('from "@vitest/browser-playwright"', 'from "vitest/browser-playwright"');
fs.writeFileSync(viteConfigPath, viteConfigContent);

// Add pnpm overrides to ensure @vitest/* packages are installed at matching versions
const vitestVersion = vitestPackageJson.devDependencies['@vitest/runner'];
const vitestOverrides = [
'@vitest/runner',
'@vitest/utils',
'@vitest/spy',
'@vitest/expect',
'@vitest/snapshot',
'@vitest/mocker',
'@vitest/pretty-format',
];

const pnpmWorkspaceContent = fs.readFileSync(pnpmWorkspacePath, 'utf8');
if (!pnpmWorkspaceContent.includes('"@vitest/runner":')) {
const overridesStr = vitestOverrides.map((pkg) => ` "${pkg}": "${vitestVersion}"`).join('\n');
const updatedContent = pnpmWorkspaceContent.replace(
/^overrides:\n/m,
`overrides:\n${overridesStr}\n`,
);
fs.writeFileSync(pnpmWorkspacePath, updatedContent);
}
}

async function patchSkeleton() {
const packageJsonPath = join(projectDir, 'skeleton', 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));

// Change test command from "vitest run" to "vite test"
packageJson.scripts.test = 'vite test';

// Add pnpm overrides with tgz files
// Include @vitest/browser and @vitest/browser-playwright to use bundled versions
packageJson.pnpm = packageJson.pnpm || {};
packageJson.pnpm.overrides = {
...packageJson.pnpm.overrides,
vite: `file:${tgzPath}/voidzero-dev-vite-plus-core-0.0.0.tgz`,
'rolldown-vite': `file:${tgzPath}/voidzero-dev-vite-plus-core-0.0.0.tgz`,
vitest: `file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz`,
'@vitest/browser': `file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz`,
'@vitest/browser-playwright': `file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz`,
'@voidzero-dev/vite-plus': `file:${tgzPath}/voidzero-dev-vite-plus-0.0.0.tgz`,
'@voidzero-dev/vite-plus-core': `file:${tgzPath}/voidzero-dev-vite-plus-core-0.0.0.tgz`,
'@voidzero-dev/vite-plus-test': `file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz`,
};

packageJson.devDependencies = {
...packageJson.devDependencies,
'@voidzero-dev/vite-plus': `latest`,
playwright: `catalog:`,
};

// Relax engine constraints to support broader node versions
if (packageJson.engines?.node) {
packageJson.engines.node = '>=22.0.0';
}

fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');

const vitestVersion = vitestPackageJson.devDependencies['@vitest/expect'];

// Patch pnpm-workspace.yaml
const pnpmWorkspacePath = join(projectDir, 'skeleton', 'pnpm-workspace.yaml');
let pnpmWorkspaceContent = fs
.readFileSync(pnpmWorkspacePath, 'utf8')
.replace(`trustPolicy: no-downgrade`, '\n')
.replace(
/'@vitest\/browser-playwright': [\d.]+/,
`'@vitest/browser-playwright': ${vitestVersion}`,
);

// Add entries to existing minimumReleaseAgeExclude if it exists, otherwise append new section
const newExcludes = ["'@voidzero-dev/*'", "'@vitest/*'", 'oxlint', 'oxfmt', 'oxlint-tsgolint'];
if (pnpmWorkspaceContent.includes('minimumReleaseAgeExclude:')) {
// Find the minimumReleaseAgeExclude section and add new entries
pnpmWorkspaceContent = pnpmWorkspaceContent.replace(
/minimumReleaseAgeExclude:\n((?: - .+\n)+)/,
(_, existingEntries) => {
const newEntriesStr = newExcludes.map((e) => ` - ${e}\n`).join('');
return `minimumReleaseAgeExclude:\n${existingEntries}${newEntriesStr}`;
},
);
} else {
pnpmWorkspaceContent += `\nminimumReleaseAgeExclude:\n${newExcludes.map((e) => ` - ${e}`).join('\n')}\n`;
}

// Add peerDependencyRules if not present
if (!pnpmWorkspaceContent.includes('peerDependencyRules:')) {
pnpmWorkspaceContent += `
peerDependencyRules:
allowAny:
- vite
- vitest
`;
}

fs.writeFileSync(pnpmWorkspacePath, pnpmWorkspaceContent);

// Update vite.config.ts files to import from vitest/browser-playwright instead of @vitest/browser-playwright
// This is needed because pnpm overrides don't affect Node.js module resolution at config load time
const skeletonReactConfigPath = join(
projectDir,
'skeleton',
'packages',
'skeleton-react',
'vite.config.ts',
);
const skeletonSvelteConfigPath = join(
projectDir,
'skeleton',
'packages',
'skeleton-svelte',
'vite.config.ts',
);

for (const configPath of [skeletonReactConfigPath, skeletonSvelteConfigPath]) {
const content = fs
.readFileSync(configPath, 'utf8')
// Handle both single and double quotes
.replace(/from ['"]@vitest\/browser-playwright['"]/, 'from "vitest/browser-playwright"');
fs.writeFileSync(configPath, content);
}

// Remove @vitest/browser-playwright from package devDependencies
// These are bundled in our vitest package now
const packagesToUpdate = [
join(projectDir, 'skeleton', 'packages', 'skeleton-react', 'package.json'),
join(projectDir, 'skeleton', 'packages', 'skeleton-svelte', 'package.json'),
];

for (const pkgPath of packagesToUpdate) {
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
if (pkg.devDependencies?.['@vitest/browser-playwright']) {
delete pkg.devDependencies['@vitest/browser-playwright'];
}
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, '\t') + '\n');
}
}

async function migrateProject(project: string) {
const repoRoot = join(projectDir, project);
// run vite migrate
Expand All @@ -228,17 +36,4 @@ async function migrateProject(project: string) {
});
}

switch (project) {
case 'vibe-dashboard':
await patchVibeDashboard();
break;
case 'skeleton':
await patchSkeleton();
break;
case 'rollipop':
await migrateProject(project);
break;
default:
console.error(`Project ${project} is not supported`);
process.exit(1);
}
await migrateProject(project);
14 changes: 12 additions & 2 deletions ecosystem-ci/repo.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,26 @@
"skeleton": {
"repository": "https://github.com/skeletonlabs/skeleton.git",
"branch": "main",
"hash": "6f613fe3326ed483885e4acc6f49e2044aa9ab79"
"hash": "6d57f29b823275c6e3fb267c6834da5d39558fb6"
},
"vibe-dashboard": {
"repository": "https://github.com/voidzero-dev/vibe-dashboard.git",
"branch": "main",
"hash": "30c68c9ad65c1315abf4c69366b21bc63b5d0fb4"
"hash": "f780e8769539feff8beb5e9bf44de6f5c5abad1c"
},
"rollipop": {
"repository": "https://github.com/leegeunhyeok/rollipop.git",
"branch": "main",
"hash": "9beb8dd8fb70ef298b3a18703a831d6d4d3c01a1"
},
"frm-stack": {
"repository": "https://github.com/Nikola-Milovic/frm-stack.git",
"branch": "main",
"hash": "e9e344125d8476ed6f34880036c0b1aef8dc0bb5"
},
"vue-mini": {
"repository": "https://github.com/vue-mini/vue-mini.git",
"branch": "master",
"hash": "c51332662993dde44f665822bdea94cd0abf368b"
}
}
30 changes: 24 additions & 6 deletions packages/global/src/migration/migrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,11 @@ function rewritePnpmWorkspaceYaml(projectPath: string): void {

// overrides
for (const key of Object.keys(VITE_PLUS_OVERRIDE_PACKAGES)) {
doc.setIn(['overrides', scalarString(key)], scalarString('catalog:'));
let version = VITE_PLUS_OVERRIDE_PACKAGES[key];
if (!version.startsWith('file:')) {
version = 'catalog:';
}
doc.setIn(['overrides', scalarString(key)], scalarString(version));
}
// remove dependency selector from vite, e.g. "vite-plugin-svgr>vite": "npm:rolldown-vite@7.0.12"
const overrides = doc.getIn(['overrides']) as YAMLMap<Scalar<string>, Scalar<string>>;
Expand Down Expand Up @@ -323,11 +327,21 @@ function rewriteYarnrcYml(projectPath: string): void {
*/
function rewriteCatalog(doc: YamlDocument): void {
for (const [key, value] of Object.entries(VITE_PLUS_OVERRIDE_PACKAGES)) {
// ERR_PNPM_CATALOG_IN_OVERRIDES  Could not resolve a catalog in the overrides: The entry for 'vite' in catalog 'default' declares a dependency using the 'file' protocol
// ignore setting catalog if value starts with 'file:'
if (value.startsWith('file:')) {
continue;
}
doc.setIn(['catalog', key], scalarString(value));
}
doc.setIn(['catalog', VITE_PLUS_NAME], scalarString(VITE_PLUS_VERSION));
if (!VITE_PLUS_VERSION.startsWith('file:')) {
doc.setIn(['catalog', VITE_PLUS_NAME], scalarString(VITE_PLUS_VERSION));
}
for (const name of REMOVE_PACKAGES) {
doc.deleteIn(['catalog', name]);
const path = ['catalog', name];
if (doc.hasIn(path)) {
doc.deleteIn(path);
}
}

// TODO: rewrite `catalogs` when OVERRIDE_PACKAGES exists in catalog
Expand Down Expand Up @@ -394,7 +408,10 @@ function rewriteRootWorkspacePackageJson(
if (!pkg.devDependencies?.[VITE_PLUS_NAME]) {
pkg.devDependencies = {
...pkg.devDependencies,
[VITE_PLUS_NAME]: packageManager === PackageManager.npm ? VITE_PLUS_VERSION : 'catalog:',
[VITE_PLUS_NAME]:
packageManager === PackageManager.npm || VITE_PLUS_VERSION.startsWith('file:')
? VITE_PLUS_VERSION
: 'catalog:',
};
}
return pkg;
Expand Down Expand Up @@ -437,7 +454,7 @@ export function rewritePackageJson(
const supportCatalog = isMonorepo && packageManager !== PackageManager.npm;
let needVitePlus = false;
for (const [key, version] of Object.entries(VITE_PLUS_OVERRIDE_PACKAGES)) {
const value = supportCatalog ? 'catalog:' : version;
const value = supportCatalog && !version.startsWith('file:') ? 'catalog:' : version;
if (pkg.devDependencies?.[key]) {
pkg.devDependencies[key] = value;
needVitePlus = true;
Expand All @@ -460,7 +477,8 @@ export function rewritePackageJson(
}
if (needVitePlus) {
// add vite-plus to devDependencies
const version = supportCatalog ? 'catalog:' : VITE_PLUS_VERSION;
const version =
supportCatalog && !VITE_PLUS_VERSION.startsWith('file:') ? 'catalog:' : VITE_PLUS_VERSION;
pkg.devDependencies = {
...pkg.devDependencies,
[VITE_PLUS_NAME]: version,
Expand Down
Loading