22#
33# GOATd Kernel GitHub Release Automation
44#
5- # Usage: ./scripts/release.sh
5+ # Usage: ./scripts/release.sh [VERSION]
66#
77# This script automates GitHub releases with interactive prompts and safety checks:
8- # 1. Prompts for version number
8+ # 1. Prompts for version number (or accepts as argument)
99# 2. Unified pre-flight safety check (GitHub release + Git tags)
1010# 3. Detects uncommitted changes and offers to commit them
1111# 4. Bumps version in Cargo.toml
1212# 5. Commits and pushes code changes
13- # 6. Creates Git tag and pushes to GitHub (with tag conflict handling)
13+ # 6. Creates Git tag and pushes to GitHub (with robust tag conflict handling)
1414# 7. Creates GitHub Release
1515# 8. Builds release binary and creates tarball
1616# 9. Uploads tarball to GitHub Release
@@ -65,8 +65,6 @@ log_prompt() {
6565# AUTO_APPROVE mode for automated testing
6666# Set AUTO_APPROVE=yes to automatically answer "y" to all prompts
6767read_input () {
68- local default_value=" ${1:- } "
69-
7068 # If AUTO_APPROVE is set, return "y" for yes/no prompts
7169 if [[ " ${AUTO_APPROVE:- } " == " yes" ]]; then
7270 echo " y"
@@ -144,12 +142,12 @@ interactive_commit_prompt() {
144142 echo " "
145143 git -C " $REPO_ROOT " status --short
146144 echo " "
145+
147146 # Prompt user for action
148147 log_prompt " Found uncommitted changes. Would you like to commit them to GitHub master before releasing? (y/N): "
149148 local response
150149 response=$( read_input) || die " Failed to read user input"
151150
152-
153151 if [[ ! " $response " =~ ^[Yy]$ ]]; then
154152 log_info " Skipping automatic commit of uncommitted changes"
155153 log_info " Continuing with release process..."
@@ -235,11 +233,11 @@ check_git_tag_exists() {
235233 local tag_local=false
236234 local tag_remote=false
237235
238- if _check_git_tag_local " $version " ; then
236+ if _check_git_tag_local " $version " 2> /dev/null ; then
239237 tag_local=true
240238 fi
241239
242- if _check_git_tag_remote " $version " ; then
240+ if _check_git_tag_remote " $version " 2> /dev/null ; then
243241 tag_remote=true
244242 fi
245243
@@ -265,33 +263,33 @@ preflight_safety_check() {
265263 echo " "
266264
267265 # Check 1: GitHub Release
268- echo -e " ${BLUE} Checking GitHub release...${NC} "
266+ log_info " Checking GitHub for existing release v $version ..."
269267 if check_github_release " $version " ; then
270- echo -e " ${YELLOW} ⚠ GitHub release v$version exists${NC} "
268+ log_warn " GitHub release v$version already exists"
271269 github_exists=true
272270 has_conflicts=true
273271 else
274- echo -e " ${GREEN} ✓ No GitHub release found${NC} "
272+ log_success " No GitHub release found for v $version "
275273 fi
276274
277275 # Check 2: Git Tags
278- echo -e " ${BLUE} Checking Git tags...${NC} "
276+ log_info " Checking for existing Git tags v $version ..."
279277 tag_status=$( check_git_tag_exists " $version " )
280278 case " $tag_status " in
281279 " both" )
282- echo -e " ${YELLOW} ⚠ Git tag v$version exists locally AND remotely${NC} "
280+ log_warn " Git tag v$version exists locally AND remotely"
283281 has_conflicts=true
284282 ;;
285283 " local" )
286- echo -e " ${YELLOW} ⚠ Git tag v$version exists locally only${NC} "
284+ log_warn " Git tag v$version exists locally only"
287285 has_conflicts=true
288286 ;;
289287 " remote" )
290- echo -e " ${YELLOW} ⚠ Git tag v$version exists remotely only${NC} "
288+ log_warn " Git tag v$version exists remotely only"
291289 has_conflicts=true
292290 ;;
293291 " none" )
294- echo -e " ${GREEN} ✓ No Git tags found${NC} "
292+ log_success " No Git tags found for v $version "
295293 ;;
296294 esac
297295
@@ -339,24 +337,6 @@ preflight_safety_check() {
339337 echo " $tag_status "
340338}
341339
342- # Legacy function - kept for compatibility but now integrated into preflight
343- cleanup_conflicting_release_and_tag () {
344- local version=" $1 "
345-
346- log_warn " Cleaning up conflicting release and tags..."
347-
348- # Delete GitHub release
349- gh release delete " v$version " --repo " $GITHUB_REPO " --yes 2> /dev/null || true
350-
351- # Delete local tag
352- git -C " $REPO_ROOT " tag -d " v$version " 2> /dev/null || true
353-
354- # Delete remote tag
355- git -C " $REPO_ROOT " push origin --delete " v$version " 2> /dev/null || true
356-
357- log_success " Cleanup complete"
358- }
359-
360340prompt_version () {
361341 # Check if version was provided as command-line argument (for automation)
362342 if [ $# -ge 1 ] && [ -n " $1 " ]; then
@@ -366,8 +346,8 @@ prompt_version() {
366346 return 0
367347 fi
368348
369- # Use stderr for prompt to ensure it's visible even in command substitution
370- echo -e " ${CYAN} [?] ${NC} Enter version number (format: X.Y.Z, e.g., 0.2.1): " >&2
349+ # Use stderr for prompt to ensure it's visible
350+ log_prompt " Enter version number (format: X.Y.Z, e.g., 0.2.1): "
371351
372352 # Read from /dev/tty if available, otherwise use stdin
373353 local version
@@ -448,26 +428,12 @@ git_tag_and_push() {
448428 # Handle any remaining tag conflicts (should be none after preflight, but just in case)
449429 case " $tag_status " in
450430 " both" |" local" )
451- log_warn " Local tag v$version still exists after preflight"
452- log_info " Attempting to delete local tag..."
453- git -C " $REPO_ROOT " tag -d " v$version " 2> /dev/null || {
454- log_error " Failed to delete local tag v$version "
455- if [[ " ${AUTO_APPROVE:- } " != " yes" ]]; then
456- log_prompt " Delete local tag manually and press Enter to continue, or Ctrl+C to abort..."
457- read_input > /dev/null || true
458- fi
459- }
431+ log_warn " Local tag v$version still exists - attempting deletion..."
432+ git -C " $REPO_ROOT " tag -d " v$version " 2> /dev/null || die " Failed to delete local tag v$version "
460433 ;;&
461434 " both" |" remote" )
462- log_warn " Remote tag v$version still exists after preflight"
463- log_info " Attempting to delete remote tag..."
464- git -C " $REPO_ROOT " push origin --delete " v$version " 2> /dev/null || {
465- log_error " Failed to delete remote tag v$version "
466- if [[ " ${AUTO_APPROVE:- } " != " yes" ]]; then
467- log_prompt " Delete remote tag manually and press Enter to continue, or Ctrl+C to abort..."
468- read_input > /dev/null || true
469- fi
470- }
435+ log_warn " Remote tag v$version still exists - attempting deletion..."
436+ git -C " $REPO_ROOT " push origin --delete " v$version " 2> /dev/null || die " Failed to delete remote tag v$version "
471437 ;;
472438 esac
473439
@@ -516,9 +482,11 @@ create_tarball() {
516482 # Generate SHA256 checksum
517483 sha256sum " $tarball_name " > " ${tarball_name} .sha256"
518484
519- # Move tarball and checksum to repo root for upload
520- mv " $tarball_name " " $REPO_ROOT /"
521- mv " ${tarball_name} .sha256" " $REPO_ROOT /"
485+ # Verify tarball doesn't already exist in root before moving
486+ if [ -f " $tarball_name " ] && [ " $( pwd) /$tarball_name " != " $REPO_ROOT /$tarball_name " ]; then
487+ mv " $tarball_name " " $REPO_ROOT /"
488+ mv " ${tarball_name} .sha256" " $REPO_ROOT /"
489+ fi
522490
523491 log_success " Tarball created: $tarball_name "
524492 log_success " SHA256 checksum: ${tarball_name} .sha256"
@@ -650,8 +618,6 @@ main() {
650618 check_requirements
651619
652620 # Step 2: Prompt for version early so we can use it in commit messages
653- # CRITICAL FIX: Declare 'local' separately to avoid stdout capture issues
654- # with command substitution that hides the prompt from the user
655621 local version
656622 version=$( prompt_version " ${1:- } " )
657623 echo " "
@@ -665,7 +631,6 @@ main() {
665631 check_git_status
666632
667633 # Step 5: Unified pre-flight safety check (GitHub release + Git tags)
668- # This replaces the separate check_github_release and handle_existing_release calls
669634 local tag_status
670635 tag_status=$( preflight_safety_check " $version " )
671636
0 commit comments