diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc0671d..4cdf9c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: env: go-version: "1.19.5" - + jobs: check-golangci-lint: name: Check golangci-lint @@ -35,7 +35,7 @@ jobs: - name: Run GoReleaser uses: goreleaser/goreleaser-action@336e29918d653399e599bfca99fadc1d7ffbc9f7 # v4.3.0 with: - args: release --skip-sign --skip-publish --snapshot --rm-dist + args: release --skip=sign,publish --snapshot --clean test: name: Run Tests diff --git a/.gitignore b/.gitignore index 849ddff..0949536 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ dist/ +.DS_Store +.idea/ \ No newline at end of file diff --git a/README.md b/README.md index ccb27e6..efe870a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Mattermost Go Vet +# Mattermost Go Vet This repository contains mattermost-specific go-vet rules that are used to maintain code consistency in `mattermost-server`. @@ -16,3 +16,26 @@ This repository contains mattermost-specific go-vet rules that are used to maint 1. **pointerToSlice** - check for usage of pointer to slice in function definitions 1. **mutexLock** - check for cases where a mutex is left locked before returning 1. **wrapError** - check for original errors being passed as details rather then wrapped + +## Running Locally +Mattermost Go Vet is designed to run against the `mattermost/mattermost` repo. It assumes that you have the `mattermost/mattermost` and `mattermost/mattermost-govet` in the same top-level directory. + +The following can be used to test locally: +``` +# ENV vars +MM_ROOT= +MM_GOVET= +GOBIN= +API_YAML=$MM_ROOT/api/v4/html/static/mattermost-openapi-v4.yaml + +# Make OpenAPI file +if [ ! -f $API_YAML ]; then + make -C $MM_ROOT/api build +fi + +# Install +go install $MM_GOVET + +# Run +go vet -vettool=$GOBIN/mattermost-govet -openApiSync -openApiSync.spec=$API_YAML ./... 2>&1 || true +``` \ No newline at end of file diff --git a/openApiSync/openApiSync.go b/openApiSync/openApiSync.go index 3a962bc..d0a8803 100644 --- a/openApiSync/openApiSync.go +++ b/openApiSync/openApiSync.go @@ -9,6 +9,7 @@ import ( "go/ast" "go/printer" "go/token" + "net/http" "os" "regexp" "strconv" @@ -91,7 +92,8 @@ func processRouterInit(pass *analysis.Pass, names []string, routerPrefixes map[s continue } prefix, _ := strconv.Unquote(aexpr.Args[0].(*ast.BasicLit).Value) - method, _ := strconv.Unquote(expr.X.(*ast.CallExpr).Args[0].(*ast.BasicLit).Value) + method := getMethodFromExpr(expr) + name := aexpr.Fun.(*ast.SelectorExpr).X.(*ast.SelectorExpr).Sel.Name handler := cleanRegexp(routerPrefixes[name]) + cleanRegexp(prefix) if stringInSlice(handler, IgnoredCases, true) { // ignore special cases @@ -240,3 +242,37 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } + +func getMethodFromExpr(expr *ast.ExprStmt) string { + var method string + methodArg := expr.X.(*ast.CallExpr).Args[0] + + if methodSelectorExpr, ok := methodArg.(*ast.SelectorExpr); ok { + if methodSelectorExpr.X.(*ast.Ident).Name == "http" { + switch methodSelectorExpr.Sel.Name { + case "MethodGet": + method = http.MethodGet + case "MethodHead": + method = http.MethodHead + case "MethodPost": + method = http.MethodPost + case "MethodPut": + method = http.MethodPut + case "MethodPatch": + method = http.MethodPatch + case "MethodDelete": + method = http.MethodDelete + case "MethodConnect": + method = http.MethodConnect + case "MethodOptions": + method = http.MethodOptions + case "MethodTrace": + method = http.MethodTrace + } + } + } else if methodBasicLit, ok := methodArg.(*ast.BasicLit); ok { + method, _ = strconv.Unquote(methodBasicLit.Value) + } + + return method +} diff --git a/openApiSync/testdata/src/api/users.go b/openApiSync/testdata/src/api/users.go index 32990de..a5b0b39 100644 --- a/openApiSync/testdata/src/api/users.go +++ b/openApiSync/testdata/src/api/users.go @@ -9,7 +9,7 @@ import ( ) func (a *API) InitUsers() { - a.BaseRoutes.Users.Handle("/ids", a.ApiSessionRequired(getUsersByIds)).Methods("POST") // want `Cannot find /api/v4/userzs/ids method: POST in OpenAPI 3 spec. \(maybe you meant: \[/api/v4/users/ids\]\)` + a.BaseRoutes.Users.Handle("/ids", a.ApiSessionRequired(getUsersByIds)).Methods(http.MethodPost) // want `Cannot find /api/v4/userzs/ids method: POST in OpenAPI 3 spec. \(maybe you meant: \[/api/v4/users/ids\]\)` a.BaseRoutes.Groups.Handle("/{group_id:[A-Za-z0-9]+}/{syncable_type:teams|channelz}/{syncable_id:[A-Za-z0-9]+}/link", a.ApiSessionRequired(getUsersByIds)).Methods("POST") // want `Cannot find /api/v4/groups/{group_id}/channelz/{syncable_id}/link method: POST in OpenAPI 3 spec.` }