ci: implement 3-stage deployment pipeline with semantic-release

This commit is contained in:
badblocks 2025-07-31 19:18:43 -07:00
parent af8d86dedb
commit d4d84ad0db
No known key found for this signature in database
13 changed files with 271 additions and 169 deletions

View file

@ -1,6 +1,6 @@
services:
portfolio:
image: badbl0cks/portfolio:${IMAGE_TAG:-stable}
image: ${IMAGE_NAME:-portfolio:latest}
# image: ghcr.io/xe/x/httpdebug
# entrypoint: ["/ko-app/httpdebug", "--bind", ":3000"]
container_name: portfolio-${RELEASE_TYPE}-${DEPLOYMENT_COLOR}
@ -10,7 +10,7 @@ services:
- portfolio-${RELEASE_TYPE}
expose:
- "3000"
env_file:
env_file:
- .env
volumes:
- ./data:/app/data
@ -21,7 +21,16 @@ services:
- "deployment.release_type=${RELEASE_TYPE}"
user: "1000:1000"
healthcheck:
test: ["CMD", "curl", "-f", "-s", "--max-time", "5", "http://localhost:3000/api/health"]
test:
[
"CMD",
"curl",
"-f",
"-s",
"--max-time",
"5",
"http://localhost:3000/api/health",
]
interval: 30s
timeout: 15s
retries: 3
@ -47,7 +56,8 @@ services:
aliases:
- wireguard-${RELEASE_TYPE}
healthcheck:
test: ["CMD", "ping", "-c", "1", "-W", "3", "$$NUXT_ANDROID_SMS_GATEWAY_IP"]
test:
["CMD", "ping", "-c", "1", "-W", "3", "$$NUXT_ANDROID_SMS_GATEWAY_IP"]
interval: 30s
timeout: 15s
retries: 3

View file

@ -10,6 +10,9 @@ else
exit 1
fi
# Validate common required environment variables
require_var "DEPLOY_HOST"
readonly HAPROXY_BASE_DIR="/srv/haproxy"
readonly HAPROXY_CONFIGS_DIR="${HAPROXY_BASE_DIR}/configs"
readonly HAPROXY_COMPOSE_FILE="${HAPROXY_BASE_DIR}/docker-compose.yml"

View file

@ -9,14 +9,12 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/common-lib.sh"
# Validate required environment variables
require_var "DOCKER_HOST"
require_var "REPO_PROJECT_PATH"
require_var "REPO_NAME_ONLY"
require_var "REPO"
require_var "IMAGE_TAR"
require_var "PROD"
require_var "DOMAIN"
require_var "WIREGUARD_ENDPOINT_HOST"
require_var "REPO_PROJECT_PATH"
require_var "DEPLOY_HOST"
validate_deployment_env
@ -76,10 +74,18 @@ echo "DEPLOYMENT_COLOR=\"${NEW_COLOR}\"" >> .env
echo "RELEASE_TYPE=\"${RELEASE_TYPE}\"" >> .env
echo "WIREGUARD_ENDPOINT_IP=\"${WIREGUARD_ENDPOINT_IP}\"" >> .env
# Set computed image name based on release type
if [ "$RELEASE_TYPE" = "staging" ]; then
IMAGE_NAME="portfolio-dev:${IMAGE_TAG}"
else
IMAGE_NAME="portfolio:${IMAGE_TAG}"
fi
echo "IMAGE_NAME=\"${IMAGE_NAME}\"" >> .env
echo "📋 Copying deployment files..."
scp deploy/docker-compose.yml deploy/haproxy.cfg .env deploy:"${NEW_RELEASE_PATH}/"
echo "🐳 Loading Docker image..."
echo "🐳 Loading Docker image (${IMAGE_TAR})..."
docker load -i "${IMAGE_TAR}"
PROJECT_NAME=$(get_project_name "$NEW_COLOR")

View file

