Merge pull request #459 from github/aeisenberg/add-linguist-data

Add baseline metrics for lines of code
This commit is contained in:
Andrew Eisenberg 2021-04-26 14:23:31 -07:00 committed by GitHub
commit 03f029c2a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 379 additions and 41 deletions

View file

@ -1 +1 @@
{"version":3,"file":"analyze-action.js","sourceRoot":"","sources":["../src/analyze-action.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"analyze-action.js","sourceRoot":"","sources":["../src/analyze-action.ts"],"names":[],"mappings":"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"}

40
lib/analyze.js generated
View file

@ -12,6 +12,7 @@ const path = __importStar(require("path"));
const toolrunner = __importStar(require("@actions/exec/lib/toolrunner"));
const analysisPaths = __importStar(require("./analysis-paths"));
const codeql_1 = require("./codeql");
const count_loc_1 = require("./count-loc");
const languages_1 = require("./languages");
const sharedEnv = __importStar(require("./shared-environment"));
const upload_lib_1 = require("./upload-lib");
@ -77,6 +78,12 @@ async function finalizeDatabaseCreation(config, threadsFlag, logger) {
// Runs queries and creates sarif files in the given folder
async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag, config, logger) {
const statusReport = {};
// count the number of lines in the background
const locPromise = count_loc_1.countLoc(path.resolve(),
// config.paths specifies external directories. the current
// directory is included in the analysis by default. Replicate
// that here.
["**"].concat(config.paths || []), config.pathsIgnore, config.languages, logger);
for (const language of config.languages) {
logger.startGroup(`Analyzing ${language}`);
const queries = config.queries[language];
@ -86,7 +93,8 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
try {
if (queries["builtin"].length > 0) {
const startTimeBuliltIn = new Date().getTime();
await runQueryGroup(language, "builtin", queries["builtin"], sarifFolder, undefined);
const sarifFile = await runQueryGroup(language, "builtin", queries["builtin"], sarifFolder, undefined);
await injectLinesOfCode(sarifFile, language, locPromise);
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
new Date().getTime() - startTimeBuliltIn;
}
@ -95,12 +103,14 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
const temporarySarifFiles = [];
for (let i = 0; i < queries["custom"].length; ++i) {
if (queries["custom"][i].queries.length > 0) {
await runQueryGroup(language, `custom-${i}`, queries["custom"][i].queries, temporarySarifDir, queries["custom"][i].searchPath);
temporarySarifFiles.push(path.join(temporarySarifDir, `${language}-custom-${i}.sarif`));
const sarifFile = await runQueryGroup(language, `custom-${i}`, queries["custom"][i].queries, temporarySarifDir, queries["custom"][i].searchPath);
temporarySarifFiles.push(sarifFile);
}
}
if (temporarySarifFiles.length > 0) {
fs.writeFileSync(path.join(sarifFolder, `${language}-custom.sarif`), upload_lib_1.combineSarifFiles(temporarySarifFiles));
const sarifFile = path.join(sarifFolder, `${language}-custom.sarif`);
fs.writeFileSync(sarifFile, upload_lib_1.combineSarifFiles(temporarySarifFiles));
await injectLinesOfCode(sarifFile, language, locPromise);
statusReport[`analyze_custom_queries_${language}_duration_ms`] =
new Date().getTime() - startTimeCustom;
}
@ -127,6 +137,7 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
await codeql.databaseAnalyze(databasePath, sarifFile, searchPath, querySuitePath, memoryFlag, addSnippetsFlag, threadsFlag);
logger.debug(`SARIF results for database ${language} created at "${sarifFile}"`);
logger.endGroup();
return sarifFile;
}
}
exports.runQueries = runQueries;
@ -141,4 +152,25 @@ async function runAnalyze(outputDir, memoryFlag, addSnippetsFlag, threadsFlag, c
return { ...queriesStats };
}
exports.runAnalyze = runAnalyze;
async function injectLinesOfCode(sarifFile, language, locPromise) {
const lineCounts = await locPromise;
if (language in lineCounts) {
const sarif = JSON.parse(fs.readFileSync(sarifFile, "utf8"));
if (Array.isArray(sarif.runs)) {
for (const run of sarif.runs) {
const metricId = `${language}/summary/lines-of-code`;
run.properties = run.properties || {};
run.properties.metricResults = run.properties.metricResults || [];
const metric = run.properties.metricResults.find(
// the metric id can be in either of two places
(m) => { var _a; return m.metricId === metricId || ((_a = m.metric) === null || _a === void 0 ? void 0 : _a.id) === metricId; });
// only add the baseline value if the metric already exists
if (metric) {
metric.baseline = lineCounts[language];
}
}
}
fs.writeFileSync(sarifFile, JSON.stringify(sarif));
}
}
//# sourceMappingURL=analyze.js.map

File diff suppressed because one or more lines are too long

80
lib/analyze.test.js generated
View file

@ -11,9 +11,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const ava_1 = __importDefault(require("ava"));
const sinon_1 = __importDefault(require("sinon"));
const analyze_1 = require("./analyze");
const codeql_1 = require("./codeql");
const count = __importStar(require("./count-loc"));
const languages_1 = require("./languages");
const logging_1 = require("./logging");
const testing_utils_1 = require("./testing-utils");
@ -23,21 +26,53 @@ testing_utils_1.setupTests(ava_1.default);
// and correct case of builtin or custom. Also checks the correct search
// paths are set in the database analyze invocation.
ava_1.default("status report fields and search path setting", async (t) => {
const mockLinesOfCode = Object.entries(languages_1.Language).reduce((obj, [lang], i) => {
// use a different line count for each languaged
obj[lang] = i + 1;
return obj;
}, {});
sinon_1.default.stub(count, "countLoc").resolves(mockLinesOfCode);
let searchPathsUsed = [];
return await util.withTmpDir(async (tmpDir) => {
testing_utils_1.setupActionsVars(tmpDir, tmpDir);
codeql_1.setCodeQL({
databaseAnalyze: async (_, sarifFile, searchPath) => {
fs.writeFileSync(sarifFile, JSON.stringify({
runs: [],
}));
searchPathsUsed.push(searchPath);
},
});
const memoryFlag = "";
const addSnippetsFlag = "";
const threadsFlag = "";
for (const language of Object.values(languages_1.Language)) {
codeql_1.setCodeQL({
databaseAnalyze: async (_, sarifFile, searchPath) => {
fs.writeFileSync(sarifFile, JSON.stringify({
runs: [
// variant 1 uses metricId
{
properties: {
metricResults: [
{
metricId: `${language}/summary/lines-of-code`,
value: 123,
},
],
},
},
// variant 2 uses metric.id
{
properties: {
metricResults: [
{
metric: {
id: `${language}/summary/lines-of-code`,
},
value: 123,
},
],
},
},
{},
],
}));
searchPathsUsed.push(searchPath);
},
});
searchPathsUsed = [];
const config = {
languages: [language],
@ -80,6 +115,35 @@ ava_1.default("status report fields and search path setting", async (t) => {
t.true(`analyze_custom_queries_${language}_duration_ms` in customStatusReport);
t.deepEqual(searchPathsUsed, [undefined, "/1", "/2"]);
}
verifyLineCounts(tmpDir);
});
function verifyLineCounts(tmpDir) {
// eslint-disable-next-line github/array-foreach
Object.keys(languages_1.Language).forEach((lang, i) => {
verifyLineCountForFile(lang, path.join(tmpDir, `${lang}-builtin.sarif`), i + 1);
verifyLineCountForFile(lang, path.join(tmpDir, `${lang}-custom.sarif`), i + 1);
});
}
function verifyLineCountForFile(lang, filePath, lineCount) {
const sarif = JSON.parse(fs.readFileSync(filePath, "utf8"));
t.deepEqual(sarif.runs[0].properties.metricResults, [
{
metricId: `${lang}/summary/lines-of-code`,
value: 123,
baseline: lineCount,
},
]);
t.deepEqual(sarif.runs[1].properties.metricResults, [
{
metric: {
id: `${lang}/summary/lines-of-code`,
},
value: 123,
baseline: lineCount,
},
]);
// when the metric doesn't exists, it should not be added
t.deepEqual(sarif.runs[2].properties.metricResults, []);
}
});
//# sourceMappingURL=analyze.test.js.map

View file

@ -1 +1 @@
{"version":3,"file":"analyze.test.js","sourceRoot":"","sources":["../src/analyze.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,uCAAyB;AAEzB,8CAAuB;AAEvB,uCAAuC;AACvC,qCAAqC;AAErC,2CAAuC;AACvC,uCAA4C;AAC5C,mDAA+D;AAC/D,6CAA+B;AAE/B,0BAAU,CAAC,aAAI,CAAC,CAAC;AAEjB,yEAAyE;AACzE,wEAAwE;AACxE,oDAAoD;AACpD,aAAI,CAAC,8CAA8C,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC/D,IAAI,eAAe,GAAa,EAAE,CAAC;IACnC,OAAO,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAC5C,gCAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEjC,kBAAS,CAAC;YACR,eAAe,EAAE,KAAK,EACpB,CAAC,EACD,SAAiB,EACjB,UAA8B,EAC9B,EAAE;gBACF,EAAE,CAAC,aAAa,CACd,SAAS,EACT,IAAI,CAAC,SAAS,CAAC;oBACb,IAAI,EAAE,EAAE;iBACT,CAAC,CACH,CAAC;gBACF,eAAe,CAAC,IAAI,CAAC,UAAW,CAAC,CAAC;YACpC,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,EAAE,CAAC;QACtB,MAAM,eAAe,GAAG,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,oBAAQ,CAAC,EAAE;YAC9C,eAAe,GAAG,EAAE,CAAC;YACrB,MAAM,MAAM,GAAW;gBACrB,SAAS,EAAE,CAAC,QAAQ,CAAC;gBACrB,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,EAAE;gBACf,KAAK,EAAE,EAAE;gBACT,iBAAiB,EAAE,EAAE;gBACrB,OAAO,EAAE,MAAM;gBACf,YAAY,EAAE,MAAM;gBACpB,SAAS,EAAE,EAAE;gBACb,aAAa,EAAE;oBACb,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM;iBACV;aACxB,CAAC;YACF,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE;gBACjE,SAAS,EAAE,IAAI;aAChB,CAAC,CAAC;YAEH,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG;gBACzB,OAAO,EAAE,CAAC,QAAQ,CAAC;gBACnB,MAAM,EAAE,EAAE;aACX,CAAC;YACF,MAAM,mBAAmB,GAAG,MAAM,oBAAU,CAC1C,MAAM,EACN,UAAU,EACV,eAAe,EACf,WAAW,EACX,MAAM,EACN,yBAAe,CAAC,IAAI,CAAC,CACtB,CAAC;YACF,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACxD,CAAC,CAAC,IAAI,CACJ,2BAA2B,QAAQ,cAAc,IAAI,mBAAmB,CACzE,CAAC;YAEF,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG;gBACzB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE;oBACN;wBACE,OAAO,EAAE,CAAC,QAAQ,CAAC;wBACnB,UAAU,EAAE,IAAI;qBACjB;oBACD;wBACE,OAAO,EAAE,CAAC,QAAQ,CAAC;wBACnB,UAAU,EAAE,IAAI;qBACjB;iBACF;aACF,CAAC;YACF,MAAM,kBAAkB,GAAG,MAAM,oBAAU,CACzC,MAAM,EACN,UAAU,EACV,eAAe,EACf,WAAW,EACX,MAAM,EACN,yBAAe,CAAC,IAAI,CAAC,CACtB,CAAC;YACF,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACvD,CAAC,CAAC,IAAI,CACJ,0BAA0B,QAAQ,cAAc,IAAI,kBAAkB,CACvE,CAAC;YACF,CAAC,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;SACvD;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
{"version":3,"file":"analyze.test.js","sourceRoot":"","sources":["../src/analyze.test.ts"],"names":[],"mappings":"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"}

54
lib/count-loc.js generated Normal file
View file

@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const github_linguist_1 = require("github-linguist");
// Map from linguist language names to language prefixes used in our metrics
const supportedLanguages = {
c: "cpp",
"c++": "cpp",
"c#": "cs",
go: "go",
java: "java",
javascript: "js",
python: "py",
ruby: "rb",
typescript: "js",
};
/**
* 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
*/
async function countLoc(cwd, include, exclude, dbLanguages, logger) {
const result = await new github_linguist_1.LocDir({
cwd,
include,
exclude,
}).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 dbLanguage = supportedLanguages[language];
if (dbLanguage && dbLanguages.includes(dbLanguage)) {
obj[dbLanguage] = code + (obj[dbLanguage] || 0);
}
return obj;
}, {});
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.warning("Did not find any lines of code in database.");
}
return lineCounts;
}
exports.countLoc = countLoc;
//# sourceMappingURL=count-loc.js.map

1
lib/count-loc.js.map Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"count-loc.js","sourceRoot":"","sources":["../src/count-loc.ts"],"names":[],"mappings":";;AAAA,qDAAyC;AAIzC,4EAA4E;AAC5E,MAAM,kBAAkB,GAAG;IACzB,CAAC,EAAE,KAAK;IACR,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,IAAI;IACV,EAAE,EAAE,IAAI;IACR,IAAI,EAAE,MAAM;IACZ,UAAU,EAAE,IAAI;IAChB,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;IACV,UAAU,EAAE,IAAI;CACjB,CAAC;AAEF;;;;;;;;;GASG;AACI,KAAK,UAAU,QAAQ,CAC5B,GAAW,EACX,OAAiB,EACjB,OAAiB,EACjB,WAAqB,EACrB,MAAc;IAEd,MAAM,MAAM,GAAG,MAAM,IAAI,wBAAM,CAAC;QAC9B,GAAG;QACH,OAAO;QACP,OAAO;KACR,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEd,uDAAuD;IACvD,uDAAuD;IACvD,2DAA2D;IAC3D,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CACxD,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE;QAC5B,MAAM,UAAU,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAChD,IAAI,UAAU,IAAI,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;YAClD,GAAG,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;SACjD;QACD,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAA4B,CAC7B,CAAC;IAEF,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE;QAClC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACrC,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;YAC1D,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,KAAK,KAAK,EAAE,CAAC,CAAC;SACzC;KACF;SAAM;QACL,MAAM,CAAC,OAAO,CAAC,6CAA6C,CAAC,CAAC;KAC/D;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AArCD,4BAqCC"}

View file

@ -69,6 +69,7 @@ async function run() {
"Config file could not be found at expected location. Has the 'init' action been called?"
);
}
const apiDetails = {
auth: actionsUtil.getRequiredInput("token"),
url: actionsUtil.getRequiredEnvParam("GITHUB_SERVER_URL"),

View file

@ -1,10 +1,13 @@
import * as fs from "fs";
import * as path from "path";
import test from "ava";
import sinon from "sinon";
import { runQueries } 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 } from "./testing-utils";
@ -16,31 +19,63 @@ 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.entries(Language).reduce((obj, [lang], i) => {
// use a different line count for each languaged
obj[lang] = i + 1;
return obj;
}, {});
sinon.stub(count, "countLoc").resolves(mockLinesOfCode);
let searchPathsUsed: string[] = [];
return await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
setCodeQL({
databaseAnalyze: async (
_,
sarifFile: string,
searchPath: string | undefined
) => {
fs.writeFileSync(
sarifFile,
JSON.stringify({
runs: [],
})
);
searchPathsUsed.push(searchPath!);
},
});
const memoryFlag = "";
const addSnippetsFlag = "";
const threadsFlag = "";
for (const language of Object.values(Language)) {
setCodeQL({
databaseAnalyze: async (
_,
sarifFile: string,
searchPath: string | undefined
) => {
fs.writeFileSync(
sarifFile,
JSON.stringify({
runs: [
// variant 1 uses metricId
{
properties: {
metricResults: [
{
metricId: `${language}/summary/lines-of-code`,
value: 123,
},
],
},
},
// variant 2 uses metric.id
{
properties: {
metricResults: [
{
metric: {
id: `${language}/summary/lines-of-code`,
},
value: 123,
},
],
},
},
{},
],
})
);
searchPathsUsed.push(searchPath!);
},
});
searchPathsUsed = [];
const config: Config = {
languages: [language],
@ -103,5 +138,49 @@ test("status report fields and search path setting", async (t) => {
);
t.deepEqual(searchPathsUsed, [undefined, "/1", "/2"]);
}
verifyLineCounts(tmpDir);
});
function verifyLineCounts(tmpDir: string) {
// eslint-disable-next-line github/array-foreach
Object.keys(Language).forEach((lang, i) => {
verifyLineCountForFile(
lang,
path.join(tmpDir, `${lang}-builtin.sarif`),
i + 1
);
verifyLineCountForFile(
lang,
path.join(tmpDir, `${lang}-custom.sarif`),
i + 1
);
});
}
function verifyLineCountForFile(
lang: string,
filePath: string,
lineCount: number
) {
const sarif = JSON.parse(fs.readFileSync(filePath, "utf8"));
t.deepEqual(sarif.runs[0].properties.metricResults, [
{
metricId: `${lang}/summary/lines-of-code`,
value: 123,
baseline: lineCount,
},
]);
t.deepEqual(sarif.runs[1].properties.metricResults, [
{
metric: {
id: `${lang}/summary/lines-of-code`,
},
value: 123,
baseline: lineCount,
},
]);
// when the metric doesn't exists, it should not be added
t.deepEqual(sarif.runs[2].properties.metricResults, []);
}
});

View file

@ -6,6 +6,7 @@ import * as toolrunner from "@actions/exec/lib/toolrunner";
import * as analysisPaths from "./analysis-paths";
import { getCodeQL } from "./codeql";
import * as configUtils from "./config-utils";
import { countLoc } from "./count-loc";
import { isScannedLanguage, Language } from "./languages";
import { Logger } from "./logging";
import * as sharedEnv from "./shared-environment";
@ -144,6 +145,18 @@ export async function runQueries(
): Promise<QueriesStatusReport> {
const statusReport: QueriesStatusReport = {};
// count the number of lines in the background
const locPromise = countLoc(
path.resolve(),
// config.paths specifies external directories. the current
// directory is included in the analysis by default. Replicate
// that here.
["**"].concat(config.paths || []),
config.pathsIgnore,
config.languages,
logger
);
for (const language of config.languages) {
logger.startGroup(`Analyzing ${language}`);
@ -157,13 +170,15 @@ export async function runQueries(
try {
if (queries["builtin"].length > 0) {
const startTimeBuliltIn = new Date().getTime();
await runQueryGroup(
const sarifFile = await runQueryGroup(
language,
"builtin",
queries["builtin"],
sarifFolder,
undefined
);
await injectLinesOfCode(sarifFile, language, locPromise);
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
new Date().getTime() - startTimeBuliltIn;
}
@ -172,23 +187,21 @@ export async function runQueries(
const temporarySarifFiles: string[] = [];
for (let i = 0; i < queries["custom"].length; ++i) {
if (queries["custom"][i].queries.length > 0) {
await runQueryGroup(
const sarifFile = await runQueryGroup(
language,
`custom-${i}`,
queries["custom"][i].queries,
temporarySarifDir,
queries["custom"][i].searchPath
);
temporarySarifFiles.push(
path.join(temporarySarifDir, `${language}-custom-${i}.sarif`)
);
temporarySarifFiles.push(sarifFile);
}
}
if (temporarySarifFiles.length > 0) {
fs.writeFileSync(
path.join(sarifFolder, `${language}-custom.sarif`),
combineSarifFiles(temporarySarifFiles)
);
const sarifFile = path.join(sarifFolder, `${language}-custom.sarif`);
fs.writeFileSync(sarifFile, combineSarifFiles(temporarySarifFiles));
await injectLinesOfCode(sarifFile, language, locPromise);
statusReport[`analyze_custom_queries_${language}_duration_ms`] =
new Date().getTime() - startTimeCustom;
}
@ -210,7 +223,7 @@ export async function runQueries(
queries: string[],
destinationFolder: string,
searchPath: string | undefined
): Promise<void> {
): Promise<string> {
const databasePath = util.getCodeQLDatabasePath(config.tempDir, language);
// Pass the queries to codeql using a file instead of using the command
// line to avoid command line length restrictions, particularly on windows.
@ -238,6 +251,8 @@ export async function runQueries(
`SARIF results for database ${language} created at "${sarifFile}"`
);
logger.endGroup();
return sarifFile;
}
}
@ -269,3 +284,30 @@ export async function runAnalyze(
return { ...queriesStats };
}
async function injectLinesOfCode(
sarifFile: string,
language: string,
locPromise: Promise<Record<string, number>>
) {
const lineCounts = await locPromise;
if (language in lineCounts) {
const sarif = JSON.parse(fs.readFileSync(sarifFile, "utf8"));
if (Array.isArray(sarif.runs)) {
for (const run of sarif.runs) {
const metricId = `${language}/summary/lines-of-code`;
run.properties = run.properties || {};
run.properties.metricResults = run.properties.metricResults || [];
const metric = run.properties.metricResults.find(
// the metric id can be in either of two places
(m) => m.metricId === metricId || m.metric?.id === metricId
);
// only add the baseline value if the metric already exists
if (metric) {
metric.baseline = lineCounts[language];
}
}
}
fs.writeFileSync(sarifFile, JSON.stringify(sarif));
}
}

65
src/count-loc.ts Normal file
View file

@ -0,0 +1,65 @@
import { LocDir } from "github-linguist";
import { Logger } from "./logging";
// Map from linguist language names to language prefixes used in our metrics
const supportedLanguages = {
c: "cpp",
"c++": "cpp",
"c#": "cs",
go: "go",
java: "java",
javascript: "js",
python: "py",
ruby: "rb",
typescript: "js",
};
/**
* 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: string[],
logger: Logger
): Promise<Record<string, number>> {
const result = await new LocDir({
cwd,
include,
exclude,
}).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 dbLanguage = supportedLanguages[language];
if (dbLanguage && dbLanguages.includes(dbLanguage)) {
obj[dbLanguage] = code + (obj[dbLanguage] || 0);
}
return obj;
},
{} as Record<string, 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.warning("Did not find any lines of code in database.");
}
return lineCounts;
}