fix(ci): repair Wine heap budget and release workflow tests (#7438)

* fix(ci): budget Wine client heap and align release assertions

* fix(release): restore hosted publication runners

* fix(ci): split Wine client checks and strengthen dispatch tests

* docs: remove Wine diagnostic instruction from AGENTS
This commit is contained in:
imccyu
2026-10-28 11:22:35 +08:00
committed by GitHub
parent e27306b2a0
commit 18bd83bf88
6 changed files with 60 additions and 24 deletions
+3 -2
View File
@@ -14,6 +14,7 @@ on:
- larger-runner-benchmark
- consolidated-runner-benchmark
- ssh-helper
- wine
# New master pushes and manual runs replace obsolete checks in this workflow/ref.
# Standby drills share cancellation; use completed runs as readiness evidence.
@@ -49,9 +50,9 @@ jobs:
secrets:
DEEPSEEK_API_KEY_EXTERNAL: ${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}
# Wine runs once here, independently of the native serial standby aggregates.
# Wine runs on master pushes or an explicit suite=wine dispatch, independently of native standbys.
windows:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
if: (github.event_name == 'push' && github.ref == 'refs/heads/master') || (github.event_name == 'workflow_dispatch' && inputs.suite == 'wine')
runs-on: ubuntu-latest
name: windows node 24 / wine
timeout-minutes: 15
+1 -12
View File
@@ -24,18 +24,7 @@ env:
jobs:
pack:
name: Pack npm tarballs
runs-on: >-
${{ vars.DSH_CI_FAILOVER_LINUX == 'selfhosted'
&& github.repository == 'deepseek-harness/deepseek-harness'
&& github.actor != 'dependabot[bot]'
&& (github.event_name == 'workflow_dispatch'
|| (github.event_name == 'push' && github.ref == 'refs/heads/master')
|| (github.event_name == 'pull_request'
&& github.event.pull_request.head.repo.full_name == github.repository
&& github.event.pull_request.head.repo.fork == false
&& github.event.pull_request.user.login != 'dependabot[bot]'))
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|| 'ubuntu-24.04' }}
runs-on: ubuntu-24.04
steps:
# Complete history: the release scripts read tags.
- uses: actions/checkout@v7.0.1
+39 -2
View File
@@ -138,7 +138,7 @@ describe('CI workflow', () => {
expect(job.steps).toContainEqual(expect.objectContaining({ run: command }))
}
for (const [file, command] of [
['release-publish.yml', 'pnpm run build:official'],
['release-publish.yml', 'pnpm run build:official --serial'],
['release-vendor-publish.yml', 'pnpm run build:lib:host'],
] as const) {
expect(workflowJob(loadWorkflow('.github/workflows/' + file), 'pack').steps)
@@ -743,7 +743,7 @@ describe('CI workflow', () => {
expect(uploadIndex).toBeGreaterThan(benchmarkIndex)
})
it('splits the Wine Host TypeScript compile and retains its heap budget', () => {
it('splits both Wine TypeScript faces and retains their aggregate heap budgets', () => {
const wineGates = readFileSync(resolve(root, 'scripts/wine-windows-gates.sh'), 'utf8')
const references = wineGates.indexOf(
@@ -757,6 +757,43 @@ describe('CI workflow', () => {
expect(references).toBeGreaterThan(metadata)
expect(aggregate).toBeGreaterThan(references)
expect(wineGates).not.toContain('-b tsconfig.host.json')
const clientReferences = wineGates.indexOf('wine_node "$scratch/logs/client-references.log" --import tsx/esm scripts/compile-referenced-projects.ts client')
const clientAggregate = wineGates.indexOf('wine_node "$scratch/logs/client-tsc.log" --max-old-space-size=8192 "$tsc_js" -p tsconfig.client.json --pretty false')
expect(clientReferences).toBeGreaterThan(aggregate)
expect(clientAggregate).toBeGreaterThan(clientReferences)
expect(wineGates).not.toContain('-b tsconfig.client.json')
expect(wineGates).toContain(' "$scratch/logs/client-references.log" \\')
})
it('runs only Wine for its manual suite and retains master-push scheduling', () => {
const master = loadWorkflow('.github/workflows/ci-master.yml')
if (!isRecord(master.on) || !isRecord(master.on.workflow_dispatch)
|| !isRecord(master.on.workflow_dispatch.inputs) || !isRecord(master.on.workflow_dispatch.inputs.suite)
|| !isRecord(master.jobs)) throw new TypeError('CI master must define manual suites and jobs')
expect(master.on.workflow_dispatch.inputs.suite.options).toEqual([
'larger-runner-benchmark', 'consolidated-runner-benchmark', 'ssh-helper', 'wine',
])
const wine = workflowJob(master, 'windows')
if (typeof wine.if !== 'string') throw new TypeError('Wine must define a trigger condition')
for (const [event, ref, suite, expected] of [
['push', 'refs/heads/master', '', true],
['push', 'refs/heads/topic', '', false],
['pull_request', 'refs/pull/42/merge', 'wine', false],
['workflow_dispatch', 'refs/heads/topic', 'wine', true],
['workflow_dispatch', 'refs/tags/dsh-v0.2.2-alpha.2', 'wine', true],
['workflow_dispatch', 'refs/heads/topic', 'ssh-helper', false],
['workflow_dispatch', 'refs/heads/topic', 'larger-runner-benchmark', false],
['workflow_dispatch', 'refs/heads/topic', 'consolidated-runner-benchmark', false],
] as const) {
expect(runInNewContext(wine.if, { github: { event_name: event, ref }, inputs: { suite } }, { timeout: 1000 })).toBe(expected)
}
const enabled = Object.entries(master.jobs).filter(([, job]) => {
if (!isRecord(job)) throw new TypeError('CI master jobs must be objects')
if (typeof job.if === 'boolean') return job.if
if (typeof job.if !== 'string') throw new TypeError('CI master jobs must define trigger conditions')
return runInNewContext(job.if, { github: { event_name: 'workflow_dispatch', ref: 'refs/heads/topic' }, inputs: { suite: 'wine' } }, { timeout: 1000 }) === true
}).map(([name]) => name)
expect(enabled).toEqual(['windows'])
})
it('cancels superseded master runs without changing the post-merge job inventory', () => {
+4 -1
View File
@@ -126,7 +126,10 @@ describe('master-only platform scheduling', () => {
it('runs Wine once on hosted master CI and seeds its own apt cache', () => {
const master = workflow('ci-master.yml')
const wine = master.jobs.windows!
expect(wine).toMatchObject({ if: masterPush, 'runs-on': 'ubuntu-latest' })
expect(wine).toMatchObject({
if: "(github.event_name == 'push' && github.ref == 'refs/heads/master') || (github.event_name == 'workflow_dispatch' && inputs.suite == 'wine')",
'runs-on': 'ubuntu-latest',
})
expect(wine.needs).toBeUndefined()
expect(wine['continue-on-error']).toBeUndefined()
expect(master.jobs['wine-apt-cache']).toBeUndefined()
+7 -2
View File
@@ -163,8 +163,13 @@ for (const [file, jobIds] of [['release.yml', ['dependencies', 'pack']], ['relea
})
}
it.each(['release-publish.yml', 'release-vendor-publish.yml'])('keeps %s manual and entirely hosted', (file) => {
const publish = workflow(file)
it('keeps vendor publication manual and entirely hosted', () => {
const publish = workflow('release-vendor-publish.yml')
expect(Object.keys(publish.on)).toEqual(['workflow_dispatch'])
for (const job of Object.values(publish.jobs)) expect(job['runs-on']).toBe(hosted)
})
it('keeps DSH publication manual and entirely hosted', () => {
const publish = workflow('release-publish.yml')
expect(Object.keys(publish.on)).toEqual(['workflow_dispatch'])
for (const job of Object.values(publish.jobs)) expect(job['runs-on']).toBe(hosted)
})
+6 -5
View File
@@ -245,10 +245,9 @@ grep -q '^smoke: win32 x64' "$scratch/logs/smoke.log" || { echo 'wine-windows-ga
# The build mirrors the root build:lib:host and build:lib:client scripts:
# generate metadata, compile the Host package projects, type-check the Host
# aggregate program, bundle the Host face, bundle apps/desktop from the Host
# lib/ outputs, then compile and bundle the Client face. The Host compile is two
# invocations because that is how the supported build splits it; a single
# `tsc -b` holds the reference graph and the aggregate program in one process
# and exceeds the heap the Host face is budgeted.
# lib/ outputs, then compile and bundle the Client face. Each face compiles
# package references separately from its aggregate program, matching the
# supported build and releasing the reference graph before aggregate checking.
# Both statuses are captured so one failure cannot hide the other's result.
build_gate() {
wine_node "$scratch/logs/host-typert.log" --import tsx/esm scripts/generate-typert.ts || return $?
@@ -256,7 +255,8 @@ build_gate() {
wine_node "$scratch/logs/host-tsc.log" --max-old-space-size=8192 "$tsc_js" -p tsconfig.host.json --pretty false || return $?
wine_node "$scratch/logs/host-tsdown.log" "$tsdown_js" --env.DSH_BUILD_FACE host || return $?
(cd apps/desktop && wine_node "$scratch/logs/desktop-tsdown.log" "../../$tsdown_js") || return $?
wine_node "$scratch/logs/client-tsc.log" "$tsc_js" -b tsconfig.client.json --pretty false || return $?
wine_node "$scratch/logs/client-references.log" --import tsx/esm scripts/compile-referenced-projects.ts client || return $?
wine_node "$scratch/logs/client-tsc.log" --max-old-space-size=8192 "$tsc_js" -p tsconfig.client.json --pretty false || return $?
wine_node "$scratch/logs/client-tsdown.log" "$tsdown_js" --env.DSH_BUILD_FACE client
}
site_gate() {
@@ -288,6 +288,7 @@ report 'build (Typert, Host tsc/tsdown, desktop tsdown, Client tsc/tsdown)' "$bu
"$scratch/logs/host-tsc.log" \
"$scratch/logs/host-tsdown.log" \
"$scratch/logs/desktop-tsdown.log" \
"$scratch/logs/client-references.log" \
"$scratch/logs/client-tsc.log" \
"$scratch/logs/client-tsdown.log"
report 'production site (vitepress build)' "$site_status" "$scratch/logs/site.log"