Skip to content

Commit f6e3125

Browse files
committed
Move check whether there are files for hashing into getHashPatterns
1 parent 889a052 commit f6e3125

File tree

3 files changed

+176
-57
lines changed

3 files changed

+176
-57
lines changed

lib/analyze-action.js

Lines changed: 39 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/init-action.js

Lines changed: 39 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/dependency-caching.ts

Lines changed: 98 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,27 @@ import { KnownLanguage, Language } from "./languages";
1414
import { Logger } from "./logging";
1515
import { getRequiredEnvParam } from "./util";
1616

17+
class NoMatchingFilesError extends Error {
18+
constructor(msg?: string) {
19+
super(msg);
20+
21+
this.name = "NoMatchingFilesError";
22+
}
23+
}
24+
1725
/**
1826
* Caching configuration for a particular language.
1927
*/
2028
interface CacheConfig {
2129
/** Gets the paths of directories on the runner that should be included in the cache. */
2230
getDependencyPaths: () => string[];
2331
/**
24-
* Gets patterns for the paths of files whose contents affect which dependencies are used
25-
* by a project. We find all files which match these patterns, calculate a hash for
26-
* their contents, and use that hash as part of the cache key.
32+
* Gets an array of glob patterns for the paths of files whose contents affect which dependencies are used
33+
* by a project. This function also checks whether there are any matching files and throws
34+
* a `NoMatchingFilesError` error if no files match.
35+
*
36+
* The glob patterns are intended to be used for cache keys, where we find all files which match these
37+
* patterns, calculate a hash for their contents, and use that hash as part of the cache key.
2738
*/
2839
getHashPatterns: (codeql: CodeQL, features: Features) => Promise<string[]>;
2940
}
@@ -59,43 +70,93 @@ export function getJavaDependencyDirs(): string[] {
5970
];
6071
}
6172

73+
/**
74+
* Checks that there are files which match `patterns`. If there are matching files for any of the patterns,
75+
* this function returns all `patterns`. Otherwise, a `NoMatchingFilesError` is thrown.
76+
*
77+
* @param patterns The glob patterns to find matching files for.
78+
* @returns The array of glob patterns if there are matching files.
79+
*/
80+
async function makePatternCheck(patterns: string[]): Promise<string[]> {
81+
const globber = await makeGlobber(patterns);
82+
83+
if ((await globber.glob()).length === 0) {
84+
throw new NoMatchingFilesError();
85+
}
86+
87+
return patterns;
88+
}
89+
6290
/**
6391
* Default caching configurations per language.
6492
*/
6593
const defaultCacheConfigs: { [language: string]: CacheConfig } = {
6694
java: {
6795
getDependencyPaths: getJavaDependencyDirs,
68-
getHashPatterns: async () => [
69-
// Maven
70-
"**/pom.xml",
71-
// Gradle
72-
"**/*.gradle*",
73-
"**/gradle-wrapper.properties",
74-
"buildSrc/**/Versions.kt",
75-
"buildSrc/**/Dependencies.kt",
76-
"gradle/*.versions.toml",
77-
"**/versions.properties",
78-
],
96+
getHashPatterns: async () =>
97+
makePatternCheck([
98+
// Maven
99+
"**/pom.xml",
100+
// Gradle
101+
"**/*.gradle*",
102+
"**/gradle-wrapper.properties",
103+
"buildSrc/**/Versions.kt",
104+
"buildSrc/**/Dependencies.kt",
105+
"gradle/*.versions.toml",
106+
"**/versions.properties",
107+
]),
79108
},
80109
csharp: {
81110
getDependencyPaths: () => [join(os.homedir(), ".nuget", "packages")],
82-
getHashPatterns: async () => [
83-
// NuGet
84-
"**/packages.lock.json",
85-
// Paket
86-
"**/paket.lock",
87-
],
111+
getHashPatterns: async () =>
112+
makePatternCheck([
113+
// NuGet
114+
"**/packages.lock.json",
115+
// Paket
116+
"**/paket.lock",
117+
]),
88118
},
89119
go: {
90120
getDependencyPaths: () => [join(os.homedir(), "go", "pkg", "mod")],
91-
getHashPatterns: async () => ["**/go.sum"],
121+
getHashPatterns: async () => makePatternCheck(["**/go.sum"]),
92122
},
93123
};
94124

95125
async function makeGlobber(patterns: string[]): Promise<glob.Globber> {
96126
return glob.create(patterns.join("\n"));
97127
}
98128

129+
/**
130+
* A wrapper around `cacheConfig.getHashPatterns` which catches `NoMatchingFilesError` errors,
131+
* and logs that there are no files to calculate a hash for the cache key from.
132+
*
133+
* @param codeql The CodeQL instance to use.
134+
* @param features Information about which FFs are enabled.
135+
* @param language The language the `CacheConfig` is for. For use in the log message.
136+
* @param cacheConfig The caching configuration to call `getHashPatterns` on.
137+
* @param logger The logger to write the log message to if there is an error.
138+
* @returns An array of glob patterns to use for hashing files, or `undefined` if there are no matching files.
139+
*/
140+
async function checkHashPatterns(
141+
codeql: CodeQL,
142+
features: Features,
143+
language: Language,
144+
cacheConfig: CacheConfig,
145+
logger: Logger,
146+
): Promise<string[] | undefined> {
147+
try {
148+
return cacheConfig.getHashPatterns(codeql, features);
149+
} catch (err) {
150+
if (err instanceof NoMatchingFilesError) {
151+
logger.info(
152+
`Skipping download of dependency cache for ${language} as we cannot calculate a hash for the cache key.`,
153+
);
154+
return undefined;
155+
}
156+
throw err;
157+
}
158+
}
159+
99160
/**
100161
* Attempts to restore dependency caches for the languages being analyzed.
101162
*
@@ -125,13 +186,14 @@ export async function downloadDependencyCaches(
125186

126187
// Check that we can find files to calculate the hash for the cache key from, so we don't end up
127188
// with an empty string.
128-
const patterns = await cacheConfig.getHashPatterns(codeql, features);
129-
const globber = await makeGlobber(patterns);
130-
131-
if ((await globber.glob()).length === 0) {
132-
logger.info(
133-
`Skipping download of dependency cache for ${language} as we cannot calculate a hash for the cache key.`,
134-
);
189+
const patterns = await checkHashPatterns(
190+
codeql,
191+
features,
192+
language,
193+
cacheConfig,
194+
logger,
195+
);
196+
if (patterns === undefined) {
135197
continue;
136198
}
137199

@@ -189,13 +251,14 @@ export async function uploadDependencyCaches(
189251

190252
// Check that we can find files to calculate the hash for the cache key from, so we don't end up
191253
// with an empty string.
192-
const patterns = await cacheConfig.getHashPatterns(codeql, features);
193-
const globber = await makeGlobber(patterns);
194-
195-
if ((await globber.glob()).length === 0) {
196-
logger.info(
197-
`Skipping upload of dependency cache for ${language} as we cannot calculate a hash for the cache key.`,
198-
);
254+
const patterns = await checkHashPatterns(
255+
codeql,
256+
features,
257+
language,
258+
cacheConfig,
259+
logger,
260+
);
261+
if (patterns === undefined) {
199262
continue;
200263
}
201264

0 commit comments

Comments
 (0)