Skip to content

Commit 073efe9

Browse files
committed
ci: ShellCheck PR comments & auto-fix suggestions workflow
Adds a separate maintenance workflow that surfaces ShellCheck output inside pull requests: * Findings job: ShellCheck via the framework's compile.sh entry-point (--check-sourced --external-sources) in gcc format, piped to reviewdog with reporter=github-pr-review. Non-autofixable warnings appear as inline review comments; cross-file SC2154 resolves correctly because the entry-point pulls in the full source closure. * Suggestions job: shellcheck -f diff over the tree (enumerated by shfmt -f .) applied to the working tree, then reviewdog/action- suggester turns the resulting hunks into GitHub suggestion blocks the reviewer can apply with one click. Both jobs reuse lib/tools/shellcheck.sh for platform-aware binary download via SHELLCHECK_INSTALL_ONLY=1, so the workflow does not hardcode linux/x86_64 release filenames and survives the runner moving to darwin/aarch64. The existing maintenance-lint-scripts.yml is left untouched — it keeps the Checks-style pass/fail gate; this workflow is purely a PR-comment companion to it. Assisted-by: Claude:claude-opus-4.7 Signed-off-by: Igor Velkov <325961+iav@users.noreply.github.com>
1 parent c7c122e commit 073efe9

2 files changed

Lines changed: 356 additions & 19 deletions

