|
|
|
|
@@ -261,17 +261,20 @@ jobs:
|
|
|
|
|
PREV_DIGEST_TOKEN_SECRET=""
|
|
|
|
|
PREV_VAPID_PUBLIC_KEY=""
|
|
|
|
|
PREV_VAPID_PRIVATE_KEY=""
|
|
|
|
|
PREV_REFRESH_TOKEN_EXPIRY_DAYS=""
|
|
|
|
|
if [ -f .env ]; then
|
|
|
|
|
PREV_SECRET_KEY=$(grep '^SECRET_KEY=' .env | head -n1 | cut -d '=' -f2- || true)
|
|
|
|
|
PREV_DIGEST_TOKEN_SECRET=$(grep '^DIGEST_TOKEN_SECRET=' .env | head -n1 | cut -d '=' -f2- || true)
|
|
|
|
|
PREV_VAPID_PUBLIC_KEY=$(grep '^VAPID_PUBLIC_KEY=' .env | head -n1 | cut -d '=' -f2- || true)
|
|
|
|
|
PREV_VAPID_PRIVATE_KEY=$(grep '^VAPID_PRIVATE_KEY=' .env | head -n1 | cut -d '=' -f2- || true)
|
|
|
|
|
PREV_REFRESH_TOKEN_EXPIRY_DAYS=$(grep '^REFRESH_TOKEN_EXPIRY_DAYS=' .env | head -n1 | cut -d '=' -f2- || true)
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
SECRET_KEY_VALUE="${{ secrets.PROD_SECRET_KEY }}"
|
|
|
|
|
DIGEST_TOKEN_SECRET_VALUE="${{ secrets.PROD_DIGEST_TOKEN_SECRET }}"
|
|
|
|
|
VAPID_PUBLIC_KEY_VALUE="${{ secrets.PROD_VAPID_PUBLIC_KEY }}"
|
|
|
|
|
VAPID_PRIVATE_KEY_VALUE="${{ secrets.PROD_VAPID_PRIVATE_KEY }}"
|
|
|
|
|
REFRESH_TOKEN_EXPIRY_DAYS_VALUE="${{ secrets.PROD_REFRESH_TOKEN_EXPIRY_DAYS }}"
|
|
|
|
|
|
|
|
|
|
if [ -z "$SECRET_KEY_VALUE" ]; then
|
|
|
|
|
if [ -n "$PREV_SECRET_KEY" ]; then
|
|
|
|
|
@@ -301,10 +304,25 @@ jobs:
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ -z "$REFRESH_TOKEN_EXPIRY_DAYS_VALUE" ]; then
|
|
|
|
|
if [ -n "$PREV_REFRESH_TOKEN_EXPIRY_DAYS" ]; then
|
|
|
|
|
REFRESH_TOKEN_EXPIRY_DAYS_VALUE="$PREV_REFRESH_TOKEN_EXPIRY_DAYS"
|
|
|
|
|
else
|
|
|
|
|
REFRESH_TOKEN_EXPIRY_DAYS_VALUE="90"
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! printf '%s' "$REFRESH_TOKEN_EXPIRY_DAYS_VALUE" | grep -Eq '^[0-9]+$'; then
|
|
|
|
|
echo "REFRESH_TOKEN_EXPIRY_DAYS must be a positive integer, got: $REFRESH_TOKEN_EXPIRY_DAYS_VALUE"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
cat > .env << EOF
|
|
|
|
|
FRONTEND_URL=${{ secrets.PROD_FRONTEND_URL }}
|
|
|
|
|
BACKEND_HOST_PORT=${{ secrets.PROD_BACKEND_HOST_PORT }}
|
|
|
|
|
FRONTEND_HOST_PORT=${{ secrets.PROD_FRONTEND_HOST_PORT }}
|
|
|
|
|
SECRET_KEY=${SECRET_KEY_VALUE}
|
|
|
|
|
REFRESH_TOKEN_EXPIRY_DAYS=${{ secrets.PROD_REFRESH_TOKEN_EXPIRY_DAYS }}
|
|
|
|
|
REFRESH_TOKEN_EXPIRY_DAYS=${REFRESH_TOKEN_EXPIRY_DAYS_VALUE}
|
|
|
|
|
DIGEST_TOKEN_SECRET=${DIGEST_TOKEN_SECRET_VALUE}
|
|
|
|
|
VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY_VALUE}
|
|
|
|
|
VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY_VALUE}
|
|
|
|
|
@@ -316,7 +334,52 @@ jobs:
|
|
|
|
|
|
|
|
|
|
chmod 600 .env .rollback-meta
|
|
|
|
|
|
|
|
|
|
backend_host_port=$(grep '^BACKEND_HOST_PORT=' .env | head -n1 | cut -d '=' -f2- || true)
|
|
|
|
|
frontend_host_port=$(grep '^FRONTEND_HOST_PORT=' .env | head -n1 | cut -d '=' -f2- || true)
|
|
|
|
|
if [ -z "$backend_host_port" ]; then
|
|
|
|
|
backend_host_port="5001"
|
|
|
|
|
fi
|
|
|
|
|
if [ -z "$frontend_host_port" ]; then
|
|
|
|
|
frontend_host_port="4601"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
docker-compose down
|
|
|
|
|
|
|
|
|
|
wait_for_container_removal() {
|
|
|
|
|
container_name="$1"
|
|
|
|
|
attempts=0
|
|
|
|
|
while docker ps -a --format '{{.Names}}' | grep -qx "$container_name"; do
|
|
|
|
|
attempts=$((attempts + 1))
|
|
|
|
|
if [ "$attempts" -ge 12 ]; then
|
|
|
|
|
echo "Container ${container_name} still exists after waiting for teardown."
|
|
|
|
|
docker ps -a --filter "name=^${container_name}$"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
echo "Waiting for ${container_name} to be removed..."
|
|
|
|
|
sleep 5
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wait_for_port_release() {
|
|
|
|
|
port="$1"
|
|
|
|
|
attempts=0
|
|
|
|
|
while docker ps -a --format '{{.ID}} {{.Names}} {{.Ports}} {{.Status}}' | grep -E "(^|[[:space:]])0\.0\.0\.0:${port}->|:::${port}->" >/dev/null 2>&1; do
|
|
|
|
|
attempts=$((attempts + 1))
|
|
|
|
|
if [ "$attempts" -ge 12 ]; then
|
|
|
|
|
echo "Port ${port} is still allocated after teardown. Blocking container(s):"
|
|
|
|
|
docker ps -a --format '{{.ID}} {{.Names}} {{.Ports}} {{.Status}}' | grep -E "(^|[[:space:]])0\.0\.0\.0:${port}->|:::${port}->" || true
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
echo "Waiting for port ${port} to be released..."
|
|
|
|
|
sleep 5
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wait_for_container_removal chores-app-frontend-prod
|
|
|
|
|
wait_for_container_removal chores-app-backend-prod
|
|
|
|
|
wait_for_port_release "$frontend_host_port"
|
|
|
|
|
wait_for_port_release "$backend_host_port"
|
|
|
|
|
|
|
|
|
|
docker-compose pull
|
|
|
|
|
docker-compose up -d
|
|
|
|
|
|
|
|
|
|
@@ -326,18 +389,22 @@ jobs:
|
|
|
|
|
frontend_running=$(docker inspect -f '{{.State.Running}}' chores-app-frontend-prod 2>/dev/null || echo false)
|
|
|
|
|
|
|
|
|
|
backend_ok=false
|
|
|
|
|
if curl -fsS http://localhost:5001/version >/dev/null 2>&1; then
|
|
|
|
|
if curl -fsS "http://localhost:${backend_host_port}/version" >/dev/null 2>&1; then
|
|
|
|
|
backend_ok=true
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
frontend_ok=false
|
|
|
|
|
if curl -kfsS https://localhost/ >/dev/null 2>&1; then
|
|
|
|
|
if curl -kfsS "https://localhost:${frontend_host_port}/" >/dev/null 2>&1; then
|
|
|
|
|
frontend_ok=true
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ "$backend_running" != "true" ] || [ "$frontend_running" != "true" ] || [ "$backend_ok" != "true" ] || [ "$frontend_ok" != "true" ]; then
|
|
|
|
|
echo "Post-deploy health check failed."
|
|
|
|
|
docker-compose ps
|
|
|
|
|
echo "--- Backend logs (last 200 lines) ---"
|
|
|
|
|
docker logs --tail 200 chores-app-backend-prod || true
|
|
|
|
|
echo "--- Frontend logs (last 120 lines) ---"
|
|
|
|
|
docker logs --tail 120 chores-app-frontend-prod || true
|
|
|
|
|
|
|
|
|
|
if [ "${{ github.event.inputs.rollback_on_failed_healthcheck }}" = "true" ]; then
|
|
|
|
|
echo "Attempting rollback using predeploy-backup image tags..."
|
|
|
|
|
@@ -345,7 +412,7 @@ jobs:
|
|
|
|
|
docker tag git.ryankegel.com:3000/kegel/chores/frontend:predeploy-backup git.ryankegel.com:3000/kegel/chores/frontend:latest || true
|
|
|
|
|
docker-compose up -d
|
|
|
|
|
sleep 20
|
|
|
|
|
curl -fsS http://localhost:5001/version >/dev/null
|
|
|
|
|
curl -fsS "http://localhost:${backend_host_port}/version" >/dev/null
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
exit 1
|
|
|
|
|
|