diff --git a/.github/workflows/apispec.yaml b/.github/workflows/apispec.yaml index 152f5b23..abfd6c49 100644 --- a/.github/workflows/apispec.yaml +++ b/.github/workflows/apispec.yaml @@ -1,4 +1,28 @@ -on: pull_request +### ### Api Spec +### +### Re-exports the OpenAPI spec (`public/api-spec-v2.{yaml,json}`) from the +### API Platform configuration. Posts a PR comment **only** when something +### needs attention — spec drift, non-breaking changes, or breaking changes — +### and stays quiet otherwise. The comment is edited in place across runs +### so a PR carries at most one comment from this workflow. +### +### #### Assumptions +### +### 1. A docker compose service named `phpfpm` can be run and `bin/console` +### can be run inside the `phpfpm` service. +### 2. The committed `public/api-spec-v2.{yaml,json}` are kept in sync with +### the API Platform configuration via `composer update-api-spec`. + +on: + pull_request: + paths: + - "src/**/*.php" + - "config/**" + - "composer.json" + - "composer.lock" + - "public/api-spec-v2.yaml" + - "public/api-spec-v2.json" + - "docker-compose.yml" name: Api Spec @@ -6,14 +30,22 @@ env: COMPOSE_USER: runner jobs: - apispec: + api-spec-export: + name: Ensure API specification is up to date runs-on: ubuntu-latest - name: API Specification validation + permissions: + contents: read + pull-requests: write steps: - name: Checkout uses: actions/checkout@v6 + + - name: Cache vendor + uses: actions/cache@v5 with: - fetch-depth: 2 + path: vendor + key: vendor-php8.4-${{ hashFiles('composer.lock') }} + restore-keys: vendor-php8.4- - name: Setup network run: docker network create frontend @@ -21,14 +53,108 @@ jobs: - name: Install Dependencies run: docker compose run --rm phpfpm composer install - - name: Export specifications (yaml) - run: docker compose run --rm phpfpm bin/console api:openapi:export --yaml --output=public/api-spec-v2.yaml --no-interaction + - name: Export specifications + run: | + docker compose run --rm phpfpm bin/console api:openapi:export --yaml --output=public/api-spec-v2.yaml --no-interaction + docker compose run --rm phpfpm bin/console api:openapi:export --output=public/api-spec-v2.json --no-interaction + + - name: Check for uncommitted changes + id: git-diff-spec + continue-on-error: true + run: git diff --diff-filter=ACMRT --exit-code public/api-spec-v2.yaml public/api-spec-v2.json + + - name: Comment PR if spec is outdated + if: steps.git-diff-spec.outcome == 'failure' + env: + GH_TOKEN: ${{ github.token }} + run: | + gh pr comment ${{ github.event.pull_request.number }} \ + --body "$(cat <<'EOF' + ## API specification not up to date + + The committed API specification files do not match the exported output. + + Please run the following command, then commit and push the changes: + + ```shell + docker compose exec phpfpm composer update-api-spec + ``` + EOF + )" \ + --create-if-none --edit-last + + - name: Fail if spec is outdated + if: steps.git-diff-spec.outcome == 'failure' + run: exit 1 + + api-spec-breaking-changes: + name: Detect breaking changes in API specification + runs-on: ubuntu-latest + needs: [api-spec-export] + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Fetch base branch for comparison + run: git fetch --depth=1 origin ${{ github.base_ref }} + + - name: Detect breaking changes + id: breaking + continue-on-error: true + uses: oasdiff/oasdiff-action/breaking@v0.0.44 + with: + base: "origin/${{ github.base_ref }}:public/api-spec-v2.yaml" + revision: "public/api-spec-v2.yaml" + fail-on: ERR + + - name: Generate changelog + id: changelog + continue-on-error: true + uses: oasdiff/oasdiff-action/changelog@v0.0.44 + with: + base: "origin/${{ github.base_ref }}:public/api-spec-v2.yaml" + revision: "public/api-spec-v2.yaml" + format: markdown + output-to-file: changelog.md + + # Stay quiet when nothing changed — neither breaking nor non-breaking. + # Comments only fire on the two branches below. - - name: Check for changes in specifications (yaml) - run: git diff --diff-filter=ACMRT --exit-code public/api-spec-v2.yaml + - name: Comment PR - non-breaking changes + if: steps.breaking.outcome == 'success' && hashFiles('changelog.md') != '' + env: + GH_TOKEN: ${{ github.token }} + run: | + { + echo "## API Specification - Non-breaking changes" + echo "" + cat changelog.md + } > comment.md + gh pr comment ${{ github.event.pull_request.number }} \ + --body-file comment.md \ + --create-if-none --edit-last - - name: Export specifications (json) - run: docker compose run --rm phpfpm bin/console api:openapi:export --output=public/api-spec-v2.json --no-interaction + - name: Comment PR - breaking changes + if: steps.breaking.outcome == 'failure' + env: + GH_TOKEN: ${{ github.token }} + run: | + { + echo "## API Specification - Breaking changes detected" + echo "" + if [ -s changelog.md ]; then + cat changelog.md + else + echo "The breaking changes action detected incompatible changes. Review the action logs for details." + fi + } > comment.md + gh pr comment ${{ github.event.pull_request.number }} \ + --body-file comment.md \ + --create-if-none --edit-last - - name: Check for changes in specifications (json) - run: git diff --diff-filter=ACMRT --exit-code public/api-spec-v2.json + - name: Fail if breaking changes detected + if: steps.breaking.outcome == 'failure' + run: exit 1 diff --git a/.github/workflows/build-images.yml b/.github/workflows/build-images.yml index cd45bc91..2560d08d 100644 --- a/.github/workflows/build-images.yml +++ b/.github/workflows/build-images.yml @@ -1,3 +1,16 @@ +### ### Build docker images +### +### Builds and pushes the API and Nginx images to GHCR. Triggers on push to +### `develop` (image tag `develop`) and on git tag pushes (image tag = git +### tag). The Nginx image layers on the API image, so the API build runs +### first in the same job. +### +### #### Assumptions +### +### 1. The `os2display` GHCR namespace exists and `GITHUB_TOKEN` carries +### `packages: write`. +### 2. `infrastructure/build-n-push.sh` mirrors the build for local use. + --- name: Build docker images diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml index 63638c2d..327d4295 100644 --- a/.github/workflows/changelog.yaml +++ b/.github/workflows/changelog.yaml @@ -1,7 +1,3 @@ -# Do not edit this file! Make a pull request on changing -# github/workflows/changelog.yaml in -# https://github.com/itk-dev/devops_itkdev-docker if need be. - ### ### Changelog ### ### Checks that changelog has been updated @@ -14,8 +10,6 @@ on: jobs: changelog: runs-on: ubuntu-latest - strategy: - fail-fast: false steps: - name: Checkout uses: actions/checkout@v6 diff --git a/.github/workflows/code-analysis.yaml b/.github/workflows/code-analysis.yaml index 0f723816..c8a27643 100644 --- a/.github/workflows/code-analysis.yaml +++ b/.github/workflows/code-analysis.yaml @@ -1,3 +1,15 @@ +### ### Code Analysis +### +### Runs PHPStan static analysis against the project. +### +### #### Assumptions +### +### 1. A docker compose service named `phpfpm` can be run and `composer` can +### be run inside the `phpfpm` service. +### 2. [phpstan/phpstan](https://phpstan.org/) is a dev requirement in +### `composer.json`. +### 3. `phpstan.dist.neon` configures the analyser. + on: pull_request name: Code Analysis @@ -13,11 +25,18 @@ jobs: - name: Checkout uses: actions/checkout@v6 + - name: Cache vendor + uses: actions/cache@v5 + with: + path: vendor + key: vendor-php8.4-${{ hashFiles('composer.lock') }} + restore-keys: vendor-php8.4- + - name: Setup network run: docker network create frontend - name: Install Dependencies - run: docker compose run --rm phpfpm composer install + run: docker compose run --rm --no-deps phpfpm composer install - name: PHPStan - run: docker compose run --rm phpfpm vendor/bin/phpstan analyse --no-progress + run: docker compose run --rm --no-deps phpfpm vendor/bin/phpstan analyse --no-progress diff --git a/.github/workflows/composer.yaml b/.github/workflows/composer.yaml index 8787034d..c4818f9b 100644 --- a/.github/workflows/composer.yaml +++ b/.github/workflows/composer.yaml @@ -1,7 +1,3 @@ -# Do not edit this file! Make a pull request on changing -# github/workflows/composer.yaml in -# https://github.com/itk-dev/devops_itkdev-docker if need be. - ### ### Composer ### ### Validates composer.json and checks that it's normalized. @@ -14,13 +10,13 @@ ### is a dev requirement in `composer.json`: ### ### ``` shell -### docker compose run --rm phpfpm composer require --dev ergebnis/composer-normalize +### docker compose run --rm --no-deps phpfpm composer require --dev ergebnis/composer-normalize ### ``` ### ### Normalize `composer.json` by running ### ### ``` shell -### docker compose run --rm phpfpm composer normalize +### docker compose run --rm --no-deps phpfpm composer normalize ### ``` name: Composer @@ -38,21 +34,23 @@ on: jobs: composer-validate: runs-on: ubuntu-latest - strategy: - fail-fast: false steps: - uses: actions/checkout@v6 - run: | docker network create frontend - docker compose run --rm phpfpm composer validate --strict + docker compose run --rm --no-deps phpfpm composer validate --strict composer-normalized: runs-on: ubuntu-latest - strategy: - fail-fast: false steps: - uses: actions/checkout@v6 + - name: Cache vendor + uses: actions/cache@v5 + with: + path: vendor + key: vendor-php8.4-${{ hashFiles('composer.lock') }} + restore-keys: vendor-php8.4- - run: | docker network create frontend - docker compose run --rm phpfpm composer install - docker compose run --rm phpfpm composer normalize --dry-run + docker compose run --rm --no-deps phpfpm composer install + docker compose run --rm --no-deps phpfpm composer normalize --dry-run diff --git a/.github/workflows/composer_install.yaml b/.github/workflows/composer_install.yaml index bdce83d6..157e4dd0 100644 --- a/.github/workflows/composer_install.yaml +++ b/.github/workflows/composer_install.yaml @@ -1,3 +1,13 @@ +### ### Composer install +### +### Verifies that `composer install --no-dev -o` succeeds in prod mode against +### the committed lockfile. +### +### #### Assumptions +### +### 1. A docker compose service named `phpfpm` can be run and `composer` can +### be run inside the `phpfpm` service. + on: pull_request name: Composer install @@ -17,4 +27,4 @@ jobs: run: docker network create frontend - name: "[prod] Composer install" - run: docker compose run --rm -e APP_ENV=prod phpfpm composer install --no-dev -o + run: docker compose run --rm --no-deps -e APP_ENV=prod phpfpm composer install --no-dev -o diff --git a/.github/workflows/doctrine.yaml b/.github/workflows/doctrine.yaml index dccba03b..4a287711 100644 --- a/.github/workflows/doctrine.yaml +++ b/.github/workflows/doctrine.yaml @@ -1,3 +1,14 @@ +### ### Doctrine +### +### Runs pending Doctrine migrations and validates the resulting schema +### against the entity metadata. +### +### #### Assumptions +### +### 1. A docker compose service named `phpfpm` can be run and `bin/console` +### can be run inside the `phpfpm` service. +### 2. A `mariadb` service is reachable from `phpfpm`. + on: pull_request name: Doctrine @@ -13,6 +24,13 @@ jobs: - name: Checkout uses: actions/checkout@v6 + - name: Cache vendor (prod) + uses: actions/cache@v5 + with: + path: vendor + key: vendor-prod-php8.4-${{ hashFiles('composer.lock') }} + restore-keys: vendor-prod-php8.4- + - name: Setup network run: docker network create frontend diff --git a/.github/workflows/env_coverage.yaml b/.github/workflows/env_coverage.yaml index 5a6dc18f..8c08be02 100644 --- a/.github/workflows/env_coverage.yaml +++ b/.github/workflows/env_coverage.yaml @@ -1,3 +1,13 @@ +### ### Env coverage +### +### Validates that every Symfony env variable read via `%env(...)%` in +### `config/` is documented in `.env`, and that every variable in `.env` +### carries a preceding description comment. +### +### #### Assumptions +### +### 1. `scripts/check-env-coverage.sh` is executable. +### 2. The Taskfile target `coding-standards:env:check` invokes it. --- on: push: diff --git a/.github/workflows/github_build_release.yml b/.github/workflows/github_build_release.yml index fc724d36..19aecc2f 100644 --- a/.github/workflows/github_build_release.yml +++ b/.github/workflows/github_build_release.yml @@ -1,3 +1,14 @@ +### ### Create Github Release +### +### On a semver tag push (`*.*.*`): builds the production tarball, writes +### `release.json`, and creates a GitHub release. Tags containing a `-` +### (e.g. `3.0.0-RC1`) are flagged as pre-releases. +### +### #### Assumptions +### +### 1. The `phpfpm` and `node` compose services can run on the runner. +### 2. The tagged commit passes the regular CI suite. + on: push: tags: diff --git a/.github/workflows/javascript.yaml b/.github/workflows/javascript.yaml index 4dacffe6..8b7ed0a9 100644 --- a/.github/workflows/javascript.yaml +++ b/.github/workflows/javascript.yaml @@ -1,7 +1,3 @@ -# Do not edit this file! Make a pull request on changing -# github/workflows/symfony/javascript.yaml in -# https://github.com/itk-dev/devops_itkdev-docker if need be. - ### ### Symfony JavaScript (and TypeScript) ### ### Validates JavaScript files. @@ -23,8 +19,6 @@ on: jobs: javascript-lint: runs-on: ubuntu-latest - strategy: - fail-fast: false steps: - name: Checkout uses: actions/checkout@v6 diff --git a/.github/workflows/markdown.yaml b/.github/workflows/markdown.yaml index 066063a5..6e4f63e9 100644 --- a/.github/workflows/markdown.yaml +++ b/.github/workflows/markdown.yaml @@ -1,7 +1,3 @@ -# Do not edit this file! Make a pull request on changing -# github/workflows/markdown.yaml in -# https://github.com/itk-dev/devops_itkdev-docker if need be. - ### ### Markdown ### ### Lints Markdown files (`**/*.md`) in the project. @@ -30,8 +26,6 @@ on: jobs: markdown-lint: runs-on: ubuntu-latest - strategy: - fail-fast: false steps: - name: Checkout uses: actions/checkout@v6 diff --git a/.github/workflows/php.yaml b/.github/workflows/php.yaml index 02dc8c53..bbbfc5c3 100644 --- a/.github/workflows/php.yaml +++ b/.github/workflows/php.yaml @@ -1,7 +1,3 @@ -# Do not edit this file! Make a pull request on changing -# github/workflows/symfony/php.yaml in -# https://github.com/itk-dev/devops_itkdev-docker if need be. - ### ### Symfony PHP ### ### Checks that PHP code adheres to the [Symfony coding @@ -15,14 +11,14 @@ ### is a dev requirement in `composer.json`: ### ### ``` shell -### docker compose run --rm phpfpm composer require --dev friendsofphp/php-cs-fixer +### docker compose run --rm --no-deps phpfpm composer require --dev friendsofphp/php-cs-fixer ### ``` ### ### Clean up and check code by running ### ### ``` shell -### docker compose run --rm phpfpm vendor/bin/php-cs-fixer fix -### docker compose run --rm phpfpm vendor/bin/php-cs-fixer fix --dry-run --diff +### docker compose run --rm --no-deps phpfpm vendor/bin/php-cs-fixer fix +### docker compose run --rm --no-deps phpfpm vendor/bin/php-cs-fixer fix --dry-run --diff ### ``` ### ### > [!NOTE] The template adds `.php-cs-fixer.dist.php` as [a configuration @@ -49,8 +45,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + - name: Cache vendor + uses: actions/cache@v5 + with: + path: vendor + key: vendor-php8.4-${{ hashFiles('composer.lock') }} + restore-keys: vendor-php8.4- - run: | docker network create frontend - docker compose run --rm phpfpm composer install + docker compose run --rm --no-deps phpfpm composer install # https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/doc/usage.rst#the-check-command - docker compose run --rm phpfpm vendor/bin/php-cs-fixer fix --dry-run --diff + docker compose run --rm --no-deps phpfpm vendor/bin/php-cs-fixer fix --dry-run --diff diff --git a/.github/workflows/phpunit.yaml b/.github/workflows/phpunit.yaml index 9daee407..87f259d8 100644 --- a/.github/workflows/phpunit.yaml +++ b/.github/workflows/phpunit.yaml @@ -1,3 +1,14 @@ +### ### Test (PHPUnit) +### +### Runs the API's PHPUnit test suite against a real database. +### +### #### Assumptions +### +### 1. A docker compose service named `phpfpm` can be run and `composer` can +### be run inside the `phpfpm` service. +### 2. A `mariadb` service is reachable from `phpfpm`. +### 3. `composer run test-setup` and `composer run test` are defined. + on: pull_request name: Test @@ -13,6 +24,13 @@ jobs: - name: Checkout uses: actions/checkout@v6 + - name: Cache vendor + uses: actions/cache@v5 + with: + path: vendor + key: vendor-php8.4-${{ hashFiles('composer.lock') }} + restore-keys: vendor-php8.4- + - name: Setup network run: docker network create frontend diff --git a/.github/workflows/playwright.yaml b/.github/workflows/playwright.yaml index 93ae2071..6cc614d8 100644 --- a/.github/workflows/playwright.yaml +++ b/.github/workflows/playwright.yaml @@ -1,3 +1,15 @@ +### ### Playwright +### +### Builds the frontend (`composer install`, `npm install`, `npm run build`) +### and runs the Playwright end-to-end test suite against the local stack. +### +### #### Assumptions +### +### 1. Docker compose services `phpfpm`, `node`, `nginx`, and `playwright` +### are defined. +### 2. The `nginx` service has a healthcheck Playwright can wait on. +### 3. `playwright.config.ts` lives in the repo root. + on: pull_request name: Test @@ -9,12 +21,24 @@ jobs: frontend-build-and-test: name: Playwright runs-on: ubuntu-latest - strategy: - fail-fast: true steps: - name: Checkout uses: actions/checkout@v6 + - name: Cache vendor + uses: actions/cache@v5 + with: + path: vendor + key: vendor-php8.4-${{ hashFiles('composer.lock') }} + restore-keys: vendor-php8.4- + + - name: Cache node_modules + uses: actions/cache@v5 + with: + path: node_modules + key: node-modules-${{ hashFiles('package-lock.json') }} + restore-keys: node-modules- + - name: Setup network run: docker network create frontend diff --git a/.github/workflows/rector.yaml b/.github/workflows/rector.yaml index 47bacbc7..0e28e905 100644 --- a/.github/workflows/rector.yaml +++ b/.github/workflows/rector.yaml @@ -1,3 +1,15 @@ +### ### Rector +### +### Runs Rector in `--dry-run` mode to detect missing modernisations. +### +### #### Assumptions +### +### 1. A docker compose service named `phpfpm` can be run and `composer` can +### be run inside the `phpfpm` service. +### 2. [rector/rector](https://github.com/rectorphp/rector) is a dev +### requirement in `composer.json`. +### 3. `rector.php` configures the rule set. + on: pull_request name: Rector @@ -13,11 +25,18 @@ jobs: - name: Checkout uses: actions/checkout@v6 + - name: Cache vendor + uses: actions/cache@v5 + with: + path: vendor + key: vendor-php8.4-${{ hashFiles('composer.lock') }} + restore-keys: vendor-php8.4- + - name: Setup network run: docker network create frontend - name: Install Dependencies - run: docker compose run --rm phpfpm composer install + run: docker compose run --rm --no-deps phpfpm composer install - name: Rector - run: docker compose run --rm phpfpm vendor/bin/rector --dry-run + run: docker compose run --rm --no-deps phpfpm vendor/bin/rector --dry-run diff --git a/.github/workflows/styles.yaml b/.github/workflows/styles.yaml index 02f9d6bc..3b4bf27b 100644 --- a/.github/workflows/styles.yaml +++ b/.github/workflows/styles.yaml @@ -1,7 +1,3 @@ -# Do not edit this file! Make a pull request on changing -# github/workflows/symfony/styles.yaml in -# https://github.com/itk-dev/devops_itkdev-docker if need be. - ### ### Symfony Styles (CSS and SCSS) ### ### Validates styles files. @@ -23,8 +19,6 @@ on: jobs: styles-lint: runs-on: ubuntu-latest - strategy: - fail-fast: false steps: - name: Checkout uses: actions/checkout@v6 diff --git a/.github/workflows/twig.yaml b/.github/workflows/twig.yaml index 76e2a57d..fbf799c8 100644 --- a/.github/workflows/twig.yaml +++ b/.github/workflows/twig.yaml @@ -1,7 +1,3 @@ -# Do not edit this file! Make a pull request on changing -# github/workflows/twig.yaml in -# https://github.com/itk-dev/devops_itkdev-docker if need be. - ### ### Twig ### ### Validates Twig files @@ -14,7 +10,7 @@ ### is a dev requirement in `composer.json`: ### ### ``` shell -### docker compose run --rm phpfpm composer require --dev vincentlanglet/twig-cs-fixer +### docker compose run --rm --no-deps phpfpm composer require --dev vincentlanglet/twig-cs-fixer ### ``` ### ### 3. A [Configuration @@ -36,13 +32,18 @@ on: jobs: twig-lint: runs-on: ubuntu-latest - strategy: - fail-fast: false steps: - name: Checkout uses: actions/checkout@v6 + - name: Cache vendor + uses: actions/cache@v5 + with: + path: vendor + key: vendor-php8.4-${{ hashFiles('composer.lock') }} + restore-keys: vendor-php8.4- + - run: | docker network create frontend - docker compose run --rm phpfpm composer install - docker compose run --rm phpfpm vendor/bin/twig-cs-fixer lint + docker compose run --rm --no-deps phpfpm composer install + docker compose run --rm --no-deps phpfpm vendor/bin/twig-cs-fixer lint diff --git a/.github/workflows/vitest.yaml b/.github/workflows/vitest.yaml index bda6ac97..ddb3e1a6 100644 --- a/.github/workflows/vitest.yaml +++ b/.github/workflows/vitest.yaml @@ -1,3 +1,13 @@ +### ### Unit tests (Vitest) +### +### Runs the client-side Vitest unit tests. +### +### #### Assumptions +### +### 1. A docker compose service named `node` can be run and `npm` can be run +### inside the `node` service. +### 2. `npm run test:unit` is defined in `package.json`. + on: pull_request name: Unit tests @@ -13,6 +23,13 @@ jobs: - name: Checkout uses: actions/checkout@v6 + - name: Cache node_modules + uses: actions/cache@v5 + with: + path: node_modules + key: node-modules-${{ hashFiles('package-lock.json') }} + restore-keys: node-modules- + - name: Setup network run: docker network create frontend diff --git a/.github/workflows/yaml.yaml b/.github/workflows/yaml.yaml index 16c44b9f..349b5575 100644 --- a/.github/workflows/yaml.yaml +++ b/.github/workflows/yaml.yaml @@ -1,7 +1,3 @@ -# Do not edit this file! Make a pull request on changing -# github/workflows/yaml.yaml in -# https://github.com/itk-dev/devops_itkdev-docker if need be. - ### ### YAML ### ### Validates YAML files. diff --git a/CHANGELOG.md b/CHANGELOG.md index ab00d452..52d4d1b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +- Cleaned up and documented CI workflows; api-spec workflow now reports breaking changes. - Gathered all repositories in one Symfony application. - Changed to vite 7 and rolldown. - Added ADRs 008 and 009.