name: Deploy Academy LMS to Hetzner on: # Manual trigger workflow_dispatch: inputs: force_rebuild: description: 'Force rebuild all images' required: false default: 'false' type: boolean environment: description: 'Deployment environment' required: false default: 'production' type: choice options: - production - test # Webhook triggers from watched repositories repository_dispatch: types: [academy-lms-updated, academy-ai-tutor-updated, academy-langchain-updated] # Push to master branch of this repo push: branches: [ master ] paths: - 'compose.yaml' - 'images/**' - '.github/workflows/**' - 'nginx/**' env: REGISTRY: ghcr.io HETZNER_HOST: 188.245.211.114 HETZNER_USER: frappe DEPLOY_PATH: /opt/frappe-deployment jobs: build-and-deploy: runs-on: ubuntu-latest # Use environment for secrets management environment: ${{ github.event.inputs.environment || 'production' }} permissions: contents: read packages: write steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata for Frappe image id: meta-frappe uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/exarlabs/ignis-academy-lms tags: | type=ref,event=branch type=ref,event=pr type=sha,prefix={{branch}}- type=raw,value=latest,enable={{is_default_branch}} - name: Build and push Frappe image uses: docker/build-push-action@v5 with: context: . file: ./images/custom/Containerfile push: true tags: ${{ steps.meta-frappe.outputs.tags }} labels: ${{ steps.meta-frappe.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max build-args: | LMS_REPO_URL=https://github.com/ExarLabs/academy-lms AI_TUTOR_REPO_URL=https://github.com/ExarLabs/academy-ai-tutor-chat - name: Clone and prepare LangChain service run: | # Clone private repository using PAT (Personal Access Token) git clone https://${{ secrets.ACADEMY_DOCKER_PAT }}@github.com/ExarLabs/academy-LangChain.git langchain-temp - name: Extract metadata for LangChain image id: meta-langchain uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/exarlabs/academy-langchain tags: | type=ref,event=branch type=ref,event=pr type=sha,prefix={{branch}}- type=raw,value=latest,enable={{is_default_branch}} - name: Build and push LangChain image uses: docker/build-push-action@v5 with: context: ./langchain-temp push: true tags: ${{ steps.meta-langchain.outputs.tags }} labels: ${{ steps.meta-langchain.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # - name: Setup SSH key # uses: webfactory/ssh-agent@v0.8.0 # with: # ssh-private-key: ${{ secrets.HETZNER_SSH_KEY }} # - name: Add Hetzner server to known hosts # run: | # ssh-keyscan -H ${{ env.HETZNER_HOST }} >> ~/.ssh/known_hosts # - name: Deploy to Hetzner # run: | # # Copy deployment files to server # scp -r compose.yaml nginx/ scripts/ ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }}:${{ env.DEPLOY_PATH }}/ # # Copy environment file if it doesn't exist # ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} " # cd ${{ env.DEPLOY_PATH }} # if [ ! -f .env ]; then # cp .env.example .env # echo 'Please update .env file with your configuration' # fi # " # # Login to private registry # ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} " # echo '${{ secrets.GITHUB_TOKEN }}' | docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin # " # - name: Update and restart services # run: | # ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} " # cd ${{ env.DEPLOY_PATH }} # # Pull latest images # docker compose pull # # Stop services gracefully # docker compose down --timeout 30 # # Start services # docker compose up -d # # Wait for services to be ready # sleep 30 # # Run migrations on all sites # ./scripts/migrate-all-sites.sh # # Show status # docker compose ps # " # - name: Health check # run: | # # Wait a bit more for services to fully start # sleep 60 # # Check if nginx-proxy is responding # if curl -f http://${{ env.HETZNER_HOST }}/health; then # echo "✅ Deployment successful - Health check passed" # else # echo "❌ Health check failed" # # Show logs for debugging # ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} " # cd ${{ env.DEPLOY_PATH }} # docker compose logs --tail=50 # " # exit 1 # fi # - name: Notify deployment status # if: always() # run: | # if [ "${{ job.status }}" == "success" ]; then # echo "🚀 Deployment to Hetzner completed successfully!" # echo "🌐 Access your application at: http://${{ env.HETZNER_HOST }}" # else # echo "💥 Deployment failed. Check the logs above for details." # fi