Skip to content

Release Automation Modernization History

Context: This document preserves the history of a three-phase refactoring effort (Nov–Dec 2025) that replaced three overlapping, 1,100-line-plus monolithic release scripts with a modular library architecture and a single canonical scripts/bin/release command. For the current system, see docs/systems/release-automation.md.


Background: Why the Refactoring Was Needed

Three scripts handled releases with heavily overlapping responsibilities:

Script Size Responsibility
gem-publish.sh 700+ lines Everything: version bump, changelog, build, publish, GitHub release
release.sh 290+ lines Duplicate of most of the above
build.sh 180+ lines Subset of both

Problems: Contributors didn't know which script to use. Version validation, git operations, gem building, and GitHub release creation were each implemented 2–3 times. Error handling patterns were inconsistent. The 700-line gem-publish.sh embedded 200 lines of changelog logic inline.

Solution: Replace the three scripts with a modular library approach: shared libraries in scripts/lib/ sourced by a single canonical scripts/bin/release command.


Phase 1 β€” Library Extraction (November 25, 2025)

Outcome: Extracted 1,100+ lines of monolithic code into 6 focused libraries (~995 lines total, well-organized).

scripts/lib/
β”œβ”€β”€ common.sh      (165 lines) β€” logging, error handling, dry-run wrapper, confirmation prompts
β”œβ”€β”€ validation.sh  (120 lines) β€” git repo, clean directory, dependencies (git/ruby/gem/bundle/jq)
β”œβ”€β”€ version.sh     (155 lines) β€” read/calculate/validate/write semantic versions
β”œβ”€β”€ git.sh         (165 lines) β€” tag detection, commit history, commit/tag/push operations
β”œβ”€β”€ changelog.sh   (230 lines) β€” conventional commit parsing, categorization, CHANGELOG.md writes
└── gem.sh         (160 lines) β€” gem build, RubyGems publish, GitHub release creation

Test suite created in parallel: 6 test files under scripts/test/lib/, covering 60+ assertions across all libraries.


Phase 2 β€” Simplified Commands & Deprecation Wrappers (January 27, 2025)

Outcome: Two new canonical commands; three old scripts converted to deprecation wrappers.

scripts/release (200 lines) β€” main release orchestrator implementing the 10-step workflow:

./scripts/release patch           # Full patch release
./scripts/release patch --dry-run # Preview without changes
./scripts/release patch --skip-publish --no-github-release  # Build and test only
Flags: --dry-run, --skip-tests, --skip-publish, --no-github-release, --non-interactive.

scripts/build (80 lines) β€” focused gem builder (replacement for build.sh).

Deprecation wrappers: gem-publish.sh, release.sh, and build.sh were converted to stubs that display a 3-second warning and redirect to the new commands, passing all arguments through. Original scripts preserved as *.legacy files.


Phase 3 β€” Documentation & Testing (November 25, 2025)

Outcome: Comprehensive documentation updates and validation confirming the new system works end-to-end.

Documentation updated: - CONTRIBUTING.md β€” added Bash 4.0+ requirement, replaced old make release-* commands with scripts/release, documented all flags and the 10-step workflow - README.md β€” added System Requirements and Release Management sections - TROUBLESHOOTING.md (created, 700+ lines) β€” 7 sections covering Bash version issues, Git, RubyGems, changelog, Docker, test suite, performance; includes diagnostic commands, timing benchmarks, and a bug report template

Validation: All commands tested in --dry-run mode. Build, version bump, changelog generation, git tagging, and gem publication each confirmed functional. The complete 10-step release workflow was traced end-to-end.

Current canonical location: scripts/bin/release (moved to bin/ subdir in a subsequent cleanup). See docs/systems/release-automation.md for the current reference.