2525 steps :
2626 - name : Checkout
2727 uses : actions/checkout@v5
28+ with :
29+ fetch-depth : 2 # need to fetch 2 to get list of changed files
30+
31+ - name : Get changed files
32+ id : changed_files
33+ shell : bash
34+ run : |
35+ firstCommit='${{ github.event.pull_request.base.sha }}'
36+ lastCommit='${{ github.event.pull_request.head.sha }}'
37+ changedFiles=$(git diff --name-only --diff-filter=d "${firstCommit}" "${lastCommit}" | tr '\n' ' ')
38+
39+ echo "Changed files: ${changedFiles}"
40+ echo "CHANGED_FILES=${changedFiles}" >> "${GITHUB_OUTPUT}"
2841
2942 - name : Download problem matchers
3043 shell : bash
4861 [cmake-lint]="${gh_path}/cmake-lint.json"
4962 [gcc]="${gh_path}/gcc.json"
5063 [hadolint]="${gh_path}/hadolint.json"
64+ [linelint]="${gh_path}/linelint.json"
5165 [shellcheck-gcc]="${gh_path}/shellcheck-gcc.json"
5266 [yamllint]="${gh_path}/yamllint.json"
5367 )
7387 python-version : ' 3.12'
7488
7589 - name : Install Python dependencies
90+ shell : bash
7691 run : |
7792 # shellcheck disable=SC2102 # this is triggered by the [toolchain] extra
7893 python -m pip install --upgrade \
@@ -101,7 +116,14 @@ jobs:
101116 "https://raw.githubusercontent.com/LizardByte/.github/master/.github/actionlint.yml"
102117 fi
103118
119+ - name : Install linelint
120+ shell : bash
121+ run : |
122+ go install github.com/fernandrone/linelint@latest
123+ echo "${HOME}/go/bin" >> "${GITHUB_PATH}"
124+
104125 - name : Replace shell
126+ # for actionlint
105127 shell : bash
106128 run : |
107129 # Replace in workflow files
@@ -130,6 +152,7 @@ jobs:
130152 - name : C++ - find files
131153 id : cpp_files
132154 if : always()
155+ shell : bash
133156 run : |
134157 # find files
135158 found_files=$(find . -type f \
@@ -176,6 +199,7 @@ jobs:
176199
177200 - name : C++ - Clang format (simple)
178201 if : always() && steps.clang_format_diff.outcome == 'failure'
202+ shell : bash
179203 run : |
180204 echo "::add-matcher::.github/matchers/clang-format.json"
181205 set +e
@@ -193,6 +217,7 @@ jobs:
193217 - name : CMake - find files
194218 id : cmake_files
195219 if : always()
220+ shell : bash
196221 run : |
197222 # find files
198223 found_files=$(find . -type f -iname "CMakeLists.txt" -o -iname "*.cmake")
@@ -221,6 +246,7 @@ jobs:
221246
222247 - name : CMake - cmake-lint
223248 if : always() && steps.cmake_files.outputs.found_files
249+ shell : bash
224250 run : |
225251 echo "::add-matcher::.github/matchers/cmake-lint.json"
226252 set +e
@@ -234,6 +260,7 @@ jobs:
234260 - name : Docker - find files
235261 id : docker_files
236262 if : always()
263+ shell : bash
237264 run : |
238265 found_files=$(find . -type f -iname "Dockerfile" -o -iname "*.dockerfile")
239266
@@ -244,6 +271,7 @@ jobs:
244271
245272 - name : Docker - hadolint
246273 if : always() && steps.docker_files.outputs.found_files
274+ shell : bash
247275 run : |
248276 docker pull hadolint/hadolint
249277
@@ -286,6 +314,42 @@ jobs:
286314
287315 exit ${error}
288316
317+ - name : eol-lint
318+ if : always()
319+ shell : bash
320+ run : |
321+ # Only print one error per file, with correct line number
322+ error=0
323+ for file in ${{ steps.changed_files.outputs.CHANGED_FILES }}; do
324+ # Get last two lines
325+ last_two=$(tail -n 2 "$file")
326+ last_line=$(echo "$last_two" | tail -n 1)
327+ second_last_line=$(echo "$last_two" | head -n 1)
328+
329+ # Check for exactly one blank line at end
330+ if [[ "$last_line" != "" || "$second_last_line" == "" ]]; then
331+ error=1
332+ error_title="EOL linting error"
333+ error_message="File '$file' does not end with a single empty blank line."
334+ error_line_number=$(wc -l < "$file")
335+ echo "::error file=$file,line=$error_line_number,title=$error_title::$error_message"
336+ fi
337+ done
338+
339+ exit ${error}
340+
341+ - name : check-trailing-spaces
342+ if : always()
343+ uses : marcopaganini/check-trailing-spaces@v2.0.0
344+
345+ - name : linelint
346+ if : always()
347+ shell : bash
348+ run : |
349+ echo "::add-matcher::.github/matchers/linelint.json"
350+ linelint ${{ steps.changed_files.outputs.CHANGED_FILES }}
351+ echo "::remove-matcher owner=linelint::"
352+
289353 - name : PowerShell - PSScriptAnalyzer
290354 if : always()
291355 shell : pwsh
@@ -339,6 +403,7 @@ jobs:
339403
340404 - name : Python - flake8
341405 if : always()
406+ shell : bash
342407 run : |
343408 echo "::group::problem matcher"
344409 set +e
@@ -359,6 +424,7 @@ jobs:
359424
360425 - name : Python - nbqa flake8
361426 if : always()
427+ shell : bash
362428 run : |
363429 echo "::group::problem matcher"
364430 set +e
@@ -381,6 +447,7 @@ jobs:
381447
382448 - name : Python - nb-clean
383449 if : always()
450+ shell : bash
384451 run : |
385452 output=$(find . -name '*.ipynb' -exec nb-clean check {} \;)
386453
@@ -393,6 +460,7 @@ jobs:
393460 - name : Rust - find Cargo.toml
394461 id : run_cargo
395462 if : always()
463+ shell : bash
396464 run : |
397465 # check if Cargo.toml exists
398466 if [ -f "Cargo.toml" ]; then
@@ -412,6 +480,7 @@ jobs:
412480
413481 - name : Rust - cargo fmt
414482 if : always() && steps.run_cargo.outputs.found_cargo == 'true'
483+ shell : bash
415484 run : |
416485 set +e
417486 error=0
@@ -449,6 +518,7 @@ jobs:
449518 - name : shellcheck - find files
450519 id : shellcheck_files
451520 if : always()
521+ shell : bash
452522 run : |
453523 found_files=$(find . -type f -iname "*.bash" -o -iname "*.sh")
454524
@@ -459,6 +529,7 @@ jobs:
459529
460530 - name : shellcheck
461531 if : always() && steps.shellcheck_files.outputs.found_files
532+ shell : bash
462533 run : |
463534 echo "::add-matcher::.github/matchers/shellcheck-gcc.json"
464535 set +e
@@ -472,6 +543,7 @@ jobs:
472543 - name : YAML - find files
473544 id : yaml_files
474545 if : always()
546+ shell : bash
475547 run : |
476548 # space separated list of files
477549 FILES=.clang-format
@@ -491,6 +563,7 @@ jobs:
491563 - name : YAML - yamllint
492564 id : yamllint
493565 if : always()
566+ shell : bash
494567 run : |
495568 if [ ! -f .yamllint.yml ]; then
496569 curl -sSL https://raw.githubusercontent.com/LizardByte/.github/master/.yamllint.yml -o .yamllint.yml
0 commit comments