Skip to content

Deploy

Deploy #30

Workflow file for this run

name: Deploy
# Triggers:
# - Automatically after CI workflow completes successfully on main
# - Manually via workflow_dispatch for hotfixes or rollbacks
on:
workflow_run:
workflows: ["CI"]
types: [completed]
branches: [main]
workflow_dispatch:
inputs:
environment:
description: "Target environment"
required: true
default: "production"
type: choice
options: [production, staging]
run_migrations:
description: "Run database migrations"
required: true
default: true
type: boolean
run_scout_import:
description: "Re-index Typesense (slow — only if schema changed)"
required: true
default: false
type: boolean
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false # never cancel an in-flight deploy
jobs:
deploy:
name: Deploy to ${{ github.event.inputs.environment || 'production' }}
runs-on: ubuntu-latest
# Only deploy if CI succeeded (or triggered manually)
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
environment: ${{ github.event.inputs.environment || 'production' }}
steps:
- name: Checkout
uses: actions/checkout@v4
# ── Build frontend assets on CI runner (npm not available on server) ──
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install Node dependencies
run: npm ci
- name: Build frontend assets
run: npm run build
# ── SSH deploy ──────────────────────────────────────────
# Required GitHub secrets:
# DEPLOY_HOST — server hostname or IP (e.g. aljebal-albeedos.com)
# DEPLOY_PORT — SSH port (e.g. 21098)
# DEPLOY_USER — SSH username (e.g. aljedkrq)
# DEPLOY_KEY — private SSH key (RSA or Ed25519)
# DEPLOY_PATH — absolute path to the app on the server
# DEPLOY_PHP — path to PHP binary on server (e.g. /home/aljedkrq/php84)
# ────────────────────────────────────────────────────────
- name: Setup SSH agent
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
- name: Add server to known hosts
run: ssh-keyscan -p ${{ secrets.DEPLOY_PORT }} -H ${{ secrets.DEPLOY_HOST }} >> ~/.ssh/known_hosts
- name: Upload built assets
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
run: |
scp -P $DEPLOY_PORT -r public/build $DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/public/
- name: Deploy
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
DEPLOY_PHP: ${{ secrets.DEPLOY_PHP }}
RUN_MIGRATIONS: ${{ github.event.inputs.run_migrations || 'true' }}
RUN_SCOUT_IMPORT: ${{ github.event.inputs.run_scout_import || 'false' }}
run: |
ssh -p $DEPLOY_PORT $DEPLOY_USER@$DEPLOY_HOST << EOF
set -e
PHP="${DEPLOY_PHP:-php}"
cd $DEPLOY_PATH
echo "==> Pulling latest code"
git pull origin main
echo "==> Installing PHP dependencies"
COMPOSER=\$(which composer 2>/dev/null || echo "\$HOME/bin/composer")
\$PHP \$COMPOSER install --no-dev --no-interaction --optimize-autoloader --prefer-dist
echo "==> Caching configuration"
\$PHP artisan config:cache
\$PHP artisan route:cache
\$PHP artisan view:cache
\$PHP artisan event:cache
if [ "\$RUN_MIGRATIONS" = "true" ]; then
echo "==> Running database migrations"
\$PHP artisan migrate --force
fi
echo "==> Restarting queue workers"
\$PHP artisan queue:restart
if [ "\$RUN_SCOUT_IMPORT" = "true" ]; then
echo "==> Re-indexing Typesense"
\$PHP artisan scout:flush "App\Domain\Product\Models\Product"
\$PHP artisan scout:import "App\Domain\Product\Models\Product"
\$PHP artisan scout:flush "App\Domain\Category\Models\Category"
\$PHP artisan scout:import "App\Domain\Category\Models\Category"
\$PHP artisan scout:flush "App\Domain\Order\Models\Order"
\$PHP artisan scout:import "App\Domain\Order\Models\Order"
fi
echo "==> Done"
EOF
- name: Notify on failure
if: failure()
run: |
echo "::error::Deployment failed. Check the logs above."
# Add Slack/email notification here if needed