Skip to content

Commit a1014ef

Browse files
authored
feat(ci): unconditionally hide prior formatting PR comments, and only post a new one in case of failure (#1425)
1 parent ea830d5 commit a1014ef

File tree

3 files changed

+132
-32
lines changed

3 files changed

+132
-32
lines changed

.github/scripts/common.mjs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
export async function hidePriorCommentsWithPrefix({
2+
github, // injected by GitHub
3+
context, // injected by GitHub
4+
exec, // injected by GitHub
5+
prefix = '',
6+
resolved = true,
7+
user = 'github-actions[bot]',
8+
}) {
9+
const comments = await github.rest.issues.listComments({
10+
owner: context.repo.owner,
11+
repo: context.repo.repo,
12+
issue_number: context.issue.number,
13+
});
14+
for (const comment of comments.data) {
15+
const isHidden = (await github.graphql(`
16+
query($nodeId: ID!) {
17+
node(id: $nodeId) {
18+
... on IssueComment {
19+
isMinimized
20+
}
21+
}
22+
}
23+
`, { nodeId: comment.node_id }))?.node?.isMinimized;
24+
await exec.exec('sleep 0.5s');
25+
if (isHidden) { continue; }
26+
if (
27+
comment.user.login === user &&
28+
comment.body.startsWith(prefix)
29+
) {
30+
console.log('Comment node_id:', comment.node_id);
31+
console.log(await github.graphql(`
32+
mutation($subjectId: ID!, $classifier: ReportedContentClassifiers!) {
33+
minimizeComment(input: {
34+
subjectId: $subjectId,
35+
classifier: $classifier
36+
}) {
37+
minimizedComment {
38+
isMinimized
39+
minimizedReason
40+
}
41+
}
42+
}
43+
`, {
44+
subjectId: comment.node_id,
45+
classifier: resolved ? 'RESOLVED' : 'OUTDATED',
46+
}));
47+
await exec.exec('sleep 0.5s');
48+
}
49+
}
50+
}
51+
52+
export async function createComment({
53+
github, // injected by GitHub
54+
context, // injected by GitHub
55+
exec, // injected by GitHub
56+
body = '',
57+
}) {
58+
await github.rest.issues.createComment({
59+
owner: context.repo.owner,
60+
repo: context.repo.repo,
61+
issue_number: context.issue.number,
62+
body: body,
63+
});
64+
}

.github/workflows/linter.yml

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ on:
1010
workflow_dispatch:
1111

1212
concurrency:
13-
group: ${{ github.workflow }}-${{ github.ref }}
13+
group: ${{ github.workflow }}-${{ github.ref }}-linter
1414
cancel-in-progress: true
1515

1616
permissions:
1717
contents: read
1818
pull-requests: write
19-
issues: write
19+
# issues: write
2020

2121
jobs:
2222
format-check:
@@ -46,41 +46,76 @@ jobs:
4646
files: |
4747
**.md
4848
**.mdx
49+
separator: ":"
4950

5051
- name: Check formatting of MDX and Markdown files
5152
id: check-fmt
5253
env:
5354
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
54-
run: |
55-
if [ -z $(echo -e "${ALL_CHANGED_FILES[@]}" | tr -d '[:space:]') ]; then
56-
echo -e '\nNo such files affected!'
57-
exit 0
58-
fi
59-
echo -e '\nChecking formatting of the following MDX and Markdown files affected by this PR:\n'
60-
for file in ${ALL_CHANGED_FILES}; do
61-
echo "- $file"
62-
done
63-
echo
64-
npx remark --no-stdout --quiet --frail --silently-ignore $(echo -e "${ALL_CHANGED_FILES[@]}" | tr '\n' ' ')
65-
66-
- name: ${{ steps.check-fmt.conclusion == 'failure' && '👀 How to fix the formatting? See these suggestions!' || '...' }}
55+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
56+
with:
57+
script: |
58+
const files = (process.env.ALL_CHANGED_FILES ?? '').trim().split(':').filter(Boolean);
59+
if (files.length === 0) {
60+
console.log('\nNo such files affected!');
61+
process.exit(0);
62+
}
63+
console.log('\nChecking formatting of the following MDX and Markdown files affected by this PR:\n');
64+
for (const file of files) {
65+
console.log(`- ${file}`);
66+
}
67+
const filesQuoted = files.map((it) => '"' + it + '"');
68+
try {
69+
await exec.exec('npm', ['run', 'check:fmt:some', '--', ...filesQuoted], {
70+
silent: true, // >/dev/null 2>&1
71+
});
72+
} catch (_) {
73+
// Comment right in the actions output
74+
const filesJoined = filesQuoted.join(' ');
75+
console.log('\n\x1b[31mError:\x1b[0m Some files are not properly formatted!');
76+
console.log('1. Install necessary dependencies: \x1b[31mnpm ci\x1b[0m');
77+
console.log(`2. Run this command to fix the issues: \x1b[31mnpm run fmt:some -- ${filesJoined}\x1b[0m`);
78+
79+
// Prepare a comment on the PR
80+
const comment = [
81+
'To fix the **formatting** issues:\n',
82+
'1. Install necessary dependencises: `npm ci`',
83+
'2. Then, run this command:',
84+
'```shell',
85+
`npm run fmt:some -- ${filesJoined}`,
86+
'```',
87+
].join('\n');
88+
89+
// Set environment variable for subsequent steps
90+
core.exportVariable('COMMENT', comment);
91+
92+
// Rethrow the exit code of the failed formatting check
93+
core.setFailed('Some files are not properly formatted!');
94+
process.exit(1);
95+
}
96+
97+
- name: Hide prior PR comments and issue a new one in case of failure
98+
if: ${{ !cancelled() && github.event_name == 'pull_request' && github.event_name != 'pull_request_target' }}
6799
env:
68-
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
69-
if: failure()
70-
run: |
71-
# Preparations
72-
FILES="$(echo -e "${ALL_CHANGED_FILES[@]}" | tr '\n' ' ')"
73-
BODY="{\"body\":\"To fix the **formatting** issues:\n\n1. Install necessary dependencies: \`npm ci\`\n2. Then, run this command:\n\`\`\`shell\nnpx remark -o --silent --silently-ignore ${FILES}\n\`\`\`\"}"
74-
# Comment on the PR
75-
curl -s -o /dev/null -L -X POST \
76-
-H "Accept: application/vnd.github+json" \
77-
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
78-
-H "X-GitHub-Api-Version: 2022-11-28" \
79-
-d "$BODY" \
80-
https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.number }}/comments
81-
# Comment right in the actions output
82-
echo -e "\nInstall necessary dependencies: \033[31mnpm ci\033[0m"
83-
echo -e "Then, run this to fix formatting: \033[31mnpx remark -o --silent --silently-ignore ${FILES}\033[0m"
100+
COMMENT: ${{ env.COMMENT }}
101+
SUCCESS: ${{ steps.check-fmt.conclusion == 'failure' && 'false' || 'true' }}
102+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
103+
with:
104+
script: |
105+
const { hidePriorCommentsWithPrefix, createComment } = await import('${{ github.workspace }}/.github/scripts/common.mjs');
106+
const success = JSON.parse(process.env.SUCCESS ?? 'false');
107+
const rawCommentText = process.env.COMMENT ?? '';
108+
if (!success && rawCommentText === '') {
109+
console.log('There was a formatting error, but no comment was given, skipping...');
110+
process.exit(0);
111+
}
112+
const prefix = rawCommentText.slice(1, 30);
113+
await hidePriorCommentsWithPrefix({ github, context, exec, prefix, resolved: success });
114+
// Create a new comment in case of a new failure
115+
if (!success) {
116+
const body = rawCommentText.slice(1, -1).replace(/\\n/g, '\n');
117+
await createComment({ github, context, exec, body });
118+
}
84119
85120
spell-check:
86121
name: "Spelling"

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
"check:navigation": "node scripts/check-navigation.mjs",
1111
"check:fs": "echo 'https://github.com/ton-org/docs/issues/1182'",
1212
"check:fmt": "remark . -e mdx,md --no-stdout --quiet --frail",
13+
"check:fmt:some": "remark --no-stdout --quiet --frail --silently-ignore",
1314
"check:spell": "cspell --no-progress --show-suggestions .",
1415
"check:all": "npm run check:openapi && npm run check:links && npm run check:redirects && npm run check:fs && npm run check:fmt && npm run check:spell",
1516
"fmt": "remark . -e mdx,md -o --silent",
16-
"fmt:some": "remark -o --silent",
17+
"fmt:some": "remark -o --silent --silently-ignore",
1718
"spell": "cspell lint --no-progress --show-suggestions .",
1819
"spell:some": "cspell lint",
1920
"lint:all": "npm run check:all",

0 commit comments

Comments
 (0)