mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
151 lines
5.0 KiB
Bash
151 lines
5.0 KiB
Bash
#!/usr/bin/env bash
|
|||
|
|
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
if ! [[ "$0" =~ scripts/lint.sh ]]; then
|
||
|
|
echo "must be run from repository root"
|
||
|
|
exit 255
|
||
|
|
fi
|
||
|
|
|
||
|
|
# The -P option is not supported by the grep version installed by
|
||
|
|
# default on macos. Since `-o errexit` is ignored in an if
|
||
|
|
# conditional, triggering the problem here ensures script failure when
|
||
|
|
# using an unsupported version of grep.
|
||
|
|
grep -P 'lint.sh' scripts/lint.sh &> /dev/null || (\
|
||
|
|
>&2 echo "error: This script requires a recent version of gnu grep.";\
|
||
|
|
>&2 echo " On macos, gnu grep can be installed with 'brew install grep'.";\
|
||
|
|
>&2 echo " It will also be necessary to ensure that gnu grep is available in the path.";\
|
||
|
|
exit 255 )
|
||
|
|
|
||
|
|
if [ "$#" -eq 0 ]; then
|
||
|
|
# by default, check all source code
|
||
|
|
# to test only "consensus" package
|
||
|
|
# ./scripts/lint.sh ./consensus/...
|
||
|
|
TARGET="./..."
|
||
|
|
else
|
||
|
|
TARGET="${1}"
|
||
|
|
fi
|
||
|
|
|
||
|
|
# by default, "./scripts/lint.sh" runs all lint tests
|
||
|
|
# to run only "license_header" test
|
||
|
|
# TESTS='license_header' ./scripts/lint.sh
|
||
|
|
# NOTE: Some checks disabled temporarily - need codebase cleanup:
|
||
|
|
# - license_header: mixed copyright formats
|
||
|
|
# - require_error_is_no_funcs_as_params: test files need refactoring
|
||
|
|
# - single_import: many files use parenthesized single imports
|
||
|
|
# - require_no_error_inline_func: test files need inline error handling
|
||
|
|
# - import_testing_only_in_tests: test helper files need moving to *test packages
|
||
|
|
TESTS=${TESTS:-"golangci_lint interface_compliance_nil"}
|
||
|
|
|
||
|
|
function test_golangci_lint {
|
||
|
|
go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run --config .golangci.yml
|
||
|
|
}
|
||
|
|
|
||
|
|
# automatically checks license headers
|
||
|
|
# to modify the file headers (if missing), remove "--verify" flag
|
||
|
|
# TESTS='license_header' ADDLICENSE_FLAGS="--debug" ./scripts/lint.sh
|
||
|
|
_addlicense_flags=${ADDLICENSE_FLAGS:-"--verify --debug"}
|
||
|
|
function test_license_header {
|
||
|
|
local files=()
|
||
|
|
while IFS= read -r line; do files+=("$line"); done < <(
|
||
|
|
find . -type f -name '*.go' \
|
||
|
|
! -name '*.pb.go' \
|
||
|
|
! -name '*.connect.go' \
|
||
|
|
! -name 'mock_*.go' \
|
||
|
|
! -name 'mocks_*.go' \
|
||
|
|
! -path './**/*mock/*.go' \
|
||
|
|
! -name '*.canoto.go' \
|
||
|
|
! -name '*.bindings.go'
|
||
|
|
)
|
||
|
|
|
||
|
|
# shellcheck disable=SC2086
|
||
|
|
go run github.com/palantir/go-license@v1.25.0 \
|
||
|
|
--config=./header.yml \
|
||
|
|
${_addlicense_flags} \
|
||
|
|
"${files[@]}"
|
||
|
|
}
|
||
|
|
|
||
|
|
function test_single_import {
|
||
|
|
if grep -R -zo -P 'import \(\n\t".*"\n\)' .; then
|
||
|
|
echo ""
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
function test_require_error_is_no_funcs_as_params {
|
||
|
|
if grep -R -zo -P 'require.ErrorIs\(.+?\)[^\n]*\)\n' .; then
|
||
|
|
echo ""
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
function test_require_no_error_inline_func {
|
||
|
|
if grep -R -zo -P '\t+err :?= ((?!require|if).|\n)*require\.NoError\((t, )?err\)' .; then
|
||
|
|
echo ""
|
||
|
|
echo "Checking that a function with a single error return doesn't error should be done in-line."
|
||
|
|
echo ""
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
# Ref: https://go.dev/doc/effective_go#blank_implements
|
||
|
|
function test_interface_compliance_nil {
|
||
|
|
if grep -R -o -P '_ .+? = &.+?\{\}' .; then
|
||
|
|
echo ""
|
||
|
|
echo "Interface compliance checks need to be of the form:"
|
||
|
|
echo " var _ json.Marshaler = (*RawMessage)(nil)"
|
||
|
|
echo ""
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
function test_import_testing_only_in_tests {
|
||
|
|
ROOT=$( git rev-parse --show-toplevel )
|
||
|
|
NON_TEST_GO_FILES=$( find "${ROOT}" -iname '*.go' ! -iname '*_test.go' ! -path "${ROOT}/tests/*" );
|
||
|
|
|
||
|
|
IMPORT_TESTING=$( echo "${NON_TEST_GO_FILES}" | xargs grep -lP '^\s*(import\s+)?"testing"');
|
||
|
|
IMPORT_TESTIFY=$( echo "${NON_TEST_GO_FILES}" | xargs grep -l '"github.com/stretchr/testify');
|
||
|
|
IMPORT_FROM_TESTS=$( echo "${NON_TEST_GO_FILES}" | xargs grep -l '"github.com/luxfi/node/tests/');
|
||
|
|
IMPORT_TEST_PKG=$( echo "${NON_TEST_GO_FILES}" | xargs grep -lP '"github.com/luxfi/node/.*?test"');
|
||
|
|
|
||
|
|
# TODO(arr4n): send a PR to add support for build tags in `mockgen` and then enable this.
|
||
|
|
# IMPORT_GOMOCK=$( echo "${NON_TEST_GO_FILES}" | xargs grep -l '"go.uber.org/mock');
|
||
|
|
HAVE_TEST_LOGIC=$( printf "%s\n%s\n%s\n%s" "${IMPORT_TESTING}" "${IMPORT_TESTIFY}" "${IMPORT_FROM_TESTS}" "${IMPORT_TEST_PKG}" );
|
||
|
|
|
||
|
|
IN_TEST_PKG=$( echo "${NON_TEST_GO_FILES}" | grep -P '.*test/[^/]+\.go$' ) # directory (hence package name) ends in "test"
|
||
|
|
|
||
|
|
# Files in /tests/ are already excluded by the `find ... ! -path`
|
||
|
|
INTENDED_FOR_TESTING="${IN_TEST_PKG}"
|
||
|
|
|
||
|
|
# -3 suppresses files that have test logic and have the "test" build tag
|
||
|
|
# -2 suppresses files that are tagged despite not having detectable test logic
|
||
|
|
UNTAGGED=$( comm -23 <( echo "${HAVE_TEST_LOGIC}" | sort -u ) <( echo "${INTENDED_FOR_TESTING}" | sort -u ) );
|
||
|
|
if [ -z "${UNTAGGED}" ];
|
||
|
|
then
|
||
|
|
return 0;
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo 'Non-test Go files importing test-only packages MUST (a) be in *test package; or (b) be in /tests/ directory:';
|
||
|
|
echo "${UNTAGGED}";
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
function run {
|
||
|
|
local test="${1}"
|
||
|
|
shift 1
|
||
|
|
echo "START: '${test}' at $(date)"
|
||
|
|
if "test_${test}" "$@" ; then
|
||
|
|
echo "SUCCESS: '${test}' completed at $(date)"
|
||
|
|
else
|
||
|
|
echo "FAIL: '${test}' failed at $(date)"
|
||
|
|
exit 255
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
echo "Running '$TESTS' at: $(date)"
|
||
|
|
for test in $TESTS; do
|
||
|
|
run "${test}" "${TARGET}"
|
||
|
|
done
|
||
|
|
|
||
|
|
echo "ALL SUCCESS!"
|