ci: add shellcheck linter (#37682)

- Adds `make lint-shell`. uses local `shellcheck` if its version
matches, otherwise runs the pinned image via docker or podman
- `.shellcheckrc` disables the most annoying rules
- Fixes findings across existing scripts

Fixes: #37648
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
This commit is contained in:
silverwind
2026-05-22 20:22:04 +00:00
committed by GitHub
co-authored by GitHub Claude TheFox0x7 Nicolas
parent f0eb065df7
commit 570173b409
12 changed files with 51 additions and 18 deletions
+7
View File
@@ -25,6 +25,8 @@ on:
value: ${{ jobs.detect.outputs.json }} value: ${{ jobs.detect.outputs.json }}
e2e: e2e:
value: ${{ jobs.detect.outputs.e2e }} value: ${{ jobs.detect.outputs.e2e }}
shell:
value: ${{ jobs.detect.outputs.shell }}
permissions: permissions:
contents: read contents: read
@@ -45,6 +47,7 @@ jobs:
yaml: ${{ steps.changes.outputs.yaml }} yaml: ${{ steps.changes.outputs.yaml }}
json: ${{ steps.changes.outputs.json }} json: ${{ steps.changes.outputs.json }}
e2e: ${{ steps.changes.outputs.e2e }} e2e: ${{ steps.changes.outputs.e2e }}
shell: ${{ steps.changes.outputs.shell }}
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
@@ -124,3 +127,7 @@ jobs:
- "tests/e2e/**" - "tests/e2e/**"
- "tools/test-e2e.sh" - "tools/test-e2e.sh"
- "playwright.config.ts" - "playwright.config.ts"
shell:
- "**/*.sh"
- ".shellcheckrc"
+3
View File
@@ -54,6 +54,9 @@ jobs:
- if: needs.files-changed.outputs.actions == 'true' - if: needs.files-changed.outputs.actions == 'true'
run: make lint-actions run: make lint-actions
- if: needs.files-changed.outputs.shell == 'true'
run: make lint-shell
checks-backend: checks-backend:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed needs: files-changed
+1
View File
@@ -0,0 +1 @@
disable=SC1091,SC2001,SC2002,SC2016,SC2028,SC2046,SC2124,SC2128,SC2129,SC2154,SC2155,SC2164,SC2181,SC2207
+10 -3
View File
@@ -20,6 +20,9 @@ SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.2 # renova
XGO_PACKAGE ?= src.techknowlogick.com/xgo@v1.9.0 # renovate: datasource=go XGO_PACKAGE ?= src.techknowlogick.com/xgo@v1.9.0 # renovate: datasource=go
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.3.0 # renovate: datasource=go GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.3.0 # renovate: datasource=go
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 # renovate: datasource=go ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 # renovate: datasource=go
SHELLCHECK_IMAGE ?= docker.io/koalaman/shellcheck:v0.11.0@sha256:61862eba1fcf09a484ebcc6feea46f1782532571a34ed51fedf90dd25f925a8d # renovate: datasource=docker
CONTAINER_RUNTIME ?= $(shell hash docker >/dev/null 2>&1 && echo docker || echo podman)
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes) HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
ifeq ($(HAS_GO), yes) ifeq ($(HAS_GO), yes)
@@ -271,7 +274,7 @@ checks-frontend: lockfile-check svg-check ## check frontend files
checks-backend: tidy-check swagger-check openapi3-check fmt-check swagger-validate security-check ## check backend files checks-backend: tidy-check swagger-check openapi3-check fmt-check swagger-validate security-check ## check backend files
.PHONY: lint .PHONY: lint
lint: lint-frontend lint-backend lint-templates lint-swagger lint-spell lint-md lint-actions lint-json lint-yaml ## lint everything lint: lint-frontend lint-backend lint-templates lint-swagger lint-spell lint-md lint-actions lint-json lint-yaml lint-shell ## lint everything
.PHONY: lint-fix .PHONY: lint-fix
lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix ## lint everything and fix issues lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix ## lint everything and fix issues
@@ -348,6 +351,10 @@ lint-actions: .venv ## lint action workflow files
@$(GO) run $(ACTIONLINT_PACKAGE) @$(GO) run $(ACTIONLINT_PACKAGE)
@uv run --frozen zizmor --quiet --min-confidence=medium .github @uv run --frozen zizmor --quiet --min-confidence=medium .github
.PHONY: lint-shell
lint-shell: ## lint shell scripts
@SHELLCHECK_IMAGE=$(SHELLCHECK_IMAGE) CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) ./tools/lint-shell.sh $$(git ls-files '*.sh')
.PHONY: lint-templates .PHONY: lint-templates
lint-templates: .venv node_modules ## lint template files lint-templates: .venv node_modules ## lint template files
@node tools/lint-templates-svg.ts @node tools/lint-templates-svg.ts
@@ -473,11 +480,11 @@ migrations.individual.test\#%:
.PHONY: playwright .PHONY: playwright
playwright: deps-frontend playwright: deps-frontend
@./tools/test-e2e.sh install @CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) ./tools/test-e2e.sh install
.PHONY: test-e2e .PHONY: test-e2e
test-e2e: playwright frontend backend test-e2e: playwright frontend backend
@EXECUTABLE=$(EXECUTABLE) ./tools/test-e2e.sh run $(GITEA_TEST_E2E_FLAGS) @CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) EXECUTABLE=$(EXECUTABLE) ./tools/test-e2e.sh run $(GITEA_TEST_E2E_FLAGS)
.PHONY: build .PHONY: build
build: frontend backend ## build everything build: frontend backend ## build everything
+1
View File
@@ -126,6 +126,7 @@ giteacmd manager flush-queues
echo "Stopping gitea at $(date)" echo "Stopping gitea at $(date)"
$service_stop $service_stop
echo "Creating backup in $giteahome" echo "Creating backup in $giteahome"
# shellcheck disable=SC2086 # flag string
giteacmd dump $backupopts giteacmd dump $backupopts
echo "Updating binary at $giteabin" echo "Updating binary at $giteabin"
cp -f "$giteabin" "$giteabin.bak" && mv -f "$binname" "$giteabin" cp -f "$giteabin" "$giteabin.bak" && mv -f "$binname" "$giteabin"
@@ -13,5 +13,5 @@ fi
if [ $# -gt 0 ]; then if [ $# -gt 0 ]; then
exec "$@" exec "$@"
else else
exec /usr/local/bin/gitea -c ${GITEA_APP_INI} web exec /usr/local/bin/gitea -c "${GITEA_APP_INI}" web
fi fi
+12 -12
View File
@@ -1,23 +1,23 @@
#!/bin/bash #!/bin/bash
# Prepare git folder # Prepare git folder
mkdir -p ${HOME} && chmod 0700 ${HOME} mkdir -p "${HOME}" && chmod 0700 "${HOME}"
if [ ! -w ${HOME} ]; then echo "${HOME} is not writable"; exit 1; fi if [ ! -w "${HOME}" ]; then echo "${HOME} is not writable"; exit 1; fi
# Prepare custom folder # Prepare custom folder
mkdir -p ${GITEA_CUSTOM} && chmod 0700 ${GITEA_CUSTOM} mkdir -p "${GITEA_CUSTOM}" && chmod 0700 "${GITEA_CUSTOM}"
# Prepare temp folder # Prepare temp folder
mkdir -p ${GITEA_TEMP} && chmod 0700 ${GITEA_TEMP} mkdir -p "${GITEA_TEMP}" && chmod 0700 "${GITEA_TEMP}"
if [ ! -w ${GITEA_TEMP} ]; then echo "${GITEA_TEMP} is not writable"; exit 1; fi if [ ! -w "${GITEA_TEMP}" ]; then echo "${GITEA_TEMP} is not writable"; exit 1; fi
#Prepare config file #Prepare config file
if [ ! -f ${GITEA_APP_INI} ]; then if [ ! -f "${GITEA_APP_INI}" ]; then
#Prepare config file folder #Prepare config file folder
GITEA_APP_INI_DIR=$(dirname ${GITEA_APP_INI}) GITEA_APP_INI_DIR=$(dirname "${GITEA_APP_INI}")
mkdir -p ${GITEA_APP_INI_DIR} && chmod 0700 ${GITEA_APP_INI_DIR} mkdir -p "${GITEA_APP_INI_DIR}" && chmod 0700 "${GITEA_APP_INI_DIR}"
if [ ! -w ${GITEA_APP_INI_DIR} ]; then echo "${GITEA_APP_INI_DIR} is not writable"; exit 1; fi if [ ! -w "${GITEA_APP_INI_DIR}" ]; then echo "${GITEA_APP_INI_DIR} is not writable"; exit 1; fi
# Set INSTALL_LOCK to true only if SECRET_KEY is not empty and # Set INSTALL_LOCK to true only if SECRET_KEY is not empty and
# INSTALL_LOCK is empty # INSTALL_LOCK is empty
@@ -34,7 +34,7 @@ if [ ! -f ${GITEA_APP_INI} ]; then
ROOT_URL=${ROOT_URL:-""} \ ROOT_URL=${ROOT_URL:-""} \
DISABLE_SSH=${DISABLE_SSH:-"false"} \ DISABLE_SSH=${DISABLE_SSH:-"false"} \
SSH_PORT=${SSH_PORT:-"2222"} \ SSH_PORT=${SSH_PORT:-"2222"} \
SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-$SSH_PORT} \ SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-} \
DB_TYPE=${DB_TYPE:-"sqlite3"} \ DB_TYPE=${DB_TYPE:-"sqlite3"} \
DB_HOST=${DB_HOST:-"localhost:3306"} \ DB_HOST=${DB_HOST:-"localhost:3306"} \
DB_NAME=${DB_NAME:-"gitea"} \ DB_NAME=${DB_NAME:-"gitea"} \
@@ -44,8 +44,8 @@ if [ ! -f ${GITEA_APP_INI} ]; then
DISABLE_REGISTRATION=${DISABLE_REGISTRATION:-"false"} \ DISABLE_REGISTRATION=${DISABLE_REGISTRATION:-"false"} \
REQUIRE_SIGNIN_VIEW=${REQUIRE_SIGNIN_VIEW:-"false"} \ REQUIRE_SIGNIN_VIEW=${REQUIRE_SIGNIN_VIEW:-"false"} \
SECRET_KEY=${SECRET_KEY:-""} \ SECRET_KEY=${SECRET_KEY:-""} \
envsubst < /etc/templates/app.ini > ${GITEA_APP_INI} envsubst < /etc/templates/app.ini > "${GITEA_APP_INI}"
fi fi
# Replace app.ini settings with env variables in the form GITEA__SECTION_NAME__KEY_NAME # Replace app.ini settings with env variables in the form GITEA__SECTION_NAME__KEY_NAME
environment-to-ini --config ${GITEA_APP_INI} environment-to-ini --config "${GITEA_APP_INI}"
+1
View File
@@ -18,6 +18,7 @@
"managerFilePatterns": ["/(^|/)Makefile$/"], "managerFilePatterns": ["/(^|/)Makefile$/"],
"matchStrings": [ "matchStrings": [
"[A-Z_]+_PACKAGE\\s*\\?=\\s*(?<depName>[^@\\s]+?)(?:/cmd/[^@/\\s]+)?@(?<currentValue>\\S+)\\s+# renovate: datasource=(?<datasource>\\S+)", "[A-Z_]+_PACKAGE\\s*\\?=\\s*(?<depName>[^@\\s]+?)(?:/cmd/[^@/\\s]+)?@(?<currentValue>\\S+)\\s+# renovate: datasource=(?<datasource>\\S+)",
"[A-Z_]+_IMAGE\\s*\\?=\\s*(?<depName>[^:\\s]+):(?<currentValue>[^@\\s]+)@(?<currentDigest>sha256:[a-f0-9]+)\\s+# renovate: datasource=(?<datasource>\\S+)",
], ],
}, },
], ],
+1 -1
View File
@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
set -e set -e
if [ ! -f go.mod -o ! -d snap ]; then if [ ! -f go.mod ] || [ ! -d snap ]; then
echo "This script should be run from the root of the gitea repository" echo "This script should be run from the root of the gitea repository"
exit 1 exit 1
fi fi
+1 -1
View File
@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
set -e set -e
if [ ! -f go.mod -o ! -d snap ]; then if [ ! -f go.mod ] || [ ! -d snap ]; then
echo "This script should be run from the root of the gitea repository" echo "This script should be run from the root of the gitea repository"
exit 1 exit 1
fi fi
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -euo pipefail
CONTAINER_RUNTIME="${CONTAINER_RUNTIME:-docker}"
VERSION=$(echo "$SHELLCHECK_IMAGE" | sed -E 's/.*:v([0-9.]+)@.*/\1/')
if hash shellcheck 2>/dev/null && shellcheck --version | grep -qx "version: $VERSION"; then
exec shellcheck --color=always "$@"
else
exec "$CONTAINER_RUNTIME" run --rm -v "$PWD":/mnt -w /mnt "$SHELLCHECK_IMAGE" --color=always "$@"
fi
+2
View File
@@ -71,8 +71,10 @@ if [ "$CMD" = "install" ]; then
if [ "$PLAYWRIGHT_MODE" = "local" ]; then if [ "$PLAYWRIGHT_MODE" = "local" ]; then
# on GitHub Actions VMs, playwright's system deps are pre-installed # on GitHub Actions VMs, playwright's system deps are pre-installed
if [ -z "${GITHUB_ACTIONS:-}" ]; then if [ -z "${GITHUB_ACTIONS:-}" ]; then
# shellcheck disable=SC2086 # flag string
pnpm exec playwright install --with-deps chromium firefox ${PLAYWRIGHT_FLAGS:-} pnpm exec playwright install --with-deps chromium firefox ${PLAYWRIGHT_FLAGS:-}
else else
# shellcheck disable=SC2086 # flag string
pnpm exec playwright install chromium firefox ${PLAYWRIGHT_FLAGS:-} pnpm exec playwright install chromium firefox ${PLAYWRIGHT_FLAGS:-}
fi fi
else else