Skip to content

Commit 2680455

Browse files
committed
Use undefined instead of NoMatchingFilesError
Add tests for `makePatternCheck` and `checkHashPatterns`
1 parent 03b2dc2 commit 2680455

File tree

4 files changed

+135
-71
lines changed

4 files changed

+135
-71
lines changed

lib/analyze-action.js

Lines changed: 8 additions & 18 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: 8 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/dependency-caching.test.ts

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,104 @@
1+
import * as fs from "fs";
2+
import path from "path";
3+
14
import test from "ava";
5+
26
// import * as sinon from "sinon";
37

48
import { cacheKeyHashLength } from "./caching-utils";
59
import { createStubCodeQL } from "./codeql";
6-
import { getFeaturePrefix } from "./dependency-caching";
10+
import {
11+
CacheConfig,
12+
checkHashPatterns,
13+
getFeaturePrefix,
14+
makePatternCheck,
15+
} from "./dependency-caching";
716
import { Feature } from "./feature-flags";
817
import { KnownLanguage } from "./languages";
9-
import { setupTests, createFeatures } from "./testing-utils";
18+
import {
19+
setupTests,
20+
createFeatures,
21+
getRecordingLogger,
22+
checkExpectedLogMessages,
23+
LoggedMessage,
24+
} from "./testing-utils";
25+
import { withTmpDir } from "./util";
1026

1127
setupTests(test);
1228

