From f2320a6c3bc497c9c302e28dcda1f5d46d94f901 Mon Sep 17 00:00:00 2001 From: Jason Kummerl Date: Fri, 2 Oct 2026 16:03:08 -0400 Subject: [PATCH] fix(ci): initialize release state on the runner --- .github/release-source.json | 6 ++-- .github/scripts/release-workflow.test.mjs | 40 ++++++++++++++++++++++- .github/workflows/npm-publish.yml | 5 ++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/.github/release-source.json b/.github/release-source.json index d60c0ca..6a0c270 100644 --- a/.github/release-source.json +++ b/.github/release-source.json @@ -2,11 +2,11 @@ "files": { ".github/scripts/release-publication.mjs": "c03d90062b6fcb38e11f9bb4cb5fd8c9a14a34a56bb67870f64d81af43f56e8e", ".github/scripts/release-publication.test.mjs": "a6176fdcf61b0d118670ce1d43a09f39a12d4171e1ab6fed7960dfe048145ebf", - ".github/scripts/release-workflow.test.mjs": "7a9e393cad156ac86e19b4b6aa1c72afedd5a6012652c6459e288f501ab43609", + ".github/scripts/release-workflow.test.mjs": "3a131742d49cb7e643ddfbc91582a9c9722f7bce9cbb6976a1a4e9097ff77243", ".github/workflows/coveralls.yml": "4e92a83a53ab4c4ffbe7e27383ab3488435c93e8b91b44f728f0b9ce311d5994", - ".github/workflows/npm-publish.yml": "bf5d43aae4d5a4bca63955af84356329ef31aeb85e379f716b00f765eae53184", + ".github/workflows/npm-publish.yml": "122af9f83944baaaf84888820d3926129f15092db20dfceef56f82efda0d279a", ".github/workflows/run-tests.yml": "f9ffe81a4eca264698490391697ad5911cf2e723e13e282e6904bb732606a8b6" }, "repository": "humanspeak/docs-kit", - "revision": "1ba2cdbd682d0c6c11e0937147919565d88b9949" + "revision": "cd74e655507ae20931f82f3bdb954503dce3bab3" } diff --git a/.github/scripts/release-workflow.test.mjs b/.github/scripts/release-workflow.test.mjs index c49b097..c0ae494 100644 --- a/.github/scripts/release-workflow.test.mjs +++ b/.github/scripts/release-workflow.test.mjs @@ -1,5 +1,9 @@ import assert from 'node:assert/strict' -import { readFileSync } from 'node:fs' +import { execFileSync } from 'node:child_process' +import { mkdtempSync, readFileSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { env } from 'node:process' import test from 'node:test' import { fileURLToPath, URL } from 'node:url' import { selectBaseline, validateMetadata } from './release-publication.mjs' @@ -9,6 +13,40 @@ const read = (path) => readFileSync(`${root}${path}`, 'utf8') const policy = JSON.parse(read('.github/release-policy.json')) const workflow = policy.event === 'calver' ? null : read('.github/workflows/npm-publish.yml') +test('release state is initialized on the runner outside checkout and isolated by attempt', () => { + const releaseWorkflow = workflow ?? read('.github/workflows/release.yml') + const job = releaseWorkflow + .split(policy.event === 'calver' ? ' release:\n' : ' publish-github-packages:\n')[1] + .split(/\n {4}[a-z][\w-]*:\n/)[0] + assert.doesNotMatch(job.split(' steps:\n')[0], /\$\{\{\s*runner\./) + const initialization = job.split(' - name: Initialize release state path\n')[1] + assert.ok(initialization, 'Release state must be initialized by a runner step') + const script = initialization.split(/\n {12}- /)[0].split(' run: |\n')[1] + assert.ok(job.indexOf('Initialize release state path') < job.indexOf('uses: actions/checkout@')) + const directory = mkdtempSync(join(tmpdir(), 'release-state-environment-')) + try { + for (const attempt of ['1', '2']) { + const environment = join(directory, `environment-${attempt}`) + execFileSync('/bin/bash', ['--noprofile', '--norc', '-eu', '-c', script], { + cwd: root, + env: { + PATH: env.PATH, + RUNNER_TEMP: directory, + GITHUB_ENV: environment, + GITHUB_RUN_ID: '12345', + GITHUB_RUN_ATTEMPT: attempt + } + }) + assert.equal( + readFileSync(environment, 'utf8'), + `RELEASE_STATE=${directory}/release-12345-${attempt}.json\n` + ) + } + } finally { + rmSync(directory, { recursive: true, force: true }) + } +}) + test('consumer policy rejects unowned manifest, dependency, lockfile, and README changes', () => { for (const config of [ { manifests: ['package.json'], lockfile: null, readme: 'unchanged' }, diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index da37ddf..5a99477 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -151,7 +151,6 @@ jobs: needs: [build, coverage-report, prepare] runs-on: ubuntu-24.04 env: - RELEASE_STATE: ${{ runner.temp }}/release-${{ github.run_id }}-${{ github.run_attempt }}.json PREPARED_SHA: ${{ needs.prepare.outputs.checkout_sha }} permissions: contents: write @@ -161,6 +160,10 @@ jobs: id-token: write steps: + - name: Initialize release state path + run: | + printf 'RELEASE_STATE=%s/release-%s-%s.json\n' "$RUNNER_TEMP" "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" >> "$GITHUB_ENV" + - name: Checkout uses: actions/checkout@v4 with: