Compare commits

...

7 Commits

Author SHA1 Message Date
Michael B. Gale 25599b3fc8 Use doc.toString rather than yaml.stringify 2026-03-09 14:29:04 +00:00
Michael B. Gale 639dddc728 Add missing newline at the end of action-versions.ts 2026-03-09 14:29:04 +00:00
Michael B. Gale 0b27c71731 Generate and use action-versions.ts 2026-03-07 00:29:11 +00:00
Michael B. Gale 6679b049d5 Generate separate TS file with version mappings 2026-03-07 00:24:18 +00:00
Michael B. Gale 13e47f85a5 Type options and add --force option 2026-03-07 00:24:17 +00:00
Michael B. Gale 5f152be4c2 Minor adjustments to PR check templates
These are needed to render them correctly in `sync_back.ts`
2026-03-06 23:40:49 +00:00
Michael B. Gale f4b6bd982f Parse/render YAML documents for sync_back.ts 2026-03-06 19:56:16 +00:00
7 changed files with 291 additions and 173 deletions
+30
View File
@@ -0,0 +1,30 @@
export const ACTION_VERSIONS = {
"actions/checkout": {
"version": "v6"
},
"actions/setup-go": {
"version": "v6"
},
"actions/setup-dotnet": {
"version": "v5"
},
"actions/upload-artifact": {
"version": "v7"
},
"actions/github-script": {
"version": "v8"
},
"actions/setup-python": {
"version": "v6"
},
"actions/setup-java": {
"version": "v5"
},
"actions/setup-node": {
"version": "v6"
},
"ruby/setup-ruby": {
"version": "09a7688d3b55cf0e976497ff046b70949eeaccfd",
"comment": " v1.288.0"
}
};
@@ -1,5 +1,5 @@
name: "Autobuild direct tracing (custom working directory)" name: "Autobuild direct tracing (custom working directory)"
description: > description: |
An end-to-end integration test of a Java repository built using 'build-mode: autobuild', An end-to-end integration test of a Java repository built using 'build-mode: autobuild',
with direct tracing enabled and a custom working directory specified as the input to the with direct tracing enabled and a custom working directory specified as the input to the
autobuild Action. autobuild Action.
+8 -9
View File
@@ -4,12 +4,11 @@
# basic mechanics of multi-registry auth is working. # basic mechanics of multi-registry auth is working.
name: "Packaging: Download using registries" name: "Packaging: Download using registries"
description: "Checks that specifying a registries block and associated auth works as expected" description: "Checks that specifying a registries block and associated auth works as expected"
versions: [ versions:
# This feature is not compatible with older CLIs # This feature is not compatible with older CLIs
"default", - "default"
"linked", - "linked"
"nightly-latest", - "nightly-latest"
]
permissions: permissions:
contents: read contents: read
@@ -24,9 +23,9 @@ steps:
config-file: ./.github/codeql/codeql-config-registries.yml config-file: ./.github/codeql/codeql-config-registries.yml
languages: javascript languages: javascript
registries: | registries: |
- url: "https://ghcr.io/v2/" - url: "https://ghcr.io/v2/"
packages: "*/*" packages: "*/*"
token: "${{ secrets.GITHUB_TOKEN }}" token: "${{ secrets.GITHUB_TOKEN }}"
- name: Verify packages installed - name: Verify packages installed
run: | run: |
+1 -1
View File
@@ -4,7 +4,7 @@ versions: ["linked", "nightly-latest"]
steps: steps:
- uses: ./../action/init - uses: ./../action/init
with: with:
languages: actions # Any language without overlay support will do languages: actions # Any language without overlay support will do
tools: ${{ steps.prepare-test.outputs.tools-url }} tools: ${{ steps.prepare-test.outputs.tools-url }}
env: env:
CODEQL_OVERLAY_DATABASE_MODE: overlay-base CODEQL_OVERLAY_DATABASE_MODE: overlay-base
+17 -6
View File
@@ -5,6 +5,8 @@ import * as path from "path";
import * as yaml from "yaml"; import * as yaml from "yaml";
import { ACTION_VERSIONS } from "./action-versions";
/** Known workflow input names. */ /** Known workflow input names. */
enum KnownInputName { enum KnownInputName {
GoVersion = "go-version", GoVersion = "go-version",
@@ -13,6 +15,9 @@ enum KnownInputName {
DotnetVersion = "dotnet-version", DotnetVersion = "dotnet-version",
} }
/** Known Action names that we have version information for. */
type KnownAction = keyof typeof ACTION_VERSIONS;
/** /**
* Represents workflow input definitions. * Represents workflow input definitions.
*/ */
@@ -94,6 +99,12 @@ const THIS_DIR = __dirname;
const CHECKS_DIR = path.join(THIS_DIR, "checks"); const CHECKS_DIR = path.join(THIS_DIR, "checks");
const OUTPUT_DIR = path.join(THIS_DIR, "..", ".github", "workflows"); const OUTPUT_DIR = path.join(THIS_DIR, "..", ".github", "workflows");
/** Gets an `actionName@ref` string for `actionName`. */
function getActionRef(actionName: KnownAction): string {
const versionInfo = ACTION_VERSIONS[actionName];
return `${actionName}@${versionInfo.version}`;
}
/** /**
* Loads and parses a YAML file. * Loads and parses a YAML file.
*/ */
@@ -216,7 +227,7 @@ function main(): void {
const steps: any[] = [ const steps: any[] = [
{ {
name: "Check out repository", name: "Check out repository",
uses: "actions/checkout@v6", uses: getActionRef("actions/checkout"),
}, },
]; ];
@@ -226,7 +237,7 @@ function main(): void {
steps.push( steps.push(
{ {
name: "Install Node.js", name: "Install Node.js",
uses: "actions/setup-node@v6", uses: getActionRef("actions/setup-node"),
with: { with: {
"node-version": "20.x", "node-version": "20.x",
cache: "npm", cache: "npm",
@@ -265,7 +276,7 @@ function main(): void {
steps.push({ steps.push({
name: "Install Go", name: "Install Go",
uses: "actions/setup-go@v6", uses: getActionRef("actions/setup-go"),
with: { with: {
"go-version": "go-version":
"${{ inputs.go-version || '" + baseGoVersionExpr + "' }}", "${{ inputs.go-version || '" + baseGoVersionExpr + "' }}",
@@ -289,7 +300,7 @@ function main(): void {
steps.push({ steps.push({
name: "Install Java", name: "Install Java",
uses: "actions/setup-java@v5", uses: getActionRef("actions/setup-java"),
with: { with: {
"java-version": "java-version":
"${{ inputs.java-version || '" + baseJavaVersionExpr + "' }}", "${{ inputs.java-version || '" + baseJavaVersionExpr + "' }}",
@@ -312,7 +323,7 @@ function main(): void {
steps.push({ steps.push({
name: "Install Python", name: "Install Python",
if: "matrix.version != 'nightly-latest'", if: "matrix.version != 'nightly-latest'",
uses: "actions/setup-python@v6", uses: getActionRef("actions/setup-python"),
with: { with: {
"python-version": "python-version":
"${{ inputs.python-version || '" + basePythonVersionExpr + "' }}", "${{ inputs.python-version || '" + basePythonVersionExpr + "' }}",
@@ -333,7 +344,7 @@ function main(): void {
steps.push({ steps.push({
name: "Install .NET", name: "Install .NET",
uses: "actions/setup-dotnet@v5", uses: getActionRef("actions/setup-dotnet"),
with: { with: {
"dotnet-version": "dotnet-version":
"${{ inputs.dotnet-version || '" + baseDotNetVersionExpr + "' }}", "${{ inputs.dotnet-version || '" + baseDotNetVersionExpr + "' }}",
+95 -80
View File
@@ -11,15 +11,18 @@ import * as path from "node:path";
import { afterEach, beforeEach, describe, it } from "node:test"; import { afterEach, beforeEach, describe, it } from "node:test";
import { import {
Options,
scanGeneratedWorkflows, scanGeneratedWorkflows,
updateSyncTs, updateActionVersions,
updateTemplateFiles, updateTemplateFiles,
} from "./sync_back"; } from "./sync_back";
let testDir: string; let testDir: string;
let workflowDir: string; let workflowDir: string;
let checksDir: string; let checksDir: string;
let syncTsPath: string; let actionVersionsTsPath: string;
const defaultOptions: Options = { verbose: false, force: false };
beforeEach(() => { beforeEach(() => {
/** Set up temporary directories and files for testing */ /** Set up temporary directories and files for testing */
@@ -29,8 +32,8 @@ beforeEach(() => {
fs.mkdirSync(workflowDir, { recursive: true }); fs.mkdirSync(workflowDir, { recursive: true });
fs.mkdirSync(checksDir, { recursive: true }); fs.mkdirSync(checksDir, { recursive: true });
// Create sync.ts file path // Create action-versions.ts file path
syncTsPath = path.join(testDir, "pr-checks", "sync.ts"); actionVersionsTsPath = path.join(testDir, "pr-checks", "action-versions.ts");
}); });
afterEach(() => { afterEach(() => {
@@ -56,9 +59,18 @@ jobs:
const result = scanGeneratedWorkflows(workflowDir); const result = scanGeneratedWorkflows(workflowDir);
assert.equal(result["actions/checkout"], "v4"); assert.deepEqual(result["actions/checkout"], {
assert.equal(result["actions/setup-node"], "v5"); version: "v4",
assert.equal(result["actions/setup-go"], "v6"); comment: undefined,
});
assert.deepEqual(result["actions/setup-node"], {
version: "v5",
comment: undefined,
});
assert.deepEqual(result["actions/setup-go"], {
version: "v6",
comment: undefined,
});
}); });
it("scanning workflows with version comments", () => { it("scanning workflows with version comments", () => {
@@ -78,12 +90,18 @@ jobs:
const result = scanGeneratedWorkflows(workflowDir); const result = scanGeneratedWorkflows(workflowDir);
assert.equal(result["actions/checkout"], "v4"); assert.deepEqual(result["actions/checkout"], {
assert.equal( version: "v4",
result["ruby/setup-ruby"], comment: undefined,
"44511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0", });
); assert.deepEqual(result["ruby/setup-ruby"], {
assert.equal(result["actions/setup-python"], "v6 # Latest Python"); version: "44511735964dcb71245e7e55f72539531f7bc0eb",
comment: " v1.257.0",
});
assert.deepEqual(result["actions/setup-python"], {
version: "v6",
comment: " Latest Python",
});
}); });
it("ignores local actions", () => { it("ignores local actions", () => {
@@ -103,89 +121,76 @@ jobs:
const result = scanGeneratedWorkflows(workflowDir); const result = scanGeneratedWorkflows(workflowDir);
assert.equal(result["actions/checkout"], "v4"); assert.deepEqual(result["actions/checkout"], {
version: "v4",
comment: undefined,
});
assert.equal("./.github/actions/local-action" in result, false); assert.equal("./.github/actions/local-action" in result, false);
assert.equal("./another-local-action" in result, false); assert.equal("./another-local-action" in result, false);
}); });
}); });
describe("updateSyncTs", () => { describe("updateActionVersions", () => {
it("updates sync.ts file", () => { it("updates action-versions.ts file", () => {
/** Test updating sync.ts file */ /** Test updating action-versions.ts file */
const syncTsContent = ` const actionVersionsTsContent = `
const steps = [ export const ACTION_VERSIONS = {
{ "actions/setup-node": {
uses: "actions/setup-node@v4", "version": "v4"
with: { "node-version": "16" },
}, },
{ "actions/setup-go": {
uses: "actions/setup-go@v5", "version": "v5"
with: { "go-version": "1.19" }, }
}, };
]; `.trim();
`;
fs.writeFileSync(syncTsPath, syncTsContent); fs.writeFileSync(actionVersionsTsPath, actionVersionsTsContent);
const actionVersions = { const actionVersions = {
"actions/setup-node": "v5", "actions/setup-node": { version: "v5" },
"actions/setup-go": "v6", "actions/setup-go": { version: "v6" },
}; };
const result = updateSyncTs(syncTsPath, actionVersions); const result = updateActionVersions(
defaultOptions,
actionVersionsTsPath,
actionVersions,
);
assert.equal(result, true); assert.equal(result, true);
const updatedContent = fs.readFileSync(syncTsPath, "utf8"); const updatedContent = fs.readFileSync(actionVersionsTsPath, "utf8");
assert.ok(updatedContent.includes('uses: "actions/setup-node@v5"')); assert.ok(
assert.ok(updatedContent.includes('uses: "actions/setup-go@v6"')); updatedContent.includes('"actions/setup-node": {\n "version": "v5"'),
}); );
assert.ok(
it("strips comments from versions", () => { updatedContent.includes('"actions/setup-go": {\n "version": "v6"'),
/** Test updating sync.ts file when versions have comments */ );
const syncTsContent = `
const steps = [
{
uses: "actions/setup-node@v4",
with: { "node-version": "16" },
},
];
`;
fs.writeFileSync(syncTsPath, syncTsContent);
const actionVersions = {
"actions/setup-node": "v5 # Latest version",
};
const result = updateSyncTs(syncTsPath, actionVersions);
assert.equal(result, true);
const updatedContent = fs.readFileSync(syncTsPath, "utf8");
// sync.ts should get the version without comment
assert.ok(updatedContent.includes('uses: "actions/setup-node@v5"'));
assert.ok(!updatedContent.includes("# Latest version"));
}); });
it("returns false when no changes are needed", () => { it("returns false when no changes are needed", () => {
/** Test that updateSyncTs returns false when no changes are needed */ /** Test that updateActionVersions returns false when no changes are needed */
const syncTsContent = ` const actionVersionsTsContent = `
const steps = [ export const ACTION_VERSIONS = {
{ "actions/setup-node": {
uses: "actions/setup-node@v5", "version": "v5"
with: { "node-version": "16" }, }
}, };
]; `.trimStart();
`;
fs.writeFileSync(syncTsPath, syncTsContent); fs.writeFileSync(actionVersionsTsPath, actionVersionsTsContent);
const actionVersions = { const actionVersions = {
"actions/setup-node": "v5", "actions/setup-node": { version: "v5" },
}; };
const result = updateSyncTs(syncTsPath, actionVersions); const result = updateActionVersions(
defaultOptions,
actionVersionsTsPath,
actionVersions,
);
const updatedContent = fs.readFileSync(actionVersionsTsPath, "utf8");
assert.equal(updatedContent, actionVersionsTsContent);
assert.equal(result, false); assert.equal(result, false);
}); });
}); });
@@ -206,11 +211,15 @@ steps:
fs.writeFileSync(templatePath, templateContent); fs.writeFileSync(templatePath, templateContent);
const actionVersions = { const actionVersions = {
"actions/checkout": "v4", "actions/checkout": { version: "v4" },
"actions/setup-node": "v5 # Latest", "actions/setup-node": { version: "v5", comment: " Latest" },
}; };
const result = updateTemplateFiles(checksDir, actionVersions); const result = updateTemplateFiles(
defaultOptions,
checksDir,
actionVersions,
);
assert.equal(result.length, 1); assert.equal(result.length, 1);
assert.ok(result.includes(templatePath)); assert.ok(result.includes(templatePath));
@@ -232,11 +241,17 @@ steps:
fs.writeFileSync(templatePath, templateContent); fs.writeFileSync(templatePath, templateContent);
const actionVersions = { const actionVersions = {
"ruby/setup-ruby": "ruby/setup-ruby": {
"55511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0", version: "55511735964dcb71245e7e55f72539531f7bc0eb",
comment: " v1.257.0",
},
}; };
const result = updateTemplateFiles(checksDir, actionVersions); const result = updateTemplateFiles(
defaultOptions,
checksDir,
actionVersions,
);
assert.equal(result.length, 1); assert.equal(result.length, 1);
const updatedContent = fs.readFileSync(templatePath, "utf8"); const updatedContent = fs.readFileSync(templatePath, "utf8");
+139 -76
View File
@@ -1,5 +1,7 @@
#!/usr/bin/env npx tsx #!/usr/bin/env npx tsx
import * as yaml from "yaml";
/* /*
Sync-back script to automatically update action versions in source templates Sync-back script to automatically update action versions in source templates
from the generated workflow files after Dependabot updates. from the generated workflow files after Dependabot updates.
@@ -25,7 +27,71 @@ import * as path from "path";
const THIS_DIR = __dirname; const THIS_DIR = __dirname;
const CHECKS_DIR = path.join(THIS_DIR, "checks"); const CHECKS_DIR = path.join(THIS_DIR, "checks");
const WORKFLOW_DIR = path.join(THIS_DIR, "..", ".github", "workflows"); const WORKFLOW_DIR = path.join(THIS_DIR, "..", ".github", "workflows");
const SYNC_TS_PATH = path.join(THIS_DIR, "sync.ts"); const ACTION_VERSIONS_PATH = path.join(THIS_DIR, "action-versions.ts");
/** Command-line options for this program. */
export type Options = {
verbose: boolean;
force: boolean;
};
/** Records information about the version of an Action with an optional comment. */
type ActionVersion = { version: string; comment?: string };
/** Converts `info` to a string that includes the version and comment. */
function versionWithCommentStr(info: ActionVersion): string {
const comment = info.comment ? ` #${info.comment}` : "";
return `${info.version}${comment}`;
}
/**
* Constructs a `yaml.visitor` which calls `fn` for `yaml.Pair` nodes where the key is "uses" and
* the value is a `yaml.Scalar`.
*/
function usesVisitor(
fn: (
pair: yaml.Pair<yaml.Scalar, yaml.Scalar>,
actionName: string,
actionVersion: ActionVersion,
) => void,
): yaml.visitor {
return {
Pair(_, pair) {
if (
yaml.isScalar(pair.key) &&
yaml.isScalar(pair.value) &&
pair.key.value === "uses" &&
typeof pair.value.value === "string"
) {
const usesValue = pair.value.value;
// Only track non-local actions (those with / but not starting with ./)
if (!usesValue.startsWith("./")) {
const parts = (pair.value.value as string).split("@");
if (parts.length !== 2) {
throw new Error(`Unexpected 'uses' value: ${usesValue}`);
}
const actionName = parts[0];
const actionVersion = parts[1].trimEnd();
const comment = pair.value.comment?.trimEnd();
fn(pair as yaml.Pair<yaml.Scalar, yaml.Scalar>, actionName, {
version: actionVersion,
comment,
});
}
// Do not visit the children of this node.
return yaml.visit.SKIP;
}
// Do nothing and continue.
return undefined;
},
};
}
/** /**
* Scan generated workflow files to extract the latest action versions. * Scan generated workflow files to extract the latest action versions.
@@ -33,8 +99,10 @@ const SYNC_TS_PATH = path.join(THIS_DIR, "sync.ts");
* @param workflowDir - Path to .github/workflows directory * @param workflowDir - Path to .github/workflows directory
* @returns Map from action names to their latest versions (including comments) * @returns Map from action names to their latest versions (including comments)
*/ */
export function scanGeneratedWorkflows(workflowDir: string): Record<string, string> { export function scanGeneratedWorkflows(
const actionVersions: Record<string, string> = {}; workflowDir: string,
): Record<string, ActionVersion> {
const actionVersions: Record<string, ActionVersion> = {};
const generatedFiles = fs const generatedFiles = fs
.readdirSync(workflowDir) .readdirSync(workflowDir)
@@ -43,86 +111,63 @@ export function scanGeneratedWorkflows(workflowDir: string): Record<string, stri
for (const filePath of generatedFiles) { for (const filePath of generatedFiles) {
const content = fs.readFileSync(filePath, "utf8"); const content = fs.readFileSync(filePath, "utf8");
const doc = yaml.parseDocument(content);
// Find all action uses in the file, including potential comments yaml.visit(
// This pattern captures: action_name@version_with_possible_comment doc,
const pattern = /uses:\s+([^/\s]+\/[^@\s]+)@([^@\n]+)/g; usesVisitor((_node, actionName, actionVersion) => {
let match: RegExpExecArray | null;
while ((match = pattern.exec(content)) !== null) {
const actionName = match[1];
const versionWithComment = match[2].trimEnd();
// Only track non-local actions (those with / but not starting with ./)
if (!actionName.startsWith("./")) {
// Assume that version numbers are consistent (this should be the case on a Dependabot update PR) // Assume that version numbers are consistent (this should be the case on a Dependabot update PR)
actionVersions[actionName] = versionWithComment; actionVersions[actionName] = actionVersion;
} }),
} );
} }
return actionVersions; return actionVersions;
} }
/** /**
* Update hardcoded action versions in pr-checks/sync.ts * Update hardcoded action versions in pr-checks/action-versions.ts
* *
* @param syncTsPath - Path to sync.ts file * @param options - The command-line options.
* @param actionVersionsTsPath - Path to action-versions.ts file
* @param actionVersions - Map of action names to versions (may include comments) * @param actionVersions - Map of action names to versions (may include comments)
* @returns True if the file was modified, false otherwise * @returns True if the file was modified, false otherwise
*/ */
export function updateSyncTs( export function updateActionVersions(
syncTsPath: string, options: Options,
actionVersions: Record<string, string>, actionVersionsTsPath: string,
actionVersions: Record<string, ActionVersion>,
): boolean { ): boolean {
if (!fs.existsSync(syncTsPath)) { // Build content for the file.
throw new Error(`Could not find ${syncTsPath}`); let newContent: string = `export const ACTION_VERSIONS = ${JSON.stringify(actionVersions, null, 2)};\n`;
}
let content = fs.readFileSync(syncTsPath, "utf8"); if (fs.existsSync(actionVersionsTsPath)) {
const originalContent = content; const content = fs.readFileSync(actionVersionsTsPath, "utf8");
if (content === newContent && !options.force) {
console.info(`No changes needed in ${actionVersionsTsPath}`);
return false;
}
}
// Update hardcoded action versions // Update hardcoded action versions
for (const [actionName, versionWithComment] of Object.entries( fs.writeFileSync(actionVersionsTsPath, newContent, "utf8");
actionVersions, console.info(`Updated ${actionVersionsTsPath}`);
)) { return true;
// Extract just the version part (before any comment) for sync.ts
const version = versionWithComment.includes("#")
? versionWithComment.split("#")[0].trim()
: versionWithComment.trim();
// Look for patterns like uses: "actions/setup-node@v4"
// Note that this will break if we store an Action uses reference in a
// variable - that's a risk we're happy to take since in that case the
// PR checks will just fail.
const escaped = actionName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const pattern = new RegExp(
`(uses:\\s*")${escaped}@(?:[^"]+)(")`,
"g",
);
content = content.replace(pattern, `$1${actionName}@${version}$2`);
}
if (content !== originalContent) {
fs.writeFileSync(syncTsPath, content, "utf8");
console.info(`Updated ${syncTsPath}`);
return true;
} else {
console.info(`No changes needed in ${syncTsPath}`);
return false;
}
} }
/** /**
* Update action versions in template files in pr-checks/checks/ * Update action versions in template files in pr-checks/checks/
* *
* @param options - The command-line options.
* @param checksDir - Path to pr-checks/checks directory * @param checksDir - Path to pr-checks/checks directory
* @param actionVersions - Map of action names to versions (may include comments) * @param actionVersions - Map of action names to versions (may include comments)
* @returns List of files that were modified * @returns List of files that were modified
*/ */
export function updateTemplateFiles( export function updateTemplateFiles(
options: Options,
checksDir: string, checksDir: string,
actionVersions: Record<string, string>, actionVersions: Record<string, ActionVersion>,
): string[] { ): string[] {
const modifiedFiles: string[] = []; const modifiedFiles: string[] = [];
@@ -132,24 +177,33 @@ export function updateTemplateFiles(
.map((f) => path.join(checksDir, f)); .map((f) => path.join(checksDir, f));
for (const filePath of templateFiles) { for (const filePath of templateFiles) {
let content = fs.readFileSync(filePath, "utf8"); const content = fs.readFileSync(filePath, "utf8");
const originalContent = content; const doc = yaml.parseDocument(content, { keepSourceTokens: true });
let modified: boolean = false;
// Update action versions yaml.visit(
for (const [actionName, versionWithComment] of Object.entries( doc,
actionVersions, usesVisitor((pair, actionName, actionVersion) => {
)) { // Try to look up version information for this action.
// Look for patterns like 'uses: actions/setup-node@v4' or 'uses: actions/setup-node@sha # comment' const versionInfo = actionVersions[actionName];
const escaped = actionName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const pattern = new RegExp( // If we found version information, and the version is different from that in the template,
`(uses:\\s+${escaped})@(?:[^@\n]+)`, // then update the pair node accordingly.
"g", if (versionInfo && versionInfo.version !== actionVersion.version) {
pair.value.value = `${actionName}@${versionInfo.version}`;
pair.value.comment = versionInfo.comment;
modified = true;
}
}),
);
// Write the YAML document back to the file if we made changes.
if (modified || options.force) {
fs.writeFileSync(
filePath,
doc.toString({ lineWidth: 0, flowCollectionPadding: false }),
"utf8",
); );
content = content.replace(pattern, `$1@${versionWithComment}`);
}
if (content !== originalContent) {
fs.writeFileSync(filePath, content, "utf8");
modifiedFiles.push(filePath); modifiedFiles.push(filePath);
console.info(`Updated ${filePath}`); console.info(`Updated ${filePath}`);
} }
@@ -166,6 +220,11 @@ function main(): number {
short: "v", short: "v",
default: false, default: false,
}, },
force: {
type: "boolean",
short: "f",
default: false,
},
}, },
strict: true, strict: true,
}); });
@@ -178,7 +237,7 @@ function main(): number {
if (verbose) { if (verbose) {
console.info("Found action versions:"); console.info("Found action versions:");
for (const [action, version] of Object.entries(actionVersions)) { for (const [action, version] of Object.entries(actionVersions)) {
console.info(` ${action}@${version}`); console.info(` ${action}@${versionWithCommentStr(version)}`);
} }
} }
@@ -192,12 +251,16 @@ function main(): number {
const modifiedFiles: string[] = []; const modifiedFiles: string[] = [];
// Update sync.ts // Update sync.ts
if (updateSyncTs(SYNC_TS_PATH, actionVersions)) { if (updateActionVersions(values, ACTION_VERSIONS_PATH, actionVersions)) {
modifiedFiles.push(SYNC_TS_PATH); modifiedFiles.push(ACTION_VERSIONS_PATH);
} }
// Update template files // Update template files
const templateModified = updateTemplateFiles(CHECKS_DIR, actionVersions); const templateModified = updateTemplateFiles(
values,
CHECKS_DIR,
actionVersions,
);
modifiedFiles.push(...templateModified); modifiedFiles.push(...templateModified);
if (modifiedFiles.length > 0) { if (modifiedFiles.length > 0) {