Files
mypage/.gitea/workflows/main.yml
RJ b1566348b0
All checks were successful
Build and Deploy Next.js Blog to Production / 🔍 Code Quality Checks (push) Successful in 15s
Build and Deploy Next.js Blog to Production / 🏗️ Build and Push Docker Image (push) Successful in 30s
Build and Deploy Next.js Blog to Production / 🚀 Deploy to Production (push) Successful in 1m4s
Added envs to variables on the repository
2025-12-02 12:53:14 +02:00

384 lines
15 KiB
YAML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Gitea Actions Workflow for Next.js Blog Application
# This workflow builds a Docker image and deploys it to production
#
# Workflow triggers:
# - Push to master branch (automatic deployment)
# - Manual trigger via workflow_dispatch
#
# Required Secrets (configure in Gitea repository settings):
# - PRODUCTION_HOST: IP address or hostname of production server
# - PRODUCTION_USER: SSH username (e.g., 'deployer')
# - SSH_PRIVATE_KEY: Private SSH key for authentication
#
# Environment Variables (configured below):
# - REGISTRY: Docker registry URL
# - IMAGE_NAME: Docker image name
#
# Docker Registry Configuration:
# - Current registry (repository.workspace:5000) is INSECURE - no authentication required
# - Registry login steps are SKIPPED to avoid 7+ minute timeout delays
# - Docker push/pull operations work without credentials
# - If switching to authenticated registry: uncomment login steps and configure secrets
name: Build and Deploy Next.js Blog to Production
on:
push:
branches:
- master # Trigger on push to master branch
workflow_dispatch: # Allow manual trigger from Gitea UI
env:
# Docker registry configuration
# Update this to match your private registry URL
REGISTRY: repository.workspace:5000
IMAGE_NAME: mypage
jobs:
# ============================================
# Job 1: Code Quality Checks (Linting)
# ============================================
lint:
name: 🔍 Code Quality Checks
runs-on: node-22
# env:
# ACTIONS_RUNTIME_URL: http://192.168.1.53:3000 # Setează la nivel de job
steps:
- name: 🔎 Checkout code
uses: actions/checkout@v4
# with:
# github-server-url: ${{ env.ACTIONS_RUNTIME_URL }}
# - name: 📦 Setup Node.js
# uses: actions/setup-node@v4
# with:
# node-version: "22"
# cache: "npm"
- name: 📥 Install dependencies
run: npm ci
- name: 🔍 Run ESLint
run: npm run lint
continue-on-error: true
- name: 💅 Check code formatting (Prettier)
run: npm run format:check
continue-on-error: true
- name: 🔤 TypeScript type checking
run: npx tsc --noEmit
- name: ✅ All quality checks passed
run: |
echo "✅ All code quality checks passed successfully!"
echo " - ESLint: No linting errors"
echo " - Prettier: Code is properly formatted"
echo " - TypeScript: No type errors"
# ============================================
# Job 2: Build and Push Docker Image
# ============================================
build-and-push:
name: 🏗️ Build and Push Docker Image
runs-on: ubuntu-latest
needs: [lint] # Wait for lint job to complete successfully
steps:
- name: 🔎 Checkout code
uses: actions/checkout@v4
- name: 📝 Create .env file from Gitea secrets
run: |
echo "Creating .env file for Docker build..."
cat > .env << EOF
# Build-time environment variables
NEXT_PUBLIC_SITE_URL=${{ vars.NEXT_PUBLIC_SITE_URL }}
NODE_ENV=production
NEXT_TELEMETRY_DISABLED=1
# Add other build-time variables here as needed
# NEXT_PUBLIC_GA_ID=${{ vars.NEXT_PUBLIC_GA_ID }}
EOF
echo "✅ .env file created successfully"
echo "Preview (secrets masked):"
cat .env | sed 's/=.*/=***MASKED***/g'
# Insecure registry configuration - no authentication required
# The registry at repository.workspace:5000 does not require login
# Docker push/pull operations work without credentials
- name: Registry configuration (insecure - no login required)
run: |
echo "=== Docker Registry Configuration ==="
echo "Registry: ${{ env.REGISTRY }}"
echo "Type: Insecure (no authentication required)"
echo ""
echo " Skipping registry login - insecure registry allows push/pull without credentials"
echo ""
echo "If your registry requires authentication in the future:"
echo " 1. Set REGISTRY_USERNAME and REGISTRY_PASSWORD secrets in Gitea"
echo " 2. Uncomment the login step below this message"
echo " 3. Change registry URL to authenticated registry"
# Uncomment this step if registry requires authentication in the future
# - name: 🔐 Log in to Docker Registry
# timeout-minutes: 1
# run: |
# if [ -n "${{ secrets.REGISTRY_USERNAME }}" ] && [ -n "${{ secrets.REGISTRY_PASSWORD }}" ]; then
# echo "Attempting login to ${{ env.REGISTRY }}..."
# timeout 30s bash -c 'echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin' || {
# echo "⚠️ Login failed - continuing anyway"
# }
# fi
- name: 🏗️ Build Docker image
timeout-minutes: 30
env:
DOCKER_BUILDKIT: 1 # Enable BuildKit for faster builds and better caching
run: |
echo "Building Next.js Docker image with BuildKit..."
echo "Build context size:"
du -sh . 2>/dev/null || echo "Cannot measure context size"
# Build the Docker image
# - Uses Dockerfile.nextjs from project root
# - Tags image with both 'latest' and commit SHA
# - Enables inline cache for faster subsequent builds
# -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} ❗ do this if deploying on PR creation
docker build \
--progress=plain \
--build-arg BUILDKIT_INLINE_CACHE=1 \
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
-f Dockerfile.nextjs \
.
echo "✅ Build successful"
echo "Image size:"
docker images ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- name: 🚀 Push Docker image to registry
run: |
echo "Pushing image to registry..."
# Push both tags (latest and commit SHA)
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
echo "✅ Image pushed successfully"
echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest"
# Clean up sensitive files
rm -f .env
echo "✅ Cleaned up .env file"
# echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}"
# ============================================
# Job 2: Deploy to Production Server
# ============================================
deploy-production:
name: 🚀 Deploy to Production
runs-on: ubuntu-latest
needs: [build-and-push] # Wait for build job to complete
environment:
name: production
url: http://192.168.1.54:3030 # Update with your actual production URL
steps:
- name: 🔎 Checkout code (for docker-compose file)
uses: actions/checkout@v4
# Verify Docker is accessible on production server
# Registry authentication is not required for insecure registry
- name: Verify production server Docker access
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ vars.PRODUCTION_HOST }}
username: ${{ vars.PRODUCTION_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: 22
script: |
echo "=== Verifying Docker is accessible ==="
docker info > /dev/null 2>&1 || {
echo "❌ Docker is not running or user has no access"
echo "Please ensure Docker is installed and user is in docker group"
exit 1
}
echo "✅ Docker is accessible"
echo ""
echo "=== Registry Configuration ==="
echo "Registry: ${{ env.REGISTRY }}"
echo "Type: Insecure (no authentication)"
echo " Skipping registry login - push/pull will work without credentials"
- name: 📁 Ensure application directory structure
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ vars.PRODUCTION_HOST }}
username: ${{ vars.PRODUCTION_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: 22
script: |
echo "=== Ensuring application directory structure ==="
# Verify base directory exists and is writable
# Update /opt/mypage to match your deployment directory
if [ ! -d /opt/mypage ]; then
echo "❌ /opt/mypage does not exist!"
echo "Please run manually on production server:"
echo " sudo mkdir -p /opt/mypage"
echo " sudo chown -R deployer:docker /opt/mypage"
echo " sudo chmod -R 775 /opt/mypage"
exit 1
fi
if [ ! -w /opt/mypage ]; then
echo "❌ /opt/mypage is not writable by $USER user"
echo "Please run manually on production server:"
echo " sudo chown -R deployer:docker /opt/mypage"
echo " sudo chmod -R 775 /opt/mypage"
exit 1
fi
# Create data directories for logs
mkdir -p /opt/mypage/data/logs || { echo "❌ Failed to create logs directory"; exit 1; }
echo "✅ Directory structure ready"
ls -la /opt/mypage
- name: 📦 Copy docker-compose.prod.yml to server
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ vars.PRODUCTION_HOST }}
username: ${{ vars.PRODUCTION_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: 22
source: "docker-compose.prod.yml"
target: "/opt/mypage/"
overwrite: true
- name: 🐳 Deploy application via Docker Compose
uses: appleboy/ssh-action@v1.0.3
env:
# Optional: only needed if registry requires authentication
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD || '' }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME || '' }}
REGISTRY_URL: ${{ env.REGISTRY }}
IMAGE_FULL: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
with:
host: ${{ vars.PRODUCTION_HOST }}
username: ${{ vars.PRODUCTION_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: 22
envs: REGISTRY_PASSWORD,REGISTRY_USERNAME,REGISTRY_URL,IMAGE_FULL
script_stop: true # Stop execution on any error
script: |
echo "=== Starting deployment to production server ==="
cd /opt/mypage
# Registry configuration - insecure registry does not require authentication
echo "=== Registry Configuration ==="
echo "Registry: $REGISTRY_URL"
echo "Type: Insecure (no authentication required)"
echo " Skipping registry login"
echo ""
# Pull latest image from registry
echo "=== Pulling latest Docker image ==="
docker pull "$IMAGE_FULL"
if [ $? -ne 0 ]; then
echo "❌ Failed to pull image, aborting deployment"
exit 1
fi
# Deploy new container
# - Stops old container
# - Removes old container
# - Creates and starts new container with fresh image
echo "=== Deploying new container ==="
docker compose -f docker-compose.prod.yml up -d --force-recreate
if [ $? -ne 0 ]; then
echo "❌ Failed to deploy new container"
echo "Check logs above for errors"
exit 1
fi
# Check container status
echo "=== Container Status ==="
docker compose -f docker-compose.prod.yml ps
# Show recent logs for debugging
echo "=== Recent application logs ==="
docker compose -f docker-compose.prod.yml logs --tail=50
# Clean up old/unused images to save disk space
echo "=== Cleaning up old Docker images ==="
docker image prune -f
echo "✅ Deployment completed successfully ==="
- name: ❤️ Health check
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ vars.PRODUCTION_HOST }}
username: ${{ vars.PRODUCTION_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: 22
script: |
echo "=== Performing health check ==="
cd /opt/mypage
max_attempts=15
attempt=1
# Wait for container to be healthy (respect start_period from health check)
echo "Waiting for application to start (40s start period)..."
sleep 40
# Retry health check up to 15 times
while [ $attempt -le $max_attempts ]; do
# Check if application responds at port 3030
if curl -f http://localhost:3030/ > /dev/null 2>&1; then
echo "✅ Health check passed!"
echo "Application is healthy and responding to requests"
exit 0
fi
echo "Attempt $attempt/$max_attempts: Health check failed, retrying in 5s..."
sleep 5
attempt=$((attempt + 1))
done
# Health check failed - gather diagnostic information
echo "❌ Health check failed after $max_attempts attempts"
echo ""
echo "=== Container Status ==="
docker compose -f docker-compose.prod.yml ps
echo ""
echo "=== Container Health ==="
docker inspect mypage-prod --format='{{.State.Health.Status}}' 2>/dev/null || echo "No health status"
echo ""
echo "=== Recent Application Logs ==="
docker compose -f docker-compose.prod.yml logs --tail=100
exit 1
- name: 📊 Deployment summary
if: always() # Run even if previous steps fail
run: |
echo "### 🚀 Deployment Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Environment**: Production" >> $GITHUB_STEP_SUMMARY
echo "- **Image**: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_STEP_SUMMARY
echo "- **Commit**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
echo "- **Workflow Run**: #${{ github.run_number }}" >> $GITHUB_STEP_SUMMARY
echo "- **Triggered By**: ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
echo "- **Status**: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Next Steps:**" >> $GITHUB_STEP_SUMMARY
echo "1. Verify application is accessible at production URL" >> $GITHUB_STEP_SUMMARY
echo "2. Check application logs for any errors" >> $GITHUB_STEP_SUMMARY
echo "3. Monitor resource usage and performance" >> $GITHUB_STEP_SUMMARY