danger-plugin-istanbul-coverage
Version:
Danger.js plugin for monitoring istanbul code coverage on changed files.
185 lines (184 loc) • 7.39 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const config_model_1 = require("./config.model");
const coverage_model_1 = require("./coverage.model");
const parse_json_summary_1 = require("./parser/parse-json-summary");
const _ = require("lodash");
const path = require("path");
const filename_utils_1 = require("./filename-utils");
const git_service_1 = require("./git.service");
const parse_lcov_1 = require("./parser/parse-lcov");
function filterForCoveredFiles(basePath, files, coverage) {
return files.map(filename => path.resolve(basePath, filename)).filter(filename => coverage[filename] !== undefined);
}
function getFileSet(reportChangeType, all, modified, created) {
if (reportChangeType === "all") {
return all;
}
if (reportChangeType === "modified") {
return modified;
}
if (reportChangeType === "created") {
return created;
}
return _.union(created, modified);
}
function getReportFunc(reportMode) {
if (reportMode === "warn") {
return warn;
}
if (reportMode === "fail") {
return fail;
}
return message;
}
function getFileGroupLongDescription(reportChangeType) {
if (reportChangeType === "all") {
return "the whole codebase";
}
if (reportChangeType === "created") {
return "the new files in this PR";
}
if (reportChangeType === "modified") {
return "the modified files in this PR";
}
return "the modified or changed files in this PR";
}
function getFileGroupShortDescription(reportChangeType) {
if (reportChangeType === "all") {
return "All Files";
}
if (reportChangeType === "created") {
return "New Files";
}
if (reportChangeType === "modified") {
return "Modified Files";
}
return "Created or Modified Files";
}
function sendPRComment(config, results) {
const reportFunc = getReportFunc(config.reportMode);
const messageType = getFileGroupLongDescription(config.reportFileSet);
if (!coverage_model_1.meetsThreshold(results, config.threshold)) {
const defaultMessage = `🤔 Hmmm, code coverage is looking low for ${messageType}.`;
reportFunc(config.customFailureMessage !== undefined ? config.customFailureMessage : defaultMessage);
}
else {
const defaultMessage = `🎉 Test coverage is looking good for ${messageType}`;
message(config.customSuccessMessage !== undefined ? config.customSuccessMessage : defaultMessage);
}
}
function formatItem(item) {
return `(${item.covered}/${item.total}) ${item.pct.toFixed(0)}%`;
}
function formatSourceName(source) {
return filename_utils_1.escapeMarkdownCharacters(filename_utils_1.getPrettyPathName(source, 30));
}
function formatLinkName(source, branchName) {
return filename_utils_1.escapeMarkdownCharacters(`../blob/${branchName}/${source}`);
}
function generateReport(basePath, branch, coverage, reportChangeType) {
const header = `## Coverage in ${getFileGroupShortDescription(reportChangeType)}
File | Line Coverage | Statement Coverage | Function Coverage | Branch Coverage
---- | ------------: | -----------------: | ----------------: | --------------:`;
const lines = Object.keys(coverage.displayed).map(filename => {
const e = coverage.displayed[filename];
const shortFilename = formatSourceName(path.relative(basePath, filename));
const linkFilename = formatLinkName(path.relative(basePath, filename), branch);
return [
`[${shortFilename}](${linkFilename})`,
formatItem(e.lines),
formatItem(e.statements),
formatItem(e.functions),
formatItem(e.branches),
].join(" | ");
});
const ellided = coverage.elidedCount === 0
? undefined
: [
`Other (${coverage.elidedCount} more)`,
formatItem(coverage.elided.lines),
formatItem(coverage.elided.statements),
formatItem(coverage.elided.functions),
formatItem(coverage.elided.branches),
].join(" | ");
const total = [
"Total",
formatItem(coverage.total.lines),
formatItem(coverage.total.statements),
formatItem(coverage.total.functions),
formatItem(coverage.total.branches),
].join(" | ");
return [header, ...lines, ellided, total, ""].filter(part => part !== undefined).join("\n");
}
function getCoveragePaths(coveragePaths) {
return coveragePaths.map(singleCoveragePath => {
let originalPath;
let type;
if (typeof singleCoveragePath === "string") {
originalPath = singleCoveragePath;
type = singleCoveragePath.match(/(lcov\.info)$/) ? "lcov" : "json-summary";
}
else {
originalPath = singleCoveragePath.path;
type = singleCoveragePath.type;
}
if (!process.mainModule) {
return { path: originalPath, type };
}
const appDir = `${process.mainModule.paths[0].split("node_modules")[0].slice(0, -1)}/`;
originalPath = path.resolve(appDir, originalPath);
const output = { path: originalPath, type };
return output;
});
}
function parseSourcePath(sourcePath) {
if (sourcePath.type === "json-summary") {
return parse_json_summary_1.parseJsonSummary(sourcePath.path);
}
else {
return parse_lcov_1.parseLcov(sourcePath.path);
}
}
function getCombinedCoverageCollection(coveragePaths) {
return coveragePaths
.map(coveragePath => parseSourcePath(coveragePath))
.reduce((previous, current) => (Object.assign({}, previous, current)), {});
}
/**
* Danger.js plugin for monitoring code coverage on changed files.
*/
function istanbulCoverage(config) {
const combinedConfig = config_model_1.makeCompleteConfiguration(config);
const coveragePaths = getCoveragePaths(combinedConfig.coveragePaths);
let coverage;
try {
const parsedCoverage = getCombinedCoverageCollection(coveragePaths);
if (!parsedCoverage) {
return Promise.resolve();
}
coverage = parsedCoverage;
}
catch (error) {
warn(error.message);
return Promise.resolve();
}
const gitService = new git_service_1.GitService();
const gitProperties = Promise.all([gitService.getRootDirectory(), gitService.getCurrentCommit()]);
return gitProperties.then(values => {
const gitRoot = values[0];
const gitBranch = values[1];
const modifiedFiles = filterForCoveredFiles(gitRoot, danger.git.modified_files, coverage);
const createdFiles = filterForCoveredFiles(gitRoot, danger.git.created_files, coverage);
const allFiles = Object.keys(coverage).filter(filename => filename !== "total");
const files = getFileSet(combinedConfig.reportFileSet, allFiles, modifiedFiles, createdFiles);
if (files.length === 0) {
return;
}
const coverageModel = coverage_model_1.makeCoverageModel(combinedConfig.numberOfEntries, files, coverage, combinedConfig.entrySortMethod);
sendPRComment(combinedConfig, coverageModel.total);
const report = generateReport(gitRoot, gitBranch, coverageModel, combinedConfig.reportFileSet);
markdown(report);
});
}
exports.istanbulCoverage = istanbulCoverage;