diff --git a/src/config-utils.test.ts b/src/config-utils.test.ts index bb63fcf6e..06994c0ed 100644 --- a/src/config-utils.test.ts +++ b/src/config-utils.test.ts @@ -139,7 +139,7 @@ function mockListLanguages(languages: string[]) { sinon.stub(api, "getApiClient").value(() => client); } -test("load empty config", async (t) => { +test.serial("load empty config", async (t) => { return await withTmpDir(async (tempDir) => { const logger = getRunnerLogger(true); const languages = "javascript,python"; @@ -180,7 +180,7 @@ test("load empty config", async (t) => { }); }); -test("load code quality config", async (t) => { +test.serial("load code quality config", async (t) => { return await withTmpDir(async (tempDir) => { const logger = getRunnerLogger(true); const languages = "actions"; @@ -230,65 +230,68 @@ test("load code quality config", async (t) => { }); }); -test("initActionState doesn't throw if there are queries configured in the repository properties", async (t) => { - return await withTmpDir(async (tempDir) => { - const logger = getRunnerLogger(true); - const languages = "javascript"; +test.serial( + "initActionState doesn't throw if there are queries configured in the repository properties", + async (t) => { + return await withTmpDir(async (tempDir) => { + const logger = getRunnerLogger(true); + const languages = "javascript"; - const codeql = createStubCodeQL({ - async betterResolveLanguages() { - return { - extractors: { - javascript: [{ extractor_root: "" }], - }, - }; - }, + const codeql = createStubCodeQL({ + async betterResolveLanguages() { + return { + extractors: { + javascript: [{ extractor_root: "" }], + }, + }; + }, + }); + + // This should be ignored and no error should be thrown. + const repositoryProperties = { + "github-codeql-extra-queries": "+foo", + }; + + // Expected configuration for a CQ-only analysis. + const computedConfig: UserConfig = { + "disable-default-queries": true, + queries: [{ uses: "code-quality" }], + "query-filters": [], + }; + + const expectedConfig = createTestConfig({ + analysisKinds: [AnalysisKind.CodeQuality], + languages: [KnownLanguage.javascript], + codeQLCmd: codeql.getPath(), + computedConfig, + dbLocation: path.resolve(tempDir, "codeql_databases"), + debugArtifactName: "", + debugDatabaseName: "", + tempDir, + repositoryProperties, + }); + + await t.notThrowsAsync(async () => { + const config = await configUtils.initConfig( + createFeatures([]), + createTestInitConfigInputs({ + analysisKinds: [AnalysisKind.CodeQuality], + languagesInput: languages, + repository: { owner: "github", repo: "example" }, + tempDir, + codeql, + repositoryProperties, + logger, + }), + ); + + t.deepEqual(config, expectedConfig); + }); }); + }, +); - // This should be ignored and no error should be thrown. - const repositoryProperties = { - "github-codeql-extra-queries": "+foo", - }; - - // Expected configuration for a CQ-only analysis. - const computedConfig: UserConfig = { - "disable-default-queries": true, - queries: [{ uses: "code-quality" }], - "query-filters": [], - }; - - const expectedConfig = createTestConfig({ - analysisKinds: [AnalysisKind.CodeQuality], - languages: [KnownLanguage.javascript], - codeQLCmd: codeql.getPath(), - computedConfig, - dbLocation: path.resolve(tempDir, "codeql_databases"), - debugArtifactName: "", - debugDatabaseName: "", - tempDir, - repositoryProperties, - }); - - await t.notThrowsAsync(async () => { - const config = await configUtils.initConfig( - createFeatures([]), - createTestInitConfigInputs({ - analysisKinds: [AnalysisKind.CodeQuality], - languagesInput: languages, - repository: { owner: "github", repo: "example" }, - tempDir, - codeql, - repositoryProperties, - logger, - }), - ); - - t.deepEqual(config, expectedConfig); - }); - }); -}); - -test("loading a saved config produces the same config", async (t) => { +test.serial("loading a saved config produces the same config", async (t) => { return await withTmpDir(async (tempDir) => { const logger = getRunnerLogger(true); @@ -335,7 +338,7 @@ test("loading a saved config produces the same config", async (t) => { }); }); -test("loading config with version mismatch throws", async (t) => { +test.serial("loading config with version mismatch throws", async (t) => { return await withTmpDir(async (tempDir) => { const logger = getRunnerLogger(true); @@ -387,7 +390,7 @@ test("loading config with version mismatch throws", async (t) => { }); }); -test("load input outside of workspace", async (t) => { +test.serial("load input outside of workspace", async (t) => { return await withTmpDir(async (tempDir) => { try { await configUtils.initConfig( @@ -412,7 +415,7 @@ test("load input outside of workspace", async (t) => { }); }); -test("load non-local input with invalid repo syntax", async (t) => { +test.serial("load non-local input with invalid repo syntax", async (t) => { return await withTmpDir(async (tempDir) => { // no filename given, just a repo const configFile = "octo-org/codeql-config@main"; @@ -440,7 +443,7 @@ test("load non-local input with invalid repo syntax", async (t) => { }); }); -test("load non-existent input", async (t) => { +test.serial("load non-existent input", async (t) => { return await withTmpDir(async (tempDir) => { const languagesInput = "javascript"; const configFile = "input"; @@ -470,7 +473,7 @@ test("load non-existent input", async (t) => { }); }); -test("load non-empty input", async (t) => { +test.serial("load non-empty input", async (t) => { return await withTmpDir(async (tempDir) => { const codeql = createStubCodeQL({ async betterResolveLanguages() { @@ -541,18 +544,20 @@ test("load non-empty input", async (t) => { }); }); -test("Using config input and file together, config input should be used.", async (t) => { - return await withTmpDir(async (tempDir) => { - process.env["RUNNER_TEMP"] = tempDir; - process.env["GITHUB_WORKSPACE"] = tempDir; +test.serial( + "Using config input and file together, config input should be used.", + async (t) => { + return await withTmpDir(async (tempDir) => { + process.env["RUNNER_TEMP"] = tempDir; + process.env["GITHUB_WORKSPACE"] = tempDir; - const inputFileContents = ` + const inputFileContents = ` name: my config queries: - uses: ./foo_file`; - const configFilePath = createConfigFile(inputFileContents, tempDir); + const configFilePath = createConfigFile(inputFileContents, tempDir); - const configInput = ` + const configInput = ` name: my config queries: - uses: ./foo @@ -563,39 +568,40 @@ test("Using config input and file together, config input should be used.", async - c/d@1.2.3 `; - fs.mkdirSync(path.join(tempDir, "foo")); + fs.mkdirSync(path.join(tempDir, "foo")); - const codeql = createStubCodeQL({ - async betterResolveLanguages() { - return { - extractors: { - javascript: [{ extractor_root: "" }], - python: [{ extractor_root: "" }], - }, - }; - }, + const codeql = createStubCodeQL({ + async betterResolveLanguages() { + return { + extractors: { + javascript: [{ extractor_root: "" }], + python: [{ extractor_root: "" }], + }, + }; + }, + }); + + // Only JS, python packs will be ignored + const languagesInput = "javascript"; + + const config = await configUtils.initConfig( + createFeatures([]), + createTestInitConfigInputs({ + languagesInput, + configFile: configFilePath, + configInput, + tempDir, + codeql, + workspacePath: tempDir, + }), + ); + + t.deepEqual(config.originalUserInput, yaml.load(configInput)); }); + }, +); - // Only JS, python packs will be ignored - const languagesInput = "javascript"; - - const config = await configUtils.initConfig( - createFeatures([]), - createTestInitConfigInputs({ - languagesInput, - configFile: configFilePath, - configInput, - tempDir, - codeql, - workspacePath: tempDir, - }), - ); - - t.deepEqual(config.originalUserInput, yaml.load(configInput)); - }); -}); - -test("API client used when reading remote config", async (t) => { +test.serial("API client used when reading remote config", async (t) => { return await withTmpDir(async (tempDir) => { const codeql = createStubCodeQL({ async betterResolveLanguages() { @@ -644,34 +650,37 @@ test("API client used when reading remote config", async (t) => { }); }); -test("Remote config handles the case where a directory is provided", async (t) => { - return await withTmpDir(async (tempDir) => { - const dummyResponse = []; // directories are returned as arrays - mockGetContents(dummyResponse); +test.serial( + "Remote config handles the case where a directory is provided", + async (t) => { + return await withTmpDir(async (tempDir) => { + const dummyResponse = []; // directories are returned as arrays + mockGetContents(dummyResponse); - const repoReference = "octo-org/codeql-config/config.yaml@main"; - try { - await configUtils.initConfig( - createFeatures([]), - createTestInitConfigInputs({ - configFile: repoReference, - tempDir, - workspacePath: tempDir, - }), - ); - throw new Error("initConfig did not throw error"); - } catch (err) { - t.deepEqual( - err, - new ConfigurationError( - errorMessages.getConfigFileDirectoryGivenMessage(repoReference), - ), - ); - } - }); -}); + const repoReference = "octo-org/codeql-config/config.yaml@main"; + try { + await configUtils.initConfig( + createFeatures([]), + createTestInitConfigInputs({ + configFile: repoReference, + tempDir, + workspacePath: tempDir, + }), + ); + throw new Error("initConfig did not throw error"); + } catch (err) { + t.deepEqual( + err, + new ConfigurationError( + errorMessages.getConfigFileDirectoryGivenMessage(repoReference), + ), + ); + } + }); + }, +); -test("Invalid format of remote config handled correctly", async (t) => { +test.serial("Invalid format of remote config handled correctly", async (t) => { return await withTmpDir(async (tempDir) => { const dummyResponse = { // note no "content" property here @@ -700,7 +709,7 @@ test("Invalid format of remote config handled correctly", async (t) => { }); }); -test("No detected languages", async (t) => { +test.serial("No detected languages", async (t) => { return await withTmpDir(async (tempDir) => { mockListLanguages([]); const codeql = createStubCodeQL({ @@ -728,7 +737,7 @@ test("No detected languages", async (t) => { }); }); -test("Unknown languages", async (t) => { +test.serial("Unknown languages", async (t) => { return await withTmpDir(async (tempDir) => { const languagesInput = "rubbish,english"; @@ -755,7 +764,7 @@ test("Unknown languages", async (t) => { const mockLogger = getRunnerLogger(true); -test("no generateRegistries when registries is undefined", async (t) => { +test.serial("no generateRegistries when registries is undefined", async (t) => { return await withTmpDir(async (tmpDir) => { const registriesInput = undefined; const logger = getRunnerLogger(true); @@ -767,24 +776,27 @@ test("no generateRegistries when registries is undefined", async (t) => { }); }); -test("generateRegistries prefers original CODEQL_REGISTRIES_AUTH", async (t) => { - return await withTmpDir(async (tmpDir) => { - process.env.CODEQL_REGISTRIES_AUTH = "original"; - const registriesInput = yaml.dump([ - { - url: "http://ghcr.io", - packages: ["codeql/*", "codeql-testing/*"], - token: "not-a-token", - }, - ]); - const logger = getRunnerLogger(true); - const { registriesAuthTokens, qlconfigFile } = - await configUtils.generateRegistries(registriesInput, tmpDir, logger); +test.serial( + "generateRegistries prefers original CODEQL_REGISTRIES_AUTH", + async (t) => { + return await withTmpDir(async (tmpDir) => { + process.env.CODEQL_REGISTRIES_AUTH = "original"; + const registriesInput = yaml.dump([ + { + url: "http://ghcr.io", + packages: ["codeql/*", "codeql-testing/*"], + token: "not-a-token", + }, + ]); + const logger = getRunnerLogger(true); + const { registriesAuthTokens, qlconfigFile } = + await configUtils.generateRegistries(registriesInput, tmpDir, logger); - t.is(registriesAuthTokens, "original"); - t.is(qlconfigFile, path.join(tmpDir, "qlconfig.yml")); - }); -}); + t.is(registriesAuthTokens, "original"); + t.is(qlconfigFile, path.join(tmpDir, "qlconfig.yml")); + }); + }, +); // getLanguages @@ -862,7 +874,7 @@ const mockRepositoryNwo = parseRepositoryNwo("owner/repo"); expectedLanguages: ["javascript"], }, ].forEach((args) => { - test(`getLanguages: ${args.name}`, async (t) => { + test.serial(`getLanguages: ${args.name}`, async (t) => { const mockRequest = mockLanguagesInRepo(args.languagesInRepository); const stubExtractorEntry = { extractor_root: "", @@ -1999,13 +2011,16 @@ for (const language in KnownLanguage) { ); } -test("hasActionsWorkflows doesn't throw if workflows folder doesn't exist", async (t) => { - return withTmpDir(async (tmpDir) => { - t.notThrows(() => configUtils.hasActionsWorkflows(tmpDir)); - }); -}); +test.serial( + "hasActionsWorkflows doesn't throw if workflows folder doesn't exist", + async (t) => { + return withTmpDir(async (tmpDir) => { + t.notThrows(() => configUtils.hasActionsWorkflows(tmpDir)); + }); + }, +); -test("getPrimaryAnalysisConfig - single analysis kind", (t) => { +test.serial("getPrimaryAnalysisConfig - single analysis kind", (t) => { // If only one analysis kind is configured, we expect to get the matching configuration. for (const analysisKind of supportedAnalysisKinds) { const singleKind = createTestConfig({ analysisKinds: [analysisKind] }); @@ -2013,7 +2028,7 @@ test("getPrimaryAnalysisConfig - single analysis kind", (t) => { } }); -test("getPrimaryAnalysisConfig - Code Scanning + Code Quality", (t) => { +test.serial("getPrimaryAnalysisConfig - Code Scanning + Code Quality", (t) => { // For CS+CQ, we expect to get the Code Scanning configuration. const codeScanningAndCodeQuality = createTestConfig({ analysisKinds: [AnalysisKind.CodeScanning, AnalysisKind.CodeQuality],