#!/usr/bin/env bash # Lint Dockerfiles with hadolint and shell scripts with shellcheck. # # Each file is streamed into the linter container on stdin instead of bind-mounting # the repository. That is deliberate: in Gitea Actions the job itself runs in a # container, and the checkout lives in a docker volume rather than on the host # filesystem. A sibling container started through the host's docker socket resolves # `-v "$PWD":/repo` against the HOST, where that path does not exist — Docker then # silently creates an empty directory and the linter reports every file as missing. # Piping needs no shared filesystem, so one command works locally and in CI. # # The linters therefore only ever see "-" as the filename, so the real path is # printed here. Note this also means shellcheck cannot follow `source` directives; # none of these scripts use them. # # Usage: lint.sh [dockerfiles|scripts|all] set -euo pipefail cd "$(dirname "$0")/.." HADOLINT_IMAGE=${HADOLINT_IMAGE:-hadolint/hadolint:latest-alpine} SHELLCHECK_IMAGE=${SHELLCHECK_IMAGE:-koalaman/shellcheck:stable} rc=0 report() { local file=$1 out=$2 ok=$3 if [ "$ok" = 0 ]; then printf ' ok %s\n' "$file" else printf ' FAIL %s\n' "$file" [ -n "$out" ] && printf '%s\n' "$out" | sed 's/^/ /' rc=1 fi } dockerfiles() { local file out ok for file in images/*/Dockerfile template/Dockerfile; do [ -f "$file" ] || continue ok=0 out=$(docker run --rm --interactive "$HADOLINT_IMAGE" \ hadolint --no-color - <"$file" 2>&1) || ok=$? report "$file" "$out" "$ok" done } scripts() { local file out ok for file in hack/*.sh images/*/test.sh template/test.sh; do [ -f "$file" ] || continue ok=0 out=$(docker run --rm --interactive "$SHELLCHECK_IMAGE" - <"$file" 2>&1) || ok=$? report "$file" "$out" "$ok" done } case "${1:-all}" in dockerfiles) dockerfiles ;; scripts) scripts ;; all) dockerfiles scripts ;; *) echo "usage: ${0##*/} [dockerfiles|scripts|all]" >&2 exit 2 ;; esac exit "$rc"