vet.sh 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #!/bin/bash
  2. set -ex # Exit on error; debugging enabled.
  3. set -o pipefail # Fail a pipe if any sub-command fails.
  4. # not makes sure the command passed to it does not exit with a return code of 0.
  5. not() {
  6. # This is required instead of the earlier (! $COMMAND) because subshells and
  7. # pipefail don't work the same on Darwin as in Linux.
  8. ! "$@"
  9. }
  10. die() {
  11. echo "$@" >&2
  12. exit 1
  13. }
  14. fail_on_output() {
  15. tee /dev/stderr | not read
  16. }
  17. # Check to make sure it's safe to modify the user's git repo.
  18. git status --porcelain | fail_on_output
  19. # Undo any edits made by this script.
  20. cleanup() {
  21. git reset --hard HEAD
  22. }
  23. trap cleanup EXIT
  24. PATH="${HOME}/go/bin:${GOROOT}/bin:${PATH}"
  25. go version
  26. if [[ "$1" = "-install" ]]; then
  27. # Install the pinned versions as defined in module tools.
  28. pushd ./test/tools
  29. go install \
  30. golang.org/x/lint/golint \
  31. golang.org/x/tools/cmd/goimports \
  32. honnef.co/go/tools/cmd/staticcheck \
  33. github.com/client9/misspell/cmd/misspell
  34. popd
  35. if [[ -z "${VET_SKIP_PROTO}" ]]; then
  36. if [[ "${GITHUB_ACTIONS}" = "true" ]]; then
  37. PROTOBUF_VERSION=22.0 # a.k.a v4.22.0 in pb.go files.
  38. PROTOC_FILENAME=protoc-${PROTOBUF_VERSION}-linux-x86_64.zip
  39. pushd /home/runner/go
  40. wget https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/${PROTOC_FILENAME}
  41. unzip ${PROTOC_FILENAME}
  42. bin/protoc --version
  43. popd
  44. elif not which protoc > /dev/null; then
  45. die "Please install protoc into your path"
  46. fi
  47. fi
  48. exit 0
  49. elif [[ "$#" -ne 0 ]]; then
  50. die "Unknown argument(s): $*"
  51. fi
  52. # - Check that generated proto files are up to date.
  53. if [[ -z "${VET_SKIP_PROTO}" ]]; then
  54. make proto && git status --porcelain 2>&1 | fail_on_output || \
  55. (git status; git --no-pager diff; exit 1)
  56. fi
  57. if [[ -n "${VET_ONLY_PROTO}" ]]; then
  58. exit 0
  59. fi
  60. # - Ensure all source files contain a copyright message.
  61. # (Done in two parts because Darwin "git grep" has broken support for compound
  62. # exclusion matches.)
  63. (grep -L "DO NOT EDIT" $(git grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)" -- '*.go') || true) | fail_on_output
  64. # - Make sure all tests in grpc and grpc/test use leakcheck via Teardown.
  65. not grep 'func Test[^(]' *_test.go
  66. not grep 'func Test[^(]' test/*.go
  67. # - Do not import x/net/context.
  68. not git grep -l 'x/net/context' -- "*.go"
  69. # - Do not import math/rand for real library code. Use internal/grpcrand for
  70. # thread safety.
  71. git grep -l '"math/rand"' -- "*.go" 2>&1 | not grep -v '^examples\|^stress\|grpcrand\|^benchmark\|wrr_test'
  72. # - Do not use "interface{}"; use "any" instead.
  73. git grep -l 'interface{}' -- "*.go" 2>&1 | not grep -v '\.pb\.go\|protoc-gen-go-grpc'
  74. # - Do not call grpclog directly. Use grpclog.Component instead.
  75. git grep -l -e 'grpclog.I' --or -e 'grpclog.W' --or -e 'grpclog.E' --or -e 'grpclog.F' --or -e 'grpclog.V' -- "*.go" | not grep -v '^grpclog/component.go\|^internal/grpctest/tlogger_test.go'
  76. # - Ensure all ptypes proto packages are renamed when importing.
  77. not git grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/" -- "*.go"
  78. # - Ensure all xds proto imports are renamed to *pb or *grpc.
  79. git grep '"github.com/envoyproxy/go-control-plane/envoy' -- '*.go' ':(exclude)*.pb.go' | not grep -v 'pb "\|grpc "'
  80. misspell -error .
  81. # - gofmt, goimports, golint (with exceptions for generated code), go vet,
  82. # go mod tidy.
  83. # Perform these checks on each module inside gRPC.
  84. for MOD_FILE in $(find . -name 'go.mod'); do
  85. MOD_DIR=$(dirname ${MOD_FILE})
  86. pushd ${MOD_DIR}
  87. go vet -all ./... | fail_on_output
  88. gofmt -s -d -l . 2>&1 | fail_on_output
  89. goimports -l . 2>&1 | not grep -vE "\.pb\.go"
  90. golint ./... 2>&1 | not grep -vE "/grpc_testing_not_regenerate/.*\.pb\.go:"
  91. go mod tidy -compat=1.19
  92. git status --porcelain 2>&1 | fail_on_output || \
  93. (git status; git --no-pager diff; exit 1)
  94. popd
  95. done
  96. # - Collection of static analysis checks
  97. #
  98. # TODO(dfawley): don't use deprecated functions in examples or first-party
  99. # plugins.
  100. # TODO(dfawley): enable ST1019 (duplicate imports) but allow for protobufs.
  101. SC_OUT="$(mktemp)"
  102. staticcheck -go 1.19 -checks 'inherit,-ST1015,-ST1019,-SA1019' ./... > "${SC_OUT}" || true
  103. # Error if anything other than deprecation warnings are printed.
  104. not grep -v "is deprecated:.*SA1019" "${SC_OUT}"
  105. # Only ignore the following deprecated types/fields/functions.
  106. not grep -Fv '.CredsBundle
  107. .HeaderMap
  108. .Metadata is deprecated: use Attributes
  109. .NewAddress
  110. .NewServiceConfig
  111. .Type is deprecated: use Attributes
  112. BuildVersion is deprecated
  113. balancer.ErrTransientFailure
  114. balancer.Picker
  115. extDesc.Filename is deprecated
  116. github.com/golang/protobuf/jsonpb is deprecated
  117. grpc.CallCustomCodec
  118. grpc.Code
  119. grpc.Compressor
  120. grpc.CustomCodec
  121. grpc.Decompressor
  122. grpc.MaxMsgSize
  123. grpc.MethodConfig
  124. grpc.NewGZIPCompressor
  125. grpc.NewGZIPDecompressor
  126. grpc.RPCCompressor
  127. grpc.RPCDecompressor
  128. grpc.ServiceConfig
  129. grpc.WithCompressor
  130. grpc.WithDecompressor
  131. grpc.WithDialer
  132. grpc.WithMaxMsgSize
  133. grpc.WithServiceConfig
  134. grpc.WithTimeout
  135. http.CloseNotifier
  136. info.SecurityVersion
  137. proto is deprecated
  138. proto.InternalMessageInfo is deprecated
  139. proto.EnumName is deprecated
  140. proto.ErrInternalBadWireType is deprecated
  141. proto.FileDescriptor is deprecated
  142. proto.Marshaler is deprecated
  143. proto.MessageType is deprecated
  144. proto.RegisterEnum is deprecated
  145. proto.RegisterFile is deprecated
  146. proto.RegisterType is deprecated
  147. proto.RegisterExtension is deprecated
  148. proto.RegisteredExtension is deprecated
  149. proto.RegisteredExtensions is deprecated
  150. proto.RegisterMapType is deprecated
  151. proto.Unmarshaler is deprecated
  152. Target is deprecated: Use the Target field in the BuildOptions instead.
  153. xxx_messageInfo_
  154. ' "${SC_OUT}"
  155. # - special golint on package comments.
  156. lint_package_comment_per_package() {
  157. # Number of files in this go package.
  158. fileCount=$(go list -f '{{len .GoFiles}}' $1)
  159. if [ ${fileCount} -eq 0 ]; then
  160. return 0
  161. fi
  162. # Number of package errors generated by golint.
  163. lintPackageCommentErrorsCount=$(golint --min_confidence 0 $1 | grep -c "should have a package comment")
  164. # golint complains about every file that's missing the package comment. If the
  165. # number of files for this package is greater than the number of errors, there's
  166. # at least one file with package comment, good. Otherwise, fail.
  167. if [ ${fileCount} -le ${lintPackageCommentErrorsCount} ]; then
  168. echo "Package $1 (with ${fileCount} files) is missing package comment"
  169. return 1
  170. fi
  171. }
  172. lint_package_comment() {
  173. set +ex
  174. count=0
  175. for i in $(go list ./...); do
  176. lint_package_comment_per_package "$i"
  177. ((count += $?))
  178. done
  179. set -ex
  180. return $count
  181. }
  182. lint_package_comment
  183. echo SUCCESS