vibetunnel/mac/scripts/release-state.sh
Peter Steinberger 9e825ff21e Improve release scripts and fix Node.js detection issues
- Fix unbound variable errors in install-node.sh and node-path-setup.sh
- Add release-progress.sh for visual release monitoring
- Add release-health-check.sh for comprehensive pre-release validation
- Add check-node-simple.sh as a simpler, more robust Node.js checker
- Create release-improved.sh with better state tracking and progress indicators
- Update release-state.sh with better timestamp tracking

These improvements address issues encountered during beta.13 release:
- Node.js detection failures due to unbound variables
- Lack of visibility into release progress
- No clear way to resume interrupted releases
- Missing pre-flight validation
2025-07-19 02:30:26 +02:00

228 lines
No EOL
5.8 KiB
Bash

#!/bin/bash
#
# Release State Management Functions
# Used by release.sh to track progress and enable resumption
#
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$SCRIPT_DIR/.."
STATE_FILE="$PROJECT_ROOT/.release-state.json"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Initialize state file
init_state() {
local release_type=$1
local release_version=$2
local build_number=$3
local tag_name=$4
cat > "$STATE_FILE" << EOF
{
"release_type": "$release_type",
"release_version": "$release_version",
"build_number": "$build_number",
"tag_name": "$tag_name",
"started_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
"current_step": 1,
"steps": {
"1": {"name": "preflight_check", "status": "pending"},
"2": {"name": "clean_build", "status": "pending"},
"3": {"name": "set_version", "status": "pending"},
"4": {"name": "build_app", "status": "pending"},
"5": {"name": "sign_notarize", "status": "pending"},
"6": {"name": "create_dmg_zip", "status": "pending"},
"7": {"name": "github_release", "status": "pending"},
"8": {"name": "update_appcast", "status": "pending"},
"9": {"name": "commit_push", "status": "pending"}
},
"artifacts": {
"app_path": "",
"dmg_path": "",
"zip_path": "",
"sparkle_signature": ""
}
}
EOF
echo -e "${BLUE}📋 Initialized release state tracking${NC}"
}
# Get current step
get_current_step() {
if [[ -f "$STATE_FILE" ]]; then
jq -r '.current_step' "$STATE_FILE"
else
echo "1"
fi
}
# Get step status
get_step_status() {
local step=$1
if [[ -f "$STATE_FILE" ]]; then
jq -r ".steps.\"$step\".status" "$STATE_FILE"
else
echo "pending"
fi
}
# Update step status
update_step() {
local step=$1
local status=$2 # pending, in_progress, completed, failed
if [[ ! -f "$STATE_FILE" ]]; then
echo -e "${RED}❌ Error: State file not found${NC}"
return 1
fi
# Update the step status
local tmp=$(mktemp)
jq ".steps.\"$step\".status = \"$status\"" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
# If completed, update current step to next
if [[ "$status" == "completed" ]]; then
local next_step=$((step + 1))
jq ".current_step = $next_step" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
fi
# Add timestamp
jq ".steps.\"$step\".${status}_at = \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
# Also update last_updated timestamp
jq ".last_updated = \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
}
# Update step progress (for long-running operations)
update_step_progress() {
local step=$1
local progress_message=$2
if [[ ! -f "$STATE_FILE" ]]; then
return 1
fi
local tmp=$(mktemp)
jq ".steps.\"$step\".progress = \"$progress_message\"" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
jq ".last_updated = \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
}
# Save artifact path
save_artifact() {
local key=$1
local value=$2
if [[ ! -f "$STATE_FILE" ]]; then
echo -e "${RED}❌ Error: State file not found${NC}"
return 1
fi
local tmp=$(mktemp)
jq ".artifacts.$key = \"$value\"" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
}
# Get artifact path
get_artifact() {
local key=$1
if [[ -f "$STATE_FILE" ]]; then
jq -r ".artifacts.$key" "$STATE_FILE"
else
echo ""
fi
}
# Get release info
get_release_info() {
local key=$1
if [[ -f "$STATE_FILE" ]]; then
jq -r ".$key" "$STATE_FILE"
else
echo ""
fi
}
# Show progress
show_progress() {
if [[ ! -f "$STATE_FILE" ]]; then
echo -e "${YELLOW}⚠️ No release in progress${NC}"
return
fi
echo -e "${BLUE}📊 Release Progress${NC}"
echo "=================="
local release_version=$(get_release_info "release_version")
local release_type=$(get_release_info "release_type")
local started_at=$(get_release_info "started_at")
echo "Version: $release_version ($release_type)"
echo "Started: $started_at"
echo ""
echo "Steps:"
for i in {1..9}; do
local name=$(jq -r ".steps.\"$i\".name" "$STATE_FILE")
local status=$(jq -r ".steps.\"$i\".status" "$STATE_FILE")
local icon="⏳"
case $status in
completed) icon="✅" ;;
in_progress) icon="🔄" ;;
failed) icon="❌" ;;
pending) icon="⏳" ;;
esac
printf "%s Step %d: %-20s %s\n" "$icon" "$i" "$name" "$status"
done
echo ""
echo "Artifacts:"
local dmg_path=$(get_artifact "dmg_path")
local zip_path=$(get_artifact "zip_path")
if [[ -n "$dmg_path" ]]; then
echo " DMG: $dmg_path"
fi
if [[ -n "$zip_path" ]]; then
echo " ZIP: $zip_path"
fi
}
# Check if release can be resumed
can_resume() {
if [[ ! -f "$STATE_FILE" ]]; then
return 1
fi
# Check if any step is in progress or if there are pending steps after completed ones
local current_step=$(get_current_step)
if [[ "$current_step" -le 9 ]]; then
return 0
fi
return 1
}
# Clean up state file
cleanup_state() {
if [[ -f "$STATE_FILE" ]]; then
rm -f "$STATE_FILE"
echo -e "${GREEN}✅ Cleaned up release state${NC}"
fi
}
# Export functions
export -f init_state
export -f get_current_step
export -f get_step_status
export -f update_step
export -f save_artifact
export -f get_artifact
export -f get_release_info
export -f show_progress
export -f can_resume
export -f cleanup_state