name: Validate script formatting on: push: branches: - main pull_request_target: paths: - "**/*.sh" - "**/*.func" jobs: shfmt: name: Check changed files runs-on: ubuntu-latest permissions: pull-requests: write steps: - name: Get pull request information if: github.event_name == 'pull_request_target' uses: actions/github-script@v7 id: pr with: script: | const { data: pullRequest } = await github.rest.pulls.get({ ...context.repo, pull_number: context.payload.pull_request.number, }); return pullRequest; - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # Ensure the full history is fetched for accurate diffing ref: ${{ github.event_name == 'pull_request_target' && fromJSON(steps.pr.outputs.result).merge_commit_sha || '' }} - name: Get changed files id: changed-files run: | if ${{ github.event_name == 'pull_request_target' }}; then echo "files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ steps.pr.outputs.result && fromJSON(steps.pr.outputs.result).merge_commit_sha }} | grep -E '\.(sh|func)$' | xargs)" >> $GITHUB_OUTPUT else echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | grep -E '\.(sh|func)$' | xargs)" >> $GITHUB_OUTPUT fi - name: Set up Go if: steps.changed-files.outputs.files != '' uses: actions/setup-go@v5 - name: Install shfmt if: steps.changed-files.outputs.files != '' run: | go install mvdan.cc/sh/v3/cmd/shfmt@latest echo "$GOPATH/bin" >> $GITHUB_PATH - name: Run shfmt if: steps.changed-files.outputs.files != '' id: shfmt run: | set +e shfmt_output=$(shfmt -d ${{ steps.changed-files.outputs.files }}) if [[ $? -eq 0 ]]; then exit 0 else echo "diff=\"$(echo -n "$shfmt_output" | base64 -w 0)\"" >> $GITHUB_OUTPUT printf "%s" "$shfmt_output" exit 1 fi - name: Post comment with results if: always() && steps.changed-files.outputs.files != '' && github.event_name == 'pull_request_target' uses: actions/github-script@v7 with: script: | const result = "${{ job.status }}" === "success" ? "success" : "failure"; const diff = Buffer.from( ${{ steps.shfmt.outputs.diff }}, "base64", ).toString(); const issueNumber = context.payload.pull_request ? context.payload.pull_request.number : null; const commentIdentifier = "validate-formatting"; let newCommentBody = `\n### Script formatting\n\n`; if (result === "failure") { newCommentBody += `:x: We found issues in the formatting of the following changed files:\n\n\`\`\`diff\n${diff}\n\`\`\`\n`; } else { newCommentBody += `:rocket: All changed shell scripts are formatted correctly!\n`; } newCommentBody += `\n\n`; if (issueNumber) { const { data: comments } = await github.rest.issues.listComments({ ...context.repo, issue_number: issueNumber, }); const existingComment = comments.find( (comment) => comment.user.login === "github-actions[bot]", ); if (existingComment) { if (existingComment.body.includes(commentIdentifier)) { const re = new RegExp( String.raw`[\s\S]*?`, "", ); newCommentBody = existingComment.body.replace(re, newCommentBody); } else { newCommentBody = existingComment.body + "\n\n---\n\n" + newCommentBody; } await github.rest.issues.updateComment({ ...context.repo, comment_id: existingComment.id, body: newCommentBody, }); } else { await github.rest.issues.createComment({ ...context.repo, issue_number: issueNumber, body: newCommentBody, }); } }