Skip to content

Commit

Permalink
Merge pull request #31 from andybelltree/filter-changed-files
Browse files Browse the repository at this point in the history
Filter changed files
  • Loading branch information
romeovs committed Dec 2, 2021
2 parents a1c0d02 + 6d980f3 commit dda1c9b
Show file tree
Hide file tree
Showing 11 changed files with 704 additions and 77 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ The location of the lcov file to read the coverage report from. Defaults to
The location of the lcov file resulting from running the tests in the base
branch. When this is set a diff of the coverage percentages is shown.

##### `filter-changed-files` (**Default: false**)
If set to true, only changed files will be included in the report. Total percentage will still include all files.

##### `delete-old-comments` (**Default: false**)
If set to true, old comments will be deleted before a new comment is posted

##### `title` (**Optional**)
If included, will be added as a title for the comment produced.

## Example usage

```yml
Expand All @@ -39,3 +48,5 @@ with:
## Acknowledgements
The initial code is based on [ziishaned/jest-reporter-action](https://github.com/ziishaned/jest-reporter-action).
Changed file retrieval based on [jitterbit/get-changed-files](https://github.com/jitterbit/get-changed-files).
11 changes: 11 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ inputs:
lcov-base:
description: The location of the lcov file for the base branch
required: false
filter-changed-files:
description: Set to true to only comment with coverage on files changed in this commit
required: false
default: false
delete-old-comments:
description: Set to true to delete old Coverage Report comments
required: false
default: false
title:
description: Title to add to the comment
required: false
runs:
using: node12
main: dist/main.js
210 changes: 174 additions & 36 deletions dist/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -22784,11 +22784,16 @@ const b = tag("b");
const table = tag("table");
const tbody = tag("tbody");
const a = tag("a");
const h2 = tag("h2");

const fragment = function(...children) {
return children.join("")
};

function normalisePath(file) {
return file.replace(/\\/g, "/")
}

// Tabulate the lcov data in a HTML table.
function tabulate(lcov, options) {
const head = tr(
Expand All @@ -22801,7 +22806,7 @@ function tabulate(lcov, options) {
);

const folders = {};
for (const file of lcov) {
for (const file of filterAndNormaliseLcov(lcov, options)) {
const parts = file.file.replace(options.prefix, "").split("/");
const folder = parts.slice(0, -1).join("/");
folders[folder] = folders[folder] || [];
Expand All @@ -22822,6 +22827,22 @@ function tabulate(lcov, options) {
return table(tbody(head, ...rows))
}

function filterAndNormaliseLcov(lcov, options) {
return lcov
.map(file => ({
...file,
file: normalisePath(file.file),
}))
.filter(file => shouldBeIncluded(file.file, options))
}

function shouldBeIncluded(fileName, options) {
if (!options.shouldFilterChangedFiles) {
return true
}
return options.changedFiles.includes(fileName.replace(options.prefix, ""))
}

function toFolder(path) {
if (path === "") {
return ""
Expand All @@ -22833,16 +22854,19 @@ function toFolder(path) {
function getStatement(file) {
const { branches, functions, lines } = file;

return [branches, functions, lines].reduce(function(acc, curr) {
if (!curr) {
return acc
}
return [branches, functions, lines].reduce(
function(acc, curr) {
if (!curr) {
return acc
}

return {
hit: acc.hit + curr.hit,
found: acc.found + curr.found,
}
}, { hit: 0, found: 0 })
return {
hit: acc.hit + curr.hit,
found: acc.found + curr.found,
}
},
{ hit: 0, found: 0 },
)
}

function toRow(file, indent, options) {
Expand Down Expand Up @@ -22889,13 +22913,18 @@ function uncovered(file, options) {

const all = ranges([...branches, ...lines]);


return all
.map(function(range) {
const fragment = range.start === range.end ? `L${range.start}` : `L${range.start}-L${range.end}`;
const fragment =
range.start === range.end
? `L${range.start}`
: `L${range.start}-L${range.end}`;
const relative = file.file.replace(options.prefix, "");
const href = `https://github.com/${options.repository}/blob/${options.commit}/${relative}#${fragment}`;
const text = range.start === range.end ? range.start : `${range.start}–${range.end}`;
const text =
range.start === range.end
? range.start
: `${range.start}–${range.end}`;

return a({ href }, text)
})
Expand Down Expand Up @@ -22929,14 +22958,24 @@ function ranges(linenos) {
return res
}