File tree

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
name: "Maintenance: Lint scripts (post)"
2+
#
3+
# Second phase of the two-phase lint pipeline. Triggered by the
4+
# completion of maintenance-lint-scripts.yml ("Maintenance: Lint
5+
# scripts"), runs in the BASE repository's context with a full write
6+
# token — so review comments and suggestion blocks can be posted to
7+
# pull requests originating from forks too.
8+
#
9+
# Security boundary: this workflow never checks out PR code. It only
10+
# downloads the lint job's artifacts (text findings + unified diffs +
11+
# PR metadata) and feeds them to reviewdog. CodeQL's
12+
# actions/untrusted-checkout rule stays quiet because no
13+
# `actions/checkout` runs with `ref: ${{ github.event.pull_request.head.sha }}`
14+
# (or equivalent untrusted ref).
15+
#
16+
# Note: GitHub always runs `workflow_run` workflows from the default
17+
# branch's copy of this file, so changes to the post pipeline take
18+
# effect only after merging into the default branch.
19+
#
20+
# Runs on every fork of armbian/build by default. If a fork doesn't
21+
# want PR comments — disable Settings → Actions → Workflows →
22+
# "Maintenance: Lint scripts (post)". Disabling only the post leaves
23+
# the red-cross Check still working (Maintenance: Lint scripts itself);
24+
# disabling both leaves the fork lint-free.
25+
26+
on:
27+
workflow_run:
28+
workflows: ["Maintenance: Lint scripts"]
29+
types: [completed]
30+
31+
permissions:
32+
contents: read
33+
actions: read # required by actions/download-artifact@v4 when downloading from another workflow run via `run-id`
34+
pull-requests: write
35+
checks: write
36+
issues: write # documented requirement of reviewdog for PR-comment APIs
37+
38+
jobs:
39+
Post:
40+
name: Post ShellCheck and shfmt diagnostics
41+
runs-on: ubuntu-latest
42+
# Run even on red-cross lint conclusions (`failure`) — the
43+
# artifact is uploaded via `if: always()` in the lint workflow,
44+
# and we want to surface diagnostics in the PR even when the
45+
# gate failed. Skip the conclusions where no artifact is
46+
# produced (cancelled / timed_out / skipped / action_required).
47+
if: >-
48+
${{ github.event.workflow_run.conclusion != 'cancelled'
49+
&& github.event.workflow_run.conclusion != 'timed_out'
50+
&& github.event.workflow_run.conclusion != 'skipped'
51+
&& github.event.workflow_run.conclusion != 'action_required' }}
52+
steps:
53+
- name: Checkout BASE for reviewdog's local git context
54+
# reviewdog requires a `.git` to be present even when its
55+
# reporter (`github-pr-review`) computes the PR diff via API.
56+
# Checking out BASE (the workflow's default branch — our own
57+
# trusted code) gives it what it needs without ever pulling PR
58+
# code into the privileged context; CodeQL's untrusted-checkout
59+
# rule stays quiet because there is no `ref: ...head.sha`.
60+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
61+
with:
62+
fetch-depth: 1
63+
persist-credentials: false # defense-in-depth: post-step uses REVIEWDOG_GITHUB_API_TOKEN, not the on-disk extraheader
64+
65+
- name: Surface workflow purpose + disable instructions in the Check summary
66+
run: |
67+
cat >>"$GITHUB_STEP_SUMMARY" <<'EOF'
68+
## What this Check does
69+
70+
`Maintenance: Lint scripts (post)` is the second phase of the lint pipeline. It downloads diagnostic artifacts produced by `Maintenance: Lint scripts` and posts them as inline review comments and auto-fix `suggestion` blocks on the PR via [reviewdog](https://github.com/reviewdog/reviewdog).
71+
72+
### Don't want PR comments?
73+
74+
This workflow runs on every fork of `armbian/build` by default. To stop the PR-comment spam:
75+
76+
* **Just the comments** — Settings → Actions → Workflows → "Maintenance: Lint scripts (post)" → "Disable workflow". The lint Check itself (red cross / green check) keeps working.
77+
* **Disable both phases** — disable `Maintenance: Lint scripts` instead; the post phase becomes a no-op automatically because there are no artifacts.
78+
79+
EOF
80+
81+
- name: Download lint artifacts (no checkout of PR code)
82+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
83+
with:
84+
name: lint-scripts-results
85+
run-id: ${{ github.event.workflow_run.id }}
86+
github-token: ${{ secrets.GITHUB_TOKEN }}
87+
88+
- name: Synthesize pull_request event JSON for reviewdog
89+
run: |
90+
# reviewdog in a workflow_run context cannot find PR info on
91+
# its own — GITHUB_EVENT_NAME is `workflow_run` and
92+
# GITHUB_EVENT_PATH points to a workflow_run payload, not a
93+
# pull_request event. CI_* fallback env vars are bypassed when
94+
# GitHub Actions context is detected. Workaround: synthesize a
95+
# minimal pull_request event JSON, then override
96+
# GITHUB_EVENT_NAME and GITHUB_EVENT_PATH at the step level
97+
# for each subsequent reviewdog invocation.
98+
PR_NUMBER=$(cat pr-number.txt)
99+
HEAD_SHA=$(cat head-sha.txt)
100+
BASE_SHA=$(cat base-sha.txt)
101+
BASE_REF=$(cat base-ref.txt)
102+
BASE_REPO=$(cat base-repo.txt)
103+
OWNER="${BASE_REPO%/*}"
104+
NAME="${BASE_REPO##*/}"
105+
jq -n \
106+
--argjson number "$PR_NUMBER" \
107+
--arg head_sha "$HEAD_SHA" \
108+
--arg base_sha "$BASE_SHA" \
109+
--arg base_ref "$BASE_REF" \
110+
--arg owner "$OWNER" \
111+
--arg name "$NAME" \
112+
--arg full "$BASE_REPO" \
113+
'{
114+
"action": "synchronize",
115+
"number": $number,
116+
"repository": {
117+
"name": $name,
118+
"full_name": $full,
119+
"owner": { "login": $owner }
120+
},
121+
"pull_request": {
122+
"number": $number,
123+
"head": {
124+
"sha": $head_sha,
125+
"ref": "pr-head",
126+
"repo": { "full_name": $full, "name": $name, "owner": { "login": $owner } }
127+
},
128+
"base": {
129+
"sha": $base_sha,
130+
"ref": $base_ref,
131+
"repo": { "full_name": $full, "name": $name, "owner": { "login": $owner } }
132+
}
133+
}
134+
}' > /tmp/pr-event.json
135+
cat /tmp/pr-event.json
136+
echo "FAKE_PR_EVENT_PATH=/tmp/pr-event.json" >> "$GITHUB_ENV"
137+
138+
- uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.4.0
139+
with:
140+
reviewdog_version: latest
141+
142+
# GitHub Actions strips `GITHUB_*` overrides from step-level
143+
# `env:` blocks (documented), so we apply the overrides inline as
144+
# bash command-environment variables — GitHub can't touch those.
145+
- name: Post ShellCheck findings as inline review comments
146+
env:
147+
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
148+
run: |
149+
# reviewdog has no built-in `gcc` parser; supply vim
150+
# errorformat (-efm) patterns matching
151+
# `file:line:col: severity: message`. Three patterns cover
152+
# error / warning / note outputs.
153+
cat shellcheck-findings.txt | env \
154+
GITHUB_EVENT_NAME=pull_request \
155+
GITHUB_EVENT_PATH="$FAKE_PR_EVENT_PATH" \
156+
reviewdog \
157+
-name=shellcheck-findings \
158+
-efm='%f:%l:%c: %trror: %m' \
159+
-efm='%f:%l:%c: %tarning: %m' \
160+
-efm='%f:%l:%c: %tote: %m' \
161+
-reporter=github-pr-review \
162+
-filter-mode=added \
163+
-fail-level=none
164+
165+
- name: Post ShellCheck auto-fix as suggestion blocks
166+
env:
167+
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
168+
run: |
169+
# `-f=diff` parses unified-diff input and emits `suggestion`
170+
# blocks for each hunk on PR-added lines (filter_mode=added).
171+
# Replaces reviewdog/action-suggester (which needs a checked-
172+
# out worktree to compute the diff itself).
173+
cat shellcheck-fix.diff | env \
174+
GITHUB_EVENT_NAME=pull_request \
175+
GITHUB_EVENT_PATH="$FAKE_PR_EVENT_PATH" \
176+
reviewdog \
177+
-name=shellcheck-fix \
178+
-f=diff \
179+
-filter-mode=added \
180+
-reporter=github-pr-review \
181+
-fail-level=none
182+
183+
- name: Post shfmt drift as suggestion blocks
184+
env:
185+
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
186+
run: |
187+
cat shfmt.diff | env \
188+
GITHUB_EVENT_NAME=pull_request \
189+
GITHUB_EVENT_PATH="$FAKE_PR_EVENT_PATH" \
190+
reviewdog \
191+
-name=shfmt \
192+
-f=diff \
193+
-filter-mode=added \
194+
-reporter=github-pr-review \
195+
-fail-level=none

0 commit comments

Comments
 (0)