Skip to content

ci: workflow counts as build, no-release label; publish only the head of main (#57, #58) - #60

Merged
compot-dev merged 2 commits into
mainfrom
uni-version-check-head
Oct 18, 2026
Merged

compot-dev merged 2 commits into
mainfrom
uni-version-check-head

Conversation

@compot-dev

Copy link
Copy Markdown
Collaborator

Closes #57. Closes #58.

Version check (.github/check-version.sh, #58)

  • .github/workflows/build.yml now counts as build: a change to it needs a new VTESSE_VERSION and its CHANGELOG.md section, like a change to ci/ or the Makefile. The script cannot tell the build steps of the workflow from its test or release steps, so:
  • the no-release label (as in ci: a no-release label lets a change that keeps the binaries skip the version; review follow-ups cerberus#39) lets a change to the code or the build through without a new version when the release files stay as they are (a test or release step, a comment). The workflow now also runs on labeled / unlabeled, so adding the label re-runs the check.

Release (#57)

  • The release job publishes only when the run's commit is still the head of main (git ls-remote), checked right before the old latest is deleted; otherwise a notice and no publication, and no Telegram post. A re-run of an older run can no longer put an older commit back as latest.

Checked locally

  • shellcheck v0.10.0 (-S style): clean; the workflow parses as YAML.
  • check-version.sh on synthetic branches (exit code without / with NO_RELEASE=true): code change without a bump 1/0; workflow-only change 1/0; docs only 0/0; Markdown inside a code directory 0/0; other .github/ file 0/0; proper bump with a CHANGELOG.md section 0/0; bump without a section 1/1.

CI only, the release files do not change: labelled no-release, no version bump.

@compot-dev compot-dev added the no-release Changes the build or the code without changing the binaries: no new version, no release label Oct 18, 2026
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Require versions for build workflow changes and guard latest releases

🐞 Bug fix ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

AI Description

• Treat build workflow changes as versioned changes unless the PR has a no-release label.
• Re-run version checks when the no-release label is added or removed.
• Publish and announce releases only when the run’s commit is still main’s head.
Diagram

graph TD
  PR["PR changes"] --> VC["Version check"] --> Gate{"Bump or label?"}
  Gate -- "allowed" --> CI["CI jobs"] --> Head{"Current main?"}
  Head -- "yes" --> Release["Publish latest"] --> Telegram["Telegram if new"]
  Head -- "no" --> Skip["Skip publication"]
Loading
High-Level Assessment

The existing version-check script and release step are appropriate places for these guards. The remote-head check is a practical safeguard against stale runs, though it cannot make the subsequent release replacement atomic.

Files changed (2) +38 / -9

Bug fix (1) +19 / -2
build.ymlWire label checks and prevent stale release publication +19/-2

Wire label checks and prevent stale release publication

• Runs PR checks on label changes and passes the no-release label state to the version script. Compares the run commit with the remote main head before replacing latest, and sends Telegram posts only when publication proceeds.

.github/workflows/build.yml

Other (1) +19 / -7
check-version.shInclude the build workflow in version checks +19/-7

Include the build workflow in version checks

• Treats changes to build.yml as code or build changes. Allows an unchanged version when NO_RELEASE=true and explains the no-release option in check output.

.github/check-version.sh

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (1) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Binary-changing patches pass as no-release 📎 Requirement gap ≡ Correctness
Description
check-version.sh exits successfully for every changed code or build path whenever
NO_RELEASE=true, without checking whether the change affects generated binaries. A
no-release-labeled source change that changes compiled output therefore reaches the successful
exit path and can proceed without a version bump.
Code

.github/check-version.sh[R50-54]

+	if [ -n "$changed" ] && [ "${NO_RELEASE:-}" = true ]; then
+		echo "::notice::code or build changed, VTESSE_VERSION stays $old: the no-release" \
+			"label says the release files do not change"
+		echo "$changed"
+		exit 0
Evidence
The checklist requires the no-release policy to allow labeled changes only when released binaries
remain unchanged. The bypass is controlled solely by the label and the presence of changed
code/build paths; it performs no binary-impact validation before exiting successfully.

Apply the chosen no-release label policy
.github/check-version.sh[50-54]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `NO_RELEASE` bypass accepts any changed code or build path when the pull request has the `no-release` label, so a source or build change that alters generated binaries can pass without a version bump.
## Fix Focus Areas
- .github/check-version.sh[50-54]
## Recommended Fix
Restrict the bypass to changes that are demonstrably non-binary, such as workflow comments or test/release-only workflow steps, and keep requiring a version bump for source and build changes unless their generated artifacts are verified unchanged.
## Recommended Fix
Update the related workflow or validation logic so a labeled pull request that can alter released binaries cannot skip the version check.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. A failed head lookup skips publication ✓ Resolved
Description
The git ls-remote command is piped to cut, so a failed remote lookup can leave head empty
without failing the publication step. When the lookup fails, the comparison takes the
notice-and-success path, leaving that run without a release or a failing status.
Code

.github/workflows/build.yml[R264-267]

+          head=$(git ls-remote origin refs/heads/main | cut -f 1)
+          if [ "$head" != "$GITHUB_SHA" ]; then
+            echo "::notice::main is at ${head:0:7} now, not ${GITHUB_SHA::7}: not published"
+            exit 0
Evidence
The new pipeline assigns head from cut and then treats every value different from GITHUB_SHA,
including an empty result, as a successful skip. The release job runs for main push and manual runs,
so a lookup failure reaches this path rather than a separate failure handler.

.github/workflows/build.yml[213-218]
.github/workflows/build.yml[257-270]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A failed `git ls-remote` lookup can be masked by the `cut` pipeline and treated as a successful decision not to publish.
## Fix Focus Areas
- .github/workflows/build.yml[264-268]
## Recommended Fix
Make the remote lookup fail the step on error, and reject an empty or malformed SHA before deciding whether the run is stale. Keep the successful stale-run case as a notice.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. New pushes can still publish stale builds 🐞 Bug ≡ Correctness
Description
The publish step compares GITHUB_SHA with main only once, before deleting and recreating
latest. If main advances after that comparison but before release creation finishes, the older
run continues with its artifacts; main runs are configured not to cancel in progress.
Code

.github/workflows/build.yml[R264-268]

+          head=$(git ls-remote origin refs/heads/main | cut -f 1)
+          if [ "$head" != "$GITHUB_SHA" ]; then
+            echo "::notice::main is at ${head:0:7} now, not ${GITHUB_SHA::7}: not published"
+            exit 0
+          fi
Evidence
Main runs are not canceled, and the workflow performs the remote-head comparison before the separate
delete and create commands. A push between those operations does not change the already-passed
condition or stop the older job.

.github/workflows/build.yml[37-44]
.github/workflows/build.yml[254-275]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The one-time head check leaves a window in which a newer push can make the run stale before it creates `latest`.
## Fix Focus Areas
- .github/workflows/build.yml[264-275]
## Recommended Fix
Add a post-publication head check and safely reconcile a stale publication only if `latest` still points to this run's commit. Avoid deleting a release already created by a newer run.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can move or hide resolved findings to focus on what still needs action

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread .github/check-version.sh
Comment thread .github/workflows/build.yml Outdated
Comment thread .github/workflows/build.yml Outdated
@compot-dev

Copy link
Copy Markdown
Collaborator Author

/review

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 178f9ff

@compot-dev
compot-dev merged commit dd237db into main Oct 18, 2026
10 checks passed
@compot-dev
compot-dev deleted the uni-version-check-head branch October 18, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-release Changes the build or the code without changing the binaries: no new version, no release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Version check: workflow build steps and a no-release label Release: publish "latest" only from the head of main

1 participant