function comment (lcov, options) {
function comment(lcov, options) {
return fragment(
options.title ? h2(options.title) : "",
options.base
? `Coverage after merging ${b(options.head)} into ${b(options.base)}`
? `Coverage after merging ${b(options.head)} into ${b(
options.base,
)} will be`
: `Coverage for this commit`,
table(tbody(tr(th(percentage(lcov).toFixed(2), "%")))),
"\n\n",
details(summary("Coverage Report"), tabulate(lcov, options)),
details(
summary(
options.shouldFilterChangedFiles
? "Coverage Report for Changed Files"
: "Coverage Report",
),
tabulate(lcov, options),
),
)
}

Expand All @@ -22949,73 +22988,172 @@ function diff(lcov, before, options) {
const pafter = percentage(lcov);
const pdiff = pafter - pbefore;
const plus = pdiff > 0 ? "+" : "";
const arrow =
pdiff === 0
? ""
: pdiff < 0
? "▾"
: "▴";
const arrow = pdiff === 0 ? "" : pdiff < 0 ? "▾" : "▴";

return fragment(
options.title ? h2(options.title) : "",
options.base
? `Coverage after merging ${b(options.head)} into ${b(options.base)}`
? `Coverage after merging ${b(options.head)} into ${b(
options.base,
)} will be`
: `Coverage for this commit`,
table(tbody(tr(
th(pafter.toFixed(2), "%"),
th(arrow, " ", plus, pdiff.toFixed(2), "%"),
))),
table(
tbody(
tr(
th(pafter.toFixed(2), "%"),
th(arrow, " ", plus, pdiff.toFixed(2), "%"),
),
),
),
"\n\n",
details(summary("Coverage Report"), tabulate(lcov, options)),
details(
summary(
options.shouldFilterChangedFiles
? "Coverage Report for Changed Files"
: "Coverage Report",
),
tabulate(lcov, options),
),
)
}

// Get list of changed files
async function getChangedFiles(githubClient, options, context) {
if (!options.commit || !options.baseCommit) {
core_7(
`The base and head commits are missing from the payload for this ${context.eventName} event.`,
);
}

// Use GitHub's compare two commits API.
// https://developer.github.com/v3/repos/commits/#compare-two-commits
const response = await githubClient.repos.compareCommits({
base: options.baseCommit,
head: options.commit,
owner: context.repo.owner,
repo: context.repo.repo,
});

if (response.status !== 200) {
core_7(
`The GitHub API for comparing the base and head commits for this ${context.eventName} event returned ${response.status}, expected 200.`,
);
}

return response.data.files
.filter(file => file.status == "modified" || file.status == "added")
.map(file => file.filename)
}

const REQUESTED_COMMENTS_PER_PAGE = 20;

async function deleteOldComments(github, options, context) {
const existingComments = await getExistingComments(github, options, context);
for (const comment of existingComments) {
core_8(`Deleting comment: ${comment.id}`);
try {
await github.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: comment.id,
});
} catch (error) {
console.error(error);
}
}
}

async function getExistingComments(github, options, context) {
let page = 0;
let results = [];
let response;
do {
response = await github.issues.listComments({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
per_page: REQUESTED_COMMENTS_PER_PAGE,
page: page,
});
results = results.concat(response.data);
page++;
} while (response.data.length === REQUESTED_COMMENTS_PER_PAGE)

return results.filter(
comment =>
!!comment.user &&
(!options.title || comment.body.includes(options.title)) &&
comment.body.includes("Coverage Report"),
)
}

const MAX_COMMENT_CHARS = 65536;

async function main$1() {
const token = core$1.getInput("github-token");
const githubClient = new github_2(token);
const lcovFile = core$1.getInput("lcov-file") || "./coverage/lcov.info";
const baseFile = core$1.getInput("lcov-base");
const shouldFilterChangedFiles = core$1.getInput("filter-changed-files").toLowerCase() === 'true';
const shouldDeleteOldComments = core$1.getInput("delete-old-comments").toLowerCase() === 'true';
const title = core$1.getInput("title");

const raw = await fs.promises.readFile(lcovFile, "utf-8").catch(err => null);
if (!raw) {
console.log(`No coverage report found at '${lcovFile}', exiting...`);
return
}

const baseRaw = baseFile && await fs.promises.readFile(baseFile, "utf-8").catch(err => null);
const baseRaw =
baseFile && (await fs.promises.readFile(baseFile, "utf-8").catch(err => null));
if (baseFile && !baseRaw) {
console.log(`No coverage report found at '${baseFile}', ignoring...`);
}

const options = {
repository: github_1.payload.repository.full_name,
prefix: `${process.env.GITHUB_WORKSPACE}/`,
prefix: normalisePath(`${process.env.GITHUB_WORKSPACE}/`),
};

if (github_1.eventName === "pull_request") {
options.commit = github_1.payload.pull_request.head.sha;
options.baseCommit = github_1.payload.pull_request.base.sha;
options.head = github_1.payload.pull_request.head.ref;
options.base = github_1.payload.pull_request.base.ref;
} else if (github_1.eventName === "push") {
options.commit = github_1.payload.after;
options.baseCommit = github_1.payload.before;
options.head = github_1.ref;
}

options.shouldFilterChangedFiles = shouldFilterChangedFiles;
options.title = title;

if (shouldFilterChangedFiles) {
options.changedFiles = await getChangedFiles(githubClient, options, github_1);
}

const lcov = await parse$2(raw);
const baselcov = baseRaw && await parse$2(baseRaw);
const body = diff(lcov, baselcov, options);
const baselcov = baseRaw && (await parse$2(baseRaw));
const body = diff(lcov, baselcov, options).substring(0, MAX_COMMENT_CHARS);

if (shouldDeleteOldComments) {
await deleteOldComments(githubClient, options, github_1);
}

if (github_1.eventName === "pull_request") {
await new github_2(token).issues.createComment({
await githubClient.issues.createComment({
repo: github_1.repo.repo,
owner: github_1.repo.owner,
issue_number: github_1.payload.pull_request.number,
body: diff(lcov, baselcov, options),
body: body,
});
} else if (github_1.eventName === "push") {
await new github_2(token).repos.createCommitComment({
await githubClient.repos.createCommitComment({
repo: github_1.repo.repo,
owner: github_1.repo.owner,
commit_sha: options.commit,
body: diff(lcov, baselcov, options),
body: body,
});
}
}
Expand Down
Loading

0 comments on commit dda1c9b

Please sign in to comment.