Skip to content

Commit 522db0e

Browse files
authored
ci(gapic-generator): add showcase canary job, span artifact upload, and isolate goldens from pre-commit (#18518)
### Problem 1. Pre-commit hooks run across the whole monorepo and risk reformatting or modifying Bazel integration test golden files (`packages/gapic-generator/tests/integration/goldens/`), causing false positive diff failures in golden verification tests. 2. In monorepo CI, gapic-generator integration tests install dependencies from PyPI rather than testing directly against local, unpublished changes in sibling packages like `google-api-core`. Being able to run showcase tests against local changes is critical for ongoing work such as the observability work. 3. When running system tests in CI, there is currently no mechanism to preserve and download raw output data (such as telemetry span dumps) to debug result regressions or verify compliance artifacts. ### Solution - Exclude `packages/gapic-generator/tests/integration/goldens/` from `.pre-commit-config.yaml` to ensure golden files remain untouched by repository-wide hooks. - Add `showcase-canary` job to `.github/workflows/gapic-generator-tests.yml` that runs Showcase integration tests against the local monorepo `google-api-core` when `INSTALL_LOCAL_CORE="true"`. - Support the `INSTALL_LOCAL_CORE` environment variable in `packages/gapic-generator/noxfile.py` to optionally install local core in development and CI environments. - Add an `Upload Raw Spans Artifact` step to both `showcase` and `showcase-canary` jobs to upload `raw_spans_output.json` as a build artifact. ### Notes for Reviewers - This change is strictly focused on testing infrastructure and repository hygiene. - It does not modify any client generation code or generator templates.
1 parent 5d57b25 commit 522db0e

4 files changed

Lines changed: 123 additions & 15 deletions

File tree

‎.github/workflows/gapic-generator-tests.yml‎

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ jobs:
7171
with:
7272
python-version: "${{ matrix.python }}"
7373
allow-prereleases: true
74-
# Caches compiled wheels locally to prevent building heavy libraries
74+
# Caches compiled wheels locally to prevent building heavy libraries
7575
# such as grpcio, which we build from scratch on every run for Python 3.15+.
7676
# Follow https://github.com/grpc/grpc/issues/41010 for updates.
7777
cache: 'pip'
@@ -142,6 +142,68 @@ jobs:
142142
run: |
143143
cd packages/gapic-generator
144144
nox -s ${{ matrix.target }}-${MATRIX_PYTHON}
145+
- name: Upload Raw Spans Artifact
146+
if: always()
147+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
148+
with:
149+
name: raw-spans-${{ matrix.target }}-${{ matrix.python }}${{ matrix.logging_scope && format('-{0}', matrix.logging_scope) || '' }}
150+
path: packages/gapic-generator/tests/system/raw_spans_output.json
151+
if-no-files-found: ignore
152+
153+
showcase-canary:
154+
needs: python_config
155+
strategy:
156+
# Run canary tests with local monorepo google-api-core on bookend runtimes
157+
matrix:
158+
python: ["${{ needs.python_config.outputs.oldest_python }}", "${{ needs.python_config.outputs.latest_stable_python }}"]
159+
target: [showcase, showcase_w_rest_async]
160+
runs-on: ubuntu-latest
161+
steps:
162+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
163+
with:
164+
persist-credentials: false
165+
- name: Set up Python "${{ matrix.python }}"
166+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
167+
with:
168+
python-version: "${{ matrix.python }}"
169+
cache: 'pip'
170+
- name: Install system dependencies.
171+
run: |
172+
sudo apt-get update
173+
sudo apt-get install -y curl pandoc unzip
174+
- name: Install showcase
175+
run: |
176+
sudo mkdir -p /usr/src/showcase
177+
sudo chown -R ${USER} /usr/src/
178+
curl --location https://github.com/googleapis/gapic-showcase/releases/download/v${SHOWCASE_VERSION}/gapic-showcase-${SHOWCASE_VERSION}-linux-amd64.tar.gz --output /usr/src/showcase/showcase-${SHOWCASE_VERSION}-linux-amd64.tar.gz
179+
cd /usr/src/showcase/
180+
tar -xf showcase-*
181+
./gapic-showcase run &
182+
cd -
183+
- name: Install nox.
184+
run: python -m pip install nox
185+
- name: Install protoc
186+
run: |
187+
sudo mkdir -p /usr/src/protoc/
188+
sudo chown -R ${USER} /usr/src/
189+
curl --location https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip --output /usr/src/protoc/protoc-${PROTOC_VERSION}.zip
190+
cd /usr/src/protoc/
191+
unzip protoc-${PROTOC_VERSION}.zip
192+
sudo ln -s /usr/src/protoc/bin/protoc /usr/local/bin/protoc
193+
- name: Run showcase canary with local google-api-core.
194+
env:
195+
INSTALL_LOCAL_CORE: "true"
196+
MATRIX_PYTHON: ${{ matrix.python }}
197+
run: |
198+
cd packages/gapic-generator
199+
nox -s ${{ matrix.target }}-${MATRIX_PYTHON}
200+
- name: Upload Raw Spans Artifact
201+
if: always()
202+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
203+
with:
204+
name: raw-spans-canary-${{ matrix.target }}-${{ matrix.python }}
205+
path: packages/gapic-generator/tests/system/raw_spans_output.json
206+
if-no-files-found: ignore
145207

146208
showcase-mypy:
147209
needs: python_config
@@ -210,7 +272,7 @@ jobs:
210272
with:
211273
python-version: ${{ needs.python_config.outputs.prerelease_python }}
212274
allow-prereleases: true
213-
# Caches compiled wheels locally to prevent building heavy libraries
275+
# Caches compiled wheels locally to prevent building heavy libraries
214276
# such as grpcio, which we build from scratch on every run for Python 3.15+.
215277
# Follow https://github.com/grpc/grpc/issues/41010 for updates.
216278
cache: 'pip'
@@ -242,7 +304,7 @@ jobs:
242304
with:
243305
python-version: ${{ matrix.python }}
244306
allow-prereleases: true
245-
# Caches compiled wheels locally to prevent building heavy libraries
307+
# Caches compiled wheels locally to prevent building heavy libraries
246308
# such as grpcio, which we build from scratch on every run for Python 3.15+.
247309
# Follow https://github.com/grpc/grpc/issues/41010 for updates.
248310
cache: 'pip'
@@ -287,13 +349,13 @@ jobs:
287349

288350
- name: Run Bazel Integration Tests
289351
run: |
290-
# We need to move into the package directory if the
352+
# We need to move into the package directory if the
291353
# WORKSPACE file is located there.
292354
cd packages/gapic-generator
293355
bazelisk test //tests/integration/... --test_output=errors
294356
295357
# Final job to simplify branch protection rules.
296-
# This job will be reported as 'Success' if all its dependencies either
358+
# This job will be reported as 'Success' if all its dependencies either
297359
# pass or are skipped due to path filtering.
298360
status:
299361
needs: [check_changes, python_config, showcase-unit, showcase, showcase-mypy, goldens, goldens-prerelease, fragment-snippet, integration]
@@ -314,4 +376,3 @@ jobs:
314376
exit 1
315377
fi
316378
echo "All checks passed or were successfully skipped."
317-

‎.pre-commit-config.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#
1515
# See https://pre-commit.com for more information
1616
# See https://pre-commit.com/hooks.html for more hooks
17+
exclude: '^packages/gapic-generator/tests/integration/goldens/'
1718
repos:
1819
- repo: https://github.com/pre-commit/pre-commit-hooks
1920
rev: v6.0.0

‎packages/gapic-generator/docs/conf.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,16 @@
183183
# -- Options for intersphinx extension ---------------------------------------
184184

185185
# Example configuration for intersphinx: refer to the Python standard library.
186-
intersphinx_mapping = {"https://docs.python.org/3/": None}
186+
intersphinx_mapping = {}
187+
188+
# Check reachability of the Python standard library inventory before attaching it.
189+
# Because Sphinx is run with `-W` (warnings as errors) in CI, an external network
190+
# failure or upstream outage on docs.python.org would otherwise treat the missing
191+
# inventory as a fatal error and fail the build.
192+
try:
193+
import urllib.request
194+
195+
with urllib.request.urlopen("https://docs.python.org/3/objects.inv", timeout=2):
196+
intersphinx_mapping["https://docs.python.org/3/"] = None
197+
except Exception:
198+
pass

‎packages/gapic-generator/noxfile.py‎

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@
1818
# PIP_INDEX_URL=https://pypi.org/simple nox
1919

2020
from __future__ import absolute_import
21-
from concurrent.futures import ThreadPoolExecutor
22-
from pathlib import Path
21+
2322
import os
23+
import shutil
2424
import sys
2525
import tempfile
2626
import typing
27-
import nox # type: ignore
28-
27+
from concurrent.futures import ThreadPoolExecutor
2928
from contextlib import contextmanager
3029
from os import path
31-
import shutil
30+
from pathlib import Path
3231

32+
import nox # type: ignore
3333

3434
nox.options.error_on_missing_interpreters = True
3535

@@ -401,9 +401,23 @@ def showcase(
401401
other_opts: typing.Iterable[str] = (),
402402
env: typing.Optional[typing.Dict[str, str]] = {},
403403
):
404-
"""Run the Showcase test suite."""
404+
"""Run the Showcase test suite.
405+
406+
Set INSTALL_LOCAL_CORE=true to install packages/google-api-core from source
407+
(useful for local testing and canary validation).
408+
"""
405409

406410
with showcase_library(session, templates=templates, other_opts=other_opts):
411+
# When opt-in environment variable is set (e.g. in canary CI or local testing),
412+
# install the local google-api-core package from source.
413+
if os.getenv("INSTALL_LOCAL_CORE") == "true":
414+
local_core = Path(__file__).resolve().parent.parent / "google-api-core"
415+
if not local_core.is_dir():
416+
session.error(
417+
f"INSTALL_LOCAL_CORE is set to 'true' but {local_core} does not exist."
418+
)
419+
session.install("-e", str(local_core))
420+
407421
# Use pytest-asyncio<1.0.0 while we investigate the recent failure described in
408422
# https://github.com/googleapis/gapic-generator-python/issues/2399
409423
session.install("pytest", "pytest-asyncio<1.0.0")
@@ -431,11 +445,25 @@ def showcase_w_rest_async(
431445
other_opts: typing.Iterable[str] = (),
432446
env: typing.Optional[typing.Dict[str, str]] = {},
433447
):
434-
"""Run the Showcase test suite."""
448+
"""Run the Showcase test suite with async rest transport.
449+
450+
Set INSTALL_LOCAL_CORE=true to install packages/google-api-core from source
451+
(useful for local testing and canary validation).
452+
"""
435453

436454
with showcase_library(
437455
session, templates=templates, other_opts=other_opts, rest_async_io_enabled=True
438456
):
457+
# When opt-in environment variable is set (e.g. in canary CI or local testing),
458+
# install the local google-api-core package from source.
459+
if os.getenv("INSTALL_LOCAL_CORE") == "true":
460+
local_core = Path(__file__).resolve().parent.parent / "google-api-core"
461+
if not local_core.is_dir():
462+
session.error(
463+
f"INSTALL_LOCAL_CORE is set to 'true' but {local_core} does not exist."
464+
)
465+
session.install("-e", str(local_core))
466+
439467
# Use pytest-asyncio<1.0.0 while we investigate the recent failure described in
440468
# https://github.com/googleapis/gapic-generator-python/issues/2399
441469
session.install("pytest", "pytest-asyncio<1.0.0")
@@ -498,7 +526,13 @@ def showcase_pqc(
498526
with showcase_library(session, templates=templates, other_opts=other_opts):
499527
session.install("pytest", "pytest-asyncio")
500528
session.install("--upgrade", "grpcio>=1.83.0", "grpcio-status>=1.83.0")
501-
session.run("py.test", "--quiet", "--tls", *(session.posargs or ["tests/system/test_pqc.py"]), env=env)
529+
session.run(
530+
"py.test",
531+
"--quiet",
532+
"--tls",
533+
*(session.posargs or ["tests/system/test_pqc.py"]),
534+
env=env,
535+
)
502536

503537

504538
def run_showcase_unit_tests(session, fail_under=100, rest_async_io_enabled=False):

0 commit comments

Comments
 (0)