Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b23b281
feat: implement ad-hoc package selection for CI/CD
chalmerlowe Jul 29, 2026
e8baccc
docs: add comment explaining inline python usage in system.sh
chalmerlowe Jul 29, 2026
85d0855
docs: tweak comment explaining inline python usage
chalmerlowe Jul 29, 2026
56576b9
fix: make grep commands safe and quote variables in adhoc_test_runner.sh
chalmerlowe Jul 29, 2026
43800e2
fix: add auth token to curl and harden inline python in system.sh
chalmerlowe Jul 29, 2026
69bb3ce
Apply suggestion from @chalmerlowe
chalmerlowe Jul 29, 2026
22cc3fb
fix: harden ad-hoc integration in system.sh against silent failures
chalmerlowe Jul 29, 2026
cfe4106
chore: add experimental comment to trigger kokoro
chalmerlowe Jul 29, 2026
a8b1c61
chore: replace heavy packages (bigquery, bigtable) with lighter ones …
chalmerlowe Jul 29, 2026
cbe0b14
chore: inject intentional failure in google-resumable-media to test a…
chalmerlowe Jul 29, 2026
2e2f861
chore: break setup.py in google-resumable-media to guarantee failure
chalmerlowe Jul 30, 2026
c007410
chore: dump logs for passed packages in system.sh for debugging
chalmerlowe Jul 30, 2026
6db8c21
chore: add debug echoes and robustify log dumping in system.sh
chalmerlowe Jul 30, 2026
86a47f8
fix: simplify argument passing to bash -c in xargs to avoid positiona…
chalmerlowe Jul 30, 2026
f5b0026
chore: replace heavy-handed setup.py breakage with a dummy failing test
chalmerlowe Jul 31, 2026
e5b4ddb
fix: remove unused pytest import to satisfy linter
chalmerlowe Jul 31, 2026
d43fcdd
feat: use associative arrays for package deduplication (matches desig…
chalmerlowe Aug 3, 2026
2b1ce74
docs: clarify experimental comments in dummy test and speech client
chalmerlowe Aug 3, 2026
c61d727
chore: add debug echoes and robustify xargs in system.sh
chalmerlowe Aug 3, 2026
e10353e
fix: resolve lint errors and harden array handling in system.sh
chalmerlowe Aug 3, 2026
c2fa46b
Update .kokoro/system.sh
chalmerlowe Aug 3, 2026
26cc68b
chore(ci): add copyright and improve error handling for adhoc tests
chalmerlowe Aug 4, 2026
21c8cd9
chore(ci): clarify precondition in adhoc test runner
chalmerlowe Aug 4, 2026
d10e510
chore: remove temporary testing artifacts and apply hardening suggest…
chalmerlowe Aug 4, 2026
1a70dac
docs: update README.md with detailed use cases and usage instructions
chalmerlowe Aug 4, 2026
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
68 changes: 65 additions & 3 deletions .kokoro/system.sh
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ reap_parallel_results() {
fi
done



if [ "$failed_count" -gt 0 ]; then
echo "=================================================="
echo "@FAILED - DETAILED LOGS FOR FAILED PACKAGES"
Expand All @@ -183,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
Expand Down Expand Up @@ -276,6 +279,63 @@ 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}..."
headers=(-H "User-Agent: Kokoro")
if [[ -n "${GITHUB_TOKEN:-${GH_TOKEN}}" ]]; then
headers+=(-H "Authorization: token ${GITHUB_TOKEN:-${GH_TOKEN}}")
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is the GitHub token already being populated in kokoro? Or is this a new secret we need to add for this feature?

@chalmerlowe chalmerlowe Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

GITHUB_TOKEN is not yet populated in kokoro but kokoro is set up to inject them if/when any GITHUB tokens are provided in SECRET MANAGER in Google Cloud Console.

This PR and the ad hoc label succeeds because we are currently relying on the fact that GitHub allows 60 unauthorized API calls from a single IP per hour.

We have no way to know if others in the firm will be in a kokoro instance behind the same IP and calling github. So it in our long-term best interest to add the token to SECRET MANAGER. Completion of that task is not required for this PR to be merged.

This Issue tracks this limitation.

:EX:

# 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
# 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
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
echo "Running ad-hoc package selection..."
source ci/adhoc/adhoc_test_runner.sh

echo "Deduplicating packages..."
# Deduplication using Associative Arrays (Requires Bash 4+)
declare -A unique_packages
for pkg in "${PACKAGES_TO_TEST[@]}"; do
[[ -n "$pkg" ]] && unique_packages["$pkg"]=1
done
for pkg in $ADHOC_PACKAGES; do
[[ -n "$pkg" ]] && unique_packages["$pkg"]=1
done

PACKAGES_TO_TEST=("${!unique_packages[@]}")

echo "Combined packages to test: ${PACKAGES_TO_TEST[*]}"
fi
# --- End Ad-hoc Testing Integration ---

# Parallel Execution Logic
MAX_JOBS=${MAX_JOBS:-4}

Expand All @@ -301,18 +361,20 @@ 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" \
[ ${#PACKAGES_TO_TEST[@]} -eq 0 ] || printf '%s\0' "${PACKAGES_TO_TEST[@]}" \
| xargs -0 -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"
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"
Expand Down
4 changes: 4 additions & 0 deletions ci/adhoc/.package_groups.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
handwritten: google-cloud-translate
handwritten: google-cloud-logging
core: google-api-core
core: google-cloud-core
3 changes: 3 additions & 0 deletions ci/adhoc/.standalone_package_list.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package: google-cloud-logging
package: google-cloud-dns
group: handwritten
47 changes: 47 additions & 0 deletions ci/adhoc/README.md
Original file line number Diff line number Diff line change
@@ -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.
50 changes: 50 additions & 0 deletions ci/adhoc/adhoc_test_runner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/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.

Comment thread
chalmerlowe marked this conversation as resolved.
# Script to determine ad-hoc packages to test.
# This script is intended to be sourced from main test scripts.
#
# Precondition: This script assumes it is sourced from the project root (as set by system.sh).

Comment thread
chalmerlowe marked this conversation as resolved.
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 | tr -d '\r' | xargs || true)

# Grab requested groups
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 | tr -d '\r' | 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)

export ADHOC_PACKAGES
Loading