Name Date Size #Lines LOC

..--

templates/H25-Apr-2025-6252

README.mdH A D25-Apr-202515.6 KiB373301

img.pngHD25-Apr-202598.9 KiB

new-client.pyH A D25-Apr-202511.2 KiB386331

requirements.inH A D25-Apr-202542 87

requirements.txtH A D25-Apr-202513.2 KiB186185

templates.pyH A D25-Apr-20251.2 KiB3516

README.md

1# New Google Client Library Generation
2
3The script allows you to create a new client library module in the
4google-cloud-java monorepo.
5
6**This tool is for repository maintainers only. Not for library users.**
7
8## Prerequisites
9
10This section is only needed for the first run of this script. If it's already
11done, go to "Run client generation script" section.
12
13
14### Environment
15
16Use Linux environment.
17
18Install Docker.
19
20### Ensure no Release Please "snapshot" pull request open
21
22Ensure google-cloud-java repository does not have [a pull request with "autorelease: snapshot" label](
23https://github.com/googleapis/google-cloud-java/pulls?q=is%3Apr+is%3Aopen+label%3A%22autorelease%3A+snapshot%22).
24
25If you find one, merge it after approving it.
26This is a pull request to append "-SNAPSHOT" to versions in pom.xml files in the
27repostiory. It's not for an actual release.
28
29Background: This new client library generation process creates pom.xml files with
30a "-SNAPSHOT" version. To have consistency with other modules, ensure the pom.xml files in
31the repository has "-SNAPSHOT" versions too.
32
33
34### Checkout google-cloud-java repository
35
36```
37$ git clone https://github.com/googleapis/google-cloud-java
38$ git checkout main
39$ git pull
40```
41
42### Install pyenv
43
44Install pyenv
45
46```
47curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer \
48| bash
49```
50
51Append the following lines to `$HOME/.bashrc`.
52
53```
54export PYENV_ROOT="$HOME/.pyenv"
55command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
56eval "$(pyenv init -)"
57eval "$(pyenv virtualenv-init -)"
58```
59
60Logout the shell and login again. You should be at the home directory.
61
62Assuming you have the following folder structure:
63```
64~ (Home)
65    -> IdeaProjects/
66        -> google-cloud-java
67    -> ...
68```
69You can run these next commands in the home directory (or IdeaProjects). Otherwise, run it at `google-cloud-java`'s parent directory.
70
71Confirm pyenv installation succeeded:
72
73```
74~$ pyenv
75pyenv 2.3.4
76Usage: pyenv <command> [<args>]
77
78Some useful pyenv commands are:
79   activate    Activate virtual environment
80   commands    List all available pyenv commands
81   deactivate   Deactivate virtual environment
82...
83```
84
85### Install Python 3.9 via pyenv
86
87```
88~$ pyenv install 3.9.13
89Downloading Python-3.9.13.tar.xz...
90-> https://www.python.org/ftp/python/3.9.13/Python-3.9.13.tar.xz
91Installing Python-3.9.13...
92WARNING: The Python sqlite3 extension was not compiled. Missing the SQLite3 lib?
93Installed Python-3.9.13 to /usr/local/google/home/suztomo/.pyenv/versions/3.9.13
94```
95
96### Install Python v3.9.13 locally
97
98Run this command
99
100```
101$ pyenv local 3.9.13
102```
103
104Confirm `python3.9` is installed:
105```
106$ which python3.9
107/usr/local/google/home/suztomo/.pyenv/shims/python3.9
108```
109
110### Install Python packages
111
112At the root of google-cloud-java repository clone, run:
113
114```
115$ python3.9 -m pip install -r generation/new_client/requirements.txt
116```
117
118### Install GitHub CLI (Optional)
119
120Install the GitHub CLI and login, if needed (may help with `Common Errors` below):
121
122```
123$ sudo apt-get install gh
124$ gh auth login
125```
126
127## Run client generation script
128
129You will run new-client.py script with the following parameters.
130Collect them from the ticket before running the command.
131
132### API short name
133
134For convenience of the subsequent commands, define a variable for API short name.
135Get the value from the DevRel Services page (Example: `apikeys`):
136
137### Proto path
138
139The script takes "proto path" parameter. This is path from google3's root to the
140directory that contains versions (e.g., "v1" or "v2"). For example, if we
141have
142
143> Link to protos: http://google3/google/api/apikeys/v2/apikeys.proto
144
145then the "proto path" value we supply to the command is "google/api/apikeys".
146
147### Name pretty
148
149Pick name from the display name in the DevRel Services site.
150For example, "API Keys API" in
151https://devrel.corp.google.com/admin/products/479.
152
153### Product Docs
154
155Find product document URL in the DevRel Services site.
156For example, "https://cloud.google.com/api-keys/" in
157https://devrel.corp.google.com/admin/products/479.
158The value must starts with "https://".
159
160### API description
161
162Find the short description of the API. Usually the first sentence in the product
163document above.
164
165### Example arguments
166
167Run `new-client.py` with the arguments above:
168
169```
170$ python3.9 generation/new_client/new-client.py generate \
171  --api_shortname=apikeys \
172  --proto-path=google/api/apikeys \
173  --name-pretty="API Keys API" \
174  --product-docs="https://cloud.google.com/api-keys/" \
175  --api-description="API Keys lets you create and manage your API keys for your projects."
176```
177
178The command creates changes for
179the new module in the monorepo. At the end (~ 10 minutes), it tells you to
180create a pull request in the monorepo:
181
182```
183...
184Please create a pull request:
185  $ git checkout -b new_module_java-discoveryengine
186  $ git add .
187  $ git commit -m 'feat: [apikeys] new module for apikeys'
188  $ gh pr create --title 'feat: [apikeys] new module for apikeys'
189```
190
191Create a pull request from the change.
192In the description, record the `python3.9 generation/new_client/new-client.py generate ...`
193command you ran above.
194
195## Advanced Options
196
197For the explanation of the available parameters, run:
198`python3.9 generation/new_client/new-client.py generate  --help`.
199
200```
201~/google-cloud-java$ python3.9 generation/new_client/new-client.py generate  --help
202/usr/local/google/home/suztomo/google-cloud-java/generation/new_client
203Usage: new-client.py generate [OPTIONS]
204
205Options:
206  --api_shortname TEXT            Name for the new directory name and
207                                  (default) artifact name  [required]
208  --name-pretty TEXT              The human-friendly name that appears in
209                                  README.md  [required]
210  --product-docs TEXT             Documentation URL that appears in README.md
211                                  [required]
212  --api-description TEXT          Description that appears in README.md
213                                  [required]
214  --release-level [stable|preview]
215                                  A label that appears in repo-metadata.json.
216                                  The first library generation is always
217                                  'preview'.  [default: preview]
218  --transport [grpc|http|both]    A label that appears in repo-metadata.json
219                                  [default: grpc]
220  --language TEXT                 [default: java]
221  --distribution-name TEXT        Maven coordinates of the generated library.
222                                  By default it's com.google.cloud:google-
223                                  cloud-<api_shortname>
224  --api-id TEXT                   The value of the apiid parameter used in
225                                  README.md It has link to https://console.clo
226                                  ud.google.com/flows/enableapi?apiid=<api_id>
227  --requires-billing BOOLEAN      Based on this value, README.md explains
228                                  whether billing setup is needed or not.
229                                  [default: True]
230  --destination-name TEXT         The directory name of the new library. By
231                                  default it's java-<api_shortname>
232  --proto-path TEXT               Path to proto file from the root of the
233                                  googleapis repository to thedirectory that
234                                  contains the proto files (without the
235                                  version).For example, to generate the
236                                  library for 'google/maps/routing/v2', then
237                                  you specify this value as
238                                  'google/maps/routing'  [required]
239  --cloud-api BOOLEAN             If true, the artifact ID of the library is
240                                  'google-cloud-'; otherwise 'google-'
241                                  [default: True]
242  --group-id TEXT                 The group ID of the artifact when
243                                  distribution name is not set  [default:
244                                  com.google.cloud]
245  --owlbot-image TEXT             The owlbot container image used in
246                                  OwlBot.yaml  [default: gcr.io/cloud-devrel-
247                                  public-resources/owlbot-java]
248  --library-type TEXT             A label that appear in repo-metadata.json to
249                                  tell how the library is maintained or
250                                  generated  [default: GAPIC_AUTO]
251  --googleapis-gen-url TEXT       The URL of the repository that has generated
252                                  Java code from proto service definition
253                                  [default:
254                                  https://github.com/googleapis/googleapis-
255                                  gen.git]
256  --help                          Show this message and exit.
257```
258
259Sometimes, a library generation requires special handling for
260Maven coordinates or API ID, especially when the library is not
261specific to Google Cloud. Refer to the following command example when we
262generated Google Maps Routes API Java client library.
263
264```
265~/google-cloud-java$ python3.9 generation/new_client/new-client.py generate \
266  --api_shortname=maps-routing \
267  --proto-path=google/maps/routing \
268  --name-pretty="Routes API" \
269  --product-docs="https://developers.google.com/maps/documentation/routes" \
270  --api-description="Routes API is the next generation, performance optimized version of the existing Directions API and Distance Matrix API. It helps you find the ideal route from A to Z, calculates ETAs and distances for matrices of origin and destination locations, and also offers new features." \
271  --api-id=routes.googleapis.com \
272  --cloud-api=false \
273  --requires-billing=true \
274  --distribution-name="com.google.maps:google-maps-routing"
275```
276
277# Principles
278
279The script should finish creating a pull request even when the newly created
280module fails to compile. This gives the user flexibility to fix things in the
281created pull request.
282
283# Common Errors
284
285## Unable to clone googleapis-gen
286```
287Creating a new module /usr/local/google/home/lawrenceqiu/IdeaProjects/google-cloud-java/java-vmwareengine
288gcr.io/cloud-devrel-public-resources/owlbot-java:latest
289Cloning googleapis-gen...
290Username for 'https://github.com': xxxxxx
291Password for 'https://[email protected]': ******
292remote: Support for password authentication was removed on August 13, 2021.
293remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
294fatal: Authentication failed for 'https://github.com/googleapis/googleapis-gen.git/'
295Traceback (most recent call last):
296  File "/usr/local/google/home/lawrenceqiu/IdeaProjects/google-cloud-java/generation/new_client/new-client.py", line 291, in <module>
297    main()
298  File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1130, in __call__
299    return self.main(*args, **kwargs)
300  File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1055, in main
301    rv = self.invoke(ctx)
302  File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1657, in invoke
303    return _process_result(sub_ctx.command.invoke(sub_ctx))
304  File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
305    return ctx.invoke(self.callback, **ctx.params)
306  File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 760, in invoke
307    return __callback(*args, **kwargs)
308  File "/usr/local/google/home/lawrenceqiu/IdeaProjects/google-cloud-java/generation/new_client/new-client.py", line 180, in generate
309    subprocess.check_call(["git", "clone", "-q", googleapis_gen_url, "./gen/googleapis-gen"], cwd=workdir)
310  File "/usr/local/google/home/lawrenceqiu/.pyenv/versions/3.9.13/lib/python3.9/subprocess.py", line 373, in check_call
311    raise CalledProcessError(retcode, cmd)
312subprocess.CalledProcessError: Command '['git', 'clone', '-q', 'https://github.com/googleapis/googleapis-gen.git', './gen/googleapis-gen']' returned non-zero exit status 128.
313```
314### Solution
315Run `gh auth login` and choose to authenticate with HTTPS. You may already be authenticated with SSH.
316![img.png](img.png)
317
318## Owl-bot Staging Directory Not Found
319```
320Removing googleapis-gen...
321mv: cannot stat 'owl-bot-staging': No such file or directory
322Traceback (most recent call last):
323  File "/usr/local/google/home/lawrenceqiu/IdeaProjects/google-cloud-java/generation/new_client/new-client.py", line 291, in <module>
324    main()
325  File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1130, in __call__
326    return self.main(*args, **kwargs)
327  File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1055, in main
328    rv = self.invoke(ctx)
329  File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1657, in invoke
330    return _process_result(sub_ctx.command.invoke(sub_ctx))
331  File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
332    return ctx.invoke(self.callback, **ctx.params)
333  File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 760, in invoke
334    return __callback(*args, **kwargs)
335  File "/usr/local/google/home/lawrenceqiu/IdeaProjects/google-cloud-java/generation/new_client/new-client.py", line 212, in generate
336    subprocess.check_call(
337  File "/usr/local/google/home/lawrenceqiu/.pyenv/versions/3.9.13/lib/python3.9/subprocess.py", line 373, in check_call
338    raise CalledProcessError(retcode, cmd)
339subprocess.CalledProcessError: Command '['mv', 'owl-bot-staging', '../']' returned non-zero exit status 1.
340```
341
342### Solution
343The proto path is incorrect. See the `Proto Path` section to find the correct path.
344
345## Python3.9 is not Installed
346```
347pyenv: version `3.9.13' is not installed (set by /workspace/.python-version)
348Traceback (most recent call last):
349File "/usr/local/google/home/lawrenceqiu/IdeaProjects/google-cloud-java/generation/new_client/new-client.py", line 291, in <module>
350main()
351File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1130, in __call__
352return self.main(*args, **kwargs)
353File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1055, in main
354rv = self.invoke(ctx)
355File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1657, in invoke
356return _process_result(sub_ctx.command.invoke(sub_ctx))
357File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
358return ctx.invoke(self.callback, **ctx.params)
359File "/usr/local/google/home/lawrenceqiu/.local/lib/python3.9/site-packages/click/core.py", line 760, in invoke
360return __callback(*args, **kwargs)
361File "/usr/local/google/home/lawrenceqiu/IdeaProjects/google-cloud-java/generation/new_client/new-client.py", line 223, in generate
362subprocess.check_call(
363File "/usr/local/google/home/lawrenceqiu/.pyenv/versions/3.9.13/lib/python3.9/subprocess.py", line 373, in check_call
364raise CalledProcessError(retcode, cmd)
365subprocess.CalledProcessError: Command '['docker', 'run', '--rm', '-v', '/usr/local/google/home/lawrenceqiu/IdeaProjects/google-cloud-java:/workspace', '--user', '1023638:89939', 'gcr.io/cloud-devrel-public-resources/owlbot-java']' returned non-zero exit status 1.
366```
367
368### Solution
369You have run the `pyenv local 3.9.13` in the `google-cloud-java` repo.
3701. Remove the `.python-version` file in `google-cloud-java`.
3712. `cd ..` out to the parent directory and run `pyenv local 3.9.13` there
3723. `cd google-cloud-java` back into the repo and run the generation script again
373