mirror of
https://github.com/github/codeql-action.git
synced 2025-12-31 11:40:24 +08:00
Merge branch 'main' into henrymercer/cleanup-for-mrva
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
import * as github from "@actions/github";
|
||||
import test from "ava";
|
||||
|
||||
import { getPullRequestBranches, isAnalyzingPullRequest } from "./actions-util";
|
||||
import {
|
||||
fixCodeQualityCategory,
|
||||
getPullRequestBranches,
|
||||
isAnalyzingPullRequest,
|
||||
} from "./actions-util";
|
||||
import { computeAutomationID } from "./api-client";
|
||||
import { EnvVar } from "./environment";
|
||||
import { getRunnerLogger } from "./logging";
|
||||
import { setupTests } from "./testing-utils";
|
||||
import { initializeEnvironment } from "./util";
|
||||
|
||||
@@ -193,3 +198,51 @@ test("initializeEnvironment", (t) => {
|
||||
initializeEnvironment("1.2.3");
|
||||
t.deepEqual(process.env[EnvVar.VERSION], "1.2.3");
|
||||
});
|
||||
|
||||
test("fixCodeQualityCategory", (t) => {
|
||||
withMockedEnv(
|
||||
{
|
||||
GITHUB_EVENT_NAME: "dynamic",
|
||||
},
|
||||
() => {
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
// Categories that should get adjusted.
|
||||
t.is(fixCodeQualityCategory(logger, "/language:c#"), "/language:csharp");
|
||||
t.is(fixCodeQualityCategory(logger, "/language:cpp"), "/language:c-cpp");
|
||||
t.is(fixCodeQualityCategory(logger, "/language:c"), "/language:c-cpp");
|
||||
t.is(
|
||||
fixCodeQualityCategory(logger, "/language:java"),
|
||||
"/language:java-kotlin",
|
||||
);
|
||||
t.is(
|
||||
fixCodeQualityCategory(logger, "/language:javascript"),
|
||||
"/language:javascript-typescript",
|
||||
);
|
||||
t.is(
|
||||
fixCodeQualityCategory(logger, "/language:typescript"),
|
||||
"/language:javascript-typescript",
|
||||
);
|
||||
t.is(
|
||||
fixCodeQualityCategory(logger, "/language:kotlin"),
|
||||
"/language:java-kotlin",
|
||||
);
|
||||
|
||||
// Categories that should not get adjusted.
|
||||
t.is(
|
||||
fixCodeQualityCategory(logger, "/language:csharp"),
|
||||
"/language:csharp",
|
||||
);
|
||||
t.is(fixCodeQualityCategory(logger, "/language:go"), "/language:go");
|
||||
t.is(
|
||||
fixCodeQualityCategory(logger, "/language:actions"),
|
||||
"/language:actions",
|
||||
);
|
||||
|
||||
// Other cases.
|
||||
t.is(fixCodeQualityCategory(logger, undefined), undefined);
|
||||
t.is(fixCodeQualityCategory(logger, "random string"), "random string");
|
||||
t.is(fixCodeQualityCategory(logger, "kotlin"), "kotlin");
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import * as io from "@actions/io";
|
||||
import { JSONSchemaForNPMPackageJsonFiles } from "@schemastore/package";
|
||||
|
||||
import type { Config } from "./config-utils";
|
||||
import { Logger } from "./logging";
|
||||
import {
|
||||
doesDirectoryExist,
|
||||
getCodeQLDatabasePath,
|
||||
@@ -409,3 +410,47 @@ export function getPullRequestBranches(): PullRequestBranches | undefined {
|
||||
export function isAnalyzingPullRequest(): boolean {
|
||||
return getPullRequestBranches() !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A workaround for code quality to map category names from old default setup workflows
|
||||
* to ones that the code quality service expects.
|
||||
*/
|
||||
const qualityCategoryMapping: Record<string, string> = {
|
||||
"c#": "csharp",
|
||||
cpp: "c-cpp",
|
||||
c: "c-cpp",
|
||||
"c++": "c-cpp",
|
||||
java: "java-kotlin",
|
||||
javascript: "javascript-typescript",
|
||||
typescript: "javascript-typescript",
|
||||
kotlin: "java-kotlin",
|
||||
};
|
||||
|
||||
/** Adjusts the category string for a Code Quality SARIF file if an "old"
|
||||
* category identifier is used by Default Setup.
|
||||
*/
|
||||
export function fixCodeQualityCategory(
|
||||
logger: Logger,
|
||||
category?: string,
|
||||
): string | undefined {
|
||||
// The `category` should always be set by Default Setup. We perform this check
|
||||
// to avoid potential issues if Code Quality supports Advanced Setup in the future
|
||||
// and before this workaround is removed.
|
||||
if (
|
||||
category !== undefined &&
|
||||
isDefaultSetup() &&
|
||||
category.startsWith("/language:")
|
||||
) {
|
||||
const language = category.substring("/language:".length);
|
||||
const mappedLanguage = qualityCategoryMapping[language];
|
||||
if (mappedLanguage) {
|
||||
const newCategory = `/language:${mappedLanguage}`;
|
||||
logger.info(
|
||||
`Adjusted category for Code Quality from '${category}' to '${newCategory}'.`,
|
||||
);
|
||||
return newCategory;
|
||||
}
|
||||
}
|
||||
|
||||
return category;
|
||||
}
|
||||
|
||||
@@ -336,7 +336,10 @@ async function run() {
|
||||
const qualityUploadResult = await uploadLib.uploadFiles(
|
||||
outputDir,
|
||||
actionsUtil.getRequiredInput("checkout_path"),
|
||||
actionsUtil.getOptionalInput("category"),
|
||||
actionsUtil.fixCodeQualityCategory(
|
||||
logger,
|
||||
actionsUtil.getOptionalInput("category"),
|
||||
),
|
||||
features,
|
||||
logger,
|
||||
uploadLib.CodeQualityTarget,
|
||||
|
||||
@@ -7,6 +7,7 @@ import del from "del";
|
||||
import * as yaml from "js-yaml";
|
||||
|
||||
import {
|
||||
fixCodeQualityCategory,
|
||||
getRequiredInput,
|
||||
getTemporaryDirectory,
|
||||
PullRequestBranches,
|
||||
@@ -698,24 +699,29 @@ export async function runQueries(
|
||||
undefined,
|
||||
sarifFile,
|
||||
config.debugMode,
|
||||
automationDetailsId,
|
||||
);
|
||||
|
||||
let qualityAnalysisSummary: string | undefined;
|
||||
if (config.augmentationProperties.qualityQueriesInput !== undefined) {
|
||||
logger.info(`Interpreting quality results for ${language}`);
|
||||
const qualityCategory = fixCodeQualityCategory(
|
||||
logger,
|
||||
automationDetailsId,
|
||||
);
|
||||
const qualitySarifFile = path.join(
|
||||
sarifFolder,
|
||||
`${language}.quality.sarif`,
|
||||
);
|
||||
const qualityAnalysisSummary = await runInterpretResults(
|
||||
qualityAnalysisSummary = await runInterpretResults(
|
||||
language,
|
||||
config.augmentationProperties.qualityQueriesInput.map((i) =>
|
||||
resolveQuerySuiteAlias(language, i.uses),
|
||||
),
|
||||
qualitySarifFile,
|
||||
config.debugMode,
|
||||
qualityCategory,
|
||||
);
|
||||
|
||||
// TODO: move
|
||||
logger.info(qualityAnalysisSummary);
|
||||
}
|
||||
const endTimeInterpretResults = new Date();
|
||||
statusReport[`interpret_results_${language}_duration_ms`] =
|
||||
@@ -723,6 +729,10 @@ export async function runQueries(
|
||||
logger.endGroup();
|
||||
logger.info(analysisSummary);
|
||||
|
||||
if (qualityAnalysisSummary) {
|
||||
logger.info(qualityAnalysisSummary);
|
||||
}
|
||||
|
||||
if (await features.getValue(Feature.QaTelemetryEnabled)) {
|
||||
const perQueryAlertCounts = getPerQueryAlertCounts(sarifFile);
|
||||
|
||||
@@ -759,6 +769,7 @@ export async function runQueries(
|
||||
queries: string[] | undefined,
|
||||
sarifFile: string,
|
||||
enableDebugLogging: boolean,
|
||||
category: string | undefined,
|
||||
): Promise<string> {
|
||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||
return await codeql.databaseInterpretResults(
|
||||
@@ -769,7 +780,7 @@ export async function runQueries(
|
||||
threadsFlag,
|
||||
enableDebugLogging ? "-vv" : "-v",
|
||||
sarifRunPropertyFlag,
|
||||
automationDetailsId,
|
||||
category,
|
||||
config,
|
||||
features,
|
||||
);
|
||||
|
||||
@@ -1159,6 +1159,7 @@ const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
|
||||
codeQL,
|
||||
args.languagesInput,
|
||||
mockRepositoryNwo,
|
||||
".",
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
@@ -1171,6 +1172,7 @@ const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
|
||||
codeQL,
|
||||
args.languagesInput,
|
||||
mockRepositoryNwo,
|
||||
".",
|
||||
mockLogger,
|
||||
),
|
||||
{ message: args.expectedError },
|
||||
|
||||
@@ -321,23 +321,58 @@ export async function getSupportedLanguageMap(
|
||||
return supportedLanguages;
|
||||
}
|
||||
|
||||
const baseWorkflowsPath = ".github/workflows";
|
||||
|
||||
/**
|
||||
* Determines if there exists a `.github/workflows` directory with at least
|
||||
* one file in it, which we use as an indicator that there are Actions
|
||||
* workflows in the workspace. This doesn't perfectly detect whether there
|
||||
* are actually workflows, but should be a good approximation.
|
||||
*
|
||||
* Alternatively, we could check specifically for yaml files, or call the
|
||||
* API to check if it knows about workflows.
|
||||
*
|
||||
* @returns True if the non-empty directory exists, false if not.
|
||||
*/
|
||||
export function hasActionsWorkflows(sourceRoot: string): boolean {
|
||||
const workflowsPath = path.resolve(sourceRoot, baseWorkflowsPath);
|
||||
const stats = fs.lstatSync(workflowsPath);
|
||||
return (
|
||||
stats !== undefined &&
|
||||
stats.isDirectory() &&
|
||||
fs.readdirSync(workflowsPath).length > 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of languages in the current repository.
|
||||
*/
|
||||
export async function getRawLanguagesInRepo(
|
||||
repository: RepositoryNwo,
|
||||
sourceRoot: string,
|
||||
logger: Logger,
|
||||
): Promise<string[]> {
|
||||
logger.debug(`GitHub repo ${repository.owner} ${repository.repo}`);
|
||||
logger.debug(
|
||||
`Automatically detecting languages (${repository.owner}/${repository.repo})`,
|
||||
);
|
||||
const response = await api.getApiClient().rest.repos.listLanguages({
|
||||
owner: repository.owner,
|
||||
repo: repository.repo,
|
||||
});
|
||||
|
||||
logger.debug(`Languages API response: ${JSON.stringify(response)}`);
|
||||
return Object.keys(response.data as Record<string, number>).map((language) =>
|
||||
language.trim().toLowerCase(),
|
||||
const result = Object.keys(response.data as Record<string, number>).map(
|
||||
(language) => language.trim().toLowerCase(),
|
||||
);
|
||||
|
||||
if (hasActionsWorkflows(sourceRoot)) {
|
||||
logger.debug(`Found a .github/workflows directory`);
|
||||
result.push("actions");
|
||||
}
|
||||
|
||||
logger.debug(`Raw languages in repository: ${result.join(", ")}`);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,12 +389,14 @@ export async function getLanguages(
|
||||
codeql: CodeQL,
|
||||
languagesInput: string | undefined,
|
||||
repository: RepositoryNwo,
|
||||
sourceRoot: string,
|
||||
logger: Logger,
|
||||
): Promise<Language[]> {
|
||||
// Obtain languages without filtering them.
|
||||
const { rawLanguages, autodetected } = await getRawLanguages(
|
||||
languagesInput,
|
||||
repository,
|
||||
sourceRoot,
|
||||
logger,
|
||||
);
|
||||
|
||||
@@ -420,6 +457,7 @@ export function getRawLanguagesNoAutodetect(
|
||||
export async function getRawLanguages(
|
||||
languagesInput: string | undefined,
|
||||
repository: RepositoryNwo,
|
||||
sourceRoot: string,
|
||||
logger: Logger,
|
||||
): Promise<{
|
||||
rawLanguages: string[];
|
||||
@@ -432,7 +470,7 @@ export async function getRawLanguages(
|
||||
}
|
||||
// Otherwise, autodetect languages in the repository.
|
||||
return {
|
||||
rawLanguages: await getRawLanguagesInRepo(repository, logger),
|
||||
rawLanguages: await getRawLanguagesInRepo(repository, sourceRoot, logger),
|
||||
autodetected: true,
|
||||
};
|
||||
}
|
||||
@@ -481,6 +519,7 @@ export async function getDefaultConfig({
|
||||
repository,
|
||||
tempDir,
|
||||
codeql,
|
||||
sourceRoot,
|
||||
githubVersion,
|
||||
features,
|
||||
logger,
|
||||
@@ -489,6 +528,7 @@ export async function getDefaultConfig({
|
||||
codeql,
|
||||
languagesInput,
|
||||
repository,
|
||||
sourceRoot,
|
||||
logger,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"bundleVersion": "codeql-bundle-v2.22.2",
|
||||
"cliVersion": "2.22.2",
|
||||
"priorBundleVersion": "codeql-bundle-v2.22.1",
|
||||
"priorCliVersion": "2.22.1"
|
||||
"bundleVersion": "codeql-bundle-v2.22.3",
|
||||
"cliVersion": "2.22.3",
|
||||
"priorBundleVersion": "codeql-bundle-v2.22.2",
|
||||
"priorCliVersion": "2.22.2"
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ async function run() {
|
||||
await upload_lib.uploadSpecifiedFiles(
|
||||
qualitySarifFiles,
|
||||
checkoutPath,
|
||||
category,
|
||||
actionsUtil.fixCodeQualityCategory(logger, category),
|
||||
features,
|
||||
logger,
|
||||
upload_lib.CodeQualityTarget,
|
||||
|
||||
Reference in New Issue
Block a user