Skip to content

Commit

Permalink
ci: Replace python go proto script with ci target (envoyproxy#27675)
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Northey <[email protected]>
Signed-off-by: Ryan Eskin <[email protected]>
  • Loading branch information
phlax authored and reskin89 committed Jul 11, 2023
1 parent a23e233 commit 951e372
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 167 deletions.
6 changes: 6 additions & 0 deletions ci/build_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

set -e

if [[ -n "$NO_BUILD_SETUP" ]]; then
exit
fi

export PPROF_PATH=/thirdparty_build/bin/pprof

[ -z "${NUM_CPUS}" ] && NUM_CPUS=$(grep -c ^processor /proc/cpuinfo)
Expand Down Expand Up @@ -196,3 +200,5 @@ if [[ "${ENVOY_BUILD_FILTER_EXAMPLE}" == "true" ]]; then
else
echo "Skip setting up Envoy Filter Example."
fi

export NO_BUILD_SETUP=1
55 changes: 44 additions & 11 deletions ci/do_ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ set -e
# TODO(phlax): Clarify and/or integrate SRCDIR and ENVOY_SRCDIR
export SRCDIR="${SRCDIR:-$PWD}"
export ENVOY_SRCDIR="${ENVOY_SRCDIR:-$PWD}"
NO_BUILD_SETUP="${NO_BUILD_SETUP:-}"

if [[ -z "$NO_BUILD_SETUP" ]]; then
# shellcheck source=ci/setup_cache.sh
. "$(dirname "$0")"/setup_cache.sh
# shellcheck source=ci/build_setup.sh
. "$(dirname "$0")"/build_setup.sh
# shellcheck source=ci/setup_cache.sh
. "$(dirname "$0")"/setup_cache.sh
# shellcheck source=ci/build_setup.sh
. "$(dirname "$0")"/build_setup.sh

echo "building using ${NUM_CPUS} CPUs"
echo "building for ${ENVOY_BUILD_ARCH}"

echo "building using ${NUM_CPUS} CPUs"
echo "building for ${ENVOY_BUILD_ARCH}"
fi
cd "${SRCDIR}"

if [[ "${ENVOY_BUILD_ARCH}" == "x86_64" ]]; then
Expand Down Expand Up @@ -202,8 +200,6 @@ case $CI_TARGET in
//tools/protoprint:protoprint_test
echo "Validating API structure..."
"${ENVOY_SRCDIR}"/tools/api/validate_structure.py
echo "Validate Golang protobuf generation..."
"${ENVOY_SRCDIR}"/tools/api/generate_go_protobuf.py
echo "Testing API..."
bazel_with_collection \
test "${BAZEL_BUILD_OPTIONS[@]}" \
Expand All @@ -215,6 +211,43 @@ case $CI_TARGET in
echo "Building API..."
bazel build "${BAZEL_BUILD_OPTIONS[@]}" \
-c fastbuild @envoy_api//envoy/...
if [[ -n "$ENVOY_API_ONLY" ]]; then
exit 0
fi
;&

api.go)
if [[ -z "$NO_BUILD_SETUP" ]]; then
setup_clang_toolchain
fi
GO_IMPORT_BASE="github.com/envoyproxy/go-control-plane"
GO_TARGETS=(@envoy_api//...)
read -r -a GO_PROTOS <<< "$(bazel query "${BAZEL_GLOBAL_OPTIONS[@]}" "kind('go_proto_library', ${GO_TARGETS[*]})" | tr '\n' ' ')"
echo "${GO_PROTOS[@]}" | grep -q envoy_api || echo "No go proto targets found"
bazel build "${BAZEL_BUILD_OPTIONS[@]}" \
--experimental_proto_descriptor_sets_include_source_info \
--remote_download_outputs=all \
"${GO_PROTOS[@]}"
rm -rf build_go
mkdir -p build_go
echo "Copying go protos -> build_go"
BAZEL_BIN="$(bazel info "${BAZEL_BUILD_OPTIONS[@]}" bazel-bin)"
for GO_PROTO in "${GO_PROTOS[@]}"; do
# strip @envoy_api//
RULE_DIR="$(echo "${GO_PROTO:12}" | cut -d: -f1)"
PROTO="$(echo "${GO_PROTO:12}" | cut -d: -f2)"
INPUT_DIR="${BAZEL_BIN}/external/envoy_api/${RULE_DIR}/${PROTO}_/${GO_IMPORT_BASE}/${RULE_DIR}"
OUTPUT_DIR="build_go/${RULE_DIR}"
mkdir -p "$OUTPUT_DIR"
if [[ ! -e "$INPUT_DIR" ]]; then
echo "Unable to find input ${INPUT_DIR}" >&2
exit 1
fi
# echo "Copying go files ${INPUT_DIR} -> ${OUTPUT_DIR}"
while read -r GO_FILE; do
cp -a "$GO_FILE" "$OUTPUT_DIR"
done <<< "$(find "$INPUT_DIR" -name "*.go")"
done
;;

api_compat)
Expand Down
161 changes: 5 additions & 156 deletions tools/api/generate_go_protobuf.py
Original file line number Diff line number Diff line change
@@ -1,164 +1,13 @@
#!/usr/bin/env python3

