Merge master and reconcile translation records
This commit is contained in:
commit
00a2e76b87
127 files changed
+4167
-557
No files matched your search
@@ -70,7 +70,7 @@ describe('repository build steps', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps artifact steps in serial dependency order', () => {
|
||||
it('finishes Host and Desktop readers before Client compilation rewrites shared outputs', () => {
|
||||
expect(graph(buildGates(root, 'artifacts'))).toEqual(artifactGraph)
|
||||
})
|
||||
|
||||
|
||||
@@ -166,10 +166,12 @@ function pnpmStep(id: LibraryStepId, label: string, args: readonly string[], nee
|
||||
/**
|
||||
* List the package-library build steps in Host, Desktop, then Client dependency order.
|
||||
* Source-only Typert generation supplies declarations before any package compilation.
|
||||
* Client compilation waits for Host and Desktop bundling because split compiler faces
|
||||
* rewrite shared lib/types files consumed by those bundles.
|
||||
* @param root - Repository root containing the compiler and bundle configurations.
|
||||
* @param faces - `host` lists Typert generation, Host compilation, and bundling; `all` adds Desktop and Client.
|
||||
* @param mode - Check package types by default; benchmark emission defers diagnostics to required full builds.
|
||||
* @returns The ordered steps; each step needs its predecessor.
|
||||
* @returns Steps with explicit compiler and bundle dependencies.
|
||||
* @throws If an aggregate configuration is invalid.
|
||||
*/
|
||||
export function libraryBuildSteps(root: string, faces: 'host' | 'all', mode: CompilationMode = 'checked'): LibraryStep[] {
|
||||
|
||||
@@ -9,7 +9,16 @@ const workflow = yaml.load(readFileSync(resolve(import.meta.dirname, '../.github
|
||||
concurrency: { group: string; 'cancel-in-progress': boolean }
|
||||
jobs: Record<string, {
|
||||
'runs-on': string[]
|
||||
steps: Array<{ id?: string; name?: string; if?: string; uses?: string; run?: string; with?: Record<string, unknown> }>
|
||||
env: Record<string, string>
|
||||
steps: Array<{
|
||||
id?: string
|
||||
name?: string
|
||||
if?: string
|
||||
uses?: string
|
||||
run?: string
|
||||
env?: Record<string, string>
|
||||
with?: Record<string, unknown>
|
||||
}>
|
||||
}>
|
||||
}
|
||||
|
||||
@@ -29,6 +38,7 @@ it('confines signed Mac packaging to manual dispatch and a dedicated Apple Silic
|
||||
expect(uploads[0]?.if).toBe("always() && steps.checkout.outcome == 'success'")
|
||||
expect(uploads[1]?.if).toBe('success()')
|
||||
expect(uploads[1]?.with?.path).toBe('${{ steps.retained.outputs.directory }}/*')
|
||||
expect(uploads[1]?.with?.['compression-level']).toBe(0)
|
||||
})
|
||||
|
||||
it('defaults to notarization and labels the explicit debugging option', () => {
|
||||
@@ -40,3 +50,21 @@ it('defaults to notarization and labels the explicit debugging option', () => {
|
||||
expect(steps.filter(step => step.run?.includes('args+=(--skip-notarization)'))).toHaveLength(2)
|
||||
expect(steps.find(step => step.name === 'Retain installers for the selected mode')?.with?.name).toContain('${{ steps.settings.outputs.mode }}')
|
||||
})
|
||||
|
||||
it('retains build inputs outside checkout and run-specific pnpm installations', () => {
|
||||
const env = workflow.jobs.package!.env
|
||||
expect(JSON.stringify(env)).not.toContain('runner.')
|
||||
const steps = workflow.jobs.package!.steps
|
||||
const cache = steps.find(step => step.name === 'Configure persistent package caches')!
|
||||
expect(cache.env?.DSH_DESKTOP_PACKAGE_CACHE_DIR).toBe('${{ runner.tool_cache }}/dsh-desktop-package-cache')
|
||||
expect(cache.run).toContain('PNPM_CONFIG_STORE_DIR=$DSH_DESKTOP_PACKAGE_CACHE_DIR/workspace-pnpm-store')
|
||||
expect(cache.run).toContain('DSH_DESKTOP_PACKAGE_CACHE_DIR=$DSH_DESKTOP_PACKAGE_CACHE_DIR')
|
||||
expect(steps.indexOf(cache)).toBeLessThan(steps.findIndex(step => step.name === 'Install locked dependencies'))
|
||||
})
|
||||
|
||||
it('offers ZIP compression choices with a fast default', () => {
|
||||
expect(workflow.on.workflow_dispatch).toMatchObject({ inputs: { zip_compression_level: {
|
||||
type: 'choice', options: ['3', '7'], default: '3', required: true,
|
||||
} } })
|
||||
expect(workflow.jobs.package!.env.PACKAGE_MACOS_ZIP_COMPRESSION_LEVEL).toBe('${{ inputs.zip_compression_level }}')
|
||||
})
|
||||
@@ -0,0 +1,66 @@
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { expect, it } from 'vitest'
|
||||
import { prepareWindowsBuildWorkspace, removeWindowsBuildWorkspace } from '../apps/desktop/scripts/windows-build-workspace.mjs'
|
||||
|
||||
it('clones the exact clean commit and removes only its run-owned checkout', () => {
|
||||
const root = realpathSync(mkdtempSync(join(tmpdir(), 'package-workspace-')))
|
||||
try {
|
||||
const sourceDirectory = join(root, 'original')
|
||||
mkdirSync(sourceDirectory)
|
||||
const git = (...args: string[]) => execFileSync('git', args, { cwd: sourceDirectory, encoding: 'utf8', stdio: 'pipe' }).trim()
|
||||
git('init')
|
||||
writeFileSync(join(sourceDirectory, 'source.txt'), 'selected source')
|
||||
writeFileSync(join(sourceDirectory, '.gitignore'), 'private.env\n')
|
||||
git('add', '.')
|
||||
git('-c', 'user.name=Fixture', '-c', '[email protected]', 'commit', '-m', 'fixture')
|
||||
writeFileSync(join(sourceDirectory, 'private.env'), 'ignored fixture')
|
||||
const options = { sourceDirectory, buildRoot: join(root, 'builds'), runId: '123', runAttempt: '1', sourceSha: git('rev-parse', 'HEAD') }
|
||||
expect(() => prepareWindowsBuildWorkspace({ ...options, buildRoot: sourceDirectory })).toThrow('outside existing Git')
|
||||
expect(() => prepareWindowsBuildWorkspace({ ...options, buildRoot: 'relative' })).toThrow('absolute')
|
||||
expect(() => prepareWindowsBuildWorkspace({ ...options, runId: '../other' })).toThrow('identity')
|
||||
expect(() => prepareWindowsBuildWorkspace({ ...options, sourceSha: '0'.repeat(40) })).toThrow('match')
|
||||
writeFileSync(join(sourceDirectory, 'source.txt'), 'dirty')
|
||||
expect(() => prepareWindowsBuildWorkspace(options)).toThrow('clean')
|
||||
writeFileSync(join(sourceDirectory, 'source.txt'), 'selected source')
|
||||
const output = join(root, 'actions-output')
|
||||
execFileSync(process.execPath, [resolve(import.meta.dirname, '../apps/desktop/scripts/windows-build-workspace.mjs')], {
|
||||
cwd: sourceDirectory,
|
||||
env: {
|
||||
...process.env,
|
||||
GITHUB_WORKSPACE: sourceDirectory,
|
||||
PACKAGE_BUILD_ROOT: options.buildRoot,
|
||||
GITHUB_RUN_ID: options.runId,
|
||||
GITHUB_RUN_ATTEMPT: options.runAttempt,
|
||||
PACKAGE_SOURCE_SHA: options.sourceSha,
|
||||
GITHUB_OUTPUT: output,
|
||||
},
|
||||
stdio: 'pipe',
|
||||
})
|
||||
const directory = join(options.buildRoot, 'windows-package-123-1', 'source')
|
||||
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()
|
||||
expect(() => { removeWindowsBuildWorkspace({ ...options, sourceSha: '0'.repeat(40) }) }).toThrow('ownership')
|
||||
expect(existsSync(directory)).toBe(true)
|
||||
const external = join(root, 'external')
|
||||
mkdirSync(external)
|
||||
writeFileSync(join(external, 'keep.txt'), 'keep')
|
||||
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')
|
||||
symlinkSync(external, linked, process.platform === 'win32' ? 'junction' : 'dir')
|
||||
expect(() => prepareWindowsBuildWorkspace({ ...options, buildRoot: join(linked, 'builds') })).toThrow('links')
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
@@ -1,13 +1,13 @@
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { resolve } from 'node:path'
|
||||
import { parse, resolve } from 'node:path'
|
||||
import yaml from 'js-yaml'
|
||||
import { expect, it } from 'vitest'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const workflow = yaml.load(readFileSync(resolve(root, '.github/workflows/windows-package.yml'), 'utf8')) as {
|
||||
on: Record<string, { inputs: Record<string, { required?: boolean; default?: string; description?: string }> }>
|
||||
on: Record<string, { inputs: Record<string, { type?: string; required?: boolean; default?: string; description?: string }> }>
|
||||
permissions: Record<string, string>
|
||||
concurrency: { group: string; 'cancel-in-progress': boolean }
|
||||
jobs: Record<string, {
|
||||
@@ -19,6 +19,7 @@ const workflow = yaml.load(readFileSync(resolve(root, '.github/workflows/windows
|
||||
uses?: string
|
||||
run?: string
|
||||
if?: string
|
||||
'working-directory'?: string
|
||||
env?: Record<string, string>
|
||||
with?: Record<string, unknown>
|
||||
}>
|
||||
@@ -61,12 +62,17 @@ it('routes manual packaging to the dedicated runner with explicit preset and sig
|
||||
expect(Object.keys(workflow.on)).toEqual(['workflow_dispatch'])
|
||||
expect(workflow.jobs.package).not.toHaveProperty('name')
|
||||
expect(job['runs-on']).toBe('dsh-win-package-trial')
|
||||
expect(JSON.stringify(job.env)).not.toContain('runner.')
|
||||
expect(job.steps.find(step => step.name === 'Configure persistent pnpm store')?.env?.DSH_DESKTOP_PACKAGE_CACHE_DIR)
|
||||
.toBe('${{ runner.tool_cache }}/dsh-desktop-package-cache')
|
||||
expect(workflow.concurrency).toEqual({ group: 'windows-desktop-package', 'cancel-in-progress': false })
|
||||
expect(workflow.permissions).toEqual({ contents: 'read' })
|
||||
expect(Object.keys(workflow.on.workflow_dispatch!.inputs).sort()).toEqual([
|
||||
'build_version', 'preset', 'signing', 'source_ref', 'test_release_id', 'update_channel', 'version_mode',
|
||||
'build_root', 'build_version', 'cache_namespace', 'compression_level', 'preset', 'signing', 'source_ref', 'test_release_id', 'update_channel', 'version_mode',
|
||||
])
|
||||
expect(workflow.on.workflow_dispatch!.inputs.signing!.default).toBe('signed')
|
||||
expect(workflow.on.workflow_dispatch!.inputs.compression_level).toMatchObject({ type: 'choice', options: ['3', '7'], default: '3', required: true })
|
||||
expect(job.env.PACKAGE_WINDOWS_COMPRESSION_LEVEL).toBe('${{ inputs.compression_level }}')
|
||||
expect(workflow.on.workflow_dispatch!.inputs.build_version!.required).toBe(false)
|
||||
expect(workflow.on.workflow_dispatch!.inputs.version_mode!.default).toBe('default')
|
||||
expect(workflow.on.workflow_dispatch!.inputs.source_ref!.default).toBe('master')
|
||||
@@ -101,9 +107,182 @@ it('retains failure diagnostics and uploads only the selected successful install
|
||||
const uploads = job.steps.filter(step => step.uses?.startsWith('actions/upload-artifact@'))
|
||||
expect(uploads).toHaveLength(3)
|
||||
expect(uploads[0]!.if).toBe("always() && steps.checkout.outcome == 'success'")
|
||||
expect(uploads[0]!.with).toMatchObject({ path: 'apps/desktop/.desktop-build/packaging-runs/', 'include-hidden-files': true })
|
||||
expect(uploads[0]!.with).toMatchObject({
|
||||
path: '${{ steps.build_workspace.outputs.directory || github.workspace }}/apps/desktop/.desktop-build/packaging-runs/',
|
||||
'include-hidden-files': true,
|
||||
})
|
||||
for (const mode of ['unsigned', 'signed']) {
|
||||
const upload = uploads.find(step => step.if === `success() && inputs.signing == '${mode}'`)!
|
||||
expect(upload.with).toMatchObject({ path: '${{ steps.retained.outputs.directory }}/*', 'if-no-files-found': 'error' })
|
||||
expect(upload.with).toMatchObject({ path: '${{ steps.retained.outputs.directory }}/*', 'if-no-files-found': 'error', 'compression-level': 0 })
|
||||
}
|
||||
})
|
||||
|
||||
it('routes all packaging consumers to the selected workspace and removes it only after successful uploads', () => {
|
||||
expect(workflow.on.workflow_dispatch!.inputs.build_root).toMatchObject({ type: 'string', default: '', required: false })
|
||||
expect(job.env.PACKAGE_BUILD_ROOT).toBe('${{ inputs.build_root }}')
|
||||
const selected = job.steps.find(step => step.id === 'build_workspace')!
|
||||
expect(selected.name).toBe('Select packaging workspace')
|
||||
expect(selected.env).toEqual({ PACKAGE_SOURCE_SHA: '${{ steps.checkout.outputs.commit }}' })
|
||||
expect(selected['working-directory']).toBeUndefined()
|
||||
expect(selected.run).toContain('if (!$env:PACKAGE_BUILD_ROOT)')
|
||||
expect(selected.run).toContain('"directory=$env:GITHUB_WORKSPACE" >> $env:GITHUB_OUTPUT')
|
||||
expect(selected.run).toContain('} else {')
|
||||
expect(selected.run).toContain('node "$env:PACKAGE_CI_HELPERS/windows-build-workspace.mjs"')
|
||||
expect(selected.run).toContain('exit $LASTEXITCODE')
|
||||
const index = job.steps.indexOf(selected)
|
||||
expect(index).toBeGreaterThan(job.steps.findIndex(step => step.uses?.startsWith('actions/setup-node@')))
|
||||
expect(index).toBeLessThan(job.steps.findIndex(step => step.name === 'Configure persistent pnpm store'))
|
||||
const consumers = [
|
||||
'Install locked dependencies',
|
||||
'Validate preset and resolve build version',
|
||||
'Check packaging configuration and toolchain',
|
||||
'Build installer and verify packaged runtime',
|
||||
'Retain complete package outside the checkout',
|
||||
]
|
||||
for (const name of consumers) {
|
||||
const step = job.steps.find(entry => entry.name === name)!
|
||||
expect(step['working-directory']).toBe('${{ steps.build_workspace.outputs.directory }}')
|
||||
expect(job.steps.indexOf(step)).toBeGreaterThan(index)
|
||||
}
|
||||
expect(job.steps.filter(step => step['working-directory'] === '${{ steps.build_workspace.outputs.directory }}'))
|
||||
.toHaveLength(consumers.length)
|
||||
const store = job.steps.find(step => step.name === 'Configure persistent pnpm store')!
|
||||
expect(store.run).toContain('[IO.Path]::GetPathRoot($env:GITHUB_WORKSPACE)')
|
||||
expect(store['working-directory']).toBeUndefined()
|
||||
const cleanup = job.steps.at(-1)!
|
||||
expect(cleanup).toMatchObject({
|
||||
name: 'Remove isolated packaging workspace',
|
||||
if: "success() && inputs.build_root != ''",
|
||||
env: { PACKAGE_SOURCE_SHA: '${{ steps.checkout.outputs.commit }}' },
|
||||
run: 'node "$env:PACKAGE_CI_HELPERS/windows-build-workspace.mjs" --remove',
|
||||
})
|
||||
expect(cleanup['working-directory']).toBeUndefined()
|
||||
for (const upload of job.steps.filter(step => step.uses?.startsWith('actions/upload-artifact@'))) {
|
||||
expect(job.steps.indexOf(upload)).toBeLessThan(job.steps.indexOf(cleanup))
|
||||
}
|
||||
})
|
||||
|
||||
it('normalizes priority in the dependency and packaging shells before launching their children', () => {
|
||||
const command = '& "$env:PACKAGE_CI_HELPERS/windows-packaging-priority.ps1" -BestEffort'
|
||||
expect(job.steps.find(entry => entry.name === 'Validate selected source and adapter support')!.run)
|
||||
.not.toContain('windows-packaging-priority.ps1')
|
||||
for (const name of ['Install locked dependencies', 'Build installer and verify packaged runtime']) {
|
||||
const step = job.steps.find(entry => entry.name === name)!
|
||||
expect(step.run!.trimStart().startsWith(command + '\n')).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
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 {
|
||||
const workspace = resolve(directory, 'runner', 'repo')
|
||||
const packageCache = resolve(directory, 'tool-cache', 'desktop')
|
||||
const store = resolve(parse(directory).root, '.pnpm-store')
|
||||
const step = job.steps.find(entry => entry.name === 'Configure persistent pnpm store')!
|
||||
expect(job.steps.indexOf(step)).toBeLessThan(job.steps.findIndex(entry => entry.name === 'Install locked dependencies'))
|
||||
const script = resolve(directory, 'store.ps1')
|
||||
writeFileSync(script, "$ErrorActionPreference = 'Stop'\n" + step.run!)
|
||||
const outputs = ['first', 'second'].map((run) => {
|
||||
const environmentFile = resolve(directory, run + '.env')
|
||||
execFileSync('pwsh', ['-NoProfile', '-File', script], {
|
||||
env: { ...process.env, GITHUB_WORKSPACE: workspace,
|
||||
PACKAGE_CACHE_NAMESPACE: '', DSH_DESKTOP_PACKAGE_CACHE_DIR: packageCache,
|
||||
PNPM_HOME: resolve(directory, run, 'pnpm'), GITHUB_ENV: environmentFile },
|
||||
stdio: 'pipe',
|
||||
})
|
||||
return readFileSync(environmentFile, 'utf8').trim()
|
||||
})
|
||||
expect(outputs.map(output => output.split(/\r?\n/u))).toEqual(Array.from({ length: 2 }, () => [
|
||||
`DSH_DESKTOP_PACKAGE_CACHE_DIR=${packageCache}`, `PNPM_CONFIG_STORE_DIR=${store}`,
|
||||
]))
|
||||
const runNamespace = (namespace: string) => {
|
||||
const output = resolve(directory, 'namespace.env')
|
||||
rmSync(output, { force: true })
|
||||
execFileSync('pwsh', ['-NoProfile', '-File', script], {
|
||||
env: { ...process.env, GITHUB_WORKSPACE: workspace,
|
||||
PACKAGE_CACHE_NAMESPACE: namespace, DSH_DESKTOP_PACKAGE_CACHE_DIR: packageCache, GITHUB_ENV: output },
|
||||
stdio: 'pipe',
|
||||
})
|
||||
return readFileSync(output, 'utf8').trim().split(/\r?\n/u)
|
||||
}
|
||||
expect(runNamespace('perf-1')).toEqual([
|
||||
`DSH_DESKTOP_PACKAGE_CACHE_DIR=${resolve(packageCache, 'perf-1')}`, `PNPM_CONFIG_STORE_DIR=${resolve(store, 'perf-1')}`,
|
||||
])
|
||||
for (const invalid of ['../escape', 'Upper', 'has space', 'con', 'perf\n', 'a'.repeat(65)]) {
|
||||
expect(() => runNamespace(invalid)).toThrow()
|
||||
}
|
||||
} finally {
|
||||
rmSync(directory, { recursive: true, force: true, maxRetries: 3 })
|
||||
}
|
||||
})
|
||||
|
||||
it('pins environment helpers to the workflow commit before selecting product source', () => {
|
||||
const helper = job.steps.find(step => step.name === 'Checkout workflow helpers')!
|
||||
const stage = job.steps.find(step => step.name === 'Stage workflow helpers')!
|
||||
const source = job.steps.find(step => step.id === 'checkout')!
|
||||
expect(helper.with).toMatchObject({ ref: '${{ github.workflow_sha }}', 'persist-credentials': false })
|
||||
expect(job.steps.indexOf(helper)).toBeLessThan(job.steps.indexOf(stage))
|
||||
expect(job.steps.indexOf(stage)).toBeLessThan(job.steps.indexOf(source))
|
||||
expect(stage.run).toContain('RUNNER_TEMP')
|
||||
expect(stage.run).toContain('windows-build-workspace.mjs')
|
||||
expect(stage.run).toContain('windows-packaging-priority.ps1')
|
||||
for (const step of job.steps.filter(step => step.name !== 'Stage workflow helpers')) {
|
||||
expect(step.run ?? '').not.toContain('./apps/desktop/scripts/windows-packaging-priority.ps1')
|
||||
expect(step.run ?? '').not.toContain('node apps/desktop/scripts/windows-build-workspace.mjs')
|
||||
}
|
||||
})
|
||||
|
||||
it.skipIf(process.platform !== 'win32')('stages helpers that remain usable when product source lacks them', () => {
|
||||
const directory = mkdtempSync(resolve(tmpdir(), 'workflow-helpers-'))
|
||||
try {
|
||||
const source = resolve(directory, 'source')
|
||||
const scripts = resolve(source, 'apps/desktop/scripts')
|
||||
const temporary = resolve(directory, 'temporary')
|
||||
mkdirSync(scripts, { recursive: true })
|
||||
mkdirSync(temporary)
|
||||
for (const name of ['windows-packaging-priority.ps1', 'windows-build-workspace.mjs']) {
|
||||
writeFileSync(resolve(scripts, name), readFileSync(resolve(root, 'apps/desktop/scripts', name)))
|
||||
}
|
||||
const stage = resolve(directory, 'stage.ps1')
|
||||
writeFileSync(stage, job.steps.find(step => step.name === 'Stage workflow helpers')!.run!)
|
||||
const env = { ...process.env, RUNNER_TEMP: temporary, GITHUB_RUN_ID: '123', GITHUB_RUN_ATTEMPT: '1', GITHUB_ENV: resolve(directory, 'env') }
|
||||
execFileSync('pwsh', ['-NoProfile', '-File', stage], { cwd: source, env, stdio: 'pipe' })
|
||||
rmSync(scripts, { recursive: true })
|
||||
const helper = resolve(temporary, 'packaging-helpers-123-1/windows-packaging-priority.ps1')
|
||||
expect(execFileSync('pwsh', ['-NoProfile', '-File', helper, '-InspectOnly'], { cwd: source, stdio: 'pipe' }).toString())
|
||||
.toContain('packaging-process-priority')
|
||||
expect(existsSync(resolve(temporary, 'packaging-helpers-123-1/windows-build-workspace.mjs'))).toBe(true)
|
||||
expect(() => execFileSync('pwsh', ['-NoProfile', '-File', stage], {
|
||||
cwd: source, env: { ...env, GITHUB_RUN_ATTEMPT: '2' }, stdio: 'pipe',
|
||||
})).toThrow()
|
||||
} finally {
|
||||
rmSync(directory, { recursive: true, force: true, maxRetries: 3 })
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user