Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add generate_repo.py #2431

Merged
merged 67 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 66 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
8c4bd4a
feat: add generate_repo.py
JoeWang1127 Jan 30, 2024
f4bccaa
refactor model
JoeWang1127 Jan 30, 2024
b2b3fe4
refactor
JoeWang1127 Jan 30, 2024
e804991
add private methods
JoeWang1127 Jan 30, 2024
737dbbd
change config file
JoeWang1127 Jan 30, 2024
362fc27
refactor to download repo only once
JoeWang1127 Jan 31, 2024
a8cd899
use absolute path
JoeWang1127 Jan 31, 2024
449f3d5
do not remove files as owlbot cli will take care of it
JoeWang1127 Jan 31, 2024
ae4726c
move pre generation to utilities
JoeWang1127 Jan 31, 2024
c134ebf
remove new-client scripts
JoeWang1127 Jan 31, 2024
23e4732
move api download function to utilities
JoeWang1127 Jan 31, 2024
f853130
add helper function
JoeWang1127 Jan 31, 2024
1478e4e
fix unit tests
JoeWang1127 Jan 31, 2024
cd90e04
add copyright
JoeWang1127 Jan 31, 2024
5b60d25
refactor
JoeWang1127 Jan 31, 2024
997cff5
regenerate root pom.xml
JoeWang1127 Jan 31, 2024
6894a55
generate gapic libraries bom using python
JoeWang1127 Feb 1, 2024
99afa38
Merge branch 'main' into feat/generate_repo
JoeWang1127 Feb 1, 2024
a7b210a
add unit tests
JoeWang1127 Feb 1, 2024
d3bc0f6
add unit tests
JoeWang1127 Feb 1, 2024
1edbb21
do not pull git repository
JoeWang1127 Feb 2, 2024
0d14629
add unit test
JoeWang1127 Feb 2, 2024
b7c6728
refactor
JoeWang1127 Feb 2, 2024
e76647c
remove irrelevant test data
JoeWang1127 Feb 2, 2024
ec8d51e
do not use enum
JoeWang1127 Feb 2, 2024
818e3a9
use apigeeconnect in yaml
JoeWang1127 Feb 2, 2024
42cc2ee
remove customized constructor
JoeWang1127 Feb 3, 2024
d9fe30c
add get_library_name
JoeWang1127 Feb 3, 2024
b047df7
separate cli and logic
JoeWang1127 Feb 3, 2024
21fa068
code format
JoeWang1127 Feb 3, 2024
f7613c1
add integration test
JoeWang1127 Feb 3, 2024
90385b1
remove shell integration test
JoeWang1127 Feb 3, 2024
3423183
code format
JoeWang1127 Feb 3, 2024
5338681
use git, rather than subprocess
JoeWang1127 Feb 3, 2024
63a7a48
remove pyenv
JoeWang1127 Feb 3, 2024
4ee961f
add unit tests
JoeWang1127 Feb 3, 2024
c2b7b21
change workflow
JoeWang1127 Feb 3, 2024
9c583cf
set git user
JoeWang1127 Feb 3, 2024
5bdd2c6
restore mvn command
JoeWang1127 Feb 3, 2024
4d0f70a
add issue_tracker to LibraryConfig
JoeWang1127 Feb 3, 2024
066af7f
add api_reference to LibraryConfig
JoeWang1127 Feb 3, 2024
e30f5c1
compare generation result in integration test
JoeWang1127 Feb 3, 2024
d1022fb
surpress mvn output
JoeWang1127 Feb 3, 2024
342df91
only generate .repo-metadat.json once
JoeWang1127 Feb 3, 2024
7cfd7c3
create library_path if it's not exist
JoeWang1127 Feb 4, 2024
047e250
remove destination path in GeneratationConfig
JoeWang1127 Feb 4, 2024
2d71f54
remove destination path in GeneratationConfig
JoeWang1127 Feb 4, 2024
9416899
add unit tests
JoeWang1127 Feb 4, 2024
f948f31
remove delete_if_exists
JoeWang1127 Feb 4, 2024
ab2d103
add log
JoeWang1127 Feb 4, 2024
ce12090
change assert
JoeWang1127 Feb 5, 2024
0610047
handle special cases in gapic-libraries-bom/pom.xml
JoeWang1127 Feb 5, 2024
984bc83
refactor compre_poms.py
JoeWang1127 Feb 5, 2024
2535b16
compare gapic-libraries-bom/pom.xml and pom.xml in integration test
JoeWang1127 Feb 5, 2024
14e1c92
Revert "compare gapic-libraries-bom/pom.xml and pom.xml in integratio…
JoeWang1127 Feb 5, 2024
1c2d9c1
compare pom.xml in integration test
JoeWang1127 Feb 5, 2024
2aad329
format config file
JoeWang1127 Feb 5, 2024
5adf0ee
covert transport
JoeWang1127 Feb 5, 2024
b9a717c
enable diff_files
JoeWang1127 Feb 5, 2024
2e0f3a9
refactor according to code review
JoeWang1127 Feb 6, 2024
2c0f9b2
code format
JoeWang1127 Feb 6, 2024
e592f71
code format
JoeWang1127 Feb 6, 2024
369ca21
add python linter
JoeWang1127 Feb 6, 2024
c17d321
change job name
JoeWang1127 Feb 6, 2024
a0dc4cb
Merge branch 'main' into feat/generate_repo
JoeWang1127 Feb 6, 2024
0e2f22b
Merge branch 'main' into feat/generate_repo
JoeWang1127 Feb 7, 2024
c1ef755
bring back config for java-bigtable
JoeWang1127 Feb 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 21 additions & 28 deletions .github/workflows/verify_library_generation.yaml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What tool did you format the python files with? It'd be nice if that tool had a linter mode that fails on non-compliant files so we can add it as part of our linter step

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What tool did you format the python files with?

