Protobufの破壊的変更を検知するProto Breaking Change Detectorを使ってみた

概要

Protobufの破壊的変更を検知するProto Breaking Change Detectorというツールを使ってみたら、良さそうだった。 github.com

経緯

uber/protool を使うと破壊的変更を検知できるようだったが、リポジトリがarchiveされている。

prototoolの代替として示されているBufの破壊的変更検出 は、buf.yamlディレクトリに置くというBufのルールに従わなければ利用できない。(たぶん。やり方を知っている人がいたら教えて欲しい。)

方法

動かしてみる

mainブランチと現在のワークツリーで、破壊的変更が発生していないかチェックする。

Proto Breaking Change Detector をインストールする。

pip install git+https://github.com/googleapis/proto-breaking-change-detector.git

2つのディレクトリ間でのprotobufの破壊的変更を検知できる。

# --original_api_definition_dirs: 比較元の--proto-pathに指定するディレクトリをカンマ区切りで
# --original_proto_files: 比較元のbeaking changeを検出したいファイルをカンマ区切りで
# --update_api_definition_dirs: 比較先の--proto-pathに指定するディレクトリをカンマ区切りで
# --update_proto_files: 比較先のbeaking changeを検出したいファイルをカンマ区切りで

PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python proto-breaking-change-detector \
    --original_api_definition_dirs=${ORIGINAL_PROTO_PATH} \
    --update_api_definition_dirs=${UPDATE_PROTO_PATH} \
    --original_proto_files=${ORIGINAL_FILE} \
    --update_proto_files=${UPDATE_FILE} \
    --human_readable_message

実行すると、detected_breaking_changes.jsonというファイルが作られて、そこに非破壊的変更("change_type": "MINOR")や、破壊的変更("change_type": "MAJOR")を含む変更の情報が入る。

mainブランチからの破壊的変更を検知してみる

mainブランチと今いるブランチの間で、破壊的変更が無いか比較してみるために、サンプルコードを作った。 github.com

cloneしてブランチを切る。

git clone git@github.com:shiba6v/pbcd_trial.git
cd pbcd_trial
git checkout -b feature/hoge

元のmainブランチのproto/fuga/fuga.proto は、次のような定義にした。

syntax = "proto3";

import "hoge.proto";

message Fuga {
    int64 id = 1;
    Hoge hoge = 2;
}

mainブランチをcloneしてきたままの状態で、proto-breaking-change-detectorを実行するスクリプトを実行する。

sh detect.sh

もちろんoriginのmainブランチから変更はないので、detected_breaking_changes.jsonの中身は空になっている。

[]

次に、破壊的変更と非破壊的変更を加えてみる。 具体的にはHoge hoge = 2;string hoge = 2;に変更して、int64 count = 3;を追加する。

syntax = "proto3";

import "hoge.proto";

message Fuga {
    int64 id = 1;
    string hoge = 2;
    int64 count = 3;
}

再度sh detect.shすると、

$ sh detect.sh
pbcd_trial/protobuf/src: warning: directory does not exist.
pbcd_trial/protobuf/src: warning: directory does not exist.
fuga.proto:3:1: warning: Import hoge.proto is unused.
fuga.proto L7: The type of an existing field `hoge` is changed from `message` to `string` in message `..Fuga`.

mainブランチから見ると破壊的変更("change_type": "MAJOR")が起こっていることが確認できる。

[
  {
    "category": "FIELD_ADDITION",
    "location": {
      "proto_file_name": "fuga.proto",
      "source_code_line": 8
    },
    "change_type": "MINOR",
    "extra_info": null,
    "subject": "count",
    "oldsubject": "",
    "context": "..Fuga",
    "type": "",
    "oldtype": ""
  },
  {
    "category": "FIELD_TYPE_CHANGE",
    "location": {
      "proto_file_name": "fuga.proto",
      "source_code_line": 7
    },
    "change_type": "MAJOR",
    "extra_info": [
      "message Fuga {",
      "hoge"
    ],
    "subject": "hoge",
    "oldsubject": "",
    "context": "..Fuga",
    "type": "string",
    "oldtype": "message"
  }
]

フィールドの追加は、非破壊的変更("change_type": "MINOR")と判定されており、これは正しい。

今後知りたいこと

  • ファイルが追加されるときや、messageがファイルを移動したときはどう検知されるか?
  • protobuf/src: warning: directory does not exist.のWarningを抑えたい。
    • protobuf/srcがデフォルトで--proto-pathに追加されている。

結論

github.com

を使おう。