fix(release): Add more checks to release scripts#127
Merged
Conversation
Ensures we are in a repo, or a specific repo.
Ensures we are on a specific branch.
Ensures we have a remote called origin, and it is for the repo we expect.
``` ❯ bats release/test_common.bats test_common.bats ✓ validate_what: accepts valid value ✓ validate_what: accepts last valid value ✓ validate_what: rejects invalid value ✓ validate_what: rejects value not in allowed set for this script ✓ validate_what: rejects empty value ✓ validate_tag: accepts final release tag ✓ validate_tag: accepts RC tag ✓ validate_tag: accepts multi-digit RC ✓ validate_tag: accepts month 12 ✓ validate_tag: rejects month 0 ✓ validate_tag: rejects month 13 ✓ validate_tag: rejects leading zero on month ✓ validate_tag: rejects missing patch ✓ validate_tag: rejects empty tag ✓ validate_tag: rejects missing hyphen in rc ✓ validate_tag: --no-rc accepts final release ✓ validate_tag: --no-rc rejects RC tag ✓ validate_tag: rejects unknown flag ✓ validate_tag: rejects trailing arguments ✓ validate_release_base_version: accepts valid version ✓ validate_release_base_version: accepts month 11 ✓ validate_release_base_version: rejects version with patch ✓ validate_release_base_version: rejects empty ✓ validate_release_base_version: rejects month 0 ✓ validate_release_base_version: rejects leading zero ✓ assert_cwd_is_repo: passes in a git repo ✓ assert_cwd_is_repo: passes with matching name ✓ assert_cwd_is_repo: fails with wrong name ✓ assert_cwd_is_repo: fails outside a git repo ✓ assert_on_branch: passes on correct branch ✓ assert_on_branch: fails on wrong branch ✓ assert_on_branch: fails with empty argument ✓ assert_remote_exists: passes with SSH URL ✓ assert_remote_exists: passes with HTTPS URL ✓ assert_remote_exists: passes without .git suffix ✓ assert_remote_exists: fails with wrong repo name ✓ assert_remote_exists: fails with wrong org ✓ assert_remote_exists: fails with nonexistent remote ✓ assert_clean_index: passes on clean repo ✓ assert_clean_index: fails on staged changes ✓ assert_clean_index: fails on unstaged changes ✓ assert_clean_index: warns on untracked files, continues with y ✓ assert_clean_index: warns on untracked files, aborts with n 43 tests, 0 failures ```
…nctions for validating the tag and the "what"
Patch releases could break if the tag is too far back
…elease-candidate-branch.sh
We now have assertions that we are in the right place.
…f some ref/branch we are
This sets commonly used variables based on the tag. Also update RELEASE to RELEASE_BASE. Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
This sets commonly used variables based on the given release base. Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
Replace all the manual double-quote stripping with it. Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
Allows us to apply a function with arguments _for each operator_ in the config. Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
Centralises the clone if not present check. Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
Centralizes `mkdir -p` of the temp folder. Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
5 tasks
This removes the need for fetching and then looking at local refs. Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
This removes the need for fetching and then looking at local tags. Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
Note: This wasn't done for release-branch-hygiene.sh because it modifies global variables. Co-authored-by: Andrew Kenworthy <andrew.kenworthy@stackable.de>
NickLarsenNZ
commented
May 21, 2026
NickLarsenNZ
commented
May 21, 2026
NickLarsenNZ
commented
May 21, 2026
NickLarsenNZ
commented
May 21, 2026
adwk67
requested changes
May 21, 2026
Co-authored-by: Nick <10092581+NickLarsenNZ@users.noreply.github.com>
Co-authored-by: Nick <10092581+NickLarsenNZ@users.noreply.github.com>
This relaxes some assertions so it can work when the previous script hasn't been run in push mode.
NickLarsenNZ
commented
Jun 25, 2026
adwk67
approved these changes
Jun 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tip
This PR is intended to be compared with #125 so we can take the best ideas of both.
Summary
Harden the release scripts with shared validation, state assertions, and consistency improvements. The goal is to catch errors early (before mutations), make handover between colleagues safer, and reduce silent misbehavior.
Also incorporates features from #125: reduced duplication via shared helpers, and centralised variable derivation.
What changed
release/common.shwith shared functions sourced by all scriptsrelease/test_common.bats)validate_tag,validate_release_base_version,validate_what)check_common_dependencies)git commit -samreplaced with explicitgit addof known filespushd/popdwith relative paths instead ofcdwith absolute pathsREPOSITORYtoREMOTEfor consistencyderive_tag_vars,derive_branch_vars)for_each_operator), cloning (ensure_clone), temp folder creation (ensure_temp_folder), and quote stripping (strip_double_quotes)RELEASEtoRELEASE_BASEfor clarityChecklist
Phase 1: Shared infrastructure
common.shwithvalidate_what,check_common_dependencies,assert_clean_indexvalidate_tag(CalVer,--no-rcflag) andvalidate_release_base_versionassert_cwd_is_repoassert_on_branchassert_remote_exists(checksgithub.com/stackabletech/$repo)Phase 2: Apply shared functions to each script
create-release-branch.shcreate-release-candidate-branch.shmerge-release-candidate.shtag-release-candidate.shpost-release.shPhase 2b: Consolidate push_branch
2.6 - Move(deferred - current per-script implementations are short and clear)push_branchtocommon.shPhase 3: Fix git state handling
--depth 1from clonesgit commit -samwith explicitgit add+git commit -smassert_clean_indexafter commits()for directory isolation (exceptrelease-branch-hygiene.shwhich needs parent state)assert_remote_branch_exists,assert_remote_branch_not_exists,assert_tag_not_exists)Commit divergence assertions (TODOs placed in scripts, deferred to future PR)Phase 4: Improve dry-run and observability
merge-release-candidate.shpush mode (fails if missing). Dry-run skips the check to allow testing before PRs exist.Summary output at end of each script(skipped - per-repo output already exists andset -estops on first failure)post-release.shPhase 5: Future-proofing (optional)
Not doing these now.
5.1 ---non-interactiveflag formerge-release-candidate.sh(deferred to future PR)5.2 - Progress/state file for handover resumability (deferred to future PR)5.3 - Two-pass operator loop (deferred to future PR)Tip
The phases below incorporate improvements from @adwk67 in #125
Phase A: Reduce duplication
derive_tag_vars(centralised variable derivation from tag)derive_branch_vars(centralised variable derivation from branch version)strip_double_quotes(replace inline quote stripping)for_each_operator(centralised operator iteration)ensure_clone(centralised clone-if-not-present)ensure_temp_folder(centralised temp folder creation)Phase B: Improve existing functions
remote_branch_existstogit ls-remote(avoids modifying local refs)assert_tag_not_existstogit ls-remote(now takes remote name as argument)update_changelog(skip if tag already present, validate tag, use fixed-string matching)Phase C: Add new safety checks
commit_and_push_rcfunction)verify_release(post-mutation verification of Cargo, Helm, antora, changelog, etc.)shellcheck source=common.shdirectivePhase D: Bug fixes
LIBGIT2_NO_PKG_CONFIG=1workaround for non-NixOS usersextra/togit addpaths in operator loopPhase E: Update release-branch-hygiene.sh
release-branch-hygiene.shPhase F: Future improvements
()instead ofpushd/popdwhere functions don't propagate parent state (all scripts exceptrelease-branch-hygiene.shwhich needsCREATED_PRS)