lint.sh 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #!/usr/bin/env bash
  2. # fail if any command fails
  3. set -eo pipefail -o nounset
  4. ROOT="$(dirname "$(dirname "$(realpath "$0")")")"
  5. DOCKERFILE="$ROOT/scripts/Dockerfile.lint"
  6. VALID_COMMANDS=("lint" "format")
  7. SELF_ARGS_WITHOUT_DOCKER=""
  8. GOIMPORTS_ARGS=""
  9. GOLANGCI_LINT_ARGS=""
  10. print_help() {
  11. cat <<-EOF >&2
  12. Usage: $(basename "$0") [-h] [-c] [-w] [-d] [-l] COMMAND
  13. COMMAND can be one of: "${VALID_COMMANDS[*]}"
  14. -h Print this help.
  15. -c Run in docker and don't worry about dependencies
  16. -w Automatically fix all formatting issues
  17. -d Print diff for all formatting issues
  18. -l List files that have formatting issues
  19. -g Format output to be parsed by github actions
  20. EOF
  21. }
  22. format(){
  23. if [ "$GOIMPORTS_ARGS" == "" ]; then
  24. GOIMPORTS_ARGS="-l"
  25. fi
  26. # only -l supports output as github action
  27. if [ "$GITHUB_ACTION" == "true" ]; then
  28. GOIMPORTS_ARGS="-l"
  29. fi
  30. # Check for dependencies
  31. if ! command -v goimports >/dev/null 2>&1; then
  32. printf "%s\n" "Require goimports. You can run this command in a docker container instead with '-c' and not worry about it or install it: \n\tgo install golang.org/x/tools/cmd/goimports@latest" >&2
  33. exit 1
  34. fi
  35. # Use -exec because of pitfall #1 in http://mywiki.wooledge.org/BashPitfalls
  36. GOFMT_OUTPUT="$(find "./sdk" "./node" "./wormchain" -type f -name '*.go' -not -path '*.pb.go' -print0 | xargs -r -0 goimports $GOIMPORTS_ARGS 2>&1)"
  37. if [ -n "$GOFMT_OUTPUT" ]; then
  38. if [ "$GITHUB_ACTION" == "true" ]; then
  39. GOFMT_OUTPUT="$(echo "$GOFMT_OUTPUT" | awk '{print "::error file="$0"::Formatting error. Please format using ./scripts/lint.sh -d format."}')"
  40. fi
  41. echo "$GOFMT_OUTPUT" >&2
  42. exit 1
  43. fi
  44. }
  45. lint(){
  46. # === Spell check
  47. if ! command -v cspell >/dev/null 2>&1; then
  48. printf "%s\n" "cspell is not installed. Skipping spellcheck"
  49. else
  50. cspell "*/**.*md"
  51. fi
  52. # === Go linting
  53. # Check for dependencies
  54. if ! command -v golangci-lint >/dev/null 2>&1; then
  55. printf "%s\n" "Require golangci-lint. You can run this command in a docker container instead with '-c' and not worry about it or install it: https://golangci-lint.run/usage/install/"
  56. fi
  57. # Do the actual linting!
  58. cd "$ROOT"/node
  59. golangci-lint run --timeout=10m $GOLANGCI_LINT_ARGS ./...
  60. cd "${ROOT}/sdk"
  61. golangci-lint run --timeout=10m $GOLANGCI_LINT_ARGS ./...
  62. }
  63. DOCKER="false"
  64. GITHUB_ACTION="false"
  65. while getopts 'cwdlgh' opt; do
  66. case "$opt" in
  67. c)
  68. DOCKER="true"
  69. ;;
  70. w)
  71. GOIMPORTS_ARGS+="-w "
  72. SELF_ARGS_WITHOUT_DOCKER+="-w "
  73. ;;
  74. d)
  75. GOIMPORTS_ARGS+="-d "
  76. SELF_ARGS_WITHOUT_DOCKER+="-d "
  77. ;;
  78. l)
  79. GOIMPORTS_ARGS+="-l "
  80. SELF_ARGS_WITHOUT_DOCKER+="-l "
  81. ;;
  82. g)
  83. GITHUB_ACTION="true"
  84. SELF_ARGS_WITHOUT_DOCKER+="-g "
  85. ;;
  86. h)
  87. print_help
  88. exit 0
  89. ;;
  90. ?)
  91. echo "Invalid command option." >&2
  92. print_help
  93. exit 1
  94. ;;
  95. esac
  96. done
  97. shift $((OPTIND - 1))
  98. if [ "$#" -ne "1" ]; then
  99. echo "Need to specify COMMAND." >&2
  100. print_help
  101. exit 1
  102. fi
  103. COMMAND="$1"
  104. if [[ ! " ${VALID_COMMANDS[*]} " == *" $COMMAND "* ]]; then
  105. echo "Invalid command $COMMAND." >&2
  106. print_help
  107. exit 1
  108. fi
  109. # run this script recursively inside docker, if requested
  110. if [ "$DOCKER" == "true" ]; then
  111. # The easy thing to do here would be to use a bind mount to share the code with the container.
  112. # But this doesn't work in scenarios where we are in a container already.
  113. # But it's easy so we just won't support that case for now.
  114. # If we wanted to support it, my idea would be to `docker run`, `docker cp`, `docker exec`, `docker rm`.
  115. if grep -Esq 'docker|lxc|kubepods' /proc/1/cgroup; then
  116. echo "Already running inside a container. This situation isn't supported (yet)." >&2
  117. exit 1
  118. fi
  119. DOCKER_IMAGE="$(docker build -q -f "$DOCKERFILE" .)"
  120. DOCKER_EXEC="./scripts/$(basename "$0")"
  121. MOUNT="--mount=type=bind,target=/app,source=$PWD"
  122. # for safety, mount as readonly unless -w flag was given
  123. if ! [[ "$GOIMPORTS_ARGS" =~ "w" ]]; then
  124. MOUNT+=",readonly"
  125. fi
  126. docker run --workdir /app "$MOUNT" "$DOCKER_IMAGE" "$DOCKER_EXEC" $SELF_ARGS_WITHOUT_DOCKER "$COMMAND"
  127. exit "$?"
  128. fi
  129. case $COMMAND in
  130. "lint")
  131. lint
  132. ;;
  133. "format")
  134. format
  135. ;;
  136. esac