diff --git a/.github/scripts/manage-pr-comments-after-check.mjs b/.github/scripts/manage-pr-comments-after-check.mjs new file mode 100644 index 000000000..2835191c0 --- /dev/null +++ b/.github/scripts/manage-pr-comments-after-check.mjs @@ -0,0 +1,58 @@ +export default async function({ github, context, exec }) { + const success = JSON.parse(process.env.SUCCESS ?? 'false'); + const rawCommentText = process.env.COMMENT ?? ''; + if (!success && rawCommentText === '') { + process.exit(0); + } + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + for (const comment of comments.data) { + const isHidden = (await github.graphql(` + query($nodeId: ID!) { + node(id: $nodeId) { + ... on IssueComment { + isMinimized + } + } + } + `, { nodeId: comment.node_id }))?.node?.isMinimized; + await exec.exec('sleep 0.5s'); + if (isHidden) { continue; } + const body = comment.body; + const prefix = rawCommentText.slice(1, 30); + if ( + comment.user.login === 'github-actions[bot]' && + body.startsWith(prefix) + ) { + console.log('Comment node_id:', comment.node_id); + console.log(await github.graphql(` + mutation($subjectId: ID!, $classifier: ReportedContentClassifiers!) { + minimizeComment(input: { + subjectId: $subjectId, + classifier: $classifier + }) { + minimizedComment { + isMinimized + minimizedReason + } + } + } + `, { + subjectId: comment.node_id, + classifier: success ? 'RESOLVED' : 'OUTDATED', + })); + await exec.exec('sleep 0.5s'); + } + } + if (!success) { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `${rawCommentText.slice(1, -1).replace(/\\n/g, '\n')}`, + }); + } +} diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index e8bd6929f..7e0f83149 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -10,13 +10,13 @@ on: workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.ref }}-linter cancel-in-progress: true permissions: contents: read pull-requests: write - issues: write + # issues: write jobs: format-check: @@ -52,6 +52,7 @@ jobs: env: ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} run: | + set -euo pipefail if [ -z $(echo -e "${ALL_CHANGED_FILES[@]}" | tr -d '[:space:]') ]; then echo -e '\nNo such files affected!' exit 0 @@ -60,27 +61,32 @@ jobs: for file in ${ALL_CHANGED_FILES}; do echo "- $file" done - echo - npx remark --no-stdout --quiet --frail --silently-ignore $(echo -e "${ALL_CHANGED_FILES[@]}" | tr '\n' ' ') - - - name: ${{ steps.check-fmt.conclusion == 'failure' && '👀 How to fix the formatting? See these suggestions!' || '...' }} - env: - ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} - if: failure() - run: | - # Preparations FILES="$(echo -e "${ALL_CHANGED_FILES[@]}" | tr '\n' ' ')" - 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\`\`\`\"}" - # Comment on the PR - curl -s -o /dev/null -L -X POST \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - -d "$BODY" \ - https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.number }}/comments - # Comment right in the actions output - echo -e "\nInstall necessary dependencies: \033[31mnpm ci\033[0m" - echo -e "Then, run this to fix formatting: \033[31mnpx remark -o --silent --silently-ignore ${FILES}\033[0m" + ( # try + npm run check:fmt:some -- $FILES >/dev/null 2>&1 + ) || ( # catch + ERR="$(echo $?)" + # Comment right in the actions output + echo -e "\n\033[31mError:\033[0m Some files are not properly formatted!" + echo -e "1. Install necessary dependencies: \033[31mnpm ci\033[0m" + echo -e "2. Run this command to fix the issues: \033[31mnpm run fmt:some -- ${FILES}\033[0m" + # Prepare a comment on the PR + COMMENT="To fix the **formatting** issues:\n\n1. Install necessary dependencies: \`npm ci\`\n2. Then, run this command:\n\`\`\`shell\nnpm run fmt:some -- ${FILES}\n\`\`\`" + echo "COMMENT='$COMMENT'" >> "$GITHUB_ENV" # notice the '' + # Rethrow the exit code of the failed formatting check + exit $ERR + ) + + - name: Hide prior PR comments and issue a new one in case of failure + if: ${{ !cancelled() && github.event_name == 'pull_request' && github.event_name != 'pull_request_target' }} + env: + COMMENT: ${{ env.COMMENT }} + SUCCESS: ${{ steps.check-fmt.conclusion == 'failure' && 'false' || 'true' }} + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 + with: + script: | + const { default: script } = await import('${{ github.workspace }}/.github/scripts/manage-pr-comments-after-check.mjs'); + await script({github, context, exec}); spell-check: name: "Spelling" diff --git a/package.json b/package.json index 9978092e0..d286589ea 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,11 @@ "check:navigation": "node scripts/check-navigation.mjs", "check:fs": "echo 'https://github.com/ton-org/docs/issues/1182'", "check:fmt": "remark . -e mdx,md --no-stdout --quiet --frail", + "check:fmt:some": "remark --no-stdout --quiet --frail --silently-ignore", "check:spell": "cspell --no-progress --show-suggestions .", "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", "fmt": "remark . -e mdx,md -o --silent", - "fmt:some": "remark -o --silent", + "fmt:some": "remark -o --silent --silently-ignore", "spell": "cspell lint --no-progress --show-suggestions .", "spell:some": "cspell lint", "lint:all": "npm run check:all",