Skip to content

feat: add cut-version script for versioning#1651

Open
Alxandr wants to merge 1 commit intowe-promise:mainfrom
Alxandr:feat/cut-version-script
Open

feat: add cut-version script for versioning#1651
Alxandr wants to merge 1 commit intowe-promise:mainfrom
Alxandr:feat/cut-version-script

Conversation

@Alxandr
Copy link
Copy Markdown

@Alxandr Alxandr commented May 2, 2026

Also adds a VERSIONING.md document explaiing the versioning scheme.

Summary by CodeRabbit

  • New Features

    • Added a CLI tool to automate cutting and tagging releases with support for alpha/beta/rc and dry-run/skip options.
  • Documentation

    • Added detailed versioning and release process guidelines.
  • Tests

    • Added shell unit tests for version logic and a reusable Bash test framework; CI now lints and runs those shell tests.
  • Chores

    • Removed automatic pre-release bump job from the publish workflow and updated ignore rules to track release scripts.

@brin-security-scanner brin-security-scanner Bot added the contributor:flagged Contributor flagged for review by trust analysis. label May 2, 2026
@brin-security-scanner
Copy link
Copy Markdown

brin-security-scanner Bot commented May 2, 2026

⚠️ Contributor Trust Check — Review Recommended

This contributor's profile shows patterns that may warrant additional review. This is based on their GitHub activity, not the contents of this PR.

Alxandr · Score: 68/100

Dimension breakdown
Dimension Score What it measures
Identity 30 Account age, contribution history, GPG keys, org memberships
Behavior 80 PR patterns, unsolicited contribution ratio, activity cadence
Content 100 PR body substance, issue linkage, contribution quality
Graph 30 Cross-repo trust, co-contributor relationships

Analyzed by Brin · Full profile

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

📝 Walkthrough
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add cut-version script for versioning' clearly and directly summarizes the primary change: adding a new script for version management.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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

@Alxandr Alxandr force-pushed the feat/cut-version-script branch from c61108e to 8e76252 Compare May 2, 2026 17:24
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c61108e172

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread scripts/cut-version
Comment on lines +107 to +110
line_count="$(wc -l < .sure-version)"
if [[ "${line_count}" -ne 1 ]]; then
log::error ".sure-version must contain exactly one line"
return 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.

P2 Badge Accept .sure-version values without trailing newline

The validation in check::sure-version uses wc -l to enforce a single-line file, but wc -l counts newline characters rather than logical lines. A valid file containing just 1.2.3 (no trailing \n) is treated as 0 lines and rejected, which makes the release script fail on otherwise valid version files created by common editors/automation. Consider validating by reading the file content directly (and checking for additional lines) instead of relying on newline count.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The idea is that cut-release should own the version-file, so this is a valid fault-state.

@brin-security-scanner brin-security-scanner Bot added the pr:flagged PR flagged for review by security analysis. label May 2, 2026
@brin-security-scanner
Copy link
Copy Markdown

Brin PR Security Scan

This PR has findings that should be reviewed.

  • Score: 33/100
  • Verdict: suspicious

Findings:

  • supply_chain_mod: CI workflow .github/workflows/ci.yml contains remote script execution (1 pattern matches)
  • security_sabotage: Security tooling config modified: .gitignore
  • ci_tampering: The CI workflow .github/workflows/ci.yml adds a step that downloads and executes a remote script using 'curl -s https://raw.githubusercontent.com/bash-unit/bash_unit/master/install.sh | bash'. This pattern is a critical security risk as it allows for arbitrary code execution in the CI environment and makes the pipeline dependent on the security of an external repository.

Analyzed by Brin

@Alxandr
Copy link
Copy Markdown
Author

Alxandr commented May 2, 2026

ci_tampering: The CI workflow .github/workflows/ci.yml adds a step that downloads and executes a remote script using 'curl -s bash-unit/bash_unit@master/install.sh (raw) | bash'. This pattern is a critical security risk as it allows for arbitrary code execution in the CI environment and makes the pipeline dependent on the security of an external repository.

To be fair, this is a valid point. I just based it on how the repo said to do it. It might be better to just copy the 1 file from the source repository in (vendor it) to reduce this risk.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
scripts/cut-version (1)

460-475: No rollback on mid-flight failure — document recovery steps.

