From 00f3d12a1db19b8d9662a18af1e508a1345b8611 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Tue, 30 Jun 2026 12:01:44 -0400 Subject: [PATCH] [manual backport `stable-5`] Fix CI Test Collision (#1162) (#1166) * Fix CI Test Collision (#1162) * Fix CI concurrency issue * More CI fixes * Fix coverage job install * Install correct test dependencies (cherry picked from commit d211f316ad5e936ec1821956674917c0339c8e47) * Restore cancel-in-progress: true --- .github/workflows/all_green_check.yaml | 56 +++++------------- .github/workflows/integration-tests.yaml | 2 +- .github/workflows/linters.yaml | 12 +--- .github/workflows/sanity-tests.yaml | 10 +--- .github/workflows/sonarcloud.yml | 73 +++++++++++++++--------- .github/workflows/unit-tests.yaml | 10 +--- 6 files changed, 66 insertions(+), 97 deletions(-) diff --git a/.github/workflows/all_green_check.yaml b/.github/workflows/all_green_check.yaml index d5cc7f76..9b9046bd 100644 --- a/.github/workflows/all_green_check.yaml +++ b/.github/workflows/all_green_check.yaml @@ -33,49 +33,37 @@ jobs: coverage: name: Unit test coverage runs-on: ubuntu-latest - needs: - - sanity - - units - env: - # stable-5 is tested against ansible-core stable-2.18 (see integration-tests.yaml). - ANSIBLE_CORE_REF: "stable-2.18" steps: - name: Checkout repository uses: actions/checkout@v4 + with: + path: ansible_collections/kubernetes/core - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.12" - - name: Install Ansible (ansible-test) + - name: Run unit tests with coverage + working-directory: ansible_collections/kubernetes/core + env: + PYTHONPATH: ${{ github.workspace }} run: | python -m pip install --upgrade pip - python -m pip install "https://github.com/ansible/ansible/archive/${ANSIBLE_CORE_REF}.tar.gz" - - - name: Run unit tests with coverage - run: ansible-test units --venv --coverage --python 3.12 --requirements - - - name: Combine and emit coverage XML - run: | - ansible-test coverage combine --venv --python 3.12 --requirements - ansible-test coverage xml --venv --python 3.12 --requirements - - - name: Prepare coverage.xml for SonarCloud - run: | - set -euo pipefail - mkdir -p "${GITHUB_WORKSPACE}" - xml=$(find tests/output/reports -maxdepth 1 -name '*.xml' ! -name '*powershell*' | head -1) - test -n "${xml}" - cp "${xml}" "${GITHUB_WORKSPACE}/coverage.xml" - # Strip workspace prefix so Sonar sees repo-relative paths (same idea as amazon.aws path rewrite) - sed -i "s#${GITHUB_WORKSPACE}/##g" "${GITHUB_WORKSPACE}/coverage.xml" + python -m pip install ansible-compat + python -m pip install https://github.com/ansible/ansible/archive/stable-2.19.tar.gz + # Same deps as the units matrix (build_install_collection); do not use + # tests/unit/requirements.txt — its kubernetes pin breaks test_core.py. + python -m pip install -r requirements.txt -r test-requirements.txt + python -m coverage run --source=plugins -m pytest tests/unit \ + --ansible-host-pattern localhost + python -m coverage xml -o coverage.xml - name: Upload coverage artifact uses: actions/upload-artifact@v4 with: name: coverage - path: ${{ github.workspace }}/coverage.xml + path: ansible_collections/kubernetes/core/coverage.xml all_green: if: ${{ always() }} @@ -125,17 +113,3 @@ jobs: print('all_green OK', results) " - - sonarcloud: - name: SonarCloud scan - needs: - - all_green - - coverage - if: >- - ${{ needs.all_green.result == 'success' - && (github.event_name == 'push' - || (github.event_name == 'pull_request' - && github.event.pull_request.head.repo.full_name == github.repository)) }} - uses: ./.github/workflows/sonarcloud.yml - secrets: - ANSIBLE_COLLECTIONS_ORG_SONAR_TOKEN_CICD_BOT: ${{ secrets.ANSIBLE_COLLECTIONS_ORG_SONAR_TOKEN_CICD_BOT }} diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index 12358e26..64a56732 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -64,7 +64,7 @@ jobs: python-version: - "3.12" workflow-id: ${{ fromJson(needs.splitter.outputs.test_jobs) }} - name: "integration-py${{ matrix.python-version }}-${{ matrix.ansible-version }}-${{ matrix.workflow-id }}-enable_turbo=${{ matrix.enable-turbo-mode }}" + name: Integration tests steps: - name: Read target id: read-targets diff --git a/.github/workflows/linters.yaml b/.github/workflows/linters.yaml index 3c308a60..35bda6ca 100644 --- a/.github/workflows/linters.yaml +++ b/.github/workflows/linters.yaml @@ -1,17 +1,7 @@ --- name: Linters -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true -on: - workflow_call: - pull_request: - branches: - - main - - stable-* - tags: - - '*' +on: [workflow_call] jobs: linters: diff --git a/.github/workflows/sanity-tests.yaml b/.github/workflows/sanity-tests.yaml index c442c793..15128910 100644 --- a/.github/workflows/sanity-tests.yaml +++ b/.github/workflows/sanity-tests.yaml @@ -1,15 +1,7 @@ --- name: Sanity tests -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true -on: - workflow_call: - pull_request: - branches: - - main - - stable-* +on: [workflow_call] jobs: sanity: diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 40521911..c56c2e2a 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -1,67 +1,88 @@ -## SonarCloud scan (reusable) +## SonarCloud Analysis Workflow for kubernetes.core # -# Invoked from **all_green** after the aggregate gate and **coverage** succeed. Uses the **caller's** -# **pull_request** / **push** event so **actions/checkout** can use **github.event.pull_request.head.sha** -# on PRs (Sonar-compliant). Not triggered by **workflow_run** + **workflow_run.head_sha** checkout. +# This workflow runs SonarCloud analysis triggered by all_green workflow completion. +# +# FLOW: all_green completes (linters, ansible-test, coverage) → workflow_run triggers this workflow → finalize job runs +# +# - Triggered by: workflow_run (all_green on pull_request or push to main/stable-*) +# - Steps: Checkout → Download coverage from all_green run → Get PR info (if PR) → Run SonarCloud scan +# - Coverage: Unit test coverage is produced by the coverage job in all_green and passed to SonarCloud here. --- name: SonarCloud on: - workflow_call: - secrets: - ANSIBLE_COLLECTIONS_ORG_SONAR_TOKEN_CICD_BOT: - required: true + workflow_run: + workflows: + - all_green + types: + - completed permissions: contents: read pull-requests: read + actions: read jobs: - scan: - name: SonarCloud scan + finalize: + name: finalize runs-on: ubuntu-latest + if: github.event.workflow_run.conclusion == 'success' steps: - name: Checkout repository uses: actions/checkout@v4 with: - ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} + ref: ${{ github.event.workflow_run.head_sha }} fetch-depth: 0 show-progress: false - - name: Download coverage artifact - uses: actions/download-artifact@v4 + - name: Download coverage artifacts + uses: dawidd6/action-download-artifact@2536c51d3d126276eb39f74d6bc9c72ac6ef30d3 # v16 with: - name: coverage - path: . + github_token: ${{ secrets.GITHUB_TOKEN }} + workflow: all_green + run_id: ${{ github.event.workflow_run.id }} + pattern: coverage* - name: Set coverage report paths run: | coverage_files=$(find . -name "coverage*.xml" -type f 2>/dev/null | tr '\n' ',' | sed 's/,$//') echo "Found coverage files: ${coverage_files:-none}" - echo "COVERAGE_PATHS=${coverage_files}" >> "$GITHUB_ENV" + echo "COVERAGE_PATHS=${coverage_files}" >> "${GITHUB_ENV}" + + - name: Get PR number and info + if: github.event.workflow_run.event == 'pull_request' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} + REPO: ${{ github.repository }} + run: | + PR_NUMBER=$(gh pr list --head "$HEAD_BRANCH" --repo "$REPO" --json number -q '.[0].number') + echo "PR_NUMBER=${PR_NUMBER}" >> "${GITHUB_ENV}" + if [ -n "${PR_NUMBER}" ]; then + PR_DATA=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}") + echo "PR_BASE=$(echo "${PR_DATA}" | jq -r '.base.ref')" >> "${GITHUB_ENV}" + echo "PR_HEAD=$(echo "${PR_DATA}" | jq -r '.head.ref')" >> "${GITHUB_ENV}" + fi - name: Prepare SonarCloud args env: - COMMIT_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} - EVENT_NAME: ${{ github.event_name }} - PR_NUMBER: ${{ github.event_name == 'pull_request' && github.event.pull_request.number || '' }} - PR_HEAD_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || '' }} - PR_BASE_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || '' }} + COMMIT_SHA: ${{ github.event.workflow_run.head_sha }} + EVENT_TYPE: ${{ github.event.workflow_run.event }} run: | SONAR_ARGS="-Dsonar.scm.revision=\"${COMMIT_SHA}\"" - if [[ "${EVENT_NAME}" == "pull_request" ]]; then + if [[ "${EVENT_TYPE}" == "pull_request" && -n "${PR_NUMBER:-}" ]]; then SONAR_ARGS="${SONAR_ARGS} -Dsonar.pullrequest.key=${PR_NUMBER}" - SONAR_ARGS="${SONAR_ARGS} -Dsonar.pullrequest.branch=${PR_HEAD_REF}" - SONAR_ARGS="${SONAR_ARGS} -Dsonar.pullrequest.base=${PR_BASE_REF}" + SONAR_ARGS="${SONAR_ARGS} -Dsonar.pullrequest.branch=${PR_HEAD}" + SONAR_ARGS="${SONAR_ARGS} -Dsonar.pullrequest.base=${PR_BASE}" fi if [[ -n "${COVERAGE_PATHS:-}" ]]; then SONAR_ARGS="${SONAR_ARGS} -Dsonar.python.coverage.reportPaths=${COVERAGE_PATHS}" fi - echo "SONAR_ARGS=${SONAR_ARGS}" >> "$GITHUB_ENV" + echo "SONAR_ARGS=${SONAR_ARGS}" >> "${GITHUB_ENV}" - name: SonarCloud Scan - uses: SonarSource/sonarqube-scan-action@a31c9398be7ace6bbfaf30c0bd5d415f843d45e9 + uses: SonarSource/sonarqube-scan-action@a31c9398be7ace6bbfaf30c0bd5d415f843d45e9 # v7 env: SONAR_TOKEN: ${{ secrets.ANSIBLE_COLLECTIONS_ORG_SONAR_TOKEN_CICD_BOT }} with: diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index 988905a0..7f563d4f 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -1,14 +1,6 @@ name: Unit tests -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true -on: - workflow_call: - pull_request: - branches: - - main - - stable-* +on: [workflow_call] jobs: unit-source: