From 587371006e460aa0660d5761f98ed9f1b30e4eb5 Mon Sep 17 00:00:00 2001 From: Afonso Jorge Ramos Date: Wed, 2 Sep 2026 23:53:53 +0200 Subject: [PATCH 1/5] feat(tools): add Vite+ installer --- .github/renovate.json | 2 + docs/custom-registries.md | 14 ++++ src/cli/install-tool/index.ts | 2 + src/cli/tools/index.ts | 1 + src/cli/tools/vp.spec.ts | 142 ++++++++++++++++++++++++++++++++++ src/cli/tools/vp.ts | 77 ++++++++++++++++++ 6 files changed, 238 insertions(+) create mode 100644 src/cli/tools/vp.spec.ts create mode 100644 src/cli/tools/vp.ts diff --git a/.github/renovate.json b/.github/renovate.json index 512eb455ad..7cf9a94565 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -105,6 +105,7 @@ "tofu", "uv", "vendir", + "vp", "wally", "yarn" ], @@ -160,6 +161,7 @@ "tofu", "uv", "vendir", + "vp", "wally", "yarn" ], diff --git a/docs/custom-registries.md b/docs/custom-registries.md index d915a42ad4..6990f3aaa4 100644 --- a/docs/custom-registries.md +++ b/docs/custom-registries.md @@ -776,6 +776,20 @@ Samples: https://github.com/vmware-tanzu/carvel-vendir/releases/download/v0.22.0/vendir-linux-amd64 ``` +## `vp` + +Vite+ releases are downloaded from: + +- `https://github.com/voidzero-dev/vite-plus/releases` + +Release archives and their checksum manifest follow these paths: + +```txt +https://github.com/voidzero-dev/vite-plus/releases/download/v/vp-x86_64-unknown-linux-gnu.tar.gz +https://github.com/voidzero-dev/vite-plus/releases/download/v/vp-aarch64-unknown-linux-gnu.tar.gz +https://github.com/voidzero-dev/vite-plus/releases/download/v/vp-checksums.txt +``` + ## `wally` Wally releases are downloaded from: diff --git a/src/cli/install-tool/index.ts b/src/cli/install-tool/index.ts index 80ea5d39b7..1b7d1ce338 100644 --- a/src/cli/install-tool/index.ts +++ b/src/cli/install-tool/index.ts @@ -111,6 +111,7 @@ import { SwiftInstallService } from '../tools/swift.ts'; import { TerraformInstallService } from '../tools/terraform.ts'; import { TofuInstallService } from '../tools/tofu.ts'; import { VendirInstallService } from '../tools/vendir.ts'; +import { VpInstallService } from '../tools/vp.ts'; import { WallyInstallService } from '../tools/wally.ts'; import { type InstallToolType, logger } from '../utils/index.ts'; import { isNotKnownV2Tool } from '../utils/v2-tool.ts'; @@ -192,6 +193,7 @@ async function prepareInstallContainer(): Promise { container.bind(INSTALL_TOOL_TOKEN).to(TerraformInstallService); container.bind(INSTALL_TOOL_TOKEN).to(TofuInstallService); container.bind(INSTALL_TOOL_TOKEN).to(VendirInstallService); + container.bind(INSTALL_TOOL_TOKEN).to(VpInstallService); container.bind(INSTALL_TOOL_TOKEN).to(WallyInstallService); container.bind(INSTALL_TOOL_TOKEN).to(YarnInstallService); container.bind(INSTALL_TOOL_TOKEN).to(YarnSlimInstallService); diff --git a/src/cli/tools/index.ts b/src/cli/tools/index.ts index 7e0b817fc6..4f481aa858 100644 --- a/src/cli/tools/index.ts +++ b/src/cli/tools/index.ts @@ -51,6 +51,7 @@ export const NoPrepareTools = [ 'tofu', 'uv', 'vendir', + 'vp', 'wally', 'yarn', 'yarn-slim', diff --git a/src/cli/tools/vp.spec.ts b/src/cli/tools/vp.spec.ts new file mode 100644 index 0000000000..f5289bd817 --- /dev/null +++ b/src/cli/tools/vp.spec.ts @@ -0,0 +1,142 @@ +import fs from 'node:fs/promises'; +import { arch } from 'node:os'; +import { join } from 'node:path'; +import type { Container } from 'inversify'; +import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'; + +import { + CompressionService, + HttpService, + LinkToolService, +} from '../services/index.ts'; +import { + VP_SYNC_VERSIONS_UNAVAILABLE, + VpInstallService, + parseVitePlusChecksum, + vitePlusAssetName, +} from './vp.ts'; +import { testContainer } from '~test/di.ts'; +import { ensurePaths } from '~test/path.ts'; + +vi.mock('execa'); + +describe('cli/tools/vp', () => { + describe('release assets', () => { + test.each([ + ['amd64', 'vp-x86_64-unknown-linux-gnu.tar.gz'], + ['arm64', 'vp-aarch64-unknown-linux-gnu.tar.gz'], + ] as const)('maps %s to the official release asset', (arch, expected) => { + expect(vitePlusAssetName(arch)).toBe(expected); + }); + + test('selects an exact release asset checksum', () => { + expect( + parseVitePlusChecksum( + [ + 'a'.repeat(64) + ' vp-aarch64-unknown-linux-gnu.tar.gz', + 'b'.repeat(64) + ' vp-x86_64-unknown-linux-gnu.tar.gz', + '', + ].join('\n'), + 'vp-x86_64-unknown-linux-gnu.tar.gz', + ), + ).toBe('b'.repeat(64)); + }); + + test('rejects missing or malformed checksums', () => { + expect(() => + parseVitePlusChecksum('', 'vp-x86_64-unknown-linux-gnu.tar.gz'), + ).toThrow('Cannot find checksum'); + expect(() => + parseVitePlusChecksum( + 'not-a-checksum vp-x86_64-unknown-linux-gnu.tar.gz', + 'vp-x86_64-unknown-linux-gnu.tar.gz', + ), + ).toThrow('Cannot find checksum'); + }); + }); + + describe('VpInstallService', () => { + let child: Container; + let service: VpInstallService; + + beforeAll(async () => { + await ensurePaths([ + 'opt/containerbase/bin', + 'opt/containerbase/tools', + 'tmp/containerbase', + 'var/lib/containerbase', + ]); + }); + + beforeEach(async () => { + child = await testContainer(); + child.bind(HttpService).toSelf(); + child.bind(CompressionService).toSelf(); + child.bind(LinkToolService).toSelf(); + child.bind(VpInstallService).toSelf(); + service = await child.getAsync(VpInstallService); + }); + + test('downloads, verifies, and extracts the exact prebuilt release', async () => { + const filename = vitePlusAssetName( + arch() === 'arm64' ? 'arm64' : 'amd64', + ); + const checksum = 'c'.repeat(64); + const checksumFile = join(globalThis.cacheDir, 'vp-checksums.txt'); + const archiveFile = join(globalThis.cacheDir, filename); + await fs.writeFile(checksumFile, `${checksum} ${filename}\n`); + await fs.writeFile(archiveFile, 'archive'); + + const download = vi + .spyOn(HttpService.prototype, 'download') + .mockResolvedValueOnce(checksumFile) + .mockResolvedValueOnce(archiveFile); + vi.spyOn(HttpService.prototype, 'exists').mockResolvedValueOnce(true); + const extract = vi + .spyOn(CompressionService.prototype, 'extract') + .mockResolvedValueOnce(); + + await service.install('0.4.0'); + + expect(download).toHaveBeenNthCalledWith(1, { + url: 'https://github.com/voidzero-dev/vite-plus/releases/download/v0.4.0/vp-checksums.txt', + }); + expect(download).toHaveBeenNthCalledWith(2, { + url: `https://github.com/voidzero-dev/vite-plus/releases/download/v0.4.0/${filename}`, + checksumType: 'sha256', + expectedChecksum: checksum, + }); + expect(extract).toHaveBeenCalledWith({ + file: archiveFile, + cwd: expect.stringMatching(/\/vp\/0\.4\.0\/bin$/), + }); + }); + + test('rejects releases that predate the bundled planner', async () => { + vi.spyOn(HttpService.prototype, 'exists').mockResolvedValueOnce(false); + const download = vi.spyOn(HttpService.prototype, 'download'); + + await expect(service.install('0.3.0')).rejects.toThrow( + `${VP_SYNC_VERSIONS_UNAVAILABLE}:0.3.0`, + ); + expect(download).not.toHaveBeenCalled(); + }); + + test('links vp with the Node runtime needed by the bundled planner', async () => { + const shellwrapper = vi + .spyOn(LinkToolService.prototype, 'shellwrapper') + .mockResolvedValueOnce(); + + await service.link('0.4.0'); + + expect(shellwrapper).toHaveBeenCalledWith('vp', { + srcDir: expect.stringMatching(/\/vp\/0\.4\.0\/bin$/), + extraToolEnvs: ['node'], + }); + }); + + test('checks the installed vp version', async () => { + await expect(service.test('0.4.0')).resolves.toBeUndefined(); + }); + }); +}); diff --git a/src/cli/tools/vp.ts b/src/cli/tools/vp.ts new file mode 100644 index 0000000000..9e48ad4dfa --- /dev/null +++ b/src/cli/tools/vp.ts @@ -0,0 +1,77 @@ +import fs from 'node:fs/promises'; +import { join } from 'node:path'; +import { injectFromHierarchy, injectable } from 'inversify'; +import { BaseInstallService } from '../install-tool/base-install.service.ts'; +import type { Arch } from '../utils/index.ts'; + +// Stable machine-readable marker consumed by Renovate. Do not reword it. +export const VP_SYNC_VERSIONS_UNAVAILABLE = + 'CONTAINERBASE_VP_SYNC_VERSIONS_UNAVAILABLE'; + +export function vitePlusAssetName(arch: Arch): string { + const target = arch === 'arm64' ? 'aarch64' : 'x86_64'; + return `vp-${target}-unknown-linux-gnu.tar.gz`; +} + +export function parseVitePlusChecksum( + checksums: string, + filename: string, +): string { + for (const line of checksums.split('\n')) { + const match = /^([a-f\d]{64})\s+\*?(.+)$/i.exec(line.trim()); + const checksum = match?.[1]; + if (checksum && match?.[2] === filename) { + return checksum.toLowerCase(); + } + } + throw new Error(`Cannot find checksum for '${filename}' in vp-checksums.txt`); +} + +@injectable() +@injectFromHierarchy() +export class VpInstallService extends BaseInstallService { + readonly name = 'vp'; + override readonly parent = 'node'; + + override async install(version: string): Promise { + const baseUrl = `https://github.com/voidzero-dev/vite-plus/releases/download/v${version}/`; + const filename = vitePlusAssetName(this.envSvc.arch); + const checksumUrl = `${baseUrl}vp-checksums.txt`; + + if (!(await this.http.exists(checksumUrl))) { + throw new Error( + `${VP_SYNC_VERSIONS_UNAVAILABLE}:${version}: Vite+ release does not provide the sync-versions planner`, + ); + } + + const checksumFile = await this.http.download({ + url: checksumUrl, + }); + const expectedChecksum = parseVitePlusChecksum( + await fs.readFile(checksumFile, 'utf8'), + filename, + ); + const file = await this.http.download({ + url: `${baseUrl}${filename}`, + checksumType: 'sha256', + expectedChecksum, + }); + + await this.pathSvc.ensureToolPath(this.name); + const path = join( + await this.pathSvc.createVersionedToolPath(this.name, version), + 'bin', + ); + await fs.mkdir(path); + await this.compress.extract({ file, cwd: path }); + } + + override async link(version: string): Promise { + const src = join(this.pathSvc.versionedToolPath(this.name, version), 'bin'); + await this.shellwrapper({ srcDir: src, extraToolEnvs: ['node'] }); + } + + override async test(_version: string): Promise { + await this._spawn(this.name, ['--version']); + } +} From f34cf9500e944d3457a31d4391f90f76fb74e475 Mon Sep 17 00:00:00 2001 From: Afonso Jorge Ramos Date: Sun, 13 Sep 2026 01:07:15 +0200 Subject: [PATCH 2/5] test(vp): validate released planner in Docker Exercise Vite+ 0.3.1 installation and dependency alignment on both Linux architectures and in the distro test matrix. Check repeat execution and verify that project manifests and configuration remain unchanged. --- test/Dockerfile.distro | 7 +++ test/latest/Dockerfile | 20 +++++++++ test/latest/Dockerfile.arm64 | 20 +++++++++ test/vp/sync-versions.mjs | 86 ++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 test/vp/sync-versions.mjs diff --git a/test/Dockerfile.distro b/test/Dockerfile.distro index adb343fda5..582a70f113 100644 --- a/test/Dockerfile.distro +++ b/test/Dockerfile.distro @@ -211,6 +211,13 @@ RUN install-tool pnpm 10.34.5 # renovate: datasource=npm packageName=@yarnpkg/cli-dist RUN install-tool yarn 4.18.0 +# renovate: datasource=github-releases depName=vp packageName=voidzero-dev/vite-plus +ARG VP_VERSION=0.3.1 +RUN install-tool vp "${VP_VERSION}" + +COPY test/vp/sync-versions.mjs /test/vp-sync-versions.mjs +RUN node /test/vp-sync-versions.mjs "${VP_VERSION}" + #-------------------------------------- # Image: test-php #-------------------------------------- diff --git a/test/latest/Dockerfile b/test/latest/Dockerfile index 9fb66e00ef..80f122454e 100644 --- a/test/latest/Dockerfile +++ b/test/latest/Dockerfile @@ -386,6 +386,25 @@ RUN install-tool nuget 7.6.0 RUN nuget search nuget.commandline -Take 1 +#-------------------------------------- +# Image: vp +#-------------------------------------- +FROM base AS test-vp + +# renovate: datasource=github-releases packageName=containerbase/node-prebuild versioning=node +RUN install-tool node 24.19.0 + +# renovate: datasource=github-releases depName=vp packageName=voidzero-dev/vite-plus +ARG VP_VERSION=0.3.1 +RUN install-tool vp "${VP_VERSION}" + +COPY test/vp/sync-versions.mjs /test/vp-sync-versions.mjs + +USER 12021 +SHELL ["/bin/sh", "-c"] + +RUN node /test/vp-sync-versions.mjs "${VP_VERSION}" + #-------------------------------------- # final #-------------------------------------- @@ -399,3 +418,4 @@ COPY --link --from=teste /.dummy /.dummy COPY --link --from=testf /.dummy /.dummy COPY --link --from=test-docker /.dummy /.dummy COPY --link --from=test-mono /.dummy /.dummy +COPY --link --from=test-vp /.dummy /.dummy diff --git a/test/latest/Dockerfile.arm64 b/test/latest/Dockerfile.arm64 index 0b8bb9d972..5abd8a3301 100644 --- a/test/latest/Dockerfile.arm64 +++ b/test/latest/Dockerfile.arm64 @@ -213,6 +213,25 @@ RUN install-tool protoc 35.1 # renovate: datasource=github-releases packageName=prefix-dev/pixi RUN install-tool pixi v0.76.2 +#-------------------------------------- +# Image: vp +#-------------------------------------- +FROM base AS test-vp + +# renovate: datasource=github-releases packageName=containerbase/node-prebuild versioning=node +RUN install-tool node 24.19.0 + +# renovate: datasource=github-releases depName=vp packageName=voidzero-dev/vite-plus +ARG VP_VERSION=0.3.1 +RUN install-tool vp "${VP_VERSION}" + +COPY test/vp/sync-versions.mjs /test/vp-sync-versions.mjs + +USER 12021 +SHELL ["/bin/sh", "-c"] + +RUN node /test/vp-sync-versions.mjs "${VP_VERSION}" + #-------------------------------------- # Image: final #-------------------------------------- @@ -235,5 +254,6 @@ COPY --from=test-mono /.dummy /.dummy COPY --from=test-terraform /.dummy /.dummy COPY --from=test-tofu /.dummy /.dummy COPY --from=test-vendir /.dummy /.dummy +COPY --from=test-vp /.dummy /.dummy COPY --from=test-others /.dummy /.dummy diff --git a/test/vp/sync-versions.mjs b/test/vp/sync-versions.mjs new file mode 100644 index 0000000000..f0d9f2f0f7 --- /dev/null +++ b/test/vp/sync-versions.mjs @@ -0,0 +1,86 @@ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +const version = process.argv[2]; +assert.ok(version, 'Expected the installed Vite+ version'); + +const cwd = mkdtempSync(join(tmpdir(), 'containerbase-vp-')); +const manifest = { + name: 'vp-install-test', + private: true, + scripts: { postinstall: 'exit 91' }, + devDependencies: { + 'vite-plus': '0.0.0', + vite: 'npm:@voidzero-dev/vite-plus-core@0.0.0', + vitest: '0.0.0', + '@vitest/coverage-v8': '0.0.0', + typescript: '5.8.0', + }, +}; +const contents = JSON.stringify(manifest, null, 2) + '\n'; +const config = 'throw new Error("Project configuration must not be loaded");\n'; + +function plan(manifestContents) { + return JSON.parse( + execFileSync(process.env.VP_TEST_BIN ?? 'vp', ['sync-versions', '--json'], { + cwd, + encoding: 'utf8', + input: JSON.stringify({ + schemaVersion: 1, + workspace: '.', + manifests: [ + { + path: 'package.json', + kind: 'packageJson', + contents: manifestContents, + }, + ], + }), + }), + ); +} + +try { + writeFileSync(join(cwd, 'package.json'), contents); + writeFileSync(join(cwd, 'vite.config.mjs'), config); + + const result = plan(contents); + assert.equal(result.schemaVersion, 1); + assert.deepEqual(result.tool, { name: 'vite-plus', version }); + assert.equal(result.workspace, '.'); + assert.equal(result.replacements.length, 1); + + const replacement = result.replacements[0]; + assert.equal(replacement.path, 'package.json'); + assert.equal(replacement.kind, 'packageJson'); + assert.equal(replacement.before, contents); + + const updated = JSON.parse(replacement.after); + const vitestVersion = updated.devDependencies.vitest; + assert.match(vitestVersion, /^\d+\.\d+\.\d+/); + assert.notEqual(vitestVersion, '0.0.0'); + assert.deepEqual(updated, { + ...manifest, + devDependencies: { + ...manifest.devDependencies, + 'vite-plus': version, + vite: `npm:@voidzero-dev/vite-plus-core@${version}`, + vitest: vitestVersion, + '@vitest/coverage-v8': vitestVersion, + }, + }); + + assert.deepEqual(plan(replacement.after), { + schemaVersion: 1, + tool: { name: 'vite-plus', version }, + workspace: '.', + replacements: [], + }); + assert.equal(readFileSync(join(cwd, 'package.json'), 'utf8'), contents); + assert.equal(readFileSync(join(cwd, 'vite.config.mjs'), 'utf8'), config); +} finally { + rmSync(cwd, { recursive: true, force: true }); +} From 6d5d561c98ad520bf0b6095d9f49f98726ae58ab Mon Sep 17 00:00:00 2001 From: Afonso Jorge Ramos Date: Mon, 14 Sep 2026 13:06:51 +0200 Subject: [PATCH 3/5] refactor(vp): align installer and tests with Node tooling Group Vite+ with its Node parent and keep planner smoke tests in the Node images. Use released download examples and assert the actual version-check command. --- docs/custom-registries.md | 8 ++++---- src/cli/install-tool/index.ts | 2 +- src/cli/tools/{ => node}/vp.spec.ts | 13 ++++++++++--- src/cli/tools/{ => node}/vp.ts | 4 ++-- test/Dockerfile.distro | 3 --- test/latest/Dockerfile | 20 -------------------- test/latest/Dockerfile.arm64 | 20 -------------------- test/node/Dockerfile | 19 +++++++++++++++++++ test/node/Dockerfile.arm64 | 17 +++++++++++++++++ test/{ => node}/vp/sync-versions.mjs | 0 10 files changed, 53 insertions(+), 53 deletions(-) rename src/cli/tools/{ => node}/vp.spec.ts (94%) rename src/cli/tools/{ => node}/vp.ts (94%) rename test/{ => node}/vp/sync-versions.mjs (100%) diff --git a/docs/custom-registries.md b/docs/custom-registries.md index 6990f3aaa4..2b2f7983c5 100644 --- a/docs/custom-registries.md +++ b/docs/custom-registries.md @@ -782,12 +782,12 @@ Vite+ releases are downloaded from: - `https://github.com/voidzero-dev/vite-plus/releases` -Release archives and their checksum manifest follow these paths: +Samples: ```txt -https://github.com/voidzero-dev/vite-plus/releases/download/v/vp-x86_64-unknown-linux-gnu.tar.gz -https://github.com/voidzero-dev/vite-plus/releases/download/v/vp-aarch64-unknown-linux-gnu.tar.gz -https://github.com/voidzero-dev/vite-plus/releases/download/v/vp-checksums.txt +https://github.com/voidzero-dev/vite-plus/releases/download/v0.3.1/vp-x86_64-unknown-linux-gnu.tar.gz +https://github.com/voidzero-dev/vite-plus/releases/download/v0.3.1/vp-aarch64-unknown-linux-gnu.tar.gz +https://github.com/voidzero-dev/vite-plus/releases/download/v0.3.1/vp-checksums.txt ``` ## `wally` diff --git a/src/cli/install-tool/index.ts b/src/cli/install-tool/index.ts index 1b7d1ce338..efd7710ee6 100644 --- a/src/cli/install-tool/index.ts +++ b/src/cli/install-tool/index.ts @@ -80,6 +80,7 @@ import { YarnVersionResolver, } from '../tools/node/resolver.ts'; import { NpmBaseInstallService } from '../tools/node/utils.ts'; +import { VpInstallService } from '../tools/node/vp.ts'; import { ComposerInstallService, ComposerVersionResolver, @@ -111,7 +112,6 @@ import { SwiftInstallService } from '../tools/swift.ts'; import { TerraformInstallService } from '../tools/terraform.ts'; import { TofuInstallService } from '../tools/tofu.ts'; import { VendirInstallService } from '../tools/vendir.ts'; -import { VpInstallService } from '../tools/vp.ts'; import { WallyInstallService } from '../tools/wally.ts'; import { type InstallToolType, logger } from '../utils/index.ts'; import { isNotKnownV2Tool } from '../utils/v2-tool.ts'; diff --git a/src/cli/tools/vp.spec.ts b/src/cli/tools/node/vp.spec.ts similarity index 94% rename from src/cli/tools/vp.spec.ts rename to src/cli/tools/node/vp.spec.ts index f5289bd817..ab0f1c4912 100644 --- a/src/cli/tools/vp.spec.ts +++ b/src/cli/tools/node/vp.spec.ts @@ -1,6 +1,7 @@ import fs from 'node:fs/promises'; import { arch } from 'node:os'; import { join } from 'node:path'; +import { execa } from 'execa'; import type { Container } from 'inversify'; import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'; @@ -8,7 +9,7 @@ import { CompressionService, HttpService, LinkToolService, -} from '../services/index.ts'; +} from '../../services/index.ts'; import { VP_SYNC_VERSIONS_UNAVAILABLE, VpInstallService, @@ -20,7 +21,7 @@ import { ensurePaths } from '~test/path.ts'; vi.mock('execa'); -describe('cli/tools/vp', () => { +describe('cli/tools/node/vp', () => { describe('release assets', () => { test.each([ ['amd64', 'vp-x86_64-unknown-linux-gnu.tar.gz'], @@ -136,7 +137,13 @@ describe('cli/tools/vp', () => { }); test('checks the installed vp version', async () => { - await expect(service.test('0.4.0')).resolves.toBeUndefined(); + await service.test('0.4.0'); + + expect(execa).toHaveBeenCalledExactlyOnceWith( + 'vp', + ['--version'], + expect.any(Object), + ); }); }); }); diff --git a/src/cli/tools/vp.ts b/src/cli/tools/node/vp.ts similarity index 94% rename from src/cli/tools/vp.ts rename to src/cli/tools/node/vp.ts index 9e48ad4dfa..b0d401e761 100644 --- a/src/cli/tools/vp.ts +++ b/src/cli/tools/node/vp.ts @@ -1,8 +1,8 @@ import fs from 'node:fs/promises'; import { join } from 'node:path'; import { injectFromHierarchy, injectable } from 'inversify'; -import { BaseInstallService } from '../install-tool/base-install.service.ts'; -import type { Arch } from '../utils/index.ts'; +import { BaseInstallService } from '../../install-tool/base-install.service.ts'; +import type { Arch } from '../../utils/index.ts'; // Stable machine-readable marker consumed by Renovate. Do not reword it. export const VP_SYNC_VERSIONS_UNAVAILABLE = diff --git a/test/Dockerfile.distro b/test/Dockerfile.distro index 582a70f113..49e785107c 100644 --- a/test/Dockerfile.distro +++ b/test/Dockerfile.distro @@ -215,9 +215,6 @@ RUN install-tool yarn 4.18.0 ARG VP_VERSION=0.3.1 RUN install-tool vp "${VP_VERSION}" -COPY test/vp/sync-versions.mjs /test/vp-sync-versions.mjs -RUN node /test/vp-sync-versions.mjs "${VP_VERSION}" - #-------------------------------------- # Image: test-php #-------------------------------------- diff --git a/test/latest/Dockerfile b/test/latest/Dockerfile index 80f122454e..9fb66e00ef 100644 --- a/test/latest/Dockerfile +++ b/test/latest/Dockerfile @@ -386,25 +386,6 @@ RUN install-tool nuget 7.6.0 RUN nuget search nuget.commandline -Take 1 -#-------------------------------------- -# Image: vp -#-------------------------------------- -FROM base AS test-vp - -# renovate: datasource=github-releases packageName=containerbase/node-prebuild versioning=node -RUN install-tool node 24.19.0 - -# renovate: datasource=github-releases depName=vp packageName=voidzero-dev/vite-plus -ARG VP_VERSION=0.3.1 -RUN install-tool vp "${VP_VERSION}" - -COPY test/vp/sync-versions.mjs /test/vp-sync-versions.mjs - -USER 12021 -SHELL ["/bin/sh", "-c"] - -RUN node /test/vp-sync-versions.mjs "${VP_VERSION}" - #-------------------------------------- # final #-------------------------------------- @@ -418,4 +399,3 @@ COPY --link --from=teste /.dummy /.dummy COPY --link --from=testf /.dummy /.dummy COPY --link --from=test-docker /.dummy /.dummy COPY --link --from=test-mono /.dummy /.dummy -COPY --link --from=test-vp /.dummy /.dummy diff --git a/test/latest/Dockerfile.arm64 b/test/latest/Dockerfile.arm64 index 5abd8a3301..0b8bb9d972 100644 --- a/test/latest/Dockerfile.arm64 +++ b/test/latest/Dockerfile.arm64 @@ -213,25 +213,6 @@ RUN install-tool protoc 35.1 # renovate: datasource=github-releases packageName=prefix-dev/pixi RUN install-tool pixi v0.76.2 -#-------------------------------------- -# Image: vp -#-------------------------------------- -FROM base AS test-vp - -# renovate: datasource=github-releases packageName=containerbase/node-prebuild versioning=node -RUN install-tool node 24.19.0 - -# renovate: datasource=github-releases depName=vp packageName=voidzero-dev/vite-plus -ARG VP_VERSION=0.3.1 -RUN install-tool vp "${VP_VERSION}" - -COPY test/vp/sync-versions.mjs /test/vp-sync-versions.mjs - -USER 12021 -SHELL ["/bin/sh", "-c"] - -RUN node /test/vp-sync-versions.mjs "${VP_VERSION}" - #-------------------------------------- # Image: final #-------------------------------------- @@ -254,6 +235,5 @@ COPY --from=test-mono /.dummy /.dummy COPY --from=test-terraform /.dummy /.dummy COPY --from=test-tofu /.dummy /.dummy COPY --from=test-vendir /.dummy /.dummy -COPY --from=test-vp /.dummy /.dummy COPY --from=test-others /.dummy /.dummy diff --git a/test/node/Dockerfile b/test/node/Dockerfile index 9ec8e24091..2aa2e26403 100644 --- a/test/node/Dockerfile +++ b/test/node/Dockerfile @@ -568,6 +568,24 @@ RUN set -ex; \ if [ -n "$(ls -A /usr/local/bin/)" ]; then echo "tools not uninstalled" >&2; exit 1; fi;\ true +#-------------------------------------- +# test: vp +#-------------------------------------- +FROM build AS test-vp + +USER root + +# renovate: datasource=github-releases depName=vp packageName=voidzero-dev/vite-plus +ARG VP_VERSION=0.3.1 +RUN install-tool vp "${VP_VERSION}" + +COPY test/node/vp/sync-versions.mjs /test/vp-sync-versions.mjs + +USER 12021 +SHELL ["/bin/sh", "-c"] + +RUN node /test/vp-sync-versions.mjs "${VP_VERSION}" + #-------------------------------------- # final #-------------------------------------- @@ -589,6 +607,7 @@ COPY --from=testn /.dummy /.dummy COPY --from=testo /.dummy /.dummy COPY --from=testp /.dummy /.dummy COPY --from=testq /.dummy /.dummy +COPY --from=test-vp /.dummy /.dummy COPY --from=test-v20 /.dummy /.dummy COPY --from=test-v22 /.dummy /.dummy diff --git a/test/node/Dockerfile.arm64 b/test/node/Dockerfile.arm64 index 1c656c5942..c632ecc3de 100644 --- a/test/node/Dockerfile.arm64 +++ b/test/node/Dockerfile.arm64 @@ -69,6 +69,22 @@ RUN install-tool renovate 44.17.1 # # renovate: datasource=npm # RUN npm install -g re2@1.20.9 +#-------------------------------------- +# Image: vp +#-------------------------------------- +FROM test-node AS test-vp + +# renovate: datasource=github-releases depName=vp packageName=voidzero-dev/vite-plus +ARG VP_VERSION=0.3.1 +RUN install-tool vp "${VP_VERSION}" + +COPY test/node/vp/sync-versions.mjs /test/vp-sync-versions.mjs + +USER 12021 +SHELL ["/bin/sh", "-c"] + +RUN node /test/vp-sync-versions.mjs "${VP_VERSION}" + #-------------------------------------- # Image: final #-------------------------------------- @@ -78,3 +94,4 @@ COPY --from=test-node /.dummy /.dummy COPY --from=test-pnpm /.dummy /.dummy COPY --from=test-yarn /.dummy /.dummy COPY --from=test-renovate /.dummy /.dummy +COPY --from=test-vp /.dummy /.dummy diff --git a/test/vp/sync-versions.mjs b/test/node/vp/sync-versions.mjs similarity index 100% rename from test/vp/sync-versions.mjs rename to test/node/vp/sync-versions.mjs From 80a118d5c7fb01f0b07dbd8f872633362dd69fff Mon Sep 17 00:00:00 2001 From: Afonso Jorge Ramos Date: Mon, 21 Sep 2026 17:06:51 +0200 Subject: [PATCH 4/5] test(vp): use async I/O for planner checks Address review feedback on #7338 with promises and execa. Bundle the fixture with the existing locked dependencies for both Node test images, and simplify the distro check to a direct versioned install. --- .dockerignore | 1 + package.json | 1 + test/Dockerfile.distro | 5 ++--- test/node/Dockerfile | 2 +- test/node/Dockerfile.arm64 | 2 +- test/node/vp/sync-versions.mjs | 31 +++++++++++++++++-------------- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/.dockerignore b/.dockerignore index d01839e765..c6d22dad49 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,3 +2,4 @@ !test !dist/docker !dist/cli +!dist/test diff --git a/package.json b/package.json index 439ed953b6..0ffb12f65c 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "bats": "node tools/bats.js --timing --verbose-run", "build": "run-s 'build:*'", "build:cli": "node tools/build.js", + "build:test": "rolldown test/node/vp/sync-versions.mjs --platform node --format esm --file dist/test/vp-sync-versions.mjs", "eslint": "eslint --cache .", "eslint-fix": "eslint --cache --fix .", "lint": "run-s prettier eslint lint:types lint:markdown", diff --git a/test/Dockerfile.distro b/test/Dockerfile.distro index 4dfb20c1b8..9e069f582b 100644 --- a/test/Dockerfile.distro +++ b/test/Dockerfile.distro @@ -211,9 +211,8 @@ RUN install-tool pnpm 10.34.5 # renovate: datasource=npm packageName=@yarnpkg/cli-dist RUN install-tool yarn 4.18.0 -# renovate: datasource=github-releases depName=vp packageName=voidzero-dev/vite-plus -ARG VP_VERSION=0.3.1 -RUN install-tool vp "${VP_VERSION}" +# renovate: datasource=github-releases packageName=voidzero-dev/vite-plus +RUN install-tool vp 0.3.1 #-------------------------------------- # Image: test-php diff --git a/test/node/Dockerfile b/test/node/Dockerfile index ff7773d366..1cac43745d 100644 --- a/test/node/Dockerfile +++ b/test/node/Dockerfile @@ -586,7 +586,7 @@ USER root ARG VP_VERSION=0.3.1 RUN install-tool vp "${VP_VERSION}" -COPY test/node/vp/sync-versions.mjs /test/vp-sync-versions.mjs +COPY dist/test/vp-sync-versions.mjs /test/vp-sync-versions.mjs USER 12021 SHELL ["/bin/sh", "-c"] diff --git a/test/node/Dockerfile.arm64 b/test/node/Dockerfile.arm64 index b5313d99c2..b5cf0f383a 100644 --- a/test/node/Dockerfile.arm64 +++ b/test/node/Dockerfile.arm64 @@ -85,7 +85,7 @@ FROM test-node AS test-vp ARG VP_VERSION=0.3.1 RUN install-tool vp "${VP_VERSION}" -COPY test/node/vp/sync-versions.mjs /test/vp-sync-versions.mjs +COPY dist/test/vp-sync-versions.mjs /test/vp-sync-versions.mjs USER 12021 SHELL ["/bin/sh", "-c"] diff --git a/test/node/vp/sync-versions.mjs b/test/node/vp/sync-versions.mjs index f0d9f2f0f7..db8c6a756f 100644 --- a/test/node/vp/sync-versions.mjs +++ b/test/node/vp/sync-versions.mjs @@ -1,13 +1,13 @@ import assert from 'node:assert/strict'; -import { execFileSync } from 'node:child_process'; -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; +import { execa } from 'execa'; const version = process.argv[2]; assert.ok(version, 'Expected the installed Vite+ version'); -const cwd = mkdtempSync(join(tmpdir(), 'containerbase-vp-')); +const cwd = await mkdtemp(join(tmpdir(), 'containerbase-vp-')); const manifest = { name: 'vp-install-test', private: true, @@ -23,9 +23,11 @@ const manifest = { const contents = JSON.stringify(manifest, null, 2) + '\n'; const config = 'throw new Error("Project configuration must not be loaded");\n'; -function plan(manifestContents) { - return JSON.parse( - execFileSync(process.env.VP_TEST_BIN ?? 'vp', ['sync-versions', '--json'], { +async function plan(manifestContents) { + const { stdout } = await execa( + process.env.VP_TEST_BIN ?? 'vp', + ['sync-versions', '--json'], + { cwd, encoding: 'utf8', input: JSON.stringify({ @@ -39,15 +41,16 @@ function plan(manifestContents) { }, ], }), - }), + }, ); + return JSON.parse(stdout); } try { - writeFileSync(join(cwd, 'package.json'), contents); - writeFileSync(join(cwd, 'vite.config.mjs'), config); + await writeFile(join(cwd, 'package.json'), contents); + await writeFile(join(cwd, 'vite.config.mjs'), config); - const result = plan(contents); + const result = await plan(contents); assert.equal(result.schemaVersion, 1); assert.deepEqual(result.tool, { name: 'vite-plus', version }); assert.equal(result.workspace, '.'); @@ -73,14 +76,14 @@ try { }, }); - assert.deepEqual(plan(replacement.after), { + assert.deepEqual(await plan(replacement.after), { schemaVersion: 1, tool: { name: 'vite-plus', version }, workspace: '.', replacements: [], }); - assert.equal(readFileSync(join(cwd, 'package.json'), 'utf8'), contents); - assert.equal(readFileSync(join(cwd, 'vite.config.mjs'), 'utf8'), config); + assert.equal(await readFile(join(cwd, 'package.json'), 'utf8'), contents); + assert.equal(await readFile(join(cwd, 'vite.config.mjs'), 'utf8'), config); } finally { - rmSync(cwd, { recursive: true, force: true }); + await rm(cwd, { recursive: true, force: true }); } From 0eb244572bc24cf03e3f7d1798a48bfa0a9d0d96 Mon Sep 17 00:00:00 2001 From: Afonso Jorge Ramos Date: Mon, 21 Sep 2026 17:59:16 +0200 Subject: [PATCH 5/5] chore: undo rolldown change --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 0ffb12f65c..439ed953b6 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "bats": "node tools/bats.js --timing --verbose-run", "build": "run-s 'build:*'", "build:cli": "node tools/build.js", - "build:test": "rolldown test/node/vp/sync-versions.mjs --platform node --format esm --file dist/test/vp-sync-versions.mjs", "eslint": "eslint --cache .", "eslint-fix": "eslint --cache --fix .", "lint": "run-s prettier eslint lint:types lint:markdown",