Skip to content

Commit 191c3a8

Browse files
authored
Refactored code of report generation (#6)
* Created PR threshold, refactored report's code * Rebuilt index.js * Fixed test * Added check for coverage threshold
1 parent 0ceddee commit 191c3a8

30 files changed

+230
-82
lines changed

.eslintrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
"@typescript-eslint/no-non-null-assertion": "off",
2222
"@typescript-eslint/ban-types": "off",
2323
"no-console": "off",
24+
"prettier/prettier": [
25+
"error",
26+
{
27+
"endOfLine": "auto"
28+
}
29+
],
2430
"simple-import-sort/imports": [
2531
"warn",
2632
{

.prettierrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"tabWidth": 4,
33
"printWidth": 80,
4-
"singleQuote": true
4+
"singleQuote": true,
5+
"endOfLine": "auto"
56
}

action.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,19 @@ branding:
77
inputs:
88
github_token:
99
required: true
10-
description: 'a github access token'
10+
description: 'A github access token'
1111
test_script:
1212
required: false
13-
description: 'a custom npm script to test'
13+
description: 'A custom npm script to test'
1414
default: npx jest --silent --coverage --coverageReporters="text" --coverageReporters="text-summary"
15+
threshold:
16+
required: false
17+
description: 'Coverage threshold. If total line coverage is less than threshold, PR will be rejected'
1518
runs:
1619
using: 'docker'
1720
image: 'Dockerfile'
1821
args:
1922
- ${{ inputs.github_token }}
2023
- ${{ inputs.test_script }}
2124
- ${{ inputs.directory }}
25+
- ${{ inputs.threshold }}

dist/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"description": "",
66
"main": "index.js",
77
"scripts": {
8+
"test": "jest",
89
"test:coverage": "jest --silent --coverage --coverageReporters=\"text\" --coverageReporters=\"text-summary\"",
910
"test:watch": "jest --watch",
1011
"start": "webpack --watch --mode development",

src/collect-coverage/parseCoverage.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { getRawCoverage } from './getRawCoverage';
22
import { parseCoverage } from './parseCoverage';
3-
import { ParsedCoverageDetails } from './parseCoverageDetails';
4-
import { ParsedCoverageSummary } from './parseCoverageSummary';
3+
import { ReportData } from '../report/generateReport';
54

65
export const collectCoverage = async (
76
testCommand: string,
87
branch?: string
9-
): Promise<[ParsedCoverageSummary, ParsedCoverageDetails]> => {
8+
): Promise<ReportData> => {
109
const source = await getRawCoverage(testCommand, branch);
1110

12-
return parseCoverage(source);
11+
if (typeof source === 'string') {
12+
return parseCoverage(source);
13+
} else {
14+
return source;
15+
}
1316
};

src/collect-coverage/getRawCoverage.ts renamed to src/collect/getRawCoverage.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
import { setFailed } from '@actions/core';
21
import { exec } from '@actions/exec';
32

4-
export const getRawCoverage = async (testCommand: string, branch?: string) => {
3+
import { FailReason } from '../report/generateReport';
4+
5+
export const getRawCoverage = async (
6+
testCommand: string,
7+
branch?: string
8+
): Promise<
9+
string | { success: false; failReason: FailReason.TESTS_FAILED }
10+
> => {
511
if (branch) {
612
try {
713
await exec(`git fetch ${branch} --depth=1`);
@@ -23,7 +29,8 @@ export const getRawCoverage = async (testCommand: string, branch?: string) => {
2329
},
2430
});
2531
} catch (error) {
26-
setFailed(`Test execution failed with message: "${error.message}"`);
32+
console.error(`Test execution failed with message: "${error.message}"`);
33+
return { success: false, failReason: FailReason.TESTS_FAILED };
2734
}
2835

2936
return output;

src/collect/parseCoverage.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { parseCoverageDetails } from './parseCoverageDetails';
2+
import { parseCoverageSummary } from './parseCoverageSummary';
3+
import { FailReason, ReportData } from '../report/generateReport';
4+
5+
export const parseCoverage = (source: string): ReportData => {
6+
if (!source.includes('-') || !source.includes('=')) {
7+
return {
8+
success: false,
9+
failReason: FailReason.INVALID_COVERAGE_FORMAT,
10+
};
11+
}
12+
13+
return {
14+
success: true,
15+
summary: parseCoverageSummary(source),
16+
details: parseCoverageDetails(source),
17+
};
18+
};

src/constants/MESSAGE_HEADING.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { heading } from '../format/strings.json';
2+
3+
export const MESSAGE_HEADING = `## ${heading}`;

src/comment-body/details/formatCoverageDetails.ts renamed to src/format/details/formatCoverageDetails.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { formatCoverageDetailsPart } from './formatCoverageDetailsPart';
2-
import { ParsedCoverageDetails } from '../../collect-coverage/parseCoverageDetails';
2+
import { ParsedCoverageDetails } from '../../collect/parseCoverageDetails';
33
import { getDecreasedCoverage } from '../getters/getDecreasedCoverage';
44
import { getNewFilesCoverage } from '../getters/getNewFilesCoverage';
55
import { details } from '../strings.json';

src/comment-body/details/formatCoverageDetailsPart.ts renamed to src/format/details/formatCoverageDetailsPart.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import markdownTable from 'markdown-table';
22

33
import { getFileCoverageDetailRow } from './getFileCoverageDetailRow';
4-
import { ParsedCoverageDetails } from '../../collect-coverage/parseCoverageDetails';
4+
import { ParsedCoverageDetails } from '../../collect/parseCoverageDetails';
55
import { details } from '../strings.json';
66
import { createMarkdownSpoiler } from '../utils/createMarkdownSpoiler';
77
import { formatHeadingAndTable } from '../utils/formatHeadingAndTable';

src/comment-body/details/getFileCoverageDetailRow.ts renamed to src/format/details/getFileCoverageDetailRow.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FileCoverageDetail } from '../../collect-coverage/parseCoverageDetails';
1+
import { FileCoverageDetail } from '../../collect/parseCoverageDetails';
22
import { formatPercentage } from '../utils/formatPercentage';
33

44
export const getFileCoverageDetailRow = (

src/comment-body/getCommentBody.ts renamed to src/format/getFormattedCoverage.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
import { formatCoverageDetails } from './details/formatCoverageDetails';
22
import { formatCoverageSummary } from './summary/formatCoverageSummary';
3-
import { ParsedCoverageDetails } from '../collect-coverage/parseCoverageDetails';
4-
import { ParsedCoverageSummary } from '../collect-coverage/parseCoverageSummary';
5-
import { MESSAGE_HEADING } from '../fetchPreviousComment';
3+
import { ParsedCoverageDetails } from '../collect/parseCoverageDetails';
4+
import { ParsedCoverageSummary } from '../collect/parseCoverageSummary';
65

7-
export const getCommentBody = (
6+
export const getFormattedCoverage = (
87
headSummary: ParsedCoverageSummary,
98
baseSummary: ParsedCoverageSummary,
109
headDetails: ParsedCoverageDetails,
1110
baseDetails: ParsedCoverageDetails
1211
): string => {
1312
return [
14-
MESSAGE_HEADING,
1513
formatCoverageSummary(headSummary, baseSummary),
1614
formatCoverageDetails(headDetails, baseDetails),
1715
]

src/format/getFormattedFailReason.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { errorIcon, errors } from './strings.json';
2+
import { FailReason } from '../report/generateReport';
3+
4+
const insertArgs = (
5+
text: string,
6+
args: Record<string, string | number | undefined>
7+
) => {
8+
Object.keys(args).forEach(
9+
(argName) =>
10+
args[argName] !== undefined &&
11+
args[argName] !== null &&
12+
(text = text.replace(`{{ ${argName} }}`, args[argName] as string))
13+
);
14+
return text;
15+
};
16+
17+
export const getFormattedFailReason = (
18+
reason: FailReason,
19+
coverageThreshold?: number,
20+
currentCoverage?: number
21+
): string =>
22+
`${errorIcon} ${insertArgs(errors[reason], {
23+
coverageThreshold,
24+
currentCoverage,
25+
})}`;

src/comment-body/getters/getDecreasedCoverage.ts renamed to src/format/getters/getDecreasedCoverage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
FileCoverageDetail,
33
ParsedCoverageDetails,
4-
} from '../../collect-coverage/parseCoverageDetails';
4+
} from '../../collect/parseCoverageDetails';
55

66
const coverageLessThan = (
77
first: FileCoverageDetail,

src/comment-body/getters/getNewFilesCoverage.ts renamed to src/format/getters/getNewFilesCoverage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ParsedCoverageDetails } from '../../collect-coverage/parseCoverageDetails';
1+
import { ParsedCoverageDetails } from '../../collect/parseCoverageDetails';
22

33
export const getNewFilesCoverage = (
44
headDetails: ParsedCoverageDetails,

src/comment-body/strings.json renamed to src/format/strings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
{
22
"increaseIcon": "🔼",
33
"decreaseIcon": "🔻",
4+
"errorIcon": "",
45
"heading": "jest coverage report 🧪",
6+
"errors": {
7+
"testsFailed": "The test suite failed. Please, check the console output for more details.",
8+
"invalidFormat": "Output of test script has invalid format. Check [documentation](https://github.com/ArtiomTr/jest-coverage-report-action#jest-coverage-report-) for more details.",
9+
"tooSmallCoverage": "Total coverage is too small. Current coverage is {{ currentCoverage }}, but it should be at least {{ coverageThreshold }}.",
10+
"unknownError": "Something went wrong. If this is an issue of jest-coverage-report-action, please report about it [here](https://github.com/ArtiomTr/jest-coverage-report-action/issues/new)."
11+
},
512
"summary": {
613
"heading": "Total coverage",
714
"columnHeaders": ["Category", "Percentage", "Covered / Total"],

src/comment-body/summary/formatCoverageSummary.ts renamed to src/format/summary/formatCoverageSummary.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import table from 'markdown-table';
22

3-
import { ParsedCoverageSummary } from '../../collect-coverage/parseCoverageSummary';
3+
import { ParsedCoverageSummary } from '../../collect/parseCoverageSummary';
44
import { summary } from '../strings.json';
55
import { formatPercentage } from '../utils/formatPercentage';
66

src/index.ts

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ import { argv } from 'process';
33
import { setFailed } from '@actions/core';
44
import { context, getOctokit } from '@actions/github';
55

6-
import { collectCoverage } from './collect-coverage/collectCoverage';
7-
import { getCommentBody } from './comment-body/getCommentBody';
8-
import { fetchPreviousComment } from './fetchPreviousComment';
6+
import { collectCoverage } from './collect/collectCoverage';
7+
import { FailReason, generateReport } from './report/generateReport';
98

109
async function run() {
1110
try {
@@ -20,43 +19,46 @@ async function run() {
2019
);
2120
}
2221

23-
const [token, testScript] = argv.slice(2);
22+
const [token, testScript, coverageThresholdStr] = argv.slice(2);
2423

25-
const octokit = getOctokit(token);
24+
const coverageThreshold = coverageThresholdStr
25+
? parseFloat(coverageThresholdStr)
26+
: undefined;
2627

27-
const [headSummary, headDetails] = await collectCoverage(testScript);
28-
const [baseSummary, baseDetails] = await collectCoverage(testScript);
28+
if (
29+
coverageThreshold !== undefined &&
30+
(coverageThreshold > 100 || coverageThreshold < 0)
31+
) {
32+
throw new Error(
33+
`Specified threshold '${coverageThreshold}' is not valid. Threshold should be more than 0 and less than 100.`
34+
);
35+
}
2936

30-
const previousComment = await fetchPreviousComment(
31-
octokit,
32-
repo,
33-
pull_request
34-
);
37+
const octokit = getOctokit(token);
3538

36-
const body = getCommentBody(
37-
headSummary,
38-
baseSummary,
39-
headDetails,
40-
baseDetails
41-
);
39+
const headReport = await collectCoverage(testScript);
40+
const baseReport = await collectCoverage(testScript);
4241

43-
try {
44-
if (previousComment) {
45-
await octokit.issues.deleteComment({
46-
...repo,
47-
comment_id: (previousComment as { id: number }).id,
48-
});
49-
}
50-
await octokit.issues.createComment({
51-
...repo,
52-
issue_number: pull_request.number,
53-
body,
54-
});
55-
} catch (error) {
56-
console.error(
57-
"Error deleting and/or creating comment. This can happen for PR's originating from a fork without write permissions."
58-
);
42+
if (
43+
coverageThreshold !== undefined &&
44+
headReport.success &&
45+
headReport.summary &&
46+
headReport.details &&
47+
!headReport.failReason &&
48+
headReport.summary.lines.percentage < coverageThreshold
49+
) {
50+
headReport.success = false;
51+
headReport.failReason = FailReason.TOO_SMALL_TOTAL_COVERAGE;
5952
}
53+
54+
await generateReport(
55+
headReport,
56+
baseReport,
57+
coverageThreshold,
58+
repo,
59+
pull_request,
60+
octokit
61+
);
6062
} catch (error) {
6163
setFailed(error.message);
6264
}

src/fetchPreviousComment.ts renamed to src/report/fetchPreviousReport.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import { getOctokit } from '@actions/github';
22

3-
import { heading } from './comment-body/strings.json';
3+
import { MESSAGE_HEADING } from '../constants/MESSAGE_HEADING';
44

5-
export const MESSAGE_HEADING = `## ${heading}`;
6-
7-
export async function fetchPreviousComment(
5+
export async function fetchPreviousReport(
86
octokit: ReturnType<typeof getOctokit>,
97
repo: { owner: string; repo: string },
108
pr: { number: number }
@@ -20,5 +18,6 @@ export async function fetchPreviousComment(
2018
const sizeLimitComment = commentList.find((comment) =>
2119
(comment as { body: string }).body.startsWith(MESSAGE_HEADING)
2220
);
21+
2322
return !sizeLimitComment ? null : sizeLimitComment;
2423
}

0 commit comments

Comments
 (0)