Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
cache-dependency-path: |
package-lock.json
pr-checks/package-lock.json

- name: Install dependencies
run: |
Expand Down Expand Up @@ -91,6 +94,12 @@ jobs:
with:
node-version: 24
cache: 'npm'
cache-dependency-path: |
package-lock.json
pr-checks/package-lock.json

- name: Install dependencies
run: npm ci

- name: Verify PR checks up to date
if: always()
Expand All @@ -99,7 +108,7 @@ jobs:
- name: Run pr-checks tests
if: always()
working-directory: pr-checks
run: npm ci && npx tsx --test
run: npx tsx --test

check-node-version:
if: github.triggering_actor != 'dependabot[bot]'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/rebuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ jobs:
working-directory: pr-checks
run: |
npm ci
npx tsx sync_back.ts --verbose
npx tsx sync-back.ts --verbose

- name: Generate workflows
working-directory: pr-checks
Expand Down
26 changes: 25 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export default [
"ava.setup.mjs",
"eslint.config.mjs",
".github/**/*",
"pr-checks/**/*",
],
},
// eslint recommended config
Expand Down Expand Up @@ -170,4 +169,29 @@ export default [
"func-style": "off",
},
},
{
files: ["pr-checks/**/*.ts"],

languageOptions: {
parserOptions: {
// Use the correct `tsconfig.json` for `pr-checks`.
project: "./pr-checks/tsconfig.json",
},
},

rules: {
// The scripts in `pr-checks` are expected to output to the console.
"no-console": "off",

"@typescript-eslint/no-floating-promises": [
"error",
{
allowForKnownSafeCalls: [
// Avoid needing explicit `void` in front of `describe` calls in test files.
{ from: "package", name: ["describe"], package: "node:test" },
],
},
],
},
},
];
67 changes: 67 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
"transpile": "tsc --build --verbose"
},
"license": "MIT",
"workspaces": [
"pr-checks"
],
"dependencies": {
"@actions/artifact": "^5.0.3",
"@actions/artifact-legacy": "npm:@actions/artifact@^1.1.2",
Expand Down
29 changes: 14 additions & 15 deletions pr-checks/sync_back.test.ts → pr-checks/sync-back.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env npx tsx

/*
Tests for the sync_back.ts script
Tests for the sync-back.ts script
*/

import * as assert from "node:assert/strict";
Expand All @@ -14,7 +14,7 @@ import {
scanGeneratedWorkflows,
updateSyncTs,
updateTemplateFiles,
} from "./sync_back";
} from "./sync-back";

let testDir: string;
let workflowDir: string;
Expand All @@ -38,8 +38,8 @@ afterEach(() => {
fs.rmSync(testDir, { recursive: true, force: true });
});

describe("scanGeneratedWorkflows", () => {
it("basic workflow scanning", () => {
describe("scanGeneratedWorkflows", async () => {
await it("basic workflow scanning", () => {
/** Test basic workflow scanning functionality */
const workflowContent = `
name: Test Workflow
Expand All @@ -61,7 +61,7 @@ jobs:
assert.equal(result["actions/setup-go"], "v6");
});

it("scanning workflows with version comments", () => {
await it("scanning workflows with version comments", () => {
/** Test scanning workflows with version comments */
const workflowContent = `
name: Test Workflow
Expand All @@ -86,7 +86,7 @@ jobs:
assert.equal(result["actions/setup-python"], "v6 # Latest Python");
});

it("ignores local actions", () => {
await it("ignores local actions", () => {
/** Test that local actions (starting with ./) are ignored */
const workflowContent = `
name: Test Workflow
Expand All @@ -109,8 +109,8 @@ jobs:
});
});

describe("updateSyncTs", () => {
it("updates sync.ts file", () => {
describe("updateSyncTs", async () => {
await it("updates sync.ts file", () => {
/** Test updating sync.ts file */
const syncTsContent = `
const steps = [
Expand Down Expand Up @@ -141,7 +141,7 @@ const steps = [
assert.ok(updatedContent.includes('uses: "actions/setup-go@v6"'));
});

it("strips comments from versions", () => {
await it("strips comments from versions", () => {
/** Test updating sync.ts file when versions have comments */
const syncTsContent = `
const steps = [
Expand All @@ -168,7 +168,7 @@ const steps = [
assert.ok(!updatedContent.includes("# Latest version"));
});

it("returns false when no changes are needed", () => {
await it("returns false when no changes are needed", () => {
/** Test that updateSyncTs returns false when no changes are needed */
const syncTsContent = `
const steps = [
Expand All @@ -190,8 +190,8 @@ const steps = [
});
});

describe("updateTemplateFiles", () => {
it("updates template files", () => {
describe("updateTemplateFiles", async () => {
await it("updates template files", () => {
/** Test updating template files */
const templateContent = `
name: Test Template
Expand Down Expand Up @@ -220,7 +220,7 @@ steps:
assert.ok(updatedContent.includes("uses: actions/setup-node@v5 # Latest"));
});

it("preserves version comments", () => {
await it("preserves version comments", () => {
/** Test that updating template files preserves version comments */
const templateContent = `
name: Test Template
Expand All @@ -232,8 +232,7 @@ steps:
fs.writeFileSync(templatePath, templateContent);

const actionVersions = {
"ruby/setup-ruby":
"55511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0",
"ruby/setup-ruby": "55511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0",
};

const result = updateTemplateFiles(checksDir, actionVersions);
Expand Down
17 changes: 6 additions & 11 deletions pr-checks/sync_back.ts → pr-checks/sync-back.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ those changes are properly synced back to the source templates. Regular workflow
files are updated directly by Dependabot and don't need sync-back.
*/

import { parseArgs } from "node:util";

import * as fs from "fs";
import { parseArgs } from "node:util";
import * as path from "path";

const THIS_DIR = __dirname;
Expand All @@ -33,7 +32,9 @@ const SYNC_TS_PATH = path.join(THIS_DIR, "sync.ts");
* @param workflowDir - Path to .github/workflows directory
* @returns Map from action names to their latest versions (including comments)
*/
export function scanGeneratedWorkflows(workflowDir: string): Record<string, string> {
export function scanGeneratedWorkflows(
workflowDir: string,
): Record<string, string> {
const actionVersions: Record<string, string> = {};

const generatedFiles = fs
Expand Down Expand Up @@ -96,10 +97,7 @@ export function updateSyncTs(
// 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",
);
const pattern = new RegExp(`(uses:\\s*")${escaped}@(?:[^"]+)(")`, "g");
content = content.replace(pattern, `$1${actionName}@${version}$2`);
}

Expand Down Expand Up @@ -141,10 +139,7 @@ export function updateTemplateFiles(
)) {
// Look for patterns like 'uses: actions/setup-node@v4' or 'uses: actions/setup-node@sha # comment'
const escaped = actionName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const pattern = new RegExp(
`(uses:\\s+${escaped})@(?:[^@\n]+)`,
"g",
);
const pattern = new RegExp(`(uses:\\s+${escaped})@(?:[^@\n]+)`, "g");
content = content.replace(pattern, `$1@${versionWithComment}`);
}

Expand Down
Loading
Loading