chore(deps): bump docker/login-action in the all-actions group (#109) #91
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: Deploy to Production | |
| on: | |
| push: | |
| branches: [master] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Image tag to deploy (leave empty for latest)' | |
| required: false | |
| type: string | |
| default: '' | |
| concurrency: | |
| group: deploy-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| packages: write | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: vreshch/diffractwd.com | |
| jobs: | |
| build-and-push: | |
| name: π³ Build & Push Docker Image | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| outputs: | |
| image-tag: ${{ steps.set-tag.outputs.tag }} | |
| steps: | |
| - name: π₯ Checkout code | |
| uses: actions/checkout@v7 | |
| - name: π·οΈ Determine image tag | |
| id: set-tag | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ inputs.tag }}" ]; then | |
| echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT | |
| echo "π Using custom tag: ${{ inputs.tag }}" | |
| else | |
| echo "tag=${{ github.sha }}" >> $GITHUB_OUTPUT | |
| echo "π Using commit SHA: ${{ github.sha }}" | |
| fi | |
| - name: π Login to GitHub Container Registry | |
| uses: docker/login-action@v4.6.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: π³ Build and push Docker image | |
| run: | | |
| IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | |
| TAG="${{ steps.set-tag.outputs.tag }}" | |
| echo "ποΈ Building image..." | |
| docker build \ | |
| --build-arg COMMIT_SHA="${{ github.sha }}" \ | |
| --build-arg BRANCH="${{ github.ref_name }}" \ | |
| --build-arg BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ | |
| -t ${IMAGE}:${TAG} -t ${IMAGE}:latest . | |
| echo "π€ Pushing image..." | |
| docker push ${IMAGE}:${TAG} | |
| docker push ${IMAGE}:latest | |
| echo "β Image pushed successfully!" | |
| echo "π¦ Image: ${IMAGE}:${TAG}" | |
| echo "π¦ Image: ${IMAGE}:latest" | |
| deploy: | |
| name: π Deploy to Server | |
| needs: build-and-push | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| environment: production | |
| steps: | |
| - name: π₯ Checkout code | |
| uses: actions/checkout@v7 | |
| - name: π§ Setup SSH | |
| run: | | |
| mkdir -p ~/.ssh | |
| echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key | |
| chmod 600 ~/.ssh/deploy_key | |
| ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts | |
| # Test SSH connection | |
| echo "Testing SSH connection..." | |
| ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no root@${{ secrets.SERVER_HOST }} "echo 'SSH connection successful'" | |
| - name: π€ Copy deployment files to server | |
| run: | | |
| echo "π¦ Ensuring remote directory exists..." | |
| ssh -i ~/.ssh/deploy_key root@${{ secrets.SERVER_HOST }} "mkdir -p /opt/diffractwd-com && chown root:root /opt/diffractwd-com && chmod 755 /opt/diffractwd-com" | |
| echo "π¦ Copying docker-compose.yml..." | |
| scp -i ~/.ssh/deploy_key docker-compose.yml root@${{ secrets.SERVER_HOST }}:/opt/diffractwd-com/ | |
| echo "π¦ Copying deployment script..." | |
| scp -i ~/.ssh/deploy_key scripts/deploy.sh root@${{ secrets.SERVER_HOST }}:/opt/diffractwd-com/ | |
| ssh -i ~/.ssh/deploy_key root@${{ secrets.SERVER_HOST }} "chmod +x /opt/diffractwd-com/deploy.sh" | |
| - name: π Write runtime env on server | |
| run: | | |
| echo "π Writing /opt/diffractwd-com/.env (runtime secrets)..." | |
| ssh -i ~/.ssh/deploy_key root@${{ secrets.SERVER_HOST }} "install -m 600 /dev/stdin /opt/diffractwd-com/.env" <<'ENV_EOF' | |
| # SigNoz tracing over the WG mesh; unset token would leave these blank = tracer off. | |
| OTEL_EXPORTER_OTLP_ENDPOINT=http://172.31.0.1:4318 | |
| OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20${{ secrets.SIGNOZ_INGEST_TOKEN }} | |
| OTEL_SERVICE_NAME=diffractwd-web | |
| OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,service.namespace=side | |
| OTEL_TRACES_SAMPLER=parentbased_traceidratio | |
| OTEL_TRACES_SAMPLER_ARG=1.0 | |
| OTEL_METRICS_EXPORTER=none | |
| OTEL_LOGS_EXPORTER=none | |
| ENV_EOF | |
| echo "β Runtime env written" | |
| - name: π Deploy application | |
| id: deploy | |
| run: | | |
| IMAGE_TAG="${{ needs.build-and-push.outputs.image-tag }}" | |
| echo "π Deploying to production..." | |
| echo "π¦ Image tag: ${IMAGE_TAG}" | |
| ssh -i ~/.ssh/deploy_key root@${{ secrets.SERVER_HOST }} << EOF | |
| set -e | |
| cd /opt/diffractwd-com | |
| # Authenticate with GHCR on server | |
| echo "π Authenticating with GHCR..." | |
| echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin | |
| # Update image tag in docker-compose | |
| sed -i "s|image:.*|image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${IMAGE_TAG}|g" docker-compose.yml | |
| # Pull new image before deploying | |
| echo "π₯ Pulling image..." | |
| docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${IMAGE_TAG} | |
| # Deploy to Docker Swarm | |
| echo "π³ Deploying stack..." | |
| docker stack deploy -c docker-compose.yml diffractwd --with-registry-auth | |
| # Force service update to ensure containers restart with new image | |
| echo "π Forcing service update..." | |
| docker service update --force diffractwd_web | |
| # Wait for deployment | |
| echo "β³ Waiting for service to be ready..." | |
| sleep 15 | |
| # Check service status | |
| echo "β Service status:" | |
| docker service ps diffractwd_web --no-trunc --format "table {{.Name}}\t{{.CurrentState}}\t{{.Error}}" | |
| # Save deployed version | |
| echo "${IMAGE_TAG}" > .deployed-version | |
| echo "β Deployment complete!" | |
| EOF | |
| - name: β Verify deployment | |
| run: | | |
| echo "π Verifying deployment..." | |
| EXPECTED="${{ github.sha }}" | |
| for i in $(seq 1 30); do | |
| LIVE_COMMIT=$(curl -sf "https://diffractwd.com/api/version" 2>/dev/null | jq -r '.commit // empty') || true | |
| if [ "$LIVE_COMMIT" = "$EXPECTED" ]; then | |
| echo "β Deployment verified! Live commit: $LIVE_COMMIT" | |
| echo "deployment-status=success" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "β³ Attempt $i/30 β got: ${LIVE_COMMIT:-no response}, want: ${EXPECTED:0:8}" | |
| sleep 10 | |
| done | |
| echo "β Deployment verification failed β live version does not match expected commit" | |
| exit 1 | |
| - name: π§Ή Cleanup | |
| if: always() | |
| run: | | |
| rm -f ~/.ssh/deploy_key | |
| echo "π§Ή Cleanup complete" | |
| deployment-summary: | |
| name: π Deployment Summary | |
| needs: [build-and-push, deploy] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: π Generate summary | |
| uses: actions/github-script@v9 | |
| env: | |
| COMMIT_MESSAGE: ${{ github.event.head_commit.message }} | |
| with: | |
| script: | | |
| const buildResult = '${{ needs.build-and-push.result }}'; | |
| const deployResult = '${{ needs.deploy.result }}'; | |
| const imageTag = '${{ needs.build-and-push.outputs.image-tag }}'; | |
| const commitSha = '${{ github.sha }}'; | |
| const commitMessage = process.env.COMMIT_MESSAGE || 'Manual deployment'; | |
| const eventName = '${{ github.event_name }}'; | |
| const triggerType = eventName === 'workflow_dispatch' ? 'Manual' : 'Automatic (push)'; | |
| let status = 'β SUCCESS'; | |
| let emoji = 'π'; | |
| if (buildResult === 'failure') { | |
| status = 'β FAILED - Build'; | |
| emoji = 'π¨'; | |
| } else if (deployResult === 'failure') { | |
| status = 'β FAILED - Deployment'; | |
| emoji = 'π¨'; | |
| } | |
| const summary = `${emoji} **Deployment ${status}** | |
| **Commit:** \`${commitSha.substring(0, 8)}\` | |
| **Message:** ${commitMessage} | |
| **Branch:** master | |
| **Trigger:** ${triggerType} | |
| **Pipeline Results:** | |
| - π³ Build & Push: ${buildResult === 'success' ? 'β ' : 'β'} ${buildResult} | |
| - π Deployment: ${deployResult === 'success' ? 'β ' : 'β'} ${deployResult} | |
| **Details:** | |
| - **Image Tag:** \`${imageTag}\` | |
| - **Registry:** ghcr.io/vreshch/diffractwd.com | |
| - **Server:** diffractwd.com | |
| - **Deployment URL:** https://diffractwd.com | |
| **Quick Actions:** | |
| - π [Workflow Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) | |
| - π [Visit Website](https://diffractwd.com) | |
| - π¦ [Registry](https://github.com/${{ github.repository }}/pkgs/container/diffractwd.com) | |
| --- | |
| β° Generated at: \`${new Date().toISOString()}\``; | |
| console.log(summary); | |
| // Create commit status | |
| try { | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: commitSha, | |
| state: deployResult === 'success' ? 'success' : 'failure', | |
| target_url: `https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}`, | |
| description: `Deployment ${status}`, | |
| context: 'deployment/production' | |
| }); | |
| } catch (error) { | |
| console.log('Could not create commit status:', error.message); | |
| } |