Skip to content

fix(release): make the release checklist able to fail - #840

Open
andyne13 wants to merge 1 commit into
developfrom
fix/releasing-checklist-gates
Open

fix(release): make the release checklist able to fail#840
andyne13 wants to merge 1 commit into
developfrom
fix/releasing-checklist-gates

Conversation

@andyne13

@andyne13 andyne13 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Fixes the four issues CodeRabbit raised on .github/RELEASING.md in #839. All four were valid, and they share a theme: the checks looked like gates but could not fail — the exact defect the document was written to prevent.

Raised there rather than fixed there because #839 was a pure back-merge, and develop dismisses stale reviews on push.

What was wrong

dg() Piped a failed registry lookup into sha256sum, which hashes empty input and returns sha256:e3b0c442… — a real-looking digest. Step 2 reported a missing image as present, and two missing tags compared equal so steps 3 and 4 printed OK.
Step 1 The job-conclusion check only printed the count of non-success jobs and exited 0 regardless, so a release could continue straight past a skipped build.
Step 5 Compared RepoDigests (repo@sha256:…) against a bare sha256:…. Those can never match literally.
Step 8 Matched any version-shaped tag instead of comparing to $VER, so a pin left at the previous release satisfied it.

What changed

  • dg() captures the manifest first and returns non-zero on an empty or failed lookup. Step 4 also gained -n guards: with the helper fixed, two missing tags are both empty and would still have compared equal.
  • The job gate exits non-zero.
  • Step 5 strips the repository prefix before comparing.
  • Step 8 checks each OpenRag repository's tag by name. Counting version-shaped tags would have been wrong — values.yaml also pins vllm, milvus and infinity, whose versions are unrelated to the release. My first attempt did exactly that and flagged vllm/vllm-openai:v0.11.2 as a stale OpenRag pin.

Verification

Every snippet was executed, not reasoned about:

  • The job gate was run against the v2.0.1 run that built nothing (30034799802) — correctly fails with 3 job(s) did not conclude success — and against the v2.1.0 run (30620163814) — passes.
  • dg() on a nonexistent tag now returns nothing and non-zero; two missing tags no longer compare equal.
  • Step 8 was extracted from the document and run verbatim against the v2.1.0 tag: step 8 PASS, exit 0.
  • Steps 2-5 were re-run against the live registries; v2.1.0's verification still holds under the stricter checks.

No change to the v2.1.0 release, which was verified with real, distinct digests and independently confirmed by pulling the image and reading 2.1.0 out of it.

Summary by CodeRabbit

  • Documentation
    • Strengthened release validation procedures with stricter version checking for all release components and improved manifest verification during the release process
    • Enhanced image and artifact digest verification to ensure consistent deployments and prevent configuration errors
    • Improved error detection and blocking workflow gates to prevent invalid or incomplete releases from reaching production

Four checks in .github/RELEASING.md looked like gates but could not fail,
which is the exact defect the document was written to prevent. Found in
review of #839.

- dg() piped a failed registry lookup into sha256sum, which hashes empty
  input and returns sha256:e3b0c442... — a real-looking digest. Step 2 then
  reported a missing image as present, and two missing tags compared equal
  so steps 3 and 4 printed OK. It now captures the manifest first and
  returns non-zero on an empty or failed lookup. Step 4 gained -n guards:
  with the helper fixed, two missing tags are both empty and would still
  have compared equal.
- The job-conclusion check only printed the count of non-success jobs and
  exited 0 regardless, so a release could continue past a skipped build.
  It now exits non-zero.
- Step 5 compared RepoDigests (repo@sha256:...) against a bare sha256:...,
  which can never match literally. It now strips the repository prefix.
- Step 8 matched any version-shaped tag rather than comparing to $VER, so a
  pin left at the previous release satisfied it. It now checks each OpenRag
  repository's tag by name. Counting version-shaped tags instead would have
  been wrong: values.yaml also pins vllm, milvus and infinity, whose
  versions are unrelated to the release.

Every snippet was executed rather than reasoned about: the job gate was run
against the v2.0.1 run that built nothing (correctly fails) and against the
v2.1.0 run (passes), and the rest against the live v2.1.0 registries.
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The release checklist now rejects missing or empty digests, failed jobs, registry and image mismatches, and missing or incorrect chart, image-tag, and compose version pins.

Changes

Release validation

Layer / File(s) Summary
Digest and job validation
.github/RELEASING.md
The digest helper rejects missing tags and empty manifests. Job verification exits when any job is unsuccessful.
Registry and image verification
.github/RELEASING.md
Registry comparisons require both digests. Pulled image digests are compared with the registry digest.
Release version validation
.github/RELEASING.md
Chart versions, OpenRag image tags, and compose pins use exact release-version checks and fail on missing or mismatched values.

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

