1*55e87721SMatt Gilbride# SynthTool (for client libraries) 2*55e87721SMatt Gilbride 3*55e87721SMatt Gilbride 4*55e87721SMatt Gilbride 5*55e87721SMatt GilbrideThis tool helps to generate and layout cloud client libraries. Synthtool runs the [GAPIC (Generated API Client) Generator][GAPIC] via [Google API Artifact Manager (artman)][artman]. 6*55e87721SMatt Gilbride 7*55e87721SMatt Gilbride[GAPIC]: https://github.com/googleapis/gapic-generator 8*55e87721SMatt Gilbride[artman]: https://github.com/googleapis/artman 9*55e87721SMatt Gilbride 10*55e87721SMatt Gilbride## Prerequisites 11*55e87721SMatt Gilbride 12*55e87721SMatt Gilbride1. **Linux** This tool runs on Linux only. No other platforms are supported. 13*55e87721SMatt Gilbride 14*55e87721SMatt Gilbride2. **Python 3.6** Either install it from [python.org][python_downloads] or use 15*55e87721SMatt Gilbride[pyenv][] to get 3.6. 16*55e87721SMatt Gilbride 17*55e87721SMatt Gilbride3. **Bazel** can be downloaded from [bazel.build](https://bazel.build/). 18*55e87721SMatt Gilbride 19*55e87721SMatt Gilbride4. **Docker** Some synth.py files require [Docker] to generate code. 20*55e87721SMatt Gilbride 21*55e87721SMatt Gilbride5. Clone this repository and install this library with pip: 22*55e87721SMatt Gilbride 23*55e87721SMatt Gilbride ``` 24*55e87721SMatt Gilbride cd synthtool 25*55e87721SMatt Gilbride python3 -m pip install -e . 26*55e87721SMatt Gilbride ``` 27*55e87721SMatt Gilbride 28*55e87721SMatt Gilbride 29*55e87721SMatt Gilbride[python_downloads]: https://www.python.org/downloads/ 30*55e87721SMatt Gilbride[pyenv]: https://github.com/pyenv/pyenv 31*55e87721SMatt Gilbride[Docker]: https://docs.docker.com/v17.09/engine/installation/#desktop 32*55e87721SMatt Gilbride 33*55e87721SMatt Gilbride 34*55e87721SMatt Gilbride## Basic usage 35*55e87721SMatt GilbrideTo start the process of generation, clone the destination repository. 36*55e87721SMatt Gilbride``` 37*55e87721SMatt Gilbridegit clone [email protected]:googleapis/python-tasks.git 38*55e87721SMatt Gilbridecd python-tasks/ 39*55e87721SMatt Gilbride``` 40*55e87721SMatt Gilbride 41*55e87721SMatt Gilbride### Running `synthtool` 42*55e87721SMatt GilbrideIf a `synth.py` script is not present, create a new one. 43*55e87721SMatt Gilbride 44*55e87721SMatt GilbrideYou can create one from scratch or copy one from another library. 45*55e87721SMatt Gilbride - e.g. the `synth.py` for the Cloud Tasks API for [Python][python_tasks_synth_py], 46*55e87721SMatt Gilbride[Java][java_tasks_synth_py], [Node.js][node_tasks_synth_py], [PHP][php_tasks_synth_py], 47*55e87721SMatt Gilbrideor [Ruby][ruby_tasks_synth_py]. 48*55e87721SMatt Gilbride 49*55e87721SMatt GilbrideRun `synthtool`: 50*55e87721SMatt Gilbride 51*55e87721SMatt Gilbride``` 52*55e87721SMatt Gilbridepython3 -m synthtool 53*55e87721SMatt Gilbride``` 54*55e87721SMatt Gilbride 55*55e87721SMatt GilbrideAfter `synthtool` runs successfully: 56*55e87721SMatt Gilbride - Investigate the changes it made 57*55e87721SMatt Gilbride - Run the library tests 58*55e87721SMatt Gilbride - Commit and push the changes to a branch and open a Pull Request 59*55e87721SMatt Gilbride 60*55e87721SMatt GilbrideFind examples below in different programming languages (Cloud Tasks API used as an example). 61*55e87721SMatt Gilbride 62*55e87721SMatt Gilbride### Python 63*55e87721SMatt Gilbride- Clone the destination repository: 64*55e87721SMatt Gilbride ``` 65*55e87721SMatt Gilbride git clone [email protected]:googleapis/python-tasks.git 66*55e87721SMatt Gilbride cd python-tasks/ 67*55e87721SMatt Gilbride ``` 68*55e87721SMatt Gilbride- Run `synthtool` to generate using the existing [`synth.py`][python_tasks_synth_py] 69*55e87721SMatt Gilbride file for the [Python Client for Cloud Tasks API][python_tasks_library]: 70*55e87721SMatt Gilbride ``` 71*55e87721SMatt Gilbride python3 -m synthtool 72*55e87721SMatt Gilbride ``` 73*55e87721SMatt Gilbride- See the Python [Contributing Guide][python_contributing] 74*55e87721SMatt Gilbride or instructions to install dependencies, run tests, and submit a contribution. 75*55e87721SMatt Gilbride 76*55e87721SMatt Gilbride[python_tasks_library]: https://github.com/googleapis/python-tasks 77*55e87721SMatt Gilbride[python_tasks_synth_py]: https://github.com/googleapis/python-tasks/blob/master/synth.py 78*55e87721SMatt Gilbride[python_contributing]: https://github.com/googleapis/python-tasks/blob/master/CONTRIBUTING.rst 79*55e87721SMatt Gilbride 80*55e87721SMatt Gilbride### Java 81*55e87721SMatt Gilbride- Clone the destination repository: 82*55e87721SMatt Gilbride ``` 83*55e87721SMatt Gilbride git clone [email protected]:googleapis/java-tasks.git 84*55e87721SMatt Gilbride cd java-tasks/ 85*55e87721SMatt Gilbride ``` 86*55e87721SMatt Gilbride- Run `synthtool` to generate using the existing [`synth.py`][java_tasks_synth_py] 87*55e87721SMatt Gilbride file for the [Google Cloud Java Client for Cloud Tasks][java_tasks_library]: 88*55e87721SMatt Gilbride ``` 89*55e87721SMatt Gilbride python3 -m synthtool 90*55e87721SMatt Gilbride ``` 91*55e87721SMatt Gilbride- See the Java [Contributing Guide][java_contributing] 92*55e87721SMatt Gilbride or instructions to install dependencies, run tests, and submit a contribution. 93*55e87721SMatt Gilbride 94*55e87721SMatt Gilbride[java_tasks_library]: https://github.com/googleapis/java-tasks 95*55e87721SMatt Gilbride[java_tasks_synth_py]: https://github.com/googleapis/java-tasks/blob/master/synth.py 96*55e87721SMatt Gilbride[java_contributing]: https://github.com/googleapis/java-tasks/blob/master/CONTRIBUTING.md 97*55e87721SMatt Gilbride 98*55e87721SMatt Gilbride### Node.js 99*55e87721SMatt Gilbride- Clone the destination repository: 100*55e87721SMatt Gilbride ``` 101*55e87721SMatt Gilbride git clone [email protected]:googleapis/nodejs-tasks.git 102*55e87721SMatt Gilbride cd nodejs-tasks/ 103*55e87721SMatt Gilbride ``` 104*55e87721SMatt Gilbride- Run `synthtool` to generate using the existing [`synth.py`][node_tasks_synth_py] 105*55e87721SMatt Gilbride file for the [Google Cloud Tasks Node.js Client][node_tasks_library]: 106*55e87721SMatt Gilbride ``` 107*55e87721SMatt Gilbride python3 -m synthtool 108*55e87721SMatt Gilbride ``` 109*55e87721SMatt Gilbride- See the Node.js [Contributing Guide][node_tasks_contributing] 110*55e87721SMatt Gilbride or instructions to install dependencies, run tests, and submit a contribution. 111*55e87721SMatt Gilbride 112*55e87721SMatt Gilbride[node_tasks_library]: https://github.com/googleapis/nodejs-tasks 113*55e87721SMatt Gilbride[node_tasks_synth_py]: https://github.com/googleapis/nodejs-tasks/blob/master/synth.py 114*55e87721SMatt Gilbride[node_tasks_contributing]: https://github.com/googleapis/nodejs-tasks/blob/master/CONTRIBUTING.md 115*55e87721SMatt Gilbride 116*55e87721SMatt Gilbride### PHP 117*55e87721SMatt Gilbride- Clone the destination repository: 118*55e87721SMatt Gilbride ``` 119*55e87721SMatt Gilbride git clone [email protected]:googleapis/google-cloud-php.git 120*55e87721SMatt Gilbride cd google-cloud-php/ 121*55e87721SMatt Gilbride ``` 122*55e87721SMatt Gilbride- Navigate to the destination directory: 123*55e87721SMatt Gilbride ``` 124*55e87721SMatt Gilbride cd Tasks/ 125*55e87721SMatt Gilbride ``` 126*55e87721SMatt Gilbride- Run `synthtool` to generate using the existing [`synth.py`][php_tasks_synth_py] 127*55e87721SMatt Gilbride file for the [Google Cloud Tasks client for PHP][php_tasks_library]: 128*55e87721SMatt Gilbride ``` 129*55e87721SMatt Gilbride python3 -m synthtool 130*55e87721SMatt Gilbride ``` 131*55e87721SMatt Gilbride- See the PHP [Contributing Guide][php_contributing] 132*55e87721SMatt Gilbride or instructions to install dependencies, run tests, and submit a contribution. 133*55e87721SMatt Gilbride 134*55e87721SMatt Gilbride[php_tasks_library]: https://github.com/googleapis/google-cloud-php/tree/master/Tasks 135*55e87721SMatt Gilbride[php_tasks_synth_py]: https://github.com/googleapis/google-cloud-php/blob/master/Tasks/synth.py 136*55e87721SMatt Gilbride[php_contributing]: https://github.com/googleapis/google-cloud-php/blob/master/CONTRIBUTING.md 137*55e87721SMatt Gilbride 138*55e87721SMatt Gilbride### Ruby 139*55e87721SMatt Gilbride- Clone the destination repository: 140*55e87721SMatt Gilbride ``` 141*55e87721SMatt Gilbride git clone [email protected]:googleapis/google-cloud-ruby.git 142*55e87721SMatt Gilbride cd google-cloud-ruby/ 143*55e87721SMatt Gilbride ``` 144*55e87721SMatt Gilbride- Navigate to the destination directory: 145*55e87721SMatt Gilbride ``` 146*55e87721SMatt Gilbride cd google-cloud-tasks/ 147*55e87721SMatt Gilbride ``` 148*55e87721SMatt Gilbride- Run `synthtool` to generate using the existing [`synth.py`][ruby_tasks_synth_py] 149*55e87721SMatt Gilbride file for the [Ruby Client for Cloud Tasks API][ruby_tasks_library]: 150*55e87721SMatt Gilbride ``` 151*55e87721SMatt Gilbride python3 -m synthtool 152*55e87721SMatt Gilbride ``` 153*55e87721SMatt Gilbride- See the Ruby [Contributing Guide][ruby_contributing] 154*55e87721SMatt Gilbride or instructions to install dependencies, run tests, and submit a contribution. 155*55e87721SMatt Gilbride 156*55e87721SMatt Gilbride[ruby_tasks_library]: https://github.com/googleapis/google-cloud-ruby/tree/master/google-cloud-tasks 157*55e87721SMatt Gilbride[ruby_tasks_synth_py]: https://github.com/googleapis/google-cloud-ruby/blob/master/google-cloud-tasks/synth.py 158*55e87721SMatt Gilbride[ruby_contributing]: https://github.com/googleapis/google-cloud-ruby/blob/master/.github/CONTRIBUTING.md 159*55e87721SMatt Gilbride 160*55e87721SMatt Gilbride## Features 161*55e87721SMatt Gilbride 162*55e87721SMatt Gilbride### Common transforms 163*55e87721SMatt Gilbride 164*55e87721SMatt GilbrideFunctions in synthtool make it easier to copy files, merge files, etc. 165*55e87721SMatt GilbrideSee the [pydocs](https://htmlpreview.github.io/?https://github.com/googleapis/synthtool/blob/master/synthtool/pydoc.html) for more details. 166*55e87721SMatt Gilbride 167*55e87721SMatt Gilbride### Templating 168*55e87721SMatt GilbrideSynthTool supports template files using [Jinja](http://jinja.pocoo.org/). 169*55e87721SMatt Gilbride 170*55e87721SMatt GilbrideTemplates are found in subdirectories of [`synthtool/gcp/templates/`](gcp/templates/) 171*55e87721SMatt Gilbridefor each language, 172*55e87721SMatt Gilbride - e.g. the template directories for [Python][python_templates], 173*55e87721SMatt Gilbride[Node.js][node_templates], [PHP][php_templates], or [Ruby][ruby_templates]. 174*55e87721SMatt Gilbride 175*55e87721SMatt Gilbride[python_templates]: gcp/templates/python_library/ 176*55e87721SMatt Gilbride[node_templates]: gcp/templates/node_library/ 177*55e87721SMatt Gilbride[php_templates]: gcp/templates/php_library/ 178*55e87721SMatt Gilbride[ruby_templates]: gcp/templates/ruby_library/ 179*55e87721SMatt Gilbride 180*55e87721SMatt GilbrideYou can generate and copy templates using `gcp.CommonTemplates` in your `synth.py`: 181*55e87721SMatt Gilbride```py 182*55e87721SMatt Gilbridecommon_templates = gcp.CommonTemplates() 183*55e87721SMatt Gilbride 184*55e87721SMatt Gilbridetemplates = common_templates.node_library() 185*55e87721SMatt Gilbrides.copy(templates) 186*55e87721SMatt Gilbride``` 187*55e87721SMatt Gilbride 188*55e87721SMatt GilbrideYou can provide variables to templates as keyword arguments to the library generation method: 189*55e87721SMatt Gilbride 190*55e87721SMatt Gilbride```py 191*55e87721SMatt Gilbridecommon_templates = gcp.CommonTemplates() 192*55e87721SMatt Gilbride 193*55e87721SMatt Gilbridetemplates = common_templates.node_library(version=5, show_version=True, previous_versions=[1,2,3,4]) 194*55e87721SMatt Gilbride 195*55e87721SMatt Gilbrides.copy(templates) 196*55e87721SMatt Gilbride``` 197*55e87721SMatt Gilbride 198*55e87721SMatt GilbrideTemplate files can access any values provided, e.g. 199*55e87721SMatt Gilbride - `README.md.j2` 200*55e87721SMatt Gilbride ```py 201*55e87721SMatt Gilbride {% if show_version %} 202*55e87721SMatt Gilbride The version is {{ version }} 203*55e87721SMatt Gilbride 204*55e87721SMatt Gilbride {% if previous versions is defined %} 205*55e87721SMatt Gilbride Previous versions: 206*55e87721SMatt Gilbride {% for ver in previous_versions %} 207*55e87721SMatt Gilbride - {{ ver }} 208*55e87721SMatt Gilbride {% endfor %} 209*55e87721SMatt Gilbride {% endif %} 210*55e87721SMatt Gilbride {% endif %} 211*55e87721SMatt Gilbride ``` 212*55e87721SMatt Gilbride 213*55e87721SMatt GilbrideFor more information on how to use Synthtool templating for Python Samples, view [/py_templating_instructions](./py_templating_instructions) 214*55e87721SMatt Gilbride 215*55e87721SMatt GilbrideYou can learn more about Jinga templating in the 216*55e87721SMatt Gilbride[Template Designer Documentation](http://jinja.pocoo.org/docs/templates/). 217*55e87721SMatt Gilbride 218*55e87721SMatt Gilbride### googleapis-private 219*55e87721SMatt GilbrideSynthTool supports generation from googleapis/googleapis-private. 220*55e87721SMatt Gilbride 221*55e87721SMatt Gilbride```py 222*55e87721SMatt Gilbridegapic = gcp.GAPICGenerator() 223*55e87721SMatt Gilbride 224*55e87721SMatt Gilbridelibrary = gapic.node_library('speech', 'v1', private=True) 225*55e87721SMatt Gilbride``` 226*55e87721SMatt Gilbride2FA is required to clone a private repo. 227*55e87721SMatt Gilbride 228*55e87721SMatt Gilbride* **Using SSH:** Before running Synthtool, set the environment variable `AUTOSYNTH_USE_SSH` to `true`. 229*55e87721SMatt Gilbride 230*55e87721SMatt GilbrideThe repo is cloned using SSH. 231*55e87721SMatt Gilbride* **Using HTTPS:** Generate a [GitHub Personal Access Token](https://github.com/settings/tokens) with scope `repo`. 232*55e87721SMatt GilbrideRun `synthtool`. 233*55e87721SMatt Gilbride 234*55e87721SMatt GilbrideWhen GitHub prompts for your GitHub password, provide the access token instead. 235*55e87721SMatt Gilbride 236*55e87721SMatt Gilbride``` 237*55e87721SMatt Gilbridesynthtool > Cloning googleapis-private. 238*55e87721SMatt GilbrideUsername for 'https://github.com': busunkim96 239*55e87721SMatt GilbridePassword for 'https://[email protected]': 240*55e87721SMatt Gilbride``` 241*55e87721SMatt Gilbride 242*55e87721SMatt Gilbride### Artman Version 243*55e87721SMatt GilbrideSynthTool uses the latest version of the [Artman Docker image](https://hub.docker.com/r/googleapis/artman). 244*55e87721SMatt GilbrideYou can change this by setting the environment variable `SYNTHTOOL_ARTMAN_VERSION` to the desired version tag. 245*55e87721SMatt Gilbride 246*55e87721SMatt Gilbride``` 247*55e87721SMatt Gilbrideexport SYNTHTOOL_ARTMAN_VERSION=0.16.2 248*55e87721SMatt Gilbride``` 249*55e87721SMatt Gilbride 250*55e87721SMatt Gilbride### GAPIC Generator Python Version 251*55e87721SMatt GilbrideSynthTool uses the latest version of [gcr.io/gapic-images/gapic-generator-python](https://gcr.io/gapic-images/gapic-generator-python). You can change this by 252*55e87721SMatt Gilbridesetting the environment variable `SYNTHTOOL_GAPIC_GENERATOR_PYTHON_VERSION` to the desired version tag. 253*55e87721SMatt Gilbride 254*55e87721SMatt Gilbride``` 255*55e87721SMatt Gilbrideexport SYNTHTOOL_GAPIC_GENERATOR_PYTHON_VERSION=0.22.0 256*55e87721SMatt Gilbride``` 257*55e87721SMatt Gilbride 258*55e87721SMatt GilbrideAlternatively you can set the generator version by passing it to `gapic.py_library`. 259*55e87721SMatt Gilbride 260*55e87721SMatt Gilbride```python 261*55e87721SMatt Gilbrideimport synthtool as s 262*55e87721SMatt Gilbrideimport synthtool.gcp as gcp 263*55e87721SMatt Gilbride 264*55e87721SMatt Gilbridegapic = gcp.GAPICMicrogenerator() 265*55e87721SMatt Gilbride 266*55e87721SMatt Gilbridelibrary = gapic.py_library( 267*55e87721SMatt Gilbride "bigquery/connection", "v1beta1", generator_version="0.22.0" 268*55e87721SMatt Gilbride) 269*55e87721SMatt Gilbride``` 270*55e87721SMatt Gilbride 271*55e87721SMatt Gilbride### Local Googleapis 272*55e87721SMatt GilbrideSynthTool supports generation from a local copy of googleapis. 273*55e87721SMatt GilbrideSpecify the path to `googleapis` in the environment variable `SYNTHTOOL_GOOGLEAPIS`. 274*55e87721SMatt Gilbride 275*55e87721SMatt Gilbride``` 276*55e87721SMatt Gilbrideexport SYNTHTOOL_GOOGLEAPIS=path/to/local/googleapis 277*55e87721SMatt Gilbride``` 278*55e87721SMatt Gilbride 279*55e87721SMatt Gilbride### Local GAPIC Generator 280*55e87721SMatt GilbrideSynthTool supports generation from a local copy of [gapic-generator](https://github.com/googleapis/gapic-generator). 281*55e87721SMatt GilbrideSpecify the path to `gapic-generator` in the environment variable `SYNTHTOOL_GENERATOR`. 282*55e87721SMatt Gilbride 283*55e87721SMatt Gilbride``` 284*55e87721SMatt Gilbrideexport SYNTHTOOL_GENERATOR=path/to/local/gapic-generator 285*55e87721SMatt Gilbride``` 286*55e87721SMatt Gilbride 287*55e87721SMatt GilbrideDon't forget to compile `gapic-generator` before running SynthTool. 288*55e87721SMatt Gilbride 289*55e87721SMatt Gilbride``` 290*55e87721SMatt Gilbridecd path/to/local/gapic-generator 291*55e87721SMatt Gilbride./gradlew fatJar 292*55e87721SMatt Gilbride``` 293*55e87721SMatt Gilbride 294*55e87721SMatt Gilbride### Local Template Files 295*55e87721SMatt GilbrideSynthTool supports specifying a local directory of templates. Specify the path to the root 296*55e87721SMatt Gilbridetemplate directory (not a SynthTool clone) in the environment variable `SYNTHTOOL_TEMPLATES`. 297*55e87721SMatt Gilbride 298*55e87721SMatt Gilbride``` 299*55e87721SMatt Gilbrideexport SYNTHTOOL_TEMPLATES=path/to/local/templates 300*55e87721SMatt Gilbride``` 301*55e87721SMatt Gilbride 302*55e87721SMatt Gilbride### Include .proto files 303*55e87721SMatt GilbrideSynthTool supports copying .proto API definition files from googleapis. 304*55e87721SMatt Gilbride 305*55e87721SMatt Gilbride```py 306*55e87721SMatt Gilbridegapic = gcp.GAPICGenerator() 307*55e87721SMatt Gilbride 308*55e87721SMatt Gilbridelibrary = gapic.node_library('speech', 'v1', include_protos=True) 309*55e87721SMatt Gilbride``` 310*55e87721SMatt Gilbride 311*55e87721SMatt Gilbride## Context-Aware Commits 312*55e87721SMatt Gilbride 313*55e87721SMatt GilbrideAutosynth runs synthtool on your `synth.py` nightly or more frequently. 314*55e87721SMatt GilbrideBy default, it runs synthtool once, and if the generated code differs, 315*55e87721SMatt Gilbridecreates a PR with the differences. 316*55e87721SMatt Gilbride 317*55e87721SMatt GilbrideAutosynth can also find which changes in upstream repositories triggered changes 318*55e87721SMatt Gilbridein the generated code. To enable this behavior (context-aware commits), 319*55e87721SMatt Gilbrideset one or both of the following flags in you synth.py file: 320*55e87721SMatt Gilbride 321*55e87721SMatt Gilbride```py 322*55e87721SMatt GilbrideAUTOSYNTH_MULTIPLE_COMMITS 323*55e87721SMatt GilbrideAUTOSYNTH_MULTIPLE_PRS 324*55e87721SMatt Gilbride``` 325*55e87721SMatt Gilbride 326*55e87721SMatt Gilbride### Example 327*55e87721SMatt Gilbride 328*55e87721SMatt GilbrideAssume that since the library source code was last generated, A, B and X, Y 329*55e87721SMatt Gilbridewere committed to googleapis and synthtool respectively, and they all triggered 330*55e87721SMatt Gilbridechanges in the generated library code. 331*55e87721SMatt Gilbride 332*55e87721SMatt Gilbride| [googleapis](https://github.com/googleapis/googleapis) | [synthtool (templates)](gcp/templates) | 333*55e87721SMatt Gilbride| :--------: | :-------------------: | 334*55e87721SMatt Gilbride| A | X | 335*55e87721SMatt Gilbride| B | Y | 336*55e87721SMatt Gilbride 337*55e87721SMatt Gilbride 338*55e87721SMatt GilbrideHere's what autosynth generates for each flag setting. 339*55e87721SMatt Gilbride 340*55e87721SMatt Gilbride```py 341*55e87721SMatt GilbrideAUTOSYNTH_MULTIPLE_COMMITS = True 342*55e87721SMatt Gilbride``` 343*55e87721SMatt Gilbride 344*55e87721SMatt GilbrideAutosynth creates one PR, with a single commit for each original commit: 345*55e87721SMatt Gilbride| PR | 346*55e87721SMatt Gilbride| - | 347*55e87721SMatt Gilbride| A | 348*55e87721SMatt Gilbride| B | 349*55e87721SMatt Gilbride| X | 350*55e87721SMatt Gilbride| Y | 351*55e87721SMatt Gilbride 352*55e87721SMatt Gilbride*** 353*55e87721SMatt Gilbride 354*55e87721SMatt Gilbride```py 355*55e87721SMatt GilbrideAUTOSYNTH_MULTIPLE_COMMITS = True 356*55e87721SMatt GilbrideAUTOSYNTH_MULTIPLE_PRS = True 357*55e87721SMatt Gilbride``` 358*55e87721SMatt Gilbride 359*55e87721SMatt GilbrideAutosynth creates two PRs, with a single commit for each original commit: 360*55e87721SMatt Gilbride| PR1 | 361*55e87721SMatt Gilbride| - | 362*55e87721SMatt Gilbride| A | 363*55e87721SMatt Gilbride| B | 364*55e87721SMatt Gilbride 365*55e87721SMatt Gilbride| PR2 | 366*55e87721SMatt Gilbride| - | 367*55e87721SMatt Gilbride| X | 368*55e87721SMatt Gilbride| Y | 369*55e87721SMatt Gilbride 370*55e87721SMatt Gilbride 371*55e87721SMatt Gilbride*** 372*55e87721SMatt Gilbride 373*55e87721SMatt Gilbride```py 374*55e87721SMatt GilbrideAUTOSYNTH_MULTIPLE_PRS = True 375*55e87721SMatt Gilbride``` 376*55e87721SMatt Gilbride 377*55e87721SMatt GilbrideAutosynth creates two PRs, with a single commit combining all the 378*55e87721SMatt Gilbrideoriginal commits. 379*55e87721SMatt Gilbride 380*55e87721SMatt Gilbride| PR1 | 381*55e87721SMatt Gilbride| - | 382*55e87721SMatt Gilbride| AB | 383*55e87721SMatt Gilbride 384*55e87721SMatt Gilbride| PR2 | 385*55e87721SMatt Gilbride| - | 386*55e87721SMatt Gilbride| XY | 387*55e87721SMatt Gilbride 388*55e87721SMatt Gilbride 389*55e87721SMatt Gilbride## Helpful tips 390*55e87721SMatt Gilbride### Where does the generated code go? 391*55e87721SMatt GilbrideSynthTool runs [Artman](https://hub.docker.com/r/googleapis/artman) which creates generated code that 392*55e87721SMatt Gilbridecan be found at `~/.cache/synthtool/googleapis<-private>/artman_genfiles`. This is useful for figuring out 393*55e87721SMatt Gilbridewhat it is you need to copy for your specific library. 394*55e87721SMatt Gilbride 395*55e87721SMatt Gilbride### Warning: Don't lint manually-written code in synth.py! 396*55e87721SMatt Gilbride 397*55e87721SMatt GilbrideBen had the misfortune to discover a corner case where autosynth deleted a file that Ben never intended or expected it to delete. 398*55e87721SMatt Gilbride 399*55e87721SMatt GilbrideHere is what happened: 400*55e87721SMatt Gilbride 401*55e87721SMatt Gilbride1. Autosynth cannot directly observe which files your synth.py generates, because synth.py could literally do anything, including launch the space shuttle. So, Autosynth figures out which files were generated by examining all the file system reads and writes that happened while synth.py was executing. Any file that is written to or copied to is deemed to have been generated by synth.py and recorded as a generatedFiles in synth.metadata. 402*55e87721SMatt Gilbride 403*55e87721SMatt Gilbride2. NodeJS's synth.py ran the linter on manually-written sample files in the repo. A new version of the linter was pulled in, which modified a manually-written sample file. Autosynth observed the write and concluded that the manually-written file was a generated file, and listed it in generatedFiles in synth.metadata. The next time Autosynth ran, the linter made no changes, and the manually-written sample file was not written to. Autosynth concluded the manually-written sample file was no longer being generated, and deleted it. 404*55e87721SMatt Gilbride 405*55e87721SMatt Gilbride#### Lesson Learned: 406*55e87721SMatt GilbrideMake sure your synth.py does not touch any manually-written files in the repo. 407