1# Prototiller Requirements for Editions 2 3**Author:** [@mcy](https://github.com/mcy) 4 5**Approved:** 2022-11-29 6 7## Background 8 9Prototiller is Protobuf's new mass refactoring Swiss army knife, similar to 10Buildozer. We plan to use Prototiller to enable LSCs within google3 and to allow 11users (internal and external) to modify `.proto` files safely. 12 13Prototiller is being developed as part of the 14[Editions](../editions/what-are-protobuf-editions.md) project, and will 15prioritize enabling Editions-related refactorings to unblock Editions migrations 16in 2023. This document describes the relevant requirements. 17 18## Overview 19 20*Protochangifier Semantic Actions* (not available externally) describes the 21original design for the Prototiller interface; it would consume a Protobuf 22message that described changes to apply to a `.proto` file passed as input. In 23this document, we prescribe a variant of this interface that fulfills *only* the 24needs of Editions, while remaining extensible for future change actions. 25 26Broad requirements are as follows: 27 28* Actions must include the following Editions-oriented upgrade workflows: 29 * Upgrade a file to a particular edition, regardless of whether it's in 30 syntax mode or editions mode, updating features in such a way to be a 31 no-op. **This is the highest-priority workflow.** 32 * "Clean up" features in a particular file: i.e., run a simple algorithm 33 to determine the smallest set of features that need to be present at 34 each level of the file. 35 * Modify features from a particular syntax element. 36* Actions must be both specific to particular syntax elements (for when change 37 specs are checked in alongside `.proto` files by Schema Consumers), and 38 generic (so that a single change spec or set of change specs can power a 39 large-scale change). 40 41In this document we provide a recommendation for a Protobuf schema based on the 42original Protochangifier design, but geared towards these specific needs. 43 44This is only a recommendation; the Prototiller project owners should modify this 45to suit the implementation; only the requirements in this document are binding, 46and the schema is merely an illustration of those requirements. 47 48The suggested schema is as follows. 49 50``` 51syntax = "proto2"; 52 53package prototiller; 54 55// This is the proto that Prototiller accepts as input. 56message ChangeSpec { 57 // Actions to execute on the file. 58 repeated Action actions = 1; 59 60 // Some changes may result in a wireformat break; changing field type is 61 // usually unsafe. By default, Prototiller does not allow such changes, 62 // users can set allow_unsafe_wire_format_changes to true to force the change. 63 optional bool allow_unsafe_wire_format_changes = 2 [default = false]; 64 optional bool allow_unsafe_text_format_changes = 3 [default = false]; 65 optional bool allow_unsafe_json_format_changes = 4 [default = false]; 66} 67 68// A single action. See messages below for description of their 69// semantics. 70message Action { 71 oneof kind { 72 UpgradeEdition upgrade_edition = 20; 73 CleanUpFeatures clean_up_features = 21; 74 ModifyFeature modify_feature = 22; 75 } 76} 77 78// Upgrades the edition of a file to a specified edition. 79// Treats syntax mode as being a weird, special edition that cannot be 80// upgraded to. 81// 82// This action is always safe. 83message UpgradeEdition { 84 // The edition to upgrade to. 85 optional string edition = 1; 86} 87 88// Cleans up features in a file, such that there are as few explicitly set 89// features as necessary. 90// 91// This action is always safe. 92message CleanUpFeatures {} 93 94// Modifies a specific feature on all syntax elements that match and which can 95// host that particular feature. 96// 97// Prototiller must be aware of which changes affect wire format, so that it 98// can flag them as unsafe. 99message ModifyFeature { 100 // The name of the feature to modify. 101 repeated proto2.UninterpretedOption.NamePart feature = 1; 102 103 // A pattern for matching paths to syntax elements to modify. 104 // 105 // Elements of this field can either be identifiers, or the string "*", which 106 // matches all identifiers. Thus, ["foo", "Bar"] matches the message foo.Bar, 107 // ["foo", "Bar", "*"] matches all fields and nested types of foo.Bar 108 // (recursively), and ["*"] matches all elements of a file. 109 repeated string path_pattern = 2; 110 111 // The value to set the feature to. If not set, this means that the 112 // feature should be deleted. 113 oneof value { 114 int64 int_value = 20; 115 double double_value = 21; 116 // ... and so on. 117 } 118} 119``` 120 121## Alternatives Considered 122 123This document does not capture a design so much as requirements that a design 124must satisfy, so we will be brief on potential alternatives to the requirements, 125and why we decided against them. 126 127* Omit feature cleanup as its own action, and let it happen implicitly as part 128 of other actions. 129 * It is desirable to be able to aggressively run this operation 130 everywhere, potentially even as part of "format on save" in Cider and 131 other IDEs. 132* Make `ModifyFeature` operate on all syntax elements of a file 133 simultaneously. 134 * `ModifyFeature` is intended so that SchemaConsumers can affect 135 fine-grained control of features in `.proto` files they import. Users 136 will want to be able to wipe out a feature from all fields in a file, or 137 perhaps just on a handful of fields they care about. Offering simple 138 pattern-matching supports both. 139