Suggested labels: chore

🚥 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 directly describes the main change: enabling the release checklist to fail when validation conditions are not met, which aligns with the PR's core objective of adding failure conditions to release verification checks.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/releasing-checklist-gates

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 added the chore No production code impact, typically improve tooling, code quality, etc label Jul 31, 2026

@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: 3

🤖 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 @.github/RELEASING.md:
- Around line 239-244: Update the compose pin validation in the “compose pins”
check to avoid interpolating VER into an unescaped regular expression and to
ignore commented lines. Validate active image fields using fixed-string or
field-based matching, requiring exactly one linagoraai/openrag:$VER pin and one
linagoraai/openrag-admin-ui:$VER pin, while failing when any additional relevant
compose image pins exist.
- Around line 82-88: Update the release-job validation around the bad count to
first verify that verify-tag, build-and-push-image, build-and-push-image-ray,
and build-and-push-image-admin-ui are all present in the gh run view result.
Fail the gate when any required job is missing, then retain the existing
non-success conclusion check before continuing.
- Around line 161-165: Update the Docker verification flow in
.github/RELEASING.md to fail immediately when docker pull fails, preventing
inspection of a stale cached image. When extracting pulled, select the
RepoDigests entry for linagoraai/openrag rather than indexing the unordered
collection, reject an empty digest, then compare that digest with registry.
🪄 Autofix (Beta)

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: c5ac40e6-828f-4166-8744-f84e9563fdb0

📥 Commits

Reviewing files that changed from the base of the PR and between 88da8b4 and 83ea1d5.

📒 Files selected for processing (1)
  • .github/RELEASING.md

Comment thread .github/RELEASING.md
Comment on lines +82 to +88
bad=$(gh run view "$RUN_ID" --json jobs \
--jq '[.jobs[] | select(.conclusion != "success")] | length') || exit 1
if [ "$bad" -ne 0 ]; then
echo "FAIL: $bad job(s) did not conclude success — do not continue" >&2
exit 1
fi
echo "OK: every job concluded success"

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

Require all four release jobs before continuing.

This gate checks only the conclusions of returned jobs. If a required job is absent, bad is still 0 when the remaining jobs succeed. Assert that verify-tag, build-and-push-image, build-and-push-image-ray, and build-and-push-image-admin-ui are present before checking their conclusions.

🤖 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 @.github/RELEASING.md around lines 82 - 88, Update the release-job validation
around the bad count to first verify that verify-tag, build-and-push-image,
build-and-push-image-ray, and build-and-push-image-admin-ui are all present in
the gh run view result. Fail the gate when any required job is missing, then
retain the existing non-success conclusion check before continuing.

Comment thread .github/RELEASING.md
Comment on lines 161 to +165
docker pull "linagoraai/openrag:$VER"
docker image inspect "linagoraai/openrag:$VER" --format '{{index .RepoDigests 0}}'
pulled=$(docker image inspect "linagoraai/openrag:$VER" \
--format '{{index .RepoDigests 0}}' | cut -d@ -f2)
registry=$(dg "linagoraai/openrag:$VER") || { echo "FAIL: tag not in registry" >&2; exit 1; }
[ "$pulled" = "$registry" ] \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpt =="
sed -n '140,175p' .github/RELEASING.md 2>/dev/null || true

echo "== nearby command context =="
git show HEAD:.github/RELEASING.md 2>/dev/null | sed -n '140,175p' || true

echo "== repo docker/digest refs =="
rg -n "docker (pull|image inspect)|RepoDigests|linagoraai/openrag|registry|verify" .github/RELEASING.md README.md 2>/dev/null || true

Repository: linagora/openrag

Length of output: 5259


🌐 Web query:

Docker CLI image inspect RepoDigests multiple entries index first entry repository may not match pulled image documentation

💡 Result:

The RepoDigests field in Docker image metadata is a list of content-addressable digests of image manifests from which a local image was referenced [1]. Because this field is a collection of all registry/repository locations from which an image has been pulled or pushed, it can contain multiple entries if the same image ID exists under different repository names or registry paths [2][3]. It is important to understand the following regarding RepoDigests: 1. Order and Indexing: The order of entries in the RepoDigests list is not guaranteed to align with the specific image tag or repository used during a recent pull [2]. Attempting to retrieve a specific entry using index 0 (e.g., {{index.RepoDigests 0}}) is unreliable if multiple digests are present, as the first entry may not correspond to the image name you used to pull the image [2]. 2. Nature of the Field: RepoDigests are attributes of where an image is stored rather than immutable properties of the image itself [3]. They record the source manifest digest at the time of the pull operation [3]. Consequently, the repository portion of the digest string is derived from the registry/repository path used during that pull and may not match the repository name you are currently working with if the image was pulled from or pushed to multiple locations [2][3]. 3. deduplication: Docker has implemented fixes in recent versions to prevent duplicate entries from appearing in the RepoDigests list, ensuring that each unique reference is stored only once [4][5][6]. To reliably work with these values, avoid relying on positional indexing. If you need a specific digest for a particular repository, you should filter or iterate through the list using external tools (such as grep or platform-specific template logic) to match the desired registry path string, rather than assuming the first element is the correct one [2].

