-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeploy.sh
More file actions
234 lines (201 loc) · 8.35 KB
/
deploy.sh
File metadata and controls
234 lines (201 loc) · 8.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#!/usr/bin/env bash
set -euo pipefail
# SmartFolio Production Deployment Script
# Usage: ./deploy.sh [--force] [--skip-build]
#
# Options:
# --force Force git reset (écrase changements locaux sans demander)
# --skip-build Skip Docker rebuild (restart seulement)
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
FORCE_RESET=0
SKIP_BUILD=0
# Parse arguments
for arg in "$@"; do
case $arg in
--force) FORCE_RESET=1 ;;
--skip-build) SKIP_BUILD=1 ;;
-h|--help)
head -n 10 "$0" | grep "^#" | sed 's/^# \?//'
exit 0
;;
esac
done
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GREEN}🚀 SmartFolio Production Deployment${NC}"
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
# Check if we're in the right directory
if [ ! -f "docker-compose.yml" ]; then
echo -e "${RED}❌ Error: docker-compose.prod.yml not found${NC}"
echo " Please run this script from the smartfolio root directory"
exit 1
fi
# Step 1: Check for local changes
echo -e "${YELLOW}📋 Step 1/5: Checking for local changes...${NC}"
if git diff --quiet && git diff --cached --quiet; then
echo -e "${GREEN}✅ No local changes${NC}"
else
echo -e "${YELLOW}⚠️ Local changes detected:${NC}"
git status --short
if [ $FORCE_RESET -eq 0 ]; then
echo ""
echo -e "${YELLOW}Do you want to discard local changes and pull from GitHub?${NC}"
echo -e "${RED}This will erase any uncommitted changes!${NC}"
read -p "Continue? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${RED}❌ Deployment cancelled${NC}"
exit 1
fi
fi
# Save changes just in case
BACKUP_FILE="/tmp/smartfolio_backup_$(date +%Y%m%d_%H%M%S).patch"
git diff > "$BACKUP_FILE"
echo -e "${GREEN}💾 Local changes backed up to: $BACKUP_FILE${NC}"
# Reset to origin
git reset --hard origin/main
echo -e "${GREEN}✅ Local changes discarded${NC}"
fi
# Step 2: Pull latest version
echo ""
echo -e "${YELLOW}📥 Step 2/5: Pulling latest version from GitHub...${NC}"
git fetch origin main
git pull origin main
echo -e "${GREEN}✅ Latest version pulled ($(git log -1 --format='%h - %s'))${NC}"
# Step 3: Verify and update .env for production
echo ""
echo -e "${YELLOW}🔧 Step 3/6: Checking .env configuration...${NC}"
# Detect server IP
SERVER_IP=$(hostname -I | awk '{print $1}')
if [ -z "$SERVER_IP" ]; then
echo -e "${RED}❌ Error: Could not detect server IP${NC}"
exit 1
fi
# Check if API_BASE_URL needs updating
CURRENT_API_URL=$(grep "^API_BASE_URL=" .env 2>/dev/null | cut -d'=' -f2 || true)
EXPECTED_API_URL="http://${SERVER_IP}:8080"
if [ "$CURRENT_API_URL" != "$EXPECTED_API_URL" ]; then
echo -e "${YELLOW}⚠️ API_BASE_URL mismatch:${NC}"
echo " Current: $CURRENT_API_URL"
echo " Expected: $EXPECTED_API_URL"
# Update .env file
if grep -q "^API_BASE_URL=" .env 2>/dev/null || false; then
sed -i "s|^API_BASE_URL=.*|API_BASE_URL=${EXPECTED_API_URL}|" .env
else
echo "API_BASE_URL=${EXPECTED_API_URL}" >> .env
fi
echo -e "${GREEN}✅ Updated API_BASE_URL to: $EXPECTED_API_URL${NC}"
else
echo -e "${GREEN}✅ API_BASE_URL already correct: $CURRENT_API_URL${NC}"
fi
# Step 4: Verify price cache exists
echo ""
echo -e "${YELLOW}💰 Step 4/7: Verifying price cache...${NC}"
CACHE_COUNT=$(find data/price_history -name "*.json" 2>/dev/null | wc -l)
if [ "$CACHE_COUNT" -lt 100 ]; then
echo -e "${RED}⚠️ Warning: Only $CACHE_COUNT price cache files found (expected ~127)${NC}"
echo -e "${YELLOW} Price history may be incomplete. Run: scp from Windows or update_price_history.py${NC}"
else
echo -e "${GREEN}✅ Price cache OK: $CACHE_COUNT files${NC}"
fi
# Step 5: Verify Saxo credentials in .env
echo ""
echo -e "${YELLOW}🔑 Step 5/7: Verifying Saxo credentials...${NC}"
# Check if .env exists
if [ ! -f ".env" ]; then
echo -e "${RED}❌ Error: .env file not found${NC}"
echo -e "${YELLOW} Copy .env.production.example to .env and fill in your credentials:${NC}"
echo -e " cp .env.production.example .env"
echo -e " nano .env # Edit and add your Saxo credentials"
exit 1
fi
# Check Saxo variables
SAXO_ENV=$(grep "^SAXO_ENVIRONMENT=" .env 2>/dev/null | cut -d'=' -f2 || echo "")
SAXO_LIVE_ID=$(grep "^SAXO_LIVE_CLIENT_ID=" .env 2>/dev/null | cut -d'=' -f2 || echo "")
SAXO_LIVE_SECRET=$(grep "^SAXO_LIVE_CLIENT_SECRET=" .env 2>/dev/null | cut -d'=' -f2 || echo "")
if [ -z "$SAXO_ENV" ]; then
echo -e "${RED}⚠️ Warning: SAXO_ENVIRONMENT not set in .env${NC}"
echo -e "${YELLOW} Add: SAXO_ENVIRONMENT=sim (or live for production)${NC}"
fi
if [ "$SAXO_ENV" = "live" ]; then
if [ -z "$SAXO_LIVE_ID" ] || [ "$SAXO_LIVE_ID" = "your_live_client_id_here" ]; then
echo -e "${RED}❌ Error: SAXO_LIVE_CLIENT_ID not configured for live environment${NC}"
echo -e "${YELLOW} Edit .env and add your real Saxo Live credentials${NC}"
exit 1
fi
if [ -z "$SAXO_LIVE_SECRET" ] || [ "$SAXO_LIVE_SECRET" = "your_live_client_secret_here" ]; then
echo -e "${RED}❌ Error: SAXO_LIVE_CLIENT_SECRET not configured for live environment${NC}"
echo -e "${YELLOW} Edit .env and add your real Saxo Live credentials${NC}"
exit 1
fi
echo -e "${GREEN}✅ Saxo credentials: LIVE mode (real trading!)${NC}"
echo -e "${YELLOW} ⚠️ WARNING: Using real Saxo account - trades will be executed!${NC}"
else
echo -e "${GREEN}✅ Saxo credentials: SIM mode (safe testing)${NC}"
fi
# Step 6: Docker rebuild or restart
echo ""
if [ $SKIP_BUILD -eq 1 ]; then
echo -e "${YELLOW}🔄 Step 6/7: Restarting Docker (skip build)...${NC}"
docker-compose restart
else
echo -e "${YELLOW}🐳 Step 6/7: Rebuilding and restarting Docker...${NC}"
# Stop old containers
docker-compose down
# Clean orphaned containers from non-prod compose
docker stop smartfolio_api_1 2>/dev/null || true
docker rm smartfolio_api_1 2>/dev/null || true
# Build and start
docker-compose up -d --build
fi
echo -e "${GREEN}✅ Docker containers started${NC}"
# Step 7: Health check
echo ""
echo -e "${YELLOW}🏥 Step 7/7: Waiting for services to be healthy...${NC}"
sleep 10
# Check Docker containers
if docker ps | grep -q "smartfolio-api"; then
echo -e "${GREEN}✅ Container smartfolio-api: running${NC}"
else
echo -e "${RED}❌ Container smartfolio-api: not found${NC}"
docker-compose logs --tail 50
exit 1
fi
# Check API health
echo -n " Testing API endpoint... "
if curl -sf http://localhost:8080/docs > /dev/null 2>&1; then
echo -e "${GREEN}✅${NC}"
else
echo -e "${RED}❌ Failed${NC}"
echo -e "${YELLOW} API may still be starting up. Check logs with:${NC}"
echo -e " docker-compose logs -f"
fi
# Check scheduler
echo -n " Testing scheduler... "
SCHEDULER_STATUS=$(curl -sf http://localhost:8080/api/scheduler/health 2>/dev/null | grep -o '"enabled":[^,]*' | cut -d':' -f2)
if [ "$SCHEDULER_STATUS" == "true" ]; then
echo -e "${GREEN}✅ Enabled${NC}"
else
echo -e "${YELLOW}⚠️ Unknown${NC}"
fi
# Final summary
echo ""
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GREEN}✅ Deployment Complete!${NC}"
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
echo -e "${YELLOW}📊 Quick Access:${NC}"
echo " • Dashboard: http://$(hostname -I | awk '{print $1}'):8080/dashboard.html"
echo " • API Docs: http://$(hostname -I | awk '{print $1}'):8080/docs"
echo " • Risk: http://$(hostname -I | awk '{print $1}'):8080/risk-dashboard.html"
echo ""
echo -e "${YELLOW}🔍 Useful Commands:${NC}"
echo " • View logs: docker-compose logs -f"
echo " • Check status: docker-compose ps"
echo " • Restart: ./deploy.sh --skip-build"
echo " • Full redeploy: ./deploy.sh --force"
echo ""