Skip to content

chore(deps): bump docker/login-action in the all-actions group (#109) #91

chore(deps): bump docker/login-action in the all-actions group (#109)

chore(deps): bump docker/login-action in the all-actions group (#109) #91

Workflow file for this run

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);
}