perf(windows): isolate packaging temporary files
This commit is contained in:
1 parent
9ee94429b9
commit
122da6fcff
8 files changed
+47
-11
No files matched your search
@@ -171,7 +171,12 @@ jobs:
|
||||
working-directory: ${{ steps.build_workspace.outputs.directory }}
|
||||
env:
|
||||
PACKAGE_VERSION: ${{ steps.settings.outputs.version }}
|
||||
PACKAGE_BUILD_TEMP: ${{ steps.build_workspace.outputs.temporaryDirectory }}
|
||||
run: |
|
||||
if ($env:PACKAGE_BUILD_TEMP) {
|
||||
$env:TEMP = $env:PACKAGE_BUILD_TEMP
|
||||
$env:TMP = $env:PACKAGE_BUILD_TEMP
|
||||
}
|
||||
$packageArgs = @('run', 'package:desktop:win:x64', '--build-version', $env:PACKAGE_VERSION)
|
||||
if ($env:PACKAGE_SIGNING -eq 'unsigned') { $packageArgs += '--unsigned' }
|
||||
pnpm @packageArgs
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
en: 5b4f0f80a117f202
|
||||
zh: ff05be196c181087
|
||||
/desktop-packaging/windows-actions-packaging:
|
||||
en: 68d800ed10cac4a6
|
||||
zh: f72ac7e939af7ad5
|
||||
en: faf2b4cffb576757
|
||||
zh: b9c807eea360d53d
|
||||
/desktop-packaging/macos-self-hosted-packaging:
|
||||
en: a3af9523fdc60036
|
||||
zh: 5e18d4740e9b7f57
|
||||
|
||||
@@ -113,7 +113,7 @@ Select the workflow in Actions, choose the source branch, preset, signing mode a
|
||||
|
||||
Open the completed run in Actions and download its Artifacts. `windows-x64-signed-<version>-<run_id>-<run_attempt>` and `windows-x64-unsigned-<version>-<run_id>-<run_attempt>` contain the corresponding EXE; `windows-package-logs-<run_id>-<run_attempt>` contains packaging diagnostics. The upload steps are `Retain verified signed installer`, `Retain verified unsigned installer`, and `Retain packaging diagnostics`; their step durations and timestamped logs show upload time. These artifacts are not a Release or download-site publication.
|
||||
|
||||
For path-sensitive Windows build measurements, `build_root` optionally selects an absolute directory outside existing Git checkouts. Each run clones the validated source commit into a new `windows-package-<run-id>-<attempt>/source` directory; ignored files and previous build outputs are not copied. Dependency and signing caches retain their existing locations. Successful runs remove only their owned checkout after artifact uploads; failed runs retain it for inspection. Leave the input empty to build in the original Actions checkout. Include checkout creation and cleanup in the complete Job timing.
|
||||
For path-sensitive Windows build measurements, `build_root` optionally selects an absolute directory outside existing Git checkouts. Each run clones the validated source commit into a new `windows-package-<run-id>-<attempt>/source` directory; ignored files and previous build outputs are not copied. Only the packaging process uses a sibling run-owned `temp` directory through `TEMP` and `TMP`; Actions steps and post-job hooks retain their original temporary directories. Dependency and signing caches retain their existing locations. Successful runs remove only their owned checkout after artifact uploads; failed runs retain it for inspection. Leave the input empty to build in the original Actions checkout. Include checkout creation and cleanup in the complete Job timing.
|
||||
|
||||
For cache measurements, `cache_namespace` selects a retained subdirectory for both dependency stores and upstream downloads; leave it empty for normal shared caches. Use a new name for a cold sample and repeat that name for warm samples. Names contain 1–64 lowercase letters, digits or hyphens, start with a letter or digit, and cannot be Windows device names. This does not reset the separate signature cache or OS file cache; report those states and Job start-to-completion time alongside phase timings and artifact size.
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ runner 的受监督启动和恢复见 [Windows runner 机器准备](../windows-s
|
||||
|
||||
在 Actions 打开完成的运行并下载 Artifacts。`windows-x64-signed-<version>-<run_id>-<run_attempt>` 与 `windows-x64-unsigned-<version>-<run_id>-<run_attempt>` 包含对应 EXE;`windows-package-logs-<run_id>-<run_attempt>` 包含打包诊断。上传步骤名为 `Retain verified signed installer`、`Retain verified unsigned installer` 和 `Retain packaging diagnostics`;步骤耗时与带时间戳的日志显示上传用时。这些产物不等于发布 Release 或下载站内容。
|
||||
|
||||
测量 Windows 构建路径对性能的影响时,可用 `build_root` 指定现有 Git checkout 之外的绝对目录。每轮任务将已验证的源码提交克隆到新的 `windows-package-<run-id>-<attempt>/source` 目录;不会复制忽略文件或此前的构建输出。依赖缓存和签名缓存沿用原有位置。成功任务在产物上传后仅删除本轮所属的 checkout;失败任务保留该目录供检查。输入留空时使用原 Actions checkout。完整 Job 耗时须包含 checkout 创建和清理。
|
||||
测量 Windows 构建路径对性能的影响时,可用 `build_root` 指定现有 Git checkout 之外的绝对目录。每轮任务将已验证的源码提交克隆到新的 `windows-package-<run-id>-<attempt>/source` 目录;不会复制忽略文件或此前的构建输出。仅打包进程通过 `TEMP` 和 `TMP` 使用同轮所属的同级 `temp` 目录;Actions 步骤及 Job 后置钩子保留原临时目录。依赖缓存和签名缓存沿用原有位置。成功任务在产物上传后仅删除本轮所属的 checkout;失败任务保留该目录供检查。输入留空时使用原 Actions checkout。完整 Job 耗时须包含 checkout 创建和清理。
|
||||
|
||||
测量缓存时,`cache_namespace` 为两个依赖 store 和上游下载选择保留的子目录;留空使用正常共享缓存。新名称用于冷缓存采样,再次使用同名用于热缓存采样。名称由 1–64 个小写字母、数字或连字符组成,以字母或数字开头,且不能为 Windows 设备名。这不会重置独立的签名缓存或操作系统文件缓存;应将其状态、Job 开始至完成的总耗时与阶段耗时和产物体积一并报告。
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ export interface WindowsBuildWorkspaceOptions {
|
||||
/**
|
||||
* Clone the clean selected commit into a new run-owned directory.
|
||||
* @param options - Original checkout and Actions run identity.
|
||||
* @returns Checkout to use for packaging.
|
||||
* @returns Checkout and temporary directory owned by this run.
|
||||
*/
|
||||
export function prepareWindowsBuildWorkspace(options: WindowsBuildWorkspaceOptions): { directory: string }
|
||||
export function prepareWindowsBuildWorkspace(options: WindowsBuildWorkspaceOptions): { directory: string; temporaryDirectory: string }
|
||||
/**
|
||||
* Remove the directory only when its ownership record matches the run.
|
||||
* @param options - Original checkout and Actions run identity.
|
||||
|
||||
@@ -30,7 +30,7 @@ function locations(options) {
|
||||
}
|
||||
const owner = join(root, `windows-package-${runId}-${runAttempt}`)
|
||||
assertUnlinkedAncestors(owner)
|
||||
return { root, owner, directory: join(owner, 'source') }
|
||||
return { root, owner, directory: join(owner, 'source'), temporaryDirectory: join(owner, 'temp') }
|
||||
}
|
||||
|
||||
function git(directory, args) {
|
||||
@@ -44,7 +44,7 @@ function ownership(options, paths) {
|
||||
/**
|
||||
* Clone the validated commit into a new run-owned checkout; failures retain diagnostics.
|
||||
* @param {{sourceDirectory: string, buildRoot: string, runId: string, runAttempt: string, sourceSha: string}} options - Source and run identity.
|
||||
* @returns {{directory: string}} Checkout to use for packaging.
|
||||
* @returns {{directory: string, temporaryDirectory: string}} Checkout and temporary directory owned by this run.
|
||||
*/
|
||||
export function prepareWindowsBuildWorkspace(options) {
|
||||
const paths = locations(options)
|
||||
@@ -54,12 +54,13 @@ export function prepareWindowsBuildWorkspace(options) {
|
||||
mkdirSync(paths.root, { recursive: true })
|
||||
mkdirSync(paths.owner)
|
||||
writeFileSync(join(paths.owner, 'owner.json'), ownership(options, paths), { flag: 'wx' })
|
||||
mkdirSync(paths.temporaryDirectory)
|
||||
git(paths.owner, ['clone', '--no-hardlinks', '--no-checkout', resolve(options.sourceDirectory), paths.directory])
|
||||
git(paths.directory, ['checkout', '--detach', options.sourceSha])
|
||||
if (git(paths.directory, ['rev-parse', 'HEAD']) !== options.sourceSha || git(paths.directory, ['status', '--porcelain'])) {
|
||||
throw new Error('Isolated packaging checkout does not match the selected commit')
|
||||
}
|
||||
return { directory: paths.directory }
|
||||
return { directory: paths.directory, temporaryDirectory: paths.temporaryDirectory }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,6 +90,6 @@ if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1]
|
||||
else {
|
||||
if (process.argv.length !== 2 || !process.env.GITHUB_OUTPUT) throw new Error('Expected Actions output file and no arguments')
|
||||
const result = prepareWindowsBuildWorkspace(options)
|
||||
appendFileSync(process.env.GITHUB_OUTPUT, `directory=${result.directory}\n`)
|
||||
appendFileSync(process.env.GITHUB_OUTPUT, `directory=${result.directory}\ntemporaryDirectory=${result.temporaryDirectory}\n`)
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,9 @@ it('clones the exact clean commit and removes only its run-owned checkout', () =
|
||||
stdio: 'pipe',
|
||||
})
|
||||
const directory = join(options.buildRoot, 'windows-package-123-1', 'source')
|
||||
expect(readFileSync(output, 'utf8')).toBe(`directory=${directory}\n`)
|
||||
const temporaryDirectory = join(options.buildRoot, 'windows-package-123-1', 'temp')
|
||||
expect(readFileSync(output, 'utf8')).toBe(`directory=${directory}\ntemporaryDirectory=${temporaryDirectory}\n`)
|
||||
writeFileSync(join(temporaryDirectory, 'temporary.txt'), 'owned temporary data')
|
||||
expect(readFileSync(join(directory, 'source.txt'), 'utf8')).toBe('selected source')
|
||||
expect(existsSync(join(directory, 'private.env'))).toBe(false)
|
||||
expect(() => prepareWindowsBuildWorkspace(options)).toThrow()
|
||||
@@ -52,6 +54,7 @@ it('clones the exact clean commit and removes only its run-owned checkout', () =
|
||||
symlinkSync(external, join(directory, 'node_modules'), process.platform === 'win32' ? 'junction' : 'dir')
|
||||
removeWindowsBuildWorkspace(options)
|
||||
expect(existsSync(directory)).toBe(false)
|
||||
expect(existsSync(temporaryDirectory)).toBe(false)
|
||||
expect(readFileSync(join(external, 'keep.txt'), 'utf8')).toBe('keep')
|
||||
expect(readFileSync(join(sourceDirectory, 'source.txt'), 'utf8')).toBe('selected source')
|
||||
const linked = join(root, 'linked')
|
||||
|
||||
@@ -160,6 +160,33 @@ it('routes all packaging consumers to the selected workspace and removes it only
|
||||
}
|
||||
})
|
||||
|
||||
it('scopes the optional temporary directory to installer building without changing Actions or later steps', () => {
|
||||
const build = job.steps.find(step => step.name === 'Build installer and verify packaged runtime')!
|
||||
expect(build.env?.PACKAGE_BUILD_TEMP).toBe('${{ steps.build_workspace.outputs.temporaryDirectory }}')
|
||||
expect(build.run).toContain([
|
||||
'if ($env:PACKAGE_BUILD_TEMP) {',
|
||||
' $env:TEMP = $env:PACKAGE_BUILD_TEMP',
|
||||
' $env:TMP = $env:PACKAGE_BUILD_TEMP',
|
||||
'}',
|
||||
].join('\n'))
|
||||
expect(build.run!.indexOf('if ($env:PACKAGE_BUILD_TEMP)')).toBeLessThan(build.run!.indexOf('$packageArgs ='))
|
||||
expect(build.run).not.toContain('GITHUB_ENV')
|
||||
expect(build.run).not.toContain('RUNNER_TEMP')
|
||||
expect(job.env).not.toHaveProperty('TEMP')
|
||||
expect(job.env).not.toHaveProperty('TMP')
|
||||
expect(job.env).not.toHaveProperty('PACKAGE_BUILD_TEMP')
|
||||
for (const step of job.steps.filter(step => step !== build)) {
|
||||
expect(step.env ?? {}).not.toHaveProperty('PACKAGE_BUILD_TEMP')
|
||||
expect(step.env ?? {}).not.toHaveProperty('TEMP')
|
||||
expect(step.env ?? {}).not.toHaveProperty('TMP')
|
||||
expect(step.run ?? '').not.toMatch(/\$env:(?:TEMP|TMP)\s*=/u)
|
||||
}
|
||||
const selected = job.steps.find(step => step.id === 'build_workspace')!
|
||||
const defaultBranch = selected.run!.split('} else {')[0]!
|
||||
expect(defaultBranch).toContain('"directory=$env:GITHUB_WORKSPACE" >> $env:GITHUB_OUTPUT')
|
||||
expect(defaultBranch).not.toContain('temporaryDirectory')
|
||||
})
|
||||
|
||||
it.skipIf(process.platform !== 'win32')('keeps the dependency store stable across run-specific pnpm homes', () => {
|
||||
const directory = mkdtempSync(resolve(tmpdir(), 'windows-package-store-'))
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user