This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch feat/publish-python-junit-test-results
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 2f0e3bce25197dbe1a6ddb9bb0c9e33893496b01
Author: rusackas <[email protected]>
AuthorDate: Mon Jul 27 22:00:00 2026 -0700

    feat(ci): publish Python unit test results as PR check annotations
    
    Right now a red check on the Python-Unit job just says "failed" and
    sends contributors to raw pytest logs to find out which test broke.
    Add EnricoMi/publish-unit-test-result-action so failing tests get
    annotated inline on the PR diff instead.
    
    pytest already writes JUnit XML for free via --junit-xml; wire that up
    for all three pytest invocations in the unit-tests job and upload it as
    an artifact (uploaded even on failure, since that's exactly when it's
    needed). A second workflow, triggered via workflow_run (same pattern
    already used for the translation-regression bot), downloads that
    artifact and publishes the check run. workflow_run always runs in the
    base-branch context, so it can safely be granted checks:write even for
    PRs from forks or Dependabot, without ever checking out untrusted PR
    code.
    
    Scoped to Python-Unit only for now; the frontend's 8-way jest shard and
    the Python integration test matrix are natural follow-ups once this
    pattern proves out.
---
 .../workflows/superset-python-unittest-report.yml  | 65 ++++++++++++++++++++++
 .github/workflows/superset-python-unittest.yml     | 33 ++++++++++-
 2 files changed, 95 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/superset-python-unittest-report.yml 
b/.github/workflows/superset-python-unittest-report.yml
new file mode 100644
index 00000000000..46d86c0d170
--- /dev/null
+++ b/.github/workflows/superset-python-unittest-report.yml
@@ -0,0 +1,65 @@
+name: Python Unit Test Results
+
+on:
+  # zizmor: ignore[dangerous-triggers] - runs in base-branch context and only 
consumes artifacts uploaded by Python-Unit; never checks out PR code (see note 
below)
+  workflow_run:
+    workflows: ["Python-Unit"]
+    types: [completed]
+
+# This workflow publishes a check run annotating failing Python unit tests
+# inline on the PR diff, using JUnit XML uploaded by the Python-Unit workflow.
+# It uses the workflow_run trigger so that it always runs in the base-branch
+# context and can safely be granted write permissions, even for PRs from
+# forks or Dependabot.
+#
+# IMPORTANT: This workflow must NEVER check out code from the PR branch. All
+# data comes from artifacts uploaded by the Python-Unit workflow.
+permissions:
+  contents: read
+  checks: write
+  issues: read
+  actions: read
+
+jobs:
+  report:
+    runs-on: ubuntu-26.04
+    timeout-minutes: 10
+    if: >
+      github.event.workflow_run.conclusion == 'success' ||
+      github.event.workflow_run.conclusion == 'failure'
+    steps:
+      # Fails soft (continue-on-error) because the source unit-tests job is
+      # itself gated on change detection: a docs-only PR skips it entirely,
+      # so there is nothing to download or report on.
+      - name: Download JUnit results
+        id: download
+        continue-on-error: true
+        uses: 
actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
+        with:
+          pattern: "junit-results-*"
+          path: artifacts
+          merge-multiple: true
+          run-id: ${{ github.event.workflow_run.id }}
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+
+      - name: Download event file
+        id: download-event
+        if: steps.download.outcome == 'success'
+        continue-on-error: true
+        uses: 
actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
+        with:
+          name: "Event File"
+          path: event
+          run-id: ${{ github.event.workflow_run.id }}
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+
+      - name: Publish test results
+        if: steps.download.outcome == 'success' && 
steps.download-event.outcome == 'success'
+        uses: 
EnricoMi/publish-unit-test-result-action@d0a4676d0e0b938bc201470d88276b7c74c712b3
 # v2.24.0
+        with:
+          commit: ${{ github.event.workflow_run.head_sha }}
+          event_file: event/event.json
+          event_name: ${{ github.event.workflow_run.event }}
+          files: "artifacts/**/*.xml"
+          check_name: "Python Unit Test Results"
+          comment_mode: "off"
diff --git a/.github/workflows/superset-python-unittest.yml 
b/.github/workflows/superset-python-unittest.yml
index 64f3c683ae6..728f06384d9 100644
--- a/.github/workflows/superset-python-unittest.yml
+++ b/.github/workflows/superset-python-unittest.yml
@@ -74,14 +74,14 @@ jobs:
           SUPERSET_TESTENV: true
           SUPERSET_SECRET_KEY: not-a-secret
         run: |
-          pytest --durations-min=0.5 --cov-report= --cov=superset 
./tests/common ./tests/unit_tests --cache-clear --maxfail=50
+          pytest --durations-min=0.5 --cov-report= --cov=superset 
./tests/common ./tests/unit_tests --cache-clear --maxfail=50 
--junit-xml=test-results/junit-unit.xml
       - name: Python 100% coverage unit tests
         env:
           SUPERSET_TESTENV: true
           SUPERSET_SECRET_KEY: not-a-secret
         run: |
-          pytest --durations-min=0.5 --cov=superset/sql/ 
./tests/unit_tests/sql/ --cache-clear --cov-fail-under=100
-          pytest --durations-min=0.5 --cov=superset/semantic_layers/ 
./tests/unit_tests/semantic_layers/ --cache-clear --cov-fail-under=100
+          pytest --durations-min=0.5 --cov=superset/sql/ 
./tests/unit_tests/sql/ --cache-clear --cov-fail-under=100 
--junit-xml=test-results/junit-sql-coverage.xml
+          pytest --durations-min=0.5 --cov=superset/semantic_layers/ 
./tests/unit_tests/semantic_layers/ --cache-clear --cov-fail-under=100 
--junit-xml=test-results/junit-semantic-layers-coverage.xml
       - name: Upload code coverage
         uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f 
# v7.0.0
         with:
@@ -89,6 +89,33 @@ jobs:
           verbose: true
           use_oidc: true
           slug: apache/superset
+      # Uploaded even when a pytest step above fails, since that is exactly
+      # when the JUnit results are needed downstream, to annotate the PR with
+      # the failing tests. Consumed by the "Python Unit Test Results" workflow
+      # via workflow_run (see that workflow for why it can't just be a step
+      # here: it needs to run with write permissions, which this PR-triggered
+      # job can't safely have on a fork PR).
+      - name: Upload JUnit test results
+        if: always()
+        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a 
# v7
+        with:
+          name: junit-results-${{ matrix.python-version }}
+          path: test-results/
+          retention-days: 7
+
+  # Uploads the raw pull_request event payload so the "Python Unit Test
+  # Results" workflow (running via workflow_run, in base-branch context) can
+  # look up which PR/commit to annotate without checking out untrusted code.
+  event-file:
+    runs-on: ubuntu-26.04
+    timeout-minutes: 5
+    steps:
+      - name: Upload event file
+        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a 
# v7
+        with:
+          name: Event File
+          path: ${{ github.event_path }}
+          retention-days: 7
 
   # Stable required-status-check anchor. `unit-tests` is a matrix job gated on
   # change detection, so on non-Python PRs it is skipped and never produces its

Reply via email to