from subprocess import check_output, STDOUT, CalledProcessError
import argparse
import glob
import os
import shlex
import shutil
import sys
import re

# Needed for CI to pass down bazel options.
BAZEL_BUILD_OPTIONS = shlex.split(os.environ.get('BAZEL_BUILD_OPTION_LIST', ''))
BAZEL_GLOBAL_OPTIONS = shlex.split(os.environ.get('BAZEL_GLOBAL_OPTION_LIST', ''))
BAZEL_STARTUP_OPTIONS = shlex.split(os.environ.get('BAZEL_STARTUP_OPTION_LIST', ''))

TARGETS = '@envoy_api//...'
IMPORT_BASE = 'github.com/envoyproxy/go-control-plane'
REPO_BASE = 'go-control-plane'
BRANCH = 'main'
MIRROR_MSG = 'Mirrored from envoyproxy/envoy @ '
USER_NAME = 'go-control-plane(Azure Pipelines)'
USER_EMAIL = '[email protected]'


def generate_protobufs(targets, output, api_repo):
bazel_bin = check_output(
['bazel', *BAZEL_STARTUP_OPTIONS, 'info', *BAZEL_BUILD_OPTIONS,
'bazel-bin']).decode().strip()
go_protos = check_output([
'bazel',
*BAZEL_STARTUP_OPTIONS,
'query',
*BAZEL_GLOBAL_OPTIONS,
'kind("go_proto_library", %s)' % targets,
]).split()

# Each rule has the form @envoy_api//foo/bar:baz_go_proto.
# First build all the rules to ensure we have the output files.
# We preserve source info so comments are retained on generated code.
try:
check_output([
'bazel', *BAZEL_STARTUP_OPTIONS, 'build', '-c', 'fastbuild',
'--experimental_proto_descriptor_sets_include_source_info'
] + BAZEL_BUILD_OPTIONS + go_protos,
stderr=STDOUT)
except CalledProcessError as e:
print(e.output)
raise e

for rule in go_protos:
# Example rule:
# @envoy_api//envoy/config/bootstrap/v2:pkg_go_proto
#
# Example generated directory:
# bazel-bin/external/envoy_api/envoy/config/bootstrap/v2/linux_amd64_stripped/pkg_go_proto%/github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v2/
#
# Example output directory:
# go_out/envoy/config/bootstrap/v2
rule_dir, proto = rule.decode().rsplit('//', 1)[1].rsplit(':', 1)

prefix = '' if not api_repo else os.path.join('external', api_repo)
input_dir = os.path.join(bazel_bin, prefix, rule_dir, proto + '_', IMPORT_BASE, rule_dir)
input_files = glob.glob(os.path.join(input_dir, '*.go'))
output_dir = os.path.join(output, rule_dir)

