name: CI on: push: branches: [main] pull_request: concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: APP_ENV: testing APP_KEY: base64:NXm/6jIyFcDGHoMKGc5QZuSaq0dRZFYPg1Isuy1fNvE= APP_LOCALE: pt_BR APP_FALLBACK_LOCALE: pt_BR APP_TIMEZONE: America/Fortaleza BCRYPT_ROUNDS: 4 CACHE_STORE: database DB_CONNECTION: pgsql DB_HOST: 127.0.0.1 DB_PORT: 5432 DB_DATABASE: amare_test DB_USERNAME: amare DB_PASSWORD: secret QUEUE_CONNECTION: database SESSION_DRIVER: database jobs: static: name: static runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - run: cp .env.example .env - uses: shivammathur/setup-php@v2 with: php-version: "8.4" extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, pdo_pgsql, bcmath, intl, sodium, gd coverage: none - uses: actions/cache@v5 with: path: ~/.composer/cache/files key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }} restore-keys: composer-${{ runner.os }}- - run: composer validate --strict - run: composer install --no-interaction --prefer-dist - run: composer pint:check - run: composer phpstan - run: composer audit unit: name: unit runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - run: cp .env.example .env - uses: shivammathur/setup-php@v2 with: php-version: "8.4" extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, pdo_pgsql, bcmath, intl, sodium, gd coverage: none - uses: actions/cache@v5 with: path: ~/.composer/cache/files key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }} restore-keys: composer-${{ runner.os }}- - run: composer install --no-interaction --prefer-dist - run: npm ci - run: npm run build - run: composer test:unit feature: name: feature runs-on: ubuntu-latest services: postgres: image: postgres:17 env: POSTGRES_DB: amare_test POSTGRES_USER: amare POSTGRES_PASSWORD: secret ports: - 5432:5432 options: >- --health-cmd "pg_isready -U amare -d amare_test" --health-interval 5s --health-timeout 5s --health-retries 10 steps: - uses: actions/checkout@v5 - run: cp .env.example .env - uses: shivammathur/setup-php@v2 with: php-version: "8.4" extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, pdo_pgsql, bcmath, intl, sodium, gd coverage: none - uses: actions/cache@v5 with: path: ~/.composer/cache/files key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }} restore-keys: composer-${{ runner.os }}- - uses: actions/cache@v5 with: path: ~/.npm key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} restore-keys: npm-${{ runner.os }}- - run: composer install --no-interaction --prefer-dist - run: npm ci - run: npm run build - run: php artisan migrate --force - run: composer test:feature browser: name: browser runs-on: ubuntu-latest services: postgres: image: postgres:17 env: POSTGRES_DB: amare_test POSTGRES_USER: amare POSTGRES_PASSWORD: secret ports: - 5432:5432 options: >- --health-cmd "pg_isready -U amare -d amare_test" --health-interval 5s --health-timeout 5s --health-retries 10 steps: - uses: actions/checkout@v5 - run: cp .env.example .env - uses: shivammathur/setup-php@v2 with: php-version: "8.4" extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, pdo_pgsql, bcmath, intl, sodium, gd coverage: none - uses: actions/cache@v5 with: path: ~/.composer/cache/files key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }} restore-keys: composer-${{ runner.os }}- - uses: actions/cache@v5 with: path: ~/.npm key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} restore-keys: npm-${{ runner.os }}- - run: composer install --no-interaction --prefer-dist - run: npm ci - run: npm run build - run: npx playwright install chromium --with-deps - run: php artisan migrate --force - run: php artisan db:seed --class=VisualContentSeeder --force - run: php artisan storage:link - name: Build application image run: docker build -t amare-app:ci . - name: Run browser tests against FrankenPHP container env: APP_FROZEN_NOW: "2026-03-15T12:00:00-03:00" run: | docker run -d --name amare-web \ -e APP_ENV=testing \ -e APP_KEY="${APP_KEY}" \ -e APP_URL=http://127.0.0.1:8000 \ -e APP_LOCALE=pt_BR \ -e APP_FALLBACK_LOCALE=pt_BR \ -e APP_TIMEZONE=America/Fortaleza \ -e APP_FROZEN_NOW="${APP_FROZEN_NOW}" \ -e DB_CONNECTION=pgsql \ -e DB_HOST=host.docker.internal \ -e DB_PORT=5432 \ -e DB_DATABASE=amare_test \ -e DB_USERNAME=amare \ -e DB_PASSWORD=secret \ -e SESSION_DRIVER=database \ -e CACHE_STORE=database \ -e QUEUE_CONNECTION=database \ --add-host=host.docker.internal:host-gateway \ -v "${GITHUB_WORKSPACE}/storage/app/public:/app/storage/app/public" \ -p 8000:8000 \ amare-app:ci for i in $(seq 1 30); do if curl -fsS http://127.0.0.1:8000/up; then break fi sleep 2 done curl -fsS http://127.0.0.1:8000/up ./vendor/bin/pest --testsuite=Browser - name: Collect failure diagnostics if: failure() run: | mkdir -p artifacts/browser docker logs amare-web > artifacts/browser/container.log 2>&1 || true cp -R storage/logs artifacts/browser/app-logs 2>/dev/null || true cp -R tests/Browser/Screenshots artifacts/browser/screenshots 2>/dev/null || true cp -R tests/.pest artifacts/browser/pest 2>/dev/null || true - name: Upload browser failure artifacts if: failure() uses: actions/upload-artifact@v4 with: name: browser-failure-artifacts path: artifacts/browser if-no-files-found: ignore container: name: container runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - name: Build production image run: docker build -t amare-app:ci . - name: Verify container healthcheck and storage link run: | docker run -d --name amare-health \ -e APP_ENV=production \ -e APP_KEY="${{ env.APP_KEY }}" \ -e APP_URL=http://127.0.0.1:8000 \ -e APP_DEBUG=false \ -e DB_CONNECTION=pgsql \ -e DB_HOST=127.0.0.1 \ -e DB_PORT=5432 \ -e DB_DATABASE=amare \ -e DB_USERNAME=amare \ -e DB_PASSWORD=secret \ -p 8000:8000 \ amare-app:ci for i in $(seq 1 30); do if curl -fsS http://127.0.0.1:8000/up; then docker exec amare-health test -L /app/public/storage exit 0 fi sleep 2 done docker logs amare-health exit 1