Skip to content

Merge branch 'main' into add-testing-315 #18064

Merge branch 'main' into add-testing-315

Merge branch 'main' into add-testing-315 #18064

Workflow file for this run

on:

Check failure on line 1 in .github/workflows/unittest.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/unittest.yml

Invalid workflow file

(Line: 113, Col: 7): There's not enough info to determine what you meant. Add one of these properties: cancel, run, shell, uses, wait, wait-all, with, working-directory
pull_request:
branches:
- main
- preview
# Trigger workflow on GitHub merge queue events
# See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#merge_group
merge_group:
types: [checks_requested]
name: unittest
permissions:
contents: read
env:
PACKAGE_DIRS: packages preview-packages
NOX_REUSE_EXISTING_VIRTUALENVS: "true"
NOX_ENVDIR: "/tmp/shared_nox_envs"
NOX_DEFAULT_VENV_BACKEND: "uv"
UV_VENV_SEED: "1"
# Note: PARALLEL_WORKERS must remain "1" for unit tests because running pytest concurrently
# on the same runner VM can cause socket/IPC/process deadlocks across packages.
PARALLEL_WORKERS: "1"
jobs:
initialize:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
is_full_run: ${{ steps.check-label.outputs.is_full_run }}
env:
MAX_SHARDS: 16
# Define weights for long-running unit tests to balance shard execution time
# Each weight is roughly 1 minute of expected execution time
# Default for unset packages is 1
PACKAGE_WEIGHTS: |
bigframes: 6
google-ai-generativelanguage: 4
google-auth: 5
google-cloud-compute: 12
google-cloud-compute-v1beta: 12
google-cloud-dialogflow: 6
google-cloud-dialogflow-cx: 6
google-cloud-discoveryengine: 8
google-cloud-retail: 5
google-shopping-merchant-accounts: 4
steps:
- name: Checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 2
persist-credentials: false
- name: Check for unit_test:all_packages label
id: check-label
run: |
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'unit_test:all_packages') }}" == "true" ]]; then
echo "is_full_run=true" >> $GITHUB_OUTPUT
else
echo "is_full_run=false" >> $GITHUB_OUTPUT
fi
- name: Setup Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.10"
- name: Get package shards
id: set-matrix
env:
BUILD_TYPE: presubmit
TARGET_BRANCH: ${{ github.base_ref || github.event.merge_group.base_ref }}
TEST_ALL_PACKAGES: ${{ steps.check-label.outputs.is_full_run }}
MAX_SHARDS: ${{ env.MAX_SHARDS }}
PACKAGE_WEIGHTS: ${{ env.PACKAGE_WEIGHTS }}
run: |
if [ -n "$TARGET_BRANCH" ]; then
git fetch origin "$TARGET_BRANCH" --depth=1 || true
fi
python3 ci/get_package_shards.py
unit:
needs: initialize
if: needs.initialize.outputs.matrix != '[]' && needs.initialize.outputs.matrix != ''
runs-on: ubuntu-22.04
strategy:
fail-fast: true
matrix:
python: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
package_shard: ${{ fromJson(needs.initialize.outputs.matrix) }}
name: ${{ matrix.package_shard.is_sharded && format('unit ({0}, {1})', matrix.python, matrix.package_shard.name) || format('unit ({0})', matrix.python) }}
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# Use a fetch-depth of 2 to avoid error `fatal: origin/main...HEAD: no merge base`
# See https://github.com/googleapis/google-cloud-python/issues/12013
# and https://github.com/actions/checkout#checkout-head.
with:
fetch-depth: 2
persist-credentials: false
- name: Setup Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: ${{ matrix.python }}
cache: 'pip'
allow-prereleases: true
- name: Setup uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
cache-dependency-glob: 'packages/**/testing/constraints*.txt'
- name: Install nox
run: |
python -m pip install --upgrade setuptools pip wheel
python -m pip install nox
- name: Run unit tests
uv pip install --system nox nox-uv
# Caches compiled wheels locally to prevent building heavy libraries
# such as grpcio, which we build from scratch on every run for Python 3.15+.
# Follow https://github.com/grpc/grpc/issues/41010 for updates.
- name: Cache Built Python 3.15 Wheels
if: matrix.python == '3.15'
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .uv-wheel-cache
key: ${{ runner.os }}-uv-wheels-3.15-${{ hashFiles('packages/**/testing/constraints*.txt') }}
restore-keys: |
${{ runner.os }}-uv-wheels-3.15-
# Pre-cache heavy dependencies sequentially before running parallel tests
- name: Pre-cache heavy dependencies (grpcio)
if: matrix.python == '3.15'
run: |
# Create the directory so uv doesn't crash if there is a `cache miss`
mkdir -p .uv-wheel-cache
# Download and compile grpcio sequentially so that parallel test workers
# immediately hit the warm cache instead of deadlocking on compilation.
uv pip install --system grpcio --find-links .uv-wheel-cache
- name: Run unit tests for ${{ matrix.package_shard.description }}
env:
BUILD_TYPE: presubmit
TARGET_BRANCH: ${{ github.base_ref || github.event.merge_group.base_ref }}
TEST_TYPE: unit
PY_VERSION: ${{ matrix.python }}
PACKAGE_LIST: ${{ matrix.package_shard.packages }}
run: |
ci/run_conditional_tests.sh
- name: Upload coverage results
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: coverage-artifact-${{ matrix.python }}-${{ matrix.package_shard.index }}
path: .coverage.${{ matrix.python }}.*
include-hidden-files: true
all-tests:
needs: [initialize, unit]
if: always()
runs-on: ubuntu-latest
steps:
- name: Check unit test results
run: |
# 1. Check initialize job
if [[ "${{ needs.initialize.result }}" != "success" ]]; then
echo "Error: The initialize job status was: ${{ needs.initialize.result }}"
exit 1
fi
# 2. Check unit test shards
if [[ "${{ needs.unit.result }}" != "success" && "${{ needs.unit.result }}" != "skipped" ]]; then
echo "Unit tests failed"
exit 1
fi
echo "All unit tests passed or were skipped"
cover:
if: always() && !cancelled() && needs.all-tests.result == 'success'
runs-on: ubuntu-latest
needs:
- all-tests
- initialize
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
# Use a fetch-depth of 2 to avoid error `fatal: origin/main...HEAD: no merge base`
# See https://github.com/googleapis/google-cloud-python/issues/12013
# and https://github.com/actions/checkout#checkout-head.
with:
fetch-depth: 2
persist-credentials: false
- name: Setup Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.10"
- name: Determine if coverage evaluation is required
id: packages
env:
TEST_ALL_PACKAGES: ${{ needs.initialize.outputs.is_full_run }}
TARGET_BRANCH: ${{ github.base_ref || github.event.merge_group.base_ref }}
run: |
if [[ "${TEST_ALL_PACKAGES}" == "true" ]]; then
echo "should_evaluate_coverage=true" >> "$GITHUB_OUTPUT"
else
TARGET_BRANCH="${TARGET_BRANCH:-main}"
git fetch origin "$TARGET_BRANCH" --depth=1 || true
num_files_changed=$(git diff --name-only "origin/${TARGET_BRANCH}" -- ${PACKAGE_DIRS} | wc -l | tr -d ' ')
if [[ "${num_files_changed}" -gt 0 ]]; then
echo "should_evaluate_coverage=true" >> "$GITHUB_OUTPUT"
else
echo "should_evaluate_coverage=false" >> "$GITHUB_OUTPUT"
fi
fi
- name: Install coverage
if: ${{ steps.packages.outputs.should_evaluate_coverage == 'true' }}
run: |
python -m pip install --upgrade setuptools pip wheel
python -m pip install coverage
- name: Download coverage results
if: ${{ steps.packages.outputs.should_evaluate_coverage == 'true' }}
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
with:
path: /dev/shm/.coverage-results/
merge-multiple: true
- name: Report coverage results
if: ${{ steps.packages.outputs.should_evaluate_coverage == 'true' }}
env:
# TODO: default to 100% coverage after next gapic-generator release
# https://github.com/googleapis/google-cloud-python/issues/17459
DEFAULT_FAIL_UNDER: 99
TEST_ALL_PACKAGES: ${{ needs.initialize.outputs.is_full_run }}
TARGET_BRANCH: ${{ github.base_ref || github.event.merge_group.base_ref }}
BUILD_TYPE: presubmit
run: |
ci/report_coverage.sh