Is your feature request related to a problem? Please describe.
.github/workflows/release.yml has a step named "Build and Test" that never runs the tests:
- name: Build and Test
id: build
run: ./gradlew clean fatJar
fatJar is a plain Jar task (build.gradle:203, task fatJar(type: Jar)). Nothing in the file makes it depend on test or check — the only dependsOn edges near it are compileJava.dependsOn spotlessApply (:198) and a dependsOn nativeCompile inside a different task (:257). So the release pipeline compiles, assembles the jar, and publishes, without ever executing the suite.
The tag-deletion gate below it is correct in form and guards the wrong thing:
- name: Delete tag on failure
if: steps.build.outcome != 'success'
steps.build is the assembly step, so a tag is deleted on a compile failure and survives a test failure. The outcome-vs-conclusion lesson was applied here (this repo uses outcome, correctly — continue-on-error rewrites conclusion to success), but the step it reads is the build rather than a test run.
Both sibling analyzers gate on a real test step:
| repo |
release step |
gate |
codeanalyzer-python |
id: test → uv run pytest |
steps.test.outcome == 'failure' |
codeanalyzer-typescript |
id: test → tests |
steps.test.outcome == 'failure' |
codeanalyzer-java |
id: build → gradlew clean fatJar |
build only; no tests run |
Describe the solution you'd like
Describe alternatives you've considered
Not stated in the original issue.
Additional context
Why it matters now
The consequence is not hypothetical for this project. In python-sdk, a release workflow whose gate did not reflect the test result shipped v1.5.0 with a red Java suite — run 30300820857 reported 11 failed, 253 passed and concluded success. That was the conclusion/outcome variant of this same defect: a gate that reads something other than "did the tests pass".
Here the effect is broader, because there is no push CI on branches either. A release cut from this workflow has no automated test evidence at any point in its life — the only evidence is whatever the maintainer ran locally, on a machine whose environment differs from the runner's. A concrete example from today: a local run of 3.1.2 was 562 of 563, the single failure being Testcontainers finding no Docker. That is exactly the class of failure a runner would surface and a laptop will not, and in the other direction a runner-only failure would today reach PyPI unnoticed.
Scope boundary
.github/workflows/release.yml, and build.gradle only if the chosen fix is a task dependency rather than a workflow step. Not the test suite itself, and not the Testcontainers/Docker question — whether the runner should provide Docker for the container-backed tests is a separate decision this issue does not make, though it has to be answered to know which tests the gate can require.
Caveats and known risks
- Adding a real test step lengthens every release and will surface pre-existing flakiness that has never blocked a publish before. That is the gate working, but it will feel like a regression the first time it fires.
- If the Docker-dependent tests are excluded, the gate becomes "the tests that can run in CI passed", which is weaker than it reads. Say so in the workflow, next to the exclusion.
- A gate that deletes tags on failure has a sharp edge already proven in
python-sdk: the delete step runs git push --delete origin <tag>, so a flaky test destroys a tag someone may have already seen. Worth confirming that is still the behaviour you want once tests can actually fail it.
Definition of done
- The release workflow runs the suite and refuses to publish when it fails, verified by a deliberately-failing run rather than by reading the YAML.
- No step's name overstates what it does.
- If any test is excluded from the gate, the exclusion and its reason are written in the workflow.
Is your feature request related to a problem? Please describe.
.github/workflows/release.ymlhas a step named "Build and Test" that never runs the tests:fatJaris a plainJartask (build.gradle:203,task fatJar(type: Jar)). Nothing in the file makes it depend ontestorcheck— the onlydependsOnedges near it arecompileJava.dependsOn spotlessApply(:198) and adependsOn nativeCompileinside a different task (:257). So the release pipeline compiles, assembles the jar, and publishes, without ever executing the suite.The tag-deletion gate below it is correct in form and guards the wrong thing:
steps.buildis the assembly step, so a tag is deleted on a compile failure and survives a test failure. Theoutcome-vs-conclusionlesson was applied here (this repo usesoutcome, correctly —continue-on-errorrewritesconclusiontosuccess), but the step it reads is the build rather than a test run.Both sibling analyzers gate on a real test step:
codeanalyzer-pythonid: test→uv run pyteststeps.test.outcome == 'failure'codeanalyzer-typescriptid: test→ testssteps.test.outcome == 'failure'codeanalyzer-javaid: build→gradlew clean fatJarDescribe the solution you'd like
id.outcome, not at the build's.Describe alternatives you've considered
Not stated in the original issue.
Additional context
Why it matters now
The consequence is not hypothetical for this project. In
python-sdk, a release workflow whose gate did not reflect the test result shippedv1.5.0with a red Java suite — run30300820857reported11 failed, 253 passedand concluded success. That was theconclusion/outcomevariant of this same defect: a gate that reads something other than "did the tests pass".Here the effect is broader, because there is no push CI on branches either. A release cut from this workflow has no automated test evidence at any point in its life — the only evidence is whatever the maintainer ran locally, on a machine whose environment differs from the runner's. A concrete example from today: a local run of 3.1.2 was 562 of 563, the single failure being Testcontainers finding no Docker. That is exactly the class of failure a runner would surface and a laptop will not, and in the other direction a runner-only failure would today reach PyPI unnoticed.
Scope boundary
.github/workflows/release.yml, andbuild.gradleonly if the chosen fix is a task dependency rather than a workflow step. Not the test suite itself, and not the Testcontainers/Docker question — whether the runner should provide Docker for the container-backed tests is a separate decision this issue does not make, though it has to be answered to know which tests the gate can require.Caveats and known risks
python-sdk: the delete step runsgit push --delete origin <tag>, so a flaky test destroys a tag someone may have already seen. Worth confirming that is still the behaviour you want once tests can actually fail it.Definition of done