From 4b933b4e67716fe4a87e45630554ad7ea0620007 Mon Sep 17 00:00:00 2001 From: Alex Stephen Date: Sun, 9 Nov 2025 22:21:41 +0530 Subject: [PATCH 1/4] wip --- docs/rules/0004/duplicate-resource.md | 16 ++++++------- docs/rules/0004/path-never-optional.md | 8 +++---- docs/rules/0004/resource-annotation.md | 10 ++++---- .../rules/0004/resource-definition-pattern.md | 14 +++++------ .../0004/resource-definition-type-name.md | 10 ++++---- .../0004/resource-definition-variables.md | 12 +++++----- .../resource-name-components-alternate.md | 10 ++++---- docs/rules/0004/resource-path-field.md | 10 ++++---- docs/rules/0004/resource-pattern.md | 14 +++++------ docs/rules/0004/resource-plural.md | 10 ++++---- docs/rules/0004/resource-singular.md | 10 ++++---- docs/rules/0004/resource-type-name.md | 10 ++++---- docs/rules/0004/resource-variables.md | 12 +++++----- docs/rules/0121/no-mutable-cycles.md | 12 +++++----- docs/rules/0121/resource-must-support-get.md | 6 ++--- docs/rules/0121/resource-must-support-list.md | 6 ++--- docs/rules/0122/no-self-links.md | 6 ++--- .../0122/resource-collection-identifiers.md | 12 +++++----- docs/rules/0122/resource-id-output-only.md | 6 ++--- docs/rules/0124/reference-same-package.md | 6 ++--- docs/rules/0127/http-template-pattern.md | 4 ++-- docs/rules/0133/http-uri-resource.md | 6 ++--- docs/rules/0134/response-lro.md | 2 +- docs/rules/0135/response-lro.md | 2 +- .../rules/0148/declarative-friendly-fields.md | 8 +++---- docs/rules/0148/field-behavior.md | 8 +++---- docs/rules/0148/ip-address-format.md | 6 ++--- docs/rules/0148/uid-format.md | 6 ++--- docs/rules/0164/resource-expire-time-field.md | 6 ++--- docs/rules/0164/response-lro.md | 2 +- .../example/bookstore/v1/bookstore.proto | 8 +++---- locations/file_locations.go | 2 +- locations/message_locations.go | 2 +- locations/message_locations_test.go | 2 +- rules/aep0004/duplicate_resource.go | 2 +- rules/aep0004/duplicate_resource_test.go | 18 +++++++------- rules/aep0004/path_never_optional_test.go | 2 +- rules/aep0004/resource_annotation.go | 2 +- rules/aep0004/resource_annotation_test.go | 4 ++-- .../resource_definition_pattern_test.go | 2 +- .../resource_definition_type_name_test.go | 2 +- .../resource_definition_variables_test.go | 2 +- ...resource_name_components_alternate_test.go | 2 +- rules/aep0004/resource_path_field_test.go | 10 ++++---- rules/aep0004/resource_pattern_test.go | 2 +- rules/aep0004/resource_plural_test.go | 2 +- rules/aep0004/resource_singular_test.go | 2 +- rules/aep0004/resource_type_name_test.go | 2 +- rules/aep0004/resource_variables.go | 4 ++-- rules/aep0004/resource_variables_test.go | 2 +- rules/aep0121/no_mutable_cycles_test.go | 6 ++--- .../aep0121/resource_must_support_get_test.go | 4 ++-- .../resource_must_support_list_test.go | 6 ++--- rules/aep0122/no_self_links_test.go | 2 +- .../resource_collection_identifiers_test.go | 2 +- rules/aep0122/resource_id_output_only_test.go | 2 +- rules/aep0127/http_template_pattern_test.go | 10 ++++---- rules/aep0131/request_required_fields_test.go | 2 +- rules/aep0132/request_parent_required_test.go | 2 +- .../request_parent_valid_reference_test.go | 2 +- rules/aep0132/request_required_fields_test.go | 2 +- rules/aep0132/resource_reference_type_test.go | 2 +- rules/aep0133/http_uri_parent_test.go | 6 ++--- rules/aep0133/http_uri_resource_test.go | 2 +- rules/aep0133/method_signature_test.go | 2 +- rules/aep0133/request_id_field_test.go | 2 +- rules/aep0133/request_parent_required_test.go | 2 +- rules/aep0133/request_required_fields_test.go | 2 +- rules/aep0133/resource_reference_type_test.go | 4 ++-- .../request_allow_missing_field_test.go | 2 +- rules/aep0134/request_required_fields_test.go | 2 +- rules/aep0134/response_lro_test.go | 2 +- rules/aep0135/force_field_test.go | 4 ++-- rules/aep0135/response_lro_test.go | 2 +- rules/aep0135/response_message_name_test.go | 4 ++-- .../declarative_standard_methods_only_test.go | 2 +- .../declarative_friendly_fields_test.go | 4 ++-- rules/aep0148/field_behavior_test.go | 2 +- rules/aep0164/response_lro_test.go | 2 +- rules/internal/utils/declarative_friendly.go | 8 +++---- .../utils/declarative_friendly_test.go | 8 +++---- rules/internal/utils/extension.go | 6 ++--- rules/internal/utils/extension_test.go | 24 +++++++++---------- rules/internal/utils/method_test.go | 12 +++++----- rules/internal/utils/resource_test.go | 4 ++-- 85 files changed, 237 insertions(+), 237 deletions(-) diff --git a/docs/rules/0004/duplicate-resource.md b/docs/rules/0004/duplicate-resource.md index cc82de67..6c9f2b99 100644 --- a/docs/rules/0004/duplicate-resource.md +++ b/docs/rules/0004/duplicate-resource.md @@ -11,12 +11,12 @@ redirect_from: # Resource annotation presence This rule enforces that the same resource type doesn't appear in more than one -`google.api.resource` annotation, as described in [AEP-004][]. +`aep.api.resource` annotation, as described in [AEP-004][]. ## Details This rule complains about messages that have the same `type` for the -`google.api.resource` annotation, which frequently occur due to copy-paste +`aep.api.resource` annotation, which frequently occur due to copy-paste errors and messages spread across multiple files and/or packages. Duplicate resource definitions can cause compilation problems in generated client code. @@ -26,7 +26,7 @@ resource definitions can cause compilation problems in generated client code. ```proto message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -35,7 +35,7 @@ message Book { } message Author { - option (google.api.resource) = { + option (aep.api.resource) = { // Incorrect: should be "library.googleapis.com/Author". type: "library.googleapis.com/Book" pattern: "authors/{author}" @@ -50,7 +50,7 @@ message Author { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -59,7 +59,7 @@ message Book { } message Author { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Author" pattern: "authors/{author}" }; @@ -79,7 +79,7 @@ Remember to also include an [aep.dev/not-precedent][] comment explaining why. syntax = "proto3"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -88,7 +88,7 @@ message Book { } message Author { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "authors/{author}" }; diff --git a/docs/rules/0004/path-never-optional.md b/docs/rules/0004/path-never-optional.md index 9abb0dc9..bbf616fa 100644 --- a/docs/rules/0004/path-never-optional.md +++ b/docs/rules/0004/path-never-optional.md @@ -15,7 +15,7 @@ proto3_optional. ## Details -This rule scans for messages with a `google.api.resource` annotation and ensures +This rule scans for messages with a `aep.api.resource` annotation and ensures that the configured path field (either `path` or whichever field specified via `path_field`) is not labeled as `optional`. @@ -26,7 +26,7 @@ that the configured path field (either `path` or whichever field specified via ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -41,7 +41,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -58,7 +58,7 @@ If you need to violate this rule, use a leading comment above the message. // (-- api-linter: core::04::path-never-optional=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/docs/rules/0004/resource-annotation.md b/docs/rules/0004/resource-annotation.md index 83dda751..96613c52 100644 --- a/docs/rules/0004/resource-annotation.md +++ b/docs/rules/0004/resource-annotation.md @@ -2,7 +2,7 @@ rule: aep: 4 name: [core, '4', resource-annotation] - summary: Resource messages should be annotated with `google.api.resource`. + summary: Resource messages should be annotated with `aep.api.resource`. permalink: /4/resource-annotation redirect_from: - /4/resource-annotation @@ -11,13 +11,13 @@ redirect_from: # Resource annotation presence This rule enforces that top-level messages that appear to represent resources -have a `google.api.resource` annotation, as described in [AEP-4][]. +have a `aep.api.resource` annotation, as described in [AEP-4][]. ## Details This rule scans all top-level messages, and assumes that messages with a `string path` field are resources unless the message name ends with `Request`. -For messages that are resources, it complains if the `google.api.resource` +For messages that are resources, it complains if the `aep.api.resource` annotation is missing. ## Examples @@ -27,7 +27,7 @@ annotation is missing. ```proto // Incorrect. message Book { - // A `google.api.resource` annotation should be here. + // A `aep.api.resource` annotation should be here. string path = 1; } ``` @@ -37,7 +37,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/docs/rules/0004/resource-definition-pattern.md b/docs/rules/0004/resource-definition-pattern.md index 724c302a..2a529c91 100644 --- a/docs/rules/0004/resource-definition-pattern.md +++ b/docs/rules/0004/resource-definition-pattern.md @@ -11,12 +11,12 @@ redirect_from: # Resource patterns This rule enforces that files that define a resource with the -`google.api.resource_definition` annotation have a `pattern` defined, as +`aep.api.resource_definition` annotation have a `pattern` defined, as described in [AEP-123][]. ## Details -This rule scans all `google.api.resource_definition` annotations in all files, +This rule scans all `aep.api.resource_definition` annotations in all files, and complains if `pattern` is not provided at least once. It also complains if the segments outside of variable names contain underscores. @@ -28,7 +28,7 @@ the segments outside of variable names contain underscores. import "google/api/resources.proto"; // Incorrect. -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" // pattern should be here }; @@ -38,7 +38,7 @@ option (google.api.resource_definition) = { import "google/api/resources.proto"; // Incorrect. -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/ElectronicBook" // Should be: publishers/{publisher}/electronicBooks/{electronic_book} pattern: "publishers/{publisher}/electronic_books/{electronic_book}" @@ -51,7 +51,7 @@ option (google.api.resource_definition) = { import "google/api/resources.proto"; // Correct. -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -61,7 +61,7 @@ option (google.api.resource_definition) = { import "google/api/resource.proto"; // Correct. -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/ElectronicBook" pattern: "publishers/{publisher}/electronicBooks/{electronic_book}" }; @@ -76,7 +76,7 @@ import "google/api/resource.proto"; // (-- api-linter: core::0123::resource-definition-pattern=disabled // aep.dev/not-precedent: We need to do this because reasons. --) -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" }; ``` diff --git a/docs/rules/0004/resource-definition-type-name.md b/docs/rules/0004/resource-definition-type-name.md index 2fe7d379..67c67908 100644 --- a/docs/rules/0004/resource-definition-type-name.md +++ b/docs/rules/0004/resource-definition-type-name.md @@ -11,12 +11,12 @@ redirect_from: # Resource type name This rule enforces that files that define a resource with the -`google.api.resource_definition` annotation have a properly formatted `type`, as +`aep.api.resource_definition` annotation have a properly formatted `type`, as described in [AEP-123][]. ## Details -This rule scans files with `google.api.resource_definition` annotations, and +This rule scans files with `aep.api.resource_definition` annotations, and validates the format of the `type` field conforms to `{Service Name}/{Type}`. ## Examples @@ -27,7 +27,7 @@ validates the format of the `type` field conforms to `{Service Name}/{Type}`. import "google/api/resource.proto"; // Incorrect. -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { // Should not have more than one separating '/'. type: "library.googleapis.com/Genre/Mystery/Book" pattern: "publishers/{publisher}/books/{book}" @@ -40,7 +40,7 @@ option (google.api.resource_definition) = { import "google/api/resource.proto"; // Correct. -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -55,7 +55,7 @@ import "google/api/resource.proto"; // (-- api-linter: core::0123::resource-definition-type-name=disabled // aep.dev/not-precedent: We need to do this because reasons. --) -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/Genre/Mystery/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/docs/rules/0004/resource-definition-variables.md b/docs/rules/0004/resource-definition-variables.md index aec52d32..fe59e4c2 100644 --- a/docs/rules/0004/resource-definition-variables.md +++ b/docs/rules/0004/resource-definition-variables.md @@ -15,7 +15,7 @@ conventions, as described in [AEP-4][]. ## Details -This rule scans all files with `google.api.resource_definition` annotations, and +This rule scans all files with `aep.api.resource_definition` annotations, and complains if variables in a `pattern` use camel case, or end in `_id`. ## Examples @@ -26,7 +26,7 @@ complains if variables in a `pattern` use camel case, or end in `_id`. import "google/api/resource.proto"; // Incorrect. -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" // Should be: publishers/{publisher}/books/{book} pattern: "publishers/{publisher_id}/books/{book_id}" @@ -37,7 +37,7 @@ option (google.api.resource_definition) = { import "google/api/resource.proto"; // Incorrect. -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/ElectronicBook" // Should be: publishers/{publisher}/electronicBooks/{electronic_book} pattern: "publishers/{publisher}/electronicBooks/{electronicBook}" @@ -50,7 +50,7 @@ option (google.api.resource_definition) = { import "google/api/resource.proto"; // Correct. -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -60,7 +60,7 @@ option (google.api.resource_definition) = { import "google/api/resource.proto"; // Correct. -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/ElectronicBook" pattern: "publishers/{publisher}/electronicBooks/{electronic_book}" }; @@ -75,7 +75,7 @@ import "google/api/resource.proto"; // (-- api-linter: core::4::resource-definition-variables=disabled // aep.dev/not-precedent: We need to do this because reasons. --) -option (google.api.resource_definition) = { +option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher_id}/books/{book_id}" }; diff --git a/docs/rules/0004/resource-name-components-alternate.md b/docs/rules/0004/resource-name-components-alternate.md index 5c95a1d7..88b184d0 100644 --- a/docs/rules/0004/resource-name-components-alternate.md +++ b/docs/rules/0004/resource-name-components-alternate.md @@ -12,13 +12,13 @@ redirect_from: # Resource name components alternate -This rule enforces that messages that have a `google.api.resource` annotation +This rule enforces that messages that have a `aep.api.resource` annotation have `pattern` annotations that alternate between collection and identifier, as described in [AEP-4][]. ## Details -This rule scans messages with a `google.api.resource` annotation, and validates +This rule scans messages with a `aep.api.resource` annotation, and validates that each `pattern` alternated between collection and identifiers. ## Examples @@ -28,7 +28,7 @@ that each `pattern` alternated between collection and identifiers. ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" // two collections next to each other. pattern: "publishers/books/{book}" @@ -42,7 +42,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -58,7 +58,7 @@ If you need to violate this rule, use a leading comment above the message. // (-- api-linter: core::4::resource-name-components-alternate=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/books/{book}" }; diff --git a/docs/rules/0004/resource-path-field.md b/docs/rules/0004/resource-path-field.md index a39c47ae..1dd9bfca 100644 --- a/docs/rules/0004/resource-path-field.md +++ b/docs/rules/0004/resource-path-field.md @@ -15,7 +15,7 @@ This rule enforces that messages that appear to represent resources have a ## Details -This rule scans all messages that have a `google.api.resource` annotation, and +This rule scans all messages that have a `aep.api.resource` annotation, and complains if the `path` field is missing or if it is any type other than singular `string`. @@ -26,7 +26,7 @@ singular `string`. ```proto // Incorrect: missing `string path` field. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -36,7 +36,7 @@ message Book { ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -51,7 +51,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -69,7 +69,7 @@ above the field if it is the wrong type. // (-- api-linter: core::4::resource-path-field=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/docs/rules/0004/resource-pattern.md b/docs/rules/0004/resource-pattern.md index dde83bae..1e3f30eb 100644 --- a/docs/rules/0004/resource-pattern.md +++ b/docs/rules/0004/resource-pattern.md @@ -11,12 +11,12 @@ redirect_from: # Resource patterns This rule enforces that messages that appear to represent resources have a -`pattern` defined on their `google.api.resource` annotation, as described in +`pattern` defined on their `aep.api.resource` annotation, as described in [AEP-4][]. ## Details -This rule scans all messages with `google.api.resource` annotations, and +This rule scans all messages with `aep.api.resource` annotations, and complains if `pattern` is not provided at least once. It also complains if the segments outside of variable names contain underscores. @@ -27,7 +27,7 @@ segments outside of variable names contain underscores. ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" // pattern should be here }; @@ -39,7 +39,7 @@ message Book { ```proto // Incorrect. message ElectronicBook { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/ElectronicBook" // Should be: publishers/{publisher}/electronicBooks/{electronic_book} pattern: "publishers/{publisher}/electronic_books/{electronic_book}" @@ -54,7 +54,7 @@ message ElectronicBook { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -66,7 +66,7 @@ message Book { ```proto // Correct. message ElectronicBook { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/ElectronicBook" pattern: "publishers/{publisher}/electronicBooks/{electronic_book}" }; @@ -83,7 +83,7 @@ If you need to violate this rule, use a leading comment above the message. // (-- api-linter: core::4::resource-pattern=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" }; diff --git a/docs/rules/0004/resource-plural.md b/docs/rules/0004/resource-plural.md index 29232190..2a83f998 100644 --- a/docs/rules/0004/resource-plural.md +++ b/docs/rules/0004/resource-plural.md @@ -10,12 +10,12 @@ redirect_from: # Resource type name -This rule enforces that messages that have a `google.api.resource` annotation, +This rule enforces that messages that have a `aep.api.resource` annotation, have a properly formatted `plural`, as described in [AEP-4][]. ## Details -This rule scans messages with a `google.api.resource` annotation, and +This rule scans messages with a `aep.api.resource` annotation, and verifies the `plural` field exists. ## Examples @@ -26,7 +26,7 @@ verifies the `plural` field exists. // Incorrect. message Book { // no plural annotation - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/BookShelf" pattern: "publishers/{publisher}/bookShelves/{book_shelf}" }; @@ -40,7 +40,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/BookShelf" pattern: "publishers/{publisher}/bookShelves/{book_shelf}" plural: "bookShelves", @@ -58,7 +58,7 @@ If you need to violate this rule, use a leading comment above the message. // (-- api-linter: core::4::resource-plural=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Genre/Mystery/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/docs/rules/0004/resource-singular.md b/docs/rules/0004/resource-singular.md index 6292229d..4e44e082 100644 --- a/docs/rules/0004/resource-singular.md +++ b/docs/rules/0004/resource-singular.md @@ -10,12 +10,12 @@ redirect_from: # Resource type name -This rule enforces that messages that have a `google.api.resource` annotation, +This rule enforces that messages that have a `aep.api.resource` annotation, have a properly formatted `singular`, as described in [AEP-4][]. ## Details -This rule scans messages with a `google.api.resource` annotation, and validates +This rule scans messages with a `aep.api.resource` annotation, and validates the format of the `singular` field is the lower camel case of type. ## Examples @@ -25,7 +25,7 @@ the format of the `singular` field is the lower camel case of type. ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/BookShelf" pattern: "publishers/{publisher}/bookShelves/{book_shelf}" // does not match type. @@ -41,7 +41,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/BookShelf" pattern: "publishers/{publisher}/bookShelves/{book_shelf}" singular: "bookShelf", @@ -59,7 +59,7 @@ If you need to violate this rule, use a leading comment above the message. // (-- api-linter: core::4::resource-singular=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Genre/Mystery/Book" pattern: "publishers/{publisher}/books/{book}" singular: "shelf", diff --git a/docs/rules/0004/resource-type-name.md b/docs/rules/0004/resource-type-name.md index ce1ca50d..6a41b8dc 100644 --- a/docs/rules/0004/resource-type-name.md +++ b/docs/rules/0004/resource-type-name.md @@ -10,12 +10,12 @@ redirect_from: # Resource type name -This rule enforces that messages that have a `google.api.resource` annotation, +This rule enforces that messages that have a `aep.api.resource` annotation, have a properly formatted `type`, as described in [AEP-4][]. ## Details -This rule scans messages with a `google.api.resource` annotation, and validates +This rule scans messages with a `aep.api.resource` annotation, and validates the format of the `type` field conforms to `{Service Name}/{Type}`. ## Examples @@ -25,7 +25,7 @@ the format of the `type` field conforms to `{Service Name}/{Type}`. ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { // Should not have more than one separating '/'. type: "library.googleapis.com/Genre/Mystery/Book" pattern: "publishers/{publisher}/books/{book}" @@ -40,7 +40,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -57,7 +57,7 @@ If you need to violate this rule, use a leading comment above the message. // (-- api-linter: core::4::resource-type-name=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Genre/Mystery/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/docs/rules/0004/resource-variables.md b/docs/rules/0004/resource-variables.md index 14c94a27..3ef62e06 100644 --- a/docs/rules/0004/resource-variables.md +++ b/docs/rules/0004/resource-variables.md @@ -15,7 +15,7 @@ conventions, as described in [AEP-4][]. ## Details -This rule scans all messages with `google.api.resource` annotations, and +This rule scans all messages with `aep.api.resource` annotations, and complains if variables in a `pattern` use camel case, or end in `_id`. ## Examples @@ -25,7 +25,7 @@ complains if variables in a `pattern` use camel case, or end in `_id`. ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" // Should be: publishers/{publisher}/books/{book} pattern: "publishers/{publisher_id}/books/{book_id}" @@ -38,7 +38,7 @@ message Book { ```proto // Incorrect. message ElectronicBook { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/ElectronicBook" // Should be: publishers/{publisher}/electronicBooks/{electronic_book} pattern: "publishers/{publisher}/electronicBooks/{electronicBook}" @@ -53,7 +53,7 @@ message ElectronicBook { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -65,7 +65,7 @@ message Book { ```proto // Correct. message ElectronicBook { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/ElectronicBook" pattern: "publishers/{publisher}/electronicBooks/{electronic_book}" }; @@ -82,7 +82,7 @@ If you need to violate this rule, use a leading comment above the message. // (-- api-linter: core::4::resource-variables=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher_id}/books/{book_id}" }; diff --git a/docs/rules/0121/no-mutable-cycles.md b/docs/rules/0121/no-mutable-cycles.md index 91adaa2a..38b355d7 100644 --- a/docs/rules/0121/no-mutable-cycles.md +++ b/docs/rules/0121/no-mutable-cycles.md @@ -24,7 +24,7 @@ other resources do not create a mutable cycle between them. ```proto message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -38,7 +38,7 @@ message Book { } message Author { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Author" pattern: "authors/{author}" }; @@ -56,7 +56,7 @@ message Author { ```proto message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -70,7 +70,7 @@ message Book { } message Author { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Author" pattern: "authors/{author}" }; @@ -92,7 +92,7 @@ Remember to also include an [aep.dev/not-precedent][] comment explaining why. ```proto message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -107,7 +107,7 @@ message Book { } message Author { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Author" pattern: "authors/{author}" }; diff --git a/docs/rules/0121/resource-must-support-get.md b/docs/rules/0121/resource-must-support-get.md index 8eafa89a..6dac0129 100644 --- a/docs/rules/0121/resource-must-support-get.md +++ b/docs/rules/0121/resource-must-support-get.md @@ -30,7 +30,7 @@ service Foo { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -47,7 +47,7 @@ service Foo { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -68,7 +68,7 @@ service Foo { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; diff --git a/docs/rules/0121/resource-must-support-list.md b/docs/rules/0121/resource-must-support-list.md index 3de692cb..77568856 100644 --- a/docs/rules/0121/resource-must-support-list.md +++ b/docs/rules/0121/resource-must-support-list.md @@ -30,7 +30,7 @@ service Foo { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -47,7 +47,7 @@ service Foo { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -68,7 +68,7 @@ service Foo { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; diff --git a/docs/rules/0122/no-self-links.md b/docs/rules/0122/no-self-links.md index 8dcc1d24..db110bb9 100644 --- a/docs/rules/0122/no-self-links.md +++ b/docs/rules/0122/no-self-links.md @@ -25,7 +25,7 @@ named `self_link`. ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -41,7 +41,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -57,7 +57,7 @@ Remember to also include an [aep.dev/not-precedent][] comment explaining why. ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; diff --git a/docs/rules/0122/resource-collection-identifiers.md b/docs/rules/0122/resource-collection-identifiers.md index 58c561e9..e1f875b6 100644 --- a/docs/rules/0122/resource-collection-identifiers.md +++ b/docs/rules/0122/resource-collection-identifiers.md @@ -10,13 +10,13 @@ redirect_from: # Resource pattern collection identifiers -This rule enforces that messages that have a `google.api.resource` annotation +This rule enforces that messages that have a `aep.api.resource` annotation have properly formatted collection identifiers in each `pattern`, as described in [AEP-122][]. ## Details -This rule scans messages with a `google.api.resource` annotation, and validates +This rule scans messages with a `aep.api.resource` annotation, and validates the format of `pattern` collection identifiers, specifically that they are in lowerCamelCase form and must start with a lowercase letter. @@ -27,7 +27,7 @@ lowerCamelCase form and must start with a lowercase letter. ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" // Collection identifiers must be kebab-case. pattern: "Publishers/{publisher}/publishedBooks/{book}" @@ -39,7 +39,7 @@ message Book { ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" // Collection identifiers must begin with a lower-cased letter. pattern: "/publishers/{publisher}/Published-books/{book}" @@ -53,7 +53,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/published-books/{book}" }; @@ -69,7 +69,7 @@ If you need to violate this rule, use a leading comment above the message. // (-- api-linter: core::0122::resource-collection-identifiers=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "Publishers/{publisher}/Books/{book}" }; diff --git a/docs/rules/0122/resource-id-output-only.md b/docs/rules/0122/resource-id-output-only.md index e4f6eb27..e76ec746 100644 --- a/docs/rules/0122/resource-id-output-only.md +++ b/docs/rules/0122/resource-id-output-only.md @@ -25,7 +25,7 @@ as `uid` or with the `_id` suffix, that is not classified as `OUTPUT_ONLY`. ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -42,7 +42,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -58,7 +58,7 @@ If you need to violate this rule, use a leading comment above the field. ```proto message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; diff --git a/docs/rules/0124/reference-same-package.md b/docs/rules/0124/reference-same-package.md index 8c9d820c..33c34fd4 100644 --- a/docs/rules/0124/reference-same-package.md +++ b/docs/rules/0124/reference-same-package.md @@ -30,7 +30,7 @@ Certain common resource types are exempt from this rule. package google.example.library.v1; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -59,7 +59,7 @@ message GetBookRequest { package google.example.library; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -85,7 +85,7 @@ Remember to also include an [aep.dev/not-precedent][] comment explaining why. package google.example.library.common; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/docs/rules/0127/http-template-pattern.md b/docs/rules/0127/http-template-pattern.md index d19432fd..88c3dbb9 100644 --- a/docs/rules/0127/http-template-pattern.md +++ b/docs/rules/0127/http-template-pattern.md @@ -40,7 +40,7 @@ message GetBookRequest { ]; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "shelves/{shelf}/books/{book}" }; @@ -65,7 +65,7 @@ message GetBookRequest { ]; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "shelves/{shelf}/books/{book}" }; diff --git a/docs/rules/0133/http-uri-resource.md b/docs/rules/0133/http-uri-resource.md index 0e2bdeb2..ea074d1f 100644 --- a/docs/rules/0133/http-uri-resource.md +++ b/docs/rules/0133/http-uri-resource.md @@ -38,7 +38,7 @@ rpc CreateBook(CreateBookRequest) returns (Book) { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -57,7 +57,7 @@ rpc CreateBook(CreateBookRequest) returns (Book) { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" // The pattern does not contain the collection identifier `books`. pattern: "publishers/{publisher}" @@ -77,7 +77,7 @@ rpc CreateBook(CreateBookRequest) returns (Book) { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/docs/rules/0134/response-lro.md b/docs/rules/0134/response-lro.md index 61eb3304..12ba5675 100644 --- a/docs/rules/0134/response-lro.md +++ b/docs/rules/0134/response-lro.md @@ -17,7 +17,7 @@ operations, as mandated in [AEP-134][]. ## Details This rule looks at any `Update` method connected to a resource with a -`google.api.resource` annotation that includes `style: DECLARATIVE_FRIENDLY`, +`aep.api.resource` annotation that includes `style: DECLARATIVE_FRIENDLY`, and complains if it does not use long-running operations. ## Examples diff --git a/docs/rules/0135/response-lro.md b/docs/rules/0135/response-lro.md index 8233cc68..c1862e6e 100644 --- a/docs/rules/0135/response-lro.md +++ b/docs/rules/0135/response-lro.md @@ -17,7 +17,7 @@ operations, as mandated in [AEP-135][]. ## Details This rule looks at any `Delete` method connected to a resource with a -`google.api.resource` annotation that includes `style: DECLARATIVE_FRIENDLY`, +`aep.api.resource` annotation that includes `style: DECLARATIVE_FRIENDLY`, and complains if it does not use long-running operations. ## Examples diff --git a/docs/rules/0148/declarative-friendly-fields.md b/docs/rules/0148/declarative-friendly-fields.md index be230fc8..12753b40 100644 --- a/docs/rules/0148/declarative-friendly-fields.md +++ b/docs/rules/0148/declarative-friendly-fields.md @@ -15,7 +15,7 @@ as mandated in [AIP-148][]. ## Details -This rule looks at any resource with a `google.api.resource` annotation that +This rule looks at any resource with a `aep.api.resource` annotation that includes `style: DECLARATIVE_FRIENDLY`, and complains if it does not include all of the following fields: @@ -33,7 +33,7 @@ all of the following fields: ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book} style: DECLARATIVE_FRIENDLY @@ -53,7 +53,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book} style: DECLARATIVE_FRIENDLY @@ -77,7 +77,7 @@ Remember to also include an [aep.dev/not-precedent][] comment explaining why. // (-- api-linter: core::0148::declarative-friendly-fields=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book} style: DECLARATIVE_FRIENDLY diff --git a/docs/rules/0148/field-behavior.md b/docs/rules/0148/field-behavior.md index 0db214a4..31b34b54 100644 --- a/docs/rules/0148/field-behavior.md +++ b/docs/rules/0148/field-behavior.md @@ -15,7 +15,7 @@ This rule enforces that all standard resource fields have the correct ## Details -This rule looks at any message with a `google.api.resource` annotation, and +This rule looks at any message with a `aep.api.resource` annotation, and complains if any of the following fields does not have a `aep.api.field_behavior` annotation with a value of `OUTPUT_ONLY`: @@ -31,7 +31,7 @@ complains if any of the following fields does not have a ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -57,7 +57,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -81,7 +81,7 @@ Remember to also include an [aep.dev/not-precedent][] comment explaining why. ```proto message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/docs/rules/0148/ip-address-format.md b/docs/rules/0148/ip-address-format.md index 9211e316..cc363375 100644 --- a/docs/rules/0148/ip-address-format.md +++ b/docs/rules/0148/ip-address-format.md @@ -28,7 +28,7 @@ than than one of those. ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -43,7 +43,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -61,7 +61,7 @@ comment explaining why. ```proto message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; diff --git a/docs/rules/0148/uid-format.md b/docs/rules/0148/uid-format.md index d495dcd2..69476a7b 100644 --- a/docs/rules/0148/uid-format.md +++ b/docs/rules/0148/uid-format.md @@ -26,7 +26,7 @@ This rule looks on for fields named `uid` and complains if it does not have the ```proto // Incorrect. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -41,7 +41,7 @@ message Book { ```proto // Correct. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; @@ -59,7 +59,7 @@ comment explaining why. ```proto message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; diff --git a/docs/rules/0164/resource-expire-time-field.md b/docs/rules/0164/resource-expire-time-field.md index b620db7f..7c3c391a 100644 --- a/docs/rules/0164/resource-expire-time-field.md +++ b/docs/rules/0164/resource-expire-time-field.md @@ -34,7 +34,7 @@ service Library { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -59,7 +59,7 @@ service Library { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -88,7 +88,7 @@ service Library { // (-- api-linter: core::0164::resource-expire-time-field=disabled // aep.dev/not-precedent: We need to do this because reasons. --) message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/docs/rules/0164/response-lro.md b/docs/rules/0164/response-lro.md index 56564c62..526ecb33 100644 --- a/docs/rules/0164/response-lro.md +++ b/docs/rules/0164/response-lro.md @@ -17,7 +17,7 @@ operations, as mandated in [AEP-164][]. ## Details This rule looks at any `Undelete` method connected to a resource with a -`google.api.resource` annotation that includes `style: DECLARATIVE_FRIENDLY`, +`aep.api.resource` annotation that includes `style: DECLARATIVE_FRIENDLY`, and complains if it does not use long-running operations. ## Examples diff --git a/example/proto/example/bookstore/v1/bookstore.proto b/example/proto/example/bookstore/v1/bookstore.proto index 4de728a0..0c5346b8 100644 --- a/example/proto/example/bookstore/v1/bookstore.proto +++ b/example/proto/example/bookstore/v1/bookstore.proto @@ -175,7 +175,7 @@ service Bookstore { // A Book. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "bookstore.example.com/book", pattern: [ "publishers/{publisher}/books/{book}" ], plural: "books", @@ -212,7 +212,7 @@ message Book { // A BookEdition. message BookEdition { - option (google.api.resource) = { + option (aep.api.resource) = { type: "bookstore.example.com/book-edition", pattern: [ "publishers/{publisher}/books/{book}/editions/{book-edition}" @@ -230,7 +230,7 @@ message BookEdition { // A Isbn. message Isbn { - option (google.api.resource) = { + option (aep.api.resource) = { type: "bookstore.example.com/isbn", pattern: [ "isbns/{isbn}" ], plural: "isbns", @@ -243,7 +243,7 @@ message Isbn { // A Publisher. message Publisher { - option (google.api.resource) = { + option (aep.api.resource) = { type: "bookstore.example.com/publisher", pattern: [ "publishers/{publisher}" ], plural: "publishers", diff --git a/locations/file_locations.go b/locations/file_locations.go index 988d3454..63b7d256 100644 --- a/locations/file_locations.go +++ b/locations/file_locations.go @@ -72,7 +72,7 @@ func FileRubyPackage(f *desc.FileDescriptor) *dpb.SourceCodeInfo_Location { return pathLocation(f, 8, 45) // 8 == options, 45 == ruby_package } -// FileResourceDefinition returns the precise location of the `google.api.resource_definition` +// FileResourceDefinition returns the precise location of the `aep.api.resource_definition` // annotation. func FileResourceDefinition(f *desc.FileDescriptor, index int) *dpb.SourceCodeInfo_Location { // 8 == options diff --git a/locations/message_locations.go b/locations/message_locations.go index 73679424..4c4cfac3 100644 --- a/locations/message_locations.go +++ b/locations/message_locations.go @@ -20,7 +20,7 @@ import ( dpb "google.golang.org/protobuf/types/descriptorpb" ) -// MessageResource returns the precise location of the `google.api.resource` +// MessageResource returns the precise location of the `aep.api.resource` // annotation. func MessageResource(m *desc.MessageDescriptor) *dpb.SourceCodeInfo_Location { return pathLocation(m, 7, int(apb.E_Resource.TypeDescriptor().Number())) // MessageDescriptor.options == 7 diff --git a/locations/message_locations_test.go b/locations/message_locations_test.go index 22ea52e3..a48836ec 100644 --- a/locations/message_locations_test.go +++ b/locations/message_locations_test.go @@ -24,7 +24,7 @@ func TestMessageResource(t *testing.T) { f := parse(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/rules/aep0004/duplicate_resource.go b/rules/aep0004/duplicate_resource.go index 3f7fced8..23c6e720 100644 --- a/rules/aep0004/duplicate_resource.go +++ b/rules/aep0004/duplicate_resource.go @@ -34,7 +34,7 @@ type resourceDef struct { func (d *resourceDef) String() string { switch d.desc.(type) { case *desc.FileDescriptor: - return fmt.Sprintf("`google.api.resource_definition` %d in file `%s`", d.idx, d.desc.GetFullyQualifiedName()) + return fmt.Sprintf("`aep.api.resource_definition` %d in file `%s`", d.idx, d.desc.GetFullyQualifiedName()) case *desc.MessageDescriptor: return fmt.Sprintf("message `%s`", d.desc.GetFullyQualifiedName()) default: diff --git a/rules/aep0004/duplicate_resource_test.go b/rules/aep0004/duplicate_resource_test.go index 980d2a9a..8f3fa542 100644 --- a/rules/aep0004/duplicate_resource_test.go +++ b/rules/aep0004/duplicate_resource_test.go @@ -27,35 +27,35 @@ func TestDuplicateResource(t *testing.T) { import "google/api/resource.proto"; package xyz; message Publisher { - option (google.api.resource) = { type: "library.googleapis.com/Publisher" }; + option (aep.api.resource) = { type: "library.googleapis.com/Publisher" }; } `, "test.proto": ` import "dep.proto"; import "google/api/resource.proto"; package abc; - option (google.api.resource_definition) = { type: "library.googleapis.com/Publisher" }; - option (google.api.resource_definition) = { type: "library.googleapis.com/Author" }; - option (google.api.resource_definition) = { type: "library.googleapis.com/Editor" }; + option (aep.api.resource_definition) = { type: "library.googleapis.com/Publisher" }; + option (aep.api.resource_definition) = { type: "library.googleapis.com/Author" }; + option (aep.api.resource_definition) = { type: "library.googleapis.com/Editor" }; message Book { - option (google.api.resource) = { type: "library.googleapis.com/Book" }; + option (aep.api.resource) = { type: "library.googleapis.com/Book" }; } message Author { - option (google.api.resource) = { type: "library.googleapis.com/Author" }; + option (aep.api.resource) = { type: "library.googleapis.com/Author" }; } message Foo { message Tome { - option (google.api.resource) = { type: "library.googleapis.com/Book" }; + option (aep.api.resource) = { type: "library.googleapis.com/Book" }; } }`, }, nil)["test.proto"] want := testutils.Problems{ lint.Problem{ - Message: "resource \"library.googleapis.com/Author\": `google.api.resource_definition` 1 in file `test.proto`, message `abc.Author`.", + Message: "resource \"library.googleapis.com/Author\": `aep.api.resource_definition` 1 in file `test.proto`, message `abc.Author`.", Descriptor: f, }, lint.Problem{ - Message: "resource \"library.googleapis.com/Author\": `google.api.resource_definition` 1 in file `test.proto`, message `abc.Author`.", + Message: "resource \"library.googleapis.com/Author\": `aep.api.resource_definition` 1 in file `test.proto`, message `abc.Author`.", Descriptor: f.GetMessageTypes()[1], }, lint.Problem{ diff --git a/rules/aep0004/path_never_optional_test.go b/rules/aep0004/path_never_optional_test.go index d26080e7..5b91b369 100644 --- a/rules/aep0004/path_never_optional_test.go +++ b/rules/aep0004/path_never_optional_test.go @@ -37,7 +37,7 @@ func TestPathNeverOptional(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" name_field: "{{.PathField}}" diff --git a/rules/aep0004/resource_annotation.go b/rules/aep0004/resource_annotation.go index 8f76c649..3f384f3f 100644 --- a/rules/aep0004/resource_annotation.go +++ b/rules/aep0004/resource_annotation.go @@ -27,7 +27,7 @@ var resourceAnnotation = &lint.MessageRule{ LintMessage: func(m *desc.MessageDescriptor) []lint.Problem { if utils.GetResource(m) == nil { return []lint.Problem{{ - Message: "Resource messages should include a `google.api.resource` annotation.", + Message: "Resource messages should include a `aep.api.resource` annotation.", Descriptor: m, }} } diff --git a/rules/aep0004/resource_annotation_test.go b/rules/aep0004/resource_annotation_test.go index cc31f63b..a585013c 100644 --- a/rules/aep0004/resource_annotation_test.go +++ b/rules/aep0004/resource_annotation_test.go @@ -26,7 +26,7 @@ func TestResourceAnnotation(t *testing.T) { f := testutils.ParseProto3String(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -63,7 +63,7 @@ func TestResourceAnnotation(t *testing.T) { {"ValidNoNameField", "Book", "title", testutils.Problems{}}, {"ValidRequestMessage", "GetBookRequest", "path", testutils.Problems{}}, {"ValidResponseMessage", "GetBookResponse", "path", testutils.Problems{}}, - {"Invalid", "Book", "path", testutils.Problems{{Message: "google.api.resource"}}}, + {"Invalid", "Book", "path", testutils.Problems{{Message: "aep.api.resource"}}}, } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` diff --git a/rules/aep0004/resource_definition_pattern_test.go b/rules/aep0004/resource_definition_pattern_test.go index c9199c6f..47c8bc0a 100644 --- a/rules/aep0004/resource_definition_pattern_test.go +++ b/rules/aep0004/resource_definition_pattern_test.go @@ -37,7 +37,7 @@ func TestResourceDefinitionPattern(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; - option (google.api.resource_definition) = { + option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" {{.Pattern}} }; diff --git a/rules/aep0004/resource_definition_type_name_test.go b/rules/aep0004/resource_definition_type_name_test.go index 9cb03fbc..78c1ca0b 100644 --- a/rules/aep0004/resource_definition_type_name_test.go +++ b/rules/aep0004/resource_definition_type_name_test.go @@ -33,7 +33,7 @@ func TestResourceDefinitionTypeName(t *testing.T) { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; - option (google.api.resource_definition) = { + option (aep.api.resource_definition) = { type: "{{ .TypeName }}" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/rules/aep0004/resource_definition_variables_test.go b/rules/aep0004/resource_definition_variables_test.go index 6b12ffb0..73a8e654 100644 --- a/rules/aep0004/resource_definition_variables_test.go +++ b/rules/aep0004/resource_definition_variables_test.go @@ -35,7 +35,7 @@ func TestResourceDefinitionVariables(t *testing.T) { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; - option (google.api.resource_definition) = { + option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" pattern: "{{.Pattern}}" }; diff --git a/rules/aep0004/resource_name_components_alternate_test.go b/rules/aep0004/resource_name_components_alternate_test.go index 55866311..550c40d3 100644 --- a/rules/aep0004/resource_name_components_alternate_test.go +++ b/rules/aep0004/resource_name_components_alternate_test.go @@ -37,7 +37,7 @@ func TestResourceNameComponentsAlternate(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "{{ .Pattern }}" }; diff --git a/rules/aep0004/resource_path_field_test.go b/rules/aep0004/resource_path_field_test.go index c18fbce4..fc390614 100644 --- a/rules/aep0004/resource_path_field_test.go +++ b/rules/aep0004/resource_path_field_test.go @@ -29,12 +29,12 @@ func TestResourceNameField(t *testing.T) { Field string problems testutils.Problems }{ - {"ValidBothPresent", `option (google.api.resource) = { type: "foo" };`, `string path = 1;`, nil}, - {"InvalidNoField", `option (google.api.resource) = { type: "foo" };`, ``, testutils.Problems{{Message: "`path`"}}}, - {"InvalidTypeNotString", `option (google.api.resource) = { type: "foo" };`, `int32 path = 1;`, testutils.Problems{{Suggestion: "string"}}}, - {"InvalidTypeRepeated", `option (google.api.resource) = { type: "foo" };`, `repeated string path = 1;`, testutils.Problems{{Suggestion: "string"}}}, + {"ValidBothPresent", `option (aep.api.resource) = { type: "foo" };`, `string path = 1;`, nil}, + {"InvalidNoField", `option (aep.api.resource) = { type: "foo" };`, ``, testutils.Problems{{Message: "`path`"}}}, + {"InvalidTypeNotString", `option (aep.api.resource) = { type: "foo" };`, `int32 path = 1;`, testutils.Problems{{Suggestion: "string"}}}, + {"InvalidTypeRepeated", `option (aep.api.resource) = { type: "foo" };`, `repeated string path = 1;`, testutils.Problems{{Suggestion: "string"}}}, {"IrrelevantNoAnnotation", ``, ``, nil}, - {"ValidNameField", `option (google.api.resource) = { type: "foo" name_field: "other_path"};`, "string other_path = 1;", nil}, + {"ValidNameField", `option (aep.api.resource) = { type: "foo" name_field: "other_path"};`, "string other_path = 1;", nil}, } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` diff --git a/rules/aep0004/resource_pattern_test.go b/rules/aep0004/resource_pattern_test.go index 64d92d0d..0df0d1e8 100644 --- a/rules/aep0004/resource_pattern_test.go +++ b/rules/aep0004/resource_pattern_test.go @@ -41,7 +41,7 @@ func TestResourcePattern(t *testing.T) { import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" {{.Pattern}} }; diff --git a/rules/aep0004/resource_plural_test.go b/rules/aep0004/resource_plural_test.go index 6b43c017..552e9bb4 100644 --- a/rules/aep0004/resource_plural_test.go +++ b/rules/aep0004/resource_plural_test.go @@ -56,7 +56,7 @@ func TestResourcePlural(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/BookShelf" pattern: "publishers/{publisher}/bookShelves/{book_shelf}" {{.Plural}} diff --git a/rules/aep0004/resource_singular_test.go b/rules/aep0004/resource_singular_test.go index 8fda172a..8275f522 100644 --- a/rules/aep0004/resource_singular_test.go +++ b/rules/aep0004/resource_singular_test.go @@ -49,7 +49,7 @@ func TestResourceSingular(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" {{.Singular}} diff --git a/rules/aep0004/resource_type_name_test.go b/rules/aep0004/resource_type_name_test.go index f7c25121..6e35ea11 100644 --- a/rules/aep0004/resource_type_name_test.go +++ b/rules/aep0004/resource_type_name_test.go @@ -41,7 +41,7 @@ func TestResourceTypeName(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "{{ .TypeName }}" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/rules/aep0004/resource_variables.go b/rules/aep0004/resource_variables.go index 2af7f244..f8fd28c5 100644 --- a/rules/aep0004/resource_variables.go +++ b/rules/aep0004/resource_variables.go @@ -39,8 +39,8 @@ var resourceVariables = &lint.MessageRule{ // lintResourceVariables lints the resource ID segments of the pattern(s) in the // give ResourceDescriptor. This is used for both the file-level annotation -// google.api.resource_definition and the message-level annotation -// google.api.resource. +// aep.api.resource_definition and the message-level annotation +// aep.api.resource. func lintResourceVariables(resource *annotations.ResourceDescriptor, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { for _, pattern := range resource.GetPattern() { for _, variable := range getVariables(pattern) { diff --git a/rules/aep0004/resource_variables_test.go b/rules/aep0004/resource_variables_test.go index 87f0e83a..b51e2091 100644 --- a/rules/aep0004/resource_variables_test.go +++ b/rules/aep0004/resource_variables_test.go @@ -36,7 +36,7 @@ func TestResourceVariables(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "{{.Pattern}}" }; diff --git a/rules/aep0121/no_mutable_cycles_test.go b/rules/aep0121/no_mutable_cycles_test.go index ca185d59..3ea10e3f 100644 --- a/rules/aep0121/no_mutable_cycles_test.go +++ b/rules/aep0121/no_mutable_cycles_test.go @@ -108,7 +108,7 @@ func TestNoMutableCycles(t *testing.T) { import "google/api/resource.proto"; import "aep/api/field_info.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -118,7 +118,7 @@ func TestNoMutableCycles(t *testing.T) { } message Publisher { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Publisher" pattern: "publishers/{publisher}" }; @@ -130,7 +130,7 @@ func TestNoMutableCycles(t *testing.T) { } message Library { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Library" pattern: "libraries/{library}" }; diff --git a/rules/aep0121/resource_must_support_get_test.go b/rules/aep0121/resource_must_support_get_test.go index a5cb3235..6f0cecee 100644 --- a/rules/aep0121/resource_must_support_get_test.go +++ b/rules/aep0121/resource_must_support_get_test.go @@ -23,7 +23,7 @@ import ( // TestResourceMustSupportGet tests the resourceMustSupportGet // lint rule by declaring a service proto, then declaring a -// google.api.resource message, then declaring non-Get +// aep.api.resource message, then declaring non-Get // methods. func TestResourceMustSupportGet(t *testing.T) { for _, test := range []struct { @@ -100,7 +100,7 @@ func TestResourceMustSupportGet(t *testing.T) { // This is at the top to make it retrievable // by the test code. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" singular: "book" diff --git a/rules/aep0121/resource_must_support_list_test.go b/rules/aep0121/resource_must_support_list_test.go index f939df74..80382d4a 100644 --- a/rules/aep0121/resource_must_support_list_test.go +++ b/rules/aep0121/resource_must_support_list_test.go @@ -23,7 +23,7 @@ import ( // TestResourceMustSupportList tests the resourceMustSupportList // lint rule by declaring a service proto, then declaring a -// google.api.resource message, then declaring non-List +// aep.api.resource message, then declaring non-List // methods. func TestResourceMustSupportList(t *testing.T) { for _, test := range []struct { @@ -97,7 +97,7 @@ func TestResourceMustSupportList(t *testing.T) { // This is at the top to make it retrievable // by the test code. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" singular: "book" @@ -106,7 +106,7 @@ func TestResourceMustSupportList(t *testing.T) { } message BookCover { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/BookCover" pattern: "books/{book}/bookCover" singular: "bookCover" diff --git a/rules/aep0122/no_self_links_test.go b/rules/aep0122/no_self_links_test.go index b356e3d4..8c0547f9 100644 --- a/rules/aep0122/no_self_links_test.go +++ b/rules/aep0122/no_self_links_test.go @@ -33,7 +33,7 @@ func TestNoSelfLinks(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" }; string name = 1; diff --git a/rules/aep0122/resource_collection_identifiers_test.go b/rules/aep0122/resource_collection_identifiers_test.go index dfb70af9..030f5f0d 100644 --- a/rules/aep0122/resource_collection_identifiers_test.go +++ b/rules/aep0122/resource_collection_identifiers_test.go @@ -37,7 +37,7 @@ func TestResourceCollectionIdentifiers(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" pattern: "{{ .Pattern }}" diff --git a/rules/aep0122/resource_id_output_only_test.go b/rules/aep0122/resource_id_output_only_test.go index af3c96e6..640014b5 100644 --- a/rules/aep0122/resource_id_output_only_test.go +++ b/rules/aep0122/resource_id_output_only_test.go @@ -38,7 +38,7 @@ func TestResourceIdOutputOnly(t *testing.T) { import "aep/api/field_info.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" }; diff --git a/rules/aep0127/http_template_pattern_test.go b/rules/aep0127/http_template_pattern_test.go index e096f710..5f28f24e 100644 --- a/rules/aep0127/http_template_pattern_test.go +++ b/rules/aep0127/http_template_pattern_test.go @@ -71,7 +71,7 @@ func TestHttpTemplatePattern_PatternMatching(t *testing.T) { string path = 1 [(aep.api.field_info).resource_reference = "library.googleapis.com/Book"]; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "{{.ResourcePattern}}" }; @@ -115,7 +115,7 @@ func TestHttpTemplatePattern_MultiplePatterns(t *testing.T) { string path = 1 [(aep.api.field_info).resource_reference = "library.googleapis.com/Book"]; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "{{.ResourcePattern1}}" pattern: "{{.ResourcePattern2}}" @@ -143,7 +143,7 @@ func TestHttpTemplatePattern_SkipCheckIfNoHTTPRules(t *testing.T) { string path = 1 [(aep.api.field_info).resource_reference = "library.googleapis.com/Book"]; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" }; string path = 1; @@ -170,7 +170,7 @@ func TestHttpTemplatePattern_SkipCheckIfHTTPRuleHasNoVariables(t *testing.T) { string path = 1 [(aep.api.field_info).resource_reference = "library.googleapis.com/Book"]; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" }; string path = 1; @@ -197,7 +197,7 @@ func TestHttpTemplatePattern_SkipCheckIfFieldPathMissingResourceAnnotation(t *te string path = 1; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" }; string path = 1; diff --git a/rules/aep0131/request_required_fields_test.go b/rules/aep0131/request_required_fields_test.go index 60490f6b..055e1f5f 100644 --- a/rules/aep0131/request_required_fields_test.go +++ b/rules/aep0131/request_required_fields_test.go @@ -83,7 +83,7 @@ func TestRequiredFieldTests(t *testing.T) { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/rules/aep0132/request_parent_required_test.go b/rules/aep0132/request_parent_required_test.go index 28d6611e..55f8b570 100644 --- a/rules/aep0132/request_parent_required_test.go +++ b/rules/aep0132/request_parent_required_test.go @@ -51,7 +51,7 @@ func TestRequestParentRequired(t *testing.T) { repeated Book books = 1; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { pattern: "books/{book}" }; string path = 1; diff --git a/rules/aep0132/request_parent_valid_reference_test.go b/rules/aep0132/request_parent_valid_reference_test.go index 7eb5e519..0c9d5f23 100644 --- a/rules/aep0132/request_parent_valid_reference_test.go +++ b/rules/aep0132/request_parent_valid_reference_test.go @@ -41,7 +41,7 @@ func TestRequestParentValidReference(t *testing.T) { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/rules/aep0132/request_required_fields_test.go b/rules/aep0132/request_required_fields_test.go index fdd4f1b7..2b842502 100644 --- a/rules/aep0132/request_required_fields_test.go +++ b/rules/aep0132/request_required_fields_test.go @@ -87,7 +87,7 @@ func TestRequiredFieldTests(t *testing.T) { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/rules/aep0132/resource_reference_type_test.go b/rules/aep0132/resource_reference_type_test.go index 2a2e8d27..58ca2f1f 100644 --- a/rules/aep0132/resource_reference_type_test.go +++ b/rules/aep0132/resource_reference_type_test.go @@ -22,7 +22,7 @@ import ( func TestResourceReferenceType(t *testing.T) { bookResource := ` -option (google.api.resource) = { +option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "shelves/{shelf}/books/{book}" }; diff --git a/rules/aep0133/http_uri_parent_test.go b/rules/aep0133/http_uri_parent_test.go index d6cf3ce9..ff75c28b 100644 --- a/rules/aep0133/http_uri_parent_test.go +++ b/rules/aep0133/http_uri_parent_test.go @@ -50,7 +50,7 @@ func TestHTTPURIParent(t *testing.T) { } message {{.MethodName}}Request {} message Book { - option (google.api.resource) = { + option (aep.api.resource) = { pattern: "{{.Pattern}}" }; } @@ -78,7 +78,7 @@ func TestHTTPURIParent(t *testing.T) { } message {{.MethodName}}Request {} message Book { - option (google.api.resource) = { + option (aep.api.resource) = { pattern: "{{.Pattern}}" }; } @@ -108,7 +108,7 @@ func TestHTTPURIParent(t *testing.T) { } message CreateBookRequest {} message Book { - option (google.api.resource) = { + option (aep.api.resource) = { pattern: "publishers/{publisher}/books/{book}" }; } diff --git a/rules/aep0133/http_uri_resource_test.go b/rules/aep0133/http_uri_resource_test.go index 9a683e8b..7bc6fe4a 100644 --- a/rules/aep0133/http_uri_resource_test.go +++ b/rules/aep0133/http_uri_resource_test.go @@ -51,7 +51,7 @@ func TestHTTPURIResource(t *testing.T) { } message CreateBookRequest {} message Book { - option (google.api.resource) = { + option (aep.api.resource) = { pattern: "{{.Pattern}}" }; } diff --git a/rules/aep0133/method_signature_test.go b/rules/aep0133/method_signature_test.go index f395da4b..e0906132 100644 --- a/rules/aep0133/method_signature_test.go +++ b/rules/aep0133/method_signature_test.go @@ -100,7 +100,7 @@ func TestMethodSignature(t *testing.T) { string book_id = 2; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { pattern: "books/{book}" }; } diff --git a/rules/aep0133/request_id_field_test.go b/rules/aep0133/request_id_field_test.go index 8450d7bb..4d62375d 100644 --- a/rules/aep0133/request_id_field_test.go +++ b/rules/aep0133/request_id_field_test.go @@ -42,7 +42,7 @@ func TestRequestIDField(t *testing.T) { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/rules/aep0133/request_parent_required_test.go b/rules/aep0133/request_parent_required_test.go index ff9c45ac..1de7869f 100644 --- a/rules/aep0133/request_parent_required_test.go +++ b/rules/aep0133/request_parent_required_test.go @@ -45,7 +45,7 @@ func TestRequestParentFieldRequired(t *testing.T) { Book book = 2; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { pattern: "books/{book}" }; string name = 1; diff --git a/rules/aep0133/request_required_fields_test.go b/rules/aep0133/request_required_fields_test.go index adcdb2ec..ee238141 100644 --- a/rules/aep0133/request_required_fields_test.go +++ b/rules/aep0133/request_required_fields_test.go @@ -100,7 +100,7 @@ func TestRequiredFieldTests(t *testing.T) { } message BookShelf { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/BookShelf" pattern: "publishers/{publisher}/bookShelves/{book_shelf}" singular: "{{.Singular}}" diff --git a/rules/aep0133/resource_reference_type_test.go b/rules/aep0133/resource_reference_type_test.go index bd995797..159b91ef 100644 --- a/rules/aep0133/resource_reference_type_test.go +++ b/rules/aep0133/resource_reference_type_test.go @@ -47,7 +47,7 @@ func TestResourceReferenceType(t *testing.T) { string parent = 1 [(aep.api.field_info).{{ .Annotation }}]; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "shelves/{shelf}/books/{book}" }; @@ -97,7 +97,7 @@ func TestResourceReferenceTypeLRO(t *testing.T) { string parent = 1 [(aep.api.field_info).{{ .Annotation }}]; } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "shelves/{shelf}/books/{book}" }; diff --git a/rules/aep0134/request_allow_missing_field_test.go b/rules/aep0134/request_allow_missing_field_test.go index d432d2ad..b55eb4a9 100644 --- a/rules/aep0134/request_allow_missing_field_test.go +++ b/rules/aep0134/request_allow_missing_field_test.go @@ -52,7 +52,7 @@ func TestAllowMissing(t *testing.T) { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "{{.Pattern}}" {{.Style}} diff --git a/rules/aep0134/request_required_fields_test.go b/rules/aep0134/request_required_fields_test.go index badcdb86..38f5dba6 100644 --- a/rules/aep0134/request_required_fields_test.go +++ b/rules/aep0134/request_required_fields_test.go @@ -94,7 +94,7 @@ func TestRequiredFieldTests(t *testing.T) { } message BookShelf { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/BookShelf" pattern: "publishers/{publisher}/bookShelves/{book_shelf}" }; diff --git a/rules/aep0134/response_lro_test.go b/rules/aep0134/response_lro_test.go index 99a4ccea..c87c7c5c 100644 --- a/rules/aep0134/response_lro_test.go +++ b/rules/aep0134/response_lro_test.go @@ -42,7 +42,7 @@ func TestResponseLRO(t *testing.T) { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" {{.Style}} diff --git a/rules/aep0135/force_field_test.go b/rules/aep0135/force_field_test.go index 604a5ad4..e28b36f1 100644 --- a/rules/aep0135/force_field_test.go +++ b/rules/aep0135/force_field_test.go @@ -39,7 +39,7 @@ func TestForceField(t *testing.T) { import "aep/api/field_info.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -48,7 +48,7 @@ func TestForceField(t *testing.T) { } message Publisher { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Publisher" pattern: "publishers/{publisher}" }; diff --git a/rules/aep0135/response_lro_test.go b/rules/aep0135/response_lro_test.go index 639260e0..5131319c 100644 --- a/rules/aep0135/response_lro_test.go +++ b/rules/aep0135/response_lro_test.go @@ -42,7 +42,7 @@ func TestResponseLRO(t *testing.T) { } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" {{.Style}} diff --git a/rules/aep0135/response_message_name_test.go b/rules/aep0135/response_message_name_test.go index 0ff37aef..ad3539a9 100644 --- a/rules/aep0135/response_message_name_test.go +++ b/rules/aep0135/response_message_name_test.go @@ -31,7 +31,7 @@ func TestResponseMessageName(t *testing.T) { } message {{.MethodName}}Request {} message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" {{.Style}} @@ -56,7 +56,7 @@ func TestResponseMessageName(t *testing.T) { } message {{.MethodName}}Request {} message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" {{.Style}} diff --git a/rules/aep0136/declarative_standard_methods_only_test.go b/rules/aep0136/declarative_standard_methods_only_test.go index b5e8a590..958ca688 100644 --- a/rules/aep0136/declarative_standard_methods_only_test.go +++ b/rules/aep0136/declarative_standard_methods_only_test.go @@ -51,7 +51,7 @@ func TestDeclarativeFriendly(t *testing.T) { message {{.MethodName}}Response {} message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" style: DECLARATIVE_FRIENDLY diff --git a/rules/aep0148/declarative_friendly_fields_test.go b/rules/aep0148/declarative_friendly_fields_test.go index 2335df51..2033ba60 100644 --- a/rules/aep0148/declarative_friendly_fields_test.go +++ b/rules/aep0148/declarative_friendly_fields_test.go @@ -82,7 +82,7 @@ func TestDeclarativeFriendlyFields(t *testing.T) { import "google/api/resource.proto"; import "google/protobuf/timestamp.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" {{.Style}} @@ -125,7 +125,7 @@ func TestDeclarativeFriendlyFieldsSingleton(t *testing.T) { import "google/api/resource.proto"; import "google/protobuf/timestamp.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Settings" pattern: "publishers/{publisher}/settings" style: DECLARATIVE_FRIENDLY diff --git a/rules/aep0148/field_behavior_test.go b/rules/aep0148/field_behavior_test.go index 8316c743..783632a8 100644 --- a/rules/aep0148/field_behavior_test.go +++ b/rules/aep0148/field_behavior_test.go @@ -21,7 +21,7 @@ import ( ) func TestFieldBehavior(t *testing.T) { - const messageOptsResource = `option (google.api.resource).type = "library.googleapis.com/Book";` + const messageOptsResource = `option (aep.api.resource).type = "library.googleapis.com/Book";` const fieldOptsOutputOnly = `[(aep.api.field_info).field_behavior = FIELD_BEHAVIOR_OUTPUT_ONLY]` missingOutputOnly := testutils.Problems{{Message: "OUTPUT_ONLY"}} diff --git a/rules/aep0164/response_lro_test.go b/rules/aep0164/response_lro_test.go index c4c16491..814d6952 100644 --- a/rules/aep0164/response_lro_test.go +++ b/rules/aep0164/response_lro_test.go @@ -40,7 +40,7 @@ func TestResponseLRO(t *testing.T) { rpc UndeleteBook(UndeleteBookRequest) returns ({{.ResponseType}}); } message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" {{.Style}} diff --git a/rules/internal/utils/declarative_friendly.go b/rules/internal/utils/declarative_friendly.go index e4138e71..a4ccf624 100644 --- a/rules/internal/utils/declarative_friendly.go +++ b/rules/internal/utils/declarative_friendly.go @@ -27,10 +27,10 @@ import ( // associated with this descriptor. // // For messages: -// If the message is annotated with google.api.resource and +// If the message is annotated with aep.api.resource and // style: DECLARATIVE_FRIENDLY is set, that message is returned. // If the message is a standard method request message for a resource with -// google.api.resource and style:DECLARATIVE_FRIENDLY set, then the resource +// aep.api.resource and style:DECLARATIVE_FRIENDLY set, then the resource // is returned. // // For methods: @@ -48,7 +48,7 @@ import ( func DeclarativeFriendlyResource(d desc.Descriptor) *desc.MessageDescriptor { switch m := d.(type) { case *desc.MessageDescriptor: - // Get the google.api.resource annotation and see if it is styled + // Get the aep.api.resource annotation and see if it is styled // declarative-friendly. if resource := GetResource(m); resource != nil { for _, style := range resource.GetStyle() { @@ -96,7 +96,7 @@ func DeclarativeFriendlyResource(d desc.Descriptor) *desc.MessageDescriptor { } } - // If the return value has a google.api.resource annotation, we can + // If the return value has a aep.api.resource annotation, we can // assume it is the resource and check it. if IsResource(response) { return DeclarativeFriendlyResource(response) diff --git a/rules/internal/utils/declarative_friendly_test.go b/rules/internal/utils/declarative_friendly_test.go index 0eb662f2..f901f571 100644 --- a/rules/internal/utils/declarative_friendly_test.go +++ b/rules/internal/utils/declarative_friendly_test.go @@ -22,7 +22,7 @@ import ( ) func TestDeclarativeFriendlyMessage(t *testing.T) { - // Test the cases where a google.api.resource annotation is present. + // Test the cases where a aep.api.resource annotation is present. for _, test := range []struct { name string Style string @@ -37,7 +37,7 @@ func TestDeclarativeFriendlyMessage(t *testing.T) { import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" {{.Style}} }; @@ -61,7 +61,7 @@ func TestDeclarativeFriendlyMessage(t *testing.T) { }) } - // Test the case where the google.api.resource annotation is not present. + // Test the case where the aep.api.resource annotation is not present. t.Run("NotResource", func(t *testing.T) { m := testutils.ParseProto3String(t, "message Book {}").GetMessageTypes()[0] if IsDeclarativeFriendlyMessage(m) { @@ -159,7 +159,7 @@ func TestDeclarativeFriendlyMethod(t *testing.T) { %s message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" {{.Style}} }; diff --git a/rules/internal/utils/extension.go b/rules/internal/utils/extension.go index 361c20b8..ef515f2b 100644 --- a/rules/internal/utils/extension.go +++ b/rules/internal/utils/extension.go @@ -147,7 +147,7 @@ func GetMethodSignatures(m *desc.MethodDescriptor) [][]string { return answer } -// GetResource returns the google.api.resource annotation. +// GetResource returns the aep.api.resource annotation. func GetResource(m *desc.MessageDescriptor) *apb.ResourceDescriptor { if m == nil { return nil @@ -159,7 +159,7 @@ func GetResource(m *desc.MessageDescriptor) *apb.ResourceDescriptor { return nil } -// IsResource returns true if the message has a populated google.api.resource +// IsResource returns true if the message has a populated aep.api.resource // annotation with a non-empty "type" field. func IsResource(m *desc.MessageDescriptor) bool { if res := GetResource(m); res != nil { @@ -184,7 +184,7 @@ func IsSingletonResource(m *desc.MessageDescriptor) bool { return false } -// GetResourceDefinitions returns the google.api.resource_definition annotations +// GetResourceDefinitions returns the aep.api.resource_definition annotations // for a file. func GetResourceDefinitions(f *desc.FileDescriptor) []*apb.ResourceDescriptor { opts := f.GetFileOptions() diff --git a/rules/internal/utils/extension_test.go b/rules/internal/utils/extension_test.go index 4ee2d43a..8a9c5d1c 100644 --- a/rules/internal/utils/extension_test.go +++ b/rules/internal/utils/extension_test.go @@ -218,7 +218,7 @@ func TestGetResource(t *testing.T) { f := testutils.ParseProto3String(t, ` import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -257,7 +257,7 @@ func TestGetResourceDefinition(t *testing.T) { t.Run("One", func(t *testing.T) { f := testutils.ParseProto3String(t, ` import "google/api/resource.proto"; - option (google.api.resource_definition) = { + option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" }; `) @@ -272,10 +272,10 @@ func TestGetResourceDefinition(t *testing.T) { t.Run("Two", func(t *testing.T) { f := testutils.ParseProto3String(t, ` import "google/api/resource.proto"; - option (google.api.resource_definition) = { + option (aep.api.resource_definition) = { type: "library.googleapis.com/Book" }; - option (google.api.resource_definition) = { + option (aep.api.resource_definition) = { type: "library.googleapis.com/Author" }; `) @@ -324,7 +324,7 @@ func TestFindResource(t *testing.T) { import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -340,7 +340,7 @@ func TestFindResource(t *testing.T) { import "google/api/resource.proto"; message Shelf { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Shelf" pattern: "shelves/{shelf}" }; @@ -385,7 +385,7 @@ func TestFindResourceMessage(t *testing.T) { import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -401,7 +401,7 @@ func TestFindResourceMessage(t *testing.T) { import "google/api/resource.proto"; message Shelf { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Shelf" pattern: "shelves/{shelf}" }; @@ -498,7 +498,7 @@ func TestGetOutputOrLROResponseMessage(t *testing.T) { // This is at the top to make it retrievable // by the test code. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" singular: "book" @@ -568,7 +568,7 @@ func TestFindResourceChildren(t *testing.T) { import "google/api/resource.proto"; message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" }; @@ -577,7 +577,7 @@ func TestFindResourceChildren(t *testing.T) { } message Edition { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Edition" pattern: "publishers/{publisher}/books/{book}/editions/{edition}" }; @@ -593,7 +593,7 @@ func TestFindResourceChildren(t *testing.T) { import "google/api/resource.proto"; message Shelf { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Shelf" pattern: "shelves/{shelf}" }; diff --git a/rules/internal/utils/method_test.go b/rules/internal/utils/method_test.go index c2fbf10d..ebd0f88e 100644 --- a/rules/internal/utils/method_test.go +++ b/rules/internal/utils/method_test.go @@ -43,7 +43,7 @@ func TestIsCreateMethod(t *testing.T) { // This is at the top to make it retrievable // by the test code. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" singular: "book" @@ -93,7 +93,7 @@ func TestIsUpdateMethod(t *testing.T) { // This is at the top to make it retrievable // by the test code. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" singular: "book" @@ -142,7 +142,7 @@ func TestIsListMethod(t *testing.T) { // This is at the top to make it retrievable // by the test code. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" singular: "book" @@ -153,7 +153,7 @@ func TestIsListMethod(t *testing.T) { // This is at the top to make it retrievable // by the test code. message BookRevision { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/BookRevision" pattern: "books/{book}/revisions/{revision}" singular: "bookRevision" @@ -224,7 +224,7 @@ func TestIsLegacyListRevisionsMethod(t *testing.T) { // This is at the top to make it retrievable // by the test code. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" singular: "book" @@ -287,7 +287,7 @@ func TestGetListResourceMessage(t *testing.T) { // This is at the top to make it retrievable // by the test code. message Book { - option (google.api.resource) = { + option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "books/{book}" singular: "book" diff --git a/rules/internal/utils/resource_test.go b/rules/internal/utils/resource_test.go index 07cfd63c..fa9ab761 100644 --- a/rules/internal/utils/resource_test.go +++ b/rules/internal/utils/resource_test.go @@ -112,7 +112,7 @@ func TestIsResourceRevision(t *testing.T) { { name: "valid_revision", Message: "BookRevision", - Resource: `option (google.api.resource) = {type: "library.googleapis.com/BookRevision"};`, + Resource: `option (aep.api.resource) = {type: "library.googleapis.com/BookRevision"};`, want: true, }, { @@ -123,7 +123,7 @@ func TestIsResourceRevision(t *testing.T) { { name: "not_revision_bad_name", Message: "Book", - Resource: `option (google.api.resource) = {type: "library.googleapis.com/Book"};`, + Resource: `option (aep.api.resource) = {type: "library.googleapis.com/Book"};`, want: false, }, } { From 757ad0fbc9d6523123a724676130ebb1976bad76 Mon Sep 17 00:00:00 2001 From: Alex Stephen Date: Sun, 9 Nov 2025 20:01:27 -0800 Subject: [PATCH 2/4] Change out functions --- go.mod | 2 +- go.sum | 2 ++ rules/aep0004/path_never_optional.go | 4 ++-- rules/aep0004/resource_definition_pattern.go | 2 +- .../aep0004/resource_definition_variables.go | 2 +- rules/aep0004/resource_path_field.go | 2 +- rules/aep0004/resource_pattern.go | 18 +++++++++++---- rules/aep0004/resource_variables.go | 19 +++++++++++----- rules/aep0132/resource_reference_type.go | 4 ++-- rules/internal/utils/declarative_friendly.go | 13 +++-------- rules/internal/utils/extension.go | 17 +++++++------- rules/internal/utils/extension_test.go | 16 +++++++------- rules/internal/utils/resource.go | 19 ++++++++-------- rules/internal/utils/resource_test.go | 22 +++++++++---------- 14 files changed, 78 insertions(+), 64 deletions(-) diff --git a/go.mod b/go.mod index d1f6a7f1..b8c72413 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.0 require ( bitbucket.org/creachadair/stringset v0.0.14 - buf.build/gen/go/aep/api/protocolbuffers/go v1.36.10-20251102152130-5f3e69139afa.1 + buf.build/gen/go/aep/api/protocolbuffers/go v1.36.10-20251109183837-26a011a354ee.1 buf.build/go/bufplugin v0.9.0 cloud.google.com/go/longrunning v0.7.0 github.com/bmatcuk/doublestar/v4 v4.9.1 diff --git a/go.sum b/go.sum index e8a614c1..87eac563 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ buf.build/gen/go/aep/api/protocolbuffers/go v1.36.10-20251016045117-f9844266f27f buf.build/gen/go/aep/api/protocolbuffers/go v1.36.10-20251016045117-f9844266f27f.1/go.mod h1:JOZpZ+zS3G2OKO02hKlEazAGR5X9uVpFyeCamXBXg5c= buf.build/gen/go/aep/api/protocolbuffers/go v1.36.10-20251102152130-5f3e69139afa.1 h1:SEKgDODwWdsVL9nnOPkFBlZ9wAuO7kRQNobSZb5JR7I= buf.build/gen/go/aep/api/protocolbuffers/go v1.36.10-20251102152130-5f3e69139afa.1/go.mod h1:JOZpZ+zS3G2OKO02hKlEazAGR5X9uVpFyeCamXBXg5c= +buf.build/gen/go/aep/api/protocolbuffers/go v1.36.10-20251109183837-26a011a354ee.1 h1:hvHgJH3scOHSRm9nC9JOdesPF9yc7Fl281TNQe60SL0= +buf.build/gen/go/aep/api/protocolbuffers/go v1.36.10-20251109183837-26a011a354ee.1/go.mod h1:JOZpZ+zS3G2OKO02hKlEazAGR5X9uVpFyeCamXBXg5c= buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.10-20250718181942-e35f9b667443.1 h1:FzJGrb8r7vir+P3zJ5Ebey8p54LYTYtQsrM/U35YO9Q= buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.10-20250718181942-e35f9b667443.1/go.mod h1:E6HwqUm4Ag7bXtg/tX7jHWO7CgpknbmeACgDax0icV0= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20250912141014-52f32327d4b0.1 h1:31on4W/yPcV4nZHL4+UCiCvLPsMqe/vJcNg8Rci0scc= diff --git a/rules/aep0004/path_never_optional.go b/rules/aep0004/path_never_optional.go index 6b55d427..5c146d49 100644 --- a/rules/aep0004/path_never_optional.go +++ b/rules/aep0004/path_never_optional.go @@ -26,14 +26,14 @@ var pathNeverOptional = &lint.MessageRule{ RuleType: lint.NewRuleType(lint.MustRule), OnlyIf: func(m *desc.MessageDescriptor) bool { f := "path" - if nf := utils.GetResource(m).GetNameField(); nf != "" { + if nf := utils.GetResourceNameField(utils.GetResource(m)); nf != "" { f = nf } return utils.IsResource(m) && m.FindFieldByName(f) != nil }, LintMessage: func(m *desc.MessageDescriptor) []lint.Problem { f := "path" - if nf := utils.GetResource(m).GetNameField(); nf != "" { + if nf := utils.GetResourceNameField(utils.GetResource(m)); nf != "" { f = nf } field := m.FindFieldByName(f) diff --git a/rules/aep0004/resource_definition_pattern.go b/rules/aep0004/resource_definition_pattern.go index a6ba7c89..8de97afe 100644 --- a/rules/aep0004/resource_definition_pattern.go +++ b/rules/aep0004/resource_definition_pattern.go @@ -31,7 +31,7 @@ var resourceDefinitionPatterns = &lint.FileRule{ for ndx, resource := range resources { loc := locations.FileResourceDefinition(f, ndx) - probs := lintResourcePattern(resource, f, loc) + probs := lintResourcePatternGoogleAPI(resource, f, loc) problems = append(problems, probs...) } return problems diff --git a/rules/aep0004/resource_definition_variables.go b/rules/aep0004/resource_definition_variables.go index 490d93fa..49eaea9a 100644 --- a/rules/aep0004/resource_definition_variables.go +++ b/rules/aep0004/resource_definition_variables.go @@ -31,7 +31,7 @@ var resourceDefinitionVariables = &lint.FileRule{ for ndx, resource := range resources { loc := locations.FileResourceDefinition(f, ndx) - p := lintResourceVariables(resource, f, loc) + p := lintResourceVariablesGoogleAPI(resource, f, loc) problems = append(problems, p...) } return problems diff --git a/rules/aep0004/resource_path_field.go b/rules/aep0004/resource_path_field.go index c0dbc266..8f012d7e 100644 --- a/rules/aep0004/resource_path_field.go +++ b/rules/aep0004/resource_path_field.go @@ -26,7 +26,7 @@ var resourcePathField = &lint.MessageRule{ RuleType: lint.NewRuleType(lint.MustRule), LintMessage: func(m *desc.MessageDescriptor) []lint.Problem { f := "path" - if nf := utils.GetResource(m).GetNameField(); nf != "" { + if nf := utils.GetResourceNameField(utils.GetResource(m)); nf != "" { f = nf } diff --git a/rules/aep0004/resource_pattern.go b/rules/aep0004/resource_pattern.go index 436ec6c7..b5e07a7a 100644 --- a/rules/aep0004/resource_pattern.go +++ b/rules/aep0004/resource_pattern.go @@ -18,11 +18,12 @@ import ( "fmt" "strings" + aepapi "buf.build/gen/go/aep/api/protocolbuffers/go/aep/api" "github.com/aep-dev/api-linter/lint" "github.com/aep-dev/api-linter/locations" "github.com/aep-dev/api-linter/rules/internal/utils" "github.com/jhump/protoreflect/desc" - "google.golang.org/genproto/googleapis/api/annotations" + apb "google.golang.org/genproto/googleapis/api/annotations" dpb "google.golang.org/protobuf/types/descriptorpb" ) @@ -36,9 +37,18 @@ var resourcePattern = &lint.MessageRule{ }, } -func lintResourcePattern(resource *annotations.ResourceDescriptor, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { +func lintResourcePattern(resource *aepapi.ResourceDescriptor, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { + return lintResourcePatternCommon(resource.GetPattern(), desc, loc) +} + +// lintResourcePatternGoogleAPI lints resource patterns for Google API ResourceDescriptor (used for file-level resource definitions) +func lintResourcePatternGoogleAPI(resource *apb.ResourceDescriptor, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { + return lintResourcePatternCommon(resource.GetPattern(), desc, loc) +} + +func lintResourcePatternCommon(patterns []string, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { // Are any patterns declared at all? If not, complain. - if len(resource.GetPattern()) == 0 { + if len(patterns) == 0 { return []lint.Problem{{ Message: "Resources should declare resource name pattern(s).", Descriptor: desc, @@ -48,7 +58,7 @@ func lintResourcePattern(resource *annotations.ResourceDescriptor, desc desc.Des // Ensure that the constant segments of the pattern uses camel case, // not snake case, and there are no spaces. - for _, pattern := range resource.GetPattern() { + for _, pattern := range patterns { plainPattern := getPlainPattern(pattern) if strings.Contains(plainPattern, "_") { diff --git a/rules/aep0004/resource_variables.go b/rules/aep0004/resource_variables.go index f8fd28c5..33383224 100644 --- a/rules/aep0004/resource_variables.go +++ b/rules/aep0004/resource_variables.go @@ -18,11 +18,12 @@ import ( "fmt" "strings" + aepapi "buf.build/gen/go/aep/api/protocolbuffers/go/aep/api" "github.com/aep-dev/api-linter/lint" "github.com/aep-dev/api-linter/locations" "github.com/aep-dev/api-linter/rules/internal/utils" "github.com/jhump/protoreflect/desc" - "google.golang.org/genproto/googleapis/api/annotations" + apb "google.golang.org/genproto/googleapis/api/annotations" dpb "google.golang.org/protobuf/types/descriptorpb" ) @@ -38,11 +39,19 @@ var resourceVariables = &lint.MessageRule{ } // lintResourceVariables lints the resource ID segments of the pattern(s) in the -// give ResourceDescriptor. This is used for both the file-level annotation -// aep.api.resource_definition and the message-level annotation +// give ResourceDescriptor. This is used for the message-level annotation // aep.api.resource. -func lintResourceVariables(resource *annotations.ResourceDescriptor, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { - for _, pattern := range resource.GetPattern() { +func lintResourceVariables(resource *aepapi.ResourceDescriptor, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { + return lintResourceVariablesCommon(resource.GetPattern(), desc, loc) +} + +// lintResourceVariablesGoogleAPI lints resource variables for Google API ResourceDescriptor (used for file-level resource definitions) +func lintResourceVariablesGoogleAPI(resource *apb.ResourceDescriptor, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { + return lintResourceVariablesCommon(resource.GetPattern(), desc, loc) +} + +func lintResourceVariablesCommon(patterns []string, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { + for _, pattern := range patterns { for _, variable := range getVariables(pattern) { if strings.ToLower(variable) != variable { return []lint.Problem{{ diff --git a/rules/aep0132/resource_reference_type.go b/rules/aep0132/resource_reference_type.go index 90f8eabf..ee0fa93b 100644 --- a/rules/aep0132/resource_reference_type.go +++ b/rules/aep0132/resource_reference_type.go @@ -15,11 +15,11 @@ package aep0132 import ( + aepapi "buf.build/gen/go/aep/api/protocolbuffers/go/aep/api" "github.com/aep-dev/api-linter/lint" "github.com/aep-dev/api-linter/locations" "github.com/aep-dev/api-linter/rules/internal/utils" "github.com/jhump/protoreflect/desc" - "google.golang.org/genproto/googleapis/api/annotations" ) // List methods should reference the target resource via `child_type` or the @@ -30,7 +30,7 @@ var resourceReferenceType = &lint.MethodRule{ OnlyIf: func(m *desc.MethodDescriptor) bool { p := m.GetInputType().FindFieldByName("parent") - var resource *annotations.ResourceDescriptor + var resource *aepapi.ResourceDescriptor resourceField := utils.GetListResourceMessage(m) if resourceField != nil { resource = utils.GetResource(resourceField) diff --git a/rules/internal/utils/declarative_friendly.go b/rules/internal/utils/declarative_friendly.go index a4ccf624..6ff87e6e 100644 --- a/rules/internal/utils/declarative_friendly.go +++ b/rules/internal/utils/declarative_friendly.go @@ -20,7 +20,6 @@ import ( "bitbucket.org/creachadair/stringset" "github.com/jhump/protoreflect/desc" "github.com/stoewer/go-strcase" - apb "google.golang.org/genproto/googleapis/api/annotations" ) // DeclarativeFriendlyResource returns the declarative-friendly resource @@ -48,15 +47,9 @@ import ( func DeclarativeFriendlyResource(d desc.Descriptor) *desc.MessageDescriptor { switch m := d.(type) { case *desc.MessageDescriptor: - // Get the aep.api.resource annotation and see if it is styled - // declarative-friendly. - if resource := GetResource(m); resource != nil { - for _, style := range resource.GetStyle() { - if style == apb.ResourceDescriptor_DECLARATIVE_FRIENDLY { - return m - } - } - } + // Note: AEP ResourceDescriptor doesn't have a Style field, + // so we can't check for DECLARATIVE_FRIENDLY style directly. + // Declarative-friendly detection will rely on method-level checks. // If this is a standard method request message, find the corresponding // resource message. The easiest way to do this is to farm it out to the diff --git a/rules/internal/utils/extension.go b/rules/internal/utils/extension.go index ef515f2b..32682804 100644 --- a/rules/internal/utils/extension.go +++ b/rules/internal/utils/extension.go @@ -148,13 +148,13 @@ func GetMethodSignatures(m *desc.MethodDescriptor) [][]string { } // GetResource returns the aep.api.resource annotation. -func GetResource(m *desc.MessageDescriptor) *apb.ResourceDescriptor { +func GetResource(m *desc.MessageDescriptor) *aepapi.ResourceDescriptor { if m == nil { return nil } opts := m.GetMessageOptions() - if x := proto.GetExtension(opts, apb.E_Resource); x != nil { - return x.(*apb.ResourceDescriptor) + if x := proto.GetExtension(opts, aepapi.E_Resource); x != nil { + return x.(*aepapi.ResourceDescriptor) } return nil } @@ -184,8 +184,9 @@ func IsSingletonResource(m *desc.MessageDescriptor) bool { return false } -// GetResourceDefinitions returns the aep.api.resource_definition annotations -// for a file. +// GetResourceDefinitions returns the google.api.resource_definition annotations +// for a file. Note: This still uses the Google API extension as AEP doesn't have +// a file-level resource_definition extension yet. func GetResourceDefinitions(f *desc.FileDescriptor) []*apb.ResourceDescriptor { opts := f.GetFileOptions() if x := proto.GetExtension(opts, apb.E_ResourceDefinition); x != nil { @@ -263,7 +264,7 @@ func GetResourceReference(f *desc.FieldDescriptor) *ResourceReference { // depenedencies, it cannot search within the entire protobuf package. // This is especially useful for resolving aep.api.field_info.resource_reference // annotations. -func FindResource(reference string, file *desc.FileDescriptor) *apb.ResourceDescriptor { +func FindResource(reference string, file *desc.FileDescriptor) *aepapi.ResourceDescriptor { m := FindResourceMessage(reference, file) return GetResource(m) } @@ -305,7 +306,7 @@ func SplitResourceTypeName(typ string) (service string, typeName string, ok bool // FindResourceChildren attempts to search for other resources defined in the // package that are parented by the given resource. -func FindResourceChildren(parent *apb.ResourceDescriptor, file *desc.FileDescriptor) []*apb.ResourceDescriptor { +func FindResourceChildren(parent *aepapi.ResourceDescriptor, file *desc.FileDescriptor) []*aepapi.ResourceDescriptor { pats := parent.GetPattern() if len(pats) == 0 { return nil @@ -315,7 +316,7 @@ func FindResourceChildren(parent *apb.ResourceDescriptor, file *desc.FileDescrip // 2. The true first pattern is the one most likely to be used as a parent. first := pats[0] - var children []*apb.ResourceDescriptor + var children []*aepapi.ResourceDescriptor files := append(file.GetDependencies(), file) for _, f := range files { for _, m := range f.GetMessageTypes() { diff --git a/rules/internal/utils/extension_test.go b/rules/internal/utils/extension_test.go index 8a9c5d1c..f332c915 100644 --- a/rules/internal/utils/extension_test.go +++ b/rules/internal/utils/extension_test.go @@ -536,25 +536,25 @@ func TestGetOutputOrLROResponseMessage(t *testing.T) { } func TestFindResourceChildren(t *testing.T) { - publisher := &apb.ResourceDescriptor{ + publisher := &aepapi.ResourceDescriptor{ Type: "library.googleapis.com/Publisher", Pattern: []string{ "publishers/{publisher}", }, } - shelf := &apb.ResourceDescriptor{ + shelf := &aepapi.ResourceDescriptor{ Type: "library.googleapis.com/Shelf", Pattern: []string{ "shelves/{shelf}", }, } - book := &apb.ResourceDescriptor{ + book := &aepapi.ResourceDescriptor{ Type: "library.googleapis.com/Book", Pattern: []string{ "publishers/{publisher}/books/{book}", }, } - edition := &apb.ResourceDescriptor{ + edition := &aepapi.ResourceDescriptor{ Type: "library.googleapis.com/Edition", Pattern: []string{ "publishers/{publisher}/books/{book}/editions/{edition}", @@ -607,11 +607,11 @@ func TestFindResourceChildren(t *testing.T) { for _, tst := range []struct { name string - parent *apb.ResourceDescriptor - want []*apb.ResourceDescriptor + parent *aepapi.ResourceDescriptor + want []*aepapi.ResourceDescriptor }{ - {"has_child_same_file", book, []*apb.ResourceDescriptor{edition}}, - {"has_child_other_file", publisher, []*apb.ResourceDescriptor{book, edition}}, + {"has_child_same_file", book, []*aepapi.ResourceDescriptor{edition}}, + {"has_child_other_file", publisher, []*aepapi.ResourceDescriptor{book, edition}}, {"no_children", shelf, nil}, } { t.Run(tst.name, func(t *testing.T) { diff --git a/rules/internal/utils/resource.go b/rules/internal/utils/resource.go index 872935fe..ba4f8ace 100644 --- a/rules/internal/utils/resource.go +++ b/rules/internal/utils/resource.go @@ -17,8 +17,8 @@ package utils import ( "strings" + aepapi "buf.build/gen/go/aep/api/protocolbuffers/go/aep/api" "github.com/jhump/protoreflect/desc" - apb "google.golang.org/genproto/googleapis/api/annotations" ) // GetResourceSingular returns the resource singular. The @@ -27,7 +27,7 @@ import ( // it from multiple different locations including: // 1. the singular annotation // 2. the type definition -func GetResourceSingular(r *apb.ResourceDescriptor) string { +func GetResourceSingular(r *aepapi.ResourceDescriptor) string { if r == nil { return "" } @@ -45,7 +45,7 @@ func GetResourceSingular(r *apb.ResourceDescriptor) string { // GetResourcePlural is a convenience method for getting the `plural` field of a // resource. -func GetResourcePlural(r *apb.ResourceDescriptor) string { +func GetResourcePlural(r *aepapi.ResourceDescriptor) string { if r == nil { return "" } @@ -54,15 +54,14 @@ func GetResourcePlural(r *apb.ResourceDescriptor) string { } // GetResourceNameField is a convenience method for getting the name of the -// field that represents the resource's name. This is either set by the -// `name_field` attribute, or defaults to "name". -func GetResourceNameField(r *apb.ResourceDescriptor) string { +// field that represents the resource's name. Since AEP ResourceDescriptor +// doesn't have a name_field attribute, this always returns "name". +func GetResourceNameField(r *aepapi.ResourceDescriptor) string { if r == nil { return "" } - if n := r.GetNameField(); n != "" { - return n - } + // AEP ResourceDescriptor doesn't have a name_field attribute, + // so we always default to "name" return "name" } @@ -74,7 +73,7 @@ func IsResourceRevision(m *desc.MessageDescriptor) bool { // IsRevisionRelationship determines if the "revision" resource is actually // a revision of the "parent" resource. -func IsRevisionRelationship(parent, revision *apb.ResourceDescriptor) bool { +func IsRevisionRelationship(parent, revision *aepapi.ResourceDescriptor) bool { _, pType, ok := SplitResourceTypeName(parent.GetType()) if !ok { return false diff --git a/rules/internal/utils/resource_test.go b/rules/internal/utils/resource_test.go index fa9ab761..81b764e7 100644 --- a/rules/internal/utils/resource_test.go +++ b/rules/internal/utils/resource_test.go @@ -17,26 +17,26 @@ package utils import ( "testing" + aepapi "buf.build/gen/go/aep/api/protocolbuffers/go/aep/api" "github.com/aep-dev/api-linter/rules/internal/testutils" - apb "google.golang.org/genproto/googleapis/api/annotations" ) func TestGetResourceSingular(t *testing.T) { for _, test := range []struct { name string - resource *apb.ResourceDescriptor + resource *aepapi.ResourceDescriptor want string }{ { name: "SingularSpecified", - resource: &apb.ResourceDescriptor{ + resource: &aepapi.ResourceDescriptor{ Singular: "bookShelf", }, want: "bookShelf", }, { name: "SingularAndTypeSpecified", - resource: &apb.ResourceDescriptor{ + resource: &aepapi.ResourceDescriptor{ Singular: "bookShelf", // NOTE: this is not a correct resource annotation. // it must match singular. @@ -46,14 +46,14 @@ func TestGetResourceSingular(t *testing.T) { }, { name: "TypeSpecified", - resource: &apb.ResourceDescriptor{ + resource: &aepapi.ResourceDescriptor{ Type: "library.googleapis.com/bookShelf", }, want: "bookShelf", }, { name: "NothingSpecified", - resource: &apb.ResourceDescriptor{}, + resource: &aepapi.ResourceDescriptor{}, want: "", }, { @@ -74,19 +74,19 @@ func TestGetResourceSingular(t *testing.T) { func TestGetResourcePlural(t *testing.T) { for _, test := range []struct { name string - resource *apb.ResourceDescriptor + resource *aepapi.ResourceDescriptor want string }{ { name: "PluralSpecified", - resource: &apb.ResourceDescriptor{ + resource: &aepapi.ResourceDescriptor{ Plural: "bookShelves", }, want: "bookShelves", }, { name: "NothingSpecified", - resource: &apb.ResourceDescriptor{}, + resource: &aepapi.ResourceDescriptor{}, want: "", }, { @@ -173,8 +173,8 @@ func TestIsRevisionRelationship(t *testing.T) { }, } { t.Run(test.name, func(t *testing.T) { - a := &apb.ResourceDescriptor{Type: test.typeA} - b := &apb.ResourceDescriptor{Type: test.typeB} + a := &aepapi.ResourceDescriptor{Type: test.typeA} + b := &aepapi.ResourceDescriptor{Type: test.typeB} if got := IsRevisionRelationship(a, b); got != test.want { t.Errorf("IsRevisionRelationship(%s, %s): got %v, want %v", test.typeA, test.typeB, got, test.want) } From e41a9c1e3511d3ff3e0f0044fe107dff5dad6a3f Mon Sep 17 00:00:00 2001 From: Alex Stephen Date: Mon, 10 Nov 2025 09:39:58 -0800 Subject: [PATCH 3/4] test fixes --- locations/field_locations_test.go | 2 +- locations/file_locations_test.go | 4 +- locations/message_locations.go | 4 +- locations/message_locations_test.go | 2 +- rules/aep0004/duplicate_resource_test.go | 9 ++- rules/aep0004/path_never_optional_test.go | 10 +-- rules/aep0004/resource_annotation_test.go | 2 +- .../resource_definition_pattern_test.go | 3 +- .../resource_definition_type_name_test.go | 3 +- .../resource_definition_variables_test.go | 3 +- ...resource_name_components_alternate_test.go | 2 +- rules/aep0004/resource_path_field_test.go | 3 +- rules/aep0004/resource_pattern.go | 6 -- rules/aep0004/resource_pattern_test.go | 2 +- rules/aep0004/resource_plural_test.go | 2 +- rules/aep0004/resource_reference_type_test.go | 2 +- rules/aep0004/resource_singular_test.go | 2 +- rules/aep0004/resource_type_name_test.go | 2 +- rules/aep0004/resource_variables_test.go | 2 +- rules/aep0121/no_mutable_cycles_test.go | 2 +- .../aep0121/resource_must_support_get_test.go | 2 +- .../resource_must_support_list_test.go | 2 +- rules/aep0122/no_self_links_test.go | 2 +- .../resource_collection_identifiers_test.go | 2 +- rules/aep0122/resource_id_output_only_test.go | 2 +- rules/aep0122/resource_reference_type_test.go | 2 +- rules/aep0127/http_template_pattern_test.go | 10 +-- rules/aep0131/request_path_reference_test.go | 4 +- .../request_path_reference_type_test.go | 2 +- rules/aep0131/request_required_fields_test.go | 2 +- .../aep0132/request_parent_reference_test.go | 4 +- rules/aep0132/request_parent_required_test.go | 2 +- .../request_parent_valid_reference_test.go | 2 +- rules/aep0132/request_required_fields_test.go | 2 +- rules/aep0132/resource_reference_type_test.go | 2 +- rules/aep0133/http_uri_parent_test.go | 6 +- rules/aep0133/http_uri_resource_test.go | 2 +- rules/aep0133/method_signature_test.go | 2 +- rules/aep0133/request_id_field_test.go | 2 +- rules/aep0133/request_parent_required_test.go | 2 +- rules/aep0133/request_required_fields_test.go | 2 +- rules/aep0133/resource_reference_type_test.go | 4 +- .../request_allow_missing_field_test.go | 20 ++--- rules/aep0134/request_required_fields_test.go | 2 +- rules/aep0134/response_lro_test.go | 14 ++-- rules/aep0135/force_field_test.go | 2 +- rules/aep0135/request_path_reference_test.go | 4 +- rules/aep0135/request_required_fields_test.go | 2 +- rules/aep0135/response_lro_test.go | 14 ++-- rules/aep0135/response_message_name_test.go | 6 +- .../declarative_standard_methods_only_test.go | 8 +- .../declarative_friendly_fields_test.go | 79 ++++++------------- rules/aep0148/field_behavior_test.go | 2 +- rules/aep0164/request_name_reference_test.go | 4 +- rules/aep0164/response_lro_test.go | 14 ++-- rules/internal/utils/common_lints_test.go | 2 +- .../utils/declarative_friendly_test.go | 71 +++++++---------- rules/internal/utils/extension_test.go | 29 ++++--- rules/internal/utils/method_test.go | 10 +-- rules/internal/utils/resource.go | 6 +- rules/internal/utils/resource_test.go | 2 +- 61 files changed, 187 insertions(+), 233 deletions(-) diff --git a/locations/field_locations_test.go b/locations/field_locations_test.go index e564f983..374dc986 100644 --- a/locations/field_locations_test.go +++ b/locations/field_locations_test.go @@ -73,7 +73,7 @@ func TestFieldLabel(t *testing.T) { func TestFieldResourceReference(t *testing.T) { f := parse(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message GetBookRequest { string name = 1 [(aep.api.field_info).resource_reference = "library.googleapis.com/Book"]; diff --git a/locations/file_locations_test.go b/locations/file_locations_test.go index 212354a5..bbe6ee01 100644 --- a/locations/file_locations_test.go +++ b/locations/file_locations_test.go @@ -28,7 +28,7 @@ func TestLocations(t *testing.T) { // proto3 rules! syntax = "proto3"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; package google.api.linter; @@ -86,7 +86,7 @@ func TestLocations(t *testing.T) { testName: "Import", idxFx: FileImport, idx: 0, - wantSpan: []int32{3, 0, int32(len(`import "google/api/resource.proto";`))}, + wantSpan: []int32{3, 0, int32(len(`import "aep/api/resource.proto";`))}, }, { testName: "CCEnableArenas", diff --git a/locations/message_locations.go b/locations/message_locations.go index 4c4cfac3..3d7a3e01 100644 --- a/locations/message_locations.go +++ b/locations/message_locations.go @@ -15,13 +15,13 @@ package locations import ( + aepapi "buf.build/gen/go/aep/api/protocolbuffers/go/aep/api" "github.com/jhump/protoreflect/desc" - apb "google.golang.org/genproto/googleapis/api/annotations" dpb "google.golang.org/protobuf/types/descriptorpb" ) // MessageResource returns the precise location of the `aep.api.resource` // annotation. func MessageResource(m *desc.MessageDescriptor) *dpb.SourceCodeInfo_Location { - return pathLocation(m, 7, int(apb.E_Resource.TypeDescriptor().Number())) // MessageDescriptor.options == 7 + return pathLocation(m, 7, int(aepapi.E_Resource.TypeDescriptor().Number())) // MessageDescriptor.options == 7 } diff --git a/locations/message_locations_test.go b/locations/message_locations_test.go index a48836ec..4086124a 100644 --- a/locations/message_locations_test.go +++ b/locations/message_locations_test.go @@ -22,7 +22,7 @@ import ( func TestMessageResource(t *testing.T) { f := parse(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" diff --git a/rules/aep0004/duplicate_resource_test.go b/rules/aep0004/duplicate_resource_test.go index 8f3fa542..84798c28 100644 --- a/rules/aep0004/duplicate_resource_test.go +++ b/rules/aep0004/duplicate_resource_test.go @@ -24,7 +24,7 @@ import ( func TestDuplicateResource(t *testing.T) { f := testutils.ParseProto3Tmpls(t, map[string]string{ "dep.proto": ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; package xyz; message Publisher { option (aep.api.resource) = { type: "library.googleapis.com/Publisher" }; @@ -32,11 +32,12 @@ func TestDuplicateResource(t *testing.T) { `, "test.proto": ` import "dep.proto"; + import "aep/api/resource.proto"; import "google/api/resource.proto"; package abc; - option (aep.api.resource_definition) = { type: "library.googleapis.com/Publisher" }; - option (aep.api.resource_definition) = { type: "library.googleapis.com/Author" }; - option (aep.api.resource_definition) = { type: "library.googleapis.com/Editor" }; + option (google.api.resource_definition) = { type: "library.googleapis.com/Publisher" }; + option (google.api.resource_definition) = { type: "library.googleapis.com/Author" }; + option (google.api.resource_definition) = { type: "library.googleapis.com/Editor" }; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" }; } diff --git a/rules/aep0004/path_never_optional_test.go b/rules/aep0004/path_never_optional_test.go index 5b91b369..77daca3f 100644 --- a/rules/aep0004/path_never_optional_test.go +++ b/rules/aep0004/path_never_optional_test.go @@ -24,23 +24,19 @@ func TestPathNeverOptional(t *testing.T) { for _, test := range []struct { name string FieldPath string - PathField string Label string problems testutils.Problems }{ - {"Valid", "path", "", "", testutils.Problems{}}, - {"ValidAlternativePath", "resource", "resource", "", testutils.Problems{}}, - {"InvalidProto3Optional", "path", "", "optional", testutils.Problems{{Message: "never be labeled"}}}, - {"SkipPathFieldDNE", "path", "does_not_exist", "", testutils.Problems{}}, + {"Valid", "path", "", testutils.Problems{}}, + {"InvalidProto3Optional", "path", "optional", testutils.Problems{{Message: "never be labeled"}}}, } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" - name_field: "{{.PathField}}" }; {{.Label}} string {{.FieldPath}} = 1; diff --git a/rules/aep0004/resource_annotation_test.go b/rules/aep0004/resource_annotation_test.go index a585013c..c7681cb6 100644 --- a/rules/aep0004/resource_annotation_test.go +++ b/rules/aep0004/resource_annotation_test.go @@ -24,7 +24,7 @@ func TestResourceAnnotation(t *testing.T) { // The rule should pass if the option is present on a resource message. t.Run("Present", func(t *testing.T) { f := testutils.ParseProto3String(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" diff --git a/rules/aep0004/resource_definition_pattern_test.go b/rules/aep0004/resource_definition_pattern_test.go index 47c8bc0a..ba27c661 100644 --- a/rules/aep0004/resource_definition_pattern_test.go +++ b/rules/aep0004/resource_definition_pattern_test.go @@ -35,9 +35,10 @@ func TestResourceDefinitionPattern(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` + import "aep/api/resource.proto"; import "google/api/resource.proto"; - option (aep.api.resource_definition) = { + option (google.api.resource_definition) = { type: "library.googleapis.com/Book" {{.Pattern}} }; diff --git a/rules/aep0004/resource_definition_type_name_test.go b/rules/aep0004/resource_definition_type_name_test.go index 78c1ca0b..b1d93627 100644 --- a/rules/aep0004/resource_definition_type_name_test.go +++ b/rules/aep0004/resource_definition_type_name_test.go @@ -32,8 +32,9 @@ func TestResourceDefinitionTypeName(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` + import "aep/api/resource.proto"; import "google/api/resource.proto"; - option (aep.api.resource_definition) = { + option (google.api.resource_definition) = { type: "{{ .TypeName }}" pattern: "publishers/{publisher}/books/{book}" }; diff --git a/rules/aep0004/resource_definition_variables_test.go b/rules/aep0004/resource_definition_variables_test.go index 73a8e654..262f414d 100644 --- a/rules/aep0004/resource_definition_variables_test.go +++ b/rules/aep0004/resource_definition_variables_test.go @@ -34,8 +34,9 @@ func TestResourceDefinitionVariables(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` + import "aep/api/resource.proto"; import "google/api/resource.proto"; - option (aep.api.resource_definition) = { + option (google.api.resource_definition) = { type: "library.googleapis.com/Book" pattern: "{{.Pattern}}" }; diff --git a/rules/aep0004/resource_name_components_alternate_test.go b/rules/aep0004/resource_name_components_alternate_test.go index 550c40d3..791a117f 100644 --- a/rules/aep0004/resource_name_components_alternate_test.go +++ b/rules/aep0004/resource_name_components_alternate_test.go @@ -35,7 +35,7 @@ func TestResourceNameComponentsAlternate(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" diff --git a/rules/aep0004/resource_path_field_test.go b/rules/aep0004/resource_path_field_test.go index fc390614..a4ca0273 100644 --- a/rules/aep0004/resource_path_field_test.go +++ b/rules/aep0004/resource_path_field_test.go @@ -34,11 +34,10 @@ func TestResourceNameField(t *testing.T) { {"InvalidTypeNotString", `option (aep.api.resource) = { type: "foo" };`, `int32 path = 1;`, testutils.Problems{{Suggestion: "string"}}}, {"InvalidTypeRepeated", `option (aep.api.resource) = { type: "foo" };`, `repeated string path = 1;`, testutils.Problems{{Suggestion: "string"}}}, {"IrrelevantNoAnnotation", ``, ``, nil}, - {"ValidNameField", `option (aep.api.resource) = { type: "foo" name_field: "other_path"};`, "string other_path = 1;", nil}, } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { {{.Options}} {{.Field}} diff --git a/rules/aep0004/resource_pattern.go b/rules/aep0004/resource_pattern.go index b5e07a7a..e7c1e801 100644 --- a/rules/aep0004/resource_pattern.go +++ b/rules/aep0004/resource_pattern.go @@ -23,7 +23,6 @@ import ( "github.com/aep-dev/api-linter/locations" "github.com/aep-dev/api-linter/rules/internal/utils" "github.com/jhump/protoreflect/desc" - apb "google.golang.org/genproto/googleapis/api/annotations" dpb "google.golang.org/protobuf/types/descriptorpb" ) @@ -41,11 +40,6 @@ func lintResourcePattern(resource *aepapi.ResourceDescriptor, desc desc.Descript return lintResourcePatternCommon(resource.GetPattern(), desc, loc) } -// lintResourcePatternGoogleAPI lints resource patterns for Google API ResourceDescriptor (used for file-level resource definitions) -func lintResourcePatternGoogleAPI(resource *apb.ResourceDescriptor, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { - return lintResourcePatternCommon(resource.GetPattern(), desc, loc) -} - func lintResourcePatternCommon(patterns []string, desc desc.Descriptor, loc *dpb.SourceCodeInfo_Location) []lint.Problem { // Are any patterns declared at all? If not, complain. if len(patterns) == 0 { diff --git a/rules/aep0004/resource_pattern_test.go b/rules/aep0004/resource_pattern_test.go index 0df0d1e8..ba502284 100644 --- a/rules/aep0004/resource_pattern_test.go +++ b/rules/aep0004/resource_pattern_test.go @@ -38,7 +38,7 @@ func TestResourcePattern(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { diff --git a/rules/aep0004/resource_plural_test.go b/rules/aep0004/resource_plural_test.go index 552e9bb4..60d22f53 100644 --- a/rules/aep0004/resource_plural_test.go +++ b/rules/aep0004/resource_plural_test.go @@ -54,7 +54,7 @@ func TestResourcePlural(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/BookShelf" diff --git a/rules/aep0004/resource_reference_type_test.go b/rules/aep0004/resource_reference_type_test.go index 9529873e..df977749 100644 --- a/rules/aep0004/resource_reference_type_test.go +++ b/rules/aep0004/resource_reference_type_test.go @@ -35,7 +35,7 @@ func TestResourceReferenceType(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message Book { {{.Type}} author = 1{{.Annotation}}; diff --git a/rules/aep0004/resource_singular_test.go b/rules/aep0004/resource_singular_test.go index 8275f522..1dc2b2ff 100644 --- a/rules/aep0004/resource_singular_test.go +++ b/rules/aep0004/resource_singular_test.go @@ -47,7 +47,7 @@ func TestResourceSingular(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" diff --git a/rules/aep0004/resource_type_name_test.go b/rules/aep0004/resource_type_name_test.go index 6e35ea11..7c341c1b 100644 --- a/rules/aep0004/resource_type_name_test.go +++ b/rules/aep0004/resource_type_name_test.go @@ -39,7 +39,7 @@ func TestResourceTypeName(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "{{ .TypeName }}" diff --git a/rules/aep0004/resource_variables_test.go b/rules/aep0004/resource_variables_test.go index b51e2091..a0e1488b 100644 --- a/rules/aep0004/resource_variables_test.go +++ b/rules/aep0004/resource_variables_test.go @@ -34,7 +34,7 @@ func TestResourceVariables(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" diff --git a/rules/aep0121/no_mutable_cycles_test.go b/rules/aep0121/no_mutable_cycles_test.go index 3ea10e3f..fc7a3ed0 100644 --- a/rules/aep0121/no_mutable_cycles_test.go +++ b/rules/aep0121/no_mutable_cycles_test.go @@ -105,7 +105,7 @@ func TestNoMutableCycles(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message Book { option (aep.api.resource) = { diff --git a/rules/aep0121/resource_must_support_get_test.go b/rules/aep0121/resource_must_support_get_test.go index 6f0cecee..4df2a6ca 100644 --- a/rules/aep0121/resource_must_support_get_test.go +++ b/rules/aep0121/resource_must_support_get_test.go @@ -90,7 +90,7 @@ func TestResourceMustSupportGet(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/longrunning/operations.proto"; import "google/protobuf/field_mask.proto"; service Foo { diff --git a/rules/aep0121/resource_must_support_list_test.go b/rules/aep0121/resource_must_support_list_test.go index 80382d4a..2a56cefe 100644 --- a/rules/aep0121/resource_must_support_list_test.go +++ b/rules/aep0121/resource_must_support_list_test.go @@ -87,7 +87,7 @@ func TestResourceMustSupportList(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/longrunning/operations.proto"; import "google/protobuf/field_mask.proto"; service Foo { diff --git a/rules/aep0122/no_self_links_test.go b/rules/aep0122/no_self_links_test.go index 8c0547f9..4787b4f2 100644 --- a/rules/aep0122/no_self_links_test.go +++ b/rules/aep0122/no_self_links_test.go @@ -31,7 +31,7 @@ func TestNoSelfLinks(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" diff --git a/rules/aep0122/resource_collection_identifiers_test.go b/rules/aep0122/resource_collection_identifiers_test.go index 030f5f0d..48ecd9d8 100644 --- a/rules/aep0122/resource_collection_identifiers_test.go +++ b/rules/aep0122/resource_collection_identifiers_test.go @@ -35,7 +35,7 @@ func TestResourceCollectionIdentifiers(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" diff --git a/rules/aep0122/resource_id_output_only_test.go b/rules/aep0122/resource_id_output_only_test.go index 640014b5..f3ac93c4 100644 --- a/rules/aep0122/resource_id_output_only_test.go +++ b/rules/aep0122/resource_id_output_only_test.go @@ -34,7 +34,7 @@ func TestResourceIdOutputOnly(t *testing.T) { {"SkipDifferentIdField", "foo_id", "", testutils.Problems{}}, } { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message Book { diff --git a/rules/aep0122/resource_reference_type_test.go b/rules/aep0122/resource_reference_type_test.go index 30eda404..6004f3db 100644 --- a/rules/aep0122/resource_reference_type_test.go +++ b/rules/aep0122/resource_reference_type_test.go @@ -34,7 +34,7 @@ func TestResourceReferenceType(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message Book { diff --git a/rules/aep0127/http_template_pattern_test.go b/rules/aep0127/http_template_pattern_test.go index 5f28f24e..c82c1d61 100644 --- a/rules/aep0127/http_template_pattern_test.go +++ b/rules/aep0127/http_template_pattern_test.go @@ -57,7 +57,7 @@ func TestHttpTemplatePattern_PatternMatching(t *testing.T) { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; service Library { rpc GetBook(GetBookRequest) returns (Book) { @@ -102,7 +102,7 @@ func TestHttpTemplatePattern_MultiplePatterns(t *testing.T) { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; service Library { rpc GetBook(GetBookRequest) returns (Book) { @@ -134,7 +134,7 @@ func TestHttpTemplatePattern_MultiplePatterns(t *testing.T) { func TestHttpTemplatePattern_SkipCheckIfNoHTTPRules(t *testing.T) { f := testutils.ParseProto3String(t, ` import "google/api/annotations.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; service Library { rpc GetBook(GetBookRequest) returns (Book) {} @@ -157,7 +157,7 @@ func TestHttpTemplatePattern_SkipCheckIfNoHTTPRules(t *testing.T) { func TestHttpTemplatePattern_SkipCheckIfHTTPRuleHasNoVariables(t *testing.T) { f := testutils.ParseProto3String(t, ` import "google/api/annotations.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; service Library { rpc GetBook(GetBookRequest) returns (Book) { @@ -184,7 +184,7 @@ func TestHttpTemplatePattern_SkipCheckIfHTTPRuleHasNoVariables(t *testing.T) { func TestHttpTemplatePattern_SkipCheckIfFieldPathMissingResourceAnnotation(t *testing.T) { f := testutils.ParseProto3String(t, ` import "google/api/annotations.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; service Library { rpc GetBook(GetBookRequest) returns (Book) { diff --git a/rules/aep0131/request_path_reference_test.go b/rules/aep0131/request_path_reference_test.go index 80df3746..2221b3fd 100644 --- a/rules/aep0131/request_path_reference_test.go +++ b/rules/aep0131/request_path_reference_test.go @@ -23,7 +23,7 @@ import ( func TestRequestNameReference(t *testing.T) { t.Run("Present", func(t *testing.T) { f := testutils.ParseProto3String(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message GetBookRequest { string path = 1 [(aep.api.field_info).resource_reference = "library.googleapis.com/Book"]; @@ -44,7 +44,7 @@ func TestRequestNameReference(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message GetBookRequest { string {{.FieldName}} = 1; diff --git a/rules/aep0131/request_path_reference_type_test.go b/rules/aep0131/request_path_reference_type_test.go index deb979a5..4fb83875 100644 --- a/rules/aep0131/request_path_reference_type_test.go +++ b/rules/aep0131/request_path_reference_type_test.go @@ -31,7 +31,7 @@ func TestRequestNameReferenceType(t *testing.T) { } { t.Run(test.testName, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message GetBookRequest { string path = 1 {{.Annotation}}; diff --git a/rules/aep0131/request_required_fields_test.go b/rules/aep0131/request_required_fields_test.go index 055e1f5f..6be77977 100644 --- a/rules/aep0131/request_required_fields_test.go +++ b/rules/aep0131/request_required_fields_test.go @@ -61,7 +61,7 @@ func TestRequiredFieldTests(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; import "aep/api/field_info.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/protobuf/field_mask.proto"; service Library { diff --git a/rules/aep0132/request_parent_reference_test.go b/rules/aep0132/request_parent_reference_test.go index 90d204fb..fb125d69 100644 --- a/rules/aep0132/request_parent_reference_test.go +++ b/rules/aep0132/request_parent_reference_test.go @@ -23,7 +23,7 @@ import ( func TestRequestParentReference(t *testing.T) { t.Run("Present", func(t *testing.T) { f := testutils.ParseProto3String(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message ListBooksRequest { string parent = 1 [(aep.api.field_info).resource_reference = "library.googleapis.com/Publisher"]; @@ -44,7 +44,7 @@ func TestRequestParentReference(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message ListBooksRequest { string {{.FieldName}} = 1; diff --git a/rules/aep0132/request_parent_required_test.go b/rules/aep0132/request_parent_required_test.go index 55f8b570..66e0741a 100644 --- a/rules/aep0132/request_parent_required_test.go +++ b/rules/aep0132/request_parent_required_test.go @@ -45,7 +45,7 @@ func TestRequestParentRequired(t *testing.T) { t.Run(test.testName, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` {{.Package}} - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message ListBooksRequest {} message ListBooksResponse { repeated Book books = 1; diff --git a/rules/aep0132/request_parent_valid_reference_test.go b/rules/aep0132/request_parent_valid_reference_test.go index 0c9d5f23..66d9bbb0 100644 --- a/rules/aep0132/request_parent_valid_reference_test.go +++ b/rules/aep0132/request_parent_valid_reference_test.go @@ -30,7 +30,7 @@ func TestRequestParentValidReference(t *testing.T) { {"Invalid", "library.googleapis.com/Book", testutils.Problems{{Message: "reference the parent(s)"}}}, } { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message ListBooksRequest { string parent = 1 [(aep.api.field_info).resource_reference = "{{.ReferenceType}}"]; diff --git a/rules/aep0132/request_required_fields_test.go b/rules/aep0132/request_required_fields_test.go index 2b842502..fb91e330 100644 --- a/rules/aep0132/request_required_fields_test.go +++ b/rules/aep0132/request_required_fields_test.go @@ -61,7 +61,7 @@ func TestRequiredFieldTests(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; import "aep/api/field_info.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; service Library { rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) { diff --git a/rules/aep0132/resource_reference_type_test.go b/rules/aep0132/resource_reference_type_test.go index 58ca2f1f..96333b80 100644 --- a/rules/aep0132/resource_reference_type_test.go +++ b/rules/aep0132/resource_reference_type_test.go @@ -46,7 +46,7 @@ option (aep.api.resource) = { for _, test := range tests { t.Run(test.testName, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; service Library { rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {} diff --git a/rules/aep0133/http_uri_parent_test.go b/rules/aep0133/http_uri_parent_test.go index ff75c28b..c17a36ed 100644 --- a/rules/aep0133/http_uri_parent_test.go +++ b/rules/aep0133/http_uri_parent_test.go @@ -40,7 +40,7 @@ func TestHTTPURIParent(t *testing.T) { t.Run(test.testName, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; service Library { rpc {{.MethodName}}({{.MethodName}}Request) returns (Book) { option (google.api.http) = { @@ -63,7 +63,7 @@ func TestHTTPURIParent(t *testing.T) { t.Run(test.testName+"/Operation", func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/longrunning/operations.proto"; service Library { rpc {{.MethodName}}({{.MethodName}}Request) returns (google.longrunning.Operation) { @@ -93,7 +93,7 @@ func TestHTTPURIParent(t *testing.T) { t.Run("AdditionalBinding", func(t *testing.T) { f := testutils.ParseProto3String(t, ` import "google/api/annotations.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; service Library { rpc CreateBook(CreateBookRequest) returns (Book) { option (google.api.http) = { diff --git a/rules/aep0133/http_uri_resource_test.go b/rules/aep0133/http_uri_resource_test.go index 7bc6fe4a..5e9db83e 100644 --- a/rules/aep0133/http_uri_resource_test.go +++ b/rules/aep0133/http_uri_resource_test.go @@ -41,7 +41,7 @@ func TestHTTPURIResource(t *testing.T) { t.Run(test.testName, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; service Library { rpc CreateBook(CreateBookRequest) returns (Book) { option (google.api.http) = { diff --git a/rules/aep0133/method_signature_test.go b/rules/aep0133/method_signature_test.go index e0906132..fd869f5b 100644 --- a/rules/aep0133/method_signature_test.go +++ b/rules/aep0133/method_signature_test.go @@ -89,7 +89,7 @@ func TestMethodSignature(t *testing.T) { t.Run("NoParent", func(t *testing.T) { file := testutils.ParseProto3String(t, ` import "google/api/client.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; service Library { rpc CreateBook(CreateBookRequest) returns (Book) { option (google.api.method_signature) = "book,book_id"; diff --git a/rules/aep0133/request_id_field_test.go b/rules/aep0133/request_id_field_test.go index 4d62375d..1c4e901f 100644 --- a/rules/aep0133/request_id_field_test.go +++ b/rules/aep0133/request_id_field_test.go @@ -35,7 +35,7 @@ func TestRequestIDField(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; service Library { rpc CreateBook(CreateBookRequest) returns (Book); diff --git a/rules/aep0133/request_parent_required_test.go b/rules/aep0133/request_parent_required_test.go index 1de7869f..b3296b14 100644 --- a/rules/aep0133/request_parent_required_test.go +++ b/rules/aep0133/request_parent_required_test.go @@ -40,7 +40,7 @@ func TestRequestParentFieldRequired(t *testing.T) { // than the other tests and therefore handled separately. t.Run("ValidTopLevel", func(t *testing.T) { f := testutils.ParseProto3String(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message CreateBookRequest { Book book = 2; } diff --git a/rules/aep0133/request_required_fields_test.go b/rules/aep0133/request_required_fields_test.go index ee238141..eb2b6546 100644 --- a/rules/aep0133/request_required_fields_test.go +++ b/rules/aep0133/request_required_fields_test.go @@ -89,7 +89,7 @@ func TestRequiredFieldTests(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; import "aep/api/field_info.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; service Library { rpc CreateBookShelf(CreateBookShelfRequest) returns (BookShelf) { diff --git a/rules/aep0133/resource_reference_type_test.go b/rules/aep0133/resource_reference_type_test.go index 159b91ef..af022c2e 100644 --- a/rules/aep0133/resource_reference_type_test.go +++ b/rules/aep0133/resource_reference_type_test.go @@ -37,7 +37,7 @@ func TestResourceReferenceType(t *testing.T) { for _, test := range tests { t.Run(test.testName, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; import "google/longrunning/operations.proto"; service Library { @@ -82,7 +82,7 @@ func TestResourceReferenceTypeLRO(t *testing.T) { for _, test := range tests { t.Run(test.testName, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; import "google/longrunning/operations.proto"; service Library { diff --git a/rules/aep0134/request_allow_missing_field_test.go b/rules/aep0134/request_allow_missing_field_test.go index b55eb4a9..86eac9f4 100644 --- a/rules/aep0134/request_allow_missing_field_test.go +++ b/rules/aep0134/request_allow_missing_field_test.go @@ -23,24 +23,25 @@ import ( func TestAllowMissing(t *testing.T) { const singletonPattern = `books/{book}/settings` const nonSingletonPattern = `books/{book}` - problems := testutils.Problems{{Message: "include a singular `bool allow_missing`"}} + // Note: AEP ResourceDescriptor doesn't have a style field, so declarative-friendly + // detection is not possible. All tests expect nil since resources won't be + // detected as declarative-friendly. for _, test := range []struct { name string - Style string Pattern string AllowMissing string problems testutils.Problems }{ - {"IgnoredNotDF", "", nonSingletonPattern, "", nil}, - {"ValidIncluded", "style: DECLARATIVE_FRIENDLY", nonSingletonPattern, "bool allow_missing = 2;", nil}, - {"Invalid", "style: DECLARATIVE_FRIENDLY", nonSingletonPattern, "", problems}, - {"InvalidWrongType", "style: DECLARATIVE_FRIENDLY", nonSingletonPattern, "string allow_missing = 2;", problems}, - {"InvalidRepeated", "style: DECLARATIVE_FRIENDLY", nonSingletonPattern, "repeated bool allow_missing = 2;", problems}, - {"IgnoredSingleton", "style: DECLARATIVE_FRIENDLY", singletonPattern, "", nil}, + {"IgnoredNotDF", nonSingletonPattern, "", nil}, + {"ValidIncluded", nonSingletonPattern, "bool allow_missing = 2;", nil}, + {"NoLongerInvalid", nonSingletonPattern, "", nil}, + {"NoLongerInvalidWrongType", nonSingletonPattern, "string allow_missing = 2;", nil}, + {"NoLongerInvalidRepeated", nonSingletonPattern, "repeated bool allow_missing = 2;", nil}, + {"IgnoredSingleton", singletonPattern, "", nil}, } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; service Library { rpc UpdateBook(UpdateBookRequest) returns (Book); @@ -55,7 +56,6 @@ func TestAllowMissing(t *testing.T) { option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "{{.Pattern}}" - {{.Style}} }; } `, test) diff --git a/rules/aep0134/request_required_fields_test.go b/rules/aep0134/request_required_fields_test.go index 38f5dba6..8e6913cb 100644 --- a/rules/aep0134/request_required_fields_test.go +++ b/rules/aep0134/request_required_fields_test.go @@ -81,7 +81,7 @@ func TestRequiredFieldTests(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; import "aep/api/field_info.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/protobuf/field_mask.proto"; service Library { diff --git a/rules/aep0134/response_lro_test.go b/rules/aep0134/response_lro_test.go index c87c7c5c..f390046d 100644 --- a/rules/aep0134/response_lro_test.go +++ b/rules/aep0134/response_lro_test.go @@ -21,20 +21,21 @@ import ( ) func TestResponseLRO(t *testing.T) { - problems := testutils.Problems{{Suggestion: "google.longrunning.Operation"}} + // Note: AEP ResourceDescriptor doesn't have a style field, so declarative-friendly + // detection is not possible. All tests expect nil since resources won't be + // detected as declarative-friendly. for _, test := range []struct { name string - Style string ResponseType string problems testutils.Problems }{ - {"ValidNotDF", "", "Book", nil}, - {"ValidLRO", "style: DECLARATIVE_FRIENDLY", "google.longrunning.Operation", nil}, - {"InvalidDFSync", "style: DECLARATIVE_FRIENDLY", "Book", problems}, + {"ValidNotDF", "Book", nil}, + {"ValidLRO", "google.longrunning.Operation", nil}, + {"NoLongerInvalidDFSync", "Book", nil}, } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/longrunning/operations.proto"; service Library { @@ -45,7 +46,6 @@ func TestResponseLRO(t *testing.T) { option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" - {{.Style}} }; } diff --git a/rules/aep0135/force_field_test.go b/rules/aep0135/force_field_test.go index e28b36f1..414badc3 100644 --- a/rules/aep0135/force_field_test.go +++ b/rules/aep0135/force_field_test.go @@ -35,7 +35,7 @@ func TestForceField(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message Book { diff --git a/rules/aep0135/request_path_reference_test.go b/rules/aep0135/request_path_reference_test.go index 91425edc..0150eeec 100644 --- a/rules/aep0135/request_path_reference_test.go +++ b/rules/aep0135/request_path_reference_test.go @@ -23,7 +23,7 @@ import ( func TestRequestNameReference(t *testing.T) { t.Run("Present", func(t *testing.T) { f := testutils.ParseProto3String(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message DeleteBookRequest { string path = 1 [(aep.api.field_info).resource_reference = "library.googleapis.com/Book"]; @@ -44,7 +44,7 @@ func TestRequestNameReference(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message DeleteBookRequest { string {{.FieldName}} = 1; diff --git a/rules/aep0135/request_required_fields_test.go b/rules/aep0135/request_required_fields_test.go index 1cfa741b..a4710e9d 100644 --- a/rules/aep0135/request_required_fields_test.go +++ b/rules/aep0135/request_required_fields_test.go @@ -61,7 +61,7 @@ func TestRequiredFieldTests(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; import "aep/api/field_info.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/longrunning/operations.proto"; service Library { diff --git a/rules/aep0135/response_lro_test.go b/rules/aep0135/response_lro_test.go index 5131319c..65721e4d 100644 --- a/rules/aep0135/response_lro_test.go +++ b/rules/aep0135/response_lro_test.go @@ -21,20 +21,21 @@ import ( ) func TestResponseLRO(t *testing.T) { - problems := testutils.Problems{{Suggestion: "google.longrunning.Operation"}} + // Note: AEP ResourceDescriptor doesn't have a style field, so declarative-friendly + // detection is not possible. All tests expect nil since resources won't be + // detected as declarative-friendly. for _, test := range []struct { name string - Style string ResponseType string problems testutils.Problems }{ - {"ValidNotDF", "", "Book", nil}, - {"ValidLRO", "style: DECLARATIVE_FRIENDLY", "google.longrunning.Operation", nil}, - {"InvalidDFSync", "style: DECLARATIVE_FRIENDLY", "Book", problems}, + {"ValidNotDF", "Book", nil}, + {"ValidLRO", "google.longrunning.Operation", nil}, + {"NoLongerInvalidDFSync", "Book", nil}, } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/longrunning/operations.proto"; service Library { @@ -45,7 +46,6 @@ func TestResponseLRO(t *testing.T) { option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" - {{.Style}} }; } diff --git a/rules/aep0135/response_message_name_test.go b/rules/aep0135/response_message_name_test.go index ad3539a9..0e97fa46 100644 --- a/rules/aep0135/response_message_name_test.go +++ b/rules/aep0135/response_message_name_test.go @@ -24,7 +24,7 @@ func TestResponseMessageName(t *testing.T) { tmpl := map[string]string{ "sync": ` package test; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/protobuf/empty.proto"; service Library { rpc {{.MethodName}}({{.MethodName}}Request) returns ({{.RespTypeName}}); @@ -34,7 +34,6 @@ func TestResponseMessageName(t *testing.T) { option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" - {{.Style}} }; } {{ if (ne .RespTypeName "google.protobuf.Empty") }}{{ if (ne .RespTypeName "Book") }} @@ -43,7 +42,7 @@ func TestResponseMessageName(t *testing.T) { `, "lro": ` package test; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/longrunning/operations.proto"; service Library { rpc {{.MethodName}}({{.MethodName}}Request) @@ -59,7 +58,6 @@ func TestResponseMessageName(t *testing.T) { option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" - {{.Style}} }; } `, diff --git a/rules/aep0136/declarative_standard_methods_only_test.go b/rules/aep0136/declarative_standard_methods_only_test.go index 958ca688..c68c721f 100644 --- a/rules/aep0136/declarative_standard_methods_only_test.go +++ b/rules/aep0136/declarative_standard_methods_only_test.go @@ -21,6 +21,9 @@ import ( ) func TestDeclarativeFriendly(t *testing.T) { + // Note: AEP ResourceDescriptor doesn't have a style field, so declarative-friendly + // detection is not possible. All tests expect nil since resources won't be + // detected as declarative-friendly. for _, test := range []struct { name string MethodName string @@ -35,11 +38,11 @@ func TestDeclarativeFriendly(t *testing.T) { {"ValidUndelete", "UndeleteBook", "", nil}, {"ValidBatch", "BatchGetBooks", "", nil}, {"ValidCustomImperativeOnly", "FrobBook", "IMPERATIVE ONLY.", nil}, - {"Invalid", "FrobBook", "", testutils.Problems{{Message: "avoid custom methods"}}}, + {"NoLongerInvalid", "FrobBook", "", nil}, } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; service Library { // The {{.MethodName}} method. @@ -54,7 +57,6 @@ func TestDeclarativeFriendly(t *testing.T) { option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" - style: DECLARATIVE_FRIENDLY }; } `, test) diff --git a/rules/aep0148/declarative_friendly_fields_test.go b/rules/aep0148/declarative_friendly_fields_test.go index 2033ba60..22a94220 100644 --- a/rules/aep0148/declarative_friendly_fields_test.go +++ b/rules/aep0148/declarative_friendly_fields_test.go @@ -16,7 +16,6 @@ package aep0148 import ( "fmt" - "strings" "testing" "bitbucket.org/creachadair/stringset" @@ -49,70 +48,43 @@ func TestDeclarativeFriendlyFields(t *testing.T) { } } - // Create the potential problem object for the missing fields. - var problems testutils.Problems - if test.skipped.Len() == 1 { - f := test.skipped.Unordered()[0] - problems = testutils.Problems{{ - Message: fmt.Sprintf("must include the `%s %s` field", reqFields[f], f), - }} - } else if test.skipped.Len() > 1 { - missingFields := stringset.New() - for _, f := range test.skipped.Unordered() { - missingFields.Add(fmt.Sprintf("%s %s", reqFields[f], f)) - } - msg := "" - for _, f := range missingFields.Elements() { - msg += fmt.Sprintf(" - `%s`\n", f) + // Note: AEP ResourceDescriptor doesn't have a style field, so declarative-friendly + // detection is not possible. All tests expect nil since resources won't be + // detected as declarative-friendly. + f := testutils.ParseProto3Tmpl(t, ` + import "aep/api/resource.proto"; + import "google/protobuf/timestamp.proto"; + message Book { + option (aep.api.resource) = { + type: "library.googleapis.com/Book" + pattern: "publishers/{publisher}/books/{book}" + }; + {{.Fields}} } - problems = testutils.Problems{{Message: strings.TrimSuffix(msg, "\n")}} - } - - // Test against declarative-friendly and standard styles. - for _, subtest := range []struct { - name string - style string - problems testutils.Problems - }{ - {"DeclFriendly", "style: DECLARATIVE_FRIENDLY", problems}, - {"NotDeclFriendly", "", nil}, - } { - t.Run(subtest.name, func(t *testing.T) { - f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; - import "google/protobuf/timestamp.proto"; - message Book { - option (aep.api.resource) = { - type: "library.googleapis.com/Book" - pattern: "publishers/{publisher}/books/{book}" - {{.Style}} - }; - {{.Fields}} - } - `, struct { - Fields string - Style string - }{Fields: fields, Style: subtest.style}) - m := f.GetMessageTypes()[0] - got := declarativeFriendlyRequired.Lint(f) - if diff := subtest.problems.SetDescriptor(m).Diff(got); diff != "" { - t.Error(diff) - } - }) + `, struct { + Fields string + }{Fields: fields}) + m := f.GetMessageTypes()[0] + got := declarativeFriendlyRequired.Lint(f) + if diff := testutils.Problems(nil).SetDescriptor(m).Diff(got); diff != "" { + t.Error(diff) } }) } } func TestDeclarativeFriendlyFieldsSingleton(t *testing.T) { + // Note: AEP ResourceDescriptor doesn't have a style field, so declarative-friendly + // detection is not possible. All tests expect nil since resources won't be + // detected as declarative-friendly. for _, test := range []struct { name string Fields string want testutils.Problems }{ { - "InvalidNoCreateTime", `string path = 1; string display_name = 2; google.protobuf.Timestamp update_time = 3;`, - testutils.Problems{{Message: "create_time"}}, + "NoLongerInvalidNoCreateTime", `string path = 1; string display_name = 2; google.protobuf.Timestamp update_time = 3;`, + nil, }, { "ValidNoDeleteTimeNoUid", `string path = 1; string display_name = 2; ` + @@ -122,13 +94,12 @@ func TestDeclarativeFriendlyFieldsSingleton(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/protobuf/timestamp.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Settings" pattern: "publishers/{publisher}/settings" - style: DECLARATIVE_FRIENDLY }; {{.Fields}} } diff --git a/rules/aep0148/field_behavior_test.go b/rules/aep0148/field_behavior_test.go index 783632a8..fe7e9d10 100644 --- a/rules/aep0148/field_behavior_test.go +++ b/rules/aep0148/field_behavior_test.go @@ -46,7 +46,7 @@ func TestFieldBehavior(t *testing.T) { t.Run(test.name, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` import "aep/api/field_info.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/protobuf/timestamp.proto"; message Book { {{.MessageOpts}} diff --git a/rules/aep0164/request_name_reference_test.go b/rules/aep0164/request_name_reference_test.go index d6e7e339..ec672873 100644 --- a/rules/aep0164/request_name_reference_test.go +++ b/rules/aep0164/request_name_reference_test.go @@ -23,7 +23,7 @@ import ( func TestRequestNameReference(t *testing.T) { t.Run("Present", func(t *testing.T) { f := testutils.ParseProto3String(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message UndeleteBookRequest { string name = 1 [(aep.api.field_info).resource_reference = "library.googleapis.com/Book"]; @@ -44,7 +44,7 @@ func TestRequestNameReference(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message UndeleteBookRequest { string {{.FieldName}} = 1; diff --git a/rules/aep0164/response_lro_test.go b/rules/aep0164/response_lro_test.go index 814d6952..596179de 100644 --- a/rules/aep0164/response_lro_test.go +++ b/rules/aep0164/response_lro_test.go @@ -21,20 +21,21 @@ import ( ) func TestResponseLRO(t *testing.T) { - problems := testutils.Problems{{Suggestion: "google.longrunning.Operation"}} + // Note: AEP ResourceDescriptor doesn't have a style field, so declarative-friendly + // detection is not possible. All tests expect nil since resources won't be + // detected as declarative-friendly. for _, test := range []struct { name string - Style string ResponseType string problems testutils.Problems }{ - {"ValidNotDF", "", "Book", nil}, - {"ValidLRO", "style: DECLARATIVE_FRIENDLY", "google.longrunning.Operation", nil}, - {"InvalidDFSync", "style: DECLARATIVE_FRIENDLY", "Book", problems}, + {"ValidNotDF", "Book", nil}, + {"ValidLRO", "google.longrunning.Operation", nil}, + {"NoLongerInvalidDFSync", "Book", nil}, } { t.Run(test.name, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/longrunning/operations.proto"; service Library { rpc UndeleteBook(UndeleteBookRequest) returns ({{.ResponseType}}); @@ -43,7 +44,6 @@ func TestResponseLRO(t *testing.T) { option (aep.api.resource) = { type: "library.googleapis.com/Book" pattern: "publishers/{publisher}/books/{book}" - {{.Style}} }; } message UndeleteBookRequest {} diff --git a/rules/internal/utils/common_lints_test.go b/rules/internal/utils/common_lints_test.go index c17cdd4b..34a62ff7 100644 --- a/rules/internal/utils/common_lints_test.go +++ b/rules/internal/utils/common_lints_test.go @@ -68,7 +68,7 @@ func TestLintFieldResourceReference(t *testing.T) { } { t.Run(test.testName, func(t *testing.T) { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message Message { string foo = 1 {{.Annotation}}; diff --git a/rules/internal/utils/declarative_friendly_test.go b/rules/internal/utils/declarative_friendly_test.go index f901f571..c541baa2 100644 --- a/rules/internal/utils/declarative_friendly_test.go +++ b/rules/internal/utils/declarative_friendly_test.go @@ -23,23 +23,22 @@ import ( func TestDeclarativeFriendlyMessage(t *testing.T) { // Test the cases where a aep.api.resource annotation is present. + // Note: AEP ResourceDescriptor doesn't have a Style field, so we can't + // check for DECLARATIVE_FRIENDLY style directly on message descriptors. + // All message-level checks should return false. for _, test := range []struct { - name string - Style string - want bool + name string + want bool }{ - {"True", "style: DECLARATIVE_FRIENDLY", true}, - {"FalseNoStyle", "", false}, - {"FalseOtherStyle", "style: STYLE_UNSPECIFIED", false}, + {"WithResource", false}, } { t.Run(test.name, func(t *testing.T) { - f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + f := testutils.ParseProto3String(t, ` + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" - {{.Style}} }; } @@ -50,7 +49,7 @@ func TestDeclarativeFriendlyMessage(t *testing.T) { service Library { rpc CreateBook(CreateBookRequest) returns (Book); } - `, test) + `) for _, m := range f.GetMessageTypes() { t.Run(m.GetName(), func(t *testing.T) { if got := IsDeclarativeFriendlyMessage(m); got != test.want { @@ -76,6 +75,9 @@ func TestDeclarativeFriendlyMethod(t *testing.T) { // Note: The Book resource itself is always present and omitted here to // avoid excess repetition; it is appended to the templates in the body of // the test. + // + // Note: AEP ResourceDescriptor doesn't have a Style field, so declarative-friendly + // detection is not possible. All tests should expect false. tmpls := map[string]string{ // The basic template just returns the resource with no frills. "basic": ` @@ -137,39 +139,24 @@ func TestDeclarativeFriendlyMethod(t *testing.T) { for key, tmpl := range tmpls { t.Run(key, func(t *testing.T) { - for _, test := range []struct { - name string - want bool - }{ - {"true", true}, - {"false", false}, - } { - t.Run(test.name, func(t *testing.T) { - // Set the style of the resource to DECLARATIVE_FRIENDLY if that - // is the expected result. - s := struct{ Style string }{Style: ""} - if test.want == true { - s.Style = "style: DECLARATIVE_FRIENDLY" - } + // Since AEP doesn't support the style field, all tests expect false + want := false - // Parse the template and test the method. - f := testutils.ParseProto3Tmpl(t, fmt.Sprintf(` - import "google/api/resource.proto"; - - %s - - message Book { - option (aep.api.resource) = { - type: "library.googleapis.com/Book" - {{.Style}} - }; - } - `, tmpl), s) - m := f.GetServices()[0].GetMethods()[0] - if got := IsDeclarativeFriendlyMethod(m); got != test.want { - t.Errorf("Got %v, expected %v.", got, test.want) - } - }) + // Parse the template and test the method. + f := testutils.ParseProto3String(t, fmt.Sprintf(` + import "aep/api/resource.proto"; + + %s + + message Book { + option (aep.api.resource) = { + type: "library.googleapis.com/Book" + }; + } + `, tmpl)) + m := f.GetServices()[0].GetMethods()[0] + if got := IsDeclarativeFriendlyMethod(m); got != want { + t.Errorf("Got %v, expected %v.", got, want) } }) } diff --git a/rules/internal/utils/extension_test.go b/rules/internal/utils/extension_test.go index f332c915..61c197c6 100644 --- a/rules/internal/utils/extension_test.go +++ b/rules/internal/utils/extension_test.go @@ -18,6 +18,7 @@ import ( "testing" "bitbucket.org/creachadair/stringset" + aepapi "buf.build/gen/go/aep/api/protocolbuffers/go/aep/api" "github.com/aep-dev/api-linter/rules/internal/testutils" "github.com/google/go-cmp/cmp" apb "google.golang.org/genproto/googleapis/api/annotations" @@ -216,7 +217,7 @@ func TestGetOperationInfoMetadataType(t *testing.T) { func TestGetResource(t *testing.T) { t.Run("Present", func(t *testing.T) { f := testutils.ParseProto3String(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" @@ -248,7 +249,7 @@ func TestGetResource(t *testing.T) { func TestGetResourceDefinition(t *testing.T) { t.Run("Zero", func(t *testing.T) { f := testutils.ParseProto3String(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; `) if got := GetResourceDefinitions(f); got != nil { t.Errorf("Got %v, expected nil.", got) @@ -256,8 +257,9 @@ func TestGetResourceDefinition(t *testing.T) { }) t.Run("One", func(t *testing.T) { f := testutils.ParseProto3String(t, ` + import "aep/api/resource.proto"; import "google/api/resource.proto"; - option (aep.api.resource_definition) = { + option (google.api.resource_definition) = { type: "library.googleapis.com/Book" }; `) @@ -271,11 +273,12 @@ func TestGetResourceDefinition(t *testing.T) { }) t.Run("Two", func(t *testing.T) { f := testutils.ParseProto3String(t, ` + import "aep/api/resource.proto"; import "google/api/resource.proto"; - option (aep.api.resource_definition) = { + option (google.api.resource_definition) = { type: "library.googleapis.com/Book" }; - option (aep.api.resource_definition) = { + option (google.api.resource_definition) = { type: "library.googleapis.com/Author" }; `) @@ -295,7 +298,7 @@ func TestGetResourceDefinition(t *testing.T) { func TestGetResourceReference(t *testing.T) { t.Run("Present", func(t *testing.T) { f := testutils.ParseProto3String(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "aep/api/field_info.proto"; message GetBookRequest { string name = 1 [(aep.api.field_info).resource_reference = "library.googleapis.com/Book"]; @@ -321,7 +324,7 @@ func TestFindResource(t *testing.T) { syntax = "proto3"; package test; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { @@ -337,7 +340,7 @@ func TestFindResource(t *testing.T) { package test; import "book.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Shelf { option (aep.api.resource) = { @@ -382,7 +385,7 @@ func TestFindResourceMessage(t *testing.T) { syntax = "proto3"; package test; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { @@ -398,7 +401,7 @@ func TestFindResourceMessage(t *testing.T) { package test; import "book.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Shelf { option (aep.api.resource) = { @@ -488,7 +491,7 @@ func TestGetOutputOrLROResponseMessage(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/longrunning/operations.proto"; import "google/protobuf/field_mask.proto"; service Foo { @@ -565,7 +568,7 @@ func TestFindResourceChildren(t *testing.T) { syntax = "proto3"; package test; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Book { option (aep.api.resource) = { @@ -590,7 +593,7 @@ func TestFindResourceChildren(t *testing.T) { package test; import "book.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message Shelf { option (aep.api.resource) = { diff --git a/rules/internal/utils/method_test.go b/rules/internal/utils/method_test.go index ebd0f88e..ff75fce6 100644 --- a/rules/internal/utils/method_test.go +++ b/rules/internal/utils/method_test.go @@ -34,7 +34,7 @@ func TestIsCreateMethod(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/protobuf/field_mask.proto"; service Foo { {{.RPCs}} @@ -84,7 +84,7 @@ func TestIsUpdateMethod(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/protobuf/field_mask.proto"; service Foo { {{.RPCs}} @@ -133,7 +133,7 @@ func TestIsListMethod(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/protobuf/field_mask.proto"; service Foo { {{.RPCs}} @@ -215,7 +215,7 @@ func TestIsLegacyListRevisionsMethod(t *testing.T) { t.Run(test.name, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` import "google/api/annotations.proto"; - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/protobuf/field_mask.proto"; service Foo { {{.RPCs}} @@ -278,7 +278,7 @@ func TestGetListResourceMessage(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { file := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; import "google/protobuf/field_mask.proto"; service Foo { {{.RPCs}} diff --git a/rules/internal/utils/resource.go b/rules/internal/utils/resource.go index ba4f8ace..f943f84e 100644 --- a/rules/internal/utils/resource.go +++ b/rules/internal/utils/resource.go @@ -55,14 +55,14 @@ func GetResourcePlural(r *aepapi.ResourceDescriptor) string { // GetResourceNameField is a convenience method for getting the name of the // field that represents the resource's name. Since AEP ResourceDescriptor -// doesn't have a name_field attribute, this always returns "name". +// doesn't have a name_field attribute, this always returns "path". func GetResourceNameField(r *aepapi.ResourceDescriptor) string { if r == nil { return "" } // AEP ResourceDescriptor doesn't have a name_field attribute, - // so we always default to "name" - return "name" + // so we always default to "path" + return "path" } // IsResourceRevision determines if the given message represents a resource diff --git a/rules/internal/utils/resource_test.go b/rules/internal/utils/resource_test.go index 81b764e7..78171be5 100644 --- a/rules/internal/utils/resource_test.go +++ b/rules/internal/utils/resource_test.go @@ -128,7 +128,7 @@ func TestIsResourceRevision(t *testing.T) { }, } { f := testutils.ParseProto3Tmpl(t, ` - import "google/api/resource.proto"; + import "aep/api/resource.proto"; message {{.Message}} { {{.Resource}} string name = 1; From 5d8ef3d0a79c3d8fa900f313b986920b122a3ee1 Mon Sep 17 00:00:00 2001 From: Alex Stephen Date: Mon, 10 Nov 2025 09:55:30 -0800 Subject: [PATCH 4/4] Remove file-level rules --- .../rules/0004/resource-definition-pattern.md | 88 ------------------- .../0004/resource-definition-type-name.md | 68 -------------- .../0004/resource-definition-variables.md | 88 ------------------- rules/aep0004/aep0004.go | 7 -- rules/aep0004/duplicate_resource.go | 41 +++------ rules/aep0004/duplicate_resource_test.go | 24 ++--- rules/aep0004/resource_definition_pattern.go | 39 -------- .../resource_definition_pattern_test.go | 52 ----------- .../aep0004/resource_definition_type_name.go | 45 ---------- .../resource_definition_type_name_test.go | 48 ---------- .../aep0004/resource_definition_variables.go | 39 -------- .../resource_definition_variables_test.go | 50 ----------- 12 files changed, 16 insertions(+), 573 deletions(-) delete mode 100644 docs/rules/0004/resource-definition-pattern.md delete mode 100644 docs/rules/0004/resource-definition-type-name.md delete mode 100644 docs/rules/0004/resource-definition-variables.md delete mode 100644 rules/aep0004/resource_definition_pattern.go delete mode 100644 rules/aep0004/resource_definition_pattern_test.go delete mode 100644 rules/aep0004/resource_definition_type_name.go delete mode 100644 rules/aep0004/resource_definition_type_name_test.go delete mode 100644 rules/aep0004/resource_definition_variables.go delete mode 100644 rules/aep0004/resource_definition_variables_test.go diff --git a/docs/rules/0004/resource-definition-pattern.md b/docs/rules/0004/resource-definition-pattern.md deleted file mode 100644 index 2a529c91..00000000 --- a/docs/rules/0004/resource-definition-pattern.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -rule: - aep: 123 - name: [core, '0123', resource-definition-pattern] - summary: Resource annotations should define a pattern. -permalink: /123/resource-definition-pattern -redirect_from: - - /0123/resource-definition-pattern ---- - -# Resource patterns - -This rule enforces that files that define a resource with the -`aep.api.resource_definition` annotation have a `pattern` defined, as -described in [AEP-123][]. - -## Details - -This rule scans all `aep.api.resource_definition` annotations in all files, -and complains if `pattern` is not provided at least once. It also complains if -the segments outside of variable names contain underscores. - -## Examples - -**Incorrect** code for this rule: - -```proto -import "google/api/resources.proto"; - -// Incorrect. -option (aep.api.resource_definition) = { - type: "library.googleapis.com/Book" - // pattern should be here -}; -``` - -```proto -import "google/api/resources.proto"; - -// Incorrect. -option (aep.api.resource_definition) = { - type: "library.googleapis.com/ElectronicBook" - // Should be: publishers/{publisher}/electronicBooks/{electronic_book} - pattern: "publishers/{publisher}/electronic_books/{electronic_book}" -}; -``` - -**Correct** code for this rule: - -```proto -import "google/api/resources.proto"; - -// Correct. -option (aep.api.resource_definition) = { - type: "library.googleapis.com/Book" - pattern: "publishers/{publisher}/books/{book}" -}; -``` - -```proto -import "google/api/resource.proto"; - -// Correct. -option (aep.api.resource_definition) = { - type: "library.googleapis.com/ElectronicBook" - pattern: "publishers/{publisher}/electronicBooks/{electronic_book}" -}; -``` - -## Disabling - -If you need to violate this rule, use a comment on the annotation. - -```proto -import "google/api/resource.proto"; - -// (-- api-linter: core::0123::resource-definition-pattern=disabled -// aep.dev/not-precedent: We need to do this because reasons. --) -option (aep.api.resource_definition) = { - type: "library.googleapis.com/Book" -}; -``` - -If you need to violate this rule for an entire file, place the comment at the -top of the file. - -[aep-123]: http://aep.dev/123 -[aep.dev/not-precedent]: https://aep.dev/not-precedent diff --git a/docs/rules/0004/resource-definition-type-name.md b/docs/rules/0004/resource-definition-type-name.md deleted file mode 100644 index 67c67908..00000000 --- a/docs/rules/0004/resource-definition-type-name.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -rule: - aep: 123 - name: [core, '0123', resource-definition-type-name] - summary: Resource type names must be of the form {Service Name}/{Type}. -permalink: /123/resource-definition-type-name -redirect_from: - - /0123/resource-definition-type-name ---- - -# Resource type name - -This rule enforces that files that define a resource with the -`aep.api.resource_definition` annotation have a properly formatted `type`, as -described in [AEP-123][]. - -## Details - -This rule scans files with `aep.api.resource_definition` annotations, and -validates the format of the `type` field conforms to `{Service Name}/{Type}`. - -## Examples - -**Incorrect** code for this rule: - -```proto -import "google/api/resource.proto"; - -// Incorrect. -option (aep.api.resource_definition) = { - // Should not have more than one separating '/'. - type: "library.googleapis.com/Genre/Mystery/Book" - pattern: "publishers/{publisher}/books/{book}" -}; -``` - -**Correct** code for this rule: - -```proto -import "google/api/resource.proto"; - -// Correct. -option (aep.api.resource_definition) = { - type: "library.googleapis.com/Book" - pattern: "publishers/{publisher}/books/{book}" -}; -``` - -## Disabling - -If you need to violate this rule, use a leading comment above the annotation. - -```proto -import "google/api/resource.proto"; - -// (-- api-linter: core::0123::resource-definition-type-name=disabled -// aep.dev/not-precedent: We need to do this because reasons. --) -option (aep.api.resource_definition) = { - type: "library.googleapis.com/Genre/Mystery/Book" - pattern: "publishers/{publisher}/books/{book}" -}; -``` - -If you need to violate this rule for an entire file, place the comment at the -top of the file. - -[aep-123]: http://aep.dev/123 -[aep.dev/not-precedent]: https://aep.dev/not-precedent diff --git a/docs/rules/0004/resource-definition-variables.md b/docs/rules/0004/resource-definition-variables.md deleted file mode 100644 index fe59e4c2..00000000 --- a/docs/rules/0004/resource-definition-variables.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -rule: - aep: 4 - name: [core, '4', resource-definition-variables] - summary: Resource patterns should use consistent variable naming. -permalink: /4/resource-definition-variables -redirect_from: - - /4/resource-definition-variables ---- - -# Resource pattern variables - -This rule enforces that resource patterns use consistent variable naming -conventions, as described in [AEP-4][]. - -## Details - -This rule scans all files with `aep.api.resource_definition` annotations, and -complains if variables in a `pattern` use camel case, or end in `_id`. - -## Examples - -**Incorrect** code for this rule: - -```proto -import "google/api/resource.proto"; - -// Incorrect. -option (aep.api.resource_definition) = { - type: "library.googleapis.com/Book" - // Should be: publishers/{publisher}/books/{book} - pattern: "publishers/{publisher_id}/books/{book_id}" -}; -``` - -```proto -import "google/api/resource.proto"; - -// Incorrect. -option (aep.api.resource_definition) = { - type: "library.googleapis.com/ElectronicBook" - // Should be: publishers/{publisher}/electronicBooks/{electronic_book} - pattern: "publishers/{publisher}/electronicBooks/{electronicBook}" -}; -``` - -**Correct** code for this rule: - -```proto -import "google/api/resource.proto"; - -// Correct. -option (aep.api.resource_definition) = { - type: "library.googleapis.com/Book" - pattern: "publishers/{publisher}/books/{book}" -}; -``` - -```proto -import "google/api/resource.proto"; - -// Correct. -option (aep.api.resource_definition) = { - type: "library.googleapis.com/ElectronicBook" - pattern: "publishers/{publisher}/electronicBooks/{electronic_book}" -}; -``` - -## Disabling - -If you need to violate this rule, use a leading comment above the annotation. - -```proto -import "google/api/resource.proto"; - -// (-- api-linter: core::4::resource-definition-variables=disabled -// aep.dev/not-precedent: We need to do this because reasons. --) -option (aep.api.resource_definition) = { - type: "library.googleapis.com/Book" - pattern: "publishers/{publisher_id}/books/{book_id}" -}; -``` - -If you need to violate this rule for an entire file, place the comment at the -top of the file. - -[aep-4]: http://aep.dev/4 -[aep.dev/not-precedent]: https://aep.dev/not-precedent diff --git a/rules/aep0004/aep0004.go b/rules/aep0004/aep0004.go index 32cc57e3..1eb205b0 100644 --- a/rules/aep0004/aep0004.go +++ b/rules/aep0004/aep0004.go @@ -41,9 +41,6 @@ func AddRules(r lint.RuleRegistry) error { resourceSingular, resourceTypeName, resourceVariables, - resourceDefinitionVariables, - resourceDefinitionPatterns, - resourceDefinitionTypeName, pathNeverOptional, ) } @@ -60,10 +57,6 @@ func hasResourceAnnotation(m *desc.MessageDescriptor) bool { return utils.GetResource(m) != nil } -func hasResourceDefinitionAnnotation(f *desc.FileDescriptor) bool { - return len(utils.GetResourceDefinitions(f)) > 0 -} - // getVariables returns a slice of variables declared in the pattern. // // For example, a pattern of "publishers/{publisher}/books/{book}" would diff --git a/rules/aep0004/duplicate_resource.go b/rules/aep0004/duplicate_resource.go index 23c6e720..3c2f8900 100644 --- a/rules/aep0004/duplicate_resource.go +++ b/rules/aep0004/duplicate_resource.go @@ -27,38 +27,18 @@ import ( ) type resourceDef struct { - desc desc.Descriptor - idx int + desc *desc.MessageDescriptor } func (d *resourceDef) String() string { - switch d.desc.(type) { - case *desc.FileDescriptor: - return fmt.Sprintf("`aep.api.resource_definition` %d in file `%s`", d.idx, d.desc.GetFullyQualifiedName()) - case *desc.MessageDescriptor: - return fmt.Sprintf("message `%s`", d.desc.GetFullyQualifiedName()) - default: - return fmt.Sprintf("unexpected descriptor type %T", d.desc) - } + return fmt.Sprintf("message `%s`", d.desc.GetFullyQualifiedName()) } func (d *resourceDef) location() *dpb.SourceCodeInfo_Location { - switch desc := d.desc.(type) { - case *desc.FileDescriptor: - return locations.FileResourceDefinition(desc, d.idx) - case *desc.MessageDescriptor: - return locations.MessageResource(desc) - default: - return nil - } + return locations.MessageResource(d.desc) } func resourceDefsInFile(f *desc.FileDescriptor, defs map[string][]resourceDef) map[string][]resourceDef { - for i, rd := range utils.GetResourceDefinitions(f) { - if t := rd.GetType(); t != "" { - defs[t] = append(defs[t], resourceDef{f, i}) - } - } for _, m := range f.GetMessageTypes() { resourceDefsInMsg(m, defs) } @@ -67,7 +47,7 @@ func resourceDefsInFile(f *desc.FileDescriptor, defs map[string][]resourceDef) m func resourceDefsInMsg(m *desc.MessageDescriptor, defs map[string][]resourceDef) { if t := utils.GetResource(m).GetType(); t != "" { - defs[t] = append(defs[t], resourceDef{m, -1}) + defs[t] = append(defs[t], resourceDef{m}) } for _, m := range m.GetNestedMessageTypes() { resourceDefsInMsg(m, defs) @@ -109,17 +89,16 @@ var duplicateResource = &lint.FileRule{ for _, t := range resourceTypes { ds := defsInFile[t] locs := []string{} - // Duplicates in this file. - if len(ds) > 1 { - for _, d := range ds { - locs = append(locs, d.String()) - } + // Collect all definitions from current file + for _, d := range ds { + locs = append(locs, d.String()) } - // Duplicates in dependencies. + // Collect all definitions from dependencies for _, d := range defsInDeps[t] { locs = append(locs, d.String()) } - if len(locs) == 0 { + // Only report if there are duplicates (2 or more total definitions) + if len(locs) <= 1 { continue } sort.Strings(locs) diff --git a/rules/aep0004/duplicate_resource_test.go b/rules/aep0004/duplicate_resource_test.go index 84798c28..472183ed 100644 --- a/rules/aep0004/duplicate_resource_test.go +++ b/rules/aep0004/duplicate_resource_test.go @@ -33,16 +33,12 @@ func TestDuplicateResource(t *testing.T) { "test.proto": ` import "dep.proto"; import "aep/api/resource.proto"; - import "google/api/resource.proto"; package abc; - option (google.api.resource_definition) = { type: "library.googleapis.com/Publisher" }; - option (google.api.resource_definition) = { type: "library.googleapis.com/Author" }; - option (google.api.resource_definition) = { type: "library.googleapis.com/Editor" }; message Book { option (aep.api.resource) = { type: "library.googleapis.com/Book" }; } - message Author { - option (aep.api.resource) = { type: "library.googleapis.com/Author" }; + message Publisher { + option (aep.api.resource) = { type: "library.googleapis.com/Publisher" }; } message Foo { message Tome { @@ -52,24 +48,16 @@ func TestDuplicateResource(t *testing.T) { }, nil)["test.proto"] want := testutils.Problems{ lint.Problem{ - Message: "resource \"library.googleapis.com/Author\": `aep.api.resource_definition` 1 in file `test.proto`, message `abc.Author`.", - Descriptor: f, - }, - lint.Problem{ - Message: "resource \"library.googleapis.com/Author\": `aep.api.resource_definition` 1 in file `test.proto`, message `abc.Author`.", - Descriptor: f.GetMessageTypes()[1], - }, - lint.Problem{ - Message: "resource \"library.googleapis.com/Book\": message `abc.Book`, message `abc.Foo.Tome`.", + Message: "Multiple definitions for resource \"library.googleapis.com/Book\": message `abc.Book`, message `abc.Foo.Tome`.", Descriptor: f.GetMessageTypes()[0], }, lint.Problem{ - Message: "resource \"library.googleapis.com/Book\": message `abc.Book`, message `abc.Foo.Tome`.", + Message: "Multiple definitions for resource \"library.googleapis.com/Book\": message `abc.Book`, message `abc.Foo.Tome`.", Descriptor: f.GetMessageTypes()[2].GetNestedMessageTypes()[0], }, lint.Problem{ - Message: "resource \"library.googleapis.com/Publisher\": message `xyz.Publisher`.", - Descriptor: f, + Message: "Multiple definitions for resource \"library.googleapis.com/Publisher\": message `abc.Publisher`, message `xyz.Publisher`.", + Descriptor: f.GetMessageTypes()[1], }, } if diff := want.Diff(duplicateResource.Lint(f)); diff != "" { diff --git a/rules/aep0004/resource_definition_pattern.go b/rules/aep0004/resource_definition_pattern.go deleted file mode 100644 index 8de97afe..00000000 --- a/rules/aep0004/resource_definition_pattern.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2022 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 aep0004 - -import ( - "github.com/aep-dev/api-linter/lint" - "github.com/aep-dev/api-linter/locations" - "github.com/aep-dev/api-linter/rules/internal/utils" - "github.com/jhump/protoreflect/desc" -) - -var resourceDefinitionPatterns = &lint.FileRule{ - Name: lint.NewRuleName(4, "resource-definition-pattern"), - RuleType: lint.NewRuleType(lint.MustRule), - OnlyIf: hasResourceDefinitionAnnotation, - LintFile: func(f *desc.FileDescriptor) []lint.Problem { - var problems []lint.Problem - resources := utils.GetResourceDefinitions(f) - - for ndx, resource := range resources { - loc := locations.FileResourceDefinition(f, ndx) - probs := lintResourcePatternGoogleAPI(resource, f, loc) - problems = append(problems, probs...) - } - return problems - }, -} diff --git a/rules/aep0004/resource_definition_pattern_test.go b/rules/aep0004/resource_definition_pattern_test.go deleted file mode 100644 index ba27c661..00000000 --- a/rules/aep0004/resource_definition_pattern_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2022 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 aep0004 - -import ( - "testing" - - "github.com/aep-dev/api-linter/rules/internal/testutils" -) - -func TestResourceDefinitionPattern(t *testing.T) { - for _, test := range []struct { - name string - Pattern string - problems testutils.Problems - }{ - {"Valid", `pattern: "publishers/{publisher}/books/{book}"`, testutils.Problems{}}, - {"ValidCamel", `pattern: "publishers/{publisher}/electronicBooks/{electronic_book}"`, testutils.Problems{}}, - {"Missing", "", testutils.Problems{{Message: "declare resource name pattern"}}}, - {"SnakeCase", `pattern: "book_publishers/{book_publisher}/books/{book}"`, testutils.Problems{{ - Message: "bookPublishers/{book_publisher}/books/{book}", - }}}, - } { - t.Run(test.name, func(t *testing.T) { - f := testutils.ParseProto3Tmpl(t, ` - import "aep/api/resource.proto"; - import "google/api/resource.proto"; - - option (google.api.resource_definition) = { - type: "library.googleapis.com/Book" - {{.Pattern}} - }; - `, test) - got := resourceDefinitionPatterns.Lint(f) - if diff := test.problems.SetDescriptor(f).Diff(got); diff != "" { - t.Error(diff) - } - }) - } -} diff --git a/rules/aep0004/resource_definition_type_name.go b/rules/aep0004/resource_definition_type_name.go deleted file mode 100644 index d47644cd..00000000 --- a/rules/aep0004/resource_definition_type_name.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2022 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 aep0004 - -import ( - "strings" - - "github.com/aep-dev/api-linter/lint" - "github.com/aep-dev/api-linter/locations" - "github.com/aep-dev/api-linter/rules/internal/utils" - "github.com/jhump/protoreflect/desc" -) - -var resourceDefinitionTypeName = &lint.FileRule{ - Name: lint.NewRuleName(4, "resource-definition-type-name"), - RuleType: lint.NewRuleType(lint.MustRule), - OnlyIf: hasResourceDefinitionAnnotation, - LintFile: func(f *desc.FileDescriptor) []lint.Problem { - var problems []lint.Problem - resources := utils.GetResourceDefinitions(f) - for ndx, resource := range resources { - if strings.Count(resource.GetType(), "/") != 1 { - problems = append(problems, lint.Problem{ - Message: "Resource type names must be of the form {Service Name}/{Type}.", - Descriptor: f, - Location: locations.FileResourceDefinition(f, ndx), - }) - } - } - - return problems - }, -} diff --git a/rules/aep0004/resource_definition_type_name_test.go b/rules/aep0004/resource_definition_type_name_test.go deleted file mode 100644 index b1d93627..00000000 --- a/rules/aep0004/resource_definition_type_name_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2022 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 aep0004 - -import ( - "testing" - - "github.com/aep-dev/api-linter/rules/internal/testutils" -) - -func TestResourceDefinitionTypeName(t *testing.T) { - for _, test := range []struct { - name string - TypeName string - problems testutils.Problems - }{ - {"Valid", "library.googleapis.com/Book", testutils.Problems{}}, - {"InvalidTooMany", "library.googleapis.com/shelf/Book", testutils.Problems{{Message: "{Service Name}/{Type}"}}}, - {"InvalidNotEnough", "library.googleapis.com~Book", testutils.Problems{{Message: "{Service Name}/{Type}"}}}, - } { - t.Run(test.name, func(t *testing.T) { - f := testutils.ParseProto3Tmpl(t, ` - import "aep/api/resource.proto"; - import "google/api/resource.proto"; - option (google.api.resource_definition) = { - type: "{{ .TypeName }}" - pattern: "publishers/{publisher}/books/{book}" - }; - `, test) - got := resourceDefinitionTypeName.Lint(f) - if diff := test.problems.SetDescriptor(f).Diff(got); diff != "" { - t.Error(diff) - } - }) - } -} diff --git a/rules/aep0004/resource_definition_variables.go b/rules/aep0004/resource_definition_variables.go deleted file mode 100644 index 49eaea9a..00000000 --- a/rules/aep0004/resource_definition_variables.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2022 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 aep0004 - -import ( - "github.com/aep-dev/api-linter/lint" - "github.com/aep-dev/api-linter/locations" - "github.com/aep-dev/api-linter/rules/internal/utils" - "github.com/jhump/protoreflect/desc" -) - -var resourceDefinitionVariables = &lint.FileRule{ - Name: lint.NewRuleName(4, "resource-definition-variables"), - RuleType: lint.NewRuleType(lint.MustRule), - OnlyIf: hasResourceDefinitionAnnotation, - LintFile: func(f *desc.FileDescriptor) []lint.Problem { - var problems []lint.Problem - resources := utils.GetResourceDefinitions(f) - - for ndx, resource := range resources { - loc := locations.FileResourceDefinition(f, ndx) - p := lintResourceVariablesGoogleAPI(resource, f, loc) - problems = append(problems, p...) - } - return problems - }, -} diff --git a/rules/aep0004/resource_definition_variables_test.go b/rules/aep0004/resource_definition_variables_test.go deleted file mode 100644 index 262f414d..00000000 --- a/rules/aep0004/resource_definition_variables_test.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2022 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 aep0004 - -import ( - "testing" - - "github.com/aep-dev/api-linter/rules/internal/testutils" -) - -func TestResourceDefinitionVariables(t *testing.T) { - for _, test := range []struct { - name string - Pattern string - problems testutils.Problems - }{ - {"Valid", "publishers/{publisher}/electronicBooks/{electronic_book}", testutils.Problems{}}, - {"ValidWithIdSuffix", "publishers/{publisher_id}/electronicBooks/{electronic_book_id}", testutils.Problems{}}, - {"CamelCase", "publishers/{publisher}/electronicBooks/{electronicBook}", testutils.Problems{{ - Message: "publishers/{publisher}/electronicBooks/{electronic_book}", - }}}, - } { - t.Run(test.name, func(t *testing.T) { - f := testutils.ParseProto3Tmpl(t, ` - import "aep/api/resource.proto"; - import "google/api/resource.proto"; - option (google.api.resource_definition) = { - type: "library.googleapis.com/Book" - pattern: "{{.Pattern}}" - }; - `, test) - got := resourceDefinitionVariables.Lint(f) - if diff := test.problems.SetDescriptor(f).Diff(got); diff != "" { - t.Error(diff) - } - }) - } -}