Repository: uber/prototool
Pull request #283 (2019-01-10 05:23:39)

Add linter to check for services ending in API
Re: #265.


Patch:
diff --git a/internal/lint/check_service_names_api_suffix.go b/internal/lint/check_service_names_api_suffix.go
new file mode 100644
index 0000000..d17072e
--- /dev/null
+++ b/internal/lint/check_service_names_api_suffix.go
@@ -0,0 +1,52 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package lint
+
+import (
+	"strings"
+
+	"github.com/emicklei/proto"
+	"github.com/uber/prototool/internal/text"
+)
+
+var serviceNamesAPISuffixLinter = NewLinter(
+	"SERVICE_NAMES_API_SUFFIX",
+	`Verifies that all service names end with "API".`,
+	checkServiceNamesAPISuffix,
+)
+
+func checkServiceNamesAPISuffix(add func(*text.Failure), dirPath string, descriptors []*proto.Proto) error {
+	return runVisitor(serviceNamesAPISuffixVisitor{baseAddVisitor: newBaseAddVisitor(add)}, descriptors)
+}
+
+type serviceNamesAPISuffixVisitor struct {
+	baseAddVisitor
+}
+
+func (v serviceNamesAPISuffixVisitor) VisitService(service *proto.Service) {
+	if !strings.HasSuffix(service.Name, "API") {
+		if strings.HasSuffix(service.Name, "Service") {
+			v.AddFailuref(service.Position, `Service name %q must end with "API". Since it currently ends with "Service", this likely means replacing "Service" with "API"`, service.Name)
+		} else {
+			v.AddFailuref(service.Position, `Service name %q must end with "API".`, service.Name)
+		}
+	}
+}
diff --git a/internal/lint/lint.go b/internal/lint/lint.go
index e7cbe2e..0d848d8 100644
--- a/internal/lint/lint.go
+++ b/internal/lint/lint.go
@@ -87,6 +87,7 @@ var (
 		requestResponseTypesUniqueLinter,
 		requestResponseNamesMatchRPCLinter,
 		servicesHaveCommentsLinter,
+		serviceNamesAPISuffixLinter,
 		serviceNamesCamelCaseLinter,
 		serviceNamesCapitalizedLinter,
 		syntaxProto3Linter,
@@ -189,6 +190,7 @@ var (
 		requestResponseNamesMatchRPCLinter,
 		requestResponseTypesInSameFileLinter,
 		requestResponseTypesUniqueLinter,
+		serviceNamesAPISuffixLinter,
 		serviceNamesCamelCaseLinter,
 		serviceNamesCapitalizedLinter,
 		syntaxProto3Linter,


Test patch:
diff --git a/internal/cmd/cmd_test.go b/internal/cmd/cmd_test.go
index 57b964d..c6dc2e1 100644
--- a/internal/cmd/cmd_test.go
+++ b/internal/cmd/cmd_test.go
@@ -399,6 +399,14 @@ func TestLint(t *testing.T) {
 		"testdata/lint/noreserved/foo.proto",
 	)
 
+	assertDoLintFile(
+		t,
+		false,
+		`10:1:SERVICE_NAMES_API_SUFFIX
+		12:1:SERVICE_NAMES_API_SUFFIX`,
+		"testdata/lint/apisuffix/foo.proto",
+	)
+
 	assertDoLintFile(
 		t,
 		false,
diff --git a/internal/cmd/testdata/lint/apisuffix/foo.proto b/internal/cmd/testdata/lint/apisuffix/foo.proto
new file mode 100644
index 0000000..94e7f81
--- /dev/null
+++ b/internal/cmd/testdata/lint/apisuffix/foo.proto
@@ -0,0 +1,12 @@
+syntax = "proto3";
+
+package foo;
+
+option go_package = "foopb";
+option java_multiple_files = true;
+option java_outer_classname = "FooProto";
+option java_package = "com.foo";
+
+service HelloService {}
+
+service Hello {}
diff --git a/internal/cmd/testdata/lint/apisuffix/prototool.yaml b/internal/cmd/testdata/lint/apisuffix/prototool.yaml
new file mode 100644
index 0000000..677f7b2
--- /dev/null
+++ b/internal/cmd/testdata/lint/apisuffix/prototool.yaml
@@ -0,0 +1,4 @@
+lint:
+  rules:
+    add:
+      - SERVICE_NAMES_API_SUFFIX