Files

5.7 KiB

CI/CD Pipeline

This template includes a GitHub Actions workflow for continuous integration and deployment.

Overview

┌─────────────┐     ┌─────────────┐     ┌─────────────────┐
│   Push to   │────▶│  Run Tests  │────▶│ Deploy Staging  │
│   develop   │     │  + Lint     │     │  (automatic)    │
└─────────────┘     └─────────────┘     └─────────────────┘

┌─────────────┐     ┌─────────────┐     ┌─────────────────┐
│   Push to   │────▶│  Run Tests  │────▶│ Deploy Prod     │
│    main     │     │  + Lint     │     │  (with approval)│
└─────────────┘     └─────────────┘     └─────────────────┘

Workflow File

Located at .github/workflows/ci.yml

Jobs

Job Trigger Description
tests All pushes/PRs Run Pest tests + Pint lint
deploy-staging Push to develop Auto-deploy to staging
deploy-production Push to main Deploy with approval

Setup

1. Create GitHub Secrets

Go to: Repository → Settings → Secrets and variables → Actions

For Staging:

STAGING_HOST        - Staging server IP/hostname
STAGING_USER        - SSH username
STAGING_SSH_KEY     - Private SSH key (full content)

For Production:

PRODUCTION_HOST     - Production server IP/hostname
PRODUCTION_USER     - SSH username
PRODUCTION_SSH_KEY  - Private SSH key (full content)

2. Generate SSH Key

# Generate a new key pair
ssh-keygen -t ed25519 -C "github-actions" -f github-actions-key

# Add public key to server
cat github-actions-key.pub >> ~/.ssh/authorized_keys

# Copy private key to GitHub secret
cat github-actions-key

3. Configure Server

On your server, ensure:

# Create deployment directory
sudo mkdir -p /var/www/staging
sudo mkdir -p /var/www/production
sudo chown -R $USER:www-data /var/www/staging /var/www/production

# Clone repository
cd /var/www/staging
git clone git@github.com:your-repo.git .

# Install dependencies
composer install
npm install && npm run build

# Configure environment
cp .env.example .env
php artisan key:generate
# Edit .env with production values

# Set permissions
chmod -R 775 storage bootstrap/cache

4. Environment Protection (Optional)

For production deployments with approval:

  1. Go to Repository → Settings → Environments
  2. Create production environment
  3. Enable "Required reviewers"
  4. Add team members who can approve

Workflow Customization

Add More Tests

- name: Run security audit
  working-directory: ./src
  run: composer audit

- name: Run static analysis
  working-directory: ./src
  run: ./vendor/bin/phpstan analyse

Add Notifications

- name: Notify Slack
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    fields: repo,commit,author,action
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
  if: always()

Add Database Migrations Check

- name: Check pending migrations
  working-directory: ./src
  run: |
    PENDING=$(php artisan migrate:status | grep -c "No" || true)
    if [ "$PENDING" -gt 0 ]; then
      echo "::warning::There are pending migrations"
    fi

Manual Deployment

If you prefer manual deployments:

# On your server
cd /var/www/production

# Enable maintenance mode
php artisan down

# Pull latest code
git pull origin main

# Install dependencies
composer install --no-dev --optimize-autoloader

# Run migrations
php artisan migrate --force

# Clear and cache
php artisan config:cache
php artisan route:cache
php artisan view:cache

# Restart queue workers
php artisan queue:restart

# Disable maintenance mode
php artisan up

Deployment Script

Create deploy/scripts/deploy.sh for reusable deployment:

#!/bin/bash
set -e

echo "🚀 Starting deployment..."

# Enter maintenance mode
php artisan down

# Pull latest changes
git pull origin main

# Install dependencies
composer install --no-dev --optimize-autoloader

# Run migrations
php artisan migrate --force

# Build assets
npm install
npm run build

# Clear caches
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache

# Restart queue
php artisan queue:restart

# Exit maintenance mode
php artisan up

echo "✅ Deployment complete!"

Rollback

If deployment fails:

# Revert to previous commit
git reset --hard HEAD~1

# Or specific commit
git reset --hard <commit-hash>

# Re-run caching
php artisan config:cache
php artisan route:cache

# Restart services
php artisan queue:restart
php artisan up

Testing Locally

Test the CI workflow locally with act:

# Install act
brew install act  # macOS
# or
curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash

# Run tests job
act -j tests

# Run with secrets
act -j tests --secret-file .secrets

Troubleshooting

SSH Connection Failed

  • Verify SSH key is correct (no extra newlines)
  • Check server firewall allows port 22
  • Ensure key is added to ~/.ssh/authorized_keys

Permission Denied

  • Check file ownership: chown -R www-data:www-data /var/www
  • Check directory permissions: chmod -R 775 storage bootstrap/cache

Composer/NPM Fails

  • Ensure sufficient memory on server
  • Check PHP extensions are installed
  • Verify Node.js version matches requirements