Skip to content

deps(frontend)(deps): bump lucide-react in /frontend #72

deps(frontend)(deps): bump lucide-react in /frontend

deps(frontend)(deps): bump lucide-react in /frontend #72

Workflow file for this run

name: 🎯 Manual Deployment

Check failure on line 1 in .github/workflows/manual-deploy.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/manual-deploy.yml

Invalid workflow file

(Line: 191, Col: 12): Unrecognized named-value: 'secrets'. Located at position 72 within expression: needs.prepare-deployment.outputs.target_environment == 'production' && secrets.VPS_URL || 'https://staging.yourdomain.com'
on:
workflow_dispatch:
inputs:
deployment_target:
description: '🎯 Deployment Target'
required: true
default: 'production'
type: choice
options:
- production
- staging
deployment_source:
description: '📦 What to Deploy'
required: true
default: 'latest-release'
type: choice
options:
- latest-release
- specific-release
- specific-commit
- current-main
release_tag:
description: '🏷️ Release Tag (if specific-release selected)'
required: false
type: string
default: ''
commit_sha:
description: '📌 Commit SHA (if specific-commit selected)'
required: false
type: string
default: ''
skip_tests:
description: '⚡ Skip Tests (emergency deployments only)'
required: false
type: boolean
default: false
env:
DOTNET_VERSION: '9.0.x'
jobs:
# ═══════════════════════════════════════════════════════════════════════════════
# 🔍 DEPLOYMENT PREPARATION
# ═══════════════════════════════════════════════════════════════════════════════
prepare-deployment:
name: 🔍 Prepare Deployment
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
deploy_ref: ${{ steps.determine-ref.outputs.deploy_ref }}
deploy_version: ${{ steps.determine-ref.outputs.deploy_version }}
deploy_description: ${{ steps.determine-ref.outputs.deploy_description }}
target_environment: ${{ steps.determine-ref.outputs.target_environment }}
steps:
- name: 📥 Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 🔍 Determine Deployment Reference
id: determine-ref
run: |
echo "🔍 Determining what to deploy..."
case "${{ github.event.inputs.deployment_source }}" in
"latest-release")
# Get latest release
LATEST_RELEASE=$(gh release list --limit 1 --json tagName --jq '.[0].tagName')
if [[ -z "$LATEST_RELEASE" || "$LATEST_RELEASE" == "null" ]]; then
echo "❌ No releases found"
exit 1
fi
DEPLOY_REF="$LATEST_RELEASE"
DEPLOY_VERSION="$LATEST_RELEASE"
DEPLOY_DESC="Latest Release: $LATEST_RELEASE"
;;
"specific-release")
RELEASE_TAG="${{ github.event.inputs.release_tag }}"
if [[ -z "$RELEASE_TAG" ]]; then
echo "❌ Release tag is required for specific-release"
exit 1
fi
# Verify release exists
if ! gh release view "$RELEASE_TAG" > /dev/null 2>&1; then
echo "❌ Release $RELEASE_TAG not found"
exit 1
fi
DEPLOY_REF="$RELEASE_TAG"
DEPLOY_VERSION="$RELEASE_TAG"
DEPLOY_DESC="Specific Release: $RELEASE_TAG"
;;
"specific-commit")
COMMIT_SHA="${{ github.event.inputs.commit_sha }}"
if [[ -z "$COMMIT_SHA" ]]; then
echo "❌ Commit SHA is required for specific-commit"
exit 1
fi
# Verify commit exists
if ! git cat-file -e "$COMMIT_SHA" 2>/dev/null; then
echo "❌ Commit $COMMIT_SHA not found"
exit 1
fi
DEPLOY_REF="$COMMIT_SHA"
DEPLOY_VERSION="${COMMIT_SHA:0:7}"
DEPLOY_DESC="Specific Commit: ${COMMIT_SHA:0:7}"
;;
"current-main")
DEPLOY_REF="main"
DEPLOY_VERSION="main-$(git rev-parse --short HEAD)"
DEPLOY_DESC="Current Main Branch"
;;
*)
echo "❌ Unknown deployment source: ${{ github.event.inputs.deployment_source }}"
exit 1
;;
esac
# Set target environment
TARGET_ENV="${{ github.event.inputs.deployment_target }}"
# Output results
echo "deploy_ref=$DEPLOY_REF" >> $GITHUB_OUTPUT
echo "deploy_version=$DEPLOY_VERSION" >> $GITHUB_OUTPUT
echo "deploy_description=$DEPLOY_DESC" >> $GITHUB_OUTPUT
echo "target_environment=$TARGET_ENV" >> $GITHUB_OUTPUT
echo "✅ Deployment plan:"
echo " 📦 Source: $DEPLOY_DESC"
echo " 🏷️ Version: $DEPLOY_VERSION"
echo " 🎯 Target: $TARGET_ENV"
echo " 📌 Ref: $DEPLOY_REF"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ═══════════════════════════════════════════════════════════════════════════════
# 🧪 OPTIONAL QUALITY CHECKS
# ═══════════════════════════════════════════════════════════════════════════════
quality-check:
name: 🧪 Quality Check
runs-on: ubuntu-latest
needs: [prepare-deployment]
if: github.event.inputs.skip_tests != 'true'
timeout-minutes: 10
steps:
- name: 📥 Checkout Deployment Source
uses: actions/checkout@v4
with:
ref: ${{ needs.prepare-deployment.outputs.deploy_ref }}
- name: ⚡ Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: 🔧 Restore Dependencies
run: dotnet restore backend/
- name: 🏗️ Build Solution
run: dotnet build backend/ --no-restore --configuration Release
- name: 🧪 Run Quick Tests
run: |
echo "🧪 Running essential tests for deployment validation..."
dotnet test backend/tests/ModernAPI.Domain.Tests/ --no-build --configuration Release --logger "console;verbosity=minimal"
# ═══════════════════════════════════════════════════════════════════════════════
# 🚀 DEPLOYMENT EXECUTION
# ═══════════════════════════════════════════════════════════════════════════════
deploy:
name: 🚀 Deploy ${{ needs.prepare-deployment.outputs.deploy_description }}
runs-on: ubuntu-latest
needs: [prepare-deployment, quality-check]
if: always() && needs.prepare-deployment.result == 'success' && (needs.quality-check.result == 'success' || needs.quality-check.result == 'skipped')
timeout-minutes: 30
environment:
name: ${{ needs.prepare-deployment.outputs.target_environment }}
url: ${{ needs.prepare-deployment.outputs.target_environment == 'production' && secrets.VPS_URL || 'https://staging.yourdomain.com' }}
steps:
- name: 🚀 Deploy to ${{ needs.prepare-deployment.outputs.target_environment }}
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ needs.prepare-deployment.outputs.target_environment == 'production' && secrets.VPS_HOST || secrets.STAGING_HOST }}
username: ${{ needs.prepare-deployment.outputs.target_environment == 'production' && secrets.VPS_USER || secrets.STAGING_USER }}
key: ${{ needs.prepare-deployment.outputs.target_environment == 'production' && secrets.VPS_SSH_KEY || secrets.STAGING_SSH_KEY }}
port: ${{ needs.prepare-deployment.outputs.target_environment == 'production' && secrets.VPS_PORT || secrets.STAGING_PORT || 22 }}
script: |
echo "🚀 Starting manual deployment..."
echo "📦 Deploying: ${{ needs.prepare-deployment.outputs.deploy_description }}"
echo "🎯 Target: ${{ needs.prepare-deployment.outputs.target_environment }}"
# Navigate to project directory
PROJECT_DIR="${{ needs.prepare-deployment.outputs.target_environment == 'production' && '/srv/modernapi' || '/srv/modernapi-staging' }}"
cd "$PROJECT_DIR" || { echo "❌ Project directory not found: $PROJECT_DIR"; exit 1; }
# Create rollback point - save current state
echo "💾 Creating rollback point..."
CURRENT_COMMIT=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
echo "$CURRENT_COMMIT" > .deployment-rollback-manual
echo "deployment_rollback_from=${{ needs.prepare-deployment.outputs.deploy_version }}" >> .deployment-rollback-manual
echo "rollback_date=$(date -u --iso-8601=seconds)" >> .deployment-rollback-manual
echo "📌 Rollback point saved: $CURRENT_COMMIT"
# Fetch latest repository state
echo "📥 Fetching repository updates..."
git fetch origin
# Checkout deployment reference
echo "📌 Checking out: ${{ needs.prepare-deployment.outputs.deploy_ref }}"
if git checkout "${{ needs.prepare-deployment.outputs.deploy_ref }}"; then
ACTUAL_COMMIT=$(git rev-parse HEAD)
echo "✅ Successfully checked out: $ACTUAL_COMMIT"
else
echo "❌ Failed to checkout ${{ needs.prepare-deployment.outputs.deploy_ref }}"
exit 1
fi
# Use appropriate docker-compose file
COMPOSE_FILE="${{ needs.prepare-deployment.outputs.target_environment == 'production' && 'docker-compose.production.yml' || 'docker-compose.staging.yml' }}"
# Stop services gracefully
echo "⏹️ Stopping current services..."
docker compose -f "$COMPOSE_FILE" down
# Build and start services
echo "🔨 Building and starting services..."
if docker compose -f "$COMPOSE_FILE" up -d --build; then
echo "✅ Services started successfully"
else
echo "❌ Service startup failed, attempting rollback..."
git checkout "$CURRENT_COMMIT" 2>/dev/null || echo "⚠️ Could not revert git state"
docker compose -f "$COMPOSE_FILE" up -d --build
exit 1
fi
# Health check
echo "🔍 Performing health check..."
HEALTH_URL="${{ needs.prepare-deployment.outputs.target_environment == 'production' && 'https://api.modernapi.dev' || 'http://localhost:5002' }}"
for i in {1..10}; do
sleep 6
if curl -f -s "$HEALTH_URL/health" > /dev/null 2>&1; then
echo "✅ Health check passed"
break
elif [[ $i -eq 10 ]]; then
echo "❌ Health check failed after 10 attempts"
echo "🔄 Rolling back..."
git checkout "$CURRENT_COMMIT" 2>/dev/null || echo "⚠️ Could not revert git state"
docker compose -f "$COMPOSE_FILE" down
docker compose -f "$COMPOSE_FILE" up -d --build
exit 1
else
echo "⏳ Health check attempt $i/10..."
fi
done
# Save successful deployment info
echo "📝 Recording successful manual deployment..."
cat > .deployment-info << EOF
deployment_type=manual
deployment_source=${{ needs.prepare-deployment.outputs.deployment_source }}
deployment_ref=${{ needs.prepare-deployment.outputs.deploy_ref }}
deployment_version=${{ needs.prepare-deployment.outputs.deploy_version }}
deployment_commit=$ACTUAL_COMMIT
deployment_date=$(date -u --iso-8601=seconds)
deployment_target=${{ needs.prepare-deployment.outputs.target_environment }}
deployment_user=${{ github.actor }}
EOF
# Cleanup old images
echo "🧹 Cleaning up old images..."
docker image prune -f --filter "until=72h" || true
echo "🎉 Manual deployment completed successfully!"
echo "📦 Version: ${{ needs.prepare-deployment.outputs.deploy_version }}"
echo "📌 Commit: $ACTUAL_COMMIT"
echo "👤 Deployed by: ${{ github.actor }}"
- name: 📊 Deployment Summary
run: |
echo "## 🎉 Manual Deployment Successful" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**📦 Deployed:** ${{ needs.prepare-deployment.outputs.deploy_description }}" >> $GITHUB_STEP_SUMMARY
echo "**🏷️ Version:** ${{ needs.prepare-deployment.outputs.deploy_version }}" >> $GITHUB_STEP_SUMMARY
echo "**🎯 Environment:** ${{ needs.prepare-deployment.outputs.target_environment }}" >> $GITHUB_STEP_SUMMARY
echo "**👤 Deployed by:** ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
echo "**📅 Deployed at:** $(date -u --iso-8601=seconds)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.event.inputs.deployment_source }}" == "specific-release" || "${{ github.event.inputs.deployment_source }}" == "latest-release" ]]; then
echo "### 📋 Release Information" >> $GITHUB_STEP_SUMMARY
echo "This deployment used a GitHub release, which provides:" >> $GITHUB_STEP_SUMMARY
echo "- ✅ **Tested code** from a tagged release" >> $GITHUB_STEP_SUMMARY
echo "- 📝 **Release notes** with changelog" >> $GITHUB_STEP_SUMMARY
echo "- 🔄 **Easy rollback** to any previous release" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
echo "### 🔄 Rollback Options" >> $GITHUB_STEP_SUMMARY
echo "If you need to rollback:" >> $GITHUB_STEP_SUMMARY
echo "1. **Quick rollback**: Run this workflow again with a different release" >> $GITHUB_STEP_SUMMARY
echo "2. **Emergency rollback**: SSH to server and run rollback script" >> $GITHUB_STEP_SUMMARY
echo "3. **Previous version**: Check .deployment-rollback-manual file on server" >> $GITHUB_STEP_SUMMARY