Skip to content

Commit 95e0bb8

Browse files
authored
fix(ci): 根治 #3071/#3060 — plugin-audit/plugin-dev 测试不再依赖已构建 dist;移除全部临时诊断 (#3075)
1 parent ca30acd commit 95e0bb8

5 files changed

Lines changed: 90 additions & 39 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -108,48 +108,14 @@ jobs:
108108
# still run (close to) everything — but the many PRs that don't touch
109109
# spec skip the bulk of the 75-package matrix.
110110
# --concurrency=4: turbo's default (10) oversubscribes the 4-vCPU
111-
# hosted runner. As the task graph grew past ~100 tasks (connector
112-
# packages + qa gates), parallel vitest workers + tsup DTS builds
113-
# started exhausting runner memory: plugin-audit#test died with ZERO
114-
# output (kernel OOM-kill signature) deterministically on the runner
115-
# while passing everywhere else — first seen on main @4f8c2d1,
116-
# reproduced twice on #3037. Matching concurrency to the core count
117-
# bounds peak memory; the job is CPU-bound anyway.
118-
# ── TEMPORARY DIAGNOSTICS for #3071 — remove before merge ────────────
119-
# plugin-audit#test dies on the hosted runner with zero captured output
120-
# (3× deterministic; passes locally under Node 20/22 with the exact CI
121-
# command). Run it ISOLATED first — fresh machine, no turbo grouping,
122-
# verbose reporter — so its real output cannot be mangled by the GH log
123-
# pipeline under burst. SIGQUIT before the timeout makes Node dump all
124-
# thread stacks if it hangs.
125-
- name: DIAG 3071 — plugin-audit isolated, verbose (temporary)
126-
if: github.event_name == 'pull_request'
127-
run: |
128-
node --version
129-
free -h || true
130-
echo "── isolated vitest run ──"
131-
timeout -s QUIT 240 pnpm --filter @objectstack/plugin-audit exec vitest run --reporter=verbose --no-file-parallelism; echo "exit=$?"
132-
continue-on-error: true
133-
111+
# hosted runner; matching the core count bounds peak memory and the
112+
# job is CPU-bound anyway.
134113
- name: Run affected tests (PR)
135114
if: github.event_name == 'pull_request'
136115
env:
137116
TURBO_SCM_BASE: ${{ github.event.pull_request.base.sha }}
138117
run: pnpm turbo run test --affected --concurrency=4
139118

140-
# ── TEMPORARY DIAGNOSTICS for #3071 — remove before merge ────────────
141-
# If the turbo step above still kills plugin-audit silently, dmesg shows
142-
# whether the kernel OOM-killer fired, and the second isolated re-run
143-
# distinguishes "machine state after the full graph" from "fresh".
144-
- name: DIAG 3071 — post-turbo dmesg + re-run (temporary)
145-
if: github.event_name == 'pull_request' && always()
146-
run: |
147-
echo "── kernel OOM traces ──"
148-
sudo dmesg | grep -iE "oom|killed process|out of memory" | tail -20 || echo "(no OOM traces)"
149-
echo "── plugin-audit re-run on post-graph machine ──"
150-
timeout -s QUIT 240 pnpm --filter @objectstack/plugin-audit exec vitest run --reporter=verbose --no-file-parallelism; echo "exit=$?"
151-
continue-on-error: true
152-
153119
# Push to main: full run, but exclude spec's plain test task — the
154120
# coverage step below executes the exact same 250-file spec suite once,
155121
# with coverage. Previously the spec suite ran twice per push.

packages/plugins/plugin-audit/src/audit-writers.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,13 @@ describe('audit writers — enable.files server-side enforcement (#2727)', () =>
440440
});
441441
});
442442

