From cf8b7a6e14d039e1cb0f7b5afbe0f2830bab2c11 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 12 Nov 2025 11:55:59 +0000 Subject: [PATCH 1/5] Refactor C# cache content paths into a function --- lib/analyze-action.js | 5 ++++- lib/init-action.js | 5 ++++- src/dependency-caching.ts | 13 ++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index fd43a2f778..72943ee05a 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -91069,6 +91069,9 @@ function getJavaDependencyDirs() { getJavaTempDependencyDir() ]; } +function getCsharpDependencyDirs() { + return [(0, import_path.join)(os3.homedir(), ".nuget", "packages")]; +} async function makePatternCheck(patterns) { const globber = await makeGlobber(patterns); if ((await globber.glob()).length === 0) { @@ -91113,7 +91116,7 @@ var defaultCacheConfigs = { ]) }, csharp: { - getDependencyPaths: () => [(0, import_path.join)(os3.homedir(), ".nuget", "packages")], + getDependencyPaths: getCsharpDependencyDirs, getHashPatterns: getCsharpHashPatterns }, go: { diff --git a/lib/init-action.js b/lib/init-action.js index 98c23c88fd..2d361f8f43 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -87256,6 +87256,9 @@ function getJavaDependencyDirs() { getJavaTempDependencyDir() ]; } +function getCsharpDependencyDirs() { + return [(0, import_path.join)(os2.homedir(), ".nuget", "packages")]; +} async function makePatternCheck(patterns) { const globber = await makeGlobber(patterns); if ((await globber.glob()).length === 0) { @@ -87300,7 +87303,7 @@ var defaultCacheConfigs = { ]) }, csharp: { - getDependencyPaths: () => [(0, import_path.join)(os2.homedir(), ".nuget", "packages")], + getDependencyPaths: getCsharpDependencyDirs, getHashPatterns: getCsharpHashPatterns }, go: { diff --git a/src/dependency-caching.ts b/src/dependency-caching.ts index 220f1d5bab..e8c31a0761 100644 --- a/src/dependency-caching.ts +++ b/src/dependency-caching.ts @@ -66,6 +66,17 @@ export function getJavaDependencyDirs(): string[] { ]; } +/** + * Returns an array of paths of directories on the runner that should be included in a dependency cache + * for a C# analysis. + * + * @returns The paths of directories on the runner that should be included in a dependency cache + * for a C# analysis. + */ +export function getCsharpDependencyDirs(): string[] { + return [join(os.homedir(), ".nuget", "packages")]; +} + /** * Checks that there are files which match `patterns`. If there are matching files for any of the patterns, * this function returns all `patterns`. Otherwise, `undefined` is returned. @@ -158,7 +169,7 @@ const defaultCacheConfigs: { [language: string]: CacheConfig } = { ]), }, csharp: { - getDependencyPaths: () => [join(os.homedir(), ".nuget", "packages")], + getDependencyPaths: getCsharpDependencyDirs, getHashPatterns: getCsharpHashPatterns, }, go: { From d854ba6ec02875972a6bd990f236c62b8f6f21a2 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 12 Nov 2025 11:58:22 +0000 Subject: [PATCH 2/5] Pass `FeatureEnablement` to `getDependencyPaths` --- lib/analyze-action.js | 13 ++++++++----- lib/init-action.js | 8 ++++---- src/dependency-caching.test.ts | 4 ++-- src/dependency-caching.ts | 29 ++++++++++++++++++++++------- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 72943ee05a..fb9ec0a2e7 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -91059,7 +91059,7 @@ var CODEQL_DEPENDENCY_CACHE_VERSION = 1; function getJavaTempDependencyDir() { return (0, import_path.join)(getTemporaryDirectory(), "codeql_java", "repository"); } -function getJavaDependencyDirs() { +async function getJavaDependencyDirs() { return [ // Maven (0, import_path.join)(os3.homedir(), ".m2", "repository"), @@ -91069,7 +91069,7 @@ function getJavaDependencyDirs() { getJavaTempDependencyDir() ]; } -function getCsharpDependencyDirs() { +async function getCsharpDependencyDirs() { return [(0, import_path.join)(os3.homedir(), ".nuget", "packages")]; } async function makePatternCheck(patterns) { @@ -91120,7 +91120,7 @@ var defaultCacheConfigs = { getHashPatterns: getCsharpHashPatterns }, go: { - getDependencyPaths: () => [(0, import_path.join)(os3.homedir(), "go", "pkg", "mod")], + getDependencyPaths: async () => [(0, import_path.join)(os3.homedir(), "go", "pkg", "mod")], getHashPatterns: async () => internal.makePatternCheck(["**/go.sum"]) } }; @@ -91159,7 +91159,7 @@ async function uploadDependencyCaches(codeql, features, config, logger) { continue; } const size = await getTotalCacheSize( - cacheConfig.getDependencyPaths(), + await cacheConfig.getDependencyPaths(codeql, features), logger, true ); @@ -91176,7 +91176,10 @@ async function uploadDependencyCaches(codeql, features, config, logger) { ); try { const start = performance.now(); - await actionsCache3.saveCache(cacheConfig.getDependencyPaths(), key); + await actionsCache3.saveCache( + await cacheConfig.getDependencyPaths(codeql, features), + key + ); const upload_duration_ms = Math.round(performance.now() - start); status.push({ language, diff --git a/lib/init-action.js b/lib/init-action.js index 2d361f8f43..d3f0d35c30 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -87246,7 +87246,7 @@ var CODEQL_DEPENDENCY_CACHE_VERSION = 1; function getJavaTempDependencyDir() { return (0, import_path.join)(getTemporaryDirectory(), "codeql_java", "repository"); } -function getJavaDependencyDirs() { +async function getJavaDependencyDirs() { return [ // Maven (0, import_path.join)(os2.homedir(), ".m2", "repository"), @@ -87256,7 +87256,7 @@ function getJavaDependencyDirs() { getJavaTempDependencyDir() ]; } -function getCsharpDependencyDirs() { +async function getCsharpDependencyDirs() { return [(0, import_path.join)(os2.homedir(), ".nuget", "packages")]; } async function makePatternCheck(patterns) { @@ -87307,7 +87307,7 @@ var defaultCacheConfigs = { getHashPatterns: getCsharpHashPatterns }, go: { - getDependencyPaths: () => [(0, import_path.join)(os2.homedir(), "go", "pkg", "mod")], + getDependencyPaths: async () => [(0, import_path.join)(os2.homedir(), "go", "pkg", "mod")], getHashPatterns: async () => internal.makePatternCheck(["**/go.sum"]) } }; @@ -87356,7 +87356,7 @@ async function downloadDependencyCaches(codeql, features, languages, logger) { ); const start = performance.now(); const hitKey = await actionsCache3.restoreCache( - cacheConfig.getDependencyPaths(), + await cacheConfig.getDependencyPaths(codeql, features), primaryKey, restoreKeys ); diff --git a/src/dependency-caching.test.ts b/src/dependency-caching.test.ts index eefb8504cd..416b096776 100644 --- a/src/dependency-caching.test.ts +++ b/src/dependency-caching.test.ts @@ -126,7 +126,7 @@ test("checkHashPatterns - logs when no patterns match", async (t) => { const features = createFeatures([]); const messages: LoggedMessage[] = []; const config: CacheConfig = { - getDependencyPaths: () => [], + getDependencyPaths: async () => [], getHashPatterns: async () => undefined, }; @@ -155,7 +155,7 @@ test("checkHashPatterns - returns patterns when patterns match", async (t) => { fs.writeFileSync(path.join(tmpDir, "test.java"), ""); const config: CacheConfig = { - getDependencyPaths: () => [], + getDependencyPaths: async () => [], getHashPatterns: async () => makePatternCheck(patterns), }; diff --git a/src/dependency-caching.ts b/src/dependency-caching.ts index e8c31a0761..5ee0504371 100644 --- a/src/dependency-caching.ts +++ b/src/dependency-caching.ts @@ -20,7 +20,10 @@ import { getErrorMessage, getRequiredEnvParam } from "./util"; */ export interface CacheConfig { /** Gets the paths of directories on the runner that should be included in the cache. */ - getDependencyPaths: () => string[]; + getDependencyPaths: ( + codeql: CodeQL, + features: FeatureEnablement, + ) => Promise; /** * Gets an array of glob patterns for the paths of files whose contents affect which dependencies are used * by a project. This function also checks whether there are any matching files and returns @@ -55,7 +58,7 @@ export function getJavaTempDependencyDir(): string { * @returns The paths of directories on the runner that should be included in a dependency cache * for a Java analysis. */ -export function getJavaDependencyDirs(): string[] { +export async function getJavaDependencyDirs(): Promise { return [ // Maven join(os.homedir(), ".m2", "repository"), @@ -66,6 +69,15 @@ export function getJavaDependencyDirs(): string[] { ]; } +/** + * Returns a path to a directory intended to be used to store dependencies + * for the C# `build-mode: none` extractor. + * @returns The path to the directory that should be used by the `build-mode: none` extractor. + */ +export function getCsharpTempDependencyDir(): string { + return join(getTemporaryDirectory(), "codeql_csharp", "repository"); +} + /** * Returns an array of paths of directories on the runner that should be included in a dependency cache * for a C# analysis. @@ -73,7 +85,7 @@ export function getJavaDependencyDirs(): string[] { * @returns The paths of directories on the runner that should be included in a dependency cache * for a C# analysis. */ -export function getCsharpDependencyDirs(): string[] { +export async function getCsharpDependencyDirs(): Promise { return [join(os.homedir(), ".nuget", "packages")]; } @@ -173,7 +185,7 @@ const defaultCacheConfigs: { [language: string]: CacheConfig } = { getHashPatterns: getCsharpHashPatterns, }, go: { - getDependencyPaths: () => [join(os.homedir(), "go", "pkg", "mod")], + getDependencyPaths: async () => [join(os.homedir(), "go", "pkg", "mod")], getHashPatterns: async () => internal.makePatternCheck(["**/go.sum"]), }, }; @@ -291,7 +303,7 @@ export async function downloadDependencyCaches( const start = performance.now(); const hitKey = await actionsCache.restoreCache( - cacheConfig.getDependencyPaths(), + await cacheConfig.getDependencyPaths(codeql, features), primaryKey, restoreKeys, ); @@ -387,7 +399,7 @@ export async function uploadDependencyCaches( // with the dependency caches. For this, we could use the Cache API to check whether other workflows // are using the quota and how full it is. const size = await getTotalCacheSize( - cacheConfig.getDependencyPaths(), + await cacheConfig.getDependencyPaths(codeql, features), logger, true, ); @@ -409,7 +421,10 @@ export async function uploadDependencyCaches( try { const start = performance.now(); - await actionsCache.saveCache(cacheConfig.getDependencyPaths(), key); + await actionsCache.saveCache( + await cacheConfig.getDependencyPaths(codeql, features), + key, + ); const upload_duration_ms = Math.round(performance.now() - start); status.push({ From a47d04cf9b3e812f4fe0998e5e6ffd3a91cc88f2 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 12 Nov 2025 11:59:13 +0000 Subject: [PATCH 3/5] Add FF for extra C# cache contents --- lib/analyze-action-post.js | 5 +++++ lib/analyze-action.js | 5 +++++ lib/autobuild-action.js | 5 +++++ lib/init-action-post.js | 5 +++++ lib/init-action.js | 5 +++++ lib/resolve-environment-action.js | 5 +++++ lib/setup-codeql-action.js | 5 +++++ lib/start-proxy-action-post.js | 5 +++++ lib/start-proxy-action.js | 5 +++++ lib/upload-lib.js | 5 +++++ lib/upload-sarif-action-post.js | 5 +++++ lib/upload-sarif-action.js | 5 +++++ src/feature-flags.ts | 6 ++++++ 13 files changed, 66 insertions(+) diff --git a/lib/analyze-action-post.js b/lib/analyze-action-post.js index b30ab9f097..484df244c7 100644 --- a/lib/analyze-action-post.js +++ b/lib/analyze-action-post.js @@ -119928,6 +119928,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/analyze-action.js b/lib/analyze-action.js index fb9ec0a2e7..22d01ab285 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -88658,6 +88658,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/autobuild-action.js b/lib/autobuild-action.js index d09fe07d82..48485a850d 100644 --- a/lib/autobuild-action.js +++ b/lib/autobuild-action.js @@ -83977,6 +83977,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/init-action-post.js b/lib/init-action-post.js index 1d3c4d5d93..b15b16f377 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -123309,6 +123309,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/init-action.js b/lib/init-action.js index d3f0d35c30..e351b0205b 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -86072,6 +86072,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/resolve-environment-action.js b/lib/resolve-environment-action.js index 7918ab61f7..766a59c171 100644 --- a/lib/resolve-environment-action.js +++ b/lib/resolve-environment-action.js @@ -83968,6 +83968,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/setup-codeql-action.js b/lib/setup-codeql-action.js index c9e95730bf..f00d601e7d 100644 --- a/lib/setup-codeql-action.js +++ b/lib/setup-codeql-action.js @@ -83880,6 +83880,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/start-proxy-action-post.js b/lib/start-proxy-action-post.js index 2386e7c27b..85e0aaeb08 100644 --- a/lib/start-proxy-action-post.js +++ b/lib/start-proxy-action-post.js @@ -119334,6 +119334,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/start-proxy-action.js b/lib/start-proxy-action.js index 281341e5aa..5613603cb9 100644 --- a/lib/start-proxy-action.js +++ b/lib/start-proxy-action.js @@ -99996,6 +99996,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/upload-lib.js b/lib/upload-lib.js index 2e980ba467..a0d12250c7 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -87034,6 +87034,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/upload-sarif-action-post.js b/lib/upload-sarif-action-post.js index 1d2a3a44b3..1d63547086 100644 --- a/lib/upload-sarif-action-post.js +++ b/lib/upload-sarif-action-post.js @@ -119500,6 +119500,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 6fd196c32e..1266953f0c 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -86830,6 +86830,11 @@ var featureConfig = { legacyApi: true, minimumVersion: "2.15.0" }, + ["csharp_cache_bmn" /* CsharpCacheBuildModeNone */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: void 0 + }, ["csharp_new_cache_key" /* CsharpNewCacheKey */]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", diff --git a/src/feature-flags.ts b/src/feature-flags.ts index 1334969795..27a3c0f4f7 100644 --- a/src/feature-flags.ts +++ b/src/feature-flags.ts @@ -47,6 +47,7 @@ export enum Feature { AnalyzeUseNewUpload = "analyze_use_new_upload", CleanupTrapCaches = "cleanup_trap_caches", CppDependencyInstallation = "cpp_dependency_installation_enabled", + CsharpCacheBuildModeNone = "csharp_cache_bmn", CsharpNewCacheKey = "csharp_new_cache_key", DiffInformedQueries = "diff_informed_queries", DisableCsharpBuildless = "disable_csharp_buildless", @@ -133,6 +134,11 @@ export const featureConfig: Record< legacyApi: true, minimumVersion: "2.15.0", }, + [Feature.CsharpCacheBuildModeNone]: { + defaultValue: false, + envVar: "CODEQL_ACTION_CSHARP_CACHE_BMN", + minimumVersion: undefined, + }, [Feature.CsharpNewCacheKey]: { defaultValue: false, envVar: "CODEQL_ACTION_CSHARP_NEW_CACHE_KEY", From ecaa6db95a8f53d47a403cf9d16a96daa295f5ff Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 13 Nov 2025 13:40:36 +0000 Subject: [PATCH 4/5] Include `getCsharpTempDependencyDir` in C# caches if FF is enabled --- lib/analyze-action.js | 15 +++++++++-- lib/init-action.js | 15 +++++++++-- src/dependency-caching.test.ts | 49 ++++++++++++++++++++++++++++++++++ src/dependency-caching.ts | 17 ++++++++++-- 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 22d01ab285..6b0e6b92f6 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -91074,8 +91074,18 @@ async function getJavaDependencyDirs() { getJavaTempDependencyDir() ]; } -async function getCsharpDependencyDirs() { - return [(0, import_path.join)(os3.homedir(), ".nuget", "packages")]; +function getCsharpTempDependencyDir() { + return (0, import_path.join)(getTemporaryDirectory(), "codeql_csharp", "repository"); +} +async function getCsharpDependencyDirs(codeql, features) { + const dirs = [ + // Nuget + (0, import_path.join)(os3.homedir(), ".nuget", "packages") + ]; + if (await features.getValue("csharp_cache_bmn" /* CsharpCacheBuildModeNone */, codeql)) { + dirs.push(getCsharpTempDependencyDir()); + } + return dirs; } async function makePatternCheck(patterns) { const globber = await makeGlobber(patterns); @@ -91227,6 +91237,7 @@ async function getFeaturePrefix(codeql, features, language) { } } else if (language === "csharp" /* csharp */) { await addFeatureIfEnabled("csharp_new_cache_key" /* CsharpNewCacheKey */); + await addFeatureIfEnabled("csharp_cache_bmn" /* CsharpCacheBuildModeNone */); } if (enabledFeatures.length > 0) { return `${createCacheKeyHash(enabledFeatures)}-`; diff --git a/lib/init-action.js b/lib/init-action.js index e351b0205b..8d63c95de0 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -87261,8 +87261,18 @@ async function getJavaDependencyDirs() { getJavaTempDependencyDir() ]; } -async function getCsharpDependencyDirs() { - return [(0, import_path.join)(os2.homedir(), ".nuget", "packages")]; +function getCsharpTempDependencyDir() { + return (0, import_path.join)(getTemporaryDirectory(), "codeql_csharp", "repository"); +} +async function getCsharpDependencyDirs(codeql, features) { + const dirs = [ + // Nuget + (0, import_path.join)(os2.homedir(), ".nuget", "packages") + ]; + if (await features.getValue("csharp_cache_bmn" /* CsharpCacheBuildModeNone */, codeql)) { + dirs.push(getCsharpTempDependencyDir()); + } + return dirs; } async function makePatternCheck(patterns) { const globber = await makeGlobber(patterns); @@ -87398,6 +87408,7 @@ async function getFeaturePrefix(codeql, features, language) { } } else if (language === "csharp" /* csharp */) { await addFeatureIfEnabled("csharp_new_cache_key" /* CsharpNewCacheKey */); + await addFeatureIfEnabled("csharp_cache_bmn" /* CsharpCacheBuildModeNone */); } if (enabledFeatures.length > 0) { return `${createCacheKeyHash(enabledFeatures)}-`; diff --git a/src/dependency-caching.test.ts b/src/dependency-caching.test.ts index 416b096776..bf2f7ba74d 100644 --- a/src/dependency-caching.test.ts +++ b/src/dependency-caching.test.ts @@ -20,6 +20,8 @@ import { downloadDependencyCaches, CacheHitKind, cacheKey, + getCsharpDependencyDirs, + getCsharpTempDependencyDir, } from "./dependency-caching"; import { Feature } from "./feature-flags"; import { KnownLanguage } from "./languages"; @@ -38,6 +40,28 @@ function makeAbsolutePatterns(tmpDir: string, patterns: string[]): string[] { return patterns.map((pattern) => path.join(tmpDir, pattern)); } +test("getCsharpDependencyDirs - does not include BMN dir if FF is enabled", async (t) => { + await withTmpDir(async (tmpDir) => { + process.env["RUNNER_TEMP"] = tmpDir; + const codeql = createStubCodeQL({}); + const features = createFeatures([]); + + const results = await getCsharpDependencyDirs(codeql, features); + t.false(results.includes(getCsharpTempDependencyDir())); + }); +}); + +test("getCsharpDependencyDirs - includes BMN dir if FF is enabled", async (t) => { + await withTmpDir(async (tmpDir) => { + process.env["RUNNER_TEMP"] = tmpDir; + const codeql = createStubCodeQL({}); + const features = createFeatures([Feature.CsharpCacheBuildModeNone]); + + const results = await getCsharpDependencyDirs(codeql, features); + t.assert(results.includes(getCsharpTempDependencyDir())); + }); +}); + test("makePatternCheck - returns undefined if no patterns match", async (t) => { await withTmpDir(async (tmpDir) => { fs.writeFileSync(path.join(tmpDir, "test.java"), ""); @@ -387,3 +411,28 @@ test("getFeaturePrefix - non-C# - returns '' if CsharpNewCacheKey is enabled", a t.deepEqual(result, "", `Expected no feature prefix for ${knownLanguage}`); } }); + +test("getFeaturePrefix - C# - returns prefix if CsharpCacheBuildModeNone is enabled", async (t) => { + const codeql = createStubCodeQL({}); + const features = createFeatures([Feature.CsharpCacheBuildModeNone]); + + const result = await getFeaturePrefix(codeql, features, KnownLanguage.csharp); + t.notDeepEqual(result, ""); + t.assert(result.endsWith("-")); + // Check the length of the prefix, which should correspond to `cacheKeyHashLength` + 1 for the trailing `-`. + t.is(result.length, cacheKeyHashLength + 1); +}); + +test("getFeaturePrefix - non-C# - returns '' if CsharpCacheBuildModeNone is enabled", async (t) => { + const codeql = createStubCodeQL({}); + const features = createFeatures([Feature.CsharpCacheBuildModeNone]); + + for (const knownLanguage of Object.values(KnownLanguage)) { + // Skip C# since we expect a result for it, which is tested in the previous test. + if (knownLanguage === KnownLanguage.csharp) { + continue; + } + const result = await getFeaturePrefix(codeql, features, knownLanguage); + t.deepEqual(result, "", `Expected no feature prefix for ${knownLanguage}`); + } +}); diff --git a/src/dependency-caching.ts b/src/dependency-caching.ts index 5ee0504371..bd39bad751 100644 --- a/src/dependency-caching.ts +++ b/src/dependency-caching.ts @@ -85,8 +85,20 @@ export function getCsharpTempDependencyDir(): string { * @returns The paths of directories on the runner that should be included in a dependency cache * for a C# analysis. */ -export async function getCsharpDependencyDirs(): Promise { - return [join(os.homedir(), ".nuget", "packages")]; +export async function getCsharpDependencyDirs( + codeql: CodeQL, + features: FeatureEnablement, +): Promise { + const dirs = [ + // Nuget + join(os.homedir(), ".nuget", "packages"), + ]; + + if (await features.getValue(Feature.CsharpCacheBuildModeNone, codeql)) { + dirs.push(getCsharpTempDependencyDir()); + } + + return dirs; } /** @@ -512,6 +524,7 @@ export async function getFeaturePrefix( } } else if (language === KnownLanguage.csharp) { await addFeatureIfEnabled(Feature.CsharpNewCacheKey); + await addFeatureIfEnabled(Feature.CsharpCacheBuildModeNone); } // If any features that affect the cache are enabled, return a feature prefix by From f5f9571d6184d3cf1e2477d1dfc61c7ce88cdf4b Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 13 Nov 2025 14:03:44 +0000 Subject: [PATCH 5/5] Configure temp dependency dir for C# extractor when FF is enabled And also clean it up. --- lib/analyze-action-post.js | 24 ++++++++++++++++-------- lib/analyze-action.js | 13 +++++++++---- src/analyze-action-env.test.ts | 21 +++++++++++++++------ src/analyze-action-input.test.ts | 21 +++++++++++++++------ src/analyze-action-post.ts | 28 ++++++++++++++++++---------- src/analyze-action.ts | 1 + src/analyze.ts | 22 +++++++++++++++++++--- 7 files changed, 93 insertions(+), 37 deletions(-) diff --git a/lib/analyze-action-post.js b/lib/analyze-action-post.js index 484df244c7..323549b8b1 100644 --- a/lib/analyze-action-post.js +++ b/lib/analyze-action-post.js @@ -120768,6 +120768,9 @@ var glob = __toESM(require_glob3()); function getJavaTempDependencyDir() { return (0, import_path.join)(getTemporaryDirectory(), "codeql_java", "repository"); } +function getCsharpTempDependencyDir() { + return (0, import_path.join)(getTemporaryDirectory(), "codeql_csharp", "repository"); +} // src/debug-artifacts.ts function sanitizeArtifactName(name) { @@ -120888,14 +120891,19 @@ async function runWrapper() { ); } } - const javaTempDependencyDir = getJavaTempDependencyDir(); - if (fs6.existsSync(javaTempDependencyDir)) { - try { - fs6.rmSync(javaTempDependencyDir, { recursive: true }); - } catch (error4) { - logger.info( - `Failed to remove temporary Java dependencies directory: ${getErrorMessage(error4)}` - ); + const tempDependencyDirs = [ + getJavaTempDependencyDir(), + getCsharpTempDependencyDir() + ]; + for (const tempDependencyDir of tempDependencyDirs) { + if (fs6.existsSync(tempDependencyDir)) { + try { + fs6.rmSync(tempDependencyDir, { recursive: true }); + } catch (error4) { + logger.info( + `Failed to remove temporary dependencies directory: ${getErrorMessage(error4)}` + ); + } } } } catch (error4) { diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 6b0e6b92f6..e5e897ca38 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -91327,7 +91327,7 @@ async function setupPythonExtractor(logger) { ); return; } -async function runExtraction(codeql, config, logger) { +async function runExtraction(codeql, features, config, logger) { for (const language of config.languages) { if (dbIsFinalized(config, language, logger)) { logger.debug( @@ -91347,6 +91347,9 @@ async function runExtraction(codeql, config, logger) { if (language === "java" /* java */ && config.buildMode === "none" /* None */) { process.env["CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_DEPENDENCY_DIR"] = getJavaTempDependencyDir(); } + if (language === "csharp" /* csharp */ && config.buildMode === "none" /* None */ && await features.getValue("csharp_cache_bmn" /* CsharpCacheBuildModeNone */)) { + process.env["CODEQL_EXTRACTOR_CSHARP_OPTION_BUILDLESS_DEPENDENCY_DIR"] = getCsharpTempDependencyDir(); + } await codeql.extractUsingBuildMode(config, language); } else { await codeql.extractScannedLanguage(config, language); @@ -91372,9 +91375,9 @@ function dbIsFinalized(config, language, logger) { return false; } } -async function finalizeDatabaseCreation(codeql, config, threadsFlag, memoryFlag, logger) { +async function finalizeDatabaseCreation(codeql, features, config, threadsFlag, memoryFlag, logger) { const extractionStart = import_perf_hooks2.performance.now(); - await runExtraction(codeql, config, logger); + await runExtraction(codeql, features, config, logger); const extractionTime = import_perf_hooks2.performance.now() - extractionStart; const trapImportStart = import_perf_hooks2.performance.now(); for (const language of config.languages) { @@ -91629,7 +91632,7 @@ async function runQueries(sarifFolder, memoryFlag, threadsFlag, diffRangePackDir return perQueryAlertCounts; } } -async function runFinalize(outputDir, threadsFlag, memoryFlag, codeql, config, logger) { +async function runFinalize(features, outputDir, threadsFlag, memoryFlag, codeql, config, logger) { try { await fs12.promises.rm(outputDir, { force: true, recursive: true }); } catch (error4) { @@ -91640,6 +91643,7 @@ async function runFinalize(outputDir, threadsFlag, memoryFlag, codeql, config, l await fs12.promises.mkdir(outputDir, { recursive: true }); const timings = await finalizeDatabaseCreation( codeql, + features, config, threadsFlag, memoryFlag, @@ -93974,6 +93978,7 @@ async function run() { await warnIfGoInstalledAfterInit(config, logger); await runAutobuildIfLegacyGoWorkflow(config, logger); dbCreationTimings = await runFinalize( + features, outputDir, threads, memory, diff --git a/src/analyze-action-env.test.ts b/src/analyze-action-env.test.ts index e4960a5803..aecbae4b02 100644 --- a/src/analyze-action-env.test.ts +++ b/src/analyze-action-env.test.ts @@ -74,11 +74,20 @@ test("analyze action with RAM & threads from environment variables", async (t) = // wait for the action promise to complete before starting verification. await analyzeAction.runPromise; - t.assert(runFinalizeStub.calledOnce); - t.deepEqual(runFinalizeStub.firstCall.args[1], "--threads=-1"); - t.deepEqual(runFinalizeStub.firstCall.args[2], "--ram=4992"); - t.assert(runQueriesStub.calledOnce); - t.deepEqual(runQueriesStub.firstCall.args[2], "--threads=-1"); - t.deepEqual(runQueriesStub.firstCall.args[1], "--ram=4992"); + t.assert( + runFinalizeStub.calledOnceWith( + sinon.match.any, + sinon.match.any, + "--threads=-1", + "--ram=4992", + ), + ); + t.assert( + runQueriesStub.calledOnceWith( + sinon.match.any, + "--ram=4992", + "--threads=-1", + ), + ); }); }); diff --git a/src/analyze-action-input.test.ts b/src/analyze-action-input.test.ts index 48fa216ebf..74c03923da 100644 --- a/src/analyze-action-input.test.ts +++ b/src/analyze-action-input.test.ts @@ -72,11 +72,20 @@ test("analyze action with RAM & threads from action inputs", async (t) => { // wait for the action promise to complete before starting verification. await analyzeAction.runPromise; - t.assert(runFinalizeStub.calledOnce); - t.deepEqual(runFinalizeStub.firstCall.args[1], "--threads=-1"); - t.deepEqual(runFinalizeStub.firstCall.args[2], "--ram=3012"); - t.assert(runQueriesStub.calledOnce); - t.deepEqual(runQueriesStub.firstCall.args[2], "--threads=-1"); - t.deepEqual(runQueriesStub.firstCall.args[1], "--ram=3012"); + t.assert( + runFinalizeStub.calledOnceWith( + sinon.match.any, + sinon.match.any, + "--threads=-1", + "--ram=3012", + ), + ); + t.assert( + runQueriesStub.calledOnceWith( + sinon.match.any, + "--ram=3012", + "--threads=-1", + ), + ); }); }); diff --git a/src/analyze-action-post.ts b/src/analyze-action-post.ts index 1f91b4f0fd..ce8ddd31bb 100644 --- a/src/analyze-action-post.ts +++ b/src/analyze-action-post.ts @@ -12,7 +12,10 @@ import { getGitHubVersion } from "./api-client"; import { getCodeQL } from "./codeql"; import { getConfig } from "./config-utils"; import * as debugArtifacts from "./debug-artifacts"; -import { getJavaTempDependencyDir } from "./dependency-caching"; +import { + getCsharpTempDependencyDir, + getJavaTempDependencyDir, +} from "./dependency-caching"; import { EnvVar } from "./environment"; import { getActionsLogger } from "./logging"; import { checkGitHubVersionInRange, getErrorMessage } from "./util"; @@ -42,17 +45,22 @@ async function runWrapper() { } } - // If we analysed Java in build-mode: none, we may have downloaded dependencies + // If we analysed Java or C# in build-mode: none, we may have downloaded dependencies // to the temp directory. Clean these up so they don't persist unnecessarily // long on self-hosted runners. - const javaTempDependencyDir = getJavaTempDependencyDir(); - if (fs.existsSync(javaTempDependencyDir)) { - try { - fs.rmSync(javaTempDependencyDir, { recursive: true }); - } catch (error) { - logger.info( - `Failed to remove temporary Java dependencies directory: ${getErrorMessage(error)}`, - ); + const tempDependencyDirs = [ + getJavaTempDependencyDir(), + getCsharpTempDependencyDir(), + ]; + for (const tempDependencyDir of tempDependencyDirs) { + if (fs.existsSync(tempDependencyDir)) { + try { + fs.rmSync(tempDependencyDir, { recursive: true }); + } catch (error) { + logger.info( + `Failed to remove temporary dependencies directory: ${getErrorMessage(error)}`, + ); + } } } } catch (error) { diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 3ab1dd1321..0349c13c30 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -315,6 +315,7 @@ async function run() { await runAutobuildIfLegacyGoWorkflow(config, logger); dbCreationTimings = await runFinalize( + features, outputDir, threads, memory, diff --git a/src/analyze.ts b/src/analyze.ts index cd82ad61b1..dc631ba98f 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -10,7 +10,10 @@ import * as analyses from "./analyses"; import { setupCppAutobuild } from "./autobuild"; import { type CodeQL } from "./codeql"; import * as configUtils from "./config-utils"; -import { getJavaTempDependencyDir } from "./dependency-caching"; +import { + getCsharpTempDependencyDir, + getJavaTempDependencyDir, +} from "./dependency-caching"; import { addDiagnostic, makeDiagnostic } from "./diagnostics"; import { DiffThunkRange, @@ -98,6 +101,7 @@ async function setupPythonExtractor(logger: Logger) { export async function runExtraction( codeql: CodeQL, + features: FeatureEnablement, config: configUtils.Config, logger: Logger, ) { @@ -122,7 +126,7 @@ export async function runExtraction( await setupCppAutobuild(codeql, logger); } - // The Java `build-mode: none` extractor places dependencies (.jar files) in the + // The Java and C# `build-mode: none` extractors place dependencies in the // database scratch directory by default. For dependency caching purposes, we want // a stable path that caches can be restored into and that we can cache at the // end of the workflow (i.e. that does not get removed when the scratch directory is). @@ -133,6 +137,15 @@ export async function runExtraction( process.env["CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_DEPENDENCY_DIR"] = getJavaTempDependencyDir(); } + if ( + language === KnownLanguage.csharp && + config.buildMode === BuildMode.None && + (await features.getValue(Feature.CsharpCacheBuildModeNone)) + ) { + process.env[ + "CODEQL_EXTRACTOR_CSHARP_OPTION_BUILDLESS_DEPENDENCY_DIR" + ] = getCsharpTempDependencyDir(); + } await codeql.extractUsingBuildMode(config, language); } else { @@ -177,13 +190,14 @@ export function dbIsFinalized( async function finalizeDatabaseCreation( codeql: CodeQL, + features: FeatureEnablement, config: configUtils.Config, threadsFlag: string, memoryFlag: string, logger: Logger, ): Promise { const extractionStart = performance.now(); - await runExtraction(codeql, config, logger); + await runExtraction(codeql, features, config, logger); const extractionTime = performance.now() - extractionStart; const trapImportStart = performance.now(); @@ -597,6 +611,7 @@ export async function runQueries( } export async function runFinalize( + features: FeatureEnablement, outputDir: string, threadsFlag: string, memoryFlag: string, @@ -615,6 +630,7 @@ export async function runFinalize( const timings = await finalizeDatabaseCreation( codeql, + features, config, threadsFlag, memoryFlag,