Skip to content

Commit 1badbc5

Browse files
committed
ci: add vibe-dashboard to e2e test
1 parent b9624d4 commit 1badbc5

8 files changed

Lines changed: 303 additions & 2 deletions

File tree

.github/actions/clone/action.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
name: 'Clone Repositories'
22
description: 'Clone self and upstream repositories'
3+
4+
inputs:
5+
ecosystem-ci-project:
6+
description: 'The ecosystem ci project to clone'
7+
required: false
8+
default: ''
9+
310
runs:
411
using: 'composite'
512
steps:
@@ -10,6 +17,14 @@ runs:
1017
node -e "console.log('ROLLDOWN_HASH=' + require('./packages/tools/.upstream-versions.json').rolldown.hash)" >> $GITHUB_OUTPUT
1118
node -e "console.log('ROLLDOWN_VITE_HASH=' + require('./packages/tools/.upstream-versions.json')['rolldown-vite'].hash)" >> $GITHUB_OUTPUT
1219
20+
- name: Output ecosystem ci project hash
21+
shell: bash
22+
id: ecosystem-ci-project-hash
23+
if: ${{ inputs.ecosystem-ci-project != '' }}
24+
run: |
25+
node -e "console.log('ECOSYSTEM_CI_PROJECT_HASH=' + require('./ecosystem-ci/repo.json')['${{ inputs.ecosystem-ci-project }}'].hash)" >> $GITHUB_OUTPUT
26+
node -e "console.log('ECOSYSTEM_CI_PROJECT_REPOSITORY=' + require('./ecosystem-ci/repo.json')['${{ inputs.ecosystem-ci-project }}'].repository.replace('https://github.com/', '').replace('.git', ''))" >> $GITHUB_OUTPUT
27+
1328
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
1429
with:
1530
repository: rolldown/rolldown
@@ -21,3 +36,10 @@ runs:
2136
repository: vitejs/rolldown-vite
2237
path: rolldown-vite
2338
ref: ${{ steps.upstream-versions.outputs.ROLLDOWN_VITE_HASH }}
39+
40+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
41+
if: ${{ inputs.ecosystem-ci-project != '' }}
42+
with:
43+
repository: ${{ steps.ecosystem-ci-project-hash.outputs.ECOSYSTEM_CI_PROJECT_REPOSITORY }}
44+
path: ecosystem-ci/${{ inputs.ecosystem-ci-project }}
45+
ref: ${{ steps.ecosystem-ci-project-hash.outputs.ECOSYSTEM_CI_PROJECT_HASH }}

.github/workflows/ci.yml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,79 @@ jobs:
218218
RUST_BACKTRACE=1 pnpm --filter=@voidzero-dev/vite-plus test && pnpm -r snap-test
219219
git diff --exit-code
220220
221+
e2e-test:
222+
name: ${{ matrix.project.name }} E2E test
223+
needs:
224+
- download-previous-rolldown-binaries
225+
runs-on: ubuntu-latest
226+
strategy:
227+
fail-fast: false
228+
matrix:
229+
project:
230+
- name: vibe-dashboard
231+
node-version: 24
232+
command: vite run ready
233+
- name: skeleton
234+
node-version: 22
235+
command: |
236+
pnpm run --filter="@skeletonlabs/*" --sequential build
237+
pnpm test
238+
if: ${{ github.ref_name == 'main' }}
239+
steps:
240+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
241+
- uses: ./.github/actions/clone
242+
with:
243+
ecosystem-ci-project: ${{ matrix.project.name }}
244+
245+
- name: Configure Git for access to vite-task
246+
run: git config --global url."https://x-access-token:${{ secrets.VITE_TASK_TOKEN }}@github.com/".insteadOf "https://github.com/"
247+
248+
- uses: oxc-project/setup-rust@d286d43bc1f606abbd98096666ff8be68c8d5f57 # v1.0.0
249+
with:
250+
save-cache: ${{ github.ref_name == 'main' }}
251+
cache-key: e2e-test
252+
253+
- uses: oxc-project/setup-node@fdbf0dfd334c4e6d56ceeb77d91c76339c2a0885 # v1.0.4
254+
255+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
256+
with:
257+
name: rolldown-binaries
258+
path: ./rolldown/packages/rolldown/src
259+
merge-multiple: true
260+
261+
- name: Build with upstream
262+
uses: ./.github/actions/build-upstream
263+
with:
264+
target: x86_64-unknown-linux-gnu
265+
266+
- name: Build all packages
267+
run: pnpm bootstrap-cli:ci
268+
269+
- name: Pack packages into tgz
270+
run: |
271+
mkdir -p tmp/tgz
272+
cd packages/core && pnpm pack --pack-destination ../../tmp/tgz && cd ../..
273+
cd packages/test && pnpm pack --pack-destination ../../tmp/tgz && cd ../..
274+
cd packages/cli && pnpm pack --pack-destination ../../tmp/tgz && cd ../..
275+
cd packages/global && pnpm pack --pack-destination ../../tmp/tgz && cd ../..
276+
ls -la tmp/tgz
277+
278+
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
279+
with:
280+
node-version: ${{ matrix.project.node-version }}
281+
package-manager-cache: false
282+
283+
- name: Install vite-plus from tgz in ${{ matrix.project.name }}
284+
working-directory: ecosystem-ci/${{ matrix.project.name }}
285+
run: |
286+
node ../patch-project.ts ${{ matrix.project.name }}
287+
pnpm install --no-frozen-lockfile
288+
pnpm playwright install --with-deps
289+
290+
- name: Run vite-plus commands in ${{ matrix.project.name }}
291+
working-directory: ecosystem-ci/${{ matrix.project.name }}
292+
run: ${{ matrix.project.command }}
293+
221294
install-e2e-test:
222295
name: vite install E2E test
223296
# FIXME: Error: spawnSync esbuild ENOTSOCK