With set -Eeuo pipefail, any step failure (e.g. network error during push-tag, or a sed issue in update-version) exits immediately. If the tag was already pushed but the version-file commit was not, the repo is left with a pushed tag pointing at the un-bumped commit. Consider documenting the manual recovery path (delete + re-push the tag, or re-run with --no-tag) in VERSIONING.md or the script's error messages.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cut-version` around lines 460 - 475, The run::cut-version function
can leave a pushed tag without a corresponding version commit if a later step
(step::push-tag, step::update-version, step::commit, step::push) fails; add a
documented recovery path and a hint in the script: update VERSIONING.md with
explicit manual recovery steps (delete the remote tag and re-create it or re-run
with a --no-tag/force option) and add a brief on-error message in
run::cut-version that prints those steps and suggests re-running with --no-tag
or deleting the tag (e.g., "git push --delete origin vX.Y.Z" then re-run) so
users know how to rollback after mid-flight failures.
scripts/cut-version.test.sh (1)

119-124: ⚡ Quick win

Missing assert_fail tests for the three forbidden prerelease transitions.

The guarded transitions (alpha→beta, alpha→rc, beta→alpha, beta→rc, rc→*) are the most error-prone paths in the version logic. The current suite only covers the happy path. bash_unit provides assert_fail for exactly this purpose:

