Merge pull request #3003 from github/mbg/rewrite-quality-category

Rewrite legacy SARIF categories for CQ
This commit is contained in:
Michael B. Gale
2025-08-07 11:30:12 +01:00
committed by GitHub
15 changed files with 195 additions and 21 deletions

View File

@@ -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");
},
);
});

View File

@@ -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;
}

View File

@@ -357,7 +357,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,

View File

@@ -7,6 +7,7 @@ import del from "del";
import * as yaml from "js-yaml";
import {
fixCodeQualityCategory,
getRequiredInput,
getTemporaryDirectory,
PullRequestBranches,
@@ -695,24 +696,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`] =
@@ -720,6 +726,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);
@@ -756,6 +766,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(
@@ -766,7 +777,7 @@ export async function runQueries(
threadsFlag,
enableDebugLogging ? "-vv" : "-v",
sarifRunPropertyFlag,
automationDetailsId,
category,
config,
features,
);

View File

@@ -112,7 +112,7 @@ async function run() {
await upload_lib.uploadSpecifiedFiles(
qualitySarifFiles,
checkoutPath,
category,
actionsUtil.fixCodeQualityCategory(logger, category),
features,
logger,
upload_lib.CodeQualityTarget,