buf icon indicating copy to clipboard operation
buf copied to clipboard

Missing breaking rule for adding into required enum

Open m-handy opened this issue 3 years ago • 6 comments
trafficstars

According to docs adding a value into required enum is a breaking change

A second issue with required fields appears when someone adds a value to an enum. In this case, the unrecognized enum value is treated as if it were missing, which also causes the required value check to fail.

Running buf breaking does not detect it. Could you please extend the rules to include it?

m-handy avatar Apr 12 '22 13:04 m-handy

@bufdev any thoughts about the issue, please?

m-handy avatar May 03 '22 13:05 m-handy

Can you provide a before and after example of what you think buf breaking should detect?

bufdev avatar Jun 10 '22 22:06 bufdev

Hi, here is an example:

enum Protocol {
    SOME_PROTOCOL = 0;
}

message SomeMessage {
    required Protocol protocol = 1;
}

changed to

enum Protocol {
    SOME_PROTOCOL = 0;
    NEW_PROTOCOL = 1
}

message SomeMessage {
    required Protocol protocol = 1;
}

should be detected as a breaking change.

m-handy avatar Jun 15 '22 11:06 m-handy

@bufdev any updates on this issue?

m-handy avatar Jul 19 '22 13:07 m-handy

@m-handy That sounds like an interesting problem. Curious: what language are you using?

I've experienced a similar type of problem before with an exhaustive switch statements breaking Kotlin code when a new enum is added. We ended up writing a linter for a default case requirement to ensure the APIs were able to add new enum values.

buildbreaker avatar Aug 12 '22 23:08 buildbreaker

It caused a problem in Android app, so Kotlin too

m-handy avatar Aug 17 '22 12:08 m-handy

Is it correct to say that this particular issue is only really relevant in the context of proto2 syntax?

The exhaustiveness checking is another issue. It certainly has merit, but in the exhaustiveness checking case, it would need to be considered a "break" even if the enum was never used as the type of a required field; I believe this is only a source-level break, whereas the required issue is a wire break if I'm understanding the documentation correctly.

jchadwick-buf avatar Oct 31 '22 18:10 jchadwick-buf

Closing this as wontfix for now - this would imply that buf breaking needs to perform a type of checking that is non-transitive. We always want to make sure that buf breaking implies that if going from commit 1 -> 2 is non-breaking, and commit 2 -> 3 is non-breaking, then going from commit 1 -> 3 is non-breaking. However, implementing this feature would require us to take into account the usage of enums in fields, ie is an enum used as a required field. Consider this case:

  • commit 1: enum has one value
  • commit 2: enum has two values
  • commit 3: enum starts being used as a required field

In this scenario, neither 1 -> 2 or 2 -> 3 would result in a breaking change that is detected, but 1 -> 3 would.

Regardless, even if we did this, this is only in the context of a given module and its dependencies, we cannot say that this applies to anyone depending on a module that implements an enum.

bufdev avatar Jan 14 '23 19:01 bufdev

@bufdev Thanks for your comment. I haven't thought about it from such perspective, but what you wrote makes sense.

m-handy avatar Jan 18 '23 14:01 m-handy