I use black to format python code and it also has a validate function.

It'd be nice if that tool had a linter mode that fails on non-compliant files so we can add it as part of our linter step

Sure, I'll add a lint step in CI.

This tool is included when I install all requirements.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a python lint job in CI.

Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ jobs:
strategy:
matrix:
java: [ 11 ]
os: [ ubuntu-22.04, macos-12 ]
post_processing: [ 'true', 'false' ]
runs-on: ${{ matrix.os }}
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
Expand Down Expand Up @@ -45,35 +43,13 @@ jobs:
pushd library_generation
pip install -r requirements.in
popd

- name: install utils (macos)
if: matrix.os == 'macos-12'
shell: bash
run: |
brew update --preinstall
# we need the `realpath` command to be available
brew install coreutils
- name: install docker (ubuntu)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to install docker because it's included in ubuntu-22.04

if: matrix.os == 'ubuntu-22.04'
shell: bash
run: |
set -x
# install docker
sudo apt install containerd -y
sudo apt install -y docker.io docker-compose

# launch docker
sudo systemctl start docker
- name: Run integration tests
# we don't run ITs with postprocessing on macos because one of its dependencies "synthtool" is designed to run on linux only
if: matrix.os == 'ubuntu-22.04' || matrix.post_processing == 'false'
shell: bash
run: |
set -x
git config --global user.email "github-workflow@github.com"
git config --global user.name "Github Workflow"
library_generation/test/generate_library_integration_test.sh \
--googleapis_gen_url https://cloud-java-bot:${{ secrets.CLOUD_JAVA_BOT_GITHUB_TOKEN }}@github.com/googleapis/googleapis-gen.git \
--enable_postprocessing "${{ matrix.post_processing }}"
python -m unittest library_generation/test/integration_tests.py
unit_tests:
strategy:
matrix:
Expand Down Expand Up @@ -106,7 +82,7 @@ jobs:
run: |
set -x
python -m unittest library_generation/test/unit_tests.py
lint:
lint-shell:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
Expand All @@ -116,3 +92,20 @@ jobs:
scandir: 'library_generation'
format: tty
severity: error
lint-python:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: install python dependencies
shell: bash
run: |
set -ex
pushd library_generation
pip install -r requirements.in
popd
- name: Lint
shell: bash
run: |
# exclude generated golden files
# exclude owlbot until further refaction
black --check library_generation --exclude "(library_generation/owlbot)|(library_generation/test/resources/goldens)"
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ target/

# Python
**/__pycache__/
.venv

# library generation
output/
library_generation/output/
library_generation/test/output
library_generation/test/googleapis
library_generation/test/resources/integration/golden
showcase/scripts/output/
Empty file added library_generation/__init__.py
Empty file.
263 changes: 147 additions & 116 deletions library_generation/generate_composed_library.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
#!/usr/bin/env python3
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
This script allows generation of libraries that are composed of more than one
service version. It is achieved by calling `generate_library.sh` without
Expand All @@ -12,130 +27,146 @@
- A "grafeas" folder found in the googleapis/googleapis repository
Note: googleapis repo is found in https://github.com/googleapis/googleapis.
"""

import click
import utilities as util
import os
import sys
import subprocess
import json
from model.GenerationConfig import GenerationConfig
from model.LibraryConfig import LibraryConfig
from model.ClientInputs import parse as parse_build_file
from pathlib import Path
from typing import List
import library_generation.utilities as util
from library_generation.model.generation_config import GenerationConfig
from library_generation.model.gapic_config import GapicConfig
from library_generation.model.gapic_inputs import GapicInputs
from library_generation.model.library_config import LibraryConfig
from library_generation.model.gapic_inputs import parse as parse_build_file

script_dir = os.path.dirname(os.path.realpath(__file__))

"""
Main function in charge of generating libraries composed of more than one
service or service version.
Arguments
- config: a GenerationConfig object representing a parsed configuration
yaml
- library: a LibraryConfig object contained inside config, passed here for
convenience and to prevent all libraries to be processed
- enable_postprocessing: true if postprocessing should be done on the generated
libraries
- repository_path: path to the repository where the generated files will be
sent. If not specified, it will default to the one defined in the configuration yaml
and will be downloaded. The versions file will be inferred from this folder
"""

def generate_composed_library(
config: GenerationConfig,
library_path: str,
library: LibraryConfig,
repository_path: str,
enable_postprocessing: bool = True,
output_folder: str,
versions_file: str,
) -> None:
output_folder = util.sh_util('get_output_folder')

print(f'output_folder: {output_folder}')
print('library: ', library)
os.makedirs(output_folder, exist_ok=True)

googleapis_commitish = config.googleapis_commitish
if library.googleapis_commitish is not None:
googleapis_commitish = library.googleapis_commitish
print('using library-specific googleapis commitish: ' + googleapis_commitish)
else:
print('using common googleapis_commitish')

print('removing old googleapis folders and files')
util.delete_if_exists(f'{output_folder}/google')
util.delete_if_exists(f'{output_folder}/grafeas')

print('downloading googleapis')
util.sh_util(f'download_googleapis_files_and_folders "{output_folder}" "{googleapis_commitish}"')

is_monorepo = len(config.libraries) > 1
"""
Generate libraries composed of more than one service or service version
:param config: a GenerationConfig object representing a parsed configuration
yaml
:param library_path: the path to which the generated file goes
:param library: a LibraryConfig object contained inside config, passed here
for convenience and to prevent all libraries to be processed
:param output_folder:
:param versions_file:
:return None
"""
util.pull_api_definition(
config=config, library=library, output_folder=output_folder
)

is_monorepo = util.check_monorepo(config=config)
base_arguments = __construct_tooling_arg(config=config)
owlbot_cli_source_folder = util.sh_util("mktemp -d")
os.makedirs(f"{library_path}", exist_ok=True)
for gapic in library.gapic_configs:
build_file_folder = Path(f"{output_folder}/{gapic.proto_path}").resolve()
print(f"build_file_folder: {build_file_folder}")
gapic_inputs = parse_build_file(build_file_folder, gapic.proto_path)
# generate prerequisite files (.repo-metadata.json, .OwlBot.yaml,
# owlbot.py) here because transport is parsed from BUILD.bazel,
# which lives in a versioned proto_path.
util.generate_prerequisite_files(
library=library,
proto_path=util.remove_version_from(gapic.proto_path),
transport=gapic_inputs.transport,
library_path=library_path,
)
service_version = gapic.proto_path.split("/")[-1]
temp_destination_path = f"java-{library.api_shortname}-{service_version}"
effective_arguments = __construct_effective_arg(
base_arguments=base_arguments,
gapic=gapic,
gapic_inputs=gapic_inputs,
temp_destination_path=temp_destination_path,
)
print("arguments: ")
print(effective_arguments)
print(f"Generating library from {gapic.proto_path} to {library_path}")
util.run_process_and_print_output(
["bash", f"{script_dir}/generate_library.sh", *effective_arguments],
"Library generation",
)

util.sh_util(
f'build_owlbot_cli_source_folder "{library_path}"'
+ f' "{owlbot_cli_source_folder}" "{output_folder}/{temp_destination_path}"'
+ f' "{gapic.proto_path}"',
cwd=output_folder,
)

base_arguments = []
base_arguments += util.create_argument('gapic_generator_version', config)
base_arguments += util.create_argument('grpc_version', config)
base_arguments += util.create_argument('protobuf_version', config)

library_name = f'java-{library.api_shortname}'
library_path = None

versions_file = ''
if is_monorepo:
print('this is a monorepo library')
destination_path = config.destination_path + '/' + library_name
library_folder = destination_path.split('/')[-1]
if repository_path is None:
print(f'sparse_cloning monorepo with {library_name}')
repository_path = f'{output_folder}/{config.destination_path}'
clone_out = util.sh_util(f'sparse_clone "https://github.com/googleapis/{MONOREPO_NAME}.git" "{library_folder} google-cloud-pom-parent google-cloud-jar-parent versions.txt .github"', cwd=output_folder)
print(clone_out)
library_path = f'{repository_path}/{library_name}'
versions_file = f'{repository_path}/versions.txt'
else:
print('this is a HW library')
destination_path = library_name
if repository_path is None:
repository_path = f'{output_folder}/{destination_path}'
util.delete_if_exists(f'{output_folder}/{destination_path}')
clone_out = util.sh_util(f'git clone "https://github.com/googleapis/{destination_path}.git"', cwd=output_folder)
print(clone_out)
library_path = f'{repository_path}'
versions_file = f'{repository_path}/versions.txt'

owlbot_cli_source_folder = util.sh_util('mktemp -d')
for gapic in library.gapic_configs:

effective_arguments = list(base_arguments)
effective_arguments += util.create_argument('proto_path', gapic)

build_file_folder = f'{output_folder}/{gapic.proto_path}'
print(f'build_file_folder: {build_file_folder}')
client_inputs = parse_build_file(build_file_folder, gapic.proto_path)
effective_arguments += [
'--proto_only', client_inputs.proto_only,
'--gapic_additional_protos', client_inputs.additional_protos,
'--transport', client_inputs.transport,
'--rest_numeric_enums', client_inputs.rest_numeric_enum,
'--gapic_yaml', client_inputs.gapic_yaml,
'--service_config', client_inputs.service_config,
'--service_yaml', client_inputs.service_yaml,
'--include_samples', client_inputs.include_samples,
]
service_version = gapic.proto_path.split('/')[-1]
temp_destination_path = f'java-{library.api_shortname}-{service_version}'
effective_arguments += [ '--destination_path', temp_destination_path ]
print('arguments: ')
print(effective_arguments)
print(f'Generating library from {gapic.proto_path} to {destination_path}...')
util.run_process_and_print_output(['bash', '-x', f'{script_dir}/generate_library.sh',
*effective_arguments], 'Library generation')


if enable_postprocessing:
util.sh_util(f'build_owlbot_cli_source_folder "{library_path}"'
+ f' "{owlbot_cli_source_folder}" "{output_folder}/{temp_destination_path}"'
+ f' "{gapic.proto_path}"',
cwd=output_folder)

if enable_postprocessing:
# call postprocess library
util.run_process_and_print_output([f'{script_dir}/postprocess_library.sh',
f'{library_path}', '', versions_file, owlbot_cli_source_folder,
config.owlbot_cli_image, config.synthtool_commitish, str(is_monorepo).lower()], 'Library postprocessing')
util.run_process_and_print_output(
[
f"{script_dir}/postprocess_library.sh",
f"{library_path}",
"",
versions_file,
owlbot_cli_source_folder,
config.owlbot_cli_image,
config.synthtool_commitish,
str(is_monorepo).lower(),
],
"Library postprocessing",
)


def __construct_tooling_arg(config: GenerationConfig) -> List[str]:
"""
Construct arguments of tooling versions used in generate_library.sh
:param config: the generation config
:return: arguments containing tooling versions
"""
arguments = []
arguments += util.create_argument("gapic_generator_version", config)
arguments += util.create_argument("grpc_version", config)
arguments += util.create_argument("protobuf_version", config)

return arguments


def __construct_effective_arg(
base_arguments: List[str],
gapic: GapicConfig,
gapic_inputs: GapicInputs,
temp_destination_path: str,
) -> List[str]:
"""
Construct arguments consist attributes of a GAPIC library which used in
generate_library.sh
:param base_arguments: arguments consist of tooling versions
:param gapic: an object of GapicConfig
:param gapic_inputs: an object of GapicInput
:param temp_destination_path: the path to which the generated library goes
:return: arguments containing attributes to generate a GAPIC library
"""
arguments = list(base_arguments)
arguments += util.create_argument("proto_path", gapic)
arguments += [
"--proto_only",
gapic_inputs.proto_only,
"--gapic_additional_protos",
gapic_inputs.additional_protos,
"--transport",
gapic_inputs.transport,
"--rest_numeric_enums",
gapic_inputs.rest_numeric_enum,
"--gapic_yaml",
gapic_inputs.gapic_yaml,
"--service_config",
gapic_inputs.service_config,
"--service_yaml",
gapic_inputs.service_yaml,
"--include_samples",
gapic_inputs.include_samples,
]
arguments += ["--destination_path", temp_destination_path]

return arguments
Loading
Loading