Skip to content
Merged
25 changes: 24 additions & 1 deletion tools/lint-go-gopls.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,34 @@ IGNORE_PATTERNS=(
"is deprecated" # TODO: fix these
)

# Install gopls if not already installed, then use the installed binary for
# faster execution. Using 'go run' each time adds overhead.
"$GO" install "$GOPLS_PACKAGE"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 go install failure is silently ignored when a stale gopls binary exists

The script uses set -uo pipefail but not set -e, so the go install command on line 12 can fail without causing the script to exit.

Click to expand

Problem

The subsequent check at line 22 ([[ ! -x "$GOPLS_BIN" ]]) only verifies that some gopls binary exists and is executable - it doesn't verify that the current go install command succeeded.

If:

  1. An older version of gopls was previously installed
  2. The current go install "$GOPLS_PACKAGE" fails (e.g., network error, Go module error)
  3. The script will silently continue using the stale/outdated gopls binary

Impact

This contradicts the PR's stated intent to "Verify gopls installation succeeded before proceeding". Users could unknowingly run linting with an outdated version of gopls that may have different behavior, miss certain issues, or report false positives.

Example scenario

# First run installs gopls v0.19.0
# Later, GOPLS_PACKAGE is updated to v0.20.0
# If go install fails, script silently uses v0.19.0

Recommendation: Check the exit code of go install explicitly, e.g.:

if ! "$GO" install "$GOPLS_PACKAGE"; then
  echo "Error: Failed to install gopls" >&2
  exit 1
fi

Or add set -e to the script options on line 2.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claude says on a clean lint this would then somehow fail with "set -euo pipefail", some kind of pitfall.
i say we let our experience with it speak rather than go into another rabbithole here, which is the intricacies of pipefail

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good - I'll leave the current implementation as-is. The explicit check for the binary existence ([[ ! -x "$GOPLS_BIN" ]]) should catch the most common failure cases, and we can iterate if real-world issues come up.

GOPLS_BIN=$("$GO" env GOPATH)/bin/gopls

# Verify gopls was installed successfully
if [[ ! -x "$GOPLS_BIN" ]]; then
echo "Error: Failed to install gopls" >&2
exit 1
fi

# Detect number of CPUs in a cross-platform way (Linux and macOS)
if command -v nproc &> /dev/null; then
NPROC=$(nproc)
elif command -v sysctl &> /dev/null; then
NPROC=$(sysctl -n hw.ncpu)
else
NPROC=1
fi

# lint all go files with 'gopls check' and look for lines starting with the
# current absolute path, indicating a error was found. This is necessary
# because the tool does not set non-zero exit code when errors are found.
# ref: https://github.com/golang/go/issues/67078
ERROR_LINES=$("$GO" run "$GOPLS_PACKAGE" check -severity=warning "$@" 2>/dev/null | grep -E "^$PWD" | grep -vFf <(printf '%s\n' "${IGNORE_PATTERNS[@]}"));
# Use xargs with parallel execution (-P) to speed up checking many files.
# Each batch of 100 files is processed in parallel across available cores.
# Use null-delimited format (-0) to handle filenames with spaces correctly.
ERROR_LINES=$(printf '%s\0' "$@" | xargs -0 -P "$NPROC" -n 100 "$GOPLS_BIN" check -severity=warning 2>/dev/null | grep -E "^$PWD" | grep -vFf <(printf '%s\n' "${IGNORE_PATTERNS[@]}"));
NUM_ERRORS=$(echo -n "$ERROR_LINES" | wc -l)

if [ "$NUM_ERRORS" -eq "0" ]; then
Expand Down