deps(frontend)(deps): bump lucide-react in /frontend #72
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: 🎯 Manual Deployment | ||
|
Check failure on line 1 in .github/workflows/manual-deploy.yml
|
||
| 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 | ||