.oxfmtrc.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
{
22
"$schema": "./node_modules/oxfmt/configuration_schema.json",
33
"ignorePatterns": [
4-
"packages/cli/binding/index.d.ts",
5-
"packages/cli/binding/index.js"
4+
"tmp/**",
5+
"ecosystem-ci/outline/**",
6+
"ecosystem-ci/vibe-dashboard/**"
67
],
78
"singleQuote": true,
89
"experimentalSortImports": {

ecosystem-ci/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
vibe-dashboard
2+
skeleton

ecosystem-ci/clone.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { execSync } from 'node:child_process';
2+
import { existsSync } from 'node:fs';
3+
import { join } from 'node:path';
4+
5+
import repos from './repo.json' with { type: 'json' };
6+
7+
const cwd = import.meta.dirname;
8+
9+
function exec(cmd: string, execCwd: string = cwd): string {
10+
return execSync(cmd, { cwd: execCwd, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
11+
}
12+
13+
function getRemoteUrl(dir: string): string | null {
14+
try {
15+
return exec('git remote get-url origin', dir);
16+
} catch {
17+
return null;
18+
}
19+
}
20+
21+
function normalizeGitUrl(url: string): string {
22+
// Convert git@github.com:owner/repo.git to github.com/owner/repo
23+
// Convert https://github.com/owner/repo.git to github.com/owner/repo
24+
return url
25+
.replace(/^git@([^:]+):/, '$1/')
26+
.replace(/^https?:\/\//, '')
27+
.replace(/\.git$/, '');
28+
}
29+
30+
function isSameRepo(url1: string, url2: string): boolean {
31+
return normalizeGitUrl(url1) === normalizeGitUrl(url2);
32+
}
33+
34+
function getCurrentHash(dir: string): string | null {
35+
try {
36+
return exec('git rev-parse HEAD', dir);
37+
} catch {
38+
return null;
39+
}
40+
}
41+
42+
function cloneRepo(repoUrl: string, branch: string, targetDir: string): void {
43+
console.info(`Cloning ${repoUrl} (branch: ${branch})...`);
44+
exec(`git clone --branch ${branch} ${repoUrl} ${targetDir}`);
45+
}
46+
47+
function checkoutHash(dir: string, hash: string): void {
48+
console.info(`Checking out ${hash}...`);
49+
exec(`git fetch origin`, dir);
50+
exec(`git checkout ${hash}`, dir);
51+
}
52+
53+
for (const [repoName, repo] of Object.entries(repos)) {
54+
const targetDir = join(cwd, repoName);
55+
56+
if (existsSync(targetDir)) {
57+
console.info(`\nDirectory ${repoName} exists, validating...`);
58+
59+
const remoteUrl = getRemoteUrl(targetDir);
60+
if (!remoteUrl) {
61+
console.error(` ✗ ${repoName} is not a git repository`);
62+
continue;
63+
}
64+
65+
if (!isSameRepo(remoteUrl, repo.repository)) {
66+
console.error(` ✗ Remote mismatch: expected ${repo.repository}, got ${remoteUrl}`);
67+
continue;
68+
}
69+
70+
console.info(` ✓ Remote matches`);
71+
72+
const currentHash = getCurrentHash(targetDir);
73+
if (currentHash === repo.hash) {
74+
console.info(` ✓ Already at correct commit ${repo.hash.slice(0, 7)}`);
75+
} else {
76+
console.info(` → Current: ${currentHash?.slice(0, 7)}, expected: ${repo.hash.slice(0, 7)}`);
77+
checkoutHash(targetDir, repo.hash);
78+
console.info(` ✓ Checked out ${repo.hash.slice(0, 7)}`);
79+
}
80+
} else {
81+
cloneRepo(repo.repository, repo.branch, targetDir);
82+
checkoutHash(targetDir, repo.hash);
83+
console.info(`✓ Cloned and checked out ${repo.hash.slice(0, 7)}`);
84+
}
85+
}
86+
87+
console.info('\nDone!');

ecosystem-ci/patch-project.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import fs from 'node:fs';
2+
import { dirname, join } from 'node:path';
3+
import { fileURLToPath } from 'node:url';
4+
5+
import vitestPackageJson from '../packages/test/package.json' with { type: 'json' };
6+
import repos from './repo.json' with { type: 'json' };
7+
8+
const projectDir = dirname(fileURLToPath(import.meta.url));
9+
10+
const projects = Object.keys(repos);
11+
12+
const project = process.argv[2];
13+
14+
if (!projects.includes(project)) {
15+
console.error(`Project ${project} is not defined in repo.json`);
16+
process.exit(1);
17+
}
18+
19+
const tgzPath = join(projectDir, '..', 'tmp', 'tgz');
20+
21+
async function patchVibeDashboard() {
22+
const pnpmWorkspacePath = join(projectDir, 'vibe-dashboard', 'pnpm-workspace.yaml');
23+
const pnpmWorkspaceFile = fs
24+
.readFileSync(pnpmWorkspacePath, 'utf8')
25+
.replace(
26+
'"vite": "npm:@voidzero-dev/vite-plus-core"',
27+
`"vite": "file:${tgzPath}/voidzero-dev-vite-plus-core-0.0.0.tgz"`,
28+
)
29+
.replace(
30+
'"vitest": "npm:@voidzero-dev/vite-plus-test"',
31+
`"vitest": "file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz"
32+
"@voidzero-dev/vite-plus": "file:${tgzPath}/voidzero-dev-vite-plus-0.0.0.tgz"
33+
"@voidzero-dev/vite-plus-core": "file:${tgzPath}/voidzero-dev-vite-plus-core-0.0.0.tgz"
34+
"@voidzero-dev/vite-plus-test": "file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz"`,
35+
);
36+
fs.writeFileSync(pnpmWorkspacePath, pnpmWorkspaceFile);
37+
}
38+
39+
async function patchSkeleton() {
40+
const packageJsonPath = join(projectDir, 'skeleton', 'package.json');
41+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
42+
43+
// Change test command from "vitest run" to "vite test"
44+
packageJson.scripts.test = 'vite test';
45+
46+
// Add pnpm overrides with tgz files
47+
packageJson.pnpm = packageJson.pnpm || {};
48+
packageJson.pnpm.overrides = {
49+
...packageJson.pnpm.overrides,
50+
vite: `file:${tgzPath}/voidzero-dev-vite-plus-core-0.0.0.tgz`,
51+
'rolldown-vite': `file:${tgzPath}/voidzero-dev-vite-plus-core-0.0.0.tgz`,
52+
vitest: `file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz`,
53+
'@voidzero-dev/vite-plus': `file:${tgzPath}/voidzero-dev-vite-plus-0.0.0.tgz`,
54+
'@voidzero-dev/vite-plus-core': `file:${tgzPath}/voidzero-dev-vite-plus-core-0.0.0.tgz`,
55+
'@voidzero-dev/vite-plus-test': `file:${tgzPath}/voidzero-dev-vite-plus-test-0.0.0.tgz`,
56+
};
57+
58+
packageJson.devDependencies = {
59+
...packageJson.devDependencies,
60+
'@voidzero-dev/vite-plus': `latest`,
61+
playwright: `catalog:`,
62+
};
63+
64+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
65+
66+
const vitestVersion = vitestPackageJson.dependencies['@vitest/expect'];
67+
68+
// Patch pnpm-workspace.yaml
69+
const pnpmWorkspacePath = join(projectDir, 'skeleton', 'pnpm-workspace.yaml');
70+
const pnpmWorkspaceContent = fs
71+
.readFileSync(pnpmWorkspacePath, 'utf8')
72+
.replace(`trustPolicy: no-downgrade`, '\n')
73+
.replace(
74+
/'@vitest\/browser-playwright': [\d.]+/,
75+
`'@vitest/browser-playwright': ${vitestVersion}`,
76+
);
77+
const appendContent = `
78+
minimumReleaseAgeExclude:
79+
- '@voidzero-dev/*'
80+
- '@vitest/*'
81+
- oxlint
82+
- oxfmt
83+
- oxlint-tsgolint
84+
85+
peerDependencyRules:
86+
allowAny:
87+
- vite
88+
- vitest
89+
`;
90+
fs.writeFileSync(pnpmWorkspacePath, pnpmWorkspaceContent + appendContent);
91+
}
92+
93+
switch (project) {
94+
case 'vibe-dashboard':
95+
await patchVibeDashboard();
96+
break;
97+
case 'skeleton':
98+
await patchSkeleton();
99+
break;
100+
default:
101+
console.error(`Project ${project} is not supported`);
102+
process.exit(1);
103+
}

ecosystem-ci/repo.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"skeleton": {
3+
"repository": "https://github.com/skeletonlabs/skeleton.git",
4+
"branch": "main",
5+
"hash": "1d59e077dbf28d1931405864b06f06f9d3578903"
6+
},
7+
"vibe-dashboard": {
8+
"repository": "https://github.com/voidzero-dev/vibe-dashboard.git",
9+
"branch": "main",
10+
"hash": "30c68c9ad65c1315abf4c69366b21bc63b5d0fb4"
11+
}
12+
}

tmp/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tgz

0 commit comments

Comments
 (0)