@@ -208,10 +208,229 @@ jobs:
208208 key : ${{ secrets.HOSTINGER }}
209209 port : ${{ secrets.HOSTINGER_PORT }}
210210 envs : GHCR_OWNER_LC,APP_NAME
211+ script_stop : all
211212 script : |
212- set -e
213- echo "Starting deployment with image: ghcr.io/${GHCR_OWNER_LC}/${APP_NAME}:latest"
213+ # Download and setup deploy script if not present
214+ DEPLOY_SCRIPT="/opt/espacogeek/deploy.sh"
215+
216+ if [ ! -f "$DEPLOY_SCRIPT" ]; then
217+ echo "Downloading deploy script..."
218+ mkdir -p "$(dirname "$DEPLOY_SCRIPT")"
219+ # You can download from a specific release or use inline
220+ cat > "$DEPLOY_SCRIPT" << 'DEPLOY_SCRIPT_EOF'
221+ #!/bin/bash
222+
223+ set -euo pipefail
224+
225+ RED='\033[0;31m'
226+ GREEN='\033[0;32m'
227+ YELLOW='\033[1;33m'
228+ BLUE='\033[0;34m'
229+ NC='\033[0m'
230+
231+ log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
232+ log_success() { echo -e "${GREEN}[✓]${NC} $*"; }
233+ log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
234+ log_error() { echo -e "${RED}[✗]${NC} $*"; }
235+
236+ trap 'on_error' ERR
237+ on_error() {
238+ local exit_code=$?
239+ if [ $exit_code -ne 0 ]; then
240+ log_error "Deployment failed with exit code $exit_code"
241+ log_warn "Attempting rollback..."
242+ rollback_deployment
243+ fi
244+ }
245+
246+ GHCR_OWNER_LC="${1:-}"
247+ APP_NAME="${2:-}"
248+ IMAGE_TAG="${3:-latest}"
249+ ENV_FILE="${4:-.env.espacogeek}"
250+ CONTAINER_NAME="espacogeek"
251+ BACKUP_DIR="${HOME}/espacogeek-backups"
252+ OLD_CONTAINER_BACKUP="${CONTAINER_NAME}-old"
253+ TIMESTAMP=$(date +%Y%m%d_%H%M%S)
254+
255+ if [ -z "$GHCR_OWNER_LC" ] || [ -z "$APP_NAME" ]; then
256+ log_error "Usage: $0 <GHCR_OWNER_LC> <APP_NAME> [IMAGE_TAG] [ENV_FILE]"
257+ exit 1
258+ fi
259+
260+ IMAGE="ghcr.io/${GHCR_OWNER_LC}/${APP_NAME}:${IMAGE_TAG}"
261+
262+ container_exists() { docker ps -a --format '{{.Names}}' | grep -q "^${1}$"; }
263+ container_running() { docker ps --format '{{.Names}}' | grep -q "^${1}$"; }
264+
265+ backup_old_container() {
266+ if ! container_exists "$CONTAINER_NAME"; then
267+ log_info "No existing container to backup"
268+ return 0
269+ fi
270+ log_info "Creating backup of old container..."
271+ mkdir -p "$BACKUP_DIR"
272+ BACKUP_FILE="${BACKUP_DIR}/${CONTAINER_NAME}_backup_${TIMESTAMP}.tar"
273+ log_info "Exporting container to ${BACKUP_FILE}..."
274+ if docker export "$CONTAINER_NAME" > "$BACKUP_FILE"; then
275+ log_success "Container backup created: ${BACKUP_FILE}"
276+ else
277+ log_error "Failed to backup container"
278+ return 1
279+ fi
280+ ls -t "${BACKUP_DIR}/${CONTAINER_NAME}_backup_"*.tar 2>/dev/null | tail -n +6 | xargs rm -f 2>/dev/null || true
281+ }
282+
283+ rename_old_container() {
284+ if ! container_exists "$CONTAINER_NAME"; then
285+ log_info "No old container to rename"
286+ return 0
287+ fi
288+ log_info "Renaming old container..."
289+ if container_running "$CONTAINER_NAME"; then
290+ log_info "Stopping old container..."
291+ docker stop "$CONTAINER_NAME" || log_warn "Failed to stop container"
292+ fi
293+ if docker rename "$CONTAINER_NAME" "${OLD_CONTAINER_BACKUP}" 2>/dev/null; then
294+ log_success "Old container renamed to ${OLD_CONTAINER_BACKUP}"
295+ else
296+ log_warn "Could not rename old container"
297+ fi
298+ }
299+
300+ pull_new_image() {
301+ log_info "Pulling new image: ${IMAGE}..."
302+ if docker pull "$IMAGE"; then
303+ log_success "Image pulled successfully"
304+ return 0
305+ else
306+ log_error "Failed to pull image"
307+ return 1
308+ fi
309+ }
310+
311+ start_new_container() {
312+ log_info "Starting new container..."
313+ if ! docker run -d --name "$CONTAINER_NAME" -p 8080:8080 --restart unless-stopped --env-file "$ENV_FILE" "$IMAGE"; then
314+ log_error "Failed to start container"
315+ return 1
316+ fi
317+ log_success "Container started with ID: $(docker ps --filter name=$CONTAINER_NAME -q)"
318+ }
319+
320+ validate_container_health() {
321+ local max_attempts=30
322+ local attempt=1
323+ log_info "Validating container health (max ${max_attempts} attempts)..."
324+ while [ $attempt -le $max_attempts ]; do
325+ if container_running "$CONTAINER_NAME"; then
326+ local status=$(docker inspect "$CONTAINER_NAME" --format='{{.State.Status}}')
327+ if [ "$status" = "running" ]; then
328+ if docker exec "$CONTAINER_NAME" wget -q -O- http://localhost:8080/actuator/health &>/dev/null 2>&1 || docker exec "$CONTAINER_NAME" curl -s http://localhost:8080/actuator/health &>/dev/null 2>&1; then
329+ log_success "Container is healthy"
330+ return 0
331+ fi
332+ else
333+ log_warn "Container status is: $status"
334+ fi
335+ fi
336+ log_info "Waiting... (attempt ${attempt}/${max_attempts})"
337+ sleep 2
338+ attempt=$((attempt + 1))
339+ done
340+ log_error "Container failed health check"
341+ return 1
342+ }
343+
344+ cleanup_old_container() {
345+ log_info "Cleaning up old container..."
346+ if container_exists "${OLD_CONTAINER_BACKUP}"; then
347+ log_info "Removing backed-up container: ${OLD_CONTAINER_BACKUP}"
348+ if docker rm -f "${OLD_CONTAINER_BACKUP}"; then
349+ log_success "Old container removed"
350+ else
351+ log_warn "Could not remove old container"
352+ fi
353+ fi
354+ }
355+
356+ rollback_deployment() {
357+ log_warn "Starting rollback procedure..."
358+ if container_exists "$CONTAINER_NAME"; then
359+ log_info "Stopping new container..."
360+ docker stop "$CONTAINER_NAME" 2>/dev/null || true
361+ docker rm "$CONTAINER_NAME" 2>/dev/null || true
362+ fi
363+ if container_exists "${OLD_CONTAINER_BACKUP}"; then
364+ log_info "Restoring old container from backup: ${OLD_CONTAINER_BACKUP}"
365+ if docker rename "${OLD_CONTAINER_BACKUP}" "$CONTAINER_NAME" 2>/dev/null; then
366+ if docker start "$CONTAINER_NAME"; then
367+ log_success "Rollback successful: Old container restored"
368+ return 0
369+ else
370+ log_error "Failed to start rolled-back container"
371+ return 1
372+ fi
373+ else
374+ log_error "Failed to rename backed-up container"
375+ return 1
376+ fi
377+ else
378+ log_error "No backed-up container available for rollback"
379+ return 1
380+ fi
381+ }
382+
383+ show_container_status() {
384+ log_info "=== Container Status ==="
385+ docker ps -a --filter name="$CONTAINER_NAME" --filter name="${OLD_CONTAINER_BACKUP}" || log_info "No containers found"
386+ log_info "======================="
387+ }
388+
389+ show_container_logs() {
390+ log_info "=== Container Logs (last 20 lines) ==="
391+ if container_exists "$CONTAINER_NAME"; then
392+ docker logs --tail 20 "$CONTAINER_NAME" || log_info "No logs available"
393+ fi
394+ log_info "======================================="
395+ }
396+
397+ log_info "Starting deployment of ${APP_NAME}:${IMAGE_TAG}"
398+ log_info "Container name: ${CONTAINER_NAME}"
399+ log_info "Image: ${IMAGE}"
400+ log_info "Environment file: ${ENV_FILE}"
401+ log_info ""
402+
403+ if [ ! -f "$ENV_FILE" ]; then
404+ log_error "Environment file not found: ${ENV_FILE}"
405+ exit 1
406+ fi
407+ log_success "Environment file found"
408+
409+ backup_old_container || exit 1
410+ rename_old_container || exit 1
411+ pull_new_image || exit 1
412+ start_new_container || exit 1
214413
414+ if ! validate_container_health; then
415+ log_error "Health check failed, initiating rollback..."
416+ rollback_deployment || exit 1
417+ exit 1
418+ fi
419+
420+ cleanup_old_container
421+
422+ log_success ""
423+ log_success "=== DEPLOYMENT SUCCESSFUL ==="
424+ show_container_status
425+ show_container_logs
426+ log_success "============================="
427+
428+ rm -f "$ENV_FILE"
429+ DEPLOY_SCRIPT_EOF
430+ chmod +x "$DEPLOY_SCRIPT"
431+ fi
432+
433+ # Create environment file
215434 cat > .env.espacogeek << 'ENVEOF'
216435 SPRING_DATASOURCE_URL=${{ secrets.SPRING_DATASOURCE_URL }}
217436 SPRING_DATASOURCE_USERNAME=${{ secrets.SPRING_DATASOURCE_USERNAME }}
@@ -229,31 +448,12 @@ jobs:
229448 FRONTEND_URL=${{ secrets.FRONTEND_URL }}
230449 ENVEOF
231450
451+ # Login to GHCR
232452 echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u "${{ secrets.GHCR_USER }}" --password-stdin
233453
234- echo "Pulling image from GHCR..."
235- docker pull ghcr.io/${GHCR_OWNER_LC}/${APP_NAME}:latest || { echo "Failed to pull image"; exit 1; }
236-
237- echo "Stopping and removing old container..."
238- docker stop espacogeek || true
239- docker rm espacogeek || true
240-
241- echo "Starting new container..."
242- if ! docker run -d --name espacogeek \
243- -p 8080:8080 \
244- --restart unless-stopped \
245- --env-file .env.espacogeek \
246- ghcr.io/${GHCR_OWNER_LC}/${APP_NAME}:latest; then
247- echo "Failed to start container"
248- docker ps -a
249- docker logs espacogeek || true
250- rm -f .env.espacogeek
251- exit 1
252- fi
454+ # Execute deployment script
455+ "$DEPLOY_SCRIPT" "${GHCR_OWNER_LC}" "${APP_NAME}" "latest" ".env.espacogeek"
253456
254- echo "Container started successfully"
255- docker ps -a
256- rm -f .env.espacogeek
257457
258458 # Final summary with generated tags
259459 - name : Summary
0 commit comments