mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-25 00:15:27 -07:00
feat(release): track prerelease deltas and validate committed notes (#216)
Co-authored-by: sudacode <claude@lmaoxd.lol>
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
commandPositions,
|
||||
executableRunLines,
|
||||
stepRunsCommand,
|
||||
stepsMissingEnvDeclaration,
|
||||
templateExpressionsInRunBodies,
|
||||
} from './workflow-test-helpers';
|
||||
|
||||
const runs = (run: string): boolean => stepRunsCommand({ run }, /^bun run verify --flag "\$VALUE"/);
|
||||
|
||||
test('stepRunsCommand matches a command that actually executes', () => {
|
||||
assert.equal(runs('bun run verify --flag "$VALUE"'), true);
|
||||
assert.equal(runs('if ! bun run verify --flag "$VALUE"; then\nexit 1\nfi'), true);
|
||||
assert.equal(runs('set -e && bun run verify --flag "$VALUE"'), true);
|
||||
assert.equal(runs(' bun run verify --flag "$VALUE" || exit 1'), true);
|
||||
});
|
||||
|
||||
test('stepRunsCommand rejects commands that are only mentioned, not run', () => {
|
||||
assert.equal(runs('# bun run verify --flag "$VALUE"'), false);
|
||||
assert.equal(runs('echo \'bun run verify --flag "$VALUE"\''), false);
|
||||
assert.equal(runs("printf '%s\\n' 'bun run verify --flag \"$VALUE\"'"), false);
|
||||
assert.equal(runs('echo "run: bun run verify --flag \\"$VALUE\\"" >> notes.txt'), false);
|
||||
// A different argument list is a different command.
|
||||
assert.equal(runs('bun run verify'), false);
|
||||
});
|
||||
|
||||
test('stepRunsCommand ignores separators inside quotes and inline comments', () => {
|
||||
assert.equal(runs('echo \'note; bun run verify --flag "$VALUE"\''), false);
|
||||
assert.equal(runs('echo "note && bun run verify --flag \\"$VALUE\\""'), false);
|
||||
assert.equal(runs("printf '%s\\n' 'a | bun run verify --flag \"$VALUE\"'"), false);
|
||||
assert.equal(runs('if false; then # bun run verify --flag "$VALUE"'), false);
|
||||
// A trailing comment does not hide the command in front of it.
|
||||
assert.equal(runs('bun run verify --flag "$VALUE" # keep this'), true);
|
||||
// A pipe is a real separator; a redirect is not.
|
||||
assert.equal(runs('cat notes | bun run verify --flag "$VALUE"'), true);
|
||||
assert.equal(stepRunsCommand({ run: 'gh release view "$V" 2>&1 | tee log' }, /^tee\b/), true);
|
||||
});
|
||||
|
||||
test('stepRunsCommand treats backslash-escaped separators as literal text', () => {
|
||||
assert.equal(runs(String.raw`echo foo \; bun run verify --flag "$VALUE"`), false);
|
||||
assert.equal(runs(String.raw`echo foo \| bun run verify --flag "$VALUE"`), false);
|
||||
assert.equal(runs(String.raw`find . -exec bun run verify --flag "$VALUE" \;`), false);
|
||||
// An escape does not swallow a following real separator.
|
||||
assert.equal(runs(String.raw`echo a\b; bun run verify --flag "$VALUE"`), true);
|
||||
});
|
||||
|
||||
test('commandPositions splits on separators and strips control-flow prefixes', () => {
|
||||
assert.deepEqual(
|
||||
commandPositions({ run: 'if gh release view "$V"; then\ngh release edit "$V"\nfi' }),
|
||||
['gh release view "$V"', 'then', 'gh release edit "$V"', 'fi'],
|
||||
);
|
||||
});
|
||||
|
||||
test('executableRunLines drops blank and comment-only lines', () => {
|
||||
assert.deepEqual(executableRunLines({ run: '\n# a comment\n \nreal command\n' }), [
|
||||
'real command',
|
||||
]);
|
||||
});
|
||||
|
||||
test('templateExpressionsInRunBodies reports every expression spelling in a run body', () => {
|
||||
const workflow = {
|
||||
jobs: {
|
||||
release: {
|
||||
steps: [
|
||||
{ name: 'Safe', env: { V: '${{ steps.version.outputs.VERSION }}' }, run: 'echo "$V"' },
|
||||
{ name: 'Dotted', run: 'echo "${{ steps.version.outputs.VERSION }}"' },
|
||||
{ name: 'Bracketed', run: 'echo "${{ steps.version.outputs[\'VERSION\'] }}"' },
|
||||
{ name: 'Github', run: 'echo "${{ github[\'ref_name\'] }}"' },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
assert.deepEqual(templateExpressionsInRunBodies(workflow), [
|
||||
'release/Dotted: ${{ steps.version.outputs.VERSION }}',
|
||||
"release/Bracketed: ${{ steps.version.outputs['VERSION'] }}",
|
||||
"release/Github: ${{ github['ref_name'] }}",
|
||||
]);
|
||||
});
|
||||
|
||||
test('stepsMissingEnvDeclaration finds shell reads with no matching env entry', () => {
|
||||
const workflow = {
|
||||
jobs: {
|
||||
release: {
|
||||
steps: [
|
||||
{ name: 'Declared', env: { TAG: 'x' }, run: 'echo "$TAG"' },
|
||||
{ name: 'Undeclared', run: 'echo "${TAG}"' },
|
||||
{ name: 'Unrelated', run: 'echo "$TAGGED"' },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
assert.deepEqual(stepsMissingEnvDeclaration(workflow, 'TAG'), ['release/Undeclared']);
|
||||
});
|
||||
Reference in New Issue
Block a user