-
Notifications
You must be signed in to change notification settings - Fork 64
feat(tools): install Vite+ releases #7338
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5873710
f34cf95
6d5d561
b808d01
80a118d
0eb2445
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,3 +2,4 @@ | |
| !test | ||
| !dist/docker | ||
| !dist/cli | ||
| !dist/test | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -51,6 +51,7 @@ export const NoPrepareTools = [ | |
| 'tofu', | ||
| 'uv', | ||
| 'vendir', | ||
| 'vp', | ||
| 'wally', | ||
| 'yarn', | ||
| 'yarn-slim', | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| 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'; | ||
|
|
||
| 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/node/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 service.test('0.4.0'); | ||
|
|
||
| expect(execa).toHaveBeenCalledExactlyOnceWith( | ||
| 'vp', | ||
| ['--version'], | ||
| expect.any(Object), | ||
| ); | ||
| }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<void> { | ||
| 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<void> { | ||
| const src = join(this.pathSvc.versionedToolPath(this.name, version), 'bin'); | ||
| await this.shellwrapper({ srcDir: src, extraToolEnvs: ['node'] }); | ||
| } | ||
|
|
||
| override async test(_version: string): Promise<void> { | ||
| await this._spawn(this.name, ['--version']); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -575,6 +575,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 dist/test/vp-sync-versions.mjs /test/vp-sync-versions.mjs | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| USER 12021 | ||
| SHELL ["/bin/sh", "-c"] | ||
|
|
||
| RUN node /test/vp-sync-versions.mjs "${VP_VERSION}" | ||
|
|
||
| #-------------------------------------- | ||
| # final | ||
| #-------------------------------------- | ||
|
|
@@ -596,6 +614,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 | ||
Uh oh!
There was an error while loading. Please reload this page.