29+
function makeAbsolutePatterns(tmpDir: string, patterns: string[]): string[] {
30+
return patterns.map((pattern) => path.join(tmpDir, pattern));
31+
}
32+
33+
test("makePatternCheck - returns undefined if no patterns match", async (t) => {
34+
await withTmpDir(async (tmpDir) => {
35+
fs.writeFileSync(path.join(tmpDir, "test.java"), "");
36+
const result = await makePatternCheck(
37+
makeAbsolutePatterns(tmpDir, ["**/*.cs"]),
38+
);
39+
t.is(result, undefined);
40+
});
41+
});
42+
43+
test("makePatternCheck - returns all patterns if any pattern matches", async (t) => {
44+
await withTmpDir(async (tmpDir) => {
45+
fs.writeFileSync(path.join(tmpDir, "test.java"), "");
46+
const patterns = makeAbsolutePatterns(tmpDir, ["**/*.cs", "**/*.java"]);
47+
const result = await makePatternCheck(patterns);
48+
t.deepEqual(result, patterns);
49+
});
50+
});
51+
52+
test("checkHashPatterns - logs when no patterns match", async (t) => {
53+
const codeql = createStubCodeQL({});
54+
const features = createFeatures([]);
55+
const messages: LoggedMessage[] = [];
56+
const config: CacheConfig = {
57+
getDependencyPaths: () => [],
58+
getHashPatterns: async () => undefined,
59+
};
60+
61+
const result = await checkHashPatterns(
62+
codeql,
63+
features,
64+
KnownLanguage.csharp,
65+
config,
66+
getRecordingLogger(messages),
67+
);
68+
69+
t.is(result, undefined);
70+
checkExpectedLogMessages(t, messages, [
71+
"Skipping download of dependency cache",
72+
]);
73+
});
74+
75+
test("checkHashPatterns - returns patterns when patterns match", async (t) => {
76+
await withTmpDir(async (tmpDir) => {
77+
const codeql = createStubCodeQL({});
78+
const features = createFeatures([]);
79+
const messages: LoggedMessage[] = [];
80+
const patterns = makeAbsolutePatterns(tmpDir, ["**/*.cs", "**/*.java"]);
81+
82+
fs.writeFileSync(path.join(tmpDir, "test.java"), "");
83+
84+
const config: CacheConfig = {
85+
getDependencyPaths: () => [],
86+
getHashPatterns: async () => makePatternCheck(patterns),
87+
};
88+
89+
const result = await checkHashPatterns(
90+
codeql,
91+
features,
92+
KnownLanguage.csharp,
93+
config,
94+
getRecordingLogger(messages),
95+
);
96+
97+
t.deepEqual(result, patterns);
98+
t.deepEqual(messages, []);
99+
});
100+
});
101+
13102
test("getFeaturePrefix - returns empty string if no features are enabled", async (t) => {
14103
const codeql = createStubCodeQL({});
15104
const features = createFeatures([]);

src/dependency-caching.ts

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,24 @@ import { KnownLanguage, Language } from "./languages";
1515
import { Logger } from "./logging";
1616
import { getErrorMessage, getRequiredEnvParam } from "./util";
1717

18-
class NoMatchingFilesError extends Error {
19-
constructor(msg?: string) {
20-
super(msg);
21-
22-
this.name = "NoMatchingFilesError";
23-
}
24-
}
25-
2618
/**
2719
* Caching configuration for a particular language.
2820
*/
29-
interface CacheConfig {
21+
export interface CacheConfig {
3022
/** Gets the paths of directories on the runner that should be included in the cache. */
3123
getDependencyPaths: () => string[];
3224
/**
3325
* Gets an array of glob patterns for the paths of files whose contents affect which dependencies are used
34-
* by a project. This function also checks whether there are any matching files and throws
35-
* a `NoMatchingFilesError` error if no files match.
26+
* by a project. This function also checks whether there are any matching files and returns
27+
* `undefined` if no files match.
3628
*
3729
* The glob patterns are intended to be used for cache keys, where we find all files which match these
3830
* patterns, calculate a hash for their contents, and use that hash as part of the cache key.
3931
*/
40-
getHashPatterns: (codeql: CodeQL, features: Features) => Promise<string[]>;
32+
getHashPatterns: (
33+
codeql: CodeQL,
34+
features: FeatureEnablement,
35+
) => Promise<string[] | undefined>;
4136
}
4237

4338
const CODEQL_DEPENDENCY_CACHE_PREFIX = "codeql-dependencies";
@@ -73,16 +68,18 @@ export function getJavaDependencyDirs(): string[] {
7368

7469
/**
7570
* Checks that there are files which match `patterns`. If there are matching files for any of the patterns,
76-
* this function returns all `patterns`. Otherwise, a `NoMatchingFilesError` is thrown.
71+
* this function returns all `patterns`. Otherwise, `undefined` is returned.
7772
*
7873
* @param patterns The glob patterns to find matching files for.
79-
* @returns The array of glob patterns if there are matching files.
74+
* @returns The array of glob patterns if there are matching files, or `undefined` otherwise.
8075
*/
81-
async function makePatternCheck(patterns: string[]): Promise<string[]> {
76+
export async function makePatternCheck(
77+
patterns: string[],
78+
): Promise<string[] | undefined> {
8279
const globber = await makeGlobber(patterns);
8380

8481
if ((await globber.glob()).length === 0) {
85-
throw new NoMatchingFilesError();
82+
return undefined;
8683
}
8784

8885
return patterns;
@@ -98,8 +95,8 @@ async function makePatternCheck(patterns: string[]): Promise<string[]> {
9895
*/
9996
async function getCsharpHashPatterns(
10097
codeql: CodeQL,
101-
features: Features,
102-
): Promise<string[]> {
98+
features: FeatureEnablement,
99+
): Promise<string[] | undefined> {
103100
// These files contain accurate information about dependencies, including the exact versions
104101
// that the relevant package manager has determined for the project. Using these gives us
105102
// stable hashes unless the dependencies change.
@@ -133,7 +130,7 @@ async function getCsharpHashPatterns(
133130
// If we get to this point, the `basePatterns` didn't find any files,
134131
// and `Feature.CsharpNewCacheKey` is either not enabled or we didn't
135132
// find any files using those patterns either.
136-
throw new NoMatchingFilesError();
133+
return undefined;
137134
}
138135

139136
/**
@@ -192,8 +189,8 @@ export interface DependencyCacheRestoreStatus {
192189
export type DependencyCacheRestoreStatusReport = DependencyCacheRestoreStatus[];
193190

194191
/**
195-
* A wrapper around `cacheConfig.getHashPatterns` which catches `NoMatchingFilesError` errors,
196-
* and logs that there are no files to calculate a hash for the cache key from.
192+
* A wrapper around `cacheConfig.getHashPatterns` which logs when there are no files to calculate
193+
* a hash for the cache key from.
197194
*
198195
* @param codeql The CodeQL instance to use.
199196
* @param features Information about which FFs are enabled.
@@ -202,24 +199,22 @@ export type DependencyCacheRestoreStatusReport = DependencyCacheRestoreStatus[];
202199
* @param logger The logger to write the log message to if there is an error.
203200
* @returns An array of glob patterns to use for hashing files, or `undefined` if there are no matching files.
204201
*/
205-
async function checkHashPatterns(
202+
export async function checkHashPatterns(
206203
codeql: CodeQL,
207-
features: Features,
204+
features: FeatureEnablement,
208205
language: Language,
209206
cacheConfig: CacheConfig,
210207
logger: Logger,
211208
): Promise<string[] | undefined> {
212-
try {
213-
return cacheConfig.getHashPatterns(codeql, features);
214-
} catch (err) {
215-
if (err instanceof NoMatchingFilesError) {
216-
logger.info(
217-
`Skipping download of dependency cache for ${language} as we cannot calculate a hash for the cache key.`,
218-
);
219-
return undefined;
220-
}
221-
throw err;
209+
const patterns = await cacheConfig.getHashPatterns(codeql, features);
210+
211+
if (patterns === undefined) {
212+
logger.info(
213+
`Skipping download of dependency cache for ${language} as we cannot calculate a hash for the cache key.`,
214+
);
222215
}
216+
217+
return patterns;
223218
}
224219

225220
/**

0 commit comments

Comments
 (0)