Skip to content

Commit 32a9845

Browse files
committed
Add upgrade command - self-upgrade via GitHub releases
1 parent 20c0518 commit 32a9845

4 files changed

Lines changed: 109 additions & 0 deletions

File tree

lib/commands/help.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Commands:
2222
rollback [N] Rollback to previous release (or N steps back)
2323
releases List all available releases
2424
migrate Migrate existing deployment to release structure
25+
upgrade Upgrade ShipNode to latest version
2526
help Show this help message
2627
2728
User Management:

lib/commands/main.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ main() {
5858
mkpasswd)
5959
cmd_mkpasswd
6060
;;
61+
upgrade)
62+
cmd_upgrade
63+
;;
6164
help|--help|-h)
6265
cmd_help
6366
;;

lib/commands/upgrade.sh

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
cmd_upgrade() {
2+
local repo_url="https://github.com/devalade/shipnode"
3+
local latest_url="$repo_url/releases/latest/download/shipnode-installer.sh"
4+
local temp_dir="/tmp/shipnode-upgrade-$$"
5+
6+
info "Checking for updates..."
7+
8+
# Fetch latest version from GitHub API
9+
local latest_version
10+
local api_response
11+
local http_code
12+
13+
# Use -w to get HTTP status code, -s for silent, -S to show errors
14+
api_response=$(curl -sSL -w "\n%{http_code}" "https://api.github.com/repos/devalade/shipnode/releases/latest" 2>/dev/null)
15+
http_code=$(echo "$api_response" | tail -n1)
16+
api_response=$(echo "$api_response" | head -n-1)
17+
18+
if [ "$http_code" = "404" ]; then
19+
error "No releases available yet. Please check $repo_url/releases"
20+
elif [ "$http_code" != "200" ]; then
21+
error "Failed to fetch latest version from GitHub (HTTP $http_code)"
22+
fi
23+
24+
# Extract version from tag_name field (e.g., "v1.2.0" -> "1.2.0")
25+
if command -v jq &> /dev/null; then
26+
# Use jq for robust JSON parsing
27+
latest_version=$(echo "$api_response" | jq -r '.tag_name' 2>/dev/null | sed 's/^v//')
28+
else
29+
# Fallback to grep for systems without jq
30+
latest_version=$(echo "$api_response" | grep -oP '"tag_name":\s*"v?\K[0-9.]+' | head -n1)
31+
fi
32+
33+
if [ -z "$latest_version" ] || [ "$latest_version" = "null" ]; then
34+
error "Failed to parse version from GitHub API response"
35+
fi
36+
37+
# Compare with current VERSION
38+
if [[ "$latest_version" == "$VERSION" ]]; then
39+
success "Already on latest version (v$VERSION)"
40+
return 0
41+
fi
42+
43+
info "Current: v$VERSION → Latest: v$latest_version"
44+
45+
# Create temp directory
46+
mkdir -p "$temp_dir"
47+
48+
# Download latest installer
49+
info "Downloading ShipNode v$latest_version..."
50+
if ! curl -fsSL "$latest_url" -o "$temp_dir/shipnode-installer.sh"; then
51+
rm -rf "$temp_dir"
52+
error "Failed to download installer from $latest_url"
53+
fi
54+
55+
# Extract the installer (it's a self-extracting script)
56+
info "Extracting installer..."
57+
58+
# The installer has a base64 payload after __SHIPNODE_PAYLOAD__ marker
59+
# Extract and decode it
60+
local payload_marker="__SHIPNODE_PAYLOAD__"
61+
local payload_start
62+
payload_start=$(grep -n "^${payload_marker}$" "$temp_dir/shipnode-installer.sh" | head -n1 | cut -d: -f1)
63+
64+
if [ -z "$payload_start" ]; then
65+
rm -rf "$temp_dir"
66+
error "Invalid installer format: payload marker not found"
67+
fi
68+
69+
# Extract base64 payload and decode
70+
payload_start=$((payload_start + 1))
71+
if ! tail -n "+${payload_start}" "$temp_dir/shipnode-installer.sh" | base64 -d | tar -xz -C "$temp_dir"; then
72+
rm -rf "$temp_dir"
73+
error "Failed to extract installer payload"
74+
fi
75+
76+
# Verify extraction
77+
if [ ! -f "$temp_dir/shipnode" ] || [ ! -d "$temp_dir/lib" ]; then
78+
rm -rf "$temp_dir"
79+
error "Extracted files are incomplete"
80+
fi
81+
82+
# Install to SHIPNODE_DIR (overwrite existing installation)
83+
info "Installing to $SHIPNODE_DIR..."
84+
85+
# Copy files
86+
cp -r "$temp_dir/shipnode" "$SHIPNODE_DIR/" || {
87+
rm -rf "$temp_dir"
88+
error "Failed to copy shipnode entry point"
89+
}
90+
91+
cp -r "$temp_dir/lib" "$SHIPNODE_DIR/" || {
92+
rm -rf "$temp_dir"
93+
error "Failed to copy lib directory"
94+
}
95+
96+
# Ensure executable
97+
chmod +x "$SHIPNODE_DIR/shipnode"
98+
99+
# Cleanup
100+
rm -rf "$temp_dir"
101+
102+
success "Upgraded to ShipNode v$latest_version"
103+
info "Restart your shell or run 'hash -r' to refresh the command cache"
104+
}

shipnode

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ source "$LIB_DIR/commands/unlock.sh"
3535
source "$LIB_DIR/commands/rollback.sh"
3636
source "$LIB_DIR/commands/migrate.sh"
3737
source "$LIB_DIR/commands/env.sh"
38+
source "$LIB_DIR/commands/upgrade.sh"
3839
source "$LIB_DIR/commands/help.sh"
3940

4041
# Source and run main entry point

0 commit comments

Comments
 (0)