|
| 1 | +name: Integration test |
| 2 | + |
| 3 | +on: |
| 4 | + schedule: |
| 5 | + - cron: "0 5 * * *" # Run daily at 05:00 UTC |
| 6 | + workflow_dispatch: # Allow manual execution |
| 7 | + |
| 8 | +permissions: |
| 9 | + contents: read |
| 10 | + issues: write |
| 11 | + |
| 12 | +jobs: |
| 13 | + e2e-integration: |
| 14 | + name: Full Symfony + EasyAdmin integration |
| 15 | + runs-on: ubuntu-latest |
| 16 | + timeout-minutes: 25 |
| 17 | + |
| 18 | + steps: |
| 19 | + - uses: actions/checkout@v5 |
| 20 | + |
| 21 | + - name: Setup PHP |
| 22 | + uses: shivammathur/setup-php@v2 |
| 23 | + with: |
| 24 | + php-version: "8.4" |
| 25 | + coverage: none |
| 26 | + extensions: mbstring, intl, pdo, pdo_sqlite, sqlite3 |
| 27 | + ini-values: date.timezone=UTC |
| 28 | + |
| 29 | + - name: Install dependencies |
| 30 | + run: | |
| 31 | + sudo apt-get update && sudo apt-get install -y sqlite3 expect wget gpg |
| 32 | + wget https://get.symfony.com/cli/installer -O - | bash |
| 33 | + mv ~/.symfony*/bin/symfony /usr/local/bin/symfony |
| 34 | + symfony version |
| 35 | +
|
| 36 | + - name: Create fresh Symfony app |
| 37 | + run: | |
| 38 | + composer create-project symfony/skeleton:"^7.3" e2e-app |
| 39 | + cd e2e-app |
| 40 | + composer config extra.symfony.require "7.3.*" |
| 41 | + composer require symfony/orm-pack symfony/twig-pack symfony/runtime |
| 42 | + composer require easycorp/easyadmin-bundle |
| 43 | + composer require --dev symfony/maker-bundle doctrine/doctrine-fixtures-bundle zenstruck/foundry symfony/test-pack fakerphp/faker |
| 44 | +
|
| 45 | + - name: Configure SQLite |
| 46 | + working-directory: e2e-app |
| 47 | + run: | |
| 48 | + sed -i 's|^#\? *DATABASE_URL=.*$|DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"|' .env |
| 49 | + mkdir -p var |
| 50 | +
|
| 51 | + - name: Create Product entity |
| 52 | + working-directory: e2e-app |
| 53 | + run: | |
| 54 | + expect <<'EOD' |
| 55 | + spawn php bin/console make:entity Product |
| 56 | + expect "New property name" { send "name\r" } |
| 57 | + expect "Field type" { send "string\r" } |
| 58 | + expect "Field length" { send "\r" } |
| 59 | + expect "nullable" { send "no\r" } |
| 60 | + expect "New property name" { send "price\r" } |
| 61 | + expect "Field type" { send "integer\r" } |
| 62 | + expect "nullable" { send "no\r" } |
| 63 | + expect "New property name" { send "\r" } |
| 64 | + expect eof |
| 65 | + EOD |
| 66 | +
|
| 67 | + - name: Create DB schema |
| 68 | + working-directory: e2e-app |
| 69 | + run: | |
| 70 | + php bin/console doctrine:database:create --if-not-exists -q |
| 71 | + php bin/console doctrine:schema:create -q |
| 72 | +
|
| 73 | + - name: Generate Dashboard and CRUD |
| 74 | + working-directory: e2e-app |
| 75 | + run: | |
| 76 | + php bin/console make:admin:dashboard --no-interaction |
| 77 | + php bin/console make:admin:crud Product --no-interaction |
| 78 | + |
| 79 | + # Add MenuItem::linkToCrud() entry if missing |
| 80 | + file="src/Controller/Admin/DashboardController.php" |
| 81 | + if ! grep -q "linkToCrud" "$file"; then |
| 82 | + sed -i '/yield MenuItem::linkToDashboard/a\ |
| 83 | + yield MenuItem::linkToCrud("Products", "fa fa-box", App\\Entity\\Product::class);' "$file" |
| 84 | + fi |
| 85 | +
|
| 86 | + - name: Create factory and fixtures |
| 87 | + working-directory: e2e-app |
| 88 | + run: | |
| 89 | + php bin/console make:factory ProductFactory --no-interaction |
| 90 | + php bin/console make:fixtures --no-interaction |
| 91 | + sed -i 's|// TODO: Implement the load() method|use App\\Factory\\ProductFactory;\n\n ProductFactory::createMany(10);|' src/DataFixtures/AppFixtures.php |
| 92 | +
|
| 93 | + - name: Load fixtures |
| 94 | + working-directory: e2e-app |
| 95 | + run: php bin/console doctrine:fixtures:load --no-interaction -q |
| 96 | + |
| 97 | + - name: Start Symfony server |
| 98 | + working-directory: e2e-app |
| 99 | + run: | |
| 100 | + symfony server:start --no-tls --port=8000 --daemon --no-humanize |
| 101 | + for i in {1..20}; do |
| 102 | + if curl -sSf http://127.0.0.1:8000/ > /dev/null; then break; fi |
| 103 | + sleep 0.5 |
| 104 | + done |
| 105 | +
|
| 106 | + - name: Functional smoke test |
| 107 | + id: smoke |
| 108 | + working-directory: e2e-app |
| 109 | + run: | |
| 110 | + set -e |
| 111 | + status=$(curl -sS -o /tmp/page.html -w "%{http_code}" http://127.0.0.1:8000/admin) |
| 112 | + echo "HTTP_STATUS=$status" >> $GITHUB_OUTPUT |
| 113 | + test "$status" = "200" |
| 114 | + grep -q "Products" /tmp/page.html |
| 115 | + grep -qi "Dashboard" /tmp/page.html |
| 116 | + grep -qi "Product" /tmp/page.html || (echo "No product content found" && exit 1) |
| 117 | +
|
| 118 | + - name: Stop Symfony server |
| 119 | + if: always() |
| 120 | + working-directory: e2e-app |
| 121 | + run: symfony server:stop || true |
| 122 | + |
| 123 | + - name: Create issue on failure |
| 124 | + if: failure() |
| 125 | + uses: actions/github-script@v7 |
| 126 | + with: |
| 127 | + script: | |
| 128 | + const fs = require('fs'); |
| 129 | + let body = 'Integration test failed.\n\n'; |
| 130 | + try { |
| 131 | + const page = fs.readFileSync('/tmp/page.html', 'utf8'); |
| 132 | + body += 'Last page HTML (truncated):\n\n```\n' + page.slice(0, 4000) + '\n```\n'; |
| 133 | + } catch (e) { |
| 134 | + body += 'Could not attach page HTML.\n'; |
| 135 | + } |
| 136 | + const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; |
| 137 | + body += `\nRun: ${runUrl}`; |
| 138 | + await github.rest.issues.create({ |
| 139 | + owner: context.repo.owner, |
| 140 | + repo: context.repo.repo, |
| 141 | + title: `Integration test failed: ${new Date().toISOString()}`, |
| 142 | + body |
| 143 | + }); |
0 commit comments