diff --git a/.changeset/owner-workflow-generation.md b/.changeset/owner-workflow-generation.md new file mode 100644 index 00000000..e271ad83 --- /dev/null +++ b/.changeset/owner-workflow-generation.md @@ -0,0 +1,5 @@ +--- +'@ankhorage/devtools': patch +--- + +Keep Devtools owner-generated workflows self-hosted and normalize rendered workflow files to one terminal newline. diff --git a/src/owner/synchronizeRenovateOwnerAsync.test.ts b/src/owner/synchronizeRenovateOwnerAsync.test.ts index f4470e47..6ab3e29f 100644 --- a/src/owner/synchronizeRenovateOwnerAsync.test.ts +++ b/src/owner/synchronizeRenovateOwnerAsync.test.ts @@ -38,7 +38,10 @@ describe('Devtools Renovate owner synchronization', () => { expect(first.readme).toContain('Bun runtime 1.4.2'); expect(first.readme).toContain('@types/bun ^1.4.1'); expect(first.ci).toContain("bun-version: '1.4.2'"); + expect(first.ci).toContain('node ./dist/cli/bin/apm-release.js validate . --allow-owner-code'); expect(first.release).toContain("bun-version: '1.4.2'"); + expect(first.release).toContain('node ./dist/cli/bin/apm-release.js sync .'); + expect(first.release).toContain('node ./dist/cli/bin/structure.js build .'); expect(first.renovate).toMatch(/changeset\.yml@[0-9a-f]{40}/u); expect(await readFile(unrelatedPath, 'utf8')).toBe('leave me alone\n'); diff --git a/src/owner/synchronizeRenovateOwnerAsync.ts b/src/owner/synchronizeRenovateOwnerAsync.ts index 371f6f2a..87b79f6c 100644 --- a/src/owner/synchronizeRenovateOwnerAsync.ts +++ b/src/owner/synchronizeRenovateOwnerAsync.ts @@ -2,12 +2,17 @@ import { spawn } from 'node:child_process'; import { mkdir, readFile, writeFile } from 'node:fs/promises'; import { dirname, resolve } from 'node:path'; +import { resolveApmReleaseCommandAsync } from '../features/apm-release-validation/adapters/outbound/resolveApmReleaseCommandAsync.js'; +import { resolveStructureReleaseCommandAsync } from '../features/structure-descriptor-generation/adapters/outbound/resolveStructureReleaseCommandAsync.js'; import { applyBunRuntimePolicy } from '../policy/applyBunRuntimePolicy.js'; import { nodeRuntimePolicy } from '../policy/bunRuntimePolicy.js'; import { renderBunPolicyDocumentation } from '../policy/renderBunPolicyDocumentation.js'; import { readCurrentDoctorVersion } from '../tools/workflows/readCurrentDoctorVersion.js'; import { renderRenovateWorkflowAsync } from '../tools/workflows/renderRenovateWorkflowAsync.js'; -import { renderWorkflowAsync } from '../tools/workflows/renderWorkflowAsync.js'; +import { + renderWorkflowAsync, + type WorkflowPolicy, +} from '../tools/workflows/renderWorkflowAsync.js'; import type { BunPolicy } from '../types/bunPolicy.js'; /*** Synchronize or validate Renovate-owned Devtools policy artifacts. */ @@ -73,11 +78,7 @@ async function createManagedDefinitionsAsync( } const readme = await readFile(resolve(targetDirectory, 'README.md'), 'utf8'); - const workflowPolicy = { - bunVersion: policy.version, - doctorVersion: readCurrentDoctorVersion(), - nodeVersion: nodeRuntimePolicy.setupVersion, - }; + const workflowPolicy = await createWorkflowPolicyAsync(targetDirectory, policy); return [ { @@ -113,6 +114,20 @@ async function createManagedDefinitionsAsync( ]; } +/*** Build the self-hosted workflow policy used by Devtools owner synchronization. */ +async function createWorkflowPolicyAsync( + targetDirectory: string, + policy: BunPolicy, +): Promise { + return { + apmReleaseCommand: await resolveApmReleaseCommandAsync(targetDirectory), + structureReleaseCommand: await resolveStructureReleaseCommandAsync(targetDirectory), + bunVersion: policy.version, + doctorVersion: readCurrentDoctorVersion(), + nodeVersion: nodeRuntimePolicy.setupVersion, + }; +} + /*** Return owner-managed artifact paths whose current bytes differ from policy output. */ async function getOutdatedPathsAsync( targetDirectory: string, diff --git a/src/tools/workflows/index.test.ts b/src/tools/workflows/index.test.ts index 715604b7..60672b58 100644 --- a/src/tools/workflows/index.test.ts +++ b/src/tools/workflows/index.test.ts @@ -170,6 +170,8 @@ describe('managed PKGViz audit', () => { expect(ci).not.toContain('Enforce PKGViz cyclic-dependencies rule'); expect(ci).not.toContain('pkgviz-audit.json'); + expect(ci?.endsWith('\n')).toBe(true); + expect(ci?.endsWith('\n\n')).toBe(false); }); }); diff --git a/src/tools/workflows/renderWorkflowAsync.ts b/src/tools/workflows/renderWorkflowAsync.ts index dcf3f890..0775c6cc 100644 --- a/src/tools/workflows/renderWorkflowAsync.ts +++ b/src/tools/workflows/renderWorkflowAsync.ts @@ -18,7 +18,7 @@ export interface WorkflowPolicy { /*** Renders one workflow template with the canonical runtime, Doctor, and Changesets policy. */ export async function renderWorkflowAsync(sourceUrl: URL, policy: WorkflowPolicy): Promise { const template = await readFile(sourceUrl, 'utf8'); - return template + const rendered = template .replaceAll(BUN_VERSION_TOKEN, policy.bunVersion) .replaceAll(PKGVIZ_AUDIT_STEPS_TOKEN, renderPkgvizAuditSteps(policy)) .replaceAll(CHANGESETS_PUBLISH_COMMAND_TOKEN, changesetsPolicy.workflowCommands.publish) @@ -34,6 +34,7 @@ export async function renderWorkflowAsync(sourceUrl: URL, policy: WorkflowPolicy policy.structureReleaseCommand ?? './node_modules/.bin/ankhorage-structure', ) .replaceAll(NODE_VERSION_TOKEN, policy.nodeVersion); + return `${rendered.trimEnd()}\n`; } const BUN_VERSION_TOKEN = '__ANKH_BUN_VERSION__';