Skip to content

Commit ccd939c

Browse files
Guard release workflow tag docs
1 parent 23751c2 commit ccd939c

4 files changed

Lines changed: 76 additions & 2 deletions

File tree

.github/workflows/ray-core-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ name: "@razroo/ray-core Release to npm"
44
#
55
# Cutting a release (after bumping packages/core/package.json version):
66
# TAG="core-v$(bun -e 'console.log(require("./packages/core/package.json").version)')"
7-
# git tag "$TAG" && git push origin "$TAG"
7+
# git tag -a "$TAG" -m "Release $TAG (@razroo/ray-core)" && git push origin "$TAG"
88
# gh release create "$TAG" --generate-notes --title "$TAG"
99

1010
on:

.github/workflows/ray-sdk-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ name: "@razroo/ray-sdk Release to npm"
55
#
66
# Cutting a release (after bumping packages/sdk/package.json version):
77
# TAG="sdk-v$(bun -e 'console.log(require("./packages/sdk/package.json").version)')"
8-
# git tag "$TAG" && git push origin "$TAG"
8+
# git tag -a "$TAG" -m "Release $TAG (@razroo/ray-sdk)" && git push origin "$TAG"
99
# gh release create "$TAG" --generate-notes --title "$TAG"
1010

1111
on:

scripts/package-runtime-coverage.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,51 @@ test("validatePackageRuntimeCoverage requires bounded npm release workflow comma
11031103
assert.ok(codes.includes("workflow_npm_publish_timeout_missing"));
11041104
});
11051105

1106+
test("validatePackageRuntimeCoverage rejects lightweight release tag workflow comments", async (t) => {
1107+
const tempDir = await mkdtemp(path.join(tmpdir(), "ray-package-runtime-release-tag-docs-"));
1108+
t.after(async () => {
1109+
await rm(tempDir, { recursive: true, force: true });
1110+
});
1111+
const workflowDir = path.join(tempDir, ".github", "workflows");
1112+
await mkdir(workflowDir, { recursive: true });
1113+
await writeFile(
1114+
path.join(workflowDir, "ray-core-release.yml"),
1115+
[
1116+
'name: "@razroo/ray-core Release to npm"',
1117+
'# TAG="core-v$(bun -e \'console.log(require("./packages/core/package.json").version)\')"',
1118+
'# git tag "$TAG" && git push origin "$TAG"',
1119+
"jobs:",
1120+
" publish:",
1121+
" if: github.repository == 'razroo/ray'",
1122+
" runs-on: ubuntu-latest",
1123+
" timeout-minutes: 60",
1124+
" permissions:",
1125+
" id-token: write",
1126+
" steps:",
1127+
" - run: timeout 120s git fetch --no-tags --prune origin main:refs/remotes/origin/main",
1128+
' - run: git merge-base --is-ancestor "$SHA" refs/remotes/origin/main',
1129+
" - run: timeout 300s npm publish ./pkg.tgz --access public --provenance",
1130+
" env:",
1131+
" NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}",
1132+
"",
1133+
].join("\n"),
1134+
);
1135+
1136+
const summary = await validatePackageRuntimeCoverage({
1137+
cwd: tempDir,
1138+
packageJsonPaths: [],
1139+
});
1140+
const diagnostics = summary.results.flatMap((result) => result.diagnostics);
1141+
1142+
assert.equal(summary.ok, false);
1143+
assert.ok(
1144+
diagnostics.some(
1145+
(diagnostic) =>
1146+
diagnostic.code === "workflow_npm_release_lightweight_tag_doc" && diagnostic.line === 3,
1147+
),
1148+
);
1149+
});
1150+
11061151
test("validatePackageRuntimeCoverage requires bounded quality release gate workflow commands", async (t) => {
11071152
const tempDir = await mkdtemp(path.join(tmpdir(), "ray-package-runtime-quality-timeouts-"));
11081153
t.after(async () => {

scripts/package-runtime-coverage.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ const workflowReleaseMainAncestryPattern =
6969
/git\s+merge-base\s+--is-ancestor\s+"\$SHA"\s+refs\/remotes\/origin\/main/;
7070
const workflowIdTokenWritePattern = /^\s*id-token:\s*write\s*$/m;
7171
const workflowNpmTokenPattern = /NODE_AUTH_TOKEN:\s*\$\{\{\s*secrets\.NPM_TOKEN\s*\}\}/;
72+
const workflowLightweightReleaseTagCommentPattern = /^\s*#\s*git\s+tag\s+"\$TAG"(?:\s|$)/;
7273
const repoOwnedVpsWorkflowDocPattern =
7374
/\b(?:GitHub VPS workflow|workflow bootstrap|workflow appends|RAY_ENV_FILE_CONTENTS|repository variables|The deploy workflow)\b/;
7475

@@ -1848,6 +1849,32 @@ function validateDeployWorkflowRayEnvReadGuards(
18481849
return diagnostics;
18491850
}
18501851

1852+
function validateNpmReleaseWorkflowTagDocs(
1853+
workflowPath: string,
1854+
publishesToNpm: boolean,
1855+
lines: string[],
1856+
): PackageRuntimeCoverageDiagnostic[] {
1857+
if (!publishesToNpm) {
1858+
return [];
1859+
}
1860+
1861+
const diagnostics: PackageRuntimeCoverageDiagnostic[] = [];
1862+
for (const [index, rawLine] of lines.entries()) {
1863+
if (workflowLightweightReleaseTagCommentPattern.test(rawLine)) {
1864+
diagnostics.push({
1865+
level: "error",
1866+
code: "workflow_npm_release_lightweight_tag_doc",
1867+
workflowPath,
1868+
line: index + 1,
1869+
message:
1870+
"npm release workflow cutting comments must use annotated git tags so operator docs do not recommend lightweight release tags.",
1871+
});
1872+
}
1873+
}
1874+
1875+
return diagnostics;
1876+
}
1877+
18511878
async function validateWorkflow(
18521879
workflowPath: string,
18531880
): Promise<{ lineCount: number; diagnostics: PackageRuntimeCoverageDiagnostic[] }> {
@@ -1913,6 +1940,8 @@ async function validateWorkflow(
19131940
});
19141941
}
19151942

1943+
diagnostics.push(...validateNpmReleaseWorkflowTagDocs(workflowPath, publishesToNpm, lines));
1944+
19161945
if (runsReleaseGate && !hasJobTimeout) {
19171946
diagnostics.push({
19181947
level: "error",

0 commit comments

Comments
 (0)