Skip to content

Commit

Permalink
feat: let action fail if coverage decreases by threshold
Browse files Browse the repository at this point in the history
  • Loading branch information
simllll committed Feb 21, 2023
1 parent f081106 commit 0c0ae7d
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 26 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ Just add this action to one of your [workflow files](https://docs.github.com/en/
The possible inputs for this action are:
| Parameter | Description | Default |
|-------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ---------------------- |
| `github-token` (**Required**) | Github token used for posting the comment. To use the key provided by the GitHub action runner, use `${{ secrets.GITHUB_TOKEN }}`. | |
| `monorepo-base-path` (**Required**) | The location of your monrepo `packages` path | |
| `s3-config` | Configuration for uploading lcov files to s3. Json Encoded. e.g. '{ credentials: { accessKeyId: "", secretAccessKey: "" }, region: "", Bucket: "repository-code-coverage" }' | |
| Parameter | Description | Default |
|-------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
| `github-token` (**Required**) | Github token used for posting the comment. To use the key provided by the GitHub action runner, use `${{ secrets.GITHUB_TOKEN }}`. | |
| `monorepo-base-path` (**Required**) | The location of your monrepo `packages` path | |
| `s3-config` | Configuration for uploading lcov files to s3. Json Encoded. e.g. '{ credentials: { accessKeyId: "", secretAccessKey: "" }, region: "", Bucket: "repository-code-coverage" }' | |
| `threshold` | Sets the threshold before the action fails if coverage of a package decreases | 0.1% |

## Examples

Expand Down
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ inputs:
s3-config:
description: 's3 config for lcov file storage, json encoded { credentials: { accessKeyId: "", secretAccessKey: "", }, region: "", Bucket: "repository-code-coverage" }'
required: false
threshold:
description: 'minimum threshold (in %) before the action fails, default is 0.1%'
required: false
runs:
using: node16
main: dist/index.js
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

19 changes: 13 additions & 6 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ export async function generateReport(
prNumber: number,
base: string,
mainBase = "master",
threshold = 0.1,
) {
const [{ lcovArrayForMonorepo }, { lcovBaseArrayForMonorepo }] =
await Promise.all([
Expand All @@ -266,19 +267,25 @@ export async function generateReport(
// head: context.payload.pull_request?.head.ref,
base,
folder: monorepoBasePath,
threshold,
};

const diff = generateDiffForMonorepo(
lcovArrayForMonorepo,
lcovBaseArrayForMonorepo,
options,
);

await upsertComment(
client,
repo,
prNumber,
generateDiffForMonorepo(
lcovArrayForMonorepo,
lcovBaseArrayForMonorepo,
options,
),
diff.text,
`<!-- monorepo-code-coverage-assistant--${monorepoBasePath} -->`,
);

return lcovArrayForMonorepo.length;
return {
count: lcovArrayForMonorepo.length,
thresholdReached: diff.thresholdReached,
};
}
1 change: 1 addition & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ try {
const options = {
base: "base...",
folder: monorepoBasePath.split("/")[1],
threshold: 0.1,
};

// eslint-disable-next-line no-console
Expand Down
20 changes: 16 additions & 4 deletions src/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ const renderEmoji = (pdiff: number) => {
export const generateDiffForMonorepo = (
lcovArrayForMonorepo: LvocList,
lcovBaseArrayForMonorepo: LvocList,
options: { base: string; folder: string },
): string => {
options: { base: string; folder: string; threshold: number },
): { text: string; thresholdReached: number } => {
const { base, folder } = options;
let thresholdReached = 0;
const rows = lcovArrayForMonorepo.map((lcovObj) => {
const baseLcov = lcovBaseArrayForMonorepo.find(
(el) => el.packageName === lcovObj.packageName,
Expand All @@ -31,6 +32,10 @@ export const generateDiffForMonorepo = (
const pbefore = baseLcov ? percentage(baseLcov.lcov) : 0;
const pafter = baseLcov ? percentage(lcovObj.lcov) : 0;
const pdiff = pafter - pbefore;

if (pdiff < -options.threshold) {
thresholdReached += 1;
}
const plus = pdiff > 0 ? "+" : "";

let arrow = "";
Expand Down Expand Up @@ -64,7 +69,14 @@ export const generateDiffForMonorepo = (

const title = `Coverage for the ${b(folder)} folder after merging into ${b(
base,
)} <p></p>`;
)} ${
thresholdReached
? `warning: ${b(`decresased for ${thresholdReached} packages`)}`
: ":"
} <p></p>`;

return fragment(title, html);
return {
text: fragment(title, html),
thresholdReached,
};
};
8 changes: 4 additions & 4 deletions src/html.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const tag =
(name: string) =>
(name: string, inline = false) =>
(...children: any[]) => {
const props =
typeof children[0] === "object"
Expand All @@ -11,16 +11,16 @@ const tag =
const c =
typeof children[0] === "string" ? children : children.slice(1);

return `<${name}${props}>${c.join("")}</${name}>\n`;
return `<${name}${props}>${c.join("")}</${name}>${!inline ? "\n" : ""}`;
};

export const tr = tag("tr");
export const td = tag("td");
export const th = tag("th");
export const b = tag("b");
export const b = tag("b", true);
export const table = tag("table");
export const tbody = tag("tbody");
export const a = tag("a");
export const a = tag("a", true);
export const span = tag("span");

export const fragment = (...children: string[]) => children.join("");
15 changes: 13 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
const token = getInput("github-token");
const monorepoBasePath = getInput("monorepo-base-path");
const s3Config = getInput("s3-config");
const threshold = getInput("threshold");
const base = context.payload.pull_request?.base.ref;

try {
Expand Down Expand Up @@ -59,18 +60,22 @@ try {

const client = getOctokit(token);

const cntReport = await generateReport(
const resultReport = await generateReport(
client,
s3Client,
s3ConfigParsed?.Bucket,
monorepoBasePath,
context.repo,
context.payload.pull_request.number,
base,
undefined,
(threshold && parseInt(threshold, 10)) || undefined,
);

// eslint-disable-next-line no-console
console.info(`generated report for ${cntReport} lcov files`);
console.info(
`generated report for ${resultReport.count} lcov files, ${resultReport.thresholdReached}x thresholds reached`,
);

if (s3Client && s3ConfigParsed) {
const cntUpload = await uploadTemporaryLvocFiles(
Expand All @@ -85,6 +90,12 @@ try {
// eslint-disable-next-line no-console
console.info(`uploaded ${cntUpload} temporary lcov files`);
}

if (resultReport.thresholdReached) {
setFailed(
`coverage decreased over threshold for ${resultReport.thresholdReached} packages`,
);
}
}
} catch (err) {
console.error(err);
Expand Down
8 changes: 4 additions & 4 deletions test/html.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ test("html tags should return the correct html", () => {
expect(tr("foo", "bar")).toBe("<tr>foobar</tr>\n");
expect(td("foo", "bar")).toBe("<td>foobar</td>\n");
expect(th("foo", "bar")).toBe("<th>foobar</th>\n");
expect(b("foo", "bar")).toBe("<b>foobar</b>\n");
expect(b("foo", "bar")).toBe("<b>foobar</b>");
expect(table("foo", "bar")).toBe("<table>foobar</table>\n");
expect(tbody("foo", "bar")).toBe("<tbody>foobar</tbody>\n");
expect(a("foo", "bar")).toBe("<a>foobar</a>\n");
expect(a("foo", "bar")).toBe("<a>foobar</a>");
expect(span("foo", "bar")).toBe("<span>foobar</span>\n");
});

Expand All @@ -19,9 +19,9 @@ test("html fragment should return the children", () => {

test("html tags should accept props", () => {
expect(a({ href: "http://www.example.com" }, "example")).toBe(
"<a href='http://www.example.com'>example</a>\n",
"<a href='http://www.example.com'>example</a>",
);
expect(
a({ href: "http://www.example.com", target: "_blank" }, "example"),
).toBe("<a href='http://www.example.com' target='_blank'>example</a>\n");
).toBe("<a href='http://www.example.com' target='_blank'>example</a>");
});

0 comments on commit 0c0ae7d

Please sign in to comment.