Skip to content

Commit 29eba1e

Browse files
committed
feat: add support for sticky comment notifications
1 parent 58050ff commit 29eba1e

File tree

9 files changed

+427
-320
lines changed

9 files changed

+427
-320
lines changed

.github/workflows/examples.yml

Lines changed: 327 additions & 295 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,15 @@ _Optional_ Will create a [GitHub Check Run](https://developer.github.com/v3/chec
7878

7979
_Optional_ Will create a comment in the linked issue if `'true'` is specified, **requires** `token` to be given as well
8080

81+
### `sticky_comment`
82+
83+
_Optional_ When using `notify_issue: true`, will edit the created comment instead of creating a new one everytime.
84+
85+
Note that the updated comment is based on the `title`. Thus:
86+
87+
* if you call the action multiple times in your workflow, make sure the titles are unique to each call to avoid overwriting the same comment
88+
* make sure the titles are the same between different calls to the action if you want to update the same comment
89+
8190
## Outputs
8291

8392
### `passed`

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ inputs:
2929
notify_issue:
3030
description: 'send a notification to the linked issue/pullrequest with the output'
3131
required: false
32+
sticky_comment:
33+
description: 'will edit the created comment instead of creating a new one everytime'
34+
required: false
3235
notify_check:
3336
description: 'create a check run with the output'
3437
required: false

dist/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 16 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/inputs.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const parseInputs = (getInput: GetInput): Inputs.Args => {
2525
let notifications;
2626
const notify_check = getInput('notify_check');
2727
const notify_issue = getInput('notify_issue');
28+
const sticky_comment = getInput('sticky_comment');
2829
if (notify_check || notify_issue) {
2930
const label = getInput('title');
3031
const token = getInput('token', {required: true});
@@ -33,6 +34,7 @@ export const parseInputs = (getInput: GetInput): Inputs.Args => {
3334
label,
3435
check: notify_check === 'true',
3536
issue: notify_issue === 'true',
37+
sticky: sticky_comment === 'true',
3638
};
3739
}
3840

src/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as github from '@actions/github';
33
import fs from 'fs';
44
import {parseInputs} from './inputs';
55
import {processDiff} from './processing';
6-
import {createRun, createComment} from './notifications';
6+
import {createRun, upsertComment} from './notifications';
77

88
async function run(): Promise<void> {
99
try {
@@ -25,7 +25,7 @@ async function run(): Promise<void> {
2525
core.debug(`Notification: Issue`);
2626
const issueId = github.context.issue.number;
2727
if (issueId || issueId === 0) {
28-
await createComment(octokit, github.context, result, inputs.notifications.label);
28+
await upsertComment(octokit, github.context, result, inputs.notifications.label);
2929
} else {
3030
core.debug(`Notification: no issue id`);
3131
}

src/namespaces/Inputs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type Args = {
1111
label?: string;
1212
issue: boolean;
1313
check: boolean;
14+
sticky: boolean;
1415
};
1516
};
1617

src/notifications.ts

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,21 @@ export const createRun = async (
3535
});
3636
};
3737

38-
export const createComment = async (
38+
const commentLocator = (label?: string): string => {
39+
return `<!-- Diff Action / Pull Request Comment / ${label ?? ''} -->`;
40+
};
41+
42+
const commentBody = (label: string | undefined, result: Result): string => {
43+
return `${commentLocator(label)}## ${getTitle(label)}: ${result.passed ? 'Success' : 'Failure'}
44+
${result.summary}
45+
46+
\`\`\`
47+
${result.output}
48+
\`\`\`
49+
`;
50+
};
51+
52+
const createComment = async (
3953
octokit: InstanceType<typeof GitHub>,
4054
context: Context,
4155
result: Result,
@@ -45,12 +59,56 @@ export const createComment = async (
4559
owner: context.repo.owner,
4660
repo: context.repo.repo,
4761
issue_number: context.issue.number,
48-
body: `## ${getTitle(label)}: ${result.passed ? 'Success' : 'Failure'}
49-
${result.summary}
62+
body: commentBody(label, result),
63+
});
64+
};
5065

51-
\`\`\`
52-
${result.output}
53-
\`\`\`
54-
`,
66+
const updateComment = async (
67+
octokit: InstanceType<typeof GitHub>,
68+
context: Context,
69+
comment_id: number,
70+
result: Result,
71+
label?: string,
72+
): Promise<void> => {
73+
await octokit.rest.issues.updateComment({
74+
owner: context.repo.owner,
75+
repo: context.repo.repo,
76+
comment_id: comment_id,
77+
body: commentBody(label, result),
5578
});
5679
};
80+
81+
const findComment = async (
82+
octokit: InstanceType<typeof GitHub>,
83+
context: Context,
84+
label?: string,
85+
): Promise<undefined | number> => {
86+
const {viewer}: {viewer: {login?: string}} = await octokit.graphql('query { viewer { login } }');
87+
const locator = commentLocator(label);
88+
for await (const entry of octokit.paginate.iterator(octokit.rest.issues.listComments, {
89+
owner: context.repo.owner,
90+
repo: context.repo.repo,
91+
issue_number: context.issue.number,
92+
})) {
93+
for (const comment of entry.data) {
94+
console.log('USER', comment.user, viewer.login);
95+
if (comment.body?.startsWith(locator) && comment.user?.login === viewer.login) {
96+
return comment.id;
97+
}
98+
}
99+
}
100+
};
101+
102+
export const upsertComment = async (
103+
octokit: InstanceType<typeof GitHub>,
104+
context: Context,
105+
result: Result,
106+
label?: string,
107+
): Promise<void> => {
108+
const comment_id = await findComment(octokit, context, label);
109+
if (comment_id !== undefined) {
110+
await updateComment(octokit, context, comment_id, result, label);
111+
} else {
112+
await createComment(octokit, context, result, label);
113+
}
114+
};

0 commit comments

Comments
 (0)