@ -1,49 +0,0 @@
#!/bin/bash
set -euo pipefail
# Generate Docker tags based on git ref and environment
# Usage: ./generate-docker-tags.sh IMAGE_BASE GIT_SHA GIT_REF PROD
if [ $# -ne 4 ]; then
echo "Error: Invalid number of arguments" > /dev/stderr
echo "Usage: $0 IMAGE_BASE GIT_SHA GIT_REF PROD" > /dev/stderr
exit 1
fi
IMAGE_BASE="$1"
GIT_SHA="$2"
GIT_REF="$3"
PROD="$4"
# Validate inputs
if [ -z "$IMAGE_BASE" ] || [ -z "$GIT_SHA" ]; then
echo "Error: IMAGE_BASE and GIT_SHA cannot be empty" > /dev/stderr
exit 1
fi
# Always include SHA tags
echo "${IMAGE_BASE}:sha-${GIT_SHA:0:7}"
echo "${IMAGE_BASE}:sha-${GIT_SHA}"
# Handle version tags
if [[ "$GIT_REF" =~ ^refs/tags/v([0-9]+)\.([0-9]+)\.([0-9]+)(-.*)?$ ]]; then
MAJOR="${BASH_REMATCH[1]}"
MINOR="${BASH_REMATCH[2]}"
PATCH="${BASH_REMATCH[3]}"
PRERELEASE="${BASH_REMATCH[4]}"
if [[ -z "$PRERELEASE" ]] && [[ "$PROD" == "true" ]]; then
echo "${IMAGE_BASE}:latest"
echo "${IMAGE_BASE}:stable"
[[ "$MAJOR" -gt 0 ]] && echo "${IMAGE_BASE}:v${MAJOR}"
echo "${IMAGE_BASE}:v${MAJOR}.${MINOR}"
echo "${IMAGE_BASE}:v${MAJOR}.${MINOR}.${PATCH}"
else
echo "${IMAGE_BASE}:latest-staging"
echo "${IMAGE_BASE}:staging"
echo "${IMAGE_BASE}:v${MAJOR}.${MINOR}.${PATCH}-prerelease"
fi
elif [[ "$PROD" == "false" ]]; then
echo "${IMAGE_BASE}:latest-staging"
echo "${IMAGE_BASE}:staging"
fi

View file

@ -1,40 +0,0 @@
#!/bin/bash
set -euo pipefail
# Parse repository name and generate project paths
# Usage: ./parse-repository-name.sh GITHUB_REPOSITORY
if [ $# -eq 0 ]; then
echo "Error: No repository name provided" > /dev/stderr
echo "Usage: $0 GITHUB_REPOSITORY" > /dev/stderr
exit 1
fi
GITHUB_REPOSITORY="$1"
echo "GITHUB_REPOSITORY: $GITHUB_REPOSITORY" > /dev/stderr
if [[ "$GITHUB_REPOSITORY" == *".git" ]]; then
if [[ "$GITHUB_REPOSITORY" == "https://"* ]]; then
echo "GITHUB_REPOSITORY ends in .git and is an HTTPS URI" > /dev/stderr
REPO=$(echo "$GITHUB_REPOSITORY" | sed 's/\.git$//' | cut -d'/' -f4-5 | sed 's/[^a-zA-Z0-9\/-]/-/g')
elif [[ "$GITHUB_REPOSITORY" == "git@"* ]]; then
echo "GITHUB_REPOSITORY ends in .git and is an SSH URI" > /dev/stderr
REPO=$(echo "$GITHUB_REPOSITORY" | sed 's/\.git$//' | cut -d':' -f2 | sed 's/[^a-zA-Z0-9\/-]/-/g')
else
echo "GITHUB_REPOSITORY ends in .git and is not a URI" > /dev/stderr
REPO=$(echo "$GITHUB_REPOSITORY" | sed 's/\.git$//' | sed 's/[^a-zA-Z0-9\/-]/-/g')
fi
else
echo "GITHUB_REPOSITORY is not a URI" > /dev/stderr
REPO=$(echo "$GITHUB_REPOSITORY" | sed 's/[^a-zA-Z0-9\/-]/-/g')
fi
REPO_NAME_ONLY=$(echo "$REPO" | cut -d'/' -f2)
# Default path - will be modified by deployment script based on environment
REPO_PROJECT_PATH="/srv/${REPO_NAME_ONLY}"
# Output in format that can be sourced - using printf %q for proper escaping
printf "export REPO=%q\n" "$REPO"
printf "export REPO_NAME_ONLY=%q\n" "$REPO_NAME_ONLY"
printf "export REPO_PROJECT_PATH=%q\n" "$REPO_PROJECT_PATH"