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,43 @@ jobs:
286314
287315 exit ${error}
288316
317+ - name : eol-lint
318+ if : always()
319+ shell : bash
320+ run : |
321+ error=0
322+ for file in ${{ steps.changed_files.outputs.CHANGED_FILES }}; do
323+
324+ # Skip empty files
325+ if [[ ! -s "$file" ]]; then
326+ continue
327+ fi
328+
329+ # Check if file ends with newline using tail -c 1
330+ if [[ -n "$(tail -c 1 "$file")" ]]; then
331+ error=1
332+ title="EOL linting error"
333+ message="File '$file' does not end with a newline character."
334+ line=$(($(wc -l < "$file") + 1))
335+
336+ echo "::error file=$file,line=$line,title=$title::$message"
337+ fi
338+ done
339+
340+ exit ${error}
341+
342+ - name : check-trailing-spaces
343+ if : always()
344+ uses : marcopaganini/check-trailing-spaces@v2.0.0
345+
346+ - name : linelint
347+ if : always()
348+ shell : bash
349+ run : |
350+ echo "::add-matcher::.github/matchers/linelint.json"
351+ linelint ${{ steps.changed_files.outputs.CHANGED_FILES }}
352+ echo "::remove-matcher owner=linelint::"
353+
289354 - name : PowerShell - PSScriptAnalyzer
290355 if : always()
291356 shell : pwsh
@@ -339,6 +404,7 @@ jobs:
339404
340405 - name : Python - flake8
341406 if : always()
407+ shell : bash
342408 run : |
343409 echo "::group::problem matcher"
344410 set +e
@@ -359,6 +425,7 @@ jobs:
359425
360426 - name : Python - nbqa flake8
361427 if : always()
428+ shell : bash
362429 run : |
363430 echo "::group::problem matcher"
364431 set +e
@@ -381,6 +448,7 @@ jobs:
381448
382449 - name : Python - nb-clean
383450 if : always()
451+ shell : bash
384452 run : |
385453 output=$(find . -name '*.ipynb' -exec nb-clean check {} \;)
386454
@@ -393,6 +461,7 @@ jobs:
393461 - name : Rust - find Cargo.toml
394462 id : run_cargo
395463 if : always()
464+ shell : bash
396465 run : |
397466 # check if Cargo.toml exists
398467 if [ -f "Cargo.toml" ]; then
@@ -412,6 +481,7 @@ jobs:
412481
413482 - name : Rust - cargo fmt
414483 if : always() && steps.run_cargo.outputs.found_cargo == 'true'
484+ shell : bash
415485 run : |
416486 set +e
417487 error=0
@@ -449,6 +519,7 @@ jobs:
449519 - name : shellcheck - find files
450520 id : shellcheck_files
451521 if : always()
522+ shell : bash
452523 run : |
453524 found_files=$(find . -type f -iname "*.bash" -o -iname "*.sh")
454525
@@ -459,6 +530,7 @@ jobs:
459530
460531 - name : shellcheck
461532 if : always() && steps.shellcheck_files.outputs.found_files
533+ shell : bash
462534 run : |
463535 echo "::add-matcher::.github/matchers/shellcheck-gcc.json"
464536 set +e
@@ -472,6 +544,7 @@ jobs:
472544 - name : YAML - find files
473545 id : yaml_files
474546 if : always()
547+ shell : bash
475548 run : |
476549 # space separated list of files
477550 FILES=.clang-format
@@ -491,6 +564,7 @@ jobs:
491564 - name : YAML - yamllint
492565 id : yamllint
493566 if : always()
567+ shell : bash
494568 run : |
495569 if [ ! -f .yamllint.yml ]; then
496570 curl -sSL https://raw.githubusercontent.com/LizardByte/.github/master/.yamllint.yml -o .yamllint.yml
0 commit comments