Skip to content

fix(ci): the release workflow could not pass its own test suite - #203

Merged
GeiserX merged 1 commit into
mainfrom
fix/release-fetch-tags
Aug 4, 2026
Merged

fix(ci): the release workflow could not pass its own test suite#203
GeiserX merged 1 commit into
mainfrom
fix/release-fetch-tags

Conversation

@GeiserX

@GeiserX GeiserX commented Aug 4, 2026

Copy link
Copy Markdown
Owner

What happened

Auto Release failed on main after the six merges, so v1.11.4 was never cut.

The failing job was Verify CI passes, and the failure was:

Failed: no semver tags in this checkout — CI must fetch tags (fetch-tags: true),
otherwise this drift test silently passes and the pin can rot again
tests/test_compose_image_pins.py:88

The test was working exactly as designed. It compares the pinned compose image tag against the newest released version, and fails loudly rather than skipping — because a silent skip is precisely how the pin rotted to 1.4 and shipped issue #188.

test.yml was given fetch-depth: 0 + fetch-tags: true when that test was written. release.yml was not, and nothing connected the two.

The fix

release.yml fetches tags, and a guard asserts every workflow job that runs the unfiltered suite checks out with them — so a third workflow can't repeat this.

The guard is narrowed to invocations that would actually collect the drift test. Its first version flagged collector-live-check.yml, which runs pytest tests/ -m live; no test carries that marker, so the drift test never executes there and requiring tags would have been a rule about a problem that workflow cannot have. A control pins that distinction rather than leaving the rule merely strict.

Evidence

ruff check + ruff format --check clean, 95.17% coverage, 2706 passed.

Negative control: removing fetch-tags from release.yml fails the guard; a marker-filtered invocation is asserted not to require it.

Summary by CodeRabbit

  • Bug Fixes

    • Improved release and validation workflows to retrieve complete repository history and tags, ensuring image tag checks run reliably.
  • Tests

    • Added automated checks confirming workflows that run compose-image validation also check out repository tags.
    • Added coverage for correctly handling marker-filtered test runs.

Auto Release failed on main after six merges, so v1.11.4 was never cut. The
failing job was "Verify CI passes", and the failure was
tests/test_compose_image_pins.py: "no semver tags in this checkout — CI must
fetch tags (fetch-tags: true), otherwise this drift test silently passes and
the pin can rot again".

The test was working exactly as designed. It compares the pinned compose image
tag against the newest RELEASED version and fails loudly rather than skipping,
because a silent skip is how the pin rotted to 1.4 and shipped issue #188.
test.yml was given fetch-depth: 0 + fetch-tags: true when that test was
written; release.yml was not, and nothing connected the two.

release.yml now fetches tags, and a guard asserts every workflow job that runs
the unfiltered suite checks out with them, so a third workflow cannot repeat it.

The guard is narrowed to runs that would actually COLLECT the drift test. Its
first version flagged collector-live-check.yml, which runs `pytest tests/ -m
live` — no test carries that marker, so the drift test never executes there and
requiring tags would have been a rule about a problem that workflow cannot
have. A control pins that distinction rather than leaving the rule merely
strict.

Negative control: removing fetch-tags from release.yml fails the guard.
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Workflow tag validation

