Fix coverage #17992
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| on: | |
| 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 | |
| jobs: | |
| unit: | |
| runs-on: ubuntu-22.04 | |
| strategy: | |
| fail-fast: true | |
| matrix: | |
| python: ['3.10', "3.11", "3.12", "3.13", "3.14"] | |
| 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 }} | |
| - name: Install nox | |
| run: | | |
| python -m pip install --upgrade setuptools pip wheel | |
| python -m pip install nox | |
| - name: Run unit tests | |
| env: | |
| COVERAGE_FILE: ${{ github.workspace }}/.coverage-${{ matrix.python }} | |
| BUILD_TYPE: presubmit | |
| TARGET_BRANCH: ${{ github.base_ref || github.event.merge_group.base_ref }} | |
| TEST_TYPE: unit | |
| PY_VERSION: ${{ matrix.python }} | |
| run: | | |
| ci/run_conditional_tests.sh | |
| - name: Upload coverage results | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: coverage-artifact-${{ matrix.python }} | |
| path: .coverage-${{ matrix.python }} | |
| include-hidden-files: true | |
| cover: | |
| runs-on: ubuntu-latest | |
| needs: | |
| - unit | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| # Use fetch-depth of 0 (full history) so Git can find the merge-base with the | |
| # target branch and calculate the exact list of modified packages. | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| # We must explicitly fetch and set the target branch reference (main, etc.) | |
| # to perform a relative diff (target_branch...HEAD). Comparing against a generic "HEAD~1" | |
| # is fragile and fails if developers merge main back into their PR, if the PR has | |
| # multiple commits, or if running inside a Merge Queue (merge_group) environment. | |
| - name: Set target branch ref | |
| id: target | |
| env: | |
| TARGET_BRANCH: ${{ github.base_ref || github.event.merge_group.base_ref || 'main' }} | |
| run: | | |
| git fetch origin $TARGET_BRANCH | |
| target_sha=$(git rev-parse FETCH_HEAD) | |
| echo "sha=${target_sha}" >> "$GITHUB_OUTPUT" | |
| - name: Setup Python | |
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | |
| with: | |
| python-version: "3.10" | |
| - name: Set number of files changes in packages and preview-packages directories | |
| id: packages | |
| env: | |
| TARGET_SHA: ${{ steps.target.outputs.sha }} | |
| run: | | |
| git diff "$TARGET_SHA"...HEAD -- packages preview-packages > /dev/null | |
| num_files_changed=$(git diff "$TARGET_SHA"...HEAD -- packages preview-packages | wc -l | tr -d ' ') | |
| echo "num_files_changed=${num_files_changed}" >> "$GITHUB_OUTPUT" | |
| - name: Install coverage | |
| if: ${{ steps.packages.outputs.num_files_changed > 0 }} | |
| run: | | |
| python -m pip install --upgrade setuptools pip wheel | |
| python -m pip install coverage | |
| - name: Download coverage results | |
| if: ${{ steps.packages.outputs.num_files_changed > 0 }} | |
| uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 | |
| with: | |
| path: .coverage-results/ | |
| - name: Report coverage results | |
| if: ${{ steps.packages.outputs.num_files_changed > 0 }} | |
| env: | |
| # TODO: default to 100% coverage after next gapic-generator release | |
| # https://github.com/googleapis/google-cloud-python/issues/17459 | |
| DEFAULT_FAIL_UNDER: 99 | |
| TARGET_SHA: ${{ steps.target.outputs.sha }} | |
| run: | | |
| target_ref="$TARGET_SHA" | |
| # Find all modified packages | |
| modified_packages=$(git diff --name-only ${target_ref}...HEAD -- packages preview-packages | cut -d/ -f1,2 | sort -u) | |
| existing_modified_packages=() | |
| for pkg in ${modified_packages}; do | |
| if [ -d "${pkg}" ]; then | |
| existing_modified_packages+=("${pkg}") | |
| fi | |
| done | |
| if [ ${#existing_modified_packages[@]} -eq 0 ]; then | |
| echo "All modified packages were deleted. Skipping coverage evaluation." | |
| exit 0 | |
| fi | |
| if [ -d .coverage-results ]; then | |
| # Unzip any zipped coverage results | |
| find .coverage-results -type f -name '*.zip' -exec unzip -o {} \; | |
| # Find all coverage files and combine them. | |
| # We find files starting with .coverage (excluding .coveragerc files and templates) | |
| coverage_files=$(find .coverage-results . -type f -name '.coverage*' ! -name '.coveragerc*') | |
| if [ -n "${coverage_files}" ]; then | |
| coverage combine ${coverage_files} | |
| else | |
| echo "Error: No coverage files found to combine." | |
| exit 1 | |
| fi | |
| # Find all modified packages | |
| modified_packages=$(git diff --name-only ${target_ref}...HEAD -- packages preview-packages | cut -d/ -f1,2 | sort -u) | |
| failed_packages=() | |
| passed_packages=() | |
| for pkg in ${modified_packages}; do | |
| if [ -d "${pkg}" ]; then | |
| echo "============================================================" | |
| echo "Evaluating coverage for package: ${pkg}" | |
| echo "============================================================" | |
| set +e | |
| pushd "${pkg}" > /dev/null | |
| if [ -f ".coveragerc" ]; then | |
| echo "Using package-specific configuration: ${pkg}/.coveragerc" | |
| # If fail_under is specified in the package-specific .coveragerc, coverage report | |
| # will automatically enforce it. Otherwise, we enforce the default. | |
| if grep -q "fail_under" ".coveragerc"; then | |
| COVERAGE_FILE=../../.coverage coverage report --include="$PWD/**" | |
| else | |
| echo "No fail_under specified in ${pkg}/.coveragerc, enforcing default" | |
| COVERAGE_FILE=../../.coverage coverage report --include="$PWD/**" --fail-under="${DEFAULT_FAIL_UNDER}" | |
| fi | |
| else | |
| echo "No .coveragerc found for ${pkg}, enforcing default" | |
| COVERAGE_FILE=../../.coverage coverage report --include="$PWD/**" --fail-under="${DEFAULT_FAIL_UNDER}" | |
| fi | |
| status=$? | |
| popd > /dev/null | |
| set -e | |
| if [ ${status} -ne 0 ]; then | |
| failed_packages+=("${pkg}") | |
| else | |
| passed_packages+=("${pkg}") | |
| fi | |
| fi | |
| done | |
| echo "============================================================" | |
| echo "Coverage Evaluation Summary" | |
| echo "============================================================" | |
| if [ ${#passed_packages[@]} -gt 0 ]; then | |
| echo "Passed packages:" | |
| for pkg in "${passed_packages[@]}"; do | |
| echo " - ${pkg}" | |
| done | |
| fi | |
| if [ ${#failed_packages[@]} -gt 0 ]; then | |
| echo "Failed packages:" | |
| for pkg in "${failed_packages[@]}"; do | |
| echo " - ${pkg}" | |
| done | |
| exit 1 | |
| fi | |
| else | |
| echo "Error: No coverage results were downloaded from the unit test jobs." | |
| echo "This usually means the unit tests did not run or failed to upload their coverage files." | |
| exit 1 | |
| fi |