Skip to content

Commit

Permalink
Show message if permissions missing (#422)
Browse files Browse the repository at this point in the history
* Pin @octokit/request-error version

* Add error notice

* Move report generation after annotation publication

* Styling

* Fix error logging in console

* Fixed tests
  • Loading branch information
ArtiomTr authored Mar 6, 2024
1 parent 0d5fce3 commit ab8c40c
Show file tree
Hide file tree
Showing 16 changed files with 351 additions and 297 deletions.
361 changes: 181 additions & 180 deletions dist/index.js

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@actions/exec": "^1.1.1",
"@actions/github": "^5.0.3",
"@actions/http-client": "^2.0.1",
"@octokit/request-error": "^2.1.0",
"fs-extra": "^10.0.0",
"markdown-table": "^2.0.0",
"micromatch": "^4.0.4",
Expand Down
11 changes: 11 additions & 0 deletions src/format/formatErrors.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { formatThresholdResults } from './formatThresholdResults';
import { ActionError } from '../typings/ActionError';
import { FailReason } from '../typings/Report';
import { ThresholdResult } from '../typings/ThresholdResult';
import { getConsoleLink } from '../utils/getConsoleLink';
import { i18n } from '../utils/i18n';
Expand All @@ -24,6 +25,16 @@ const formatErrorsInner = (
return undefined;
}

if (
errors.some(
(error) =>
error instanceof ActionError &&
error.failReason === FailReason.MISSING_CHECKS_PERMISSION
)
) {
return i18n('errors.missingChecksPermissionDetail');
}

if (errors.length === 1) {
const error = errors[0];

Expand Down
19 changes: 18 additions & 1 deletion src/format/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"baseCoverage": "Base coverage collection",
"switchToBase": "Switching to base branch",
"generateReportContent": "Generating report",
"generateRunReport": "Generating run report",
"publishReport": "Report publish",
"failedTestsAnnotations": "Failed tests' annotations publication",
"coverageAnnotations": "Coverage annotations publication",
Expand Down Expand Up @@ -106,7 +107,23 @@
"failedGettingCoverage": "Getting code coverage data failed.",
"reportGenerationError": "Action wasn't able to generate report within GitHub comment limit. If you're facing this issue, please let me know by commenting under [this issue](https://github.com/ArtiomTr/jest-coverage-report-action/issues/404).",
"testFail": "Test run failed",
"coverageFail": "Coverage does not meet threshold"
"coverageFail": "Coverage does not meet threshold",
"missingChecksPermission": "Missing `checks: write` permission",
"missingChecksPermissionDetail": [
"You've enabled `annotations` option, but `checks` permission is missing. To fix this, add this to your `action.yaml` file:",
"```diff",
"jobs:",
" permissions:",
" contents: write",
" pull-requests: write",
"+ checks: write",
" coverage:",
" runs-on: ubuntu-latest",
" steps:",
" - uses: actions/checkout@v3",
" - uses: ArtiomTr/jest-coverage-report-action@v2",
"```"
]
},
"detailsHidden": ":warning: Details were not displayed: the report size has exceeded the limit.",
"summaryTitle": "Coverage report {{ dir }}",
Expand Down
107 changes: 61 additions & 46 deletions src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { generateCommitReport } from './report/generateCommitReport';
import { generatePRReport } from './report/generatePRReport';
import { checkThreshold } from './stages/checkThreshold';
import { createReport } from './stages/createReport';
import { createRunReport } from './stages/createRunReport';
import { getCoverage } from './stages/getCoverage';
import {
checkoutRef,
Expand Down Expand Up @@ -170,54 +171,22 @@ export const run = async (
}
);

const [isReportContentGenerated, summaryReport] = await runStage(
'generateReportContent',
const [isRunReportGenerated, runReport] = await runStage(
'generateRunReport',
dataCollector,
async () => {
return createReport(dataCollector, options, thresholdResults ?? []);
}
);

await runStage('publishReport', dataCollector, async (skip) => {
if (!isReportContentGenerated || !options.output.includes('comment')) {
skip();
}

const octokit = getOctokit(options.token);

if (isInPR) {
await generatePRReport(
summaryReport!.text,
options,
context.repo,
options.pullRequest as { number: number },
octokit
);
} else {
await generateCommitReport(
summaryReport!.text,
context.repo,
octokit
);
}
});

await runStage('setOutputs', dataCollector, (skip) => {
if (
!isReportContentGenerated ||
!options.output.includes('report-markdown')
) {
skip();
}
(skip) => {
if (!isHeadCoverageGenerated) {
skip();
}

if (options.output.includes('report-markdown')) {
setOutput('report', summaryReport!.text);
return createRunReport(headCoverage!);
}
});
);

await runStage('failedTestsAnnotations', dataCollector, async (skip) => {
if (
!isHeadCoverageGenerated ||
!isRunReportGenerated ||
!['all', 'failed-tests'].includes(options.annotations)
) {
skip();
Expand All @@ -228,11 +197,7 @@ export const run = async (
const octokit = getOctokit(options.token);
await upsertCheck(
octokit,
formatFailedTestsAnnotations(
summaryReport!.runReport,
failedAnnotations,
options
)
formatFailedTestsAnnotations(runReport!, failedAnnotations, options)
);
});

Expand Down Expand Up @@ -261,6 +226,56 @@ export const run = async (
);
});

const [isReportContentGenerated, summaryReport] = await runStage(
'generateReportContent',
dataCollector,
async () => {
return createReport(
dataCollector,
runReport,
options,
thresholdResults ?? []
);
}
);

await runStage('publishReport', dataCollector, async (skip) => {
if (!isReportContentGenerated || !options.output.includes('comment')) {
skip();
}

const octokit = getOctokit(options.token);

if (isInPR) {
await generatePRReport(
summaryReport!.text,
options,
context.repo,
options.pullRequest as { number: number },
octokit
);
} else {
await generateCommitReport(
summaryReport!.text,
context.repo,
octokit
);
}
});

await runStage('setOutputs', dataCollector, (skip) => {
if (
!isReportContentGenerated ||
!options.output.includes('report-markdown')
) {
skip();
}

if (options.output.includes('report-markdown')) {
setOutput('report', summaryReport!.text);
}
});

if (dataCollector.get().errors.length > 0) {
setFailed(i18n('failed'));
}
Expand Down
26 changes: 2 additions & 24 deletions src/stages/createReport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { GITHUB_MESSAGE_SIZE_LIMIT } from '../constants/GITHUB_MESSAGE_SIZE_LIMI
import { formatCoverage } from '../format/formatCoverage';
import { formatErrors } from '../format/formatErrors';
import { formatRunReport } from '../format/formatRunReport';
import { getFailureDetails } from '../format/getFailureDetails';
import template from '../format/template.md';
import { JsonReport } from '../typings/JsonReport';
import { Options } from '../typings/Options';
Expand All @@ -22,6 +21,7 @@ export const getSha = () =>

export const createReport = (
dataCollector: DataCollector<JsonReport>,
runReport: TestRunReport | undefined,
options: Options,
thresholdResults: ThresholdResult[]
): SummaryReport => {
Expand All @@ -38,28 +38,7 @@ export const createReport = (
);

const coverage = formatCoverage(headReport, baseReport, undefined, false);
const runReport: TestRunReport = headReport.success
? {
success: true,
title: i18n('testsSuccess'),
summary: i18n('testsSuccessSummary', {
numPassedTests: headReport.numPassedTests,
numPassedTestSuites: headReport.numPassedTestSuites,
ending: headReport.numPassedTestSuites > 1 ? 's' : '',
}),
}
: {
success: false,
title: i18n('testsFail'),
summary: i18n('testsFailSummary', {
numFailedTests: headReport.numFailedTests,
numTotalTests: headReport.numTotalTests,
numFailedTestSuites: headReport.numFailedTestSuites,
numTotalTestSuites: headReport.numTotalTestSuites,
}),
failures: getFailureDetails(headReport),
};
const formattedReport = formatRunReport(runReport);
const formattedReport = runReport ? formatRunReport(runReport) : '';

let templateText = insertArgs(template, {
body: [formattedErrors, coverage, formattedReport].join('\n'),
Expand Down Expand Up @@ -108,6 +87,5 @@ export const createReport = (

return {
text: templateText,
runReport,
};
};
28 changes: 28 additions & 0 deletions src/stages/createRunReport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { getFailureDetails } from '../format/getFailureDetails';
import { JsonReport } from '../typings/JsonReport';
import { TestRunReport } from '../typings/Report';
import { i18n } from '../utils/i18n';

export const createRunReport = (headReport: JsonReport): TestRunReport => {
return headReport.success
? {
success: true,
title: i18n('testsSuccess'),
summary: i18n('testsSuccessSummary', {
numPassedTests: headReport.numPassedTests,
numPassedTestSuites: headReport.numPassedTestSuites,
ending: headReport.numPassedTestSuites > 1 ? 's' : '',
}),
}
: {
success: false,
title: i18n('testsFail'),
summary: i18n('testsFailSummary', {
numFailedTests: headReport.numFailedTests,
numTotalTests: headReport.numTotalTests,
numFailedTestSuites: headReport.numFailedTestSuites,
numTotalTestSuites: headReport.numTotalTestSuites,
}),
failures: getFailureDetails(headReport),
};
};
3 changes: 3 additions & 0 deletions src/typings/ActionError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import { FailReason } from './Report';
import { i18n } from '../utils/i18n';

export class ActionError<T> extends Error {
public readonly failReason: FailReason;

public constructor(reason: FailReason, details?: T) {
super(
i18n(
`errors.${reason}`,
(details as unknown) as Record<string, unknown>
)
);
this.failReason = reason;
}

public toString(): string {
Expand Down
2 changes: 1 addition & 1 deletion src/typings/Report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum FailReason {
REPORT_NOT_FOUND = 'reportNotFound',
READING_COVERAGE_FILE_FAILED = 'readingCoverageFileFailed',
FAILED_GETTING_COVERAGE = 'failedGettingCoverage',
MISSING_CHECKS_PERMISSION = 'missingChecksPermission',
}

export type TestRunReport =
Expand All @@ -23,5 +24,4 @@ export type TestRunReport =

export type SummaryReport = {
text: string;
runReport: TestRunReport;
};
6 changes: 5 additions & 1 deletion src/utils/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ const icons = (strings.icons as Record<string, Record<string, string>>)[
];

export const i18n = (key: string, args?: Record<string, unknown>) => {
const string = get(strings, key, key) as string;
let string = get(strings, key, key) as string | string[];

if (Array.isArray(string)) {
string = string.join('\n');
}

const normalizedIconsString = string.replace(
iconRegex,
Expand Down
27 changes: 19 additions & 8 deletions src/utils/upsertCheck.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { getOctokit } from '@actions/github';
import { RequestError } from '@octokit/request-error';

import { CreateCheckOptions } from '../format/annotations/CreateCheckOptions';
import { ActionError } from '../typings/ActionError';
import { FailReason } from '../typings/Report';

export const upsertCheck = async (
octokit: ReturnType<typeof getOctokit>,
Expand All @@ -26,13 +29,21 @@ export const upsertCheck = async (
);
}

if (check_id === undefined) {
await octokit.rest.checks.create(check);
} else {
await octokit.rest.checks.update({
check_run_id: check_id,
...check,
head_sha: undefined,
});
try {
if (check_id === undefined) {
await octokit.rest.checks.create(check);
} else {
await octokit.rest.checks.update({
check_run_id: check_id,
...check,
head_sha: undefined,
});
}
} catch (error) {
if (error instanceof RequestError && error.status === 403) {
throw new ActionError(FailReason.MISSING_CHECKS_PERMISSION);
}

throw error;
}
};
Loading

0 comments on commit ab8c40c

Please sign in to comment.