From d28fb10360054fce2c52d1e336801e3db9a3696e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20West=C3=B6=C3=B6?= Date: Sat, 24 Jan 2026 17:42:08 +0100 Subject: [PATCH] Implement enhanced deployment script with auto-detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major Enhancement: Smart deployment with setup/update modes Features Added: ============== 1. **Auto-Detection Mode** (default) - Checks for .deployment-uuid file - First run → Setup mode (creates new deployment) - Subsequent runs → Update mode (updates existing) - No flags needed for common workflows 2. **Three Operation Modes:** A. Setup Mode (--setup or auto if no UUID) - Creates NEW application via POST /api/v1/applications - Saves UUID to .deployment-uuid file (git-ignored) - Sets up Gitea webhook (one-time) - Warns if UUID file already exists B. Update Mode (--update or auto if UUID exists) - Reads UUID from .deployment-uuid - Verifies application exists: GET /api/v1/applications/:uuid - Updates env vars: PATCH /api/v1/applications/:uuid/env - Triggers redeploy: POST /api/v1/applications/:uuid/deploy - GITEA_API_TOKEN not required (webhook already configured) C. Status Mode (--status) - Fetches current deployment details - Shows application info, status, domain - Provides monitoring commands 3. **UUID Persistence** - .deployment-uuid file stores application UUID - Enables stateful deployments - Prevents duplicate application creation - Git-ignored for security 4. **Improved User Experience** - Clear mode indication (SETUP/UPDATE/STATUS) - Verification step before overwriting existing deployment - Comprehensive error messages with actionable steps - Updated deployment-info.txt with mode information - Smart dependency checks (GITEA_TOKEN only for setup) 5. **Updated .gitignore** - Added .deployment-uuid to prevent accidental commits Usage Examples: =============== # First deployment (auto-detects no UUID → setup) ./deploy-to-apps.sh → Creates application, saves UUID, sets up webhook # Update after changing .env (auto-detects UUID → update) ./deploy-to-apps.sh → Updates env vars, triggers redeployment # Force new deployment ./deploy-to-apps.sh --setup # Check status ./deploy-to-apps.sh --status Benefits: ========= ✅ Idempotent - Can run multiple times safely ✅ Stateful - Remembers previous deployments ✅ User-friendly - Automatic mode detection ✅ Safe - Prevents duplicate applications ✅ Flexible - Supports multiple scenarios ✅ Clear feedback - Shows exactly what's happening Files Modified: =============== - deploy-to-apps.example.sh: Complete rewrite with 3 modes - .gitignore: Added .deployment-uuid - DEPLOYMENT_SCRIPT_PROPOSAL.md: Full design document Migration for Existing Users: ============================== If you already deployed with the old script: 1. Find your UUID: curl -H "X-API-Key: $SAAC_API_KEY" $SAAC_API/applications 2. Save it: echo "your-uuid" > .deployment-uuid 3. Run updates: ./deploy-to-apps.sh 🤖 Generated with Claude Code https://claude.com/claude-code Co-Authored-By: Claude --- .gitignore | 1 + DEPLOYMENT_SCRIPT_PROPOSAL.md | 279 +++++++++++++++++++++++++++ deploy-to-apps.example.sh | 349 ++++++++++++++++++++++++++++------ 3 files changed, 573 insertions(+), 56 deletions(-) create mode 100644 DEPLOYMENT_SCRIPT_PROPOSAL.md diff --git a/.gitignore b/.gitignore index 2b3101f..03d0174 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ deploy_key* deploy.sh deploy-to-apps.sh deployment-info.txt +.deployment-uuid diff --git a/DEPLOYMENT_SCRIPT_PROPOSAL.md b/DEPLOYMENT_SCRIPT_PROPOSAL.md new file mode 100644 index 0000000..a06e463 --- /dev/null +++ b/DEPLOYMENT_SCRIPT_PROPOSAL.md @@ -0,0 +1,279 @@ +# Deployment Script Enhancement Proposal + +## Problem Statement + +The current `deploy-to-apps.sh` script only handles initial deployment. Running it a second time will: +1. Attempt to create a duplicate application +2. Likely fail with "subdomain already exists" error +3. Have no way to update existing application's environment variables +4. Have no way to trigger redeployment + +## Solution: Setup vs Update Modes + +### Architecture + +``` +.deployment-uuid (git-ignored file storing application UUID) +deploy-to-apps.sh (enhanced script with mode detection) +``` + +### Script Modes + +#### 1. Auto-Detection (Default) +```bash +./deploy-to-apps.sh +``` +- Checks if `.deployment-uuid` exists +- **If NOT exists:** Run setup mode (first deployment) +- **If exists:** Run update mode (redeploy with new env vars) + +#### 2. Explicit Setup (Force New Deployment) +```bash +./deploy-to-apps.sh --setup +``` +- Creates NEW application +- Overwrites `.deployment-uuid` with new UUID +- Use case: Deploying to different subdomain/environment + +#### 3. Explicit Update +```bash +./deploy-to-apps.sh --update +``` +- Requires `.deployment-uuid` to exist +- Updates environment variables +- Triggers redeployment +- Fails if `.deployment-uuid` not found + +#### 4. Status Check +```bash +./deploy-to-apps.sh --status +``` +- Shows current deployment info +- Fetches live status from API +- Shows domain, deployment status, etc. + +--- + +## Implementation Details + +### File Structure + +```bash +.deployment-uuid # Single line: application UUID +deployment-info.txt # Human-readable deployment details +.gitignore # Must include .deployment-uuid +``` + +### Setup Mode Flow + +1. Check if subdomain already deployed (optional safety check) +2. Create application via `POST /api/v1/applications` +3. Save UUID to `.deployment-uuid` +4. Set up Gitea webhook (only once) +5. Save deployment info to `deployment-info.txt` +6. Show success message with next steps + +### Update Mode Flow + +1. Read UUID from `.deployment-uuid` +2. Verify application exists via `GET /api/v1/applications/:uuid` +3. Update environment variables via `PATCH /api/v1/applications/:uuid/env` +4. Trigger redeployment via `POST /api/v1/applications/:uuid/deploy` +5. Show redeployment progress + +### Status Mode Flow + +1. Read UUID from `.deployment-uuid` +2. Fetch application details via `GET /api/v1/applications/:uuid` +3. Display formatted status information + +--- + +## API Endpoints Used + +### Setup Mode +```bash +POST /api/v1/applications +→ Returns: { application_uuid, domain, webhook_url, ... } + +POST https://git.startanaicompany.com/api/v1/repos/{owner}/{repo}/hooks +→ Sets up Gitea webhook (one-time) +``` + +### Update Mode +```bash +GET /api/v1/applications/:uuid +→ Verify application exists + +PATCH /api/v1/applications/:uuid/env +→ Body: { "variables": { "COMPANY_NAME": "...", ... } } + +POST /api/v1/applications/:uuid/deploy +→ Triggers redeployment +``` + +### Status Mode +```bash +GET /api/v1/applications/:uuid +→ Returns application details and status +``` + +--- + +## Error Handling + +### Setup Mode Errors +- **Subdomain already exists:** Suggest using `--update` or different subdomain +- **API key invalid:** Show registration instructions +- **Gitea token invalid:** Show token generation instructions +- **Webhook already exists:** Warn but continue (non-fatal) + +### Update Mode Errors +- **No .deployment-uuid file:** Suggest running `--setup` first +- **Application not found:** UUID invalid or app deleted, suggest `--setup` +- **Environment variable validation failed:** Show which vars are invalid +- **Deployment failed:** Show error from API + +--- + +## Example Usage + +### First Deployment +```bash +$ ./deploy-to-apps.sh + +======================================== + AI Recruitment Site Deployment +======================================== +📝 Mode: SETUP (first deployment) +📦 Configuration: + Company: Acme Corp + Repository: git@git.startanaicompany.com:user/acme-recruit.git + Domain: https://acmerecruit.startanaicompany.com + +📝 Creating application on StartAnAiCompany server... +✅ Application created! + Application UUID: abc-123-def-456 + Domain: https://acmerecruit.startanaicompany.com + +💾 UUID saved to .deployment-uuid +🪝 Setting up deployment webhook... +✅ Webhook configured for automatic deployments + +======================================== + Deployment Complete! +======================================== +Your site will be available in 2-3 minutes. + +Next runs will automatically UPDATE this deployment. +To deploy a new site, use: ./deploy-to-apps.sh --setup +``` + +### Update Deployment (Changed Company Name) +```bash +$ ./deploy-to-apps.sh + +======================================== + AI Recruitment Site Deployment +======================================== +📝 Mode: UPDATE (existing deployment) +📦 Configuration: + Application UUID: abc-123-def-456 + Company: New Company Name (CHANGED) + Domain: https://acmerecruit.startanaicompany.com + +🔄 Updating environment variables... +✅ Environment variables updated (8 variables) + +🚀 Triggering redeployment... +✅ Deployment triggered + +======================================== + Update Complete! +======================================== +Your changes will be live in 2-3 minutes. + +Monitor deployment: + ./deploy-to-apps.sh --status +``` + +### Check Status +```bash +$ ./deploy-to-apps.sh --status + +======================================== + Deployment Status +======================================== +Application UUID: abc-123-def-456 +Name: acme-recruit +Domain: https://acmerecruit.startanaicompany.com +Status: running +Last deployment: 2026-01-24 17:30:00 UTC + +Company: Acme Corp +Repository: git@git.startanaicompany.com:user/acme-recruit.git +Branch: master +``` + +--- + +## .gitignore Updates Required + +Add to `.gitignore`: +``` +# Deployment configuration (contains UUID, API keys) +.deployment-uuid +deployment-info.txt +deploy-to-apps.sh + +# Keep the example for users to copy +!deploy-to-apps.example.sh +``` + +--- + +## Benefits + +1. ✅ **Idempotent:** Can run script multiple times safely +2. ✅ **User-friendly:** Auto-detects mode based on context +3. ✅ **Flexible:** Supports multiple deployment scenarios +4. ✅ **Safe:** Prevents duplicate applications +5. ✅ **Traceable:** UUID stored locally for easy updates +6. ✅ **Stateful:** Remembers previous deployment +7. ✅ **Informative:** Clear feedback on what's happening + +--- + +## Migration for Existing Users + +If someone already ran the old script: + +```bash +# Find their application UUID +curl -H "X-API-Key: $SAAC_API_KEY" https://apps.startanaicompany.com/api/v1/applications + +# Save UUID to file +echo "abc-123-def-456" > .deployment-uuid + +# Now they can use update mode +./deploy-to-apps.sh --update +``` + +--- + +## Implementation Priority + +### Phase 1 (Must Have) +1. Auto-detection (check for `.deployment-uuid`) +2. Setup mode (create new + save UUID) +3. Update mode (update env vars + redeploy) + +### Phase 2 (Nice to Have) +4. Status mode (query current status) +5. Enhanced error messages +6. Safety checks (subdomain conflicts, etc.) + +### Phase 3 (Future) +7. Rollback support +8. Multiple environment support (dev/staging/prod) +9. Configuration validation before deployment diff --git a/deploy-to-apps.example.sh b/deploy-to-apps.example.sh index 25bf47c..34060bc 100644 --- a/deploy-to-apps.example.sh +++ b/deploy-to-apps.example.sh @@ -12,11 +12,51 @@ # Prerequisites: # 1. Register for API key at: https://apps.startanaicompany.com/api/v1/register # 2. Set SAAC_API_KEY environment variable -# 3. Set GITEA_API_TOKEN environment variable (required for automatic deployments) +# 3. Set GITEA_API_TOKEN environment variable (required for setup mode) # 4. Customize your .env file with company information +# +# Modes: +# ./deploy-to-apps.sh # Auto-detect (setup or update) +# ./deploy-to-apps.sh --setup # Force new deployment +# ./deploy-to-apps.sh --update # Force update existing +# ./deploy-to-apps.sh --status # Check deployment status set -e # Exit on error +# Configuration +DEPLOYMENT_UUID_FILE=".deployment-uuid" +DEPLOYMENT_INFO_FILE="deployment-info.txt" +SAAC_API="https://apps.startanaicompany.com/api/v1" +GITEA_API="https://git.startanaicompany.com/api/v1" + +# Parse command line arguments +MODE="auto" +if [ "$1" == "--setup" ]; then + MODE="setup" +elif [ "$1" == "--update" ]; then + MODE="update" +elif [ "$1" == "--status" ]; then + MODE="status" +elif [ -n "$1" ]; then + echo "❌ Unknown option: $1" + echo "" + echo "Usage:" + echo " $0 # Auto-detect mode" + echo " $0 --setup # Force new deployment" + echo " $0 --update # Force update existing" + echo " $0 --status # Check deployment status" + exit 1 +fi + +# Auto-detect mode based on .deployment-uuid existence +if [ "$MODE" == "auto" ]; then + if [ -f "$DEPLOYMENT_UUID_FILE" ]; then + MODE="update" + else + MODE="setup" + fi +fi + # Load environment variables from .env if [ ! -f .env ]; then echo "❌ Error: .env file not found. Copy .env.example to .env and customize it." @@ -30,7 +70,7 @@ if [ -z "$SAAC_API_KEY" ]; then echo "❌ Error: SAAC_API_KEY environment variable not set" echo "" echo "To get your API key:" - echo "1. Register at: curl -X POST https://apps.startanaicompany.com/api/v1/register \\" + echo "1. Register at: curl -X POST https://apps.startanaicompany.com/api/v1/users/register \\" echo " -H 'Content-Type: application/json' \\" echo " -d '{\"email\":\"your@email.com\",\"gitea_username\":\"${GITEA_USERNAME}\"}'" echo "" @@ -40,12 +80,12 @@ if [ -z "$SAAC_API_KEY" ]; then exit 1 fi -if [ -z "$GITEA_API_TOKEN" ]; then +# GITEA_API_TOKEN only required for setup mode (webhook creation) +if [ "$MODE" == "setup" ] && [ -z "$GITEA_API_TOKEN" ]; then echo "❌ Error: GITEA_API_TOKEN environment variable not set" echo "" - echo "GITEA_API_TOKEN is required for:" - echo " - Cloning your private repository" - echo " - Setting up automatic deployment webhooks" + echo "GITEA_API_TOKEN is required for setup mode to:" + echo " - Set up automatic deployment webhooks" echo "" echo "To get your Gitea API token:" echo "1. Go to https://git.startanaicompany.com" @@ -67,34 +107,222 @@ if [ -z "$SUBDOMAIN" ]; then exit 1 fi -if [ -z "$GITEA_USERNAME" ]; then - echo "❌ Error: GITEA_USERNAME not set in .env" - exit 1 -fi +if [ "$MODE" == "setup" ]; then + if [ -z "$GITEA_USERNAME" ]; then + echo "❌ Error: GITEA_USERNAME not set in .env" + exit 1 + fi -if [ -z "$GITEA_REPO_NAME" ]; then - echo "❌ Error: GITEA_REPO_NAME not set in .env" - exit 1 + if [ -z "$GITEA_REPO_NAME" ]; then + echo "❌ Error: GITEA_REPO_NAME not set in .env" + exit 1 + fi fi -# SAAC API configuration -SAAC_API="https://apps.startanaicompany.com/api/v1" - # Repository URL (SSH format required by Coolify for private repos) REPO_URL="git@git.startanaicompany.com:${GITEA_USERNAME}/${GITEA_REPO_NAME}.git" # Domain (e.g., annarecruit.startanaicompany.com or johnrecruit.startanaicompany.com) FULL_DOMAIN="${SUBDOMAIN}recruit.startanaicompany.com" +# ======================================== +# MODE: STATUS +# ======================================== +if [ "$MODE" == "status" ]; then + echo "=========================================" + echo " Deployment Status" + echo "=========================================" + echo "" + + # Check if deployment UUID exists + if [ ! -f "$DEPLOYMENT_UUID_FILE" ]; then + echo "❌ No deployment found" + echo " Run './deploy-to-apps.sh --setup' to create a new deployment" + exit 1 + fi + + APP_UUID=$(cat "$DEPLOYMENT_UUID_FILE") + echo "📦 Fetching status for application: $APP_UUID" + echo "" + + # Get application details + STATUS_RESPONSE=$(curl -s -X GET "${SAAC_API}/applications/${APP_UUID}" \ + -H "X-API-Key: ${SAAC_API_KEY}") + + # Check for errors + if echo "$STATUS_RESPONSE" | grep -q "error"; then + echo "❌ Failed to fetch status:" + echo "$STATUS_RESPONSE" | jq '.' 2>/dev/null || echo "$STATUS_RESPONSE" + exit 1 + fi + + # Display formatted status + echo "Application UUID: $APP_UUID" + echo "Name: $(echo "$STATUS_RESPONSE" | jq -r '.app_name')" + echo "Domain: $(echo "$STATUS_RESPONSE" | jq -r '.domain')" + echo "Status: $(echo "$STATUS_RESPONSE" | jq -r '.status')" + echo "Repository: $(echo "$STATUS_RESPONSE" | jq -r '.git_repo')" + echo "Branch: $(echo "$STATUS_RESPONSE" | jq -r '.git_branch')" + echo "Created: $(echo "$STATUS_RESPONSE" | jq -r '.created_at')" + echo "" + echo "🔍 View logs:" + echo " curl -H \"X-API-Key: \$SAAC_API_KEY\" \\" + echo " ${SAAC_API}/applications/${APP_UUID}/logs" + echo "" + + exit 0 +fi + +# ======================================== +# MODE: UPDATE +# ======================================== +if [ "$MODE" == "update" ]; then + echo "=========================================" + echo " AI Recruitment Site Deployment" + echo "=========================================" + echo "📝 Mode: UPDATE (existing deployment)" + echo "" + + # Check if deployment UUID exists + if [ ! -f "$DEPLOYMENT_UUID_FILE" ]; then + echo "❌ No deployment found (.deployment-uuid file missing)" + echo " Run './deploy-to-apps.sh --setup' to create a new deployment" + exit 1 + fi + + APP_UUID=$(cat "$DEPLOYMENT_UUID_FILE") + + echo "📦 Configuration:" + echo " Application UUID: $APP_UUID" + echo " Company: $COMPANY_NAME" + echo " Domain: https://$FULL_DOMAIN" + echo "" + + # Verify application still exists + echo "🔍 Verifying application exists..." + VERIFY_RESPONSE=$(curl -s -X GET "${SAAC_API}/applications/${APP_UUID}" \ + -H "X-API-Key: ${SAAC_API_KEY}") + + if echo "$VERIFY_RESPONSE" | grep -q "error"; then + echo "❌ Application not found or access denied" + echo " The application may have been deleted or UUID is invalid" + echo " Run './deploy-to-apps.sh --setup' to create a new deployment" + exit 1 + fi + + echo "✅ Application verified" + echo "" + + # Update environment variables + echo "🔄 Updating environment variables..." + UPDATE_RESPONSE=$(curl -s -X PATCH "${SAAC_API}/applications/${APP_UUID}/env" \ + -H "X-API-Key: ${SAAC_API_KEY}" \ + -H "Content-Type: application/json" \ + -d "{ + \"variables\": { + \"COMPANY_NAME\": \"${COMPANY_NAME}\", + \"COMPANY_TAGLINE\": \"${COMPANY_TAGLINE}\", + \"COMPANY_DESCRIPTION\": \"${COMPANY_DESCRIPTION}\", + \"PRIMARY_COLOR\": \"${PRIMARY_COLOR}\", + \"ACCENT_COLOR\": \"${ACCENT_COLOR}\", + \"DARK_COLOR\": \"${DARK_COLOR}\", + \"CONTACT_EMAIL\": \"${CONTACT_EMAIL}\", + \"CONTACT_PHONE\": \"${CONTACT_PHONE}\", + \"CONTACT_ADDRESS\": \"${CONTACT_ADDRESS}\" + } + }") + + # Check for errors + if echo "$UPDATE_RESPONSE" | grep -q "error"; then + echo "❌ Failed to update environment variables:" + echo "$UPDATE_RESPONSE" | jq '.' 2>/dev/null || echo "$UPDATE_RESPONSE" + exit 1 + fi + + echo "✅ Environment variables updated" + echo "" + + # Trigger redeployment + echo "🚀 Triggering redeployment..." + DEPLOY_RESPONSE=$(curl -s -X POST "${SAAC_API}/applications/${APP_UUID}/deploy" \ + -H "X-API-Key: ${SAAC_API_KEY}") + + # Check for errors + if echo "$DEPLOY_RESPONSE" | grep -q "error"; then + echo "❌ Failed to trigger deployment:" + echo "$DEPLOY_RESPONSE" | jq '.' 2>/dev/null || echo "$DEPLOY_RESPONSE" + exit 1 + fi + + echo "✅ Deployment triggered" + echo "" + + # Update deployment info file + cat > "$DEPLOYMENT_INFO_FILE" < "$DEPLOYMENT_UUID_FILE" +echo "💾 UUID saved to $DEPLOYMENT_UUID_FILE" +echo "" + # Configure webhook for automatic deployments echo "🪝 Setting up deployment webhook..." -# Create webhook in Gitea -GITEA_API="https://git.startanaicompany.com/api/v1" WEBHOOK_RESPONSE=$(curl -s -X POST "${GITEA_API}/repos/${GITEA_USERNAME}/${GITEA_REPO_NAME}/hooks" \ -H "Authorization: token ${GITEA_API_TOKEN}" \ -H "Content-Type: application/json" \ @@ -172,48 +403,14 @@ else echo "✅ Webhook configured for automatic deployments" fi -echo "" -echo "=========================================" -echo " Deployment Complete!" -echo "=========================================" -echo "" -echo "📋 Deployment Details:" -echo " Application UUID: $APP_UUID" -echo " Domain: $DOMAIN" -echo "" -echo "⏳ Your site will be available in 2-3 minutes at:" -echo " $DOMAIN" -echo "" -echo "📝 Next Steps:" -echo " 1. Configure Cloudflare DNS (if not already done):" -echo " - Add CNAME record:" -echo " - Name: ${SUBDOMAIN}recruit" -echo " - Target: apps.startanaicompany.com" -echo " - Proxy: Enabled" -echo "" -echo " 2. Wait 2-3 minutes for deployment to complete" -echo "" -echo " 3. Visit your site:" -echo " $DOMAIN" -echo "" -echo " 4. Create your first admin account via the login page:" -echo " ${DOMAIN}/admin/login" -echo "" -echo "🔍 Monitor deployment:" -echo " View logs:" -echo " curl -H \"X-API-Key: \$SAAC_API_KEY\" \\" -echo " ${SAAC_API}/applications/${APP_UUID}/logs" -echo "" -echo " List your applications:" -echo " curl -H \"X-API-Key: \$SAAC_API_KEY\" \\" -echo " ${SAAC_API}/applications" echo "" # Save deployment info -cat > deployment-info.txt < "$DEPLOYMENT_INFO_FILE" <