Skip to content

Commit 5d90a13

Browse files
t3chguyabenhamdine
andauthored
Add support for github pull request annotations (#367)
Co-authored-by: Arnaud Benhamdine <arnaud.benhamdine@gmail.com> Fixes #163
1 parent dea4cd3 commit 5d90a13

File tree

7 files changed

+146
-81
lines changed

7 files changed

+146
-81
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ Value|Behaviour
7474
`errors_in_pr`| Check fails if any errors are present in the files added/modified in the PR branch (even if already in base branche).
7575
`errors_in_code`| Check fails if any errors are present in the whole branch.
7676

77+
The output behaviour depends on the value of `output-behaviour`
78+
79+
Value|Behaviour
80+
-- | --
81+
`comment` | Default, comments on the PR with the errors found for this run.
82+
`annotate` | Uses github line annotations with the errors found for this run.
83+
`both` | Does both of the above.
84+
7785
## Use a specific tsconfig file
7886

7987
By default, this actions uses tsconfig file located at './tsconfig.json'
@@ -86,4 +94,4 @@ parameter `ts-config-path` :
8694

8795
```yml
8896
ts-config-path: './tsconfig.check.json'
89-
```
97+
```

action.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ inputs:
2828
check-fail-mode:
2929
description: "Allowed values : added, errors_in_pr, errors_in_code"
3030
required: true
31+
output-behaviour:
32+
description: "Allowed values : comment, annotate, both"
33+
default: "comment"
34+
required: false
3135
debug:
32-
description: "Set true to log ts errors in base branch and pr branc"
36+
description: "Set true to log ts errors in base branch and pr branch"
3337
default: false
3438
runs:
3539
using: 'node16'

dist/index.js

Lines changed: 57 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ function getAndValidateArgs() {
177177
lineNumbers: (_d = JSON.parse((0, core_1.getInput)('line-numbers'))) !== null && _d !== void 0 ? _d : [],
178178
useCheck: (0, core_1.getBooleanInput)('use-check'),
179179
checkFailMode: (0, core_1.getInput)('check-fail-mode'),
180+
outputBehaviour: (0, core_1.getInput)('output-behaviour'),
180181
debug: (0, core_1.getBooleanInput)('debug')
181182
};
182183
if (![
@@ -186,6 +187,13 @@ function getAndValidateArgs() {
186187
].includes(args.checkFailMode)) {
187188
throw new Error(`Invalid value ${args.checkFailMode} for input check-fail-mode`);
188189
}
190+
if (![
191+
"comment" /* OUTPUT_BEHAVIOUR.COMMENT */,
192+
"annotate" /* OUTPUT_BEHAVIOUR.ANNOTATE */,
193+
"both" /* OUTPUT_BEHAVIOUR.COMMENT_AND_ANNOTATE */
194+
].includes(args.outputBehaviour)) {
195+
throw new Error(`Invalid value ${args.outputBehaviour} for input output-behaviour`);
196+
}
189197
return args;
190198
}
191199
exports.getAndValidateArgs = getAndValidateArgs;
@@ -369,6 +377,9 @@ const parseOutputTsc_1 = __nccwpck_require__(4155);
369377
async function run() {
370378
try {
371379
const args = (0, getAndValidateArgs_1.getAndValidateArgs)();
380+
if (args.debug) {
381+
(0, core_1.info)(`[config] args: \n${JSON.stringify(args)}`);
382+
}
372383
const workingDir = path.join(process.cwd(), args.directory);
373384
(0, core_1.info)(`working directory: ${workingDir}`);
374385
const tsconfigPath = path.join(workingDir, args.tsConfigPath);
@@ -461,44 +472,57 @@ async function run() {
461472
});
462473
(0, core_1.info)(`${newErrorsInModifiedFiles.length} added errors in modified files`);
463474
(0, core_1.endGroup)();
464-
(0, core_1.startGroup)(`Creating comment`);
465-
const commentInfo = {
466-
...github_1.context.repo,
467-
issue_number: github_1.context.payload.pull_request.number
468-
};
469-
const comment = {
470-
...commentInfo,
471-
body: (0, getBodyComment_1.getBodyComment)({
472-
errorsInProjectBefore: errorsBaseBranch,
473-
errorsInProjectAfter: errorsPr,
474-
newErrorsInProject: resultCompareErrors.errorsAdded,
475-
errorsInModifiedFiles,
476-
newErrorsInModifiedFiles
477-
})
478-
};
479-
(0, core_1.info)(`comment body obtained`);
480-
try {
481-
await octokit.rest.issues.createComment(comment);
475+
if (["annotate" /* OUTPUT_BEHAVIOUR.ANNOTATE */, "both" /* OUTPUT_BEHAVIOUR.COMMENT_AND_ANNOTATE */].includes(args.outputBehaviour)) {
476+
resultCompareErrors.errorsAdded.forEach(err => {
477+
var _a;
478+
(0, core_1.error)(`${err.fileName}:${err.line}:${err.column} - ${err.message}`, {
479+
file: err.fileName,
480+
startLine: parseInt(err.line),
481+
startColumn: parseInt(err.column),
482+
title: (_a = err.extraMsg) !== null && _a !== void 0 ? _a : err.message
483+
});
484+
});
482485
}
483-
catch (e) {
484-
(0, core_1.info)(`Error creating comment: ${e.message}`);
485-
(0, core_1.info)(`Submitting a PR review comment instead...`);
486+
if (["comment" /* OUTPUT_BEHAVIOUR.COMMENT */, "both" /* OUTPUT_BEHAVIOUR.COMMENT_AND_ANNOTATE */].includes(args.outputBehaviour)) {
487+
(0, core_1.startGroup)(`Creating comment`);
488+
const commentInfo = {
489+
...github_1.context.repo,
490+
issue_number: github_1.context.payload.pull_request.number
491+
};
492+
const comment = {
493+
...commentInfo,
494+
body: (0, getBodyComment_1.getBodyComment)({
495+
errorsInProjectBefore: errorsBaseBranch,
496+
errorsInProjectAfter: errorsPr,
497+
newErrorsInProject: resultCompareErrors.errorsAdded,
498+
errorsInModifiedFiles,
499+
newErrorsInModifiedFiles
500+
})
501+
};
502+
(0, core_1.info)(`comment body obtained`);
486503
try {
487-
const issue = github_1.context.issue || pr;
488-
await octokit.rest.pulls.createReview({
489-
owner: issue.owner,
490-
repo: issue.repo,
491-
pull_number: issue.number,
492-
event: 'COMMENT',
493-
body: comment.body
494-
});
504+
await octokit.rest.issues.createComment(comment);
495505
}
496-
catch (errCreateComment) {
497-
(0, core_1.info)(`Error creating PR review ${errCreateComment.message}`);
506+
catch (e) {
507+
(0, core_1.info)(`Error creating comment: ${e.message}`);
508+
(0, core_1.info)(`Submitting a PR review comment instead...`);
509+
try {
510+
const issue = github_1.context.issue || pr;
511+
await octokit.rest.pulls.createReview({
512+
owner: issue.owner,
513+
repo: issue.repo,
514+
pull_number: issue.number,
515+
event: 'COMMENT',
516+
body: comment.body
517+
});
518+
}
519+
catch (errCreateComment) {
520+
(0, core_1.info)(`Error creating PR review ${errCreateComment.message}`);
521+
}
498522
}
523+
(0, core_1.info)(`comment created`);
524+
(0, core_1.endGroup)();
499525
}
500-
(0, core_1.info)(`comment created`);
501-
(0, core_1.endGroup)();
502526
let shouldFailCheck = false;
503527
let title = '';
504528
let summary = '';

dist/index.js.map

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

src/checkoutAndInstallBaseBranch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,4 @@ export async function checkoutAndInstallBaseBranch({ installScript, payload, exe
4646
startGroup(`[base branch] Install Dependencies`)
4747
await exec(installScript, [], execOptions)
4848
endGroup()
49-
}
49+
}

src/getAndValidateArgs.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ export const enum CHECK_FAIL_MODE {
55
ON_ERRORS_PRESENT_IN_PR = 'errors_in_pr',
66
ON_ERRORS_PRESENT_IN_CODE = 'errors_in_code'
77
}
8+
9+
export const enum OUTPUT_BEHAVIOUR {
10+
COMMENT = 'comment',
11+
ANNOTATE = 'annotate',
12+
COMMENT_AND_ANNOTATE = 'both'
13+
}
14+
815
type Args = {
916
repoToken: string
1017
directory: string
@@ -34,11 +41,12 @@ type Args = {
3441
* 2
3542
* ]
3643
* }
37-
* ]
44+
* ]
3845
*/
3946
lineNumbers: { path: string, added: number[], removed: number[] }[]
4047
useCheck: boolean
41-
checkFailMode: CHECK_FAIL_MODE,
48+
checkFailMode: CHECK_FAIL_MODE
49+
outputBehaviour: OUTPUT_BEHAVIOUR
4250
debug: boolean
4351
}
4452

@@ -53,6 +61,7 @@ export function getAndValidateArgs(): Args {
5361
lineNumbers: JSON.parse(getInput('line-numbers')) ?? [],
5462
useCheck: getBooleanInput('use-check'),
5563
checkFailMode: getInput('check-fail-mode') as CHECK_FAIL_MODE,
64+
outputBehaviour: getInput('output-behaviour') as OUTPUT_BEHAVIOUR,
5665
debug: getBooleanInput('debug')
5766
}
5867

@@ -64,5 +73,13 @@ export function getAndValidateArgs(): Args {
6473
throw new Error(`Invalid value ${args.checkFailMode} for input check-fail-mode`)
6574
}
6675

76+
if (![
77+
OUTPUT_BEHAVIOUR.COMMENT,
78+
OUTPUT_BEHAVIOUR.ANNOTATE,
79+
OUTPUT_BEHAVIOUR.COMMENT_AND_ANNOTATE
80+
].includes(args.outputBehaviour)) {
81+
throw new Error(`Invalid value ${args.outputBehaviour} for input output-behaviour`)
82+
}
83+
6784
return args
6885
}

src/main.ts

Lines changed: 54 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { info, startGroup, endGroup, setFailed } from '@actions/core'
1+
import { info, startGroup, endGroup, error, setFailed } from '@actions/core'
22
import * as path from 'path'
33
import { context, getOctokit } from '@actions/github'
44
import { createCheck } from './createCheck'
55
import * as github from '@actions/github'
66
import * as fs from 'fs'
77
import { parseTsConfigFile } from './tscHelpers/parseTsConfigFileToCompilerOptions'
8-
import { getAndValidateArgs, CHECK_FAIL_MODE } from './getAndValidateArgs'
8+
import { getAndValidateArgs, CHECK_FAIL_MODE, OUTPUT_BEHAVIOUR } from './getAndValidateArgs'
99
import { exec } from '@actions/exec'
1010
import { getBodyComment } from './getBodyComment'
1111
import { checkoutAndInstallBaseBranch } from './checkoutAndInstallBaseBranch'
@@ -24,16 +24,15 @@ export type ErrorTs = {
2424
/** for long error messages */
2525
extraMsg?: string
2626
}
27-
interface PullRequest {
28-
number: number;
29-
html_url?: string
30-
body?: string
31-
changed_files: number
32-
}
3327

3428
async function run(): Promise<void> {
3529
try {
3630
const args = getAndValidateArgs()
31+
32+
if (args.debug) {
33+
info(`[config] args: \n${JSON.stringify(args)}`)
34+
}
35+
3736
const workingDir = path.join(process.cwd(), args.directory)
3837
info(`working directory: ${workingDir}`)
3938

@@ -161,47 +160,60 @@ async function run(): Promise<void> {
161160

162161
endGroup()
163162

164-
startGroup(`Creating comment`)
165-
166-
const commentInfo = {
167-
...context.repo,
168-
issue_number: context.payload.pull_request!.number
169-
}
170-
171-
const comment = {
172-
...commentInfo,
173-
body: getBodyComment({
174-
errorsInProjectBefore: errorsBaseBranch,
175-
errorsInProjectAfter: errorsPr,
176-
newErrorsInProject: resultCompareErrors.errorsAdded,
177-
errorsInModifiedFiles,
178-
newErrorsInModifiedFiles
163+
if ([OUTPUT_BEHAVIOUR.ANNOTATE, OUTPUT_BEHAVIOUR.COMMENT_AND_ANNOTATE].includes(args.outputBehaviour)) {
164+
resultCompareErrors.errorsAdded.forEach(err => {
165+
error(`${err.fileName}:${err.line}:${err.column} - ${err.message}`, {
166+
file: err.fileName,
167+
startLine: parseInt(err.line),
168+
startColumn: parseInt(err.column),
169+
title: err.extraMsg ?? err.message
170+
})
179171
})
180172
}
181-
info(`comment body obtained`)
182173

183-
try {
184-
await octokit.rest.issues.createComment(comment)
185-
} catch (e) {
186-
info(`Error creating comment: ${(e as Error).message}`)
187-
info(`Submitting a PR review comment instead...`)
188-
try {
189-
const issue = context.issue || pr
190-
await octokit.rest.pulls.createReview({
191-
owner: issue.owner,
192-
repo: issue.repo,
193-
pull_number: issue.number,
194-
event: 'COMMENT',
195-
body: comment.body
174+
if ([OUTPUT_BEHAVIOUR.COMMENT, OUTPUT_BEHAVIOUR.COMMENT_AND_ANNOTATE].includes(args.outputBehaviour)) {
175+
startGroup(`Creating comment`)
176+
177+
const commentInfo = {
178+
...context.repo,
179+
issue_number: context.payload.pull_request!.number
180+
}
181+
182+
const comment = {
183+
...commentInfo,
184+
body: getBodyComment({
185+
errorsInProjectBefore: errorsBaseBranch,
186+
errorsInProjectAfter: errorsPr,
187+
newErrorsInProject: resultCompareErrors.errorsAdded,
188+
errorsInModifiedFiles,
189+
newErrorsInModifiedFiles
196190
})
197-
} catch (errCreateComment) {
198-
info(`Error creating PR review ${(errCreateComment as Error).message}`)
199191
}
200-
}
192+
info(`comment body obtained`)
193+
194+
try {
195+
await octokit.rest.issues.createComment(comment)
196+
} catch (e) {
197+
info(`Error creating comment: ${(e as Error).message}`)
198+
info(`Submitting a PR review comment instead...`)
199+
try {
200+
const issue = context.issue || pr
201+
await octokit.rest.pulls.createReview({
202+
owner: issue.owner,
203+
repo: issue.repo,
204+
pull_number: issue.number,
205+
event: 'COMMENT',
206+
body: comment.body
207+
})
208+
} catch (errCreateComment) {
209+
info(`Error creating PR review ${(errCreateComment as Error).message}`)
210+
}
211+
}
201212

202-
info(`comment created`)
213+
info(`comment created`)
203214

204-
endGroup()
215+
endGroup()
216+
}
205217

206218
let shouldFailCheck = false
207219
let title = ''

0 commit comments

Comments
 (0)