From b23b2811b78576d6ec62a3547e2b0a87151aeb68 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 29 Jul 2026 07:38:55 -0400 Subject: [PATCH 01/25] feat: implement ad-hoc package selection for CI/CD --- .kokoro/system.sh | 45 +++++++++++++++++++++++++++ ci/adhoc/.package_groups.txt | 4 +++ ci/adhoc/.standalone_package_list.txt | 3 ++ ci/adhoc/adhoc_test_runner.sh | 40 ++++++++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 ci/adhoc/.package_groups.txt create mode 100644 ci/adhoc/.standalone_package_list.txt create mode 100755 ci/adhoc/adhoc_test_runner.sh diff --git a/.kokoro/system.sh b/.kokoro/system.sh index 7635c0be17ea..ccf2fb177772 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -276,6 +276,51 @@ for path in `find 'packages' \ fi done +# --- Ad-hoc Testing Integration --- +TRIGGER_ADHOC="false" +if [[ -n "${KOKORO_GITHUB_PULL_REQUEST_NUMBER}" ]]; then + echo "Checking for adhoc test label on PR #${KOKORO_GITHUB_PULL_REQUEST_NUMBER}..." + LABELS_JSON=$(curl -s -H "User-Agent: Kokoro" "https://api.github.com/repos/googleapis/google-cloud-python/issues/${KOKORO_GITHUB_PULL_REQUEST_NUMBER}/labels") + + IS_ADHOC=$(python3 -c " +import json +import sys +try: + labels = json.loads(sys.argv[1]) + if any(l.get('name') == 'test:adhoc' for l in labels): + print('true') +except Exception: + pass +" "$LABELS_JSON") + + if [[ "$IS_ADHOC" == "true" ]]; then + TRIGGER_ADHOC="true" + echo "Adhoc test label 'test:adhoc' found!" + fi +fi + +if [[ "$TRIGGER_ADHOC" == "true" ]]; then + echo "Running ad-hoc package selection..." + source ci/adhoc/adhoc_test_runner.sh + + declare -A unique_packages + for pkg in "${PACKAGES_TO_TEST[@]}"; do + unique_packages["$pkg"]=1 + done + + for pkg in $ADHOC_PACKAGES; do + unique_packages["$pkg"]=1 + done + + PACKAGES_TO_TEST=() + for pkg in "${!unique_packages[@]}"; do + PACKAGES_TO_TEST+=("$pkg") + done + + echo "Combined packages to test: ${PACKAGES_TO_TEST[*]}" +fi +# --- End Ad-hoc Testing Integration --- + # Parallel Execution Logic MAX_JOBS=${MAX_JOBS:-4} diff --git a/ci/adhoc/.package_groups.txt b/ci/adhoc/.package_groups.txt new file mode 100644 index 000000000000..2ea28bb05dcf --- /dev/null +++ b/ci/adhoc/.package_groups.txt @@ -0,0 +1,4 @@ +handwritten: google-cloud-bigquery +handwritten: google-cloud-logging +core: google-api-core +core: google-cloud-core diff --git a/ci/adhoc/.standalone_package_list.txt b/ci/adhoc/.standalone_package_list.txt new file mode 100644 index 000000000000..ecbd2dfe04af --- /dev/null +++ b/ci/adhoc/.standalone_package_list.txt @@ -0,0 +1,3 @@ +package: google-cloud-logging +package: google-cloud-bigtable +group: handwritten diff --git a/ci/adhoc/adhoc_test_runner.sh b/ci/adhoc/adhoc_test_runner.sh new file mode 100755 index 000000000000..2fb1d5eedfa8 --- /dev/null +++ b/ci/adhoc/adhoc_test_runner.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Script to determine ad-hoc packages to test. +# This script is intended to be sourced from main test scripts. + +# Ensure we are in the project root if called directly, +# but usually this is sourced and CWD is already project root. +# For safety, we can use script location but if sourced $0 might be the parent script. +# Let's assume CWD is project root as per system.sh behavior. + +ADHOC_DIR="ci/adhoc" +STANDALONE_LIST="${ADHOC_DIR}/.standalone_package_list.txt" +GROUPS_FILE="${ADHOC_DIR}/.package_groups.txt" + +if [[ ! -f "$STANDALONE_LIST" ]]; then + echo "Warning: $STANDALONE_LIST not found." + return 0 2>/dev/null || exit 0 +fi + +if [[ ! -f "$GROUPS_FILE" ]]; then + echo "Warning: $GROUPS_FILE not found." + return 0 2>/dev/null || exit 0 +fi + +# Grab individual packages +adhoc_packages=$(grep "^package:" "$STANDALONE_LIST" | cut -d':' -f2 | xargs) + +# Grab requested groups +requested_groups=$(grep "^group:" "$STANDALONE_LIST" | cut -d':' -f2 | xargs) + +# Expand groups +for group in $requested_groups; do + group_pkgs=$(grep "^$group:" "$GROUPS_FILE" | cut -d':' -f2 | xargs) + adhoc_packages="$adhoc_packages $group_pkgs" +done + +# Convert to unique list (deduplicate our adhoc packages) +ADHOC_PACKAGES=$(echo $adhoc_packages | tr ' ' '\n' | sort -u | xargs) + +export ADHOC_PACKAGES From e8baccc45503f22c41af25d8e3feded4971b316f Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 29 Jul 2026 07:54:45 -0400 Subject: [PATCH 02/25] docs: add comment explaining inline python usage in system.sh --- .kokoro/system.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index ccf2fb177772..62c0e4e77f66 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -282,6 +282,9 @@ if [[ -n "${KOKORO_GITHUB_PULL_REQUEST_NUMBER}" ]]; then echo "Checking for adhoc test label on PR #${KOKORO_GITHUB_PULL_REQUEST_NUMBER}..." LABELS_JSON=$(curl -s -H "User-Agent: Kokoro" "https://api.github.com/repos/googleapis/google-cloud-python/issues/${KOKORO_GITHUB_PULL_REQUEST_NUMBER}/labels") + # We use a small inline Python snippet here because parsing JSON in pure Bash is difficult/error-prone, + # and we cannot guarantee that tools like 'jq' or 'gh' are installed in the test environment. + # Python and its built-in 'json' module are guaranteed to be available in this repository. IS_ADHOC=$(python3 -c " import json import sys From 85d0855e4b9743bedcd537c61f81e87ac59682bf Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 29 Jul 2026 07:58:39 -0400 Subject: [PATCH 03/25] docs: tweak comment explaining inline python usage --- .kokoro/system.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index 62c0e4e77f66..cc84f12abaf8 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -282,7 +282,8 @@ if [[ -n "${KOKORO_GITHUB_PULL_REQUEST_NUMBER}" ]]; then echo "Checking for adhoc test label on PR #${KOKORO_GITHUB_PULL_REQUEST_NUMBER}..." LABELS_JSON=$(curl -s -H "User-Agent: Kokoro" "https://api.github.com/repos/googleapis/google-cloud-python/issues/${KOKORO_GITHUB_PULL_REQUEST_NUMBER}/labels") - # We use a small inline Python snippet here because parsing JSON in pure Bash is difficult/error-prone, + # For this prototype: + # we use a small inline Python snippet here because parsing JSON in pure Bash is difficult/error-prone, # and we cannot guarantee that tools like 'jq' or 'gh' are installed in the test environment. # Python and its built-in 'json' module are guaranteed to be available in this repository. IS_ADHOC=$(python3 -c " From 56576b95501fc35f369889320939bab209cef4b9 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 29 Jul 2026 08:38:53 -0400 Subject: [PATCH 04/25] fix: make grep commands safe and quote variables in adhoc_test_runner.sh --- ci/adhoc/adhoc_test_runner.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/adhoc/adhoc_test_runner.sh b/ci/adhoc/adhoc_test_runner.sh index 2fb1d5eedfa8..8a658da9013f 100755 --- a/ci/adhoc/adhoc_test_runner.sh +++ b/ci/adhoc/adhoc_test_runner.sh @@ -23,18 +23,18 @@ if [[ ! -f "$GROUPS_FILE" ]]; then fi # Grab individual packages -adhoc_packages=$(grep "^package:" "$STANDALONE_LIST" | cut -d':' -f2 | xargs) +adhoc_packages=$(grep "^package:" "$STANDALONE_LIST" | cut -d':' -f2 | xargs || true) # Grab requested groups -requested_groups=$(grep "^group:" "$STANDALONE_LIST" | cut -d':' -f2 | xargs) +requested_groups=$(grep "^group:" "$STANDALONE_LIST" | cut -d':' -f2 | xargs || true) # Expand groups for group in $requested_groups; do - group_pkgs=$(grep "^$group:" "$GROUPS_FILE" | cut -d':' -f2 | xargs) + group_pkgs=$(grep "^$group:" "$GROUPS_FILE" | cut -d':' -f2 | xargs || true) adhoc_packages="$adhoc_packages $group_pkgs" done # Convert to unique list (deduplicate our adhoc packages) -ADHOC_PACKAGES=$(echo $adhoc_packages | tr ' ' '\n' | sort -u | xargs) +ADHOC_PACKAGES=$(echo "$adhoc_packages" | tr ' ' '\n' | sort -u | xargs) export ADHOC_PACKAGES From 43800e26561356fd226880aa8d6d5eda48122bc9 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 29 Jul 2026 08:39:05 -0400 Subject: [PATCH 05/25] fix: add auth token to curl and harden inline python in system.sh --- .kokoro/system.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index cc84f12abaf8..073d78c80ef7 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -280,7 +280,11 @@ done TRIGGER_ADHOC="false" if [[ -n "${KOKORO_GITHUB_PULL_REQUEST_NUMBER}" ]]; then echo "Checking for adhoc test label on PR #${KOKORO_GITHUB_PULL_REQUEST_NUMBER}..." - LABELS_JSON=$(curl -s -H "User-Agent: Kokoro" "https://api.github.com/repos/googleapis/google-cloud-python/issues/${KOKORO_GITHUB_PULL_REQUEST_NUMBER}/labels") + headers=(-H "User-Agent: Kokoro") + if [[ -n "${GITHUB_TOKEN:-${GH_TOKEN}}" ]]; then + headers+=(-H "Authorization: token ${GITHUB_TOKEN:-${GH_TOKEN}}") + fi + LABELS_JSON=$(curl -s "${headers[@]}" "https://api.github.com/repos/googleapis/google-cloud-python/issues/${KOKORO_GITHUB_PULL_REQUEST_NUMBER}/labels") # For this prototype: # we use a small inline Python snippet here because parsing JSON in pure Bash is difficult/error-prone, @@ -291,8 +295,9 @@ import json import sys try: labels = json.loads(sys.argv[1]) - if any(l.get('name') == 'test:adhoc' for l in labels): - print('true') + if isinstance(labels, list): + if any(isinstance(l, dict) and l.get('name') == 'test:adhoc' for l in labels): + print('true') except Exception: pass " "$LABELS_JSON") From 69bb3ce1d097ddb59e265bed96ba18d6c8ed3c31 Mon Sep 17 00:00:00 2001 From: Chalmer Lowe Date: Wed, 29 Jul 2026 09:26:02 -0400 Subject: [PATCH 06/25] Apply suggestion from @chalmerlowe --- ci/adhoc/adhoc_test_runner.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/adhoc/adhoc_test_runner.sh b/ci/adhoc/adhoc_test_runner.sh index 8a658da9013f..a7e0c10f880b 100755 --- a/ci/adhoc/adhoc_test_runner.sh +++ b/ci/adhoc/adhoc_test_runner.sh @@ -2,7 +2,7 @@ # Script to determine ad-hoc packages to test. # This script is intended to be sourced from main test scripts. - +# # Ensure we are in the project root if called directly, # but usually this is sourced and CWD is already project root. # For safety, we can use script location but if sourced $0 might be the parent script. From 22cc3fb1ba340dae8e61526a54edb125eaaa8795 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 29 Jul 2026 09:33:05 -0400 Subject: [PATCH 07/25] fix: harden ad-hoc integration in system.sh against silent failures --- .kokoro/system.sh | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index 073d78c80ef7..d344a948a7f1 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -284,7 +284,8 @@ if [[ -n "${KOKORO_GITHUB_PULL_REQUEST_NUMBER}" ]]; then if [[ -n "${GITHUB_TOKEN:-${GH_TOKEN}}" ]]; then headers+=(-H "Authorization: token ${GITHUB_TOKEN:-${GH_TOKEN}}") fi - LABELS_JSON=$(curl -s "${headers[@]}" "https://api.github.com/repos/googleapis/google-cloud-python/issues/${KOKORO_GITHUB_PULL_REQUEST_NUMBER}/labels") + # Hardened curl call with || true to prevent script termination if network fails + LABELS_JSON=$(curl -s "${headers[@]}" "https://api.github.com/repos/googleapis/google-cloud-python/issues/${KOKORO_GITHUB_PULL_REQUEST_NUMBER}/labels" || echo "[]") # For this prototype: # we use a small inline Python snippet here because parsing JSON in pure Bash is difficult/error-prone, @@ -305,6 +306,8 @@ except Exception: if [[ "$IS_ADHOC" == "true" ]]; then TRIGGER_ADHOC="true" echo "Adhoc test label 'test:adhoc' found!" + else + echo "Adhoc test label not found or error occurred." fi fi @@ -312,19 +315,10 @@ if [[ "$TRIGGER_ADHOC" == "true" ]]; then echo "Running ad-hoc package selection..." source ci/adhoc/adhoc_test_runner.sh - declare -A unique_packages - for pkg in "${PACKAGES_TO_TEST[@]}"; do - unique_packages["$pkg"]=1 - done - - for pkg in $ADHOC_PACKAGES; do - unique_packages["$pkg"]=1 - done - - PACKAGES_TO_TEST=() - for pkg in "${!unique_packages[@]}"; do - PACKAGES_TO_TEST+=("$pkg") - done + echo "Deduplicating packages..." + # Portable deduplication avoiding 'declare -A' (compatible with older Bash) + COMBINED=$(printf "%s\n" "${PACKAGES_TO_TEST[@]}" $ADHOC_PACKAGES | sort -u | grep -v '^$' || true) + PACKAGES_TO_TEST=($COMBINED) echo "Combined packages to test: ${PACKAGES_TO_TEST[*]}" fi From cfe410632e1b798d71df3472fc577bd209bca141 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 29 Jul 2026 10:04:54 -0400 Subject: [PATCH 08/25] chore: add experimental comment to trigger kokoro --- .../cloud/speech_v1/services/speech/client.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py b/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py index 0ac38ec19cdf..4639cae41d8e 100644 --- a/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py +++ b/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py @@ -13,6 +13,16 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# EXPERIMENTAL: This is a temporary change to trigger Kokoro system tests. +# Because Kokoro is currently configured to only watch specific package paths (like packages/google-cloud-speech/.*), +# we must touch a file in one of those paths to wake it up. +# +# This file is GAPIC_AUTO, and this specific file is NOT one of the 5 tracked files (setup.py, etc.) +# in system.sh, so this change will NOT trigger tests for google-cloud-speech itself. +# +# If this ad-hoc testing prototype proves successful, we will update the internal Kokoro +# JobConfigs to watch 'ci/adhoc/.*' instead, eliminating the need for this workaround. + import json import logging as std_logging import os @@ -45,9 +55,8 @@ from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.auth.transport import mtls # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore -from google.oauth2 import service_account # type: ignore - from google.cloud.speech_v1 import gapic_version as package_version +from google.oauth2 import service_account # type: ignore try: OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault, None] @@ -67,9 +76,8 @@ import google.api_core.operation_async as operation_async # type: ignore import google.protobuf.duration_pb2 as duration_pb2 # type: ignore import google.rpc.status_pb2 as status_pb2 # type: ignore -from google.longrunning import operations_pb2 # type: ignore - from google.cloud.speech_v1.types import cloud_speech +from google.longrunning import operations_pb2 # type: ignore from .transports.base import DEFAULT_CLIENT_INFO, SpeechTransport from .transports.grpc import SpeechGrpcTransport From a8b1c61bdb9de2886f3bfb85f476d62485ca7da9 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 29 Jul 2026 13:57:11 -0400 Subject: [PATCH 09/25] chore: replace heavy packages (bigquery, bigtable) with lighter ones in adhoc configs --- ci/adhoc/.package_groups.txt | 2 +- ci/adhoc/.standalone_package_list.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/adhoc/.package_groups.txt b/ci/adhoc/.package_groups.txt index 2ea28bb05dcf..fe24e6ba4c96 100644 --- a/ci/adhoc/.package_groups.txt +++ b/ci/adhoc/.package_groups.txt @@ -1,4 +1,4 @@ -handwritten: google-cloud-bigquery +handwritten: google-cloud-translate handwritten: google-cloud-logging core: google-api-core core: google-cloud-core diff --git a/ci/adhoc/.standalone_package_list.txt b/ci/adhoc/.standalone_package_list.txt index ecbd2dfe04af..31760352449c 100644 --- a/ci/adhoc/.standalone_package_list.txt +++ b/ci/adhoc/.standalone_package_list.txt @@ -1,3 +1,3 @@ package: google-cloud-logging -package: google-cloud-bigtable +package: google-cloud-dns group: handwritten From cbe0b14a9f1ce93955db391c6c58d7aa40f21b77 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 29 Jul 2026 17:24:23 -0400 Subject: [PATCH 10/25] chore: inject intentional failure in google-resumable-media to test ad-hoc behavior --- .../tests/system/requests/test_download.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/google-resumable-media/tests/system/requests/test_download.py b/packages/google-resumable-media/tests/system/requests/test_download.py index f0bd6c7e30e1..5d0a517e9e97 100644 --- a/packages/google-resumable-media/tests/system/requests/test_download.py +++ b/packages/google-resumable-media/tests/system/requests/test_download.py @@ -21,15 +21,13 @@ import google.auth # type: ignore import google.auth.transport.requests as tr_requests # type: ignore -import pytest # type: ignore - -from google.resumable_media import common import google.resumable_media.requests as resumable_requests -from google.resumable_media import _helpers -from google.resumable_media.requests import _request_helpers import google.resumable_media.requests.download as download_mod -from tests.system import utils +import pytest # type: ignore +from google.resumable_media import _helpers, common +from google.resumable_media.requests import _request_helpers +from tests.system import utils CURR_DIR = os.path.dirname(os.path.realpath(__file__)) DATA_DIR = os.path.join(CURR_DIR, "..", "..", "data") @@ -270,6 +268,7 @@ def _read_response_content(response): @pytest.mark.parametrize("checksum", ["md5", "crc32c", None]) def test_download_full(self, add_files, authorized_transport, checksum): + assert False, "Intentional failure to verify ad-hoc testing behavior" for info in ALL_FILES: actual_contents = self._get_contents(info) blob_name = get_blob_name(info) From 2e2f861770547c4f9b99e06ec880accb9ecc0b4a Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 30 Jul 2026 05:07:11 -0400 Subject: [PATCH 11/25] chore: break setup.py in google-resumable-media to guarantee failure --- packages/google-resumable-media/setup.py | 1 + .../tests/system/requests/test_download.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google-resumable-media/setup.py b/packages/google-resumable-media/setup.py index 01466b055f0f..cbac1b35dbd6 100644 --- a/packages/google-resumable-media/setup.py +++ b/packages/google-resumable-media/setup.py @@ -16,6 +16,7 @@ import setuptools +raise RuntimeError("Intentional breakage to verify ad-hoc testing behavior") PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__)) diff --git a/packages/google-resumable-media/tests/system/requests/test_download.py b/packages/google-resumable-media/tests/system/requests/test_download.py index 5d0a517e9e97..260adaa94f9a 100644 --- a/packages/google-resumable-media/tests/system/requests/test_download.py +++ b/packages/google-resumable-media/tests/system/requests/test_download.py @@ -268,7 +268,6 @@ def _read_response_content(response): @pytest.mark.parametrize("checksum", ["md5", "crc32c", None]) def test_download_full(self, add_files, authorized_transport, checksum): - assert False, "Intentional failure to verify ad-hoc testing behavior" for info in ALL_FILES: actual_contents = self._get_contents(info) blob_name = get_blob_name(info) From c007410b4fd73733b0d7b990df69f88ae41cc29c Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 30 Jul 2026 05:12:40 -0400 Subject: [PATCH 12/25] chore: dump logs for passed packages in system.sh for debugging --- .kokoro/system.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index d344a948a7f1..80fc9ce65eb9 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -161,6 +161,7 @@ reap_parallel_results() { fi done + if [ "$failed_count" -gt 0 ]; then echo "==================================================" echo "@FAILED - DETAILED LOGS FOR FAILED PACKAGES" From 6db8c21f76724e98db74dfaf1e21062a9cd3c27e Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 30 Jul 2026 05:22:40 -0400 Subject: [PATCH 13/25] chore: add debug echoes and robustify log dumping in system.sh --- .kokoro/system.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index 80fc9ce65eb9..19fbf83f9c9f 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -162,6 +162,7 @@ reap_parallel_results() { done + if [ "$failed_count" -gt 0 ]; then echo "==================================================" echo "@FAILED - DETAILED LOGS FOR FAILED PACKAGES" @@ -184,6 +185,7 @@ reap_parallel_results() { cat "$LOG_DIR/$pkg.log" else echo "Warning: No log file found for failed package $pkg" + fi echo "" fi @@ -357,11 +359,12 @@ printf '%s\n' "${PACKAGES_TO_TEST[@]}" \ # Determine log location: prefer Sponge artifacts directory if available if [ -n "$KOKORO_ARTIFACTS_DIR" ]; then pkg_log_dir="$KOKORO_ARTIFACTS_DIR/$pkg" - mkdir -p "$pkg_log_dir" || { touch "$LOG_DIR/$pkg.failed"; exit 1; } + mkdir -p "$pkg_log_dir" || { echo "Failed to mkdir $pkg_log_dir"; touch "$LOG_DIR/$pkg.failed"; exit 1; } log_file="$pkg_log_dir/sponge_log.log" else log_file="$LOG_DIR/$pkg.log" fi + echo "Log file for $pkg: $log_file" # Run test; if it fails, create a .failed file to signal failure to the reaper run_package_test "$pkg" > "$log_file" 2>&1 || touch "$LOG_DIR/$pkg.failed" From 86a47f82f07077d6539465f6bbd96e0236a83183 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 30 Jul 2026 05:48:43 -0400 Subject: [PATCH 14/25] fix: simplify argument passing to bash -c in xargs to avoid positional parameter confusion --- .kokoro/system.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index 19fbf83f9c9f..afaf29ae47d6 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -356,6 +356,7 @@ printf '%s\n' "${PACKAGES_TO_TEST[@]}" \ | xargs -n 1 -P "$MAX_JOBS" \ bash -c ' pkg="$0" + # Determine log location: prefer Sponge artifacts directory if available if [ -n "$KOKORO_ARTIFACTS_DIR" ]; then pkg_log_dir="$KOKORO_ARTIFACTS_DIR/$pkg" From f5b002655a0f90485152f48a96d96269aa3bd03f Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Fri, 31 Jul 2026 07:54:47 -0400 Subject: [PATCH 15/25] chore: replace heavy-handed setup.py breakage with a dummy failing test --- packages/google-resumable-media/setup.py | 2 -- .../system/requests/test_dummy_failure.py | 26 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 packages/google-resumable-media/tests/system/requests/test_dummy_failure.py diff --git a/packages/google-resumable-media/setup.py b/packages/google-resumable-media/setup.py index cbac1b35dbd6..372fdac5adc1 100644 --- a/packages/google-resumable-media/setup.py +++ b/packages/google-resumable-media/setup.py @@ -16,8 +16,6 @@ import setuptools -raise RuntimeError("Intentional breakage to verify ad-hoc testing behavior") - PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(PACKAGE_ROOT, 'README.rst')) as file_obj: diff --git a/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py b/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py new file mode 100644 index 000000000000..4d510a694f41 --- /dev/null +++ b/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 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. + +""" +Temporary dummy test to verify ad-hoc testing failure reporting. +This file is for experimentation/prototyping only and will be removed before merge. +""" + +import pytest + + +def test_intentional_failure(): + """Intentional failure to verify CI output formatting.""" + assert False, "Intentional failure to verify ad-hoc testing behavior" From e5b4ddbc3d1e0bad33d2338f8cc8f7fbf357b9e2 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Fri, 31 Jul 2026 07:59:50 -0400 Subject: [PATCH 16/25] fix: remove unused pytest import to satisfy linter --- .../tests/system/requests/test_dummy_failure.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py b/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py index 4d510a694f41..005c4b4e4792 100644 --- a/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py +++ b/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py @@ -18,7 +18,6 @@ This file is for experimentation/prototyping only and will be removed before merge. """ -import pytest def test_intentional_failure(): From d43fcdd8d79ffb64558ba39492b7a99e07bb46dd Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Mon, 3 Aug 2026 06:27:58 -0400 Subject: [PATCH 17/25] feat: use associative arrays for package deduplication (matches design doc) --- .kokoro/system.sh | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index afaf29ae47d6..4e47a335a593 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -319,9 +319,19 @@ if [[ "$TRIGGER_ADHOC" == "true" ]]; then source ci/adhoc/adhoc_test_runner.sh echo "Deduplicating packages..." - # Portable deduplication avoiding 'declare -A' (compatible with older Bash) - COMBINED=$(printf "%s\n" "${PACKAGES_TO_TEST[@]}" $ADHOC_PACKAGES | sort -u | grep -v '^$' || true) - PACKAGES_TO_TEST=($COMBINED) + # Deduplication using Associative Arrays (Requires Bash 4+) + declare -A unique_packages + for pkg in "${PACKAGES_TO_TEST[@]}"; do + unique_packages["$pkg"]=1 + done + for pkg in $ADHOC_PACKAGES; do + unique_packages["$pkg"]=1 + done + + # Remove empty string key if any + unset 'unique_packages[""]' + + PACKAGES_TO_TEST=("${!unique_packages[@]}") echo "Combined packages to test: ${PACKAGES_TO_TEST[*]}" fi From 2b1ce7438e1bbb9ac750b985fedefa06c4eb1fac Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Mon, 3 Aug 2026 06:45:35 -0400 Subject: [PATCH 18/25] docs: clarify experimental comments in dummy test and speech client --- .../google/cloud/speech_v1/services/speech/client.py | 2 +- .../tests/system/requests/test_dummy_failure.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py b/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py index 4639cae41d8e..5ffac70baa9a 100644 --- a/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py +++ b/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py @@ -18,7 +18,7 @@ # we must touch a file in one of those paths to wake it up. # # This file is GAPIC_AUTO, and this specific file is NOT one of the 5 tracked files (setup.py, etc.) -# in system.sh, so this change will NOT trigger tests for google-cloud-speech itself. +# in system.sh, so this change will NOT launch google-cloud-speech's tests. # # If this ad-hoc testing prototype proves successful, we will update the internal Kokoro # JobConfigs to watch 'ci/adhoc/.*' instead, eliminating the need for this workaround. diff --git a/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py b/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py index 005c4b4e4792..ede44e31f441 100644 --- a/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py +++ b/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py @@ -16,6 +16,7 @@ """ Temporary dummy test to verify ad-hoc testing failure reporting. This file is for experimentation/prototyping only and will be removed before merge. +We are using this to test packages that have legit changes (i.e. they would show up in `package_diff` naturally AND would have failing tests. """ From c61d727c411e1cb40a4c242acdfdca6d7489490e Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Mon, 3 Aug 2026 07:10:20 -0400 Subject: [PATCH 19/25] chore: add debug echoes and robustify xargs in system.sh --- .kokoro/system.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index 4e47a335a593..b2a4f40734b2 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -18,6 +18,8 @@ # or zero if all commands in the pipeline exit successfully. set -eo pipefail +echo "=== STARTING SYSTEM.SH ===" + # Disable buffering, so that the logs stream through. export PYTHONUNBUFFERED=1 @@ -362,8 +364,8 @@ export system_test_script PROJECT_ROOT KOKORO_GFILE_DIR # Stream package names to xargs for parallel execution # -P "$MAX_JOBS" controls concurrency # -I {} replaces {} with the package name -printf '%s\n' "${PACKAGES_TO_TEST[@]}" \ - | xargs -n 1 -P "$MAX_JOBS" \ +printf '%s\0' "${PACKAGES_TO_TEST[@]}" \ + | xargs -0 -n 1 -P "$MAX_JOBS" \ bash -c ' pkg="$0" From e10353e0e5c86d129b2b4f31a8a55e10ebb0937c Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Mon, 3 Aug 2026 07:19:08 -0400 Subject: [PATCH 20/25] fix: resolve lint errors and harden array handling in system.sh --- .kokoro/system.sh | 7 ++----- .../tests/system/requests/test_dummy_failure.py | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index b2a4f40734b2..70a0a184e1d3 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -324,15 +324,12 @@ if [[ "$TRIGGER_ADHOC" == "true" ]]; then # Deduplication using Associative Arrays (Requires Bash 4+) declare -A unique_packages for pkg in "${PACKAGES_TO_TEST[@]}"; do - unique_packages["$pkg"]=1 + [[ -n "$pkg" ]] && unique_packages["$pkg"]=1 done for pkg in $ADHOC_PACKAGES; do - unique_packages["$pkg"]=1 + [[ -n "$pkg" ]] && unique_packages["$pkg"]=1 done - # Remove empty string key if any - unset 'unique_packages[""]' - PACKAGES_TO_TEST=("${!unique_packages[@]}") echo "Combined packages to test: ${PACKAGES_TO_TEST[*]}" diff --git a/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py b/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py index ede44e31f441..7ba7d5d43dd5 100644 --- a/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py +++ b/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py @@ -20,7 +20,6 @@ """ - def test_intentional_failure(): """Intentional failure to verify CI output formatting.""" assert False, "Intentional failure to verify ad-hoc testing behavior" From c2fa46beea042db9623c9ab8e612b7579b53a54e Mon Sep 17 00:00:00 2001 From: Chalmer Lowe Date: Mon, 3 Aug 2026 14:38:28 -0400 Subject: [PATCH 21/25] Update .kokoro/system.sh --- .kokoro/system.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index 70a0a184e1d3..309c612410c1 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -18,8 +18,6 @@ # or zero if all commands in the pipeline exit successfully. set -eo pipefail -echo "=== STARTING SYSTEM.SH ===" - # Disable buffering, so that the logs stream through. export PYTHONUNBUFFERED=1 From 26cc68ba9cfa1c528d454203967982cc05656ab9 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 4 Aug 2026 06:13:42 -0400 Subject: [PATCH 22/25] chore(ci): add copyright and improve error handling for adhoc tests --- .kokoro/system.sh | 31 +++++++++++++++---------------- ci/adhoc/adhoc_test_runner.sh | 13 +++++++++++++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.kokoro/system.sh b/.kokoro/system.sh index 309c612410c1..1baaa22c2f4b 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -290,28 +290,27 @@ if [[ -n "${KOKORO_GITHUB_PULL_REQUEST_NUMBER}" ]]; then # Hardened curl call with || true to prevent script termination if network fails LABELS_JSON=$(curl -s "${headers[@]}" "https://api.github.com/repos/googleapis/google-cloud-python/issues/${KOKORO_GITHUB_PULL_REQUEST_NUMBER}/labels" || echo "[]") - # For this prototype: - # we use a small inline Python snippet here because parsing JSON in pure Bash is difficult/error-prone, - # and we cannot guarantee that tools like 'jq' or 'gh' are installed in the test environment. - # Python and its built-in 'json' module are guaranteed to be available in this repository. - IS_ADHOC=$(python3 -c " -import json -import sys -try: - labels = json.loads(sys.argv[1]) - if isinstance(labels, list): - if any(isinstance(l, dict) and l.get('name') == 'test:adhoc' for l in labels): - print('true') -except Exception: - pass -" "$LABELS_JSON") + # Use jq to parse github labels (works as long as jq is available in python-multi image). + IS_ADHOC=$(echo "$LABELS_JSON" | jq -r 'if type == "array" then any(.name == "test:adhoc") else false end' 2>/dev/null) + if [[ "$IS_ADHOC" == "true" ]]; then TRIGGER_ADHOC="true" echo "Adhoc test label 'test:adhoc' found!" else - echo "Adhoc test label not found or error occurred." + if [[ "$LABELS_JSON" != "["* ]]; then + API_ERR_MSG=$(echo "$LABELS_JSON" | jq -r '.message // "Unknown error"' 2>/dev/null) + echo "================================================================" + echo "WARNING: Failed to fetch PR labels from GitHub API!" + echo "Error Message: $API_ERR_MSG" + echo "This might be due to API Rate Limiting." + echo "Ad-hoc tests will NOT be triggered." + echo "================================================================" + else + echo "Adhoc test label 'test:adhoc' not found." + fi fi + fi if [[ "$TRIGGER_ADHOC" == "true" ]]; then diff --git a/ci/adhoc/adhoc_test_runner.sh b/ci/adhoc/adhoc_test_runner.sh index a7e0c10f880b..27002161e427 100755 --- a/ci/adhoc/adhoc_test_runner.sh +++ b/ci/adhoc/adhoc_test_runner.sh @@ -1,4 +1,17 @@ #!/bin/bash +# Copyright 2026 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 +# +# https://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. # Script to determine ad-hoc packages to test. # This script is intended to be sourced from main test scripts. From 21c8cd925b6ea1873a0e29a68a1f11170f0e873c Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 4 Aug 2026 06:58:00 -0400 Subject: [PATCH 23/25] chore(ci): clarify precondition in adhoc test runner --- ci/adhoc/adhoc_test_runner.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ci/adhoc/adhoc_test_runner.sh b/ci/adhoc/adhoc_test_runner.sh index 27002161e427..a0a3d3b15e0f 100755 --- a/ci/adhoc/adhoc_test_runner.sh +++ b/ci/adhoc/adhoc_test_runner.sh @@ -16,10 +16,8 @@ # Script to determine ad-hoc packages to test. # This script is intended to be sourced from main test scripts. # -# Ensure we are in the project root if called directly, -# but usually this is sourced and CWD is already project root. -# For safety, we can use script location but if sourced $0 might be the parent script. -# Let's assume CWD is project root as per system.sh behavior. +# Precondition: This script assumes it is sourced from the project root (as set by system.sh). + ADHOC_DIR="ci/adhoc" STANDALONE_LIST="${ADHOC_DIR}/.standalone_package_list.txt" From d10e510fece89c08e8d1e73056bd0f618a849b66 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 4 Aug 2026 11:51:49 -0400 Subject: [PATCH 24/25] chore: remove temporary testing artifacts and apply hardening suggestions --- .kokoro/system.sh | 45 ++++++++++--------- ci/adhoc/adhoc_test_runner.sh | 7 ++- .../cloud/speech_v1/services/speech/client.py | 16 ++----- packages/google-resumable-media/setup.py | 1 + .../tests/system/requests/test_download.py | 10 +++-- .../system/requests/test_dummy_failure.py | 25 ----------- 6 files changed, 38 insertions(+), 66 deletions(-) delete mode 100644 packages/google-resumable-media/tests/system/requests/test_dummy_failure.py diff --git a/.kokoro/system.sh b/.kokoro/system.sh index 1baaa22c2f4b..e99efcc76b3d 100755 --- a/.kokoro/system.sh +++ b/.kokoro/system.sh @@ -287,30 +287,33 @@ if [[ -n "${KOKORO_GITHUB_PULL_REQUEST_NUMBER}" ]]; then if [[ -n "${GITHUB_TOKEN:-${GH_TOKEN}}" ]]; then headers+=(-H "Authorization: token ${GITHUB_TOKEN:-${GH_TOKEN}}") fi - # Hardened curl call with || true to prevent script termination if network fails - LABELS_JSON=$(curl -s "${headers[@]}" "https://api.github.com/repos/googleapis/google-cloud-python/issues/${KOKORO_GITHUB_PULL_REQUEST_NUMBER}/labels" || echo "[]") - - # Use jq to parse github labels (works as long as jq is available in python-multi image). - IS_ADHOC=$(echo "$LABELS_JSON" | jq -r 'if type == "array" then any(.name == "test:adhoc") else false end' 2>/dev/null) - - - if [[ "$IS_ADHOC" == "true" ]]; then - TRIGGER_ADHOC="true" - echo "Adhoc test label 'test:adhoc' found!" + # Fetch PR labels from GitHub API, handling connection failures gracefully + if ! LABELS_JSON=$(curl -s "${headers[@]}" "https://api.github.com/repos/googleapis/google-cloud-python/issues/${KOKORO_GITHUB_PULL_REQUEST_NUMBER}/labels"); then + echo "===============================================================" + echo "WARNING: Failed to connect to GitHub API!" + echo "Ad-hoc tests will NOT be triggered." + echo "===============================================================" else - if [[ "$LABELS_JSON" != "["* ]]; then - API_ERR_MSG=$(echo "$LABELS_JSON" | jq -r '.message // "Unknown error"' 2>/dev/null) - echo "================================================================" - echo "WARNING: Failed to fetch PR labels from GitHub API!" - echo "Error Message: $API_ERR_MSG" - echo "This might be due to API Rate Limiting." - echo "Ad-hoc tests will NOT be triggered." - echo "================================================================" + # Use jq to parse github labels (works as long as jq is available in python-multi image). + IS_ADHOC=$(echo "$LABELS_JSON" | jq -r 'if type == "array" then any(.name == "test:adhoc") else false end' 2>/dev/null) + + if [[ "$IS_ADHOC" == "true" ]]; then + TRIGGER_ADHOC="true" + echo "Adhoc test label 'test:adhoc' found!" else - echo "Adhoc test label 'test:adhoc' not found." + if [[ "$LABELS_JSON" != "["* ]]; then + API_ERR_MSG=$(echo "$LABELS_JSON" | jq -r '.message // "Unknown error"' 2>/dev/null) + echo "===============================================================" + echo "WARNING: Failed to fetch PR labels from GitHub API!" + echo "Error Message: $API_ERR_MSG" + echo "This might be due to API Rate Limiting." + echo "Ad-hoc tests will NOT be triggered." + echo "===============================================================" + else + echo "Adhoc test label 'test:adhoc' not found." + fi fi fi - fi if [[ "$TRIGGER_ADHOC" == "true" ]]; then @@ -358,7 +361,7 @@ export system_test_script PROJECT_ROOT KOKORO_GFILE_DIR # Stream package names to xargs for parallel execution # -P "$MAX_JOBS" controls concurrency # -I {} replaces {} with the package name -printf '%s\0' "${PACKAGES_TO_TEST[@]}" \ +[ ${#PACKAGES_TO_TEST[@]} -eq 0 ] || printf '%s\0' "${PACKAGES_TO_TEST[@]}" \ | xargs -0 -n 1 -P "$MAX_JOBS" \ bash -c ' pkg="$0" diff --git a/ci/adhoc/adhoc_test_runner.sh b/ci/adhoc/adhoc_test_runner.sh index a0a3d3b15e0f..50f9943fc222 100755 --- a/ci/adhoc/adhoc_test_runner.sh +++ b/ci/adhoc/adhoc_test_runner.sh @@ -18,7 +18,6 @@ # # Precondition: This script assumes it is sourced from the project root (as set by system.sh). - ADHOC_DIR="ci/adhoc" STANDALONE_LIST="${ADHOC_DIR}/.standalone_package_list.txt" GROUPS_FILE="${ADHOC_DIR}/.package_groups.txt" @@ -34,14 +33,14 @@ if [[ ! -f "$GROUPS_FILE" ]]; then fi # Grab individual packages -adhoc_packages=$(grep "^package:" "$STANDALONE_LIST" | cut -d':' -f2 | xargs || true) +adhoc_packages=$(grep "^package:" "$STANDALONE_LIST" | cut -d':' -f2 | tr -d '\r' | xargs || true) # Grab requested groups -requested_groups=$(grep "^group:" "$STANDALONE_LIST" | cut -d':' -f2 | xargs || true) +requested_groups=$(grep "^group:" "$STANDALONE_LIST" | cut -d':' -f2 | tr -d '\r' | xargs || true) # Expand groups for group in $requested_groups; do - group_pkgs=$(grep "^$group:" "$GROUPS_FILE" | cut -d':' -f2 | xargs || true) + group_pkgs=$(grep "^$group:" "$GROUPS_FILE" | cut -d':' -f2 | tr -d '\r' | xargs || true) adhoc_packages="$adhoc_packages $group_pkgs" done diff --git a/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py b/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py index 5ffac70baa9a..0ac38ec19cdf 100644 --- a/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py +++ b/packages/google-cloud-speech/google/cloud/speech_v1/services/speech/client.py @@ -13,16 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# EXPERIMENTAL: This is a temporary change to trigger Kokoro system tests. -# Because Kokoro is currently configured to only watch specific package paths (like packages/google-cloud-speech/.*), -# we must touch a file in one of those paths to wake it up. -# -# This file is GAPIC_AUTO, and this specific file is NOT one of the 5 tracked files (setup.py, etc.) -# in system.sh, so this change will NOT launch google-cloud-speech's tests. -# -# If this ad-hoc testing prototype proves successful, we will update the internal Kokoro -# JobConfigs to watch 'ci/adhoc/.*' instead, eliminating the need for this workaround. - import json import logging as std_logging import os @@ -55,9 +45,10 @@ from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.auth.transport import mtls # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore -from google.cloud.speech_v1 import gapic_version as package_version from google.oauth2 import service_account # type: ignore +from google.cloud.speech_v1 import gapic_version as package_version + try: OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault, None] except AttributeError: # pragma: NO COVER @@ -76,9 +67,10 @@ import google.api_core.operation_async as operation_async # type: ignore import google.protobuf.duration_pb2 as duration_pb2 # type: ignore import google.rpc.status_pb2 as status_pb2 # type: ignore -from google.cloud.speech_v1.types import cloud_speech from google.longrunning import operations_pb2 # type: ignore +from google.cloud.speech_v1.types import cloud_speech + from .transports.base import DEFAULT_CLIENT_INFO, SpeechTransport from .transports.grpc import SpeechGrpcTransport from .transports.grpc_asyncio import SpeechGrpcAsyncIOTransport diff --git a/packages/google-resumable-media/setup.py b/packages/google-resumable-media/setup.py index 372fdac5adc1..01466b055f0f 100644 --- a/packages/google-resumable-media/setup.py +++ b/packages/google-resumable-media/setup.py @@ -16,6 +16,7 @@ import setuptools + PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(PACKAGE_ROOT, 'README.rst')) as file_obj: diff --git a/packages/google-resumable-media/tests/system/requests/test_download.py b/packages/google-resumable-media/tests/system/requests/test_download.py index 260adaa94f9a..f0bd6c7e30e1 100644 --- a/packages/google-resumable-media/tests/system/requests/test_download.py +++ b/packages/google-resumable-media/tests/system/requests/test_download.py @@ -21,14 +21,16 @@ import google.auth # type: ignore import google.auth.transport.requests as tr_requests # type: ignore -import google.resumable_media.requests as resumable_requests -import google.resumable_media.requests.download as download_mod import pytest # type: ignore -from google.resumable_media import _helpers, common -from google.resumable_media.requests import _request_helpers +from google.resumable_media import common +import google.resumable_media.requests as resumable_requests +from google.resumable_media import _helpers +from google.resumable_media.requests import _request_helpers +import google.resumable_media.requests.download as download_mod from tests.system import utils + CURR_DIR = os.path.dirname(os.path.realpath(__file__)) DATA_DIR = os.path.join(CURR_DIR, "..", "..", "data") PLAIN_TEXT = "text/plain" diff --git a/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py b/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py deleted file mode 100644 index 7ba7d5d43dd5..000000000000 --- a/packages/google-resumable-media/tests/system/requests/test_dummy_failure.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2026 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. - -""" -Temporary dummy test to verify ad-hoc testing failure reporting. -This file is for experimentation/prototyping only and will be removed before merge. -We are using this to test packages that have legit changes (i.e. they would show up in `package_diff` naturally AND would have failing tests. -""" - - -def test_intentional_failure(): - """Intentional failure to verify CI output formatting.""" - assert False, "Intentional failure to verify ad-hoc testing behavior" From 1a70dacc58a02b423cada980a96328992e9d29bf Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 4 Aug 2026 12:35:16 -0400 Subject: [PATCH 25/25] docs: update README.md with detailed use cases and usage instructions --- ci/adhoc/README.md | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 ci/adhoc/README.md diff --git a/ci/adhoc/README.md b/ci/adhoc/README.md new file mode 100644 index 000000000000..dec40a0b4d2f --- /dev/null +++ b/ci/adhoc/README.md @@ -0,0 +1,47 @@ +# Ad-Hoc Package Testing + +## Overview +Ad-hoc package testing allows you to run CI tests for a specific subset of packages or predefined package groups without the need for intrusive and/or temporary mods to the package code to trigger a CI job run. Key use cases include: + +* **Downstream Dependency Smoke Tests:** If you update a core library (like `google-api-core`), the diff detector only sees the core library. Ad-hoc lets you explicitly include major downstream consumers (like `storage`) to verify compatibility. +* **Debugging specific package failures:** If you want to look at just one OR two failing packages out of a larger group of failing packages, it can be helpful to run them in isolation in a separate PR (so that your prospective changes don't have to wait on all the other packages). This allows you to easily flag which packages you want to investigate by potentially starting with a baseline test with no changes (i.e. does this fail due to an externality OR due to a change in the code)? +* **Testing CI infrastructure updates:** If you are changing `.kokoro/system.sh` or root scripts, the standard diff detector won't trigger tests because no package folders changed. Ad-hoc allows you to test your CI scripts using a single lightweight package without polluting package code with dummy comments. + +## How It Works +The ad-hoc testing system reads configuration files in the `ci/adhoc/` directory to determine which packages to test. It is triggered via the `test:adhoc` GitHub label on Pull Requests. + +When triggered, the ad-hoc selected packages are **merged** with any packages automatically detected by the CI system (e.g., packages modified in the current PR). The final combined list is automatically deduplicated, ensuring each package is tested only once. + +## Configuration Files + +These files are located in the `ci/adhoc/` directory. + +### 1. `.standalone_package_list.txt` +This file lists the specific packages or groups you want to test. + +* **To test an individual package:** Add a line starting with `package: ` (be sure to include the colon and space) followed by the package directory name. + * *Example:* `package: google-cloud-dns` +* **To test a group of packages:** Add a line starting with `group: ` (be sure to include the colon and space) followed by the group name. NOTE: groups are defined in the file: `.package_groups.txt` + * *Example:* `group: handwritten` + +### 2. `.package_groups.txt` +This file defines groups of commonly tested packages for convenience of the team. Groups such as all handwritten, all core, all hybrids, most widely used, etc. can be defined here. + +* **Format:** Each package in a group should be on its own line, prefixed by the group name, colon, and a space. + * *Example:* + ```text + handwritten: google-cloud-translate + handwritten: google-cloud-logging + core: google-api-core + ``` + +#### 💡 Pro Tip +You can mix packages and groups in `.standalone_package_list.txt`. The system will automatically expand groups and deduplicate the list! + +## Usage + +1. **Edit Configuration:** Open `ci/adhoc/.standalone_package_list.txt` and add the packages or groups you want to test. +2. **Trigger Tests:** + * **New PR:** Commit the changes and open a Pull Request form. + * **Activate Label:** Add the `test:adhoc` label to your PR form in the GitHub UI. If you miss this step, simply applying the label won't magically launch the tests the way `kokoro-force-run` does. The label is only checked when a commit is detected. + * **Existing PR:** Commit and push the changes to your branch. If the label is already present, pushing a new commit will trigger the tests.