➕ Suggested additions
+test::version::next-alpha::from-beta-fails() {
+  assert_fail "version::next-alpha '1.2.3-beta.1'"
+}
+
+test::version::next-alpha::from-rc-fails() {
+  assert_fail "version::next-alpha '1.2.3-rc.1'"
+}
+
+test::version::next-beta::from-rc-fails() {
+  assert_fail "version::next-beta '1.2.3-rc.1'"
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cut-version.test.sh` around lines 119 - 124, Add negative tests using
bash_unit's assert_fail to cover the forbidden prerelease transitions that
currently lack coverage: create tests alongside
test::version::next-alpha::from-alpha-increments-alpha (and equivalent test
suites for next-beta/next-rc) that call the version functions (e.g.,
version::next-alpha, version::next-beta, version::next-rc) with inputs
representing the guarded transitions (alpha→beta, alpha→rc, beta→alpha, beta→rc,
and any rc→* attempts) and assert_fail that the function returns non-zero;
ensure each forbidden input is its own test case and uses assert_fail instead of
assert_equals so the suite verifies these transitions are rejected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 88-90: Replace the unpinned, silent piped installer by fetching a
specific, pinned release (tag or commit SHA) and failing on HTTP errors: update
the curl invocation (the current "curl -s
https://raw.githubusercontent.com/.../install.sh | bash") to download a release
tarball or a pinned install.sh URL and verify integrity (e.g., checksum or GPG)
before executing, and enable curl failure visibility (use -f and -S or -fsSL) so
CI fails on HTTP errors; do not pipe arbitrary upstream content to bash—save the
downloaded file, verify it, then run it or prefer installing via the official
release artifact instead of piping from master.

In `@scripts/cut-version`:
- Around line 107-111: The current line_count="$(wc -l < .sure-version)"
miscounts files missing a trailing newline; change the line counting to a method
that counts logical lines regardless of trailing newline (e.g., use grep -c ''
or an awk/counting approach) when computing line_count for .sure-version, then
keep the existing check that calls log::error ".sure-version must contain
exactly one line" and returns 1; ensure the replacement still captures failures
(use || true or similar) so the script doesn't exit unexpectedly and preserves
the existing variable name line_count and error path.
- Around line 411-412: The sed invocations in scripts/cut-version use `sed -i -E
...` which on BSD sed creates backup files like Chart.yaml-E; change these two
invocations that target charts/sure/Chart.yaml to use a portable in-place edit
pattern (e.g., `-i.bak` with the -E flag) and then remove the generated `.bak`
files so no backup remains in the working tree; update both instances that
perform the version and appVersion substitutions accordingly and ensure the
cleanup (rm) runs after both edits.

---

Nitpick comments:
In `@scripts/cut-version`:
- Around line 460-475: The run::cut-version function can leave a pushed tag
without a corresponding version commit if a later step (step::push-tag,
step::update-version, step::commit, step::push) fails; add a documented recovery
path and a hint in the script: update VERSIONING.md with explicit manual
recovery steps (delete the remote tag and re-create it or re-run with a
--no-tag/force option) and add a brief on-error message in run::cut-version that
prints those steps and suggests re-running with --no-tag or deleting the tag
(e.g., "git push --delete origin vX.Y.Z" then re-run) so users know how to
rollback after mid-flight failures.

In `@scripts/cut-version.test.sh`:
- Around line 119-124: Add negative tests using bash_unit's assert_fail to cover
the forbidden prerelease transitions that currently lack coverage: create tests
alongside test::version::next-alpha::from-alpha-increments-alpha (and equivalent
test suites for next-beta/next-rc) that call the version functions (e.g.,
version::next-alpha, version::next-beta, version::next-rc) with inputs
representing the guarded transitions (alpha→beta, alpha→rc, beta→alpha, beta→rc,
and any rc→* attempts) and assert_fail that the function returns non-zero;
ensure each forbidden input is its own test case and uses assert_fail instead of
assert_equals so the suite verifies these transitions are rejected.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8ad59f48-1dcf-4fda-982f-12952d23a2b6

📥 Commits

Reviewing files that changed from the base of the PR and between 95c2208 and c61108e.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • .github/workflows/publish.yml
  • .gitignore
  • VERSIONING.md
  • scripts/cut-version
  • scripts/cut-version.test.sh
💤 Files with no reviewable changes (1)
  • .github/workflows/publish.yml

Comment thread .github/workflows/ci.yml Outdated
Comment thread scripts/cut-version
Comment thread scripts/cut-version Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
.github/workflows/ci.yml (1)

89-92: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pin the bash_unit installer before executing it in CI.

This is the same CI supply-chain risk flagged earlier: curl -s .../master/install.sh | bash can execute unreviewed upstream changes and will also hide download failures. Please pin the installer to a release tag or commit SHA and fail fast on HTTP errors.

🔧 Suggested change
-          curl -s https://raw.githubusercontent.com/bash-unit/bash_unit/master/install.sh | bash
+          curl -fsSL https://raw.githubusercontent.com/bash-unit/bash_unit/<tag-or-sha>/install.sh -o /tmp/bash_unit_install.sh
+          bash /tmp/bash_unit_install.sh
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/ci.yml around lines 89 - 92, The CI step that installs
bash_unit via curl -s https://.../master/install.sh | bash is unsafe; update the
"Test shell scripts" job to fetch a pinned installer (use a specific release tag
or commit SHA in the URL instead of master), use curl -fSL to fail-fast on HTTP
errors, download the script to a file first (do not pipe directly to bash),
optionally verify a known checksum or GPG signature, then run the downloaded
script before running FORCE_COLOR=true ./bash_unit ./scripts/*.test.sh; ensure
the command sequence around the installer URL and the test invocation (the
install step and the FORCE_COLOR test runner) is updated accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.github/workflows/ci.yml:
- Around line 89-92: The CI step that installs bash_unit via curl -s
https://.../master/install.sh | bash is unsafe; update the "Test shell scripts"
job to fetch a pinned installer (use a specific release tag or commit SHA in the
URL instead of master), use curl -fSL to fail-fast on HTTP errors, download the
script to a file first (do not pipe directly to bash), optionally verify a known
checksum or GPG signature, then run the downloaded script before running
FORCE_COLOR=true ./bash_unit ./scripts/*.test.sh; ensure the command sequence
around the installer URL and the test invocation (the install step and the
FORCE_COLOR test runner) is updated accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9381e1ee-ef60-46e8-b7e3-92abdac87dfd

📥 Commits

Reviewing files that changed from the base of the PR and between c61108e and 8e76252.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • .github/workflows/publish.yml
  • .gitignore
  • VERSIONING.md
  • scripts/cut-version
  • scripts/cut-version.test.sh
💤 Files with no reviewable changes (1)
  • .github/workflows/publish.yml
✅ Files skipped from review due to trivial changes (3)
  • .gitignore
  • VERSIONING.md
  • scripts/cut-version.test.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/cut-version

Also adds a VERSIONING.md document explaiing the versioning scheme.
@Alxandr Alxandr force-pushed the feat/cut-version-script branch from 8e76252 to 9e54782 Compare May 2, 2026 18:25
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@vendor/scripts/bash_unit`:
- Around line 159-176: The custom error prefix variable message in
assert_within_delta is used in the precondition asserts before it is set;
initialize message early (e.g., declare local message and assign it from $4 or
to empty string) before the three assert calls so those asserts include the
caller-provided prefix; update the assert_within_delta function to set local
message=${4:-} (or local message="" then message=${4:-}) prior to calling
is_number/assert so the custom message is preserved when validation fails.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4f52dd8d-0059-406e-8383-326b10898f04

📥 Commits

Reviewing files that changed from the base of the PR and between 8e76252 and 9e54782.

📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • .github/workflows/publish.yml
  • .gitignore
  • VERSIONING.md
  • scripts/cut-version
  • scripts/cut-version.test.sh
  • vendor/scripts/bash_unit
💤 Files with no reviewable changes (1)
  • .github/workflows/publish.yml
✅ Files skipped from review due to trivial changes (2)
  • .gitignore
  • scripts/cut-version.test.sh
🚧 Files skipped from review as they are similar to previous changes (3)
  • .github/workflows/ci.yml
  • VERSIONING.md
  • scripts/cut-version

Comment thread vendor/scripts/bash_unit
Comment on lines +159 to +176
assert_within_delta() {
function abs() {
local value=$1
local sign=$(( value < 0 ? -1 : 1 ))
echo $((value * sign))
}
function is_number() {
local value=$1
test "$value" -eq "$value" 2>/dev/null
}
local expected=$1
local actual=$2
local max_delta=$3
assert "is_number $expected" "$message expected value [$expected] is not a number"
assert "is_number $actual" "$message actual value [$actual] is not a number"
assert "is_number $max_delta" "$message max_delta [$max_delta] is not a number"
local message=${4:-}
[[ -z $message ]] || message="$message\n"
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Initialize message before the validation asserts.

The custom message is read on Lines 172-174 before it is assigned on Line 175, so callers lose their prefix whenever one of the numeric precondition checks fails.

💡 Proposed fix
 assert_within_delta() {
+  local expected=$1
+  local actual=$2
+  local max_delta=$3
+  local message=${4:-}
+  [[ -z $message ]] || message="$message\n"
+
   function abs() {
     local value=$1
     local sign=$(( value < 0 ? -1 : 1 ))
     echo $((value * sign))
   }
   function is_number() {
     local value=$1
     test "$value" -eq "$value" 2>/dev/null
   }
-  local expected=$1
-  local actual=$2
-  local max_delta=$3
   assert "is_number $expected" "$message expected value [$expected] is not a number"
   assert "is_number $actual" "$message actual value [$actual] is not a number"
   assert "is_number $max_delta" "$message max_delta [$max_delta] is not a number"
-  local message=${4:-}
-  [[ -z $message ]] || message="$message\n"
 
   local actual_delta="$(abs $((expected - actual)))"
📝 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
assert_within_delta() {
function abs() {
local value=$1
local sign=$(( value < 0 ? -1 : 1 ))
echo $((value * sign))
}
function is_number() {
local value=$1
test "$value" -eq "$value" 2>/dev/null
}
local expected=$1
local actual=$2
local max_delta=$3
assert "is_number $expected" "$message expected value [$expected] is not a number"
assert "is_number $actual" "$message actual value [$actual] is not a number"
assert "is_number $max_delta" "$message max_delta [$max_delta] is not a number"
local message=${4:-}
[[ -z $message ]] || message="$message\n"
assert_within_delta() {
local expected=$1
local actual=$2
local max_delta=$3
local message=${4:-}
[[ -z $message ]] || message="$message\n"
function abs() {
local value=$1
local sign=$(( value < 0 ? -1 : 1 ))
echo $((value * sign))
}
function is_number() {
local value=$1
test "$value" -eq "$value" 2>/dev/null
}
assert "is_number $expected" "$message expected value [$expected] is not a number"
assert "is_number $actual" "$message actual value [$actual] is not a number"
assert "is_number $max_delta" "$message max_delta [$max_delta] is not a number"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vendor/scripts/bash_unit` around lines 159 - 176, The custom error prefix
variable message in assert_within_delta is used in the precondition asserts
before it is set; initialize message early (e.g., declare local message and
assign it from $4 or to empty string) before the three assert calls so those
asserts include the caller-provided prefix; update the assert_within_delta
function to set local message=${4:-} (or local message="" then message=${4:-})
prior to calling is_number/assert so the custom message is preserved when
validation fails.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Real/hallucination @Alxandr?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

@jjmata jjmata removed the contributor:flagged Contributor flagged for review by trust analysis. label May 3, 2026
Copy link
Copy Markdown
Collaborator

@jjmata jjmata left a comment

Choose a reason for hiding this comment

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

Looks good on first (quick) inspection ... let me get through PR backlog a bit and come back to this. 🙏

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

Labels

pr:flagged PR flagged for review by security analysis.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants