Skip to content

chore(ci): name failing tests in the django gate - #70815

Merged
rnegron merged 2 commits into
masterfrom
worktree-ci-backend-failure-rollup
Jul 15, 2026
Merged

chore(ci): name failing tests in the django gate#70815
rnegron merged 2 commits into
masterfrom
worktree-ci-backend-failure-rollup

Conversation

@rnegron

@rnegron rnegron commented Jul 14, 2026

Copy link
Copy Markdown
Member

Problem

The "Django Tests Pass" gate tells you which job failed, not which test. Product test failures can't even be named, because their JUnit never gets uploaded. On this run it just says the product matrix failed, so you're left digging through the shard by hand.

Changes

  • When a test job fails, the gate downloads that shard's JUnit and lists the failing tests. It prints them from the failing Check dependency results step (GitHub only auto-expands the step that failed), and also writes a job-summary table plus file-linked ::error:: annotations.
  • Product tests now upload their JUnit, staged as junit-product-<name>.xml under a product-junit-results-* prefix so it stays out of the snob shadow verdict and the timing reporter.
  • All of it is best effort (|| true) and skipped on green runs, so it never touches the pass/fail result.

Before

flowchart LR
  D[Django shards] --> G{{Django Tests Pass}}
  P[Product shards] --> G
  G --> R[Reports which JOB failed]
  classDef phBlue fill:#1d4aff,stroke:#1d4aff,color:#fff;
  classDef phYellow fill:#f9bd2b,stroke:#f9bd2b,color:#000;
  classDef phGray fill:#e5e7eb,stroke:#c7ccd1,color:#000;
  class G phBlue;
  class R phYellow;
  class D,P phGray;
Loading

After

flowchart LR
  D[Django shards] -->|result| G{{Django Tests Pass}}
  P[Product shards] -->|result| G
  D -. JUnit .-> A[(Artifacts)]
  P -. JUnit .-> A
  A -. "download (on failure)" .-> G
  G --> R[Reports which TEST failed + file annotations]
  classDef phBlue fill:#1d4aff,stroke:#1d4aff,color:#fff;
  classDef phYellow fill:#f9bd2b,stroke:#f9bd2b,color:#000;
  classDef phGray fill:#e5e7eb,stroke:#c7ccd1,color:#000;
  class G phBlue;
  class R phYellow;
  class D,P,A phGray;
Loading
Live proof: a run where a test was failed on purpose, then reverted
Shard Test Message
core-18 posthog/test/test_datetime.py::test_ci_rollup_demo_remove_before_merge AssertionError: ci rollup demo failure ... assert 1 == 2

Plus a file-linked annotation on the Checks tab. That run predates the current step layout and staged product upload, but uses the same parser, validated locally for backend, product, green-silent, and the XXE guard. The failing test was a throwaway and has been reverted.

Note

No change to test behavior. The verdict is untouched; this only adds detail on failure.

How did you test this code?

  • The live run above named the failing test and shard in the summary and as an annotation.
  • Ran the parser against backend and product JUnit fixtures: correct labels, repo-relative links, pipe-escaped output, silent on green, DTD/entity payloads refused. Also exercised the staging shell loop.
  • hogli lint:workflows 6/6, actionlint 0 new, ci:preflight --strict green.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Confirmed the rollup gate still exists (it does: django_tests, strengthened recently) before building this out. Claude (Opus 4.8) wrote the first pass and a /simplify run tightened it.

  • Print from the failing step, since GitHub only auto-expands the step that failed and a separate green step would hide the detail.
  • Stage product JUnit as junit-product-<name>.xml so it survives upload-artifact's path collapse (same trick as the coverage step); the name is parsed back out of the filename.
  • Download artifacts only when a test job failed, to avoid pulling ~50 artifacts on green runs.
  • Use a separate product-junit-results-* prefix so test-selection-verdict and report-test-timings don't ingest product results.
  • Inline stdlib parser (the gate holds no secrets); XXE handled by refusing DTD/entity files rather than pulling in defusedxml.
  • Depot shadow strips artifact uploads, so this is canonical-only, documented as an intentional delta.

@rnegron rnegron self-assigned this Jul 14, 2026
@rnegron rnegron added the run-ci-backend Force ci-backend's full test matrices to run even on a draft PR label Jul 14, 2026
@trunk-io

trunk-io Bot commented Jul 14, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@rnegron
rnegron force-pushed the worktree-ci-backend-failure-rollup branch from 529f7b7 to 1b6a99f Compare July 14, 2026 18:15
@rnegron rnegron removed the run-ci-backend Force ci-backend's full test matrices to run even on a draft PR label Jul 14, 2026
@rnegron
rnegron force-pushed the worktree-ci-backend-failure-rollup branch from 1b6a99f to 368a4d5 Compare July 14, 2026 18:21
@rnegron
rnegron force-pushed the worktree-ci-backend-failure-rollup branch from 368a4d5 to c0eef1c Compare July 14, 2026 18:33
@rnegron
rnegron marked this pull request as ready for review July 14, 2026 18:49
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team July 14, 2026 18:49
@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "chore(ci): name failing tests in the dja..." | Re-trigger Greptile

Comment on lines +855 to +858
with:
name: product-junit-results-${{ strategy.job-index }}
path: junit-staging/junit-product-*.xml
if-no-files-found: ignore

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.

P1 Rerun Artifact Name Collides

Rerunning a product matrix job uploads the same product-junit-results-${{ strategy.job-index }} name, but artifacts are immutable unless overwrite is enabled. The upload step then fails with a conflict and can turn a passing test rerun into a failed job; the coverage upload below already enables overwrite for this case.

Suggested change
with:
name: product-junit-results-${{ strategy.job-index }}
path: junit-staging/junit-product-*.xml
if-no-files-found: ignore
with:
name: product-junit-results-${{ strategy.job-index }}
path: junit-staging/junit-product-*.xml
if-no-files-found: ignore
overwrite: true

Comment on lines +2977 to +2978
for path in glob.glob(os.path.join(ROOT, "**", "junit-*.xml"), recursive=True):
artifact = os.path.relpath(path, ROOT).split(os.sep)[0]

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.

P2 Single Artifact Loses Shard Name

When the pattern matches exactly one artifact, download-artifact can extract its files directly into ROOT instead of an artifact-named directory. The first relative path component is then the XML filename, so a selected run reports junit-core.xml as the shard rather than the failing matrix shard.

Comment thread .github/workflows/ci-backend.yml Outdated
@rnegron
rnegron merged commit 27dbe1b into master Jul 15, 2026
236 checks passed
@rnegron
rnegron deleted the worktree-ci-backend-failure-rollup branch July 15, 2026 12:51
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 15, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-15 13:19 UTC Run
prod-us ✅ Deployed 2026-07-15 13:46 UTC Run
prod-eu ✅ Deployed 2026-07-15 13:46 UTC Run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants