|
| 1 | +#!/bin/sh |
| 2 | + |
| 3 | +# Unified golangci-lint runner script |
| 4 | +# Usage: ./scripts/run-golangci-lint.sh <mode> |
| 5 | +# Modes: precommit, makefile |
| 6 | + |
| 7 | +# Uncomment this to see the commands being run |
| 8 | +# Note: We don't use 'set -e' because we need to handle golangci-lint's |
| 9 | +# exit codes manually to distinguish between linting issues and other errors |
| 10 | +# set -x |
| 11 | + |
| 12 | +# Exit code used by golangci-lint when linting issues are found |
| 13 | +# Allows us to distinguish between linting issues and other errors |
| 14 | +readonly ISSUES_EXIT_CODE=42 |
| 15 | + |
| 16 | +MODE="${1}" |
| 17 | + |
| 18 | +# Safely check whether Go is installed and set the GOPATH |
| 19 | +# Also check for GOBIN and add it to the PATH in case the binary was installed to a non-standard location |
| 20 | + if command -v go >/dev/null 2>&1; then |
| 21 | + GOBIN="$(go env GOBIN)" |
| 22 | + GOPATH_BIN="$(go env GOPATH)/bin" |
| 23 | + [ -n "${GOBIN}" ] && export PATH="${PATH}:${GOBIN}" |
| 24 | + export PATH="${PATH}:${GOPATH_BIN}" |
| 25 | + fi |
| 26 | + |
| 27 | +# Function to install golangci-lint (for makefile mode) |
| 28 | +install_golangci_lint() { |
| 29 | + echo "Installing the latest golangci-lint with local toolchain" |
| 30 | + if ! go install -a "github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest" |
| 31 | + then |
| 32 | + echo "⚠️ Failed to install golangci-lint" |
| 33 | + exit 0 |
| 34 | + fi |
| 35 | +} |
| 36 | + |
| 37 | +# Function to run golangci-lint in precommit mode |
| 38 | +run_precommit_lint() { |
| 39 | + echo "Running golangci-lint in precommit mode..." |
| 40 | + |
| 41 | + # Check if golangci-lint is available - exit gracefully if it isn't |
| 42 | + if ! command -v golangci-lint >/dev/null 2>&1 |
| 43 | + then |
| 44 | + echo "⚠️ golangci-lint not found – run 'make lint' to install it automatically" |
| 45 | + exit 0 |
| 46 | + fi |
| 47 | + |
| 48 | + # Collect staged Go files as positional args |
| 49 | + # cached: retrieve only staged files |
| 50 | + # name-only: retrieve only the names of the files |
| 51 | + # diff-filter=ACMR: retrieve only the files that have been added, copied, modified, or renamed |
| 52 | + # grep -E '\.go$': retrieve only the files that end with .go |
| 53 | + # || true: if there are no staged Go files, return a zero-status exit code |
| 54 | + set -- $(git diff --cached --name-only --diff-filter=ACMR | grep -E '\.go$' || true) |
| 55 | + # If there are no staged Go files, exit successfully |
| 56 | + if [ "$#" -eq 0 ]; then |
| 57 | + echo "✅ No staged Go files were found, exiting" |
| 58 | + exit 0 |
| 59 | + fi |
| 60 | + |
| 61 | + echo "Running golangci-lint on staged files..." |
| 62 | + BASE=$(git rev-parse --verify HEAD 2>/dev/null || echo "") |
| 63 | + |
| 64 | + if [ -z "${BASE}" ] |
| 65 | + then |
| 66 | + # Initial commit – lint only staged files |
| 67 | + golangci-lint run --issues-exit-code=${ISSUES_EXIT_CODE} --config .golangci.yml "${@}" |
| 68 | + else |
| 69 | + # Lint only staged changes vs HEAD |
| 70 | + golangci-lint run --issues-exit-code=${ISSUES_EXIT_CODE} --config .golangci.yml --new-from-rev="${BASE}" "${@}" |
| 71 | + fi |
| 72 | + |
| 73 | + # Store the exit code |
| 74 | + LINT_EXIT_CODE=${?} |
| 75 | + |
| 76 | + # Handle exit codes properly |
| 77 | + if [ ${LINT_EXIT_CODE} -eq ${ISSUES_EXIT_CODE} ] |
| 78 | + then |
| 79 | + echo "❌ golangci-lint found linting issues in staged files. Please fix them before committing." |
| 80 | + exit 1 |
| 81 | + elif [ ${LINT_EXIT_CODE} -ne 0 ] |
| 82 | + then |
| 83 | + echo "⚠️ golangci-lint encountered an error (exit code: ${LINT_EXIT_CODE})" |
| 84 | + exit 0 |
| 85 | + fi |
| 86 | + |
| 87 | + echo "✅ golangci-lint passed!" |
| 88 | +} |
| 89 | + |
| 90 | +# Function to run golangci-lint in makefile mode |
| 91 | +run_makefile_lint() { |
| 92 | + echo "Running golangci-lint in makefile mode..." |
| 93 | + |
| 94 | + # Install golangci-lint if needed |
| 95 | + install_golangci_lint |
| 96 | + |
| 97 | + echo "Running lint on all files" |
| 98 | + golangci-lint run --issues-exit-code=${ISSUES_EXIT_CODE} --config .golangci.yml |
| 99 | + |
| 100 | + # Store the exit code |
| 101 | + LINT_EXIT_CODE=${?} |
| 102 | + |
| 103 | + # Handle exit codes properly |
| 104 | + if [ ${LINT_EXIT_CODE} -eq ${ISSUES_EXIT_CODE} ] |
| 105 | + then |
| 106 | + echo "❌ golangci-lint found linting issues. Please fix them." |
| 107 | + exit 1 |
| 108 | + elif [ ${LINT_EXIT_CODE} -ne 0 ] |
| 109 | + then |
| 110 | + echo "⚠️ golangci-lint encountered an error (exit code: ${LINT_EXIT_CODE})" |
| 111 | + exit 0 |
| 112 | + fi |
| 113 | + |
| 114 | + echo "✅ golangci-lint passed!" |
| 115 | +} |
| 116 | + |
| 117 | +# Main logic |
| 118 | +case "${MODE}" in |
| 119 | + "precommit") |
| 120 | + run_precommit_lint |
| 121 | + ;; |
| 122 | + "makefile") |
| 123 | + run_makefile_lint |
| 124 | + ;; |
| 125 | + *) |
| 126 | + echo "Usage: ${0} <mode>" |
| 127 | + echo "Modes: precommit, makefile" |
| 128 | + exit 1 |
| 129 | + ;; |
| 130 | +esac |
0 commit comments