From 12ae8d47b4c0b6e1168be8ea0bf78547674e312d Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 11 Aug 2026 13:17:55 +0200 Subject: [PATCH 01/12] ci: add a working PWA lint gate Triggers without requiring a label, unlike the deployment workflow, so bot-opened dependency bumps are gated too. The install is frozen, so a lockfile out of sync with the manifest fails instead of being silently resolved. The package manager version is activated globally rather than left to the manifest, the dependency cache being resolved from the repository root where nothing pins it. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 101 +++++++++++++++------------------------ 1 file changed, 39 insertions(+), 62 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 084f2435a..77ecaae48 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,65 +1,42 @@ -# name: CI +name: CI -# on: -# push: -# branches: -# - deploy-v3 -# pull_request: ~ -# workflow_dispatch: ~ +on: + push: + branches: + - main + pull_request: ~ + workflow_dispatch: ~ -# concurrency: -# group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} -# cancel-in-progress: true +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true -# jobs: -# tests: -# name: Tests -# runs-on: ubuntu-latest -# permissions: -# contents: 'read' -# id-token: 'write' -# steps: -# - name: Checkout -# uses: actions/checkout@v3 -# - name: Pull images -# run: docker compose pull --ignore-pull-failures || true -# - name: Start services -# run: docker compose up --build -d -# - name: Wait for services -# run: | -# while status="$(docker inspect --format="{{if .Config.Healthcheck}}{{print .State.Health.Status}}{{end}}" "$(docker compose ps -q php)")"; do -# case $status in -# starting) sleep 1;; -# healthy) exit 0;; -# unhealthy) -# docker compose ps -# docker compose logs -# exit 1 -# ;; -# esac -# done -# exit 1 -# - name: Check HTTP reachability -# run: curl -v -o /dev/null http://localhost -# - name: Check API reachability -# run: curl -vk -o /dev/null https://localhost -# - name: Check PWA reachability -# run: "curl -vk -o /dev/null -H 'Accept: text/html' https://localhost" -# - name: Create test database -# run: | -# docker compose exec -T php bin/console -e test doctrine:database:create -# docker compose exec -T php bin/console -e test doctrine:migrations:migrate --no-interaction -# - name: PHPUnit -# run: docker compose exec -T php bin/phpunit -# - name: Doctrine Schema Validator -# run: docker compose exec -T php bin/console doctrine:schema:validate -# - name: Psalm -# run: docker compose exec -T php vendor/bin/psalm -# # gcloud does not work with Python 3.10 because collections. Mappings were removed in Python 3.10. -# - uses: actions/setup-python@v4 -# with: -# python-version: 3.9.15 -# - name: Setup gcloud -# uses: google-github-actions/setup-gcloud@v1 -# - name: Lint Helm -# run: helm lint ./helm/api-platform/ +permissions: + contents: read + +jobs: + pwa: + name: PWA + runs-on: ubuntu-latest + defaults: + run: + working-directory: pwa + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + # Activated globally: the cache lookup below runs pnpm from the repository + # root, where no packageManager field pins the version. + - name: Enable corepack + run: | + corepack enable + corepack prepare pnpm@9.1.1 --activate + - name: Setup Node + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 20 + cache: pnpm + cache-dependency-path: pwa/pnpm-lock.yaml + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: ESLint + run: pnpm lint From 8e4e77a02e60b7d0b8cfca74f346d4cc98e7a043 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 11 Aug 2026 13:32:15 +0200 Subject: [PATCH 02/12] ci: raise a set of correctness lint rules to error The shared config this project extends reports everything as a warning, by design, so the linter always exited zero and the check it feeds could never fail. Rules covering code that cannot work as written, rather than matters of style, are now errors, which leaves formatting and unused symbols as warnings. Co-Authored-By: Claude Opus 5 (1M context) --- pwa/.eslintrc.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pwa/.eslintrc.json b/pwa/.eslintrc.json index 2de1e6848..8e0e252ea 100644 --- a/pwa/.eslintrc.json +++ b/pwa/.eslintrc.json @@ -14,7 +14,18 @@ "@typescript-eslint/no-explicit-any": "off", "prettier/prettier": [ "warn" - ] + ], + "getter-return": "error", + "no-const-assign": "error", + "no-dupe-args": "error", + "no-dupe-keys": "error", + "no-func-assign": "error", + "no-import-assign": "error", + "no-obj-calls": "error", + "no-setter-return": "error", + "no-unreachable": "error", + "use-isnan": "error", + "valid-typeof": "error" }, "settings": { "next": { From c95a3aeb633ff3a7f1363be07e4b5ae164a14024 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 11 Aug 2026 13:23:04 +0200 Subject: [PATCH 03/12] fix(api): point dev routing imports at the PHP resources The framework and profiler bundles dropped their XML routing resources in favour of PHP ones, but the imports were never updated, so every console command run in the dev environment aborted while loading the router. Installing dependencies failed with it, its post-install scripts warming the dev cache. Co-Authored-By: Claude Opus 5 (1M context) --- api/config/routes/framework.yaml | 2 +- api/config/routes/web_profiler.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/config/routes/framework.yaml b/api/config/routes/framework.yaml index 0fc74bbac..bc1feace1 100644 --- a/api/config/routes/framework.yaml +++ b/api/config/routes/framework.yaml @@ -1,4 +1,4 @@ when@dev: _errors: - resource: '@FrameworkBundle/Resources/config/routing/errors.xml' + resource: '@FrameworkBundle/Resources/config/routing/errors.php' prefix: /_error diff --git a/api/config/routes/web_profiler.yaml b/api/config/routes/web_profiler.yaml index 8d85319fd..b3b7b4b0e 100644 --- a/api/config/routes/web_profiler.yaml +++ b/api/config/routes/web_profiler.yaml @@ -1,8 +1,8 @@ when@dev: web_profiler_wdt: - resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' + resource: '@WebProfilerBundle/Resources/config/routing/wdt.php' prefix: /_wdt web_profiler_profiler: - resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' + resource: '@WebProfilerBundle/Resources/config/routing/profiler.php' prefix: /_profiler From f786b8c44063451ad0e2d3d54c35436a54f86d45 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 11 Aug 2026 13:23:39 +0200 Subject: [PATCH 04/12] ci: add an API lint gate Runs the config, template and container linters, which catch a bundle upgrade that breaks service wiring or removes a resource an import still points at. Validation of the manifest also fails when the lock file has drifted out of sync with it. The test environment is forced, so the job never loads the development toolbar and profiler, which are irrelevant to a gate and pull in more surface than they are worth. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 77ecaae48..f50c07eb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,3 +40,40 @@ jobs: run: pnpm install --frozen-lockfile - name: ESLint run: pnpm lint + + api: + name: API + runs-on: ubuntu-latest + env: + APP_ENV: test + defaults: + run: + working-directory: api + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Setup PHP + uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2 + with: + php-version: '8.4' + coverage: none + tools: composer:v2 + - name: Validate composer.json and composer.lock + run: composer validate --strict --no-check-publish + - name: Get Composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT" + - name: Cache Composer dependencies + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('api/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + - name: Install dependencies + run: composer install --prefer-dist --no-progress + - name: Lint YAML + run: bin/console lint:yaml config --parse-tags + - name: Lint Twig + run: bin/console lint:twig templates + - name: Lint container + run: bin/console lint:container From de29ef7b57b304a9e1ffaecda2a1a809feee0aee Mon Sep 17 00:00:00 2001 From: Maxcastel Date: Wed, 15 Apr 2026 10:30:54 +0200 Subject: [PATCH 05/12] feat: re enable CI --- .github/workflows/ci.yml | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f50c07eb9..365d9ce8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,3 +77,53 @@ jobs: run: bin/console lint:twig templates - name: Lint container run: bin/console lint:container + + tests: + name: Tests + runs-on: ubuntu-latest + permissions: + contents: 'read' + id-token: 'write' + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Pull images + run: docker compose pull --ignore-pull-failures || true + - name: Start services + run: docker compose up --build -d + - name: Wait for services + run: | + while status="$(docker inspect --format="{{if .Config.Healthcheck}}{{print .State.Health.Status}}{{end}}" "$(docker compose ps -q php)")"; do + case $status in + starting) sleep 1;; + healthy) exit 0;; + unhealthy) + docker compose ps + docker compose logs + exit 1 + ;; + esac + done + exit 1 + - name: Check HTTP reachability + run: curl -v -o /dev/null http://localhost + - name: Check API reachability + run: curl -vk -o /dev/null https://localhost + - name: Check PWA reachability + run: "curl -vk -o /dev/null -H 'Accept: text/html' https://localhost" + - name: Create test database + run: | + docker compose exec -T php bin/console -e test doctrine:database:create + docker compose exec -T php bin/console -e test doctrine:migrations:migrate --no-interaction + - name: PHPUnit + run: docker compose exec -T php bin/phpunit + - name: Doctrine Schema Validator + run: docker compose exec -T php bin/console doctrine:schema:validate + # gcloud does not work with Python 3.10 because collections. Mappings were removed in Python 3.10. + - uses: actions/setup-python@v4 + with: + python-version: 3.9.15 + - name: Setup gcloud + uses: google-github-actions/setup-gcloud@v1 + - name: Lint Helm + run: helm lint ./helm/api-platform/ From a0ba2bed06434b07641b42f172d3a2f26c82c89b Mon Sep 17 00:00:00 2001 From: Maxcastel Date: Wed, 15 Apr 2026 11:30:49 +0200 Subject: [PATCH 06/12] fix(ci): update CI env variable and docker-compose secrets config --- .github/workflows/ci.yml | 2 ++ docker-compose.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 365d9ce8f..6a6556d72 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,6 +84,8 @@ jobs: permissions: contents: 'read' id-token: 'write' + env: + GITHUB_KEY: ${{ secrets.GH_KEY }} steps: - name: Checkout uses: actions/checkout@v3 diff --git a/docker-compose.yml b/docker-compose.yml index 4f48d9866..5e269a242 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -88,4 +88,4 @@ volumes: secrets: GITHUB_KEY: - file: ./secret_github_key + environment: GITHUB_KEY From 97e0b318a4655ea54024726efa6c12c15ffa4b80 Mon Sep 17 00:00:00 2001 From: Maxcastel Date: Wed, 15 Apr 2026 11:45:09 +0200 Subject: [PATCH 07/12] fix(test): remove mercure true from Greeting #[ApiResource] --- api/src/Entity/Greeting.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/Entity/Greeting.php b/api/src/Entity/Greeting.php index 93c831a4d..4e1d1aa92 100644 --- a/api/src/Entity/Greeting.php +++ b/api/src/Entity/Greeting.php @@ -9,7 +9,7 @@ /** * This is a dummy entity. Remove it! */ -#[ApiResource(mercure: true)] +#[ApiResource] #[ORM\Entity] class Greeting { From a3a9677aa4a52570feb14b56f72295cb2838488a Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 11 Aug 2026 14:14:38 +0200 Subject: [PATCH 08/12] ci: adapt the Docker test job to run on forks Actions are pinned to full commit SHAs, which the repository settings can require and which a mutable tag cannot guarantee. The token feeding the front-end build falls back to the run token, absent a personal one on forks, the contributors fetch being rate-limited without either. Helm was pulled in as part of the cloud SDK, whose own constraint forced an old interpreter alongside it. Nothing in the job talks to that cloud, so it is installed on its own instead. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a6556d72..bb368f092 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,10 +85,12 @@ jobs: contents: 'read' id-token: 'write' env: - GITHUB_KEY: ${{ secrets.GH_KEY }} + # Falls back to the run token on forks, where the personal token is absent: + # the contributors fetch during the PWA build is rate-limited without one. + GITHUB_KEY: ${{ secrets.GH_KEY || secrets.GITHUB_TOKEN }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Pull images run: docker compose pull --ignore-pull-failures || true - name: Start services @@ -121,11 +123,9 @@ jobs: run: docker compose exec -T php bin/phpunit - name: Doctrine Schema Validator run: docker compose exec -T php bin/console doctrine:schema:validate - # gcloud does not work with Python 3.10 because collections. Mappings were removed in Python 3.10. - - uses: actions/setup-python@v4 - with: - python-version: 3.9.15 - - name: Setup gcloud - uses: google-github-actions/setup-gcloud@v1 + # Helm came from the gcloud SDK, itself pinned to an old Python. Nothing in + # this job calls gcloud, so it is installed directly instead. + - name: Setup Helm + uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 - name: Lint Helm run: helm lint ./helm/api-platform/ From f77b62cc896fbbf5ebf3faf3cf0690b0dde404cc Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 11 Aug 2026 14:22:34 +0200 Subject: [PATCH 09/12] fix(api): keep sequence identity generation on PostgreSQL The schema was created when sequences were the default generation strategy on this platform. The mapping layer since defaults to identity columns, and expects a column default the migrations never created, so every insert sent a null primary key and the database refused it. The preference is now declared rather than inherited, which the mapping layer also asks for by deprecation. Co-Authored-By: Claude Opus 5 (1M context) --- api/config/packages/doctrine.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/config/packages/doctrine.yaml b/api/config/packages/doctrine.yaml index 08f1fba70..6d4d57362 100644 --- a/api/config/packages/doctrine.yaml +++ b/api/config/packages/doctrine.yaml @@ -6,6 +6,10 @@ doctrine: # either here or in the DATABASE_URL env var (see .env file) #server_version: '15' orm: + # The schema was created when SEQUENCE was the PostgreSQL default; IDENTITY + # is now, and it expects a column default the migrations never created. + identity_generation_preferences: + Doctrine\DBAL\Platforms\PostgreSQLPlatform: sequence naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware auto_mapping: true mappings: From f728b2ad4c65f0435f536407562f7f287e49f040 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 11 Aug 2026 14:29:24 +0200 Subject: [PATCH 10/12] test(api): fail only on deprecations this code triggers The test runner defaults to failing on any deprecation, legacy ones aside, which the current dependency versions emit from inside their own internals, on a passing suite. Nothing in this repository can silence those, so the threshold now applies to the group attributed to our own code and leaves the rest reported but harmless. It is passed to the container rather than declared in the test configuration: the handler freezes its settings on the first deprecation, which is emitted while classes are still being autoloaded, before that configuration is read. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb368f092..f07a32754 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,7 +120,7 @@ jobs: docker compose exec -T php bin/console -e test doctrine:database:create docker compose exec -T php bin/console -e test doctrine:migrations:migrate --no-interaction - name: PHPUnit - run: docker compose exec -T php bin/phpunit + run: docker compose exec -T -e SYMFONY_DEPRECATIONS_HELPER='max[self]=0' php bin/phpunit - name: Doctrine Schema Validator run: docker compose exec -T php bin/console doctrine:schema:validate # Helm came from the gcloud SDK, itself pinned to an old Python. Nothing in From 15506ecaca0143b16dcf77acbb8d63b47f077c56 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 11 Aug 2026 14:39:02 +0200 Subject: [PATCH 11/12] ci: lint the chart in its own job It was the last step of the container job, so any earlier failure skipped it and a malformed chart stayed hidden behind an unrelated one. Nothing it reads comes from that job, the chart being linted straight off the checkout, so it now runs on its own and in parallel. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f07a32754..36c30ec31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -123,8 +123,13 @@ jobs: run: docker compose exec -T -e SYMFONY_DEPRECATIONS_HELPER='max[self]=0' php bin/phpunit - name: Doctrine Schema Validator run: docker compose exec -T php bin/console doctrine:schema:validate - # Helm came from the gcloud SDK, itself pinned to an old Python. Nothing in - # this job calls gcloud, so it is installed directly instead. + + helm: + name: Helm + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Helm uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 - name: Lint Helm From cf9b14704d5adcf8df4e0780ef5597a1209feee2 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 11 Aug 2026 19:28:51 +0200 Subject: [PATCH 12/12] docs: document the token as an environment variable The compose file now reads it from the environment, so the instructions to write it into a file left contributors with an unauthenticated, and therefore rate-limited, fetch of the contributors list. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6121e7622..69e6fd47b 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,11 @@ You need to use a valid github token to retrieve the list of contributors. 2. Select scopes `public_repo`, `read:org` and `read:user`, generate the token and copy it. 3. If you use "pnpm dev" on the folder pwa to launch the project, add a new `.env.local` file on the root of pwa folder, and set your token as an environment variable named `GITHUB_KEY`. -If you use docker, create a file "secret_github_key" at the root of the project with your token inside: +If you use docker, export your token as a `GITHUB_KEY` environment variable, which the compose file reads to build the images: ```console -# Create the secret_github_key file -echo "YOUR_GITHUB_TOKEN" > secret_github_key +# Export the token for the current shell +export GITHUB_KEY=YOUR_GITHUB_TOKEN ``` > **❗Core team badges restriction**: You need to be a member of API Platform organization to retrieve API Platform teams. You can still locally launch the project, but the badges of the core team members will not appear. @@ -38,8 +38,8 @@ git clone https://github.com/api-platform/website.git # Change directory cd website -# Create the github_key file -echo YOUR_GITHUB_TOKEN > secret_github_key +# Export the GitHub token +export GITHUB_KEY=YOUR_GITHUB_TOKEN # Install and run the project locally docker compose up -d