diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 1c78da10f..77a544cfa 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -42,11 +42,6 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'npm' - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: 3.11 - - name: Install dependencies run: | # Use the system Bash shell to ensure we can run commands like `npm ci` @@ -68,7 +63,7 @@ jobs: - name: Run pr-checks tests if: always() working-directory: pr-checks - run: python -m unittest discover + run: npm ci && npx tsx --test - name: Lint if: always() && matrix.os != 'windows-latest' diff --git a/.github/workflows/rebuild.yml b/.github/workflows/rebuild.yml index fcf6affd0..095c0726f 100644 --- a/.github/workflows/rebuild.yml +++ b/.github/workflows/rebuild.yml @@ -73,17 +73,13 @@ jobs: npm run lint -- --fix npm run build - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: 3.11 - - name: Sync back version updates to generated workflows # Only sync back versions on Dependabot update PRs if: startsWith(env.HEAD_REF, 'dependabot/') working-directory: pr-checks run: | - python3 sync_back.py -v + npm ci + npx tsx sync_back.ts --verbose - name: Generate workflows working-directory: pr-checks diff --git a/lib/analyze-action-post.js b/lib/analyze-action-post.js index b753e030e..e2afab379 100644 --- a/lib/analyze-action-post.js +++ b/lib/analyze-action-post.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 5a99e1d1f..ae24bd2fa 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/lib/autobuild-action.js b/lib/autobuild-action.js index 6a5998873..9bd492faf 100644 --- a/lib/autobuild-action.js +++ b/lib/autobuild-action.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/lib/init-action-post.js b/lib/init-action-post.js index a24252700..45475b829 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/lib/init-action.js b/lib/init-action.js index cc32ddc52..2f027f535 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { @@ -106393,9 +106393,9 @@ var OVERLAY_ANALYSIS_CODE_SCANNING_FEATURES = { rust: "overlay_analysis_code_scanning_rust" /* OverlayAnalysisCodeScanningRust */, swift: "overlay_analysis_code_scanning_swift" /* OverlayAnalysisCodeScanningSwift */ }; -async function isOverlayAnalysisFeatureEnabled(features, codeql, languages, codeScanningConfig) { +async function checkOverlayAnalysisFeatureEnabled(features, codeql, languages, codeScanningConfig) { if (!await features.getValue("overlay_analysis" /* OverlayAnalysis */, codeql)) { - return false; + return new Failure("overall-feature-not-enabled" /* OverallFeatureNotEnabled */); } let enableForCodeScanningOnly = false; for (const language of languages) { @@ -106408,17 +106408,20 @@ async function isOverlayAnalysisFeatureEnabled(features, codeql, languages, code enableForCodeScanningOnly = true; continue; } - return false; + return new Failure("language-not-enabled" /* LanguageNotEnabled */); } if (enableForCodeScanningOnly) { - return codeScanningConfig["disable-default-queries"] !== true && codeScanningConfig.packs === void 0 && codeScanningConfig.queries === void 0 && codeScanningConfig["query-filters"] === void 0; + const usesDefaultQueriesOnly = codeScanningConfig["disable-default-queries"] !== true && codeScanningConfig.packs === void 0 && codeScanningConfig.queries === void 0 && codeScanningConfig["query-filters"] === void 0; + if (!usesDefaultQueriesOnly) { + return new Failure("non-default-queries" /* NonDefaultQueries */); + } } - return true; + return new Success(void 0); } function runnerHasSufficientDiskSpace(diskUsage, logger, useV2ResourceChecks) { const minimumDiskSpaceBytes = useV2ResourceChecks ? OVERLAY_MINIMUM_AVAILABLE_DISK_SPACE_V2_BYTES : OVERLAY_MINIMUM_AVAILABLE_DISK_SPACE_BYTES; - if (diskUsage === void 0 || diskUsage.numAvailableBytes < minimumDiskSpaceBytes) { - const diskSpaceMb = diskUsage === void 0 ? 0 : Math.round(diskUsage.numAvailableBytes / 1e6); + if (diskUsage.numAvailableBytes < minimumDiskSpaceBytes) { + const diskSpaceMb = Math.round(diskUsage.numAvailableBytes / 1e6); const minimumDiskSpaceMb = Math.round(minimumDiskSpaceBytes / 1e6); logger.info( `Setting overlay database mode to ${"none" /* None */} due to insufficient disk space (${diskSpaceMb} MB, needed ${minimumDiskSpaceMb} MB).` @@ -106449,93 +106452,110 @@ async function runnerHasSufficientMemory(codeql, ramInput, logger) { ); return true; } -async function runnerSupportsOverlayAnalysis(codeql, diskUsage, ramInput, logger, useV2ResourceChecks) { +async function checkRunnerResources(codeql, diskUsage, ramInput, logger, useV2ResourceChecks) { if (!runnerHasSufficientDiskSpace(diskUsage, logger, useV2ResourceChecks)) { - return false; + return new Failure("insufficient-disk-space" /* InsufficientDiskSpace */); } if (!await runnerHasSufficientMemory(codeql, ramInput, logger)) { - return false; + return new Failure("insufficient-memory" /* InsufficientMemory */); } - return true; + return new Success(void 0); } -async function getOverlayDatabaseMode(codeql, features, languages, sourceRoot, buildMode, ramInput, codeScanningConfig, repositoryProperties, gitVersion, logger) { - let overlayDatabaseMode = "none" /* None */; - let useOverlayDatabaseCaching = false; - let disabledReason; +async function checkOverlayEnablement(codeql, features, languages, sourceRoot, buildMode, ramInput, codeScanningConfig, repositoryProperties, gitVersion, logger) { const modeEnv = process.env.CODEQL_OVERLAY_DATABASE_MODE; if (modeEnv === "overlay" /* Overlay */ || modeEnv === "overlay-base" /* OverlayBase */ || modeEnv === "none" /* None */) { - overlayDatabaseMode = modeEnv; logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} from the CODEQL_OVERLAY_DATABASE_MODE environment variable.` + `Setting overlay database mode to ${modeEnv} from the CODEQL_OVERLAY_DATABASE_MODE environment variable.` ); - } else if (repositoryProperties["github-codeql-disable-overlay" /* DISABLE_OVERLAY */] === true) { + if (modeEnv === "none" /* None */) { + return new Failure("disabled-by-environment-variable" /* DisabledByEnvironmentVariable */); + } + return validateOverlayDatabaseMode( + modeEnv, + false, + codeql, + languages, + sourceRoot, + buildMode, + gitVersion, + logger + ); + } + if (repositoryProperties["github-codeql-disable-overlay" /* DISABLE_OVERLAY */] === true) { logger.info( `Setting overlay database mode to ${"none" /* None */} because the ${"github-codeql-disable-overlay" /* DISABLE_OVERLAY */} repository property is set to true.` ); - overlayDatabaseMode = "none" /* None */; - disabledReason = "disabled-by-repository-property" /* DisabledByRepositoryProperty */; - } else if (await isOverlayAnalysisFeatureEnabled( + return new Failure("disabled-by-repository-property" /* DisabledByRepositoryProperty */); + } + const featureResult = await checkOverlayAnalysisFeatureEnabled( features, codeql, languages, codeScanningConfig - )) { - const performResourceChecks = !await features.getValue( - "overlay_analysis_skip_resource_checks" /* OverlayAnalysisSkipResourceChecks */, - codeql + ); + if (featureResult.isFailure()) { + return featureResult; + } + const performResourceChecks = !await features.getValue( + "overlay_analysis_skip_resource_checks" /* OverlayAnalysisSkipResourceChecks */, + codeql + ); + const useV2ResourceChecks = await features.getValue( + "overlay_analysis_resource_checks_v2" /* OverlayAnalysisResourceChecksV2 */ + ); + const checkOverlayStatus = await features.getValue( + "overlay_analysis_status_check" /* OverlayAnalysisStatusCheck */ + ); + const needDiskUsage = performResourceChecks || checkOverlayStatus; + const diskUsage = needDiskUsage ? await checkDiskUsage(logger) : void 0; + if (needDiskUsage && diskUsage === void 0) { + logger.warning( + `Unable to determine disk usage, therefore setting overlay database mode to ${"none" /* None */}.` ); - const useV2ResourceChecks = await features.getValue( - "overlay_analysis_resource_checks_v2" /* OverlayAnalysisResourceChecksV2 */ + return new Failure("unable-to-determine-disk-usage" /* UnableToDetermineDiskUsage */); + } + const resourceResult = performResourceChecks && diskUsage !== void 0 ? await checkRunnerResources( + codeql, + diskUsage, + ramInput, + logger, + useV2ResourceChecks + ) : new Success(void 0); + if (resourceResult.isFailure()) { + return resourceResult; + } + if (checkOverlayStatus && diskUsage !== void 0 && await shouldSkipOverlayAnalysis(codeql, languages, diskUsage, logger)) { + logger.info( + `Setting overlay database mode to ${"none" /* None */} because overlay analysis previously failed with this combination of languages, disk space, and CodeQL version.` ); - const checkOverlayStatus = await features.getValue( - "overlay_analysis_status_check" /* OverlayAnalysisStatusCheck */ + return new Failure("skipped-due-to-cached-status" /* SkippedDueToCachedStatus */); + } + let overlayDatabaseMode; + if (isAnalyzingPullRequest()) { + overlayDatabaseMode = "overlay" /* Overlay */; + logger.info( + `Setting overlay database mode to ${overlayDatabaseMode} with caching because we are analyzing a pull request.` + ); + } else if (await isAnalyzingDefaultBranch()) { + overlayDatabaseMode = "overlay-base" /* OverlayBase */; + logger.info( + `Setting overlay database mode to ${overlayDatabaseMode} with caching because we are analyzing the default branch.` ); - const diskUsage = performResourceChecks || checkOverlayStatus ? await checkDiskUsage(logger) : void 0; - if (performResourceChecks && !await runnerSupportsOverlayAnalysis( - codeql, - diskUsage, - ramInput, - logger, - useV2ResourceChecks - )) { - overlayDatabaseMode = "none" /* None */; - disabledReason = "insufficient-resources" /* InsufficientResources */; - } else if (checkOverlayStatus && diskUsage === void 0) { - logger.warning( - `Unable to determine disk usage, therefore setting overlay database mode to ${"none" /* None */}.` - ); - overlayDatabaseMode = "none" /* None */; - disabledReason = "unable-to-determine-disk-usage" /* UnableToDetermineDiskUsage */; - } else if (checkOverlayStatus && diskUsage && await shouldSkipOverlayAnalysis(codeql, languages, diskUsage, logger)) { - logger.info( - `Setting overlay database mode to ${"none" /* None */} because overlay analysis previously failed with this combination of languages, disk space, and CodeQL version.` - ); - overlayDatabaseMode = "none" /* None */; - disabledReason = "skipped-due-to-cached-status" /* SkippedDueToCachedStatus */; - } else if (isAnalyzingPullRequest()) { - overlayDatabaseMode = "overlay" /* Overlay */; - useOverlayDatabaseCaching = true; - logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} with caching because we are analyzing a pull request.` - ); - } else if (await isAnalyzingDefaultBranch()) { - overlayDatabaseMode = "overlay-base" /* OverlayBase */; - useOverlayDatabaseCaching = true; - logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} with caching because we are analyzing the default branch.` - ); - } } else { - disabledReason = "feature-not-enabled" /* FeatureNotEnabled */; - } - const disabledResult = (reason) => ({ - overlayDatabaseMode: "none" /* None */, - useOverlayDatabaseCaching: false, - disabledReason: reason - }); - if (overlayDatabaseMode === "none" /* None */) { - return disabledResult(disabledReason); + return new Failure("not-pull-request-or-default-branch" /* NotPullRequestOrDefaultBranch */); } + return validateOverlayDatabaseMode( + overlayDatabaseMode, + true, + codeql, + languages, + sourceRoot, + buildMode, + gitVersion, + logger + ); +} +async function validateOverlayDatabaseMode(overlayDatabaseMode, useOverlayDatabaseCaching, codeql, languages, sourceRoot, buildMode, gitVersion, logger) { if (buildMode !== "none" /* None */ && (await Promise.all( languages.map( async (l) => l !== "go" /* go */ && // Workaround to allow overlay analysis for Go with any build @@ -106548,37 +106568,36 @@ async function getOverlayDatabaseMode(codeql, features, languages, sourceRoot, b logger.warning( `Cannot build an ${overlayDatabaseMode} database because build-mode is set to "${buildMode}" instead of "none". Falling back to creating a normal full database instead.` ); - return disabledResult("incompatible-build-mode" /* IncompatibleBuildMode */); + return new Failure("incompatible-build-mode" /* IncompatibleBuildMode */); } if (!await codeQlVersionAtLeast(codeql, CODEQL_OVERLAY_MINIMUM_VERSION)) { logger.warning( `Cannot build an ${overlayDatabaseMode} database because the CodeQL CLI is older than ${CODEQL_OVERLAY_MINIMUM_VERSION}. Falling back to creating a normal full database instead.` ); - return disabledResult("incompatible-codeql" /* IncompatibleCodeQl */); + return new Failure("incompatible-codeql" /* IncompatibleCodeQl */); } if (await getGitRoot(sourceRoot) === void 0) { logger.warning( `Cannot build an ${overlayDatabaseMode} database because the source root "${sourceRoot}" is not inside a git repository. Falling back to creating a normal full database instead.` ); - return disabledResult("no-git-root" /* NoGitRoot */); + return new Failure("no-git-root" /* NoGitRoot */); } if (gitVersion === void 0) { logger.warning( `Cannot build an ${overlayDatabaseMode} database because the Git version could not be determined. Falling back to creating a normal full database instead.` ); - return disabledResult("incompatible-git" /* IncompatibleGit */); + return new Failure("incompatible-git" /* IncompatibleGit */); } if (!gitVersion.isAtLeast(GIT_MINIMUM_VERSION_FOR_OVERLAY)) { logger.warning( `Cannot build an ${overlayDatabaseMode} database because the installed Git version is older than ${GIT_MINIMUM_VERSION_FOR_OVERLAY}. Falling back to creating a normal full database instead.` ); - return disabledResult("incompatible-git" /* IncompatibleGit */); + return new Failure("incompatible-git" /* IncompatibleGit */); } - return { + return new Success({ overlayDatabaseMode, - useOverlayDatabaseCaching, - disabledReason - }; + useOverlayDatabaseCaching + }); } function dbLocationOrDefault(dbLocation, tempDir) { return dbLocation || path9.resolve(tempDir, "codeql_databases"); @@ -106666,11 +106685,7 @@ async function initConfig(features, inputs) { } else { logger.debug(`Skipping check for generated files.`); } - const { - overlayDatabaseMode, - useOverlayDatabaseCaching, - disabledReason: overlayDisabledReason - } = await getOverlayDatabaseMode( + const overlayDatabaseModeResult = await checkOverlayEnablement( inputs.codeql, inputs.features, config.languages, @@ -106682,19 +106697,27 @@ async function initConfig(features, inputs) { gitVersion, logger ); - logger.info( - `Using overlay database mode: ${overlayDatabaseMode} ${useOverlayDatabaseCaching ? "with" : "without"} caching.` - ); - config.overlayDatabaseMode = overlayDatabaseMode; - config.useOverlayDatabaseCaching = useOverlayDatabaseCaching; - if (overlayDisabledReason !== void 0) { + if (overlayDatabaseModeResult.isSuccess()) { + const { overlayDatabaseMode, useOverlayDatabaseCaching } = overlayDatabaseModeResult.value; + logger.info( + `Using overlay database mode: ${overlayDatabaseMode} ${useOverlayDatabaseCaching ? "with" : "without"} caching.` + ); + config.overlayDatabaseMode = overlayDatabaseMode; + config.useOverlayDatabaseCaching = useOverlayDatabaseCaching; + } else { + const overlayDisabledReason = overlayDatabaseModeResult.value; + logger.info( + `Using overlay database mode: ${"none" /* None */} without caching.` + ); + config.overlayDatabaseMode = "none" /* None */; + config.useOverlayDatabaseCaching = false; await addOverlayDisablementDiagnostics( config, inputs.codeql, overlayDisabledReason ); } - if (overlayDatabaseMode === "overlay" /* Overlay */ || await shouldPerformDiffInformedAnalysis( + if (config.overlayDatabaseMode === "overlay" /* Overlay */ || await shouldPerformDiffInformedAnalysis( inputs.codeql, inputs.features, logger diff --git a/lib/resolve-environment-action.js b/lib/resolve-environment-action.js index 1631f7c2c..ffb29f931 100644 --- a/lib/resolve-environment-action.js +++ b/lib/resolve-environment-action.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/lib/setup-codeql-action.js b/lib/setup-codeql-action.js index 6f1f3261f..4ff355976 100644 --- a/lib/setup-codeql-action.js +++ b/lib/setup-codeql-action.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/lib/start-proxy-action-post.js b/lib/start-proxy-action-post.js index d1b828de8..8e280e0f3 100644 --- a/lib/start-proxy-action-post.js +++ b/lib/start-proxy-action-post.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/lib/start-proxy-action.js b/lib/start-proxy-action.js index 0dbbe3691..6d0e3e00e 100644 --- a/lib/start-proxy-action.js +++ b/lib/start-proxy-action.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/lib/upload-lib.js b/lib/upload-lib.js index b3d35b747..345ad7769 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -47350,14 +47350,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/lib/upload-sarif-action-post.js b/lib/upload-sarif-action-post.js index b3802f733..e62b286bf 100644 --- a/lib/upload-sarif-action-post.js +++ b/lib/upload-sarif-action-post.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index c41ee0c1a..048265b52 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -46053,14 +46053,14 @@ var require_package = __commonJS({ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", glob: "^11.1.0", globals: "^17.3.0", nock: "^14.0.11", sinon: "^21.0.1", typescript: "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, overrides: { "@actions/tool-cache": { diff --git a/package-lock.json b/package-lock.json index 2bd163cb5..456048f00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,14 +52,14 @@ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", "glob": "^11.1.0", "globals": "^17.3.0", "nock": "^14.0.11", "sinon": "^21.0.1", "typescript": "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2553,17 +2553,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", - "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/type-utils": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -2576,7 +2576,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.56.0", + "@typescript-eslint/parser": "^8.56.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -2592,16 +2592,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", - "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3" }, "engines": { @@ -2635,14 +2635,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", - "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.0", - "@typescript-eslint/types": "^8.56.0", + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", "debug": "^4.4.3" }, "engines": { @@ -2675,14 +2675,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", - "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0" + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2693,9 +2693,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", - "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", "dev": true, "license": "MIT", "engines": { @@ -2710,15 +2710,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", - "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/utils": "8.56.0", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -2753,9 +2753,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", - "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", "dev": true, "license": "MIT", "engines": { @@ -2767,18 +2767,18 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", - "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.56.0", - "@typescript-eslint/tsconfig-utils": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", - "minimatch": "^9.0.5", + "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" @@ -2794,14 +2794,27 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { @@ -2823,32 +2836,32 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", - "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0" + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2863,13 +2876,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", - "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -2881,9 +2894,9 @@ } }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", - "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5146,9 +5159,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "62.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.6.0.tgz", - "integrity": "sha512-Z18zZD1Q2m9usqFbAzb30z+lF8bzE4WiUy+dfOXljJlZ1Jm5uhkuAWfGV97FYyh+WlKfrvpDYs+s1z45eZWMfA==", + "version": "62.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.7.1.tgz", + "integrity": "sha512-4Zvx99Q7d1uggYBUX/AIjvoyqXhluGbbKrRmG8SQTLprPFg6fa293tVJH1o1GQwNe3lUydd8ZHzn37OaSncgSQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -5163,7 +5176,7 @@ "html-entities": "^2.6.0", "object-deep-merge": "^2.0.0", "parse-imports-exports": "^0.2.4", - "semver": "^7.7.3", + "semver": "^7.7.4", "spdx-expression-parse": "^4.0.0", "to-valid-identifier": "^1.0.0" }, @@ -5171,7 +5184,7 @@ "node": "^20.19.0 || ^22.13.0 || >=24" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" } }, "node_modules/eslint-plugin-jsdoc/node_modules/debug": { @@ -9189,16 +9202,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.0.tgz", - "integrity": "sha512-c7toRLrotJ9oixgdW7liukZpsnq5CZ7PuKztubGYlNppuTqhIoWfhgHo/7EU0v06gS2l/x0i2NEFK1qMIf0rIg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz", + "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.56.0", - "@typescript-eslint/parser": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/utils": "8.56.0" + "@typescript-eslint/eslint-plugin": "8.56.1", + "@typescript-eslint/parser": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index 197f910f0..240fa1785 100644 --- a/package.json +++ b/package.json @@ -67,14 +67,14 @@ "eslint-import-resolver-typescript": "^3.8.7", "eslint-plugin-github": "^6.0.0", "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-jsdoc": "^62.6.0", + "eslint-plugin-jsdoc": "^62.7.1", "eslint-plugin-no-async-foreach": "^0.1.1", "glob": "^11.1.0", "globals": "^17.3.0", "nock": "^14.0.11", "sinon": "^21.0.1", "typescript": "^5.9.3", - "typescript-eslint": "^8.56.0" + "typescript-eslint": "^8.56.1" }, "overrides": { "@actions/tool-cache": { diff --git a/pr-checks/.gitignore b/pr-checks/.gitignore index c06afdaf9..c2658d7d1 100644 --- a/pr-checks/.gitignore +++ b/pr-checks/.gitignore @@ -1,4 +1 @@ -env -__pycache__/ -*.pyc node_modules/ diff --git a/pr-checks/__init__.py b/pr-checks/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/pr-checks/readme.md b/pr-checks/readme.md index 283ed3599..81eff0cda 100644 --- a/pr-checks/readme.md +++ b/pr-checks/readme.md @@ -6,9 +6,9 @@ to one of the files in this directory. ## Updating workflows +Run `./sync.sh` to invoke the workflow generator and re-generate the workflow files in `.github/workflows/` based on the templates in `pr-checks/checks/`. + +Alternatively, you can use `just`: + 1. Install https://github.com/casey/just by whichever way you prefer. 2. Run `just update-pr-checks` in your terminal. - -### If you don't want to install `just` - -Manually run each step in the `justfile`. diff --git a/pr-checks/sync_back.py b/pr-checks/sync_back.py deleted file mode 100755 index 1474b455e..000000000 --- a/pr-checks/sync_back.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python3 -""" -Sync-back script to automatically update action versions in source templates -from the generated workflow files after Dependabot updates. - -This script scans the generated workflow files (.github/workflows/__*.yml) to find -all external action versions used, then updates: -1. Hardcoded action versions in pr-checks/sync.py -2. Action version references in template files in pr-checks/checks/ - -The script automatically detects all actions used in generated workflows and -preserves version comments (e.g., # v1.2.3) when syncing versions. - -This ensures that when Dependabot updates action versions in generated workflows, -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 os -import re -import glob -import argparse -import sys -from pathlib import Path -from typing import Dict, List - - -def scan_generated_workflows(workflow_dir: str) -> Dict[str, str]: - """ - Scan generated workflow files to extract the latest action versions. - - Args: - workflow_dir: Path to .github/workflows directory - - Returns: - Dictionary mapping action names to their latest versions (including comments) - """ - action_versions = {} - generated_files = glob.glob(os.path.join(workflow_dir, "__*.yml")) - - for file_path in generated_files: - with open(file_path, 'r') as f: - content = f.read() - - # Find all action uses in the file, including potential comments - # This pattern captures: action_name@version_with_possible_comment - pattern = r'uses:\s+([^/\s]+/[^@\s]+)@([^@\n]+)' - matches = re.findall(pattern, content) - - for action_name, version_with_comment in matches: - # Only track non-local actions (those with / but not starting with ./) - if not action_name.startswith('./'): - # Assume that version numbers are consistent (this should be the case on a Dependabot update PR) - action_versions[action_name] = version_with_comment.rstrip() - - return action_versions - - -def update_sync_py(sync_py_path: str, action_versions: Dict[str, str]) -> bool: - """ - Update hardcoded action versions in pr-checks/sync.py - - Args: - sync_py_path: Path to sync.py file - action_versions: Dictionary of action names to versions (may include comments) - - Returns: - True if file was modified, False otherwise - """ - if not os.path.exists(sync_py_path): - raise FileNotFoundError(f"Could not find {sync_py_path}") - - with open(sync_py_path, 'r') as f: - content = f.read() - - original_content = content - - # Update hardcoded action versions - for action_name, version_with_comment in action_versions.items(): - # Extract just the version part (before any comment) for sync.py - version = version_with_comment.split('#')[0].strip() if '#' in version_with_comment else version_with_comment.strip() - - # 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. - pattern = rf"('uses':\s*'){re.escape(action_name)}@(?:[^']+)(')" - replacement = rf"\1{action_name}@{version}\2" - content = re.sub(pattern, replacement, content) - - if content != original_content: - with open(sync_py_path, 'w') as f: - f.write(content) - print(f"Updated {sync_py_path}") - return True - else: - print(f"No changes needed in {sync_py_path}") - return False - - -def update_template_files(checks_dir: str, action_versions: Dict[str, str]) -> List[str]: - """ - Update action versions in template files in pr-checks/checks/ - - Args: - checks_dir: Path to pr-checks/checks directory - action_versions: Dictionary of action names to versions (may include comments) - - Returns: - List of files that were modified - """ - modified_files = [] - template_files = glob.glob(os.path.join(checks_dir, "*.yml")) - - for file_path in template_files: - with open(file_path, 'r') as f: - content = f.read() - - original_content = content - - # Update action versions - for action_name, version_with_comment in action_versions.items(): - # Look for patterns like 'uses: actions/setup-node@v4' or 'uses: actions/setup-node@sha # comment' - pattern = rf"(uses:\s+{re.escape(action_name)})@(?:[^@\n]+)" - replacement = rf"\1@{version_with_comment}" - content = re.sub(pattern, replacement, content) - - if content != original_content: - with open(file_path, 'w') as f: - f.write(content) - modified_files.append(file_path) - print(f"Updated {file_path}") - - return modified_files - - -def main(): - parser = argparse.ArgumentParser(description="Sync action versions from generated workflows back to templates") - parser.add_argument("--verbose", "-v", action="store_true", help="Enable verbose output") - args = parser.parse_args() - - # Get the repository root (assuming script is in pr-checks/) - script_dir = Path(__file__).parent - repo_root = script_dir.parent - - workflow_dir = repo_root / ".github" / "workflows" - checks_dir = script_dir / "checks" - sync_py_path = script_dir / "sync.py" - - print("Scanning generated workflows for latest action versions...") - action_versions = scan_generated_workflows(str(workflow_dir)) - - if args.verbose: - print("Found action versions:") - for action, version in action_versions.items(): - print(f" {action}@{version}") - - if not action_versions: - print("No action versions found in generated workflows") - return 1 - - # Update files - print("\nUpdating source files...") - modified_files = [] - - # Update sync.py - if update_sync_py(str(sync_py_path), action_versions): - modified_files.append(str(sync_py_path)) - - # Update template files - template_modified = update_template_files(str(checks_dir), action_versions) - modified_files.extend(template_modified) - - if modified_files: - print(f"\nSync completed. Modified {len(modified_files)} files:") - for file_path in modified_files: - print(f" {file_path}") - else: - print("\nNo files needed updating - all action versions are already in sync") - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file diff --git a/pr-checks/sync_back.test.ts b/pr-checks/sync_back.test.ts new file mode 100755 index 000000000..316d2b730 --- /dev/null +++ b/pr-checks/sync_back.test.ts @@ -0,0 +1,250 @@ +#!/usr/bin/env npx tsx + +/* +Tests for the sync_back.ts script +*/ + +import * as assert from "node:assert/strict"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import { afterEach, beforeEach, describe, it } from "node:test"; + +import { + scanGeneratedWorkflows, + updateSyncTs, + updateTemplateFiles, +} from "./sync_back"; + +let testDir: string; +let workflowDir: string; +let checksDir: string; +let syncTsPath: string; + +beforeEach(() => { + /** Set up temporary directories and files for testing */ + testDir = fs.mkdtempSync(path.join(os.tmpdir(), "sync-back-test-")); + workflowDir = path.join(testDir, ".github", "workflows"); + checksDir = path.join(testDir, "pr-checks", "checks"); + fs.mkdirSync(workflowDir, { recursive: true }); + fs.mkdirSync(checksDir, { recursive: true }); + + // Create sync.ts file path + syncTsPath = path.join(testDir, "pr-checks", "sync.ts"); +}); + +afterEach(() => { + /** Clean up temporary directories */ + fs.rmSync(testDir, { recursive: true, force: true }); +}); + +describe("scanGeneratedWorkflows", () => { + it("basic workflow scanning", () => { + /** Test basic workflow scanning functionality */ + const workflowContent = ` +name: Test Workflow +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v5 + - uses: actions/setup-go@v6 +`; + + fs.writeFileSync(path.join(workflowDir, "__test.yml"), workflowContent); + + const result = scanGeneratedWorkflows(workflowDir); + + assert.equal(result["actions/checkout"], "v4"); + assert.equal(result["actions/setup-node"], "v5"); + assert.equal(result["actions/setup-go"], "v6"); + }); + + it("scanning workflows with version comments", () => { + /** Test scanning workflows with version comments */ + const workflowContent = ` +name: Test Workflow +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@44511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0 + - uses: actions/setup-python@v6 # Latest Python +`; + + fs.writeFileSync(path.join(workflowDir, "__test.yml"), workflowContent); + + const result = scanGeneratedWorkflows(workflowDir); + + assert.equal(result["actions/checkout"], "v4"); + assert.equal( + result["ruby/setup-ruby"], + "44511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0", + ); + assert.equal(result["actions/setup-python"], "v6 # Latest Python"); + }); + + it("ignores local actions", () => { + /** Test that local actions (starting with ./) are ignored */ + const workflowContent = ` +name: Test Workflow +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/local-action + - uses: ./another-local-action@v1 +`; + + fs.writeFileSync(path.join(workflowDir, "__test.yml"), workflowContent); + + const result = scanGeneratedWorkflows(workflowDir); + + assert.equal(result["actions/checkout"], "v4"); + assert.equal("./.github/actions/local-action" in result, false); + assert.equal("./another-local-action" in result, false); + }); +}); + +describe("updateSyncTs", () => { + it("updates sync.ts file", () => { + /** Test updating sync.ts file */ + const syncTsContent = ` +const steps = [ + { + uses: "actions/setup-node@v4", + with: { "node-version": "16" }, + }, + { + uses: "actions/setup-go@v5", + with: { "go-version": "1.19" }, + }, +]; +`; + + fs.writeFileSync(syncTsPath, syncTsContent); + + const actionVersions = { + "actions/setup-node": "v5", + "actions/setup-go": "v6", + }; + + const result = updateSyncTs(syncTsPath, actionVersions); + assert.equal(result, true); + + const updatedContent = fs.readFileSync(syncTsPath, "utf8"); + + assert.ok(updatedContent.includes('uses: "actions/setup-node@v5"')); + assert.ok(updatedContent.includes('uses: "actions/setup-go@v6"')); + }); + + it("strips comments from versions", () => { + /** 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", () => { + /** Test that updateSyncTs returns false when no changes are needed */ + const syncTsContent = ` +const steps = [ + { + uses: "actions/setup-node@v5", + with: { "node-version": "16" }, + }, +]; +`; + + fs.writeFileSync(syncTsPath, syncTsContent); + + const actionVersions = { + "actions/setup-node": "v5", + }; + + const result = updateSyncTs(syncTsPath, actionVersions); + assert.equal(result, false); + }); +}); + +describe("updateTemplateFiles", () => { + it("updates template files", () => { + /** Test updating template files */ + const templateContent = ` +name: Test Template +steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v4 + with: + node-version: 16 +`; + + const templatePath = path.join(checksDir, "test.yml"); + fs.writeFileSync(templatePath, templateContent); + + const actionVersions = { + "actions/checkout": "v4", + "actions/setup-node": "v5 # Latest", + }; + + const result = updateTemplateFiles(checksDir, actionVersions); + assert.equal(result.length, 1); + assert.ok(result.includes(templatePath)); + + const updatedContent = fs.readFileSync(templatePath, "utf8"); + + assert.ok(updatedContent.includes("uses: actions/checkout@v4")); + assert.ok(updatedContent.includes("uses: actions/setup-node@v5 # Latest")); + }); + + it("preserves version comments", () => { + /** Test that updating template files preserves version comments */ + const templateContent = ` +name: Test Template +steps: + - uses: ruby/setup-ruby@44511735964dcb71245e7e55f72539531f7bc0eb # v1.256.0 +`; + + const templatePath = path.join(checksDir, "test.yml"); + fs.writeFileSync(templatePath, templateContent); + + const actionVersions = { + "ruby/setup-ruby": + "55511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0", + }; + + const result = updateTemplateFiles(checksDir, actionVersions); + assert.equal(result.length, 1); + + const updatedContent = fs.readFileSync(templatePath, "utf8"); + + assert.ok( + updatedContent.includes( + "uses: ruby/setup-ruby@55511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0", + ), + ); + }); +}); diff --git a/pr-checks/sync_back.ts b/pr-checks/sync_back.ts new file mode 100755 index 000000000..7e1375580 --- /dev/null +++ b/pr-checks/sync_back.ts @@ -0,0 +1,220 @@ +#!/usr/bin/env npx tsx + +/* +Sync-back script to automatically update action versions in source templates +from the generated workflow files after Dependabot updates. + +This script scans the generated workflow files (.github/workflows/__*.yml) to find +all external action versions used, then updates: +1. Hardcoded action versions in pr-checks/sync.ts +2. Action version references in template files in pr-checks/checks/ + +The script automatically detects all actions used in generated workflows and +preserves version comments (e.g., # v1.2.3) when syncing versions. + +This ensures that when Dependabot updates action versions in generated workflows, +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 * as path from "path"; + +const THIS_DIR = __dirname; +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"); + +/** + * 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 { + const actionVersions: Record = {}; + + const generatedFiles = fs + .readdirSync(workflowDir) + .filter((f) => f.startsWith("__") && f.endsWith(".yml")) + .map((f) => path.join(workflowDir, f)); + + for (const filePath of generatedFiles) { + const content = fs.readFileSync(filePath, "utf8"); + + // Find all action uses in the file, including potential comments + // This pattern captures: action_name@version_with_possible_comment + const pattern = /uses:\s+([^/\s]+\/[^@\s]+)@([^@\n]+)/g; + 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) + actionVersions[actionName] = versionWithComment; + } + } + } + + return actionVersions; +} + +/** + * Update hardcoded action versions in pr-checks/sync.ts + * + * @param syncTsPath - Path to sync.ts file + * @param actionVersions - Map of action names to versions (may include comments) + * @returns True if the file was modified, false otherwise + */ +export function updateSyncTs( + syncTsPath: string, + actionVersions: Record, +): boolean { + if (!fs.existsSync(syncTsPath)) { + throw new Error(`Could not find ${syncTsPath}`); + } + + let content = fs.readFileSync(syncTsPath, "utf8"); + const originalContent = content; + + // Update hardcoded action versions + for (const [actionName, versionWithComment] of Object.entries( + actionVersions, + )) { + // 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/ + * + * @param checksDir - Path to pr-checks/checks directory + * @param actionVersions - Map of action names to versions (may include comments) + * @returns List of files that were modified + */ +export function updateTemplateFiles( + checksDir: string, + actionVersions: Record, +): string[] { + const modifiedFiles: string[] = []; + + const templateFiles = fs + .readdirSync(checksDir) + .filter((f) => f.endsWith(".yml")) + .map((f) => path.join(checksDir, f)); + + for (const filePath of templateFiles) { + let content = fs.readFileSync(filePath, "utf8"); + const originalContent = content; + + // Update action versions + for (const [actionName, versionWithComment] of Object.entries( + actionVersions, + )) { + // 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", + ); + content = content.replace(pattern, `$1@${versionWithComment}`); + } + + if (content !== originalContent) { + fs.writeFileSync(filePath, content, "utf8"); + modifiedFiles.push(filePath); + console.info(`Updated ${filePath}`); + } + } + + return modifiedFiles; +} + +function main(): number { + const { values } = parseArgs({ + options: { + verbose: { + type: "boolean", + short: "v", + default: false, + }, + }, + strict: true, + }); + + const verbose = values.verbose ?? false; + + console.info("Scanning generated workflows for latest action versions..."); + const actionVersions = scanGeneratedWorkflows(WORKFLOW_DIR); + + if (verbose) { + console.info("Found action versions:"); + for (const [action, version] of Object.entries(actionVersions)) { + console.info(` ${action}@${version}`); + } + } + + if (Object.keys(actionVersions).length === 0) { + console.error("No action versions found in generated workflows"); + return 1; + } + + // Update files + console.info("\nUpdating source files..."); + const modifiedFiles: string[] = []; + + // Update sync.ts + if (updateSyncTs(SYNC_TS_PATH, actionVersions)) { + modifiedFiles.push(SYNC_TS_PATH); + } + + // Update template files + const templateModified = updateTemplateFiles(CHECKS_DIR, actionVersions); + modifiedFiles.push(...templateModified); + + if (modifiedFiles.length > 0) { + console.info(`\nSync completed. Modified ${modifiedFiles.length} files:`); + for (const filePath of modifiedFiles) { + console.info(` ${filePath}`); + } + } else { + console.info( + "\nNo files needed updating - all action versions are already in sync", + ); + } + + return 0; +} + +// Only call `main` if this script was run directly. +if (require.main === module) { + process.exit(main()); +} diff --git a/pr-checks/test_sync_back.py b/pr-checks/test_sync_back.py deleted file mode 100644 index de2e42d73..000000000 --- a/pr-checks/test_sync_back.py +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/env python3 -""" -Tests for the sync_back.py script -""" - -import os -import shutil -import tempfile -import unittest - -import sync_back - - -class TestSyncBack(unittest.TestCase): - - def setUp(self): - """Set up temporary directories and files for testing""" - self.test_dir = tempfile.mkdtemp() - self.workflow_dir = os.path.join(self.test_dir, ".github", "workflows") - self.checks_dir = os.path.join(self.test_dir, "pr-checks", "checks") - os.makedirs(self.workflow_dir) - os.makedirs(self.checks_dir) - - # Create sync.py file - self.sync_py_path = os.path.join(self.test_dir, "pr-checks", "sync.py") - - def tearDown(self): - """Clean up temporary directories""" - shutil.rmtree(self.test_dir) - - def test_scan_generated_workflows_basic(self): - """Test basic workflow scanning functionality""" - # Create a test generated workflow file - workflow_content = """ -name: Test Workflow -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v5 - - uses: actions/setup-go@v6 - """ - - with open(os.path.join(self.workflow_dir, "__test.yml"), 'w') as f: - f.write(workflow_content) - - result = sync_back.scan_generated_workflows(self.workflow_dir) - - self.assertEqual(result['actions/checkout'], 'v4') - self.assertEqual(result['actions/setup-node'], 'v5') - self.assertEqual(result['actions/setup-go'], 'v6') - - def test_scan_generated_workflows_with_comments(self): - """Test scanning workflows with version comments""" - workflow_content = """ -name: Test Workflow -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@44511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0 - - uses: actions/setup-python@v6 # Latest Python - """ - - with open(os.path.join(self.workflow_dir, "__test.yml"), 'w') as f: - f.write(workflow_content) - - result = sync_back.scan_generated_workflows(self.workflow_dir) - - self.assertEqual(result['actions/checkout'], 'v4') - self.assertEqual(result['ruby/setup-ruby'], '44511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0') - self.assertEqual(result['actions/setup-python'], 'v6 # Latest Python') - - def test_scan_generated_workflows_ignores_local_actions(self): - """Test that local actions (starting with ./) are ignored""" - workflow_content = """ -name: Test Workflow -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: ./.github/actions/local-action - - uses: ./another-local-action@v1 - """ - - with open(os.path.join(self.workflow_dir, "__test.yml"), 'w') as f: - f.write(workflow_content) - - result = sync_back.scan_generated_workflows(self.workflow_dir) - - self.assertEqual(result['actions/checkout'], 'v4') - self.assertNotIn('./.github/actions/local-action', result) - self.assertNotIn('./another-local-action', result) - - - def test_update_sync_py(self): - """Test updating sync.py file""" - sync_py_content = """ -steps = [ - { - 'uses': 'actions/setup-node@v4', - 'with': {'node-version': '16'} - }, - { - 'uses': 'actions/setup-go@v5', - 'with': {'go-version': '1.19'} - } -] - """ - - with open(self.sync_py_path, 'w') as f: - f.write(sync_py_content) - - action_versions = { - 'actions/setup-node': 'v5', - 'actions/setup-go': 'v6' - } - - result = sync_back.update_sync_py(self.sync_py_path, action_versions) - self.assertTrue(result) - - with open(self.sync_py_path, 'r') as f: - updated_content = f.read() - - self.assertIn("'uses': 'actions/setup-node@v5'", updated_content) - self.assertIn("'uses': 'actions/setup-go@v6'", updated_content) - - def test_update_sync_py_with_comments(self): - """Test updating sync.py file when versions have comments""" - sync_py_content = """ -steps = [ - { - 'uses': 'actions/setup-node@v4', - 'with': {'node-version': '16'} - } -] - """ - - with open(self.sync_py_path, 'w') as f: - f.write(sync_py_content) - - action_versions = { - 'actions/setup-node': 'v5 # Latest version' - } - - result = sync_back.update_sync_py(self.sync_py_path, action_versions) - self.assertTrue(result) - - with open(self.sync_py_path, 'r') as f: - updated_content = f.read() - - # sync.py should get the version without comment - self.assertIn("'uses': 'actions/setup-node@v5'", updated_content) - self.assertNotIn("# Latest version", updated_content) - - def test_update_template_files(self): - """Test updating template files""" - template_content = """ -name: Test Template -steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v4 - with: - node-version: 16 - """ - - template_path = os.path.join(self.checks_dir, "test.yml") - with open(template_path, 'w') as f: - f.write(template_content) - - action_versions = { - 'actions/checkout': 'v4', - 'actions/setup-node': 'v5 # Latest' - } - - result = sync_back.update_template_files(self.checks_dir, action_versions) - self.assertEqual(len(result), 1) - self.assertIn(template_path, result) - - with open(template_path, 'r') as f: - updated_content = f.read() - - self.assertIn("uses: actions/checkout@v4", updated_content) - self.assertIn("uses: actions/setup-node@v5 # Latest", updated_content) - - def test_update_template_files_preserves_comments(self): - """Test that updating template files preserves version comments""" - template_content = """ -name: Test Template -steps: - - uses: ruby/setup-ruby@44511735964dcb71245e7e55f72539531f7bc0eb # v1.256.0 - """ - - template_path = os.path.join(self.checks_dir, "test.yml") - with open(template_path, 'w') as f: - f.write(template_content) - - action_versions = { - 'ruby/setup-ruby': '55511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0' - } - - result = sync_back.update_template_files(self.checks_dir, action_versions) - self.assertEqual(len(result), 1) - - with open(template_path, 'r') as f: - updated_content = f.read() - - self.assertIn("uses: ruby/setup-ruby@55511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0", updated_content) - - def test_no_changes_needed(self): - """Test that functions return False/empty when no changes are needed""" - # Test sync.py with no changes needed - sync_py_content = """ -steps = [ - { - 'uses': 'actions/setup-node@v5', - 'with': {'node-version': '16'} - } -] - """ - - with open(self.sync_py_path, 'w') as f: - f.write(sync_py_content) - - action_versions = { - 'actions/setup-node': 'v5' - } - - result = sync_back.update_sync_py(self.sync_py_path, action_versions) - self.assertFalse(result) - - -if __name__ == '__main__': - unittest.main() diff --git a/src/config-utils.test.ts b/src/config-utils.test.ts index 4ab7a1748..06994c0ed 100644 --- a/src/config-utils.test.ts +++ b/src/config-utils.test.ts @@ -40,6 +40,8 @@ import { withTmpDir, BuildMode, DiskUsage, + Success, + Failure, } from "./util"; import * as util from "./util"; @@ -942,55 +944,46 @@ for (const { displayName, language, feature } of [ feature: Feature.DisableCsharpBuildless, }, ]) { - test.serial( - `Build mode not overridden when disable ${displayName} buildless feature flag disabled`, - async (t) => { - const messages: LoggedMessage[] = []; - const buildMode = await configUtils.parseBuildModeInput( - "none", - [language], - createFeatures([]), - getRecordingLogger(messages), - ); - t.is(buildMode, BuildMode.None); - t.deepEqual(messages, []); - }, - ); + test(`Build mode not overridden when disable ${displayName} buildless feature flag disabled`, async (t) => { + const messages: LoggedMessage[] = []; + const buildMode = await configUtils.parseBuildModeInput( + "none", + [language], + createFeatures([]), + getRecordingLogger(messages), + ); + t.is(buildMode, BuildMode.None); + t.deepEqual(messages, []); + }); - test.serial( - `Build mode not overridden for other languages when disable ${displayName} buildless feature flag enabled`, - async (t) => { - const messages: LoggedMessage[] = []; - const buildMode = await configUtils.parseBuildModeInput( - "none", - [KnownLanguage.python], - createFeatures([feature]), - getRecordingLogger(messages), - ); - t.is(buildMode, BuildMode.None); - t.deepEqual(messages, []); - }, - ); + test(`Build mode not overridden for other languages when disable ${displayName} buildless feature flag enabled`, async (t) => { + const messages: LoggedMessage[] = []; + const buildMode = await configUtils.parseBuildModeInput( + "none", + [KnownLanguage.python], + createFeatures([feature]), + getRecordingLogger(messages), + ); + t.is(buildMode, BuildMode.None); + t.deepEqual(messages, []); + }); - test.serial( - `Build mode overridden when analyzing ${displayName} and disable ${displayName} buildless feature flag enabled`, - async (t) => { - const messages: LoggedMessage[] = []; - const buildMode = await configUtils.parseBuildModeInput( - "none", - [language], - createFeatures([feature]), - getRecordingLogger(messages), - ); - t.is(buildMode, BuildMode.Autobuild); - t.deepEqual(messages, [ - { - message: `Scanning ${displayName} code without a build is temporarily unavailable. Falling back to 'autobuild' build mode.`, - type: "warning", - }, - ]); - }, - ); + test(`Build mode overridden when analyzing ${displayName} and disable ${displayName} buildless feature flag enabled`, async (t) => { + const messages: LoggedMessage[] = []; + const buildMode = await configUtils.parseBuildModeInput( + "none", + [language], + createFeatures([feature]), + getRecordingLogger(messages), + ); + t.is(buildMode, BuildMode.Autobuild); + t.deepEqual(messages, [ + { + message: `Scanning ${displayName} code without a build is temporarily unavailable. Falling back to 'autobuild' build mode.`, + type: "warning", + }, + ]); + }); } interface OverlayDatabaseModeTestSetup { @@ -1033,16 +1026,19 @@ const defaultOverlayDatabaseModeTestSetup: OverlayDatabaseModeTestSetup = { repositoryProperties: {}, }; -const getOverlayDatabaseModeMacro = test.macro({ +const checkOverlayEnablementMacro = test.macro({ exec: async ( t: ExecutionContext, _title: string, setupOverrides: Partial, - expected: { - overlayDatabaseMode: OverlayDatabaseMode; - useOverlayDatabaseCaching: boolean; - disabledReason?: OverlayDisabledReason; - }, + expected: + | { + overlayDatabaseMode: OverlayDatabaseMode; + useOverlayDatabaseCaching: boolean; + } + | { + disabledReason: OverlayDisabledReason; + }, ) => { return await withTmpDir(async (tempDir) => { const messages: LoggedMessage[] = []; @@ -1100,7 +1096,7 @@ const getOverlayDatabaseModeMacro = test.macro({ .stub(gitUtils, "isAnalyzingDefaultBranch") .resolves(setup.isDefaultBranch); - const result = await configUtils.getOverlayDatabaseMode( + const result = await configUtils.checkOverlayEnablement( codeql, features, setup.languages, @@ -1113,22 +1109,22 @@ const getOverlayDatabaseModeMacro = test.macro({ logger, ); - if (!("disabledReason" in expected)) { - expected.disabledReason = undefined; + if ("disabledReason" in expected) { + t.deepEqual(result, new Failure(expected.disabledReason)); + } else { + t.deepEqual(result, new Success(expected)); } - - t.deepEqual(result, expected); } finally { // Restore the original environment process.env = originalEnv; } }); }, - title: (_, title) => `getOverlayDatabaseMode: ${title}`, + title: (_, title) => `checkOverlayEnablement: ${title}`, }); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Environment variable override - Overlay", { overlayDatabaseEnvVar: "overlay", @@ -1140,7 +1136,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Environment variable override - OverlayBase", { overlayDatabaseEnvVar: "overlay-base", @@ -1152,45 +1148,41 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Environment variable override - None", { overlayDatabaseEnvVar: "none", }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, + disabledReason: OverlayDisabledReason.DisabledByEnvironmentVariable, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Ignore invalid environment variable", { overlayDatabaseEnvVar: "invalid-mode", }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.OverallFeatureNotEnabled, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Ignore feature flag when analyzing non-default branch", { languages: [KnownLanguage.javascript], features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript], }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, + disabledReason: OverlayDisabledReason.NotPullRequestOrDefaultBranch, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay-base database on default branch when feature enabled", { languages: [KnownLanguage.javascript], @@ -1204,7 +1196,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay-base database on default branch when feature enabled with custom analysis", { languages: [KnownLanguage.javascript], @@ -1221,7 +1213,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay-base database on default branch when code-scanning feature enabled", { languages: [KnownLanguage.javascript], @@ -1238,7 +1230,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch if runner disk space is too low", { languages: [KnownLanguage.javascript], @@ -1253,14 +1245,12 @@ test.serial( }, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.InsufficientResources, + disabledReason: OverlayDisabledReason.InsufficientDiskSpace, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch if we can't determine runner disk space", { languages: [KnownLanguage.javascript], @@ -1272,14 +1262,12 @@ test.serial( diskUsage: undefined, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.InsufficientResources, + disabledReason: OverlayDisabledReason.UnableToDetermineDiskUsage, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay-base database on default branch if runner disk space is too low and skip resource checks flag is enabled", { languages: [KnownLanguage.javascript], @@ -1301,7 +1289,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch if runner disk space is below v2 limit and v2 resource checks enabled", { languages: [KnownLanguage.javascript], @@ -1317,14 +1305,12 @@ test.serial( }, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.InsufficientResources, + disabledReason: OverlayDisabledReason.InsufficientDiskSpace, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay-base database on default branch if runner disk space is between v2 and v1 limits and v2 resource checks enabled", { languages: [KnownLanguage.javascript], @@ -1346,7 +1332,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch if runner disk space is between v2 and v1 limits and v2 resource checks not enabled", { languages: [KnownLanguage.javascript], @@ -1361,14 +1347,12 @@ test.serial( }, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.InsufficientResources, + disabledReason: OverlayDisabledReason.InsufficientDiskSpace, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch if memory flag is too low", { languages: [KnownLanguage.javascript], @@ -1380,14 +1364,12 @@ test.serial( memoryFlagValue: 3072, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.InsufficientResources, + disabledReason: OverlayDisabledReason.InsufficientMemory, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay-base database on default branch if memory flag is too low but CodeQL >= 2.24.3", { languages: [KnownLanguage.javascript], @@ -1406,7 +1388,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay-base database on default branch if memory flag is too low and skip resource checks flag is enabled", { languages: [KnownLanguage.javascript], @@ -1425,7 +1407,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch when cached status indicates previous failure", { languages: [KnownLanguage.javascript], @@ -1438,14 +1420,12 @@ test.serial( shouldSkipOverlayAnalysisDueToCachedStatus: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, disabledReason: OverlayDisabledReason.SkippedDueToCachedStatus, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR when cached status indicates previous failure", { languages: [KnownLanguage.javascript], @@ -1458,14 +1438,12 @@ test.serial( shouldSkipOverlayAnalysisDueToCachedStatus: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, disabledReason: OverlayDisabledReason.SkippedDueToCachedStatus, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch when code-scanning feature enabled with disable-default-queries", { languages: [KnownLanguage.javascript], @@ -1479,14 +1457,12 @@ test.serial( isDefaultBranch: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.NonDefaultQueries, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch when code-scanning feature enabled with packs", { languages: [KnownLanguage.javascript], @@ -1500,14 +1476,12 @@ test.serial( isDefaultBranch: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.NonDefaultQueries, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch when code-scanning feature enabled with queries", { languages: [KnownLanguage.javascript], @@ -1521,14 +1495,12 @@ test.serial( isDefaultBranch: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.NonDefaultQueries, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch when code-scanning feature enabled with query-filters", { languages: [KnownLanguage.javascript], @@ -1542,14 +1514,12 @@ test.serial( isDefaultBranch: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.NonDefaultQueries, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch when only language-specific feature enabled", { languages: [KnownLanguage.javascript], @@ -1557,14 +1527,12 @@ test.serial( isDefaultBranch: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.OverallFeatureNotEnabled, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch when only code-scanning feature enabled", { languages: [KnownLanguage.javascript], @@ -1572,14 +1540,12 @@ test.serial( isDefaultBranch: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.OverallFeatureNotEnabled, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay-base database on default branch when language-specific feature disabled", { languages: [KnownLanguage.javascript], @@ -1587,14 +1553,12 @@ test.serial( isDefaultBranch: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.LanguageNotEnabled, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay analysis on PR when feature enabled", { languages: [KnownLanguage.javascript], @@ -1608,7 +1572,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay analysis on PR when feature enabled with custom analysis", { languages: [KnownLanguage.javascript], @@ -1625,7 +1589,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay analysis on PR when code-scanning feature enabled", { languages: [KnownLanguage.javascript], @@ -1642,7 +1606,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR if runner disk space is too low", { languages: [KnownLanguage.javascript], @@ -1657,14 +1621,12 @@ test.serial( }, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.InsufficientResources, + disabledReason: OverlayDisabledReason.InsufficientDiskSpace, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay analysis on PR if runner disk space is too low and skip resource checks flag is enabled", { languages: [KnownLanguage.javascript], @@ -1686,7 +1648,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR if we can't determine runner disk space", { languages: [KnownLanguage.javascript], @@ -1698,14 +1660,12 @@ test.serial( diskUsage: undefined, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.InsufficientResources, + disabledReason: OverlayDisabledReason.UnableToDetermineDiskUsage, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR if memory flag is too low", { languages: [KnownLanguage.javascript], @@ -1717,14 +1677,12 @@ test.serial( memoryFlagValue: 3072, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.InsufficientResources, + disabledReason: OverlayDisabledReason.InsufficientMemory, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay analysis on PR if memory flag is too low but CodeQL >= 2.24.3", { languages: [KnownLanguage.javascript], @@ -1743,7 +1701,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay analysis on PR if memory flag is too low and skip resource checks flag is enabled", { languages: [KnownLanguage.javascript], @@ -1762,7 +1720,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR when code-scanning feature enabled with disable-default-queries", { languages: [KnownLanguage.javascript], @@ -1776,14 +1734,12 @@ test.serial( isPullRequest: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.NonDefaultQueries, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR when code-scanning feature enabled with packs", { languages: [KnownLanguage.javascript], @@ -1797,14 +1753,12 @@ test.serial( isPullRequest: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.NonDefaultQueries, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR when code-scanning feature enabled with queries", { languages: [KnownLanguage.javascript], @@ -1818,14 +1772,12 @@ test.serial( isPullRequest: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.NonDefaultQueries, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR when code-scanning feature enabled with query-filters", { languages: [KnownLanguage.javascript], @@ -1839,14 +1791,12 @@ test.serial( isPullRequest: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.NonDefaultQueries, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR when only language-specific feature enabled", { languages: [KnownLanguage.javascript], @@ -1854,14 +1804,12 @@ test.serial( isPullRequest: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.OverallFeatureNotEnabled, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR when only code-scanning feature enabled", { languages: [KnownLanguage.javascript], @@ -1869,14 +1817,12 @@ test.serial( isPullRequest: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.OverallFeatureNotEnabled, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay analysis on PR when language-specific feature disabled", { languages: [KnownLanguage.javascript], @@ -1884,14 +1830,12 @@ test.serial( isPullRequest: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.LanguageNotEnabled, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay PR analysis by env", { overlayDatabaseEnvVar: "overlay", @@ -1903,7 +1847,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay PR analysis by env on a runner with low disk space", { overlayDatabaseEnvVar: "overlay", @@ -1916,7 +1860,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay PR analysis by feature flag", { languages: [KnownLanguage.javascript], @@ -1930,7 +1874,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Fallback due to autobuild with traced language", { overlayDatabaseEnvVar: "overlay", @@ -1938,14 +1882,12 @@ test.serial( languages: [KnownLanguage.java], }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, disabledReason: OverlayDisabledReason.IncompatibleBuildMode, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Fallback due to no build mode with traced language", { overlayDatabaseEnvVar: "overlay", @@ -1953,70 +1895,60 @@ test.serial( languages: [KnownLanguage.java], }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, disabledReason: OverlayDisabledReason.IncompatibleBuildMode, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Fallback due to old CodeQL version", { overlayDatabaseEnvVar: "overlay", codeqlVersion: "2.14.0", }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, disabledReason: OverlayDisabledReason.IncompatibleCodeQl, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Fallback due to missing git root", { overlayDatabaseEnvVar: "overlay", gitRoot: undefined, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, disabledReason: OverlayDisabledReason.NoGitRoot, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Fallback due to old git version", { overlayDatabaseEnvVar: "overlay", gitVersion: new GitVersionInfo("2.30.0", "2.30.0"), // Version below required 2.38.0 }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, disabledReason: OverlayDisabledReason.IncompatibleGit, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Fallback when git version cannot be determined", { overlayDatabaseEnvVar: "overlay", gitVersion: undefined, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, disabledReason: OverlayDisabledReason.IncompatibleGit, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "No overlay when disabled via repository property", { languages: [KnownLanguage.javascript], @@ -2027,14 +1959,12 @@ test.serial( }, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, disabledReason: OverlayDisabledReason.DisabledByRepositoryProperty, }, ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Overlay not disabled when repository property is false", { languages: [KnownLanguage.javascript], @@ -2051,7 +1981,7 @@ test.serial( ); test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, "Environment variable override takes precedence over repository property", { overlayDatabaseEnvVar: "overlay", @@ -2068,7 +1998,7 @@ test.serial( // Exercise language-specific overlay analysis features code paths for (const language in KnownLanguage) { test.serial( - getOverlayDatabaseModeMacro, + checkOverlayEnablementMacro, `Check default overlay analysis feature for ${language}`, { languages: [language], @@ -2076,9 +2006,7 @@ for (const language in KnownLanguage) { isPullRequest: true, }, { - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: OverlayDisabledReason.FeatureNotEnabled, + disabledReason: OverlayDisabledReason.LanguageNotEnabled, }, ); } diff --git a/src/config-utils.ts b/src/config-utils.ts index 14274a723..b80586938 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -69,6 +69,9 @@ import { isInTestMode, joinAtMost, DiskUsage, + Result, + Success, + Failure, } from "./util"; /** @@ -653,14 +656,18 @@ const OVERLAY_ANALYSIS_CODE_SCANNING_FEATURES: Record = { swift: Feature.OverlayAnalysisCodeScanningSwift, }; -async function isOverlayAnalysisFeatureEnabled( +/** + * Checks whether the overlay analysis feature is enabled for the given + * languages and configuration. + */ +async function checkOverlayAnalysisFeatureEnabled( features: FeatureEnablement, codeql: CodeQL, languages: Language[], codeScanningConfig: UserConfig, -): Promise { +): Promise> { if (!(await features.getValue(Feature.OverlayAnalysis, codeql))) { - return false; + return new Failure(OverlayDisabledReason.OverallFeatureNotEnabled); } let enableForCodeScanningOnly = false; for (const language of languages) { @@ -677,39 +684,35 @@ async function isOverlayAnalysisFeatureEnabled( enableForCodeScanningOnly = true; continue; } - return false; + return new Failure(OverlayDisabledReason.LanguageNotEnabled); } if (enableForCodeScanningOnly) { // A code-scanning configuration runs only the (default) code-scanning suite // if the default queries are not disabled, and no packs, queries, or // query-filters are specified. - return ( + const usesDefaultQueriesOnly = codeScanningConfig["disable-default-queries"] !== true && codeScanningConfig.packs === undefined && codeScanningConfig.queries === undefined && - codeScanningConfig["query-filters"] === undefined - ); + codeScanningConfig["query-filters"] === undefined; + if (!usesDefaultQueriesOnly) { + return new Failure(OverlayDisabledReason.NonDefaultQueries); + } } - return true; + return new Success(undefined); } /** Checks if the runner has enough disk space for overlay analysis. */ function runnerHasSufficientDiskSpace( - diskUsage: DiskUsage | undefined, + diskUsage: DiskUsage, logger: Logger, useV2ResourceChecks: boolean, ): boolean { const minimumDiskSpaceBytes = useV2ResourceChecks ? OVERLAY_MINIMUM_AVAILABLE_DISK_SPACE_V2_BYTES : OVERLAY_MINIMUM_AVAILABLE_DISK_SPACE_BYTES; - if ( - diskUsage === undefined || - diskUsage.numAvailableBytes < minimumDiskSpaceBytes - ) { - const diskSpaceMb = - diskUsage === undefined - ? 0 - : Math.round(diskUsage.numAvailableBytes / 1_000_000); + if (diskUsage.numAvailableBytes < minimumDiskSpaceBytes) { + const diskSpaceMb = Math.round(diskUsage.numAvailableBytes / 1_000_000); const minimumDiskSpaceMb = Math.round(minimumDiskSpaceBytes / 1_000_000); logger.info( `Setting overlay database mode to ${OverlayDatabaseMode.None} ` + @@ -754,23 +757,28 @@ async function runnerHasSufficientMemory( } /** - * Checks if the runner supports overlay analysis based on available disk space - * and the maximum memory CodeQL will be allowed to use. + * Checks if the runner has sufficient disk space and memory for overlay + * analysis. */ -async function runnerSupportsOverlayAnalysis( +async function checkRunnerResources( codeql: CodeQL, - diskUsage: DiskUsage | undefined, + diskUsage: DiskUsage, ramInput: string | undefined, logger: Logger, useV2ResourceChecks: boolean, -): Promise { +): Promise> { if (!runnerHasSufficientDiskSpace(diskUsage, logger, useV2ResourceChecks)) { - return false; + return new Failure(OverlayDisabledReason.InsufficientDiskSpace); } if (!(await runnerHasSufficientMemory(codeql, ramInput, logger))) { - return false; + return new Failure(OverlayDisabledReason.InsufficientMemory); } - return true; + return new Success(undefined); +} + +interface EnabledOverlayConfig { + overlayDatabaseMode: Exclude; + useOverlayDatabaseCaching: boolean; } /** @@ -791,10 +799,11 @@ async function runnerSupportsOverlayAnalysis( * For `Overlay` and `OverlayBase`, the function performs further checks and * reverts to `None` if any check should fail. * - * @returns An object containing the overlay database mode and whether the - * action should perform overlay-base database caching. + * @returns A `Success` containing the overlay database mode and whether the + * action should perform overlay-base database caching, or a `Failure` + * containing the reason why overlay analysis is disabled. */ -export async function getOverlayDatabaseMode( +export async function checkOverlayEnablement( codeql: CodeQL, features: FeatureEnablement, languages: Language[], @@ -805,15 +814,7 @@ export async function getOverlayDatabaseMode( repositoryProperties: RepositoryProperties, gitVersion: GitVersionInfo | undefined, logger: Logger, -): Promise<{ - overlayDatabaseMode: OverlayDatabaseMode; - useOverlayDatabaseCaching: boolean; - disabledReason: OverlayDisabledReason | undefined; -}> { - let overlayDatabaseMode = OverlayDatabaseMode.None; - let useOverlayDatabaseCaching = false; - let disabledReason: OverlayDisabledReason | undefined; - +): Promise> { const modeEnv = process.env.CODEQL_OVERLAY_DATABASE_MODE; // Any unrecognized CODEQL_OVERLAY_DATABASE_MODE value will be ignored and // treated as if the environment variable was not set. @@ -822,101 +823,132 @@ export async function getOverlayDatabaseMode( modeEnv === OverlayDatabaseMode.OverlayBase || modeEnv === OverlayDatabaseMode.None ) { - overlayDatabaseMode = modeEnv; logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} ` + + `Setting overlay database mode to ${modeEnv} ` + "from the CODEQL_OVERLAY_DATABASE_MODE environment variable.", ); - } else if ( - repositoryProperties[RepositoryPropertyName.DISABLE_OVERLAY] === true - ) { + if (modeEnv === OverlayDatabaseMode.None) { + return new Failure(OverlayDisabledReason.DisabledByEnvironmentVariable); + } + return validateOverlayDatabaseMode( + modeEnv, + false, + codeql, + languages, + sourceRoot, + buildMode, + gitVersion, + logger, + ); + } + + if (repositoryProperties[RepositoryPropertyName.DISABLE_OVERLAY] === true) { logger.info( `Setting overlay database mode to ${OverlayDatabaseMode.None} ` + `because the ${RepositoryPropertyName.DISABLE_OVERLAY} repository property is set to true.`, ); - overlayDatabaseMode = OverlayDatabaseMode.None; - disabledReason = OverlayDisabledReason.DisabledByRepositoryProperty; - } else if ( - await isOverlayAnalysisFeatureEnabled( - features, - codeql, - languages, - codeScanningConfig, - ) + return new Failure(OverlayDisabledReason.DisabledByRepositoryProperty); + } + + const featureResult = await checkOverlayAnalysisFeatureEnabled( + features, + codeql, + languages, + codeScanningConfig, + ); + if (featureResult.isFailure()) { + return featureResult; + } + + const performResourceChecks = !(await features.getValue( + Feature.OverlayAnalysisSkipResourceChecks, + codeql, + )); + const useV2ResourceChecks = await features.getValue( + Feature.OverlayAnalysisResourceChecksV2, + ); + const checkOverlayStatus = await features.getValue( + Feature.OverlayAnalysisStatusCheck, + ); + const needDiskUsage = performResourceChecks || checkOverlayStatus; + const diskUsage = needDiskUsage ? await checkDiskUsage(logger) : undefined; + if (needDiskUsage && diskUsage === undefined) { + logger.warning( + `Unable to determine disk usage, therefore setting overlay database mode to ${OverlayDatabaseMode.None}.`, + ); + return new Failure(OverlayDisabledReason.UnableToDetermineDiskUsage); + } + const resourceResult = + performResourceChecks && diskUsage !== undefined + ? await checkRunnerResources( + codeql, + diskUsage, + ramInput, + logger, + useV2ResourceChecks, + ) + : new Success(undefined); + if (resourceResult.isFailure()) { + return resourceResult; + } + if ( + checkOverlayStatus && + diskUsage !== undefined && + (await shouldSkipOverlayAnalysis(codeql, languages, diskUsage, logger)) ) { - const performResourceChecks = !(await features.getValue( - Feature.OverlayAnalysisSkipResourceChecks, - codeql, - )); - const useV2ResourceChecks = await features.getValue( - Feature.OverlayAnalysisResourceChecksV2, + logger.info( + `Setting overlay database mode to ${OverlayDatabaseMode.None} ` + + "because overlay analysis previously failed with this combination of languages, " + + "disk space, and CodeQL version.", ); - const checkOverlayStatus = await features.getValue( - Feature.OverlayAnalysisStatusCheck, + return new Failure(OverlayDisabledReason.SkippedDueToCachedStatus); + } + + let overlayDatabaseMode: OverlayDatabaseMode; + if (isAnalyzingPullRequest()) { + overlayDatabaseMode = OverlayDatabaseMode.Overlay; + logger.info( + `Setting overlay database mode to ${overlayDatabaseMode} ` + + "with caching because we are analyzing a pull request.", + ); + } else if (await isAnalyzingDefaultBranch()) { + overlayDatabaseMode = OverlayDatabaseMode.OverlayBase; + logger.info( + `Setting overlay database mode to ${overlayDatabaseMode} ` + + "with caching because we are analyzing the default branch.", ); - const diskUsage = - performResourceChecks || checkOverlayStatus - ? await checkDiskUsage(logger) - : undefined; - if ( - performResourceChecks && - !(await runnerSupportsOverlayAnalysis( - codeql, - diskUsage, - ramInput, - logger, - useV2ResourceChecks, - )) - ) { - overlayDatabaseMode = OverlayDatabaseMode.None; - disabledReason = OverlayDisabledReason.InsufficientResources; - } else if (checkOverlayStatus && diskUsage === undefined) { - logger.warning( - `Unable to determine disk usage, therefore setting overlay database mode to ${OverlayDatabaseMode.None}.`, - ); - overlayDatabaseMode = OverlayDatabaseMode.None; - disabledReason = OverlayDisabledReason.UnableToDetermineDiskUsage; - } else if ( - checkOverlayStatus && - diskUsage && - (await shouldSkipOverlayAnalysis(codeql, languages, diskUsage, logger)) - ) { - logger.info( - `Setting overlay database mode to ${OverlayDatabaseMode.None} ` + - "because overlay analysis previously failed with this combination of languages, " + - "disk space, and CodeQL version.", - ); - overlayDatabaseMode = OverlayDatabaseMode.None; - disabledReason = OverlayDisabledReason.SkippedDueToCachedStatus; - } else if (isAnalyzingPullRequest()) { - overlayDatabaseMode = OverlayDatabaseMode.Overlay; - useOverlayDatabaseCaching = true; - logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} ` + - "with caching because we are analyzing a pull request.", - ); - } else if (await isAnalyzingDefaultBranch()) { - overlayDatabaseMode = OverlayDatabaseMode.OverlayBase; - useOverlayDatabaseCaching = true; - logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} ` + - "with caching because we are analyzing the default branch.", - ); - } } else { - disabledReason = OverlayDisabledReason.FeatureNotEnabled; + return new Failure(OverlayDisabledReason.NotPullRequestOrDefaultBranch); } - const disabledResult = (reason: OverlayDisabledReason | undefined) => ({ - overlayDatabaseMode: OverlayDatabaseMode.None, - useOverlayDatabaseCaching: false, - disabledReason: reason, - }); - - if (overlayDatabaseMode === OverlayDatabaseMode.None) { - return disabledResult(disabledReason); - } + return validateOverlayDatabaseMode( + overlayDatabaseMode, + true, + codeql, + languages, + sourceRoot, + buildMode, + gitVersion, + logger, + ); +} +/** + * Validates that the given overlay database mode is compatible with the current + * configuration (build mode, CodeQL version, git repository, git version). Returns + * the mode unchanged if all checks pass, or falls back to `None` with the + * appropriate disabled reason. + */ +async function validateOverlayDatabaseMode( + overlayDatabaseMode: Exclude, + useOverlayDatabaseCaching: boolean, + codeql: CodeQL, + languages: Language[], + sourceRoot: string, + buildMode: BuildMode | undefined, + gitVersion: GitVersionInfo | undefined, + logger: Logger, +): Promise> { if ( buildMode !== BuildMode.None && ( @@ -937,7 +969,7 @@ export async function getOverlayDatabaseMode( `build-mode is set to "${buildMode}" instead of "none". ` + "Falling back to creating a normal full database instead.", ); - return disabledResult(OverlayDisabledReason.IncompatibleBuildMode); + return new Failure(OverlayDisabledReason.IncompatibleBuildMode); } if (!(await codeQlVersionAtLeast(codeql, CODEQL_OVERLAY_MINIMUM_VERSION))) { logger.warning( @@ -945,7 +977,7 @@ export async function getOverlayDatabaseMode( `the CodeQL CLI is older than ${CODEQL_OVERLAY_MINIMUM_VERSION}. ` + "Falling back to creating a normal full database instead.", ); - return disabledResult(OverlayDisabledReason.IncompatibleCodeQl); + return new Failure(OverlayDisabledReason.IncompatibleCodeQl); } if ((await getGitRoot(sourceRoot)) === undefined) { logger.warning( @@ -953,7 +985,7 @@ export async function getOverlayDatabaseMode( `the source root "${sourceRoot}" is not inside a git repository. ` + "Falling back to creating a normal full database instead.", ); - return disabledResult(OverlayDisabledReason.NoGitRoot); + return new Failure(OverlayDisabledReason.NoGitRoot); } if (gitVersion === undefined) { logger.warning( @@ -961,7 +993,7 @@ export async function getOverlayDatabaseMode( "the Git version could not be determined. " + "Falling back to creating a normal full database instead.", ); - return disabledResult(OverlayDisabledReason.IncompatibleGit); + return new Failure(OverlayDisabledReason.IncompatibleGit); } if (!gitVersion.isAtLeast(GIT_MINIMUM_VERSION_FOR_OVERLAY)) { logger.warning( @@ -969,14 +1001,13 @@ export async function getOverlayDatabaseMode( `the installed Git version is older than ${GIT_MINIMUM_VERSION_FOR_OVERLAY}. ` + "Falling back to creating a normal full database instead.", ); - return disabledResult(OverlayDisabledReason.IncompatibleGit); + return new Failure(OverlayDisabledReason.IncompatibleGit); } - return { + return new Success({ overlayDatabaseMode, useOverlayDatabaseCaching, - disabledReason, - }; + }); } function dbLocationOrDefault( @@ -1122,11 +1153,7 @@ export async function initConfig( // and queries, which in turn depends on the user config and the augmentation // properties. So we need to calculate the overlay database mode after the // rest of the config has been populated. - const { - overlayDatabaseMode, - useOverlayDatabaseCaching, - disabledReason: overlayDisabledReason, - } = await getOverlayDatabaseMode( + const overlayDatabaseModeResult = await checkOverlayEnablement( inputs.codeql, inputs.features, config.languages, @@ -1138,14 +1165,22 @@ export async function initConfig( gitVersion, logger, ); - logger.info( - `Using overlay database mode: ${overlayDatabaseMode} ` + - `${useOverlayDatabaseCaching ? "with" : "without"} caching.`, - ); - config.overlayDatabaseMode = overlayDatabaseMode; - config.useOverlayDatabaseCaching = useOverlayDatabaseCaching; - - if (overlayDisabledReason !== undefined) { + if (overlayDatabaseModeResult.isSuccess()) { + const { overlayDatabaseMode, useOverlayDatabaseCaching } = + overlayDatabaseModeResult.value; + logger.info( + `Using overlay database mode: ${overlayDatabaseMode} ` + + `${useOverlayDatabaseCaching ? "with" : "without"} caching.`, + ); + config.overlayDatabaseMode = overlayDatabaseMode; + config.useOverlayDatabaseCaching = useOverlayDatabaseCaching; + } else { + const overlayDisabledReason = overlayDatabaseModeResult.value; + logger.info( + `Using overlay database mode: ${OverlayDatabaseMode.None} without caching.`, + ); + config.overlayDatabaseMode = OverlayDatabaseMode.None; + config.useOverlayDatabaseCaching = false; await addOverlayDisablementDiagnostics( config, inputs.codeql, @@ -1154,7 +1189,7 @@ export async function initConfig( } if ( - overlayDatabaseMode === OverlayDatabaseMode.Overlay || + config.overlayDatabaseMode === OverlayDatabaseMode.Overlay || (await shouldPerformDiffInformedAnalysis( inputs.codeql, inputs.features, diff --git a/src/overlay/diagnostics.ts b/src/overlay/diagnostics.ts index abf3c24a7..6bc11a73f 100644 --- a/src/overlay/diagnostics.ts +++ b/src/overlay/diagnostics.ts @@ -10,20 +10,35 @@ import { RepositoryPropertyName } from "../feature-flags/properties"; /** Reason why overlay analysis was disabled. */ export enum OverlayDisabledReason { + /** Overlay analysis was disabled by the CODEQL_OVERLAY_DATABASE_MODE environment variable being set to "none". */ + DisabledByEnvironmentVariable = "disabled-by-environment-variable", /** Overlay analysis was disabled by a repository property. */ DisabledByRepositoryProperty = "disabled-by-repository-property", - /** Overlay analysis feature was not enabled. */ - FeatureNotEnabled = "feature-not-enabled", /** The build mode is incompatible with overlay analysis. */ IncompatibleBuildMode = "incompatible-build-mode", /** The CodeQL CLI version is too old to support overlay analysis. */ IncompatibleCodeQl = "incompatible-codeql", /** The Git version could not be determined or is too old. */ IncompatibleGit = "incompatible-git", - /** The runner does not have enough disk space or memory. */ - InsufficientResources = "insufficient-resources", + /** The runner does not have enough disk space to perform overlay analysis. */ + InsufficientDiskSpace = "insufficient-disk-space", + /** The runner does not have enough memory to perform overlay analysis. */ + InsufficientMemory = "insufficient-memory", + /** Overlay analysis is not enabled for one or more of the configured languages. */ + LanguageNotEnabled = "language-not-enabled", /** The source root is not inside a git repository. */ NoGitRoot = "no-git-root", + /** + * For one or more of the configured languages, overlay analysis is only + * enabled when using the default query suite, but the config customises the + * queries by disabling default queries, specifying custom queries or packs, + * or adding query filters. + */ + NonDefaultQueries = "non-default-queries", + /** We are not analyzing a pull request or the default branch. */ + NotPullRequestOrDefaultBranch = "not-pull-request-or-default-branch", + /** The top-level overlay analysis feature flag is not enabled. */ + OverallFeatureNotEnabled = "overall-feature-not-enabled", /** Overlay analysis was skipped because it previously failed with similar hardware resources. */ SkippedDueToCachedStatus = "skipped-due-to-cached-status", /** Disk usage could not be determined during the overlay status check. */