Files
kulakpos_web/.gitea/workflows/pipeline.yml
eko eafa8d362f
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 14s
Build, Push and Deploy / deploy-staging (push) Successful in 36s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 0s
fix vald
2026-04-05 00:39:10 +07:00

335 lines
13 KiB
YAML

name: Build, Push and Deploy
on:
push:
branches: [ main, master ]
workflow_dispatch:
inputs:
deploy_to_production:
description: 'Deploy to Production?'
required: true
default: 'no'
type: choice
options:
- 'yes'
- 'no'
image_tag:
description: 'Image tag to deploy (optional, uses latest if empty)'
required: false
type: string
jobs:
build-and-push:
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.vars.outputs.image_tag }}
image_sha: ${{ steps.vars.outputs.image_sha }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set variables
id: vars
run: |
echo "image_tag=$(echo ${{ gitea.sha }} | cut -c1-8)" >> $GITHUB_OUTPUT
echo "image_sha=${{ gitea.sha }}" >> $GITHUB_OUTPUT
echo "build_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Gitea Registry
uses: docker/login-action@v3
with:
registry: kode.sadateknologi.site
username: ${{ gitea.repository_owner }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:latest
kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:${{ gitea.sha }}
kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:${{ steps.vars.outputs.image_tag }}
labels: |
org.opencontainers.image.created=${{ steps.vars.outputs.build_time }}
org.opencontainers.image.revision=${{ gitea.sha }}
org.opencontainers.image.version=${{ steps.vars.outputs.image_tag }}
deploy-staging:
runs-on: ubuntu-latest
needs: build-and-push
if: gitea.event_name == 'push' && (gitea.ref == 'refs/heads/main' || gitea.ref == 'refs/heads/master')
steps:
- name: Deploy to Staging (Local)
run: |
echo "🚀 Starting staging deployment on local server..."
# Pull the latest image
echo "Pulling image: kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:latest"
docker pull kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:latest
# Stop and remove existing container
echo "Stopping existing container..."
docker stop kulakpos_web_staging || true
docker rm kulakpos_web_staging || true
# Clean up old images (keep last 5)
docker image prune -f
# Run new container
echo "Starting new container..."
docker run -d \
--restart unless-stopped \
--health-cmd="curl -f http://127.0.0.1:8000 || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
--name kulakpos_web_staging \
--network="host" \
-v /opt/kulakpos/staging/.env:/var/www/html/.env \
-p 8000:8000 \
-e MODE=staging \
-e APP_ENV=staging \
kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:latest
# Check if container is running
sleep 5
if docker ps | grep kulakpos_web_staging; then
echo "✅ Staging deployment successful!"
docker logs --tail 20 kulakpos_web_staging
else
echo "❌ Staging deployment failed! Check logs:"
docker logs kulakpos_web_staging || echo "No logs available"
exit 1
fi
- name: Verify Staging Deployment
run: |
curl -f http://localhost:8000/health || curl -f http://localhost:8000 || echo 'Health check endpoint not found, but service may be running'
echo "✅ Staging deployment verified!"
deploy-production:
runs-on: ubuntu-latest
needs: build-and-push
if: gitea.event_name == 'workflow_dispatch' && gitea.event.inputs.deploy_to_production == 'yes'
environment: production
steps:
# ============================================
# STEP 1: Setup SSH Key and Configuration
# ============================================
- name: Setup SSH Key and Config
run: |
echo "🔑 Setting up SSH authentication..."
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Decode the base64-encoded SSH key
echo "${{ secrets.PRODUCTION_SSH_KEY_BASE64 }}" | base64 -d > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
# Add host to known_hosts
ssh-keyscan -H ${{ secrets.PRODUCTION_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true
# Create SSH config
cat > ~/.ssh/config << EOF
Host kulakpos_prod
HostName ${{ secrets.PRODUCTION_HOST }}
User ${{ secrets.PRODUCTION_USER }}
IdentityFile ~/.ssh/id_rsa
StrictHostKeyChecking accept-new
EOF
chmod 600 ~/.ssh/config
echo "✅ SSH configuration complete"
- name: Debug SSH Configuration
run: |
echo "Current user: $(whoami)"
echo "Home directory: $HOME"
echo "SSH config location: $HOME/.ssh/config"
echo "SSH config content:"
cat $HOME/.ssh/config || echo "No SSH config found"
echo ""
echo "SSH key permissions:"
ls -la ~/.ssh/
echo ""
echo "Testing SSH connection:"
ssh -v kulakpos_prod echo "Connection successful" || echo "Connection failed"
- name: Determine image tag for production
id: prod_image
run: |
if [ -n "${{ gitea.event.inputs.image_tag }}" ]; then
echo "image_tag=${{ gitea.event.inputs.image_tag }}" >> $GITHUB_OUTPUT
else
echo "image_tag=latest" >> $GITHUB_OUTPUT
fi
- name: Deploy to Production Server
run: |
ssh kulakpos_prod << 'EOF'
IMAGE_TAG="${{ steps.prod_image.outputs.image_tag }}"
echo "🚀 Starting production deployment with image tag: $IMAGE_TAG"
# Show current deployment
echo "Current production container:"
docker ps --filter name=kulakpos_web_prod
# Create backup of current deployment info
mkdir -p /opt/kulakpos/backups
docker inspect kulakpos_web_prod > /opt/kulakpos/backups/kulakpos_backup_$(date +%Y%m%d_%H%M%S).json || true
# Backup .env file
if [ -f "/opt/kulakpos/.env" ]; then
cp /opt/kulakpos/.env /opt/kulakpos/backups/.env_backup_$(date +%Y%m%d_%H%M%S)
fi
# Pull the specified image
echo "Pulling image: kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:$IMAGE_TAG"
docker pull kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:$IMAGE_TAG
# Stop and remove existing container
echo "Stopping existing container..."
docker stop kulakpos_web_prod || true
docker rm kulakpos_web_prod || true
# Run new container (using PHP's built-in server on port 8000 like staging)
echo "Starting new production container on port 8000..."
docker run -d \
--restart unless-stopped \
--health-cmd="curl -f http://127.0.0.1:8000 || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-start-period=40s \
--health-retries=3 \
--name kulakpos_web_prod \
--network="host" \
-v /opt/kulakpos/.env:/var/www/html/.env \
-e MODE=production \
-e APP_ENV=production \
-e APP_DEBUG=false \
-e AUTO_MIGRATE=false \
kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:$IMAGE_TAG
# Wait for container to be ready
echo "Waiting for container to be ready..."
sleep 10
# Check if container is running
if docker ps | grep kulakpos_web_prod; then
echo "✅ Production deployment successful!"
echo ""
echo "Container status:"
docker ps --filter name=kulakpos_web_prod --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
echo ""
echo "Container logs (last 20 lines):"
docker logs --tail 20 kulakpos_web_prod
# Test the application locally
echo ""
echo "Testing application locally..."
curl -f http://127.0.0.1:8000 > /dev/null 2>&1 && echo "✅ Application is responding on port 8000" || echo "⚠️ Application not responding on port 8000"
else
echo "❌ Production deployment failed! Checking logs:"
docker logs kulakpos_web_prod || echo "No logs available"
# Attempt rollback to previous version if available
echo ""
echo "Attempting rollback to previous version..."
PREVIOUS_BACKUP=$(ls -t /opt/kulakpos/backups/kulakpos_backup_*.json 2>/dev/null | head -1)
if [ -f "$PREVIOUS_BACKUP" ]; then
PREVIOUS_IMAGE=$(jq -r '.[0].Config.Image' $PREVIOUS_BACKUP 2>/dev/null || echo "")
if [ -n "$PREVIOUS_IMAGE" ] && [ "$PREVIOUS_IMAGE" != "kode.sadateknologi.site/${{ gitea.repository_owner }}/kulakpos_web:$IMAGE_TAG" ]; then
echo "Rolling back to: $PREVIOUS_IMAGE"
docker run -d \
--restart unless-stopped \
--health-cmd="curl -f http://127.0.0.1:8000 || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-start-period=40s \
--health-retries=3 \
--name kulakpos_web_prod \
--network="host" \
-v /opt/kulakpos/.env:/var/www/html/.env \
-e MODE=production \
-e APP_ENV=production \
-e APP_DEBUG=false \
-e AUTO_MIGRATE=false \
$PREVIOUS_IMAGE
echo "Rollback completed"
fi
fi
exit 1
fi
EOF
- name: Verify Production Deployment
run: |
ssh kulakpos_prod << 'EOF'
echo "🔍 Verifying production deployment..."
# Check container status (fixed - removed -q flag)
if docker ps --filter "name=kulakpos_web_prod" --format "{{.Status}}" | grep "Up" > /dev/null 2>&1; then
echo "✅ Container is running"
else
echo "❌ Container is not running"
exit 1
fi
# Check if port 8000 is listening (with timeout)
if timeout 5 ss -tlnp 2>/dev/null | grep ":8000" 2>/dev/null || netstat -tlnp 2>/dev/null | grep ":8000" 2>/dev/null; then
echo "✅ Application is listening on port 8000"
else
echo "⚠️ Port 8000 not listening, checking container process..."
docker exec kulakpos_web_prod ps aux | grep php || echo "No PHP process found"
exit 1
fi
# Test application response (with timeout and retry)
echo "Testing application response..."
for i in 1 2 3 4 5; do
if curl -f -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8000 | grep "200\|302"; then
echo "✅ Application is responding"
break
elif [ $i -eq 5 ]; then
echo "❌ Application not responding after 5 attempts"
docker logs --tail 20 kulakpos_web_prod
exit 1
fi
echo "Attempt $i/5 failed, waiting..."
sleep 2
done
echo "🎉 Production deployment verification complete!"
EOF
- name: Send Deployment Notification
if: always()
run: |
STATUS="${{ job.status }}"
if [ "$STATUS" = "success" ]; then
echo "✅ Production deployment completed successfully!"
echo "🌐 Application is now running at: https://prod-test.kulakpos.id"
echo "🐳 Container name: kulakpos_web_prod"
echo "🔌 Port: 8000 (internal) -> 80/443 (Nginx proxy)"
else
echo "❌ Production deployment failed!"
echo "Please check the logs above for details"
exit 1
fi
cleanup:
runs-on: ubuntu-latest
needs: [deploy-staging, deploy-production]
if: always()
steps:
- name: Cleanup old Docker images on runners
run: |
docker system prune -f --filter "until=24h"