From 94643ffceb9cc33f3da3e1ef88e8ea57765556e1 Mon Sep 17 00:00:00 2001 From: sudacode Date: Sun, 23 Aug 2026 03:57:21 -0700 Subject: [PATCH] test(release): ignore shell comments when matching workflow commands Matching a step's whole run body meant a commented-out command satisfied the ordering assertion, so commenting out the prerelease notes check left the test green while the workflow no longer validated anything. Match executable lines only, and fold the version argument into the same match so dropping it also fails. --- src/prerelease-workflow.test.ts | 11 +++++------ src/workflow-test-helpers.ts | 13 +++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/prerelease-workflow.test.ts b/src/prerelease-workflow.test.ts index 371be2c2..ce162f11 100644 --- a/src/prerelease-workflow.test.ts +++ b/src/prerelease-workflow.test.ts @@ -5,6 +5,7 @@ import { resolve } from 'node:path'; import { jobSteps, readWorkflow, + stepRunsCommand, stepsMissingEnvDeclaration, templateExpressionsInRunBodies, } from './workflow-test-helpers'; @@ -136,20 +137,18 @@ test('prerelease workflow rejects committed notes generated for a different beta 'bun run scripts/build-changelog.ts check-prerelease-notes', ); + // Matched against executable lines only, so commenting the check out fails the + // test rather than silently satisfying it. const steps = jobSteps(parsedPrereleaseWorkflow, 'release'); const checkIndex = steps.findIndex((step) => - step.run?.includes('changelog:check-prerelease-notes'), + stepRunsCommand(step, /changelog:check-prerelease-notes --version "\$RELEASE_VERSION"/), ); - const publishIndex = steps.findIndex((step) => /gh release (create|edit)/.test(step.run ?? '')); + const publishIndex = steps.findIndex((step) => stepRunsCommand(step, /gh release (create|edit)/)); assert.notEqual(checkIndex, -1); assert.notEqual(publishIndex, -1); // Stale notes are already published if the check runs after the release. assert.ok(checkIndex < publishIndex); - assert.match( - steps[checkIndex]!.run!, - /changelog:check-prerelease-notes --version "\$RELEASE_VERSION"/, - ); }); test('prerelease workflow keeps tag-derived values out of shell bodies', () => { diff --git a/src/workflow-test-helpers.ts b/src/workflow-test-helpers.ts index 6771988c..7d93b196 100644 --- a/src/workflow-test-helpers.ts +++ b/src/workflow-test-helpers.ts @@ -42,6 +42,19 @@ function allSteps(workflow: ParsedWorkflow): Array<{ job: string; step: Workflow ); } +// Lines of a step's shell body that actually execute. Comments are dropped so a +// commented-out command cannot satisfy a "this step runs X" assertion. +export function executableRunLines(step: WorkflowStep): string[] { + return (typeof step.run === 'string' ? step.run.split('\n') : []) + .map((line) => line.trim()) + .filter((line) => line.length > 0 && !line.startsWith('#')); +} + +// Whether a step actually executes a command matching the pattern. +export function stepRunsCommand(step: WorkflowStep, pattern: RegExp): boolean { + return executableRunLines(step).some((line) => pattern.test(line)); +} + // GitHub substitutes ${{ }} into a run script before the shell parses it, so any // value used that way is executed as script rather than read as data. Reporting // every expression (rather than allow-listing known-safe ones) also covers