Citations:


🌐 Web query:

Docker CLI image pull returns non-zero when pull fails separate from image inspect caching documented

💡 Result:

The Docker CLI docker pull command is designed to return a non-zero exit code when a pull operation fails [1]. This behavior is generally consistent with command-line standards where failures are signaled through exit status [2][3]. While some legacy reports or specific environmental configurations (such as certain uses of docker-compose) have occasionally raised questions about suppression of error codes [1], the docker pull command itself executes via the Docker daemon, which propagates errors returned during the pull process [4]. If the daemon encounters an error—such as an image not found, an authentication failure, or a network issue—the CLI client receives and reports this error, typically resulting in a non-zero exit status [5][4][1]. It is important to note that the Docker CLI's error handling and exit codes are not always granularly documented for every failure scenario [6]. In practice: - A failed docker pull due to registry unavailability, missing images, or access issues will generally result in a non-zero exit code [5][1]. - Some users have historically requested specific or distinct exit codes for different types of failures (e.g., distinguishing between authentication issues and network issues) [5][2], but these are not currently implemented as a standardized, stable API, and users should rely on the standard non-zero exit convention to detect failure [2]. - Behaviors may occasionally appear inconsistent across different versions or when used in combination with tools like docker-compose, which may have its own logic for handling or suppressing exit statuses [1]. There is no documented "caching" mechanism that would cause a failed pull to return a zero exit code under normal circumstances; if an image is already cached locally (pulled successfully previously), docker pull will verify its existence and return zero, which is the expected "success" behavior. If you are experiencing unexpected zero exit codes during a failed pull, ensure you are not masking the error in a shell script (e.g., using || true or checking the exit code of the wrong process) [2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
text = Path(".github/RELEASING.md").read_text()
lines = text.splitlines()
print("contains ignored pull:", "docker pull" in text and "||" in "\n".join(lines[158:164]))
print("line 161-165:")
for i in range(157, min(166, len(lines))):
    print(f"{i+1}: {lines[i]}")
PY

if command -v docker >/dev/null 2>&1; then
  echo "== local Docker availability =="
  docker version 2>&1 | sed -n '1,20p'
else
  echo "== local Docker availability: not installed =="
fi

Repository: linagora/openrag

Length of output: 661


Fail on Docker pull errors and compare only the matching repository digest.

docker pull status is ignored, so the script can inspect an older locally cached image after a failed pull and may still pass if that stale digest equals the registry value. Also avoid {{index .RepoDigests 0}} because RepoDigests is an unordered collection. Use the pull exit status, select only the linagoraai/openrag entry, reject an empty digest, then compare with registry.

🤖 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 @.github/RELEASING.md around lines 161 - 165, Update the Docker verification
flow in .github/RELEASING.md to fail immediately when docker pull fails,
preventing inspection of a stale cached image. When extracting pulled, select
the RepoDigests entry for linagoraai/openrag rather than indexing the unordered
collection, reject an empty digest, then compare that digest with registry.

Comment thread .github/RELEASING.md
Comment on lines +239 to +244
# compose pins (2 expected: openrag, openrag-admin-ui)
cpins=$(git show "$VER:infra/compose/docker-compose.yaml" \
| grep -cE "image: linagoraai/openrag(-admin-ui)?:$VER$")
[ "$cpins" -eq 2 ] \
&& echo "OK 2 compose pins at $VER" \
|| { echo "FAIL $cpins compose pins at $VER (expected 2)"; fail=1; }

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

Validate each compose image exactly.

$VER is interpolated into an extended regular expression. For v2.1.0, each . matches any character, so a value such as v2x1y0 can pass.

The count also does not require one openrag pin and one openrag-admin-ui pin. Duplicate pins can pass, and an additional stale pin is ignored. The unanchored pattern can also count commented lines.

Use fixed-string or field-based matching. Require exactly one active pin for each expected repository, and reject extra relevant pins.

🤖 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 @.github/RELEASING.md around lines 239 - 244, Update the compose pin
validation in the “compose pins” check to avoid interpolating VER into an
unescaped regular expression and to ignore commented lines. Validate active
image fields using fixed-string or field-based matching, requiring exactly one
linagoraai/openrag:$VER pin and one linagoraai/openrag-admin-ui:$VER pin, while
failing when any additional relevant compose image pins exist.

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

Labels

chore No production code impact, typically improve tooling, code quality, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant