diff --git a/api/bazel/repositories.bzl b/api/bazel/repositories.bzl index 74e19f831179f..ef92aa45f0064 100644 --- a/api/bazel/repositories.bzl +++ b/api/bazel/repositories.bzl @@ -47,6 +47,11 @@ def api_dependencies(): name = "opentelemetry_proto", build_file_content = OPENTELEMETRY_LOGS_BUILD_CONTENT, ) + external_http_archive( + name = "com_github_bufbuild_buf", + build_file_content = BUF_BUILD_CONTENT, + tags = ["manual"], + ) PROMETHEUSMETRICS_BUILD_CONTENT = """ load("@envoy_api//bazel:api_build_system.bzl", "api_cc_py_proto_library") @@ -150,3 +155,17 @@ go_proto_library( visibility = ["//visibility:public"], ) """ + +BUF_BUILD_CONTENT = """ +package( + default_visibility = ["//visibility:public"], +) + +filegroup( + name = "buf", + srcs = [ + "@com_github_bufbuild_buf//:bin/buf", + ], + tags = ["manual"], # buf is downloaded as a linux binary; tagged manual to prevent build for non-linux users +) +""" diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index 968c6a9ffa286..b004baf0c58c9 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -118,4 +118,16 @@ REPOSITORY_LOCATIONS_SPEC = dict( urls = ["https://github.com/open-telemetry/opentelemetry-proto/archive/v{version}.tar.gz"], use_category = ["api"], ), + com_github_bufbuild_buf = dict( + project_name = "buf", + project_desc = "A new way of working with Protocol Buffers.", # Used for breaking change detection in API protobufs + project_url = "https://buf.build", + version = "0.48.2", + sha256 = "ee0ea6c4a7bbb016d79b056905c0a1f018e7c5e47b37038c993a77b1bc732c0d", + strip_prefix = "buf", + urls = ["https://github.com/bufbuild/buf/releases/download/v{version}/buf-Linux-x86_64.tar.gz"], + release_date = "2021-07-30", + use_category = ["api"], + tags = ["manual"], + ), ) diff --git a/generated_api_shadow/bazel/repositories.bzl b/generated_api_shadow/bazel/repositories.bzl index 74e19f831179f..ef92aa45f0064 100644 --- a/generated_api_shadow/bazel/repositories.bzl +++ b/generated_api_shadow/bazel/repositories.bzl @@ -47,6 +47,11 @@ def api_dependencies(): name = "opentelemetry_proto", build_file_content = OPENTELEMETRY_LOGS_BUILD_CONTENT, ) + external_http_archive( + name = "com_github_bufbuild_buf", + build_file_content = BUF_BUILD_CONTENT, + tags = ["manual"], + ) PROMETHEUSMETRICS_BUILD_CONTENT = """ load("@envoy_api//bazel:api_build_system.bzl", "api_cc_py_proto_library") @@ -150,3 +155,17 @@ go_proto_library( visibility = ["//visibility:public"], ) """ + +BUF_BUILD_CONTENT = """ +package( + default_visibility = ["//visibility:public"], +) + +filegroup( + name = "buf", + srcs = [ + "@com_github_bufbuild_buf//:bin/buf", + ], + tags = ["manual"], # buf is downloaded as a linux binary; tagged manual to prevent build for non-linux users +) +""" diff --git a/generated_api_shadow/bazel/repository_locations.bzl b/generated_api_shadow/bazel/repository_locations.bzl index 968c6a9ffa286..b004baf0c58c9 100644 --- a/generated_api_shadow/bazel/repository_locations.bzl +++ b/generated_api_shadow/bazel/repository_locations.bzl @@ -118,4 +118,16 @@ REPOSITORY_LOCATIONS_SPEC = dict( urls = ["https://github.com/open-telemetry/opentelemetry-proto/archive/v{version}.tar.gz"], use_category = ["api"], ), + com_github_bufbuild_buf = dict( + project_name = "buf", + project_desc = "A new way of working with Protocol Buffers.", # Used for breaking change detection in API protobufs + project_url = "https://buf.build", + version = "0.48.2", + sha256 = "ee0ea6c4a7bbb016d79b056905c0a1f018e7c5e47b37038c993a77b1bc732c0d", + strip_prefix = "buf", + urls = ["https://github.com/bufbuild/buf/releases/download/v{version}/buf-Linux-x86_64.tar.gz"], + release_date = "2021-07-30", + use_category = ["api"], + tags = ["manual"], + ), ) diff --git a/tools/api_proto_breaking_change_detector/BUILD b/tools/api_proto_breaking_change_detector/BUILD new file mode 100644 index 0000000000000..7eec29a9772b7 --- /dev/null +++ b/tools/api_proto_breaking_change_detector/BUILD @@ -0,0 +1,35 @@ +load("@rules_python//python:defs.bzl", "py_binary", "py_test") + +licenses(["notice"]) # Apache 2 + +py_binary( + name = "proto_breaking_change_detector", + srcs = ["detector.py"], + data = [ + ":buf.lock", + ":buf.yaml", + "@com_github_bufbuild_buf//:buf", + ], + main = "detector.py", + tags = ["manual"], + deps = [ + "//tools:run_command", + ], +) + +py_test( + name = "proto_breaking_change_detector_test", + srcs = ["detector_test.py"], + data = [ + "//tools/testdata/api_proto_breaking_change_detector:proto_breaking_change_detector_testdata", + "@com_github_bufbuild_buf//:buf", + ], + main = "detector_test.py", + python_version = "PY3", + srcs_version = "PY3", + tags = ["manual"], + deps = [ + ":proto_breaking_change_detector", + "@rules_python//python/runfiles", + ], +) diff --git a/tools/api_proto_breaking_change_detector/buf.lock b/tools/api_proto_breaking_change_detector/buf.lock new file mode 100644 index 0000000000000..d33cf64e43a58 --- /dev/null +++ b/tools/api_proto_breaking_change_detector/buf.lock @@ -0,0 +1,45 @@ +# Generated by buf. DO NOT EDIT. +version: v1 +deps: + - remote: buf.build + owner: beta + repository: googleapis + branch: main + commit: 1c473ad9220a49bca9320f4cc690eba5 + digest: b1-unlhrcI3tnJd0JEGuOb692LZ_tY_gCGq6mK1bgCn1Pg= + create_time: 2021-06-23T20:16:47.788079Z + - remote: buf.build + owner: beta + repository: opencensus + branch: main + commit: 5f5f8259293649d68707d2e5b6285748 + digest: b1-myYwcdM0Xu05qIwhiy4eWEcARYUuZZ1vTbYvrrHu1mU= + create_time: 2021-03-03T20:50:42.079743Z + - remote: buf.build + owner: beta + repository: opentelemetry + branch: main + commit: ee82722300c04a618e1c9a2373ce2958 + digest: b1-MwMH-u3ygagogGt6GnJMsqSyxDL-6RKCThaBQRdT_28= + create_time: 2021-06-23T20:17:01.385563Z + - remote: buf.build + owner: beta + repository: prometheus + branch: main + commit: a91b42d18a994cd4b07b37f365f87cf9 + digest: b1-uKmv58fyoNwJI855qg7UEagfdyUl6XNPsFAdDoi57f4= + create_time: 2021-06-23T20:16:58.410272Z + - remote: buf.build + owner: beta + repository: protoc-gen-validate + branch: main + commit: 3aa3a142febe4d198171026cddadb18b + digest: b1-MkZlf7zGl1xvJCsBhk-Kh46tvCHpRNpGNUOtryA9-ng= + create_time: 2021-03-30T19:57:01.168017Z + - remote: buf.build + owner: beta + repository: udpa + branch: main + commit: 64457162aab743c5a695a8cccbd93d8d + digest: b1-15-sblwZI7jDyUli6FyJsBTy8dRe6mHTA2B2VTcIm4g= + create_time: 2021-03-30T19:57:09.877302Z diff --git a/tools/api_proto_breaking_change_detector/buf.yaml b/tools/api_proto_breaking_change_detector/buf.yaml new file mode 100644 index 0000000000000..2f3631072e7c4 --- /dev/null +++ b/tools/api_proto_breaking_change_detector/buf.yaml @@ -0,0 +1,13 @@ +version: v1beta1 +breaking: + use: + - FIELD_SAME_ONEOF + - FIELD_SAME_JSON_NAME + - FIELD_SAME_NAME + - FIELD_SAME_TYPE + - FIELD_SAME_LABEL + - FILE_SAME_PACKAGE + + # needed for allowing removal/reserving of fields + - FIELD_NO_DELETE_UNLESS_NUMBER_RESERVED + - FIELD_NO_DELETE_UNLESS_NAME_RESERVED diff --git a/tools/api_proto_breaking_change_detector/detector.py b/tools/api_proto_breaking_change_detector/detector.py new file mode 100644 index 0000000000000..88fe99ed193a8 --- /dev/null +++ b/tools/api_proto_breaking_change_detector/detector.py @@ -0,0 +1,161 @@ +""" Protocol Buffer Breaking Change Detector + +This tool is used to detect "breaking changes" in protobuf files, to +ensure proper backwards-compatibility in protobuf API updates. The tool +can check for breaking changes of a single API by taking 2 .proto file +paths as input (before and after) and outputting a bool `is_breaking`. + +The breaking change detector creates a temporary directory, copies in +each file to compute a protobuf "state", computes a diff of the "before" +and "after" states, and runs the diff against a set of rules to determine +if there was a breaking change. + +The tool is currently implemented with buf (https://buf.build/) +""" + +import tempfile +from rules_python.python.runfiles import runfiles +from tools.run_command import run_command +from shutil import copyfile +from pathlib import Path +import os +from typing import List + + +class ProtoBreakingChangeDetector(object): + """Abstract breaking change detector interface""" + + def __init__(self, path_to_before: str, path_to_after: str) -> None: + """Initialize the configuration of the breaking change detector + + This function sets up any necessary config without actually + running the detector against any proto files. + + Takes in a single protobuf as 2 files, in a ``before`` state + and an ``after`` state, and checks if the ``after`` state + violates any breaking change rules. + + Args: + path_to_before {str} -- absolute path to the .proto file in the before state + path_to_after {str} -- absolute path to the .proto file in the after state + """ + pass + + def run_detector(self) -> None: + """Run the breaking change detector to detect rule violations + + This method should populate the detector's internal data such + that `is_breaking` and `lock_file_changed` do not require any + additional invocations to the breaking change detector. + """ + pass + + def is_breaking(self) -> bool: + """Return True if breaking changes were detected in the given protos""" + pass + + def lock_file_changed(self) -> bool: + """Return True if the detector state file changed after being run + + This function assumes that the detector uses a lock file to + compare "before" and "after" states of protobufs, which is + admittedly an implementation detail. It is mostly used for + testing, to ensure that the breaking change detector is + checking all of the protobuf features we are interested in. + """ + pass + + +class ChangeDetectorError(Exception): + pass + + +class ChangeDetectorInitializeError(ChangeDetectorError): + pass + + +BUF_STATE_FILE = "tmp.json" + + +class BufWrapper(ProtoBreakingChangeDetector): + """Breaking change detector implemented with buf""" + + def __init__( + self, + path_to_before: str, + path_to_after: str, + additional_args: List[str] = None) -> None: + if not Path(path_to_before).is_file(): + raise ValueError(f"path_to_before {path_to_before} does not exist") + + if not Path(path_to_after).is_file(): + raise ValueError(f"path_to_after {path_to_after} does not exist") + + self._path_to_before = path_to_before + self._path_to_after = path_to_after + self._additional_args = additional_args + + def run_detector(self) -> None: + # buf requires protobuf files to be in a subdirectory of the yaml file + with tempfile.TemporaryDirectory(prefix=str(Path(".").absolute()) + os.sep) as temp_dir: + buf_path = runfiles.Create().Rlocation("com_github_bufbuild_buf/bin/buf") + + buf_config_loc = Path(".", "tools", "api_proto_breaking_change_detector") + + yaml_file_loc = Path(".", "buf.yaml") + copyfile(Path(buf_config_loc, "buf.yaml"), yaml_file_loc) + + target = Path(temp_dir, f"{Path(self._path_to_before).stem}.proto") + + buf_args = [ + "--path", + # buf requires relative pathing for roots + str(target.relative_to(Path(".").absolute())), + "--config", + str(yaml_file_loc), + ] + buf_args.extend(self._additional_args or []) + + copyfile(self._path_to_before, target) + + lock_location = Path(temp_dir, BUF_STATE_FILE) + + initial_code, initial_out, initial_err = run_command( + ' '.join([buf_path, f"build -o {lock_location}", *buf_args])) + initial_out, initial_err = ''.join(initial_out), ''.join(initial_err) + + if initial_code != 0 or len(initial_out) > 0 or len(initial_err) > 0: + raise ChangeDetectorInitializeError( + f"Unexpected error during init:\n\tExit Status Code: {initial_code}\n\tstdout: {initial_out}\n\t stderr: {initial_err}\n" + ) + + with open(lock_location, "r") as f: + self._initial_lock = f.readlines() + + copyfile(self._path_to_after, target) + + final_code, final_out, final_err = run_command( + ' '.join([buf_path, f"breaking --against {lock_location}", *buf_args])) + final_out, final_err = ''.join(final_out), ''.join(final_err) + + if len(final_out) == len(final_err) == final_code == 0: + _, _, _ = run_command(' '.join([buf_path, f"build -o {lock_location}", *buf_args])) + with open(lock_location, "r") as f: + self._final_lock = f.readlines() + + self._initial_result = initial_code, initial_out, initial_err + self._final_result = final_code, final_out, final_err + + def is_breaking(self) -> bool: + final_code, final_out, final_err = self._final_result + + if final_code != 0: + return True + if final_out != "" or "Failure" in final_out: + return True + if final_err != "" or "Failure" in final_err: + return True + return False + + def lock_file_changed(self) -> bool: + return any(before != after for before, after in zip(self._initial_lock, self._final_lock)) diff --git a/tools/api_proto_breaking_change_detector/detector_test.py b/tools/api_proto_breaking_change_detector/detector_test.py new file mode 100644 index 0000000000000..874ad4b788bc3 --- /dev/null +++ b/tools/api_proto_breaking_change_detector/detector_test.py @@ -0,0 +1,112 @@ +""" Proto Breaking Change Detector Test Suite + +This script evaluates breaking change detectors (e.g. buf) against +different protobuf file changes to ensure proper and consistent behavior +in `allowed`and `breaking` circumstances. Although the dependency likely +already tests for these circumstances, these specify Envoy's requirements +and ensure that tool behavior is consistent across dependency updates. +""" + +from pathlib import Path +import unittest + +from detector import BufWrapper + + +class BreakingChangeDetectorTests(object): + detector_type = None + + def run_detector_test(self, testname, is_breaking, expects_changes, additional_args=None): + """Runs a test case for an arbitrary breaking change detector type""" + tests_path = Path( + Path(__file__).absolute().parent.parent, "testdata", + "api_proto_breaking_change_detector", "breaking" if is_breaking else "allowed") + + current = Path(tests_path, f"{testname}_current") + changed = Path(tests_path, f"{testname}_next") + + detector_obj = self.detector_type(current, changed, additional_args) + detector_obj.run_detector() + + breaking_response = detector_obj.is_breaking() + self.assertEqual(breaking_response, is_breaking) + + lock_file_changed_response = detector_obj.lock_file_changed() + self.assertEqual(lock_file_changed_response, expects_changes) + + +class TestBreakingChanges(BreakingChangeDetectorTests): + + def run_breaking_test(self, testname): + self.run_detector_test(testname, is_breaking=True, expects_changes=False) + + def test_change_field_id(self): + self.run_breaking_test(self.test_change_field_id.__name__) + + def test_change_field_type(self): + self.run_breaking_test(self.test_change_field_type.__name__) + + def test_change_field_plurality(self): + self.run_breaking_test(self.test_change_field_plurality.__name__) + + def test_change_field_name(self): + self.run_breaking_test(self.test_change_field_name.__name__) + + def test_change_package_name(self): + self.run_breaking_test(self.test_change_package_name.__name__) + + def test_change_field_from_oneof(self): + self.run_breaking_test(self.test_change_field_from_oneof.__name__) + + def test_change_field_to_oneof(self): + self.run_breaking_test(self.test_change_field_to_oneof.__name__) + + def test_change_pgv_field(self): + self.run_breaking_test(self.test_change_pgv_field.__name__) + + def test_change_pgv_message(self): + self.run_breaking_test(self.test_change_pgv_message.__name__) + + def test_change_pgv_oneof(self): + self.run_breaking_test(self.test_change_pgv_oneof.__name__) + + +class TestAllowedChanges(BreakingChangeDetectorTests): + + def run_allowed_test(self, testname): + self.run_detector_test(testname, is_breaking=False, expects_changes=True) + + def test_add_comment(self): + self.run_allowed_test(self.test_add_comment.__name__) + + def test_add_field(self): + self.run_allowed_test(self.test_add_field.__name__) + + def test_add_option(self): + self.run_allowed_test(self.test_add_option.__name__) + + def test_add_enum_value(self): + self.run_allowed_test(self.test_add_enum_value.__name__) + + def test_remove_and_reserve_field(self): + self.run_allowed_test(self.test_remove_and_reserve_field.__name__) + + +class BufTests(TestAllowedChanges, TestBreakingChanges, unittest.TestCase): + detector_type = BufWrapper + + @unittest.skip("PGV field support not yet added to buf") + def test_change_pgv_field(self): + pass + + @unittest.skip("PGV message option support not yet added to buf") + def test_change_pgv_message(self): + pass + + @unittest.skip("PGV oneof option support not yet added to buf") + def test_change_pgv_oneof(self): + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/testdata/api_proto_breaking_change_detector/BUILD b/tools/testdata/api_proto_breaking_change_detector/BUILD new file mode 100644 index 0000000000000..5fb56cefbd2b4 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/BUILD @@ -0,0 +1,40 @@ +licenses(["notice"]) # Apache 2 + +filegroup( + name = "proto_breaking_change_detector_testdata", + srcs = [ + "allowed/test_add_comment_current", + "allowed/test_add_comment_next", + "allowed/test_add_enum_value_current", + "allowed/test_add_enum_value_next", + "allowed/test_add_field_current", + "allowed/test_add_field_next", + "allowed/test_add_option_current", + "allowed/test_add_option_next", + "allowed/test_force_breaking_change_current", + "allowed/test_force_breaking_change_next", + "allowed/test_remove_and_reserve_field_current", + "allowed/test_remove_and_reserve_field_next", + "breaking/test_change_field_from_oneof_current", + "breaking/test_change_field_from_oneof_next", + "breaking/test_change_field_id_current", + "breaking/test_change_field_id_next", + "breaking/test_change_field_name_current", + "breaking/test_change_field_name_next", + "breaking/test_change_field_plurality_current", + "breaking/test_change_field_plurality_next", + "breaking/test_change_field_to_oneof_current", + "breaking/test_change_field_to_oneof_next", + "breaking/test_change_field_type_current", + "breaking/test_change_field_type_next", + "breaking/test_change_package_name_current", + "breaking/test_change_package_name_next", + "breaking/test_change_pgv_field_current", + "breaking/test_change_pgv_field_next", + "breaking/test_change_pgv_message_current", + "breaking/test_change_pgv_message_next", + "breaking/test_change_pgv_oneof_current", + "breaking/test_change_pgv_oneof_next", + ], + visibility = ["//visibility:public"], +) diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_comment_current b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_comment_current new file mode 100644 index 0000000000000..ff7a78b1fc434 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_comment_current @@ -0,0 +1,9 @@ +syntax = "proto3"; +package test.protos.breaking; + +option java_package = "io.envoyproxy.envoy.protolock"; +option java_outer_classname = "EnvoyProtolock"; +option java_multiple_files = true; + +message CommonExtensionConfig { +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_comment_next b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_comment_next new file mode 100644 index 0000000000000..8bd44e75c89b8 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_comment_next @@ -0,0 +1,10 @@ +syntax = "proto3"; +package test.protos.breaking; + +option java_package = "io.envoyproxy.envoy.protolock"; +option java_outer_classname = "EnvoyProtolock"; +option java_multiple_files = true; + +// Common configuration for all tap extensions. +message CommonExtensionConfig { +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_enum_value_current b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_enum_value_current new file mode 100644 index 0000000000000..0663f21f38ac6 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_enum_value_current @@ -0,0 +1,17 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SearchRequest { + string query = 1; + int32 page_number = 2; + int32 result_per_page = 3; + enum Corpus { + UNIVERSAL = 0; + WEB = 1; + IMAGES = 2; + LOCAL = 3; + NEWS = 4; + PRODUCTS = 5; + } + Corpus corpus = 4; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_enum_value_next b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_enum_value_next new file mode 100644 index 0000000000000..290aea11693ce --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_enum_value_next @@ -0,0 +1,18 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SearchRequest { + string query = 1; + int32 page_number = 2; + int32 result_per_page = 3; + enum Corpus { + UNIVERSAL = 0; + WEB = 1; + IMAGES = 2; + LOCAL = 3; + NEWS = 4; + PRODUCTS = 5; + VIDEO = 6; + } + Corpus corpus = 4; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_field_current b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_field_current new file mode 100644 index 0000000000000..4a38563f01d97 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_field_current @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string three = 3; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_field_next b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_field_next new file mode 100644 index 0000000000000..b17fe188e3fea --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_field_next @@ -0,0 +1,7 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string three = 3; + float four = 4; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_option_current b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_option_current new file mode 100644 index 0000000000000..f6f3f59b856d7 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_option_current @@ -0,0 +1,9 @@ +syntax = "proto3"; +package test.protos.breaking; + +option java_package = "io.envoyproxy.envoy.protolock"; +option java_outer_classname = "EnvoyProtolock"; + +// Common configuration for all tap extensions. +message CommonExtensionConfig { +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_option_next b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_option_next new file mode 100644 index 0000000000000..8bd44e75c89b8 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_add_option_next @@ -0,0 +1,10 @@ +syntax = "proto3"; +package test.protos.breaking; + +option java_package = "io.envoyproxy.envoy.protolock"; +option java_outer_classname = "EnvoyProtolock"; +option java_multiple_files = true; + +// Common configuration for all tap extensions. +message CommonExtensionConfig { +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_force_breaking_change_current b/tools/testdata/api_proto_breaking_change_detector/allowed/test_force_breaking_change_current new file mode 100644 index 0000000000000..4a38563f01d97 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_force_breaking_change_current @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string three = 3; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_force_breaking_change_next b/tools/testdata/api_proto_breaking_change_detector/allowed/test_force_breaking_change_next new file mode 100644 index 0000000000000..2059fdb4f514e --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_force_breaking_change_next @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + float three = 3; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_remove_and_reserve_field_current b/tools/testdata/api_proto_breaking_change_detector/allowed/test_remove_and_reserve_field_current new file mode 100644 index 0000000000000..b17fe188e3fea --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_remove_and_reserve_field_current @@ -0,0 +1,7 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string three = 3; + float four = 4; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/allowed/test_remove_and_reserve_field_next b/tools/testdata/api_proto_breaking_change_detector/allowed/test_remove_and_reserve_field_next new file mode 100644 index 0000000000000..f2ffa0510ad37 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/allowed/test_remove_and_reserve_field_next @@ -0,0 +1,9 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + reserved 4; + reserved "four"; + + string three = 3; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_from_oneof_current b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_from_oneof_current new file mode 100644 index 0000000000000..564601045ee9a --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_from_oneof_current @@ -0,0 +1,10 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + oneof test_oneof { + string name = 4; + string sub_message = 9; + float special = 10; + } +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_from_oneof_next b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_from_oneof_next new file mode 100644 index 0000000000000..b4965f64fd7ac --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_from_oneof_next @@ -0,0 +1,10 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + oneof test_oneof { + string name = 4; + string sub_message = 9; + } + float special = 10; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_id_current b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_id_current new file mode 100644 index 0000000000000..4a38563f01d97 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_id_current @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string three = 3; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_id_next b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_id_next new file mode 100644 index 0000000000000..35984ed9637b9 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_id_next @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string three = 42; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_name_current b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_name_current new file mode 100644 index 0000000000000..4471dbbb1a208 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_name_current @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string seventeen = 17; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_name_next b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_name_next new file mode 100644 index 0000000000000..c6003d1384893 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_name_next @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string twenty = 17; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_plurality_current b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_plurality_current new file mode 100644 index 0000000000000..09e5e4374eeff --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_plurality_current @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string from = 1; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_plurality_next b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_plurality_next new file mode 100644 index 0000000000000..63a5af85d0b24 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_plurality_next @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + repeated string from = 1; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_to_oneof_current b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_to_oneof_current new file mode 100644 index 0000000000000..1bb452fdb9414 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_to_oneof_current @@ -0,0 +1,10 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + oneof test_oneof { + string name = 4; + string sub_message = 9; + } + float loner = 10; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_to_oneof_next b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_to_oneof_next new file mode 100644 index 0000000000000..3336f4e384e92 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_to_oneof_next @@ -0,0 +1,10 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + oneof test_oneof { + string name = 4; + string sub_message = 9; + float loner = 10; + } +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_type_current b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_type_current new file mode 100644 index 0000000000000..5cae750860e12 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_type_current @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + float pi = 314; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_type_next b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_type_next new file mode 100644 index 0000000000000..b235c8e224d0d --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_field_type_next @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string pi = 314; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_package_name_current b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_package_name_current new file mode 100644 index 0000000000000..f48663822058d --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_package_name_current @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string passcode = 69; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_package_name_next b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_package_name_next new file mode 100644 index 0000000000000..867e36699374c --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_package_name_next @@ -0,0 +1,6 @@ +syntax = "proto3"; +package wrong.package; + +message SampleMessage { + string passcode = 69; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_field_current b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_field_current new file mode 100644 index 0000000000000..72b792e819e5e --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_field_current @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string useremail = 1 [(validate.rules).string.email = true]; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_field_next b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_field_next new file mode 100644 index 0000000000000..2715676735f30 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_field_next @@ -0,0 +1,6 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + string useremail = 1 [(validate.rules).string.email = false]; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_message_current b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_message_current new file mode 100644 index 0000000000000..1df9b09c14b28 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_message_current @@ -0,0 +1,8 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + option (validate.disabled) = true; + + SampleMessage q = 543; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_message_next b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_message_next new file mode 100644 index 0000000000000..62fd2266f00fc --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_message_next @@ -0,0 +1,8 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + option (validate.disabled) = false; + + SampleMessage q = 543; +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_oneof_current b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_oneof_current new file mode 100644 index 0000000000000..266d6fee1cfd0 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_oneof_current @@ -0,0 +1,10 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + oneof test_oneof { + option (validate.required) = true; + string name = 4; + string sub_message = 9;; + } +} diff --git a/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_oneof_next b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_oneof_next new file mode 100644 index 0000000000000..989642b4aca82 --- /dev/null +++ b/tools/testdata/api_proto_breaking_change_detector/breaking/test_change_pgv_oneof_next @@ -0,0 +1,10 @@ +syntax = "proto3"; +package test.protos.breaking; + +message SampleMessage { + oneof test_oneof { + option (validate.required) = false; + string name = 4; + string sub_message = 9;; + } +}