443-
describe('audit writers — localized activity summaries (framework#3039)', () => {
443+
// timeout: the FIRST localized case pays the one-off cost of dynamically
444+
// importing @objectstack/core + the shipped translation bundle (and, with the
445+
// #3071 src aliases, their vite transforms). On a shared 4-vCPU CI runner that
446+
// cold start alone was measured at ~5s — right at vitest's default timeout —
447+
// while every warmed case runs in ~1ms. 20s bounds the cold start without
448+
// masking a real hang.
449+
describe('audit writers — localized activity summaries (framework#3039)', { timeout: 20_000 }, () => {
444450
// Real memory i18n (what the kernel registers as the 'i18n' fallback) loaded
445451
// with this plugin's shipped bundle plus an app-contributed object label —
446452
// exercises the actual key shapes (`messages.activityCreated`,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
// #3071: without these aliases, vitest resolves workspace deps through their
4+
// package.json `exports` — i.e. `dist/` — so whether this package's tests
5+
// even LOAD depends on turbo build ordering and cache-restore integrity on
6+
// the runner (the deterministic zero-output CI failure). Aliasing to `src/`
7+
// (the same convention plugin-hono-server et al. already use) removes the
8+
// dist dependency entirely.
9+
import { defineConfig } from 'vitest/config';
10+
import path from 'path';
11+
12+
export default defineConfig({
13+
test: {
14+
globals: true,
15+
environment: 'node',
16+
},
17+
resolve: {
18+
alias: {
19+
'@objectstack/core': path.resolve(__dirname, '../../core/src/index.ts'),
20+
'@objectstack/platform-objects/audit': path.resolve(__dirname, '../../platform-objects/src/audit/index.ts'),
21+
'@objectstack/spec/contracts': path.resolve(__dirname, '../../spec/src/contracts/index.ts'),
22+
'@objectstack/spec/data': path.resolve(__dirname, '../../spec/src/data/index.ts'),
23+
'@objectstack/spec/system': path.resolve(__dirname, '../../spec/src/system/index.ts'),
24+
'@objectstack/spec/api': path.resolve(__dirname, '../../spec/src/api/index.ts'),
25+
'@objectstack/spec/kernel': path.resolve(__dirname, '../../spec/src/kernel/index.ts'),
26+
'@objectstack/spec': path.resolve(__dirname, '../../spec/src/index.ts'),
27+
'@objectstack/types': path.resolve(__dirname, '../../types/src/index.ts'),
28+
},
29+
},
30+
});

packages/plugins/plugin-dev/src/dev-plugin.test.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,25 @@
11
import { describe, it, expect, vi } from 'vitest';
22
import { DevPlugin } from './dev-plugin';
33

4+
// #3060: init()'s graceful-degradation path dynamically imports ~10 real
5+
// workspace packages (objectql, runtime, plugin-auth, …). Under a fully
6+
// parallel `pnpm test` those vite transforms alone can blow past the test
7+
// timeout — the "handle missing deps" test flaked at 15s while passing in
8+
// <100ms standalone. The test's INTENT is "peer deps missing", so make them
9+
// genuinely missing: each factory throws the same shape an absent package
10+
// produces. The degradation branch is exercised for real, with zero real
11+
// module resolution on the hot path. (The stub-contract tests below disable
12+
// all real services, so they never reach these imports.)
13+
// (vi.mock calls are hoisted above any const, so the factories are inline.)
14+
vi.mock('@objectstack/objectql', () => { throw Object.assign(new Error("Cannot find package '@objectstack/objectql'"), { code: 'ERR_MODULE_NOT_FOUND' }); });
15+
vi.mock('@objectstack/runtime', () => { throw Object.assign(new Error("Cannot find package '@objectstack/runtime'"), { code: 'ERR_MODULE_NOT_FOUND' }); });
16+
vi.mock('@objectstack/driver-memory', () => { throw Object.assign(new Error("Cannot find package '@objectstack/driver-memory'"), { code: 'ERR_MODULE_NOT_FOUND' }); });
17+
vi.mock('@objectstack/service-i18n', () => { throw Object.assign(new Error("Cannot find package '@objectstack/service-i18n'"), { code: 'ERR_MODULE_NOT_FOUND' }); });
18+
vi.mock('@objectstack/plugin-auth', () => { throw Object.assign(new Error("Cannot find package '@objectstack/plugin-auth'"), { code: 'ERR_MODULE_NOT_FOUND' }); });
19+
vi.mock('@objectstack/plugin-security', () => { throw Object.assign(new Error("Cannot find package '@objectstack/plugin-security'"), { code: 'ERR_MODULE_NOT_FOUND' }); });
20+
vi.mock('@objectstack/plugin-hono-server', () => { throw Object.assign(new Error("Cannot find package '@objectstack/plugin-hono-server'"), { code: 'ERR_MODULE_NOT_FOUND' }); });
21+
vi.mock('@objectstack/rest', () => { throw Object.assign(new Error("Cannot find package '@objectstack/rest'"), { code: 'ERR_MODULE_NOT_FOUND' }); });
22+
423
describe('DevPlugin', () => {
524
it('should have correct metadata', () => {
625
const plugin = new DevPlugin();
@@ -41,10 +60,12 @@ describe('DevPlugin', () => {
4160
getKernel: vi.fn(),
4261
};
4362

44-
// DevPlugin should not throw even if peer dependencies are missing
63+
// DevPlugin should not throw even if peer dependencies are missing.
64+
// Deps are mocked-away above (#3060), so the default timeout suffices —
65+
// if someone removes the mocks, the slowness resurfaces loudly here.
4566
const plugin = new DevPlugin({ seedAdminUser: false });
4667
await expect(plugin.init(ctx)).resolves.not.toThrow();
47-
}, 15_000);
68+
});
4869

4970
it('should register contract-compliant dev stubs for all core services', async () => {
5071
const registeredServices = new Map<string, any>();
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
// #3071/#3060: alias workspace deps to `src/` so the tests load regardless of
4+
// whether upstream `dist/` has been built — same convention as
5+
// plugin-hono-server. Without this, vitest resolves @objectstack/core through
6+
// its package.json `exports` (dist), which on a fresh tree / CI runner may
7+
// not exist yet.
8+
import { defineConfig } from 'vitest/config';
9+
import path from 'path';
10+
11+
export default defineConfig({
12+
test: {
13+
globals: true,
14+
environment: 'node',
15+
},
16+
resolve: {
17+
alias: {
18+
'@objectstack/core': path.resolve(__dirname, '../../core/src/index.ts'),
19+
'@objectstack/types': path.resolve(__dirname, '../../types/src/index.ts'),
20+
'@objectstack/spec/api': path.resolve(__dirname, '../../spec/src/api/index.ts'),
21+
'@objectstack/spec/contracts': path.resolve(__dirname, '../../spec/src/contracts/index.ts'),
22+
'@objectstack/spec/data': path.resolve(__dirname, '../../spec/src/data/index.ts'),
23+
'@objectstack/spec/kernel': path.resolve(__dirname, '../../spec/src/kernel/index.ts'),
24+
'@objectstack/spec/system': path.resolve(__dirname, '../../spec/src/system/index.ts'),
25+
'@objectstack/spec': path.resolve(__dirname, '../../spec/src/index.ts'),
26+
},
27+
},
28+
});

0 commit comments

Comments
 (0)