From 6531f80d49cefc1e9734e536fff94e40f2061df4 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 5 Mar 2026 15:23:51 +0000 Subject: [PATCH] Document regular expressions --- pr-checks/sync_back.ts | 91 +++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 18 deletions(-) diff --git a/pr-checks/sync_back.ts b/pr-checks/sync_back.ts index 7e1375580b..c7a82aed6f 100755 --- a/pr-checks/sync_back.ts +++ b/pr-checks/sync_back.ts @@ -27,13 +27,79 @@ const CHECKS_DIR = path.join(THIS_DIR, "checks"); const WORKFLOW_DIR = path.join(THIS_DIR, "..", ".github", "workflows"); const SYNC_TS_PATH = path.join(THIS_DIR, "sync.ts"); +/** + * Used to find action references (including versions and comments) in a workflow file. + * + * This pattern captures `action_name` and `version_with_possible_comment` from + * `uses: action_name@version_with_possible_comment`. For example, if we have + * + * ``` + * uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1.288.0 + * ``` + * + * in a workflow file, this regular expression gets us: + * + * - `ruby/setup-ruby`; and + * - `09a7688d3b55cf0e976497ff046b70949eeaccfd # v1.288.0`. + */ +const EXTRACT_ACTION_REF_PATTERN: RegExp = + /uses:\s+([^/\s]+\/[^@\s]+)@([^@\n]+)/g; + +/** + * Used to identify characters in `action_name` strings that need to + * be escaped before inserting them into TypeScript or YAML strings. + */ +const ESCAPE_PATTERN = /[.*+?^${}()|[\]\\]/g; + +/** + * A `SyncBackPattern` is a function which constructs a regular expression for a specific `actionName`, + * which finds references to `actionName` and surrounding context in a particular file that we want + * to sync updated versions back to. + */ +type SyncBackPattern = (actionName: string) => RegExp; + +/** + * Used to find lines containing action references in `sync.ts`. + * + * Matches `uses: "actionName@version_str"` in PR check specifications and groups `uses: "` + * and `"`, allowing `actionName@version_str` to be replaced with a new action reference. + */ +const TS_PATTERN: SyncBackPattern = (actionName: string) => + new RegExp(`(uses:\\s*")${actionName}@(?:[^"]+)(")`, "g"); + +/** + * Used to find lines containing action references in a PR check specification. + * + * Matches `uses: actionName@rest_of_line` in PR check specifications and extracts `uses: actionName`, + * allowing `rest_of_line` to be replaced with a new version string. + */ +const YAML_PATTERN: SyncBackPattern = (actionName: string) => + new RegExp(`(uses:\\s+${actionName})@(?:[^@\n]+)`, "g"); + +/** + * Constructs a regular expression using `patternFunction` for `actionName`, which is sanitised + * before `patternFunction` is called. + * + * @param patternFunction The pattern builder to use. + * @param actionName The action name, which will be sanitised. + * @returns The regular expression returned by `patternFunction`. + */ +function makeReplacementPattern( + patternFunction: SyncBackPattern, + actionName: string, +): RegExp { + return patternFunction(actionName.replace(ESCAPE_PATTERN, "\\$&")); +} + /** * Scan generated workflow files to extract the latest action versions. * * @param workflowDir - Path to .github/workflows directory * @returns Map from action names to their latest versions (including comments) */ -export function scanGeneratedWorkflows(workflowDir: string): Record { +export function scanGeneratedWorkflows( + workflowDir: string, +): Record { const actionVersions: Record = {}; const generatedFiles = fs @@ -43,13 +109,10 @@ export function scanGeneratedWorkflows(workflowDir: string): Record