github.com/jwilson-ts/prototool@v1.3.0/README.md (about) 1 # prototool [![Mit License][mit-img]][mit] [![GitHub Release][release-img]][release] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] 2 3 [Protobuf](https://developers.google.com/protocol-buffers) is one of the best interface description languages out there - it's widely adopted, and after over 15 years of use, it's practically bulletproof. However, working with Protobuf and maintaining consistency across your Protobuf files can be a pain - protoc, while being a tool that has stood the test of time, is non-trivial to use, and the Protobuf community has not developed common standards with regards to stub generation. Prototool aims to solve this by making working with Protobuf much simpler. 4 5 Prototool lets you: 6 7 - Handle installation of protoc and the import of all of the Well-Known Types behind the scenes in a platform-independent manner without any work on the part of the user. 8 - Standardize building of your Protobuf files with a common configuration, abstracting away all of the pain of protoc for you. 9 - Lint your Protobuf files with common linting rules according to a Style Guide. 10 - Format your Protobuf files in a consistent manner. 11 - Generate Protobuf files from a template that passes lint, taking care of package naming for you. 12 - Generate stubs using any plugin based on a simple configuration file, including handling imports of all the Well-Known Types. 13 - Call gRPC endpoints with ease, taking care of the JSON to binary conversion for you. 14 - Output errors and lint failures in a common file:line:column:message format, making integration with editors possible, Vim integration is provided out of the box. 15 16 Prototool accomplishes this by downloading and calling protoc on the fly for you, handing error messages from protoc and your plugins, and using the generated FileDescriptorSets for internal functionality, as well as wrapping a few great external libraries already in the Protobuf ecosystem. 17 18 * [Installation](#installation) 19 * [Quick Start](#quick-start) 20 * [Full Example](#full-example) 21 * [Configuration](#configuration) 22 * [File Discovery](#file-discovery) 23 * [Command Overview](#command-overview) 24 * [prototool config init](#prototool-config-init) 25 * [prototool compile](#prototool-compile) 26 * [prototool generate](#prototool-generate) 27 * [prototool lint](#prototool-lint) 28 * [prototool format](#prototool-format) 29 * [prototool create](#prototool-create) 30 * [prototool files](#prototool-files) 31 * [prototool grpc](#prototool-grpc) 32 * [gRPC Example](#grpc-example) 33 * [Tips and Tricks](#tips-and-tricks) 34 * [Vim Integration](#vim-integration) 35 * [Development](#development) 36 * [FAQ](#faq) 37 * [Pre-Cache Protoc](#pre-cache-protoc) 38 * [Alpine Linux Issues](#alpine-linux-issues) 39 * [Managing External Plugins/Docker](#managing-external-pluginsdocker) 40 * [Lint/Format Choices](#lintformat-choices) 41 * [Special Thanks](#special-thanks) 42 43 ## Installation 44 45 Prototool can be installed on Mac OS X via [Homebrew](https://brew.sh/) or Linux via [Linuxbrew](http://linuxbrew.sh/). 46 47 ```bash 48 brew install prototool 49 ``` 50 51 This installs the `prototool` binary, along with bash completion, zsh completion, and man pages. 52 You can also install all of the assets on Linux or without Homebrew from GitHub Releases. 53 54 ```bash 55 curl -sSL https://github.com/uber/prototool/releases/download/v1.3.0/prototool-$(uname -s)-$(uname -m).tar.gz | \ 56 tar -C /usr/local --strip-components 1 -xz 57 ``` 58 59 If you do not want to install bash completion, zsh completion, or man mages, you can install just the 60 `prototool` binary from GitHub Releases as well. 61 62 ```bash 63 curl -sSL https://github.com/uber/prototool/releases/download/v1.3.0/prototool-$(uname -s)-$(uname -m) \ 64 -o /usr/local/bin/prototool && \ 65 chmod +x /usr/local/bin/prototool 66 ``` 67 68 Prototool is purposefully all put under internal in an attempt to emphasize that you should not install `prototool` with `go get`. 69 Although you can technically `go get` from `internal`, we do not check in the vendor directory, so `go get` will not respect the 70 versions in `glide.yaml`. We have specific version requirements, so not using these can and probably will result in errors when building 71 `prototool` and/or result in unexpected runtime errors. 72 73 ## Quick Start 74 75 We'll start with a general overview of the commands. There are more commands, and we will get into usage below, but this shows the basic functionality. 76 77 ```bash 78 prototool help 79 prototool lint path/to/foo.proto path/to/bar.proto # file mode, specify multiple specific files 80 prototool lint idl/uber # directory mode, search for all .proto files recursively, obeying exclude_paths in prototool.yaml or prototool.json files 81 prototool lint # same as "prototool lint .", by default the current directory is used in directory mode 82 prototool create foo.proto # create the file foo.proto from a template that passes lint 83 prototool files idl/uber # list the files that will be used after applying exclude_paths from corresponding prototool.yaml or prototool.json files 84 prototool lint --list-linters # list all current lint rules being used 85 prototool compile idl/uber # make sure all .proto files in idl/uber compile, but do not generate stubs 86 prototool generate idl/uber # generate stubs, see the generation directives in the config file example 87 prototool grpc idl/uber --address 0.0.0.0:8080 --method foo.ExcitedService/Exclamation --data '{"value":"hello"}' # call the foo.ExcitedService method Exclamation with the given data on 0.0.0.0:8080 88 ``` 89 90 ## Full Example 91 92 See the [example](example) directory. 93 94 The make command `make example` runs prototool while installing the necessary plugins. 95 96 ## Configuration 97 98 Prototool operates using a config file named either `prototool.yaml` or `prototool.json`. Only one of `prototool.yaml` or `prototool.json` can exist in a given directory. For non-trivial use, you should have a config file checked in to at least the root of your repository. It is important because the directory of an associated config file is passed to `protoc` as an include directory with `-I`, so this is the logical location your Protobuf file imports should start from. 99 100 Recommended base config file: 101 102 ```yaml 103 protoc: 104 version: 3.6.1 105 ``` 106 107 The command `prototool config init` will generate a config file in the current directory with all available configuration options commented out except `protoc.version`. See [etc/config/example/prototool.yaml](etc/config/example/prototool.yaml) for the config file that `prototool config init --uncomment` generates. 108 109 When specifying a directory or set of files for Prototool to operate on, Prototool will search for config files for each directory starting at the given path, and going up a directory until hitting root. If no config file is found, Prototool will use default values and operate as if there was a config file in the current directory, including the current directory with `-I` to `protoc`. 110 111 If multiple `prototool.yaml` or `prototool.json` files are found that match the input directory or files, an error will be returned. 112 113 ## File Discovery 114 115 In most Prototool commands, you will see help along the following lines: 116 117 ```bash 118 $ prototool help lint 119 Lint proto files and compile with protoc to check for failures. 120 121 Usage: 122 prototool lint [dirOrFile] [flags] 123 ``` 124 125 `dirOrFile` can take two forms: 126 127 - You can specify exactly one directory. If this is done, Prototool goes up until it finds a `prototool.yaml` or `prototool.json` file (or uses the current directory if none is found), and then walks starting at this location for all `.proto` files, and these are used, except for files in the `excludes` lists in `prototool.yaml` or `prototool.json` files. 128 - You can specify exactly one file. This has the effect as if you specified the directory of this file (using the logic above), but errors are only printed for that file. This is useful for e.g. Vim integration. 129 - You can specify nothing. This has the effect as if you specified the current directory as the directory. 130 131 The idea with "directory builds" is that you often need more than just one file to do a `protoc` call, for example if you have types in other files in the same package that are not referenced by their fully-qualified name, and/or if you need to know what directories to specify with `-I` to `protoc` (by default, the directory of the `prototool.yaml` or `prototool.json` file is used). 132 133 ## Command Overview 134 135 Let's go over some of the basic commands. 136 137 ##### `prototool config init` 138 139 Create a `prototool.yaml` file in the current directory, with all options except `protoc.version` commented out. 140 141 ##### `prototool compile` 142 143 Compile your Protobuf files, but do not generate stubs. This has the effect of calling `protoc` with `-o /dev/null`. 144 145 ##### `prototool generate` 146 147 Compile your Protobuf files and generate stubs according to the rules in your `prototool.yaml` or `prototool.json` file. See [example/idl/uber/prototool.yaml](example/idl/uber/prototool.yaml) for an example. 148 149 ##### `prototool lint` 150 151 Lint your Protobuf files. The default rule set follows the Style Guide at [etc/style/uber/uber.proto](etc/style/uber/uber.proto). You can add or exclude lint rules in your `prototool.yaml` or `prototool.json` file. The default rule set is "strict", and we are working on having two main sets of rules. 152 153 ##### `prototool format` 154 155 Format a Protobuf file and print the formatted file to stdout. There are flags to perform different actions: 156 157 - `-d` Write a diff instead. 158 - `-f` Fix the file according to the Style Guide. 159 - `-l` Write a lint error in the form file:line:column:message if a file is unformatted. 160 - `-w` Overwrite the existing file instead. 161 162 Concretely, the `-f` flag can be used so that the values for `java_multiple_files`, `java_outer_classname`, and `java_package` are updated to reflect what is expected by the 163 [Google Cloud APIs file structure](https://cloud.google.com/apis/design/file_structure), and the value of `go_package` is updated to reflect what we expect for the 164 default Style Guide. By formatting, the linting for these values will pass by default. See the documentation below for `prototool create` for an example. 165 166 ##### `prototool create` 167 168 Create a Protobuf file from a template that passes lint. Assuming the filename `example_create_file.proto`, the file will look like the following: 169 170 ```proto 171 syntax = "proto3"; 172 173 package SOME.PKG; 174 175 option go_package = "PKGpb"; 176 option java_multiple_files = true; 177 option java_outer_classname = "ExampleCreateFileProto"; 178 option java_package = "com.SOME.PKG.pb"; 179 ``` 180 181 This matches what the linter expects. `SOME.PKG` will be computed as follows: 182 183 - If `--package` is specified, `SOME.PKG` will be the value passed to `--package`. 184 - Otherwise, if there is no `prototool.yaml` or `prototool.json` that would apply to the new file, use `uber.prototool.generated`. 185 - Otherwise, if there is a `prototool.yaml` or `prototool.json` file, check if it has a `packages` setting under the 186 `create` section (see [etc/config/example/prototool.yaml](etc/config/example/prototool.yaml) for an example). 187 If it does, this package, concatenated with the relative path from the directory with the `prototool.yaml` or `prototool.json` file will be used. 188 - Otherwise, if there is no `packages` directive, just use the relative path from the directory 189 with the `prototool.yaml` or `prototool.json` file. If the file is in the same directory as the `prototoo.yaml` file, 190 use `uber.prototool.generated` 191 192 For example, assume you have the following file at `repo/prototool.yaml`: 193 194 ```yaml 195 create: 196 packages: 197 - directory: idl 198 name: uber 199 - directory: idl/baz 200 name: special 201 ``` 202 203 - `prototool create repo/idl/foo/bar/bar.proto` will have the package `uber.foo.bar`. 204 - `prototool create repo/idl/bar.proto` will have the package `uber`. 205 - `prototool create repo/idl/baz/baz.proto` will have the package `special`. 206 - `prototool create repo/idl/baz/bat/bat.proto` will have the package `special.bat`. 207 - `prototool create repo/another/dir/bar.proto` will have the package `another.dir`. 208 - `prototool create repo/bar.proto` will have the package `uber.prototool.generated`. 209 210 This is meant to mimic what you generally want - a base package for your idl directory, followed 211 by packages matching the directory structure. 212 213 Note you can override the directory that the `prototool.yaml` or `prototool.json` file is in as well. If we update our 214 file at `repo/prototool.yaml` to this: 215 216 ```yaml 217 create: 218 packages: 219 - directory: . 220 name: foo.bar 221 ``` 222 223 Then `prototool create repo/bar.proto` will have the package `foo.bar`, and `prototool create repo/another/dir/bar.proto` 224 will have the package `foo.bar.another.dir`. 225 226 If [Vim integration](#vim-integration) is set up, files will be generated when you open a new Protobuf file. 227 228 ##### `prototool files` 229 230 Print the list of all files that will be used given the input `dirOrFile`. Useful for debugging. 231 232 ##### `prototool grpc` 233 234 Call a gRPC endpoint using a JSON input. What this does behind the scenes: 235 236 - Compiles your Protobuf files with `protoc`, generating a `FileDescriptorSet`. 237 - Uses the `FileDescriptorSet` to figure out the request and response type for the endpoint, and to convert the JSON input to binary. 238 - Calls the gRPC endpoint. 239 - Uses the `FileDescriptorSet` to convert the resulting binary back to JSON, and prints it out for you. 240 241 All these steps take on the order of milliseconds, for example the overhead for a file with four dependencies is about 30ms, so there is little overhead for CLI calls to gRPC. 242 243 ## gRPC Example 244 245 There is a full example for gRPC in the [example](example) directory. Run `make init example` to make sure everything is installed and generated. 246 247 Start the example server in a separate terminal by doing `go run example/cmd/excited/main.go`. 248 249 `prototool grpc [dirOrFile] --address serverAddress --method package.service/Method --data 'requestData'` 250 251 Either use `--data 'requestData'` as the the JSON data to input, or `--stdin` which will result in the input being read from stdin as JSON. 252 253 ```bash 254 $ make init example # make sure everything is built just in case 255 256 $ prototool grpc example \ 257 --address 0.0.0.0:8080 \ 258 --method foo.ExcitedService/Exclamation \ 259 --data '{"value":"hello"}' 260 { 261 "value": "hello!" 262 } 263 264 $ prototool grpc example \ 265 --address 0.0.0.0:8080 \ 266 --method foo.ExcitedService/ExclamationServerStream \ 267 --data '{"value":"hello"}' 268 { 269 "value": "h" 270 } 271 { 272 "value": "e" 273 } 274 { 275 "value": "l" 276 } 277 { 278 "value": "l" 279 } 280 { 281 "value": "o" 282 } 283 { 284 "value": "!" 285 } 286 287 $ cat input.json 288 {"value":"hello"} 289 {"value":"salutations"} 290 291 $ cat input.json | prototool grpc example \ 292 --address 0.0.0.0:8080 \ 293 --method foo.ExcitedService/ExclamationClientStream \ 294 --stdin 295 { 296 "value": "hellosalutations!" 297 } 298 299 $ cat input.json | prototool grpc example \ 300 --address 0.0.0.0:8080 \ 301 --method foo.ExcitedService/ExclamationBidiStream \ 302 --stdin 303 { 304 "value": "hello!" 305 } 306 { 307 "value": "salutations!" 308 } 309 ``` 310 311 ## Tips and Tricks 312 313 Prototool is meant to help enforce a consistent development style for Protobuf, and as such you should follow some basic rules: 314 315 - Have all your imports start from the directory your `prototool.yaml` or `prototool.json` file is in. While there is a configuration option `protoc.includes` to denote extra include directories, this is not recommended. 316 - Have all Protobuf files in the same directory use the same `package`, and use the same values for `go_package`, `java_multiple_files`, `java_outer_classname`, and `java_package`. 317 - Do not use long-form `go_package` values, ie use `foopb`, not `github.com/bar/baz/foo;foopb`. This helps `prototool generate` do the best job. 318 319 ## Vim Integration 320 321 This repository is a self-contained plugin for use with the [ALE Lint Engine](https://github.com/w0rp/ale). It should be similarly easy to add support for Syntastic, Neomake, etc. 322 323 The Vim integration will currently provide lint errors, optionally regenerate all the stubs, and optionally format your files on save. It 324 will also optionally create new files from a template when opened. 325 326 The plugin is under [vim/prototool](vim/prototool), so your plugin manager needs to point there instead of the base of this repository. Assuming you are using [vim-plug](https://github.com/junegunn/vim-plug), copy/paste the following into your vimrc and you should be good to go. If you are using [Vundle](https://github.com/VundleVim/Vundle.vim), just replace `Plug` with `Vundle` below. 327 328 ```vim 329 " Prototool must be installed as a binary for the Vim integration to work. 330 331 " Add ale and prototool with your package manager. 332 " Note that Plug downloads from dev by default. There may be minor changes 333 " to the Vim integration on dev between releases, but this won't be common. 334 " To make sure you are on the same branch as your Prototool install, set 335 " the branch field in the options for uber/prototool per the vim-plug 336 " documentation. Vundle does not allow setting branches, so on Vundle, 337 " go into plug directory and checkout the branch of the release you are on. 338 Plug 'w0rp/ale' 339 Plug 'uber/prototool', { 'rtp':'vim/prototool' } 340 341 " We recommend setting just this for Golang, as well as the necessary set for proto. 342 let g:ale_linters = { 343 \ 'go': ['golint'], 344 \ 'proto': ['prototool'], 345 \} 346 " We recommend you set this. 347 let g:ale_lint_on_text_changed = 'never' 348 " Set to 'lint' to not do code generation. 349 " Set to 'compile' to not do linting either and just compile without code generation. 350 "let g:ale_proto_prototool_command = 'compile' 351 352 " We generally have <leader> mapped to ",", uncomment this to set leader. 353 "let mapleader="," 354 355 " ,f will toggle formatting on and off. 356 " Change to PrototoolFormatFixToggle to toggle with --fix instead. 357 nnoremap <silent> <leader>f :call PrototoolFormatToggle()<CR> 358 " ,c will toggle create on and off. 359 nnoremap <silent> <leader>c :call PrototoolCreateToggle()<CR> 360 361 " Uncomment this to enable formatting by default. 362 "call PrototoolFormatEnable() 363 " Uncomment this to enable formatting with --fix by default. 364 "call PrototoolFormatFixEnable() 365 " Uncomment this to disable creating Protobuf files from a template by default. 366 "call PrototoolCreateDisable() 367 ``` 368 369 Editor integration is a key goal of Prototool. We've demonstrated support internally for Intellij, and hope that we have integration for more editors in the future. 370 371 ## Development 372 373 Prototool is under active development. If you want to help, here's some places to start: 374 375 - Try out `prototool` and file feature requests or bug reports. 376 - Submit PRs with any changes you'd like to see made. 377 378 We appreciate any input you have! 379 380 Before filing an issue or submitting a PR, make sure to review the [Issue Guidelines](https://github.com/uber/prototool/blob/dev/.github/ISSUE_TEMPLATE.md), and before submitting a PR, make sure to also review 381 the [PR Guidelines](https://github.com/uber/prototool/blob/dev/.github/PULL_REQUEST_TEMPLATE.md). The Issue Guidelines will show up in the description field when filing a new issue, and the PR guidelines will show up in the 382 description field when submitting a PR, but clear the description field of this pre-populated text once you've read it :-) 383 384 Note that development of Prototool will only work with Golang 1.10 or newer. On initially cloning the repository, run `make init` if you have not already to download dependencies to `vendor`. 385 386 Before submitting a PR, make sure to: 387 388 - Run `make generate` to make sure there is no diff. 389 - Run `make` to make sure all tests pass. This is functionally equivalent to the tests run on CI. 390 391 All Golang code is purposefully under the `internal` package to not expose any API for the time being. 392 393 ## FAQ 394 395 ##### Pre-Cache Protoc 396 397 *Question:* How do I download `protoc` ahead of time as part of a Docker build/CI pipeline? 398 399 *Answer*: We used to have a command that did this, but removed it for simplicity and because the command as implemented did not properly 400 read the configuration file to figure out what version of `protoc` to download. We may re-add this command in the future, however 401 here is a technique to accomplish this, including as a `RUN` directive for Docker: 402 403 ```bash 404 # the first rm -rf call is not needed if this is a RUN directive for Docker 405 rm -rf /tmp/prototool-bootstrap && \ 406 echo $'protoc\n version: 3.6.1' > /tmp/prototool-bootstrap/prototool.yaml && \ 407 echo 'syntax = "proto3";' > /tmp/prototool-bootstrap/tmp.proto && \ 408 prototool compile /tmp/prototool-bootstrap && \ 409 rm -rf /tmp/prototool-bootstrap 410 ``` 411 412 The better way to do this as part of a bash script would be to use `mktemp -d` i.e.: 413 414 ```bash 415 #!/bin/bash 416 417 set -euo pipefail 418 419 TMPDIR="$(mktemp -d)" 420 trap 'rm -rf "${TMPDIR}"' EXIT 421 422 echo $'protoc\n version: 3.6.1' > "${TMPDIR}/prototool.yaml" 423 echo 'syntax = "proto3";' > "${TMPDIR}/tmp.proto" 424 prototool compile "${TMPDIR}" 425 ``` 426 427 But for Darwin or Linux, the above should work. 428 429 ##### Alpine Linux Issues 430 431 *Question:* Help! Prototool is failing when I use it within a Docker image based on Alpine Linux! 432 433 *Answer:* `apk add libc6-compat` 434 435 `protoc` is not statically compiled, and adding this packages fixes the problem. 436 437 ##### Managing External Plugins/Docker 438 439 *Question:* Can Prototool manage my external plugins such as protoc-gen-go? 440 441 *Answer:* Unfortunately, no. This was an explicit design decision - Prototool is not meant to "know the world", instead 442 Prototool just takes care of what it is good at (managing your Protobuf build) to keep Prototool simple, leaving you to do 443 external plugin management. Prototool does provide the ability to use the "built-in" output directives `cpp, csharp, java, js, objc, php, python, ruby` 444 provided by `protoc` out of the box, however. 445 446 If you want to have a consistent build environment for external plugins, we recommend creating a Docker image. Here's an example `Dockerfile` that 447 results in a Docker image around 33MB that contains `prototool`, a cached `protoc`, and `protoc-gen-go`: 448 449 ```dockerfile 450 FROM golang:1.11.0-alpine3.8 AS build 451 452 ARG PROTOTOOL_VERSION=1.3.0 453 ARG PROTOC_VERSION=3.6.1 454 ARG PROTOC_GEN_GO_VERSION=1.2.0 455 456 RUN \ 457 apk update && \ 458 apk add curl git libc6-compat && \ 459 rm -rf /var/cache/apk/* 460 RUN \ 461 curl -sSL https://github.com/uber/prototool/releases/download/v$PROTOTOOL_VERSION/prototool-Linux-x86_64 -o /bin/prototool && \ 462 chmod +x /bin/prototool 463 RUN \ 464 mkdir /tmp/prototool-bootstrap && \ 465 echo $'protoc:\n version:' $PROTOC_VERSION > /tmp/prototool-bootstrap/prototool.yaml && \ 466 echo 'syntax = "proto3";' > /tmp/prototool-bootstrap/tmp.proto && \ 467 prototool compile /tmp/prototool-bootstrap && \ 468 rm -rf /tmp/prototool-bootstrap 469 RUN go get github.com/golang/protobuf/... && \ 470 cd /go/src/github.com/golang/protobuf && \ 471 git checkout v$PROTOC_GEN_GO_VERSION && \ 472 go install ./protoc-gen-go 473 474 FROM alpine:3.8 475 476 WORKDIR /in 477 478 RUN \ 479 apk update && \ 480 apk add libc6-compat && \ 481 rm -rf /var/cache/apk/* 482 483 COPY --from=build /bin/prototool /bin/prototool 484 COPY --from=build /root/.cache/prototool /root/.cache/prototool 485 COPY --from=build /go/bin/protoc-gen-go /bin/protoc-gen-go 486 487 ENTRYPOINT ["/bin/prototool"] 488 ``` 489 490 Assuming this is in a file named `Dockerfile` in your current directory, build the image with: 491 492 ```bash 493 docker build -t me/prototool-env . 494 ``` 495 496 Then, assuming you are in the directory you want to pass to Prototool and you want to run `prototool compile`, run: 497 498 ```bash 499 docker run -v $(pwd):/in me/prototool-env compile 500 ``` 501 502 ##### Lint/Format Choices 503 504 *Question:* I don't like some of the choices made in the Style Guide and that are enforced by default by the linter and/or I don't like 505 the choices made in the formatter. Can we change some things? 506 507 *Answer:* Sorry, but we can't - The goal of Prototool is to provide a straightforward Style Guide and consistent formatting that minimizes various issues that arise from Protobuf usage across large organizations. There are pros and cons to many of the choices in the Style Guide, but it's our belief that the best answer is a **single** answer, sometimes regardless of what that single answer is. 508 509 It is possible to ignore lint rules via configuration. However, especially if starting from a clean slate, we highly recommend using all default lint rules for consistency. 510 511 Many of the lint rules exist to mitigate backwards compatibility problems as schemas evolves. For example: requiring a unique request-response pair per RPC - while this potentially resuls in duplicated messages, this makes it impossible to affect an adjacent RPC by adding or modifying an existing field. 512 513 ## Special Thanks 514 515 Prototool uses some external libraries that deserve special mention and thanks for their contribution to Prototool's functionality: 516 517 - [github.com/emicklei/proto](https://github.com/emicklei/proto) - The Golang Protobuf parsing library that started it all, and is still used for the linting and formatting functionality. We can't thank Ernest Micklei enough for his help and putting up with all the [filed issues](https://github.com/emicklei/proto/issues?q=is%3Aissue+is%3Aclosed). 518 - [github.com/jhump/protoreflect](https://github.com/jhump/protoreflect) - Used for the JSON to binary and back conversion. Josh Humphries is an amazing developer, thank you so much. 519 - [github.com/fullstorydev/grpcurl](https://github.com/fullstorydev/grpcurl) - Still used for the gRPC functionality. Again a thank you to Josh Humphries and the team over at FullStory for their work. 520 521 [mit-img]: http://img.shields.io/badge/License-MIT-blue.svg 522 [mit]: https://github.com/uber/prototool/blob/master/LICENSE 523 524 [release-img]: https://img.shields.io/github/release/uber/prototool/all.svg 525 [release]: https://github.com/uber/prototool/releases 526 527 [ci-img]: https://img.shields.io/travis/uber/prototool/dev.svg 528 [ci]: https://travis-ci.org/uber/prototool/builds 529 530 [cov-img]: https://codecov.io/gh/uber/prototool/branch/dev/graph/badge.svg 531 [cov]: https://codecov.io/gh/uber/prototool/branch/dev