From 09bd6312e308abd22a4db665e26ac9f0f5b5b8be Mon Sep 17 00:00:00 2001 From: evanpelle Date: Fri, 27 Jun 2025 16:39:05 -0700 Subject: [PATCH] Split build & deploy scripts (#1239) ## Description: Split deploy.sh into build.sh & deploy.sh (deploy only) build.sh builds & pushes the docker image deploy.sh copies the update.sh into machine, pulls the image, and runs it. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: evan --------- Co-authored-by: Scott Anderson --- .github/workflows/deploy.yml | 2 +- build-deploy.sh | 96 ++++++++++++++++++++++++++++++++ build.sh | 91 ++++++++++++++++++++++++++++++ deploy.sh | 104 +++++++++++++++-------------------- 4 files changed, 232 insertions(+), 61 deletions(-) create mode 100755 build-deploy.sh create mode 100755 build.sh diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e99413f03..d0909dd6e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -127,7 +127,7 @@ jobs: VERSION_TAG: latest run: | echo "::group::deploy.sh" - ./deploy.sh "$ENV" "$HOST" "$SUBDOMAIN" + ./build-deploy.sh "$ENV" "$HOST" "$SUBDOMAIN" echo "Deployment created in ${SECONDS} seconds" >> $GITHUB_STEP_SUMMARY echo "::endgroup::" - name: ⏳ Wait for deployment to start diff --git a/build-deploy.sh b/build-deploy.sh new file mode 100755 index 000000000..c008be0df --- /dev/null +++ b/build-deploy.sh @@ -0,0 +1,96 @@ +#!/bin/bash +# build-deploy.sh - Wrapper script that runs build.sh and deploy.sh in sequence +# This script maintains backward compatibility with the original build-deploy.sh + +set -e # Exit immediately if a command exits with a non-zero status + +# Function to print section headers +print_header() { + echo "======================================================" + echo "🚀 $1" + echo "======================================================" +} + +print_header "BUILD AND DEPLOY WRAPPER" +echo "This script will run build.sh and deploy.sh in sequence." +echo "You can also run them separately:" +echo " ./build.sh [prod|staging] [version_tag]" +echo " ./deploy.sh [prod|staging] [eu|nbg1|staging|masters] [version_tag] [subdomain] [--enable_basic_auth]" +echo "" + +# Check command line arguments +if [ $# -lt 3 ] || [ $# -gt 5 ]; then + echo "Error: Please specify environment, host, and subdomain" + echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [subdomain] [--enable_basic_auth]" + exit 1 +fi + +# Validate first argument (environment) +if [ "$1" != "prod" ] && [ "$1" != "staging" ]; then + echo "Error: First argument must be either 'prod' or 'staging'" + echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [subdomain] [--enable_basic_auth]" + exit 1 +fi + +# Validate second argument (host) +if [ "$2" != "eu" ] && [ "$2" != "nbg1" ] && [ "$2" != "staging" ] && [ "$2" != "masters" ]; then + echo "Error: Second argument must be either 'eu', 'nbg1', 'staging', or 'masters'" + echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [subdomain] [--enable_basic_auth]" + exit 1 +fi + +# Validate third argument (subdomain) +if [ -z "$3" ]; then + echo "Error: Subdomain is required" + echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [subdomain] [--enable_basic_auth]" + exit 1 +fi + +# Generate version tag +VERSION_TAG=$(date +"%Y%m%d-%H%M%S") +echo "Generated version tag: $VERSION_TAG" + +# Extract arguments +ENV="$1" +HOST="$2" +SUBDOMAIN="$3" +ENABLE_BASIC_AUTH="" + +# Parse remaining arguments +shift 3 +while [[ $# -gt 0 ]]; do + case $1 in + --enable_basic_auth) + ENABLE_BASIC_AUTH="--enable_basic_auth" + shift + ;; + *) + echo "Error: Unknown argument: $1" + echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [subdomain] [--enable_basic_auth]" + exit 1 + ;; + esac +done + +# Step 1: Run build.sh +echo "Step 1: Running build.sh..." +./build.sh "$ENV" "$VERSION_TAG" + +if [ $? -ne 0 ]; then + echo "❌ Build failed. Stopping deployment." + exit 1 +fi + +echo "" +echo "Step 2: Running deploy.sh" +./deploy.sh "$ENV" "$HOST" "$VERSION_TAG" "$SUBDOMAIN" + +if [ $? -ne 0 ]; then + echo "❌ Deploy failed." + exit 1 +fi + +print_header "BUILD AND DEPLOY COMPLETED SUCCESSFULLY" +echo "✅ Both build and deploy operations completed successfully!" +echo "Version tag used: $VERSION_TAG" +echo "=======================================================" diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..a9719de73 --- /dev/null +++ b/build.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# build.sh - Build and upload Docker image to Docker Hub +# This script: +# 1. Builds and uploads the Docker image to Docker Hub with appropriate tag +# 2. Optionally saves container metadata to a file (if METADATA_FILE is provided as 3rd argument) + +set -e # Exit immediately if a command exits with a non-zero status + +# Parse command line arguments +DEPLOY_ENV="$1" +VERSION_TAG="$2" +METADATA_FILE="$3" + +# Set default metadata file if not provided +if [ -z "$METADATA_FILE" ]; then + METADATA_FILE="/tmp/build-metadata-$RANDOM.json" +fi + +# Check required arguments +if [ -z "$DEPLOY_ENV" ] || [ -z "$VERSION_TAG" ]; then + echo "Error: Please specify environment and version tag" + echo "Usage: $0 [prod|staging] [version_tag] [metadata_file]" + echo "Note: Provide metadata_file as third argument to save container metadata to a file" + exit 1 +fi + +# Validate environment argument +if [ "$DEPLOY_ENV" != "prod" ] && [ "$DEPLOY_ENV" != "staging" ]; then + echo "Error: First argument must be either 'prod' or 'staging'" + echo "Usage: $0 [prod|staging] [version_tag] [metadata_file]" + echo "Note: Provide metadata_file as third argument to save container metadata to a file" + exit 1 +fi + +print_header() { + echo "======================================================" + echo "🚀 ${1}" + echo "======================================================" +} + +# Load common environment variables first +if [ -f .env ]; then + echo "Loading common configuration from .env file..." + set -o allexport + source .env + set +o allexport +fi + +# Load environment-specific variables +if [ -f .env.$DEPLOY_ENV ]; then + echo "Loading $DEPLOY_ENV-specific configuration from .env.$DEPLOY_ENV file..." + set -o allexport + source .env.$DEPLOY_ENV + set +o allexport +fi + +# Check required environment variables for build +if [ -z "$DOCKER_USERNAME" ] || [ -z "$DOCKER_REPO" ]; then + echo "Error: DOCKER_USERNAME or DOCKER_REPO not defined in .env file or environment" + exit 1 +fi + +DOCKER_IMAGE="${DOCKER_USERNAME}/${DOCKER_REPO}:${VERSION_TAG}" + +# Build and upload Docker image to Docker Hub +echo "Environment: ${DEPLOY_ENV}" +echo "Using version tag: $VERSION_TAG" +echo "Docker repository: $DOCKER_REPO" +echo "Metadata file: $METADATA_FILE" + +# Get Git commit for build info +GIT_COMMIT=$(git rev-parse HEAD 2> /dev/null || echo "unknown") +echo "Git commit: $GIT_COMMIT" + +docker buildx build \ + --platform linux/amd64 \ + --build-arg GIT_COMMIT=$GIT_COMMIT \ + --metadata-file $METADATA_FILE \ + -t $DOCKER_IMAGE \ + --push \ + . + +if [ $? -ne 0 ]; then + echo "❌ Docker build failed." + exit 1 +fi + +echo "✅ Docker image built and pushed successfully." +echo "Image: $DOCKER_IMAGE" + +print_header "BUILD COMPLETED SUCCESSFULLY ${DOCKER_IMAGE}" diff --git a/deploy.sh b/deploy.sh index dd8210778..b0aadfc47 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,9 +1,8 @@ #!/bin/bash -# deploy.sh - Complete deployment script for Hetzner with Docker Hub and R2 +# deploy.sh - Deploy application to Hetzner server # This script: -# 1. Builds and uploads the Docker image to Docker Hub with appropriate tag -# 2. Copies the update script to Hetzner server -# 3. Executes the update script on the Hetzner server +# 1. Copies the update script to Hetzner server +# 2. Executes the update script on the Hetzner server set -e # Exit immediately if a command exits with a non-zero status @@ -28,27 +27,6 @@ done # Restore positional parameters set -- "${POSITIONAL_ARGS[@]}" -# Check command line arguments -if [ $# -lt 2 ] || [ $# -gt 3 ]; then - echo "Error: Please specify environment and host, with optional subdomain" - echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [subdomain] [--enable_basic_auth]" - exit 1 -fi - -# Validate first argument (environment) -if [ "$1" != "prod" ] && [ "$1" != "staging" ]; then - echo "Error: First argument must be either 'prod' or 'staging'" - echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [subdomain] [--enable_basic_auth]" - exit 1 -fi - -# Validate second argument (host) -if [ "$2" != "eu" ] && [ "$2" != "nbg1" ] && [ "$2" != "staging" ] && [ "$2" != "masters" ]; then - echo "Error: Second argument must be either 'eu', 'nbg1', 'staging', or 'masters'" - echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [subdomain] [--enable_basic_auth]" - exit 1 -fi - # Function to print section headers print_header() { echo "======================================================" @@ -56,17 +34,34 @@ print_header() { echo "======================================================" } +# Check command line arguments +if [ $# -ne 4 ]; then + echo "Error: Please specify environment, host, version tag, and subdomain" + echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [version_tag] [subdomain] [--enable_basic_auth]" + exit 1 +fi + +# Validate first argument (environment) +if [ "$1" != "prod" ] && [ "$1" != "staging" ]; then + echo "Error: First argument must be either 'prod' or 'staging'" + echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [version_tag] [subdomain] [--enable_basic_auth]" + exit 1 +fi + +# Validate second argument (host) +if [ "$2" != "eu" ] && [ "$2" != "nbg1" ] && [ "$2" != "staging" ] && [ "$2" != "masters" ]; then + echo "Error: Second argument must be either 'eu', 'nbg1', 'staging', or 'masters'" + echo "Usage: $0 [prod|staging] [eu|nbg1|staging|masters] [version_tag] [subdomain] [--enable_basic_auth]" + exit 1 +fi + ENV=$1 HOST=$2 -SUBDOMAIN=$3 # Optional third argument for custom subdomain +VERSION_TAG=$3 +SUBDOMAIN=$4 -# Set subdomain - use the custom subdomain if provided, otherwise use REGION -if [ -n "$SUBDOMAIN" ]; then - echo "Using custom subdomain: $SUBDOMAIN" -else - SUBDOMAIN=$HOST - echo "Using host as subdomain: $SUBDOMAIN" -fi +# Set subdomain - use the provided subdomain +echo "Using subdomain: $SUBDOMAIN" # Load common environment variables first if [ -f .env ]; then @@ -80,6 +75,14 @@ if [ -f .env.$ENV ]; then export $(grep -v '^#' .env.$ENV | xargs) fi +# Check required environment variables for deployment +if [ -z "$DOCKER_USERNAME" ] || [ -z "$DOCKER_REPO" ]; then + echo "Error: DOCKER_USERNAME or DOCKER_REPO not defined in .env file or environment" + exit 1 +fi + +DOCKER_IMAGE="${DOCKER_USERNAME}/${DOCKER_REPO}:${VERSION_TAG}" + if [ "$HOST" == "staging" ]; then print_header "DEPLOYING TO STAGING HOST" SERVER_HOST=$SERVER_HOST_STAGING @@ -121,43 +124,22 @@ REMOTE_USER="openfront" REMOTE_UPDATE_PATH="/home/$REMOTE_USER" REMOTE_UPDATE_SCRIPT="$REMOTE_UPDATE_PATH/update-openfront.sh" # Where to place the script on server -VERSION_TAG=$(date +"%Y%m%d-%H%M%S") -DOCKER_IMAGE="${DOCKER_USERNAME}/${DOCKER_REPO}:${VERSION_TAG}" - # Check if update script exists if [ ! -f "$UPDATE_SCRIPT" ]; then echo "Error: Update script $UPDATE_SCRIPT not found!" exit 1 fi -# Step 1: Build and upload Docker image to Docker Hub -print_header "STEP 1: Building and uploading Docker image to Docker Hub" +# Display deployment information +print_header "DEPLOYMENT INFORMATION" echo "Environment: ${ENV}" echo "Host: ${HOST}" echo "Subdomain: ${SUBDOMAIN}" -echo "Using version tag: $VERSION_TAG" -echo "Docker repository: $DOCKER_REPO" +echo "Docker Image: $DOCKER_IMAGE" +echo "Target Server: $SERVER_HOST" -# Get Git commit for build info -GIT_COMMIT=$(git rev-parse HEAD 2> /dev/null || echo "unknown") -echo "Git commit: $GIT_COMMIT" - -docker buildx build \ - --platform linux/amd64 \ - --build-arg GIT_COMMIT=$GIT_COMMIT \ - -t $DOCKER_IMAGE \ - --push \ - . - -if [ $? -ne 0 ]; then - echo "❌ Docker build failed. Stopping deployment." - exit 1 -fi - -echo "✅ Docker image built and pushed successfully." - -# Step 2: Copy update script to Hetzner server -print_header "STEP 2: Copying update script to server" +# Copy update script to Hetzner server +print_header "COPYING UPDATE SCRIPT TO SERVER" echo "Target: $REMOTE_USER@$SERVER_HOST" # Make sure the update script is executable @@ -175,6 +157,8 @@ fi # when multiple deployments are happening at the same time. ENV_FILE="${REMOTE_UPDATE_PATH}/${SUBDOMAIN}-${RANDOM}.env" +print_header "EXECUTING UPDATE SCRIPT ON SERVER" + ssh -i $SSH_KEY $REMOTE_USER@$SERVER_HOST "chmod +x $REMOTE_UPDATE_SCRIPT && \ cat > $ENV_FILE << 'EOL' GAME_ENV=$ENV