Remove lines of code counting in the Action

We now only need to support doing this in the CLI.
This commit is contained in:
Henry Mercer
2022-11-11 18:08:17 +00:00
parent ea990a3118
commit 84e5134df9
171 changed files with 32 additions and 19927 deletions

View File

@@ -3,7 +3,6 @@ import * as path from "path";
import test, { ExecutionContext } from "ava";
import * as yaml from "js-yaml";
import * as sinon from "sinon";
import {
convertPackToQuerySuiteEntry,
@@ -13,7 +12,6 @@ import {
} from "./analyze";
import { setCodeQL } from "./codeql";
import { Config } from "./config-utils";
import * as count from "./count-loc";
import { Language } from "./languages";
import { getRunnerLogger } from "./logging";
import { setupTests, setupActionsVars, createFeatures } from "./testing-utils";
@@ -25,12 +23,6 @@ setupTests(test);
// and correct case of builtin or custom. Also checks the correct search
// paths are set in the database analyze invocation.
test("status report fields and search path setting", async (t) => {
const mockLinesOfCode = Object.values(Language).reduce((obj, lang, i) => {
// use a different line count for each language
obj[lang] = i + 1;
return obj;
}, {});
sinon.stub(count, "countLoc").resolves(mockLinesOfCode);
let searchPathsUsed: Array<string | undefined> = [];
return await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
@@ -96,6 +88,7 @@ test("status report fields and search path setting", async (t) => {
);
return "";
},
databasePrintBaseline: async () => "",
});
searchPathsUsed = [];
@@ -202,35 +195,9 @@ test("status report fields and search path setting", async (t) => {
t.true(`interpret_results_${language}_duration_ms` in customStatusReport);
}
verifyLineCounts(tmpDir);
verifyQuerySuites(tmpDir);
});
function verifyLineCounts(tmpDir: string) {
// eslint-disable-next-line github/array-foreach
Object.keys(Language).forEach((lang, i) => {
verifyLineCountForFile(path.join(tmpDir, `${lang}.sarif`), i + 1);
});
}
function verifyLineCountForFile(filePath: string, lineCount: number) {
const sarif = JSON.parse(fs.readFileSync(filePath, "utf8"));
t.deepEqual(sarif.runs[0].properties.metricResults, [
{
rule: {
index: 0,
toolComponent: {
index: 0,
},
},
value: 123,
baseline: lineCount,
},
]);
// when the rule doesn't exist, it should not be added
t.deepEqual(sarif.runs[1].properties.metricResults, []);
}
function verifyQuerySuites(tmpDir: string) {
const qlsContent = [
{

View File

@@ -10,7 +10,6 @@ import { DatabaseCreationTimings } from "./actions-util";
import * as analysisPaths from "./analysis-paths";
import { CodeQL, CODEQL_VERSION_NEW_TRACING, getCodeQL } from "./codeql";
import * as configUtils from "./config-utils";
import { countLoc } from "./count-loc";
import { FeatureEnablement } from "./feature-flags";
import { isScannedLanguage, Language } from "./languages";
import { Logger } from "./logging";
@@ -213,25 +212,6 @@ export async function runQueries(
): Promise<QueriesStatusReport> {
const statusReport: QueriesStatusReport = {};
let locPromise: Promise<Partial<Record<Language, number>>> = Promise.resolve(
{}
);
const countLocDebugMode =
process.env["INTERNAL_CODEQL_ACTION_DEBUG_LOC"] || config.debugMode;
if (countLocDebugMode) {
// count the number of lines in the background
locPromise = countLoc(
path.resolve(),
// config.paths specifies external directories. the current
// directory is included in the analysis by default. Replicate
// that here.
config.paths,
config.pathsIgnore,
config.languages,
logger
);
}
const codeql = await getCodeQL(config.codeQLCmd);
await util.logCodeScanningConfigInCli(codeql, featureEnablement, logger);
@@ -249,7 +229,7 @@ export async function runQueries(
if (!hasBuiltinQueries && !hasCustomQueries && !hasPackWithCustomQueries) {
throw new Error(
`Unable to analyse ${language} as no queries were selected for this language`
`Unable to analyze ${language} as no queries were selected for this language`
);
}
@@ -345,9 +325,6 @@ export async function runQueries(
logger.endGroup();
logger.info(analysisSummary);
}
if (countLocDebugMode) {
printLinesOfCodeSummary(logger, language, await locPromise);
}
logger.info(await runPrintLinesOfCode(language));
} catch (e) {
logger.info(String(e));
@@ -536,18 +513,6 @@ export async function runCleanup(
logger.endGroup();
}
function printLinesOfCodeSummary(
logger: Logger,
language: Language,
lineCounts: Partial<Record<Language, number>>
) {
if (language in lineCounts) {
logger.info(
`Counted a baseline of ${lineCounts[language]} lines of code for ${language}.`
);
}
}
// exported for testing
export function validateQueryFilters(queryFilters?: configUtils.QueryFilter[]) {
if (!queryFilters) {

View File

@@ -1,112 +0,0 @@
import * as path from "path";
import test from "ava";
import { countLoc } from "./count-loc";
import { Language } from "./languages";
import { getRunnerLogger } from "./logging";
import { setupTests } from "./testing-utils";
setupTests(test);
test("ensure lines of code works for cpp and js", async (t) => {
const results = await countLoc(
path.join(__dirname, "../tests/multi-language-repo"),
[],
[],
[Language.cpp, Language.javascript],
getRunnerLogger(true)
);
t.deepEqual(results, {
cpp: 6,
javascript: 9,
});
});
test("ensure lines of code works for csharp", async (t) => {
const results = await countLoc(
path.join(__dirname, "../tests/multi-language-repo"),
[],
[],
[Language.csharp],
getRunnerLogger(true)
);
t.deepEqual(results, {
csharp: 10,
});
});
test("ensure lines of code can handle undefined language", async (t) => {
const results = await countLoc(
path.join(__dirname, "../tests/multi-language-repo"),
[],
[],
[Language.javascript, Language.python, "hucairz" as Language],
getRunnerLogger(true)
);
t.deepEqual(results, {
javascript: 9,
python: 5,
});
});
test("ensure lines of code can handle empty languages", async (t) => {
const results = await countLoc(
path.join(__dirname, "../tests/multi-language-repo"),
[],
[],
[],
getRunnerLogger(true)
);
t.deepEqual(results, {});
});
test("ensure lines of code can handle includes", async (t) => {
// note that "**" is always included. The includes are for extra
// directories outside the normal structure.
const results = await countLoc(
path.join(__dirname, "../tests/multi-language-repo"),
["../../src/testdata"],
[],
[Language.javascript],
getRunnerLogger(true)
);
t.deepEqual(results, {
javascript: 12,
});
});
test("ensure lines of code can handle empty includes", async (t) => {
// note that "**" is always included. The includes are for extra
// directories outside the normal structure.
const results = await countLoc(
path.join(__dirname, "../tests/multi-language-repo"),
["idontexist"],
[],
[Language.javascript],
getRunnerLogger(true)
);
t.deepEqual(results, {
// should get no results
});
});
test("ensure lines of code can handle exclude", async (t) => {
const results = await countLoc(
path.join(__dirname, "../tests/multi-language-repo"),
[],
["**/*.py"],
[Language.javascript, Language.python],
getRunnerLogger(true)
);
t.deepEqual(results, {
javascript: 9,
});
});

View File

@@ -1,86 +0,0 @@
import { LocDir } from "github-linguist";
import { Language } from "./languages";
import { Logger } from "./logging";
// Map from linguist language names to language prefixes used in the action and codeql
const linguistToMetrics: Record<string, Language> = {
c: Language.cpp,
"c++": Language.cpp,
"c#": Language.csharp,
go: Language.go,
java: Language.java,
javascript: Language.javascript,
python: Language.python,
ruby: Language.ruby,
typescript: Language.javascript,
};
const nameToLinguist = Object.entries(linguistToMetrics).reduce(
(obj, [key, name]) => {
if (!obj[name]) {
obj[name] = [];
}
obj[name].push(key);
return obj;
},
{} as Record<Language, string[]>
);
/**
* Count the lines of code of the specified language using the include
* and exclude glob paths.
*
* @param cwd the root directory to start the count from
* @param include glob patterns to include in the search for relevant files
* @param exclude glob patterns to exclude in the search for relevant files
* @param dbLanguages list of languages to include in the results
* @param logger object to log results
*/
export async function countLoc(
cwd: string,
include: string[],
exclude: string[],
dbLanguages: Language[],
logger: Logger
): Promise<Partial<Record<Language, number>>> {
const result = await new LocDir({
cwd,
include: Array.isArray(include) && include.length > 0 ? include : ["**"],
exclude,
analysisLanguages: dbLanguages.flatMap((lang) => nameToLinguist[lang]),
}).loadInfo();
// The analysis counts LoC in all languages. We need to
// extract the languages we care about. Also, note that
// the analysis uses slightly different names for language.
const lineCounts = Object.entries(result.languages).reduce(
(obj, [language, { code }]) => {
const metricsLanguage = linguistToMetrics[language];
if (metricsLanguage && dbLanguages.includes(metricsLanguage)) {
obj[metricsLanguage] = code + (obj[metricsLanguage] || 0);
}
return obj;
},
{} as Record<Language, number>
);
if (Object.keys(lineCounts).length) {
logger.debug("Lines of code count:");
for (const [language, count] of Object.entries(lineCounts)) {
logger.debug(` ${language}: ${count}`);
}
} else {
logger.info(
"Could not determine the baseline lines of code count in this repository. " +
"Because of this, it will not be possible to compare the lines " +
"of code analyzed by code scanning with the baseline. This will not affect " +
"the results produced by code scanning. If you have any questions, you can " +
"raise an issue at https://github.com/github/codeql-action/issues. Please " +
"include a link to the repository if public, or otherwise information about " +
"the code scanning workflow you are using."
);
}
return lineCounts;
}