test(api-docs): align post-process outputs (#6942)
- read assertions from _build artifacts instead of source specs\n- capture issue 6939 plan for follow-up steps\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>clean-squash
parent
1d200bd719
commit
90260d5d24
|
|
@ -73,11 +73,20 @@ function createTmpRoot(): {
|
|||
productDir: string;
|
||||
specDir: string;
|
||||
specPath: string;
|
||||
buildSpecPath: string;
|
||||
} {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'post-process-test-'));
|
||||
const productDir = path.join(root, 'influxdb3', 'core');
|
||||
const specDir = path.join(productDir, 'v3');
|
||||
const specPath = path.join(specDir, 'openapi.yaml');
|
||||
const buildSpecPath = path.join(
|
||||
root,
|
||||
'_build',
|
||||
'influxdb3',
|
||||
'core',
|
||||
'v3',
|
||||
'openapi.yaml'
|
||||
);
|
||||
|
||||
fs.mkdirSync(specDir, { recursive: true });
|
||||
|
||||
|
|
@ -90,7 +99,7 @@ function createTmpRoot(): {
|
|||
};
|
||||
fs.writeFileSync(path.join(productDir, '.config.yml'), yaml.dump(config));
|
||||
|
||||
return { root, productDir, specDir, specPath };
|
||||
return { root, productDir, specDir, specPath, buildSpecPath };
|
||||
}
|
||||
|
||||
function writeYaml(filePath: string, data: unknown): void {
|
||||
|
|
@ -157,7 +166,7 @@ function assert(name: string, condition: boolean, reason: string): void {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
function testDescriptionSetting(): void {
|
||||
const { root, specDir, specPath } = createTmpRoot();
|
||||
const { root, specDir, specPath, buildSpecPath } = createTmpRoot();
|
||||
try {
|
||||
writeYaml(specPath, makeSpec([{ name: 'Write data' }], ['Write data']));
|
||||
writeYaml(path.join(specDir, 'tags.yml'), {
|
||||
|
|
@ -169,7 +178,7 @@ function testDescriptionSetting(): void {
|
|||
const { exitCode } = runScript(root, 'influxdb3/core');
|
||||
assert('1a. exits 0', exitCode === 0, `exit code was ${exitCode}`);
|
||||
|
||||
const spec = readYaml<OpenApiSpec>(specPath);
|
||||
const spec = readYaml<OpenApiSpec>(buildSpecPath);
|
||||
const tag = spec.tags?.find((t) => t.name === 'Write data');
|
||||
assert(
|
||||
'1b. description applied to tag',
|
||||
|
|
@ -182,7 +191,7 @@ function testDescriptionSetting(): void {
|
|||
}
|
||||
|
||||
function testTagRename(): void {
|
||||
const { root, specDir, specPath } = createTmpRoot();
|
||||
const { root, specDir, specPath, buildSpecPath } = createTmpRoot();
|
||||
try {
|
||||
writeYaml(specPath, makeSpec([{ name: 'Cache data' }], ['Cache data']));
|
||||
writeYaml(path.join(specDir, 'tags.yml'), {
|
||||
|
|
@ -194,7 +203,7 @@ function testTagRename(): void {
|
|||
const { exitCode } = runScript(root, 'influxdb3/core');
|
||||
assert('2a. exits 0', exitCode === 0, `exit code was ${exitCode}`);
|
||||
|
||||
const spec = readYaml<OpenApiSpec>(specPath);
|
||||
const spec = readYaml<OpenApiSpec>(buildSpecPath);
|
||||
const oldTag = spec.tags?.find((t) => t.name === 'Cache data');
|
||||
assert(
|
||||
'2b. old tag name gone from tags[]',
|
||||
|
|
@ -223,7 +232,7 @@ function testTagRename(): void {
|
|||
}
|
||||
|
||||
function testXRelated(): void {
|
||||
const { root, specDir, specPath } = createTmpRoot();
|
||||
const { root, specDir, specPath, buildSpecPath } = createTmpRoot();
|
||||
try {
|
||||
writeYaml(specPath, makeSpec([{ name: 'Write data' }], ['Write data']));
|
||||
writeYaml(path.join(specDir, 'tags.yml'), {
|
||||
|
|
@ -240,7 +249,7 @@ function testXRelated(): void {
|
|||
const { exitCode } = runScript(root, 'influxdb3/core');
|
||||
assert('3a. exits 0', exitCode === 0, `exit code was ${exitCode}`);
|
||||
|
||||
const spec = readYaml<OpenApiSpec>(specPath);
|
||||
const spec = readYaml<OpenApiSpec>(buildSpecPath);
|
||||
const tag = spec.tags?.find((t) => t.name === 'Write data');
|
||||
const related = tag?.['x-related'] as
|
||||
| Array<{ title: string; href: string }>
|
||||
|
|
@ -364,7 +373,7 @@ function testMalformedYamlFails(): void {
|
|||
|
||||
// 8. Info overlay — API-specific content/info.yml
|
||||
function testInfoOverlay(): void {
|
||||
const { root, specDir, specPath } = createTmpRoot();
|
||||
const { root, specDir, specPath, buildSpecPath } = createTmpRoot();
|
||||
try {
|
||||
writeYaml(
|
||||
specPath,
|
||||
|
|
@ -385,7 +394,7 @@ function testInfoOverlay(): void {
|
|||
const { exitCode } = runScript(root, 'influxdb3/core');
|
||||
assert('8a. exits 0', exitCode === 0, `exit code was ${exitCode}`);
|
||||
|
||||
const spec = readYaml<OpenApiSpec>(specPath);
|
||||
const spec = readYaml<OpenApiSpec>(buildSpecPath);
|
||||
assert(
|
||||
'8b. title overridden',
|
||||
spec.info.title === 'Overridden Title',
|
||||
|
|
@ -409,7 +418,7 @@ function testInfoOverlay(): void {
|
|||
|
||||
// 9. Info overlay — product-level fallback
|
||||
function testInfoOverlayProductFallback(): void {
|
||||
const { root, productDir, specPath } = createTmpRoot();
|
||||
const { root, productDir, specPath, buildSpecPath } = createTmpRoot();
|
||||
try {
|
||||
writeYaml(
|
||||
specPath,
|
||||
|
|
@ -428,7 +437,7 @@ function testInfoOverlayProductFallback(): void {
|
|||
const { exitCode } = runScript(root, 'influxdb3/core');
|
||||
assert('9a. exits 0', exitCode === 0, `exit code was ${exitCode}`);
|
||||
|
||||
const spec = readYaml<OpenApiSpec>(specPath);
|
||||
const spec = readYaml<OpenApiSpec>(buildSpecPath);
|
||||
assert(
|
||||
'9b. title from product-level',
|
||||
spec.info.title === 'Product-Level Title',
|
||||
|
|
@ -446,7 +455,7 @@ function testInfoOverlayProductFallback(): void {
|
|||
|
||||
// 10. Servers overlay
|
||||
function testServersOverlay(): void {
|
||||
const { root, specDir, specPath } = createTmpRoot();
|
||||
const { root, specDir, specPath, buildSpecPath } = createTmpRoot();
|
||||
try {
|
||||
writeYaml(
|
||||
specPath,
|
||||
|
|
@ -474,7 +483,7 @@ function testServersOverlay(): void {
|
|||
const { exitCode } = runScript(root, 'influxdb3/core');
|
||||
assert('10a. exits 0', exitCode === 0, `exit code was ${exitCode}`);
|
||||
|
||||
const spec = readYaml<OpenApiSpec>(specPath);
|
||||
const spec = readYaml<OpenApiSpec>(buildSpecPath);
|
||||
assert(
|
||||
'10b. servers replaced',
|
||||
spec.servers?.length === 1,
|
||||
|
|
@ -497,7 +506,7 @@ function testServersOverlay(): void {
|
|||
|
||||
// 11. Info overlay preserves fields not in overlay
|
||||
function testInfoOverlayPreservesFields(): void {
|
||||
const { root, specDir, specPath } = createTmpRoot();
|
||||
const { root, specDir, specPath, buildSpecPath } = createTmpRoot();
|
||||
try {
|
||||
writeYaml(
|
||||
specPath,
|
||||
|
|
@ -521,7 +530,7 @@ function testInfoOverlayPreservesFields(): void {
|
|||
const { exitCode } = runScript(root, 'influxdb3/core');
|
||||
assert('11a. exits 0', exitCode === 0, `exit code was ${exitCode}`);
|
||||
|
||||
const spec = readYaml<OpenApiSpec>(specPath);
|
||||
const spec = readYaml<OpenApiSpec>(buildSpecPath);
|
||||
assert(
|
||||
'11b. title preserved',
|
||||
spec.info.title === 'Original Title',
|
||||
|
|
@ -550,7 +559,7 @@ function testInfoOverlayPreservesFields(): void {
|
|||
|
||||
// 12. No content overlays — spec unchanged
|
||||
function testNoOverlaysNoWrite(): void {
|
||||
const { root, specPath } = createTmpRoot();
|
||||
const { root, specPath, buildSpecPath } = createTmpRoot();
|
||||
try {
|
||||
const original = makeSpec([{ name: 'Write data' }], ['Write data']);
|
||||
writeYaml(specPath, original);
|
||||
|
|
@ -562,12 +571,19 @@ function testNoOverlaysNoWrite(): void {
|
|||
/* busy wait */
|
||||
}
|
||||
|
||||
const { exitCode, stderr } = runScript(root, 'influxdb3/core');
|
||||
const { exitCode } = runScript(root, 'influxdb3/core');
|
||||
assert('12a. exits 0', exitCode === 0, `exit code was ${exitCode}`);
|
||||
|
||||
const built = readYaml<OpenApiSpec>(buildSpecPath);
|
||||
assert(
|
||||
'12b. no write message',
|
||||
!stderr.includes('wrote'),
|
||||
`unexpected write: ${stderr}`
|
||||
'12b. build output matches input when no overlays/tags',
|
||||
JSON.stringify(built) === JSON.stringify(original),
|
||||
'build output differed from source'
|
||||
);
|
||||
assert(
|
||||
'12c. source file untouched',
|
||||
fs.statSync(specPath).mtimeMs === mtime,
|
||||
'source spec modified'
|
||||
);
|
||||
} finally {
|
||||
cleanup(root);
|
||||
|
|
@ -576,7 +592,7 @@ function testNoOverlaysNoWrite(): void {
|
|||
|
||||
// 13. Combined: info + servers + tags applied together
|
||||
function testCombinedOverlaysAndTags(): void {
|
||||
const { root, specDir, specPath } = createTmpRoot();
|
||||
const { root, specDir, specPath, buildSpecPath } = createTmpRoot();
|
||||
try {
|
||||
writeYaml(
|
||||
specPath,
|
||||
|
|
@ -607,7 +623,7 @@ function testCombinedOverlaysAndTags(): void {
|
|||
const { exitCode } = runScript(root, 'influxdb3/core');
|
||||
assert('13a. exits 0', exitCode === 0, `exit code was ${exitCode}`);
|
||||
|
||||
const spec = readYaml<OpenApiSpec>(specPath);
|
||||
const spec = readYaml<OpenApiSpec>(buildSpecPath);
|
||||
assert(
|
||||
'13b. info title updated',
|
||||
spec.info.title === 'New Title',
|
||||
|
|
@ -667,7 +683,7 @@ const tests: Array<[string, () => void]> = [
|
|||
'11. Info overlay preserves fields not in overlay',
|
||||
testInfoOverlayPreservesFields,
|
||||
],
|
||||
['12. No overlays or tags — no write', testNoOverlaysNoWrite],
|
||||
['12. No overlays or tags — build mirrors source', testNoOverlaysNoWrite],
|
||||
['13. Combined: info + servers + tags', testCombinedOverlaysAndTags],
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
## Issue #6939 plan
|
||||
|
||||
### Summary
|
||||
|
||||
- PR #6939 overhauls the API docs pipeline: a unified TypeScript post-processor (`api-docs/scripts/post-process-specs.ts`) writes resolved specs to `_build/`, Redoc and static copies read from `_build/`, and workflows add a TypeScript compile step.
|
||||
- We need to review and harden the new script and workflows, focusing on correctness when overlays/tags are absent and ensuring CI/previews run the build steps in the right order.
|
||||
|
||||
### Files to touch
|
||||
|
||||
- `api-docs/scripts/post-process-specs.ts` — adjust write/log behavior when no overlays/tags are applied and ensure output handling is correct (lines \~350-395).
|
||||
- `api-docs/scripts/test-post-process-specs.ts` — align tests with expected write/log behavior and add coverage if needed (lines \~552-575).
|
||||
- `.circleci/config.yml` — confirm/adjust API docs build step ordering and TypeScript compile inclusion (lines \~24-35).
|
||||
- `.github/workflows/pr-preview.yml` — ensure PR preview runs TypeScript compile + API docs generation when API docs change (lines \~118-150).
|
||||
- (If needed) `api-docs/generate-api-docs.sh` — keep pipeline steps in sync (lines \~52-68).
|
||||
|
||||
### Approach
|
||||
|
||||
1. Run the PR’s test plan locally to surface current failures: `npx tsc --project api-docs/scripts/tsconfig.json`, `node api-docs/scripts/dist/post-process-specs.js`, `node api-docs/scripts/dist/generate-openapi-articles.js --static-only`, and `npx hugo --quiet` (accepting the runtime). Note existing untracked artifacts (`content/enterprise_influxdb/v1/api/v1/`, `static/openapi/`) to avoid clobbering.
|
||||
2. Review `post-process-specs.ts` logic around overlays/tags and output writes; ensure it skips unnecessary writes/logs while still producing required `_build` outputs for downstream steps.
|
||||
3. Update tests in `test-post-process-specs.ts` to reflect the intended behavior (particularly the “no overlays” case) and add assertions for `_build` outputs if needed.
|
||||
4. Validate CI wiring: confirm `.circleci/config.yml` and `pr-preview.yml` run TypeScript compile before API docs generation and don’t skip API steps incorrectly.
|
||||
5. Re-run the pipeline commands after changes; ensure Hugo/build/test outputs are clean, then prepare for branch/commit per guidelines.
|
||||
|
||||
### Risks / Open questions
|
||||
|
||||
- Hugo build is long (\~75s) and must not be canceled.
|
||||
- If any product lacks overlays/tags, skipping writes could leave `_build` empty; need to balance no-op behavior with required outputs.
|
||||
- Existing untracked API outputs may obscure diffs; keep them untouched.
|
||||
Loading…
Reference in New Issue