# Ensure the output directory exists
os.makedirs(output_dir, 0o755, exist_ok=True)
for generated_file in input_files:
shutil.copy(generated_file, output_dir)
print('Go artifacts placed into: ' + output)


def git(repo, *args):
cmd = ['git']
if repo:
cmd = cmd + ['-C', repo]
for arg in args:
cmd = cmd + [arg]
return check_output(cmd).decode()


def clone_go_protobufs(repo):
# Create a local clone of go-control-plane
git(None, 'clone', '[email protected]:envoyproxy/go-control-plane', repo, '-b', BRANCH)


def find_last_sync_sha(repo):
# Determine last envoyproxy/envoy SHA in envoyproxy/go-control-plane
last_commit = git(repo, 'log', '--grep=' + MIRROR_MSG, '-n', '1', '--format=%B').strip()
# Initial SHA from which the APIs start syncing. Prior to that it was done manually.
if last_commit == "":
return 'e7f0b7176efdc65f96eb1697b829d1e6187f4502'
m = re.search(MIRROR_MSG + '(\w+)', last_commit)
return m.group(1)


def updated_since_sha(repo, last_sha):
# Determine if there are changes to API since last SHA
return git(None, 'rev-list', '%s..HEAD' % last_sha).split()


def write_revision_info(repo, sha):
# Put a file in the generated code root containing the latest mirrored SHA
dst = os.path.join(repo, 'envoy', 'COMMIT')
with open(dst, 'w') as fh:
fh.write(sha)


def sync_go_protobufs(output, repo):
for folder in ['envoy', 'contrib']:
# Sync generated content against repo and return true if there is a commit necessary
dst = os.path.join(repo, folder)
# Remove subtree in repo
git(repo, 'rm', '-r', '--ignore-unmatch', folder)
# Copy subtree from output to repo
shutil.copytree(os.path.join(output, folder), dst)
git(repo, 'add', folder)


def publish_go_protobufs(repo, sha):
# Publish generated files with the last SHA changes to API
git(repo, 'config', 'user.name', USER_NAME)
git(repo, 'config', 'user.email', USER_EMAIL)
git(repo, 'add', 'envoy')
git(repo, 'add', 'contrib')
git(repo, 'commit', '--allow-empty', '-s', '-m', MIRROR_MSG + sha)
git(repo, 'push', 'origin', BRANCH)


def updated(repo):
return len([
f for f in git(repo, 'diff', 'HEAD', '--name-only').splitlines() if f != 'envoy/COMMIT'
]) > 0
def main():
# TODO(phlax): remove this 12/23
sys.stderr.write("This script has been removed, please use `ci/do_ci.sh api.go` instead\n")
sys.exit(1)


if __name__ == "__main__":
parser = argparse.ArgumentParser(
description='Generate Go protobuf files and sync with go-control-plane')
parser.add_argument('--sync', action='store_true')
parser.add_argument('--output_base', default='build_go')
parser.add_argument('--targets', default=TARGETS)
parser.add_argument('--api_repo', default="envoy_api")
args = parser.parse_args()

workspace = check_output(
['bazel', *BAZEL_STARTUP_OPTIONS, 'info', *BAZEL_BUILD_OPTIONS,
'workspace']).decode().strip()
output = os.path.join(workspace, args.output_base)
generate_protobufs(args.targets, output, args.api_repo)
if not args.sync:
print('Skipping sync with go-control-plane')
sys.exit()

repo = os.path.join(workspace, REPO_BASE)
clone_go_protobufs(repo)
sync_go_protobufs(output, repo)
last_sha = find_last_sync_sha(repo)
changes = updated_since_sha(repo, last_sha)
if updated(repo):
print('Changes detected: %s' % changes)
new_sha = changes[0]
write_revision_info(repo, new_sha)
publish_go_protobufs(repo, new_sha)
main()

0 comments on commit 951e372

Please sign in to comment.