Files
alrahma_sunday_school_api/.gitea/workflows/build.yml
T
root c5fd9d6f66
API CI/CD / Validate (composer + pint) (push) Successful in 2m7s
API CI/CD / Test (PHPUnit) (push) Failing after 55s
API CI/CD / Build frontend assets (push) Successful in 54s
API CI/CD / Security audit (push) Successful in 33s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
Revert "fix(ci): avoid cache:clear — use config:clear + view:clear + clear-compiled instead"
This reverts commit accb55baba.
2026-06-25 18:34:22 -04:00

361 lines
13 KiB
YAML

# Gitea CI/CD for Laravel 12 API
#
# Triggers:
# - Push to any branch
# - Pull requests
# - Tags
#
# Stages: validate → test → build → security
name: API CI/CD
on:
push:
branches: [main, master, develop, 'feature/**', 'fix/**']
tags: ['v*']
pull_request:
branches: [main, master, develop]
env:
APP_ENV: testing
APP_DEBUG: false
APP_KEY: ""
LOG_CHANNEL: stderr
LOG_LEVEL: debug
DB_CONNECTION: sqlite
DB_DATABASE: ${{ github.workspace }}/database/database.sqlite
CACHE_DRIVER: array
SESSION_DRIVER: array
QUEUE_CONNECTION: sync
MAIL_MAILER: array
FILESYSTEM_DISK: local
COMPOSER_CACHE_DIR: ${{ github.workspace }}/.composer-cache
jobs:
# ──────────────────────────────────────────────
# VALIDATE: composer validate + Laravel Pint
# ──────────────────────────────────────────────
validate:
name: Validate (composer + pint)
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/devcontainers/php:8.4
steps:
- name: Checkout repository
run: |
apt-get update
apt-get install -y --no-install-recommends git ca-certificates
git clone --depth 1 https://gitea:${{ secrets.GITHUB_TOKEN }}@192.168.3.80/melabidi/alrahma_sunday_school_api.git .
env:
GIT_SSL_NO_VERIFY: "1"
- name: Install system dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends \
git unzip curl libzip-dev libpng-dev libonig-dev libxml2-dev libsqlite3-dev \
nodejs
docker-php-ext-install mbstring zip gd pdo_sqlite
- name: Install Composer
run: |
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
rm composer-setup.php
- name: Cache Composer dependencies
uses: actions/cache@v4
with:
path: |
vendor/
.composer-cache/
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install PHP dependencies
run: |
composer install --prefer-dist --no-interaction --no-progress
composer dump-autoload
- name: Composer validate
run: composer validate
- name: Laravel Pint (code style check)
run: |
composer require --dev laravel/pint --ignore-platform-reqs || true
vendor/bin/pint --test || echo "Pint found style issues (non-blocking)"
# ──────────────────────────────────────────────
# TEST: PHPUnit (Unit + Feature with SQLite)
# ──────────────────────────────────────────────
test:
name: Test (PHPUnit)
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/devcontainers/php:8.4
env:
NODE_TLS_REJECT_UNAUTHORIZED: "0"
steps:
- name: Checkout repository
run: |
apt-get update
apt-get install -y --no-install-recommends git ca-certificates
git clone --depth 1 https://gitea:${{ secrets.GITHUB_TOKEN }}@192.168.3.80/melabidi/alrahma_sunday_school_api.git .
env:
GIT_SSL_NO_VERIFY: "1"
- name: Install system dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends \
git unzip curl libzip-dev libpng-dev libonig-dev libxml2-dev libsqlite3-dev \
nodejs
docker-php-ext-install mbstring zip gd pdo_sqlite
- name: Install Composer
run: |
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
rm composer-setup.php
- name: Cache Composer dependencies
uses: actions/cache@v4
with:
path: |
vendor/
.composer-cache/
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install PHP dependencies
run: |
composer install --prefer-dist --no-interaction --no-progress
composer dump-autoload
- name: Bootstrap Laravel testing environment
run: |
cat > .env <<'EOF'
APP_NAME=school_api
APP_ENV=testing
APP_KEY=
APP_DEBUG=false
APP_URL=http://localhost
LOG_CHANNEL=stderr
LOG_LEVEL=debug
DB_CONNECTION=sqlite
DB_DATABASE=${{ github.workspace }}/database/database.sqlite
CACHE_DRIVER=array
SESSION_DRIVER=array
QUEUE_CONNECTION=sync
MAIL_MAILER=array
FILESYSTEM_DISK=local
JWT_SECRET=ci_test_jwt_secret_not_for_production
EOF
mkdir -p database storage/framework/cache storage/framework/sessions \
storage/framework/views storage/logs bootstrap/cache reports
touch database/database.sqlite
php artisan key:generate --force
php artisan jwt:secret --force || true
- name: Run database migrations
run: php artisan migrate:fresh --force
- name: Clear caches
run: php artisan optimize:clear
- name: Run Unit tests
continue-on-error: true
run: php artisan test --testsuite=Unit --log-junit reports/phpunit-unit.xml || echo "Unit tests have failures (non-blocking)"
- name: Run Feature tests
run: php artisan test --testsuite=Feature --log-junit reports/phpunit-feature.xml
- name: Upload test reports
uses: actions/upload-artifact@v3
if: always()
continue-on-error: true
with:
name: test-reports
path: reports/
retention-days: 7
# ──────────────────────────────────────────────
# BUILD: Compile frontend assets (Vite)
# ──────────────────────────────────────────────
build:
name: Build frontend assets
runs-on: ubuntu-latest
container:
image: node:22-bookworm-slim
env:
NODE_TLS_REJECT_UNAUTHORIZED: "0"
steps:
- name: Checkout repository
run: |
apt-get update
apt-get install -y --no-install-recommends git ca-certificates
git clone --depth 1 https://gitea:${{ secrets.GITHUB_TOKEN }}@192.168.3.80/melabidi/alrahma_sunday_school_api.git .
env:
GIT_SSL_NO_VERIFY: "1"
- name: Cache npm dependencies
uses: actions/cache@v4
with:
path: node_modules/
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
- name: Install dependencies
run: npm install --cache .npm --prefer-offline
- name: Build assets
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v3
continue-on-error: true
with:
name: frontend-assets
path: |
public/build/
public/css/
public/js/
retention-days: 7
# ──────────────────────────────────────────────
# SECURITY: Dependency audits + secret scanning
# ──────────────────────────────────────────────
security:
name: Security audit
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/devcontainers/php:8.4
steps:
- name: Checkout repository
run: |
apt-get update
apt-get install -y --no-install-recommends git ca-certificates
git clone --depth 1 https://gitea:${{ secrets.GITHUB_TOKEN }}@192.168.3.80/melabidi/alrahma_sunday_school_api.git .
env:
GIT_SSL_NO_VERIFY: "1"
- name: Install system dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends git unzip curl libzip-dev libpng-dev libonig-dev libxml2-dev libsqlite3-dev nodejs
docker-php-ext-install mbstring zip gd pdo_sqlite
- name: Install Composer
run: |
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
rm composer-setup.php
- name: Install PHP dependencies
run: |
composer install --prefer-dist --no-interaction --no-progress
composer dump-autoload
- name: Composer audit
run: composer audit --locked --no-interaction --format=json || echo "Audit found advisories (non-blocking)"
- name: Secret detection (basic)
run: |
echo "Scanning for committed secrets..."
if grep -RInE \
"(APP_KEY=base64:[A-Za-z0-9+/=]{44}|DB_PASSWORD=.+|JWT_SECRET=.+|MAIL_PASSWORD=.+|AKIA[0-9A-Z]{16}|-----BEGIN (RSA|OPENSSH|PRIVATE) KEY-----)" \
--exclude-dir=.git \
--exclude-dir=vendor \
--exclude-dir=node_modules \
--exclude=.env.example \
--exclude=.env.prod.example \
. 2>&1; then
echo "❌ Secrets detected!"
exit 1
else
echo "✅ No secrets found"
fi
# ──────────────────────────────────────────────
# DEPLOY (manual): to shared hosting via SSH
# ──────────────────────────────────────────────
deploy:
name: Deploy to shared hosting (PHP)
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/devcontainers/php:8.4
env:
NODE_TLS_REJECT_UNAUTHORIZED: "0"
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
needs: [test, build, security]
environment:
name: production
url: ${{ vars.PRODUCTION_URL }}
steps:
- name: Checkout repository
run: |
apt-get update
apt-get install -y --no-install-recommends git ca-certificates
git clone --depth 1 https://gitea:${{ secrets.GITHUB_TOKEN }}@192.168.3.80/melabidi/alrahma_sunday_school_api.git .
env:
GIT_SSL_NO_VERIFY: "1"
- name: Install system dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends \
git unzip curl libzip-dev libpng-dev libonig-dev libxml2-dev \
openssh-client sshpass rsync nodejs
docker-php-ext-install mbstring zip gd pdo_mysql
- name: Install Composer
run: |
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
rm composer-setup.php
- name: Install production PHP dependencies
run: |
composer install --no-dev --optimize-autoloader --no-interaction --no-progress
- name: Download frontend build artifacts
uses: actions/download-artifact@v4
with:
name: frontend-assets
path: ./
- name: Deploy Laravel app to shared hosting
run: |
sshpass -p "${{ secrets.SSH_PASSWORD }}" rsync -avz --delete \
-e "ssh -p ${{ vars.SSH_PORT || 22 }} -o StrictHostKeyChecking=no" \
--exclude='.env' \
--exclude='.git' \
--exclude='.gitea' \
--exclude='tests' \
--exclude='storage/logs/*' \
--exclude='database/database.sqlite' \
--exclude='node_modules' \
--exclude='.npm' \
--exclude='reports' \
--exclude='.phpunit.result.cache' \
--exclude='package-lock.json' \
--exclude='.composer-cache' \
./ \
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ vars.SSH_TARGET_DIR }}/
- name: Post-deploy artisan commands
run: |
sshpass -p "${{ secrets.SSH_PASSWORD }}" ssh \
-o StrictHostKeyChecking=no \
-p ${{ vars.SSH_PORT || 22 }} \
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
"cd ${{ vars.SSH_TARGET_DIR }} && \
php artisan migrate --force && \
php artisan config:cache && \
php artisan route:cache && \
php artisan view:cache && \
php artisan optimize"