Skip to content

Commit

Permalink
feat: Add rule for AIP-162 Commit HTTP URI suffix (#728)
Browse files Browse the repository at this point in the history
  • Loading branch information
apasel422 authored Jan 20, 2021
1 parent 7ba8f51 commit 9f4f1bc
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 0 deletions.
67 changes: 67 additions & 0 deletions docs/rules/0162/commit-http-uri-suffix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
rule:
aip: 162
name: [core, '0162', commit-http-uri-suffix]
summary: Commit methods must have the correct URI suffix
permalink: /162/commit-http-uri-suffix
redirect_from:
- /0162/commit-http-uri-suffix
---

# Commit methods: URI suffix

This rule enforces that `Commit` methods include the `:commit` suffix
in the REST URI, as mandated in [AIP-162][].

## Details

This rule looks at any method beginning with `Commit`, and
complains if the HTTP URI does not end with `:commit`.

## Examples

**Incorrect** code for this rule:

```proto
// Incorrect.
rpc CommitBook(CommitBookRequest) returns (Book) {
option (google.api.http) = {
post: "/v1/{name=publishers/*/books/*}:save" // Should end with `:commit`
body: "*"
};
}
```

**Correct** code for this rule:

```proto
// Correct.
rpc CommitBook(CommitBookRequest) returns (Book) {
option (google.api.http) = {
post: "/v1/{name=publishers/*/books/*}:commit"
body: "*"
};
}
```

## Disabling

If you need to violate this rule, use a leading comment above the method.
Remember to also include an [aip.dev/not-precedent][] comment explaining why.

```proto
// (-- api-linter: core::0162::commit-http-uri-suffix=disabled
// aip.dev/not-precedent: We need to do this because reasons. --)
rpc Commit(CommitBookRequest) returns (Book) {
option (google.api.http) = {
post: "/v1/{name=publishers/*/books/*}:save"
body: "*"
};
}
```

If you need to violate this rule for an entire file, place the comment at the
top of the file.

[aip-162]: https://aip.dev/162
[aip.dev/not-precedent]: https://aip.dev/not-precedent
9 changes: 9 additions & 0 deletions rules/aip0162/aip0162.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
func AddRules(r lint.RuleRegistry) error {
return r.Register(
162,
commitHTTPURISuffix,
tagRevisionHTTPBody,
tagRevisionHTTPMethod,
tagRevisionHTTPURISuffix,
Expand All @@ -53,3 +54,11 @@ func isTagRevisionMethod(m *desc.MethodDescriptor) bool {
func isTagRevisionRequestMessage(m *desc.MessageDescriptor) bool {
return tagRevisionReqMessageRegexp.MatchString(m.GetName())
}

var commitMethodRegexp = regexp.MustCompile(`^Commit(?:[A-Za-z0-9]+)$`)
var commitURINameRegexp = regexp.MustCompile(`:commit$`)

// Returns true if this is an AIP-162 Commit method, false otherwise.
func isCommitMethod(m *desc.MethodDescriptor) bool {
return commitMethodRegexp.MatchString(m.GetName())
}
39 changes: 39 additions & 0 deletions rules/aip0162/commit_http_uri_suffix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package aip0162

import (
"github.com/googleapis/api-linter/lint"
"github.com/googleapis/api-linter/rules/internal/utils"
"github.com/jhump/protoreflect/desc"
)

// Commit methods should have a proper HTTP pattern.
var commitHTTPURISuffix = &lint.MethodRule{
Name: lint.NewRuleName(162, "commit-http-uri-suffix"),
OnlyIf: isCommitMethod,
LintMethod: func(m *desc.MethodDescriptor) []lint.Problem {
for _, httpRule := range utils.GetHTTPRules(m) {
if !commitURINameRegexp.MatchString(httpRule.URI) {
return []lint.Problem{{
Message: `Commit URI should end with ":commit".`,
Descriptor: m,
}}
}
}

return nil
},
}
57 changes: 57 additions & 0 deletions rules/aip0162/commit_http_uri_suffix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package aip0162

import (
"testing"

"github.com/googleapis/api-linter/rules/internal/testutils"
)

func TestCommitHTTPURISuffix(t *testing.T) {
tests := []struct {
testName string
URI string
MethodName string
problems testutils.Problems
}{
{"Valid", "/v1/{name=publishers/*/books/*}:commit", "CommitBook", nil},
{"InvalidSuffix", "/v1/{name=publishers/*/books/*}:save", "CommitBook", testutils.Problems{{Message: ":commit"}}},
{"Irrelevant", "/v1/{name=publishers/*/books/*}:save", "AcquireBook", nil},
}

for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
file := testutils.ParseProto3Tmpl(t, `
import "google/api/annotations.proto";
service Library {
rpc {{.MethodName}}({{.MethodName}}Request) returns (Book) {
option (google.api.http) = {
post: "{{.URI}}"
body: "*"
};
}
}
message Book {}
message {{.MethodName}}Request {}
`, test)

problems := commitHTTPURISuffix.Lint(file)
if diff := test.problems.SetDescriptor(file.GetServices()[0].GetMethods()[0]).Diff(problems); diff != "" {
t.Errorf(diff)
}
})
}
}

0 comments on commit 9f4f1bc

Please sign in to comment.