From a402daeebed2b98f5ca4e6aecce7b308e985acd9 Mon Sep 17 00:00:00 2001 From: XingYu-Zhong <1736101137@qq.com> Date: Fri, 31 Jul 2026 10:27:53 +0800 Subject: [PATCH] fix(release): extract Windows TUI ZIPs with Node --- .github/workflows/pr-checks.yml | 24 ++++++++++- scripts/smoke-standalone-tui.mjs | 21 +++++++++- scripts/smoke-standalone-tui.test.mjs | 57 +++++++++++++++++++++------ 3 files changed, 86 insertions(+), 16 deletions(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index ccc6a4670..b28f82578 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -340,7 +340,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: ${{ env.NODE_VERSION }} + node-version: '22.23.1' cache: npm cache-dependency-path: | package-lock.json @@ -371,6 +371,28 @@ jobs: - name: Check Extension public release gate (host-native Windows) run: npm run check:extension-release-gate + - name: Build and smoke standalone TUI (host-native Windows) + shell: pwsh + run: | + $version = node -p "require('./kun/package.json').version" + $env:KUN_APP_VERSION = $version + $env:KUN_ARTIFACT_VERSION = $version + $env:KUN_UPDATE_CHANNEL = 'stable' + $env:RELEASE_CHANNEL = 'stable' + npm run build:kun + npm run package:tui -- ` + --version $version ` + --artifact-version $version ` + --tag "v$version" ` + --channel stable ` + --commit $env:GITHUB_SHA ` + --target win32-x64 ` + --output dist/tui-pr + npm run smoke:standalone-tui -- ` + --artifact "dist/tui-pr/Kun-TUI-$version-win-x64.zip" ` + --version $version ` + --target win32-x64 + - name: Build Windows NSIS installer run: npm run dist:win diff --git a/scripts/smoke-standalone-tui.mjs b/scripts/smoke-standalone-tui.mjs index 9b06ccabb..7447b5ce2 100644 --- a/scripts/smoke-standalone-tui.mjs +++ b/scripts/smoke-standalone-tui.mjs @@ -6,13 +6,22 @@ import { mkdtemp, readFile, rm, stat } from 'node:fs/promises' import { tmpdir } from 'node:os' import { basename, dirname, join, resolve } from 'node:path' import { pathToFileURL } from 'node:url' +import extractZip from 'extract-zip' export function createArchiveExtractionInvocation( artifact, destination, pathApi = { basename, dirname } ) { + if (artifact.toLowerCase().endsWith('.zip')) { + return { + kind: 'zip', + artifact, + options: { dir: destination } + } + } return { + kind: 'tar', command: 'tar', args: ['-xf', pathApi.basename(artifact), '-C', destination], options: { @@ -22,6 +31,15 @@ export function createArchiveExtractionInvocation( } } +export async function extractArchive(artifact, destination) { + const extraction = createArchiveExtractionInvocation(artifact, destination) + if (extraction.kind === 'zip') { + await extractZip(extraction.artifact, extraction.options) + } else { + execFileSync(extraction.command, extraction.args, extraction.options) + } +} + async function main() { const flags = readFlags(process.argv.slice(2)) const artifact = resolve(required(flags, 'artifact')) @@ -29,8 +47,7 @@ async function main() { const expectedTarget = required(flags, 'target') const temporary = await mkdtemp(join(tmpdir(), 'kun-tui-smoke-')) try { - const extraction = createArchiveExtractionInvocation(artifact, temporary) - execFileSync(extraction.command, extraction.args, extraction.options) + await extractArchive(artifact, temporary) const root = join(temporary, 'kun') const release = JSON.parse(await readFile(join(root, 'release.json'), 'utf8')) if (release.version !== expectedVersion || release.target !== expectedTarget) { diff --git a/scripts/smoke-standalone-tui.test.mjs b/scripts/smoke-standalone-tui.test.mjs index b78c377fc..2cb914234 100644 --- a/scripts/smoke-standalone-tui.test.mjs +++ b/scripts/smoke-standalone-tui.test.mjs @@ -1,9 +1,19 @@ import assert from 'node:assert/strict' -import { win32 } from 'node:path' +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join, posix, win32 } from 'node:path' import test from 'node:test' -import { createArchiveExtractionInvocation } from './smoke-standalone-tui.mjs' +import { + createArchiveExtractionInvocation, + extractArchive +} from './smoke-standalone-tui.mjs' -test('extracts a Windows TUI archive without passing the drive-qualified path to tar', () => { +const ZIP_FIXTURE = Buffer.from( + 'UEsDBBQAAAgIADJT/1zKTlJ0CQAAAAcAAAAJAAAAcHJvYmUudHh0q8os0M3P5gIAUEsBAj8DFAAACAgAMlP/XMpOUnQJAAAABwAAAAkACQAAAAAAAAAAALSBAAAAAHByb2JlLnR4dFVUBQADoAdsalBLBQYAAAAAAQABAEAAAAAwAAAAAAA=', + 'base64' +) + +test('extracts a Windows TUI ZIP without passing it to tar', () => { assert.deepEqual( createArchiveExtractionInvocation( 'D:\\a\\Kun\\Kun\\dist\\Kun-TUI-0.2.32-win-x64.zip', @@ -11,17 +21,38 @@ test('extracts a Windows TUI archive without passing the drive-qualified path to win32 ), { + kind: 'zip', + artifact: 'D:\\a\\Kun\\Kun\\dist\\Kun-TUI-0.2.32-win-x64.zip', + options: { dir: 'C:\\Users\\runner\\Temp\\kun-tui-smoke' } + } + ) +}) + +test('extracts a TUI tarball from its local directory', () => { + assert.deepEqual( + createArchiveExtractionInvocation( + '/release/Kun-TUI-0.2.32-linux-x64.tar.gz', + '/tmp/kun-tui-smoke', + posix + ), + { + kind: 'tar', command: 'tar', - args: [ - '-xf', - 'Kun-TUI-0.2.32-win-x64.zip', - '-C', - 'C:\\Users\\runner\\Temp\\kun-tui-smoke' - ], - options: { - cwd: 'D:\\a\\Kun\\Kun\\dist', - stdio: 'inherit' - } + args: ['-xf', 'Kun-TUI-0.2.32-linux-x64.tar.gz', '-C', '/tmp/kun-tui-smoke'], + options: { cwd: '/release', stdio: 'inherit' } } ) }) + +test('extracts ZIP contents through the Node ZIP implementation', async () => { + const temporary = await mkdtemp(join(tmpdir(), 'kun-tui-zip-test-')) + try { + const archive = join(temporary, 'probe.zip') + const destination = join(temporary, 'extracted') + await writeFile(archive, ZIP_FIXTURE) + await extractArchive(archive, destination) + assert.equal(await readFile(join(destination, 'probe.txt'), 'utf8'), 'zip-ok\n') + } finally { + await rm(temporary, { recursive: true, force: true }) + } +})