Layer / File(s) Summary
Release checkout configuration
.github/workflows/release.yml
The checkout action now fetches complete history and repository tags.
Workflow checkout validation
tests/test_compose_image_pins.py
Tests identify applicable pytest workflows, exclude filtered runs, require multiple workflows, and detect checkout steps without fetch-tags.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the CI release workflow failure addressed by fetching repository tags for the test suite.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/release-fetch-tags

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_compose_image_pins.py`:
- Around line 184-190: Update the checkout validation around the offenders loop
to require parsed fetch-tags to be boolean true and fetch-depth to be numeric
zero, rejecting string values such as "false" and nonzero depths. Add
negative-control test cases covering fetch-tags: "false" and a nonzero
fetch-depth while preserving acceptance of the required inputs.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 37ca27d4-83c5-418e-ac64-3c9d7f12e903

📥 Commits

Reviewing files that changed from the base of the PR and between 6a8569f and efc7687.

📒 Files selected for processing (2)
  • .github/workflows/release.yml
  • tests/test_compose_image_pins.py

Comment on lines +184 to +190
checkouts = [s for s in steps if str(s.get("uses", "")).startswith("actions/checkout")]
for step in checkouts:
if not (step.get("with") or {}).get("fetch-tags"):
offenders.append(f"{name}:{job_name}")
assert not offenders, (
f"these run pytest without fetching tags, so the compose-pin drift test fails: {offenders}. "
"Add `fetch-depth: 0` and `fetch-tags: true` to the checkout."

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file context =="
sed -n '120,210p' tests/test_compose_image_pins.py || true

echo "== related tests =="
rg -n "TestEveryWorkflowThatRunsTheSuiteFetchesTags|fetch-tags|fetch-depth|actions/checkout|pytest" tests/test_compose_image_pins.py tests || true

echo "== python yaml/load semantics probe =="
python3 - <<'PY'
import yaml
samples = {
    "null": None,
    "boolean_true": True,
    "string_true": "true",
    "string_false": "false",
    "quoted_false": '"false"',
    "fetch_tags_1": {
        "uses": "actions/checkout",
        "with": {"fetch-tags": True, "fetch-depth": 1},
    },
    "fetch_tags_false": {
        "uses": "actions/checkout",
        "with": {"fetch-tags": "false", "fetch-depth": "0"},
    },
    "fetch_tags_true_depth_1": {
        "uses": "actions/checkout",
        "with": {"fetch-tags": True, "fetch-depth": "1"},
    },
}
for name, step in samples.items():
    if step is None:
        value = None
    elif isinstance(step, dict):
        value = (step.get("with") or {}).get("fetch-tags")
    else:
        value = step
    print(f"{name}: value={value!r} bool={bool(value)}")
PY

Repository: GeiserX/CashPilot

Length of output: 43862


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
print("== workflows using pytest ==")
for path in sorted(Path(".github/workflows").glob("*.yml")):
    text = path.read_text()
    if "pytest" in text:
        with_checkout = False
        with fetch_tags_1 = False
        with fetch_tags_false = False
        for lineno, line in enumerate(text.splitlines(), 1):
            if "uses:" in line and "actions/checkout" in line:
                with_checkout = True
            elif with_checkout:
                if "fetch-tags:" in line:
                    with_fetch_tags_1 = True
                elif 'fetch-tags: "false"' in line or "fetch-tags: false" in line:
                    with_fetch_tags_false = True
        fetch_tags_found = any("fetch-tags:" in l for l in text.splitlines())
        fetch_depth_found = any("fetch-depth:" in l for l in text.splitlines())
        print(f"{path}: pytest={str(bool(text))}: checkout={with_checkout}; has fetch-tags={fetch_tags_found}; has fetch-depth={fetch_depth_found}; fetch-tags boolean-ish {with_fetch_tags_1}; fetch-tags false-ish {with_fetch_tags_false}")

print("\n== python parse samples from strings ==")
import ast, os
import glob
import subprocess
# read all workflow files
for path in Path(".github/workflows").glob("*.yml"):
    text = path.read_text()
    print(path)
    for line in text.splitlines():
        if "fetch-tags:" in line:
            print("  " + line.strip())
PY

Repository: GeiserX/CashPilot

Length of output: 262


Validate checkout inputs instead of present keys.

Line 186 only checks that fetch-tags is truthy. A string value such as fetch-tags: "false" currently passes, and the required fetch-depth: 0 input is not checked at all. Update the guard to compare the parsed values, or validate through a YAML parser, so these invalid workflow values are rejected.

Proposed fix
         checkouts = [s for s in steps if str(s.get("uses", "")).startswith("actions/checkout")]
         for step in checkouts:
-            if not (step.get("with") or {}).get("fetch-tags"):
+            checkout_with = step.get("with") or {}
+            if (
+                str(checkout_with.get("fetch-tags")).lower() != "true"
+                or str(checkout_with.get("fetch-depth")) != "0"
+            ):
                 offenders.append(f"{name}:{job_name}")

Add negative controls for fetch-tags: "false" and a nonzero fetch-depth.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
checkouts = [s for s in steps if str(s.get("uses", "")).startswith("actions/checkout")]
for step in checkouts:
if not (step.get("with") or {}).get("fetch-tags"):
offenders.append(f"{name}:{job_name}")
assert not offenders, (
f"these run pytest without fetching tags, so the compose-pin drift test fails: {offenders}. "
"Add `fetch-depth: 0` and `fetch-tags: true` to the checkout."
checkouts = [s for s in steps if str(s.get("uses", "")).startswith("actions/checkout")]
for step in checkouts:
checkout_with = step.get("with") or {}
if (
str(checkout_with.get("fetch-tags")).lower() != "true"
or str(checkout_with.get("fetch-depth")) != "0"
):
offenders.append(f"{name}:{job_name}")
assert not offenders, (
f"these run pytest without fetching tags, so the compose-pin drift test fails: {offenders}. "
"Add `fetch-depth: 0` and `fetch-tags: true` to the checkout."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_compose_image_pins.py` around lines 184 - 190, Update the checkout
validation around the offenders loop to require parsed fetch-tags to be boolean
true and fetch-depth to be numeric zero, rejecting string values such as "false"
and nonzero depths. Add negative-control test cases covering fetch-tags: "false"
and a nonzero fetch-depth while preserving acceptance of the required inputs.

@GeiserX
GeiserX merged commit 2264efa into main Aug 4, 2026
8 checks passed
@GeiserX
GeiserX deleted the fix/release-fetch-tags branch August 4, 2026 16:48
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.

1 participant