diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b7dd1d2..24db029 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,80 @@ version: 2 updates: -- package-ecosystem: composer - directory: "/" - schedule: - interval: monthly - open-pull-requests-limit: 10 +# +# +# [GHAction] +# Based on https://github.com/yoanm/shared-config/blob/master/GitHub/dependabot/github-action.yml file +# + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + day: sunday # Create PRs during week-ends, they will be ready on monday morning + commit-message: + prefix: '[dependabot][ghaction] - ' # No need to specify prod/dev for GHAction as there is only "production" updates ! + include: scope + groups: +# Group all basic updates inside the a single PR +# No need to split prod/dev as there is only prod updates + all-actions: + applies-to: version-updates + patterns: ['*'] +# Group all security updates inside the a single PR +# No need to split prod/dev as there is only prod updates +# +Most likely no need to split major and other updates either + SECURITY-all: + applies-to: security-updates + patterns: ['*'] +# +# +# [Composer] +# Based on https://github.com/yoanm/shared-config/blob/master/GitHub/dependabot/composer.yml file +# + - package-ecosystem: composer + directory: / + schedule: # Create PRs during week-ends, they will be ready on monday morning + interval: weekly + day: sunday + versioning-strategy: widen + commit-message: + prefix: '[dependabot][prod][composer] - ' + prefix-development: '[dependabot][dev][composer] - ' + include: scope + groups: +# Split basic updates by: +# - prod vs dev +# - major vs others (assuming packages properly follow semver !) + prod-majors: + applies-to: version-updates + dependency-type: production + update-types: ['major'] + patterns: ['*'] + prod-others: + applies-to: version-updates + dependency-type: production + patterns: ['*'] + dev-majors: + applies-to: version-updates + dependency-type: development + update-types: ['major'] + patterns: ['*'] + dev-others: + applies-to: version-updates + dependency-type: development + patterns: ['*'] +# Split security updates by: +# - prod vs dev +# - Major prod updates vs other prod updates + SECURITY-prod-major: + applies-to: security-updates + dependency-type: production + update-types: ['major'] + patterns: ['*'] + SECURITY-prod: + applies-to: security-updates + dependency-type: production + patterns: ['*'] + SECURITY-dev: + applies-to: security-updates + dependency-type: development + patterns: ['*'] diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c706207..454e83f 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -1,251 +1,47 @@ name: 'CI' + on: # Build any PRs and main branch changes workflow_dispatch: # Allows to run the workflow manually from the Actions tab pull_request: types: - opened - - edited - synchronize + paths-ignore: + # >>> CI Pre-check + # In case of updates to those workflows, they must be pre-checked by `pre-check-CI-updates.yml` rather than this workflow ! + # Any updates on those workflows are expected to be restricted to those workflows only ! (no update on code for instance) + - '.github/workflows/pre-check-CI-updates.yml' + - '.github/workflows/reusable-CI-workflow.yml' + - '.github/workflows/reusable-coverage-upload-workflow.yml' + # <<< CI Pre-check + # >>> Irrelevant files (no impact whatsoever on this GHWorkflow) + - '.github/workflows/coverage-upload.yml' # Executed for on master (workflow_run), no impact here + - '.github/workflows/dependabot-PRs.yml' # Executed for dependabot PRs, no impact here + - '**/*.md' + - '**/LICENSE' + - '**/CODEOWNERS' + - '**/.remarkrc*' + - '**/.editorconfig' + - '**/.scrutinizer.yml' + # <<< Irrelevant files push: branches: [ master ] schedule: - cron: '0 0 1 * *' # Every month +permissions: + contents: read + concurrency: group: "${{ github.workflow }}-${{ github.head_ref || github.ref }}" cancel-in-progress: true env: TEST_OUTPUT_STYLE: pretty - COMPOSER_OPTIONS: --optimize-autoloader - CODACY_CACHE_PATH: ~/.cache/codacy - CODACY_BIN: ~/.cache/codacy/codacy.sh jobs: tests: - name: UTs & FTs - Symfony ${{ matrix.symfony-version }} - runs-on: ubuntu-latest - env: - COVERAGE_TYPE: none - strategy: - fail-fast: true - max-parallel: 4 - matrix: - include: - # Bare minimum => Lowest versions allowed by composer config - - symfony-version: '4.4' - php-version: '8.0' - composer-flag: --prefer-lowest - # Up to date versions => Latest versions allowed by composer config - - symfony-version: '5.4' - php-version: '8.2' - # Late symfony migration => Lowest symfony version with latest minor php version allowed by composer config - - symfony-version: '4.4' - php-version: '8.2' - composer-flag: --prefer-lowest - # Late php migration => Latest symfony version with lowest minor php version allowed by composer config - - symfony-version: '5.4' - php-version: '8.0' - # Symfony 6.0 latest - - symfony-version: '6.0' - php-version: '8.2' - # Symfony 6.0 lowest - - symfony-version: '6.0' - php-version: '8.0' - composer-flag: --prefer-lowest - steps: - - name: Check out code - uses: actions/checkout@v3 - - - name: Enable coverage - if: ${{ matrix.php-version == '8.2' }} - run: | - echo "COVERAGE_OUTPUT_STYLE=clover" >> $GITHUB_ENV - echo "COVERAGE_TYPE=xdebug" >> $GITHUB_ENV - - - name: Setup PHP ${{ matrix.php-version }} - uses: shivammathur/setup-php@v2 - with: - php-version: '${{ matrix.php-version }}' - tools: composer - coverage: ${{ env.COVERAGE_TYPE }} - env: - # Always use latest available patch for the version - update: true - - - name: Setup cache - id: cache - uses: actions/cache@v3 - with: - path: | - ~/.composer - ./vendor - ${{ env.CODACY_CACHE_PATH }} - # Clear the cache if composer json (as composer.lock is in the repo) has been updated - key: tests-${{ matrix.php-version }}-${{ matrix.symfony-version }}-${{ matrix.composer-flag }}-${{ hashFiles('composer.json') }} - - - name: Download codacy binary - if: steps.cache.outputs.cache-hit != 'true' - run: | - mkdir -p ${{ env.CODACY_CACHE_PATH }} \ - && curl -LN https://coverage.codacy.com/get.sh -o ${{ env.CODACY_BIN }} \ - && chmod +x ${{ env.CODACY_BIN }} \ - && ${{ env.CODACY_BIN }} download - - - name: Build - run: | - SF_VERSION=${{ matrix.symfony-version }} - # Issue with ParamterBag below 4.4.30 => https://github.com/symfony/symfony/commit/3eca446b21607ea1c7a865ece2dd8254c33679cc - test '${{ matrix.symfony-version }}' = '4.4' && test '${{ matrix.php-version }}' = '8.2' && SF_VERSION=4.4.30 - composer require -W ${{ env.COMPOSER_OPTIONS }} ${{ matrix.composer-flag }} \ - symfony/validator:^$SF_VERSION \ - && composer update ${{ env.COMPOSER_OPTIONS }} ${{ matrix.composer-flag }} \ - && make build - - - name: Tests - run: make test-unit && make test-functional - - # Upload to codacy first as codecov action always remove coverage files despite move_coverage_to_trash at false - # And only if it's not a PR from a fork => Can't work as codacy secret is not accessible in that context - - name: Upload coverages to Codacy - if: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'yoanm/php-jsonrpc-params-symfony-validator-sdk') && env.COVERAGE_TYPE == 'xdebug' }} - run: ${{ env.CODACY_BIN }} report -r build/coverage-phpunit/unit.clover -r build/coverage-behat/clover.xml -r build/coverage-phpunit/functional.clover -t ${{ secrets.CODACY_PROJECT_TOKEN }} --partial - - # See the reports at https://codecov.io/gh/yoanm/php-jsonrpc-params-symfony-validator-sdk - - name: Upload unit tests coverage to codecov - if: ${{ env.COVERAGE_TYPE == 'xdebug' }} - uses: codecov/codecov-action@v3 - with: - file: "build/coverage-phpunit/unit.clover" - name: "unit-tests-${{ matrix.php-version }}-${{ matrix.symfony-version }}" - flags: "unit-tests,php-${{ matrix.php-version }},sf-${{ matrix.symfony-version }}" - fail_ci_if_error: true - move_coverage_to_trash: false - verbose: ${{ runner.debug == '1' }} - - - name: Upload functional tests coverage to codecov - if: ${{ env.COVERAGE_TYPE == 'xdebug' }} - uses: codecov/codecov-action@v3 - with: - files: "build/coverage-behat/clover.xml,build/coverage-phpunit/functional.clover" - name: "functional-tests-${{ matrix.php-version }}-${{ matrix.symfony-version }}" - flags: "functional-tests,php-${{ matrix.php-version }},sf-${{ matrix.symfony-version }}" - fail_ci_if_error: true - move_coverage_to_trash: false - verbose: ${{ runner.debug == '1' }} - - static-checks: - name: Static checks - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Setup PHP 8.2 - uses: shivammathur/setup-php@v2 - with: - php-version: 8.2 # Latest supported - tools: composer - coverage: none - env: - # Always use latest available patch for the version - update: true - - - name: Setup cache - id: cache - uses: actions/cache@v3 - with: - path: | - ~/.composer - # Clear the cache if composer json (as composer.lock is in the repo) has been updated - key: tests-${{ env.PHP_VERSION }}-${{ hashFiles('composer.json') }} - - - name: Build - run: make build - - - name: ComposerRequireChecker - uses: docker://webfactory/composer-require-checker:4.5.0 - - - name: Dependencies check - if: ${{ github.event_name == 'pull_request' }} - uses: actions/dependency-review-action@v1 - - finalize-codacy-coverage-report: - runs-on: ubuntu-latest - name: Finalize Codacy coverage report - if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'yoanm/php-jsonrpc-params-symfony-validator-sdk' }} - needs: [ tests ] - steps: - - name: Setup cache - id: cache - uses: actions/cache@v3 - with: - path: | - ${{ env.CODACY_CACHE_PATH }} - key: codacy-final - - - name: Download codacy binary - if: steps.cache.outputs.cache-hit != 'true' - run: | - mkdir -p ${{ env.CODACY_CACHE_PATH }} \ - && curl -LN https://coverage.codacy.com/get.sh -o ${{ env.CODACY_BIN }} \ - && chmod +x ${{ env.CODACY_BIN }} \ - && ${{ env.CODACY_BIN }} download - - - name: Finalize reporting - run: ${{ env.CODACY_BIN }} final -t ${{ secrets.CODACY_PROJECT_TOKEN }} - - nightly-tests: - name: Nightly - Symfony ${{ matrix.symfony-version }} - runs-on: ubuntu-latest - env: - COMPOSER_OPTIONS: '--optimize-autoloader --ignore-platform-req=php+' - continue-on-error: true - needs: [ static-checks, tests ] - strategy: - fail-fast: false - max-parallel: 4 - matrix: - php-version: - - '8.3' # Current php dev version - symfony-version: - - '4.4' # Lowest LTS - - '5.4' # Latest LTS - - '6.0' # Current major version - include: - - symfony-version: '6.3' # Next symfony minor version to manage with latest supported PHP version - php-version: '8.2' - - steps: - - name: Check out code - uses: actions/checkout@v3 - - - name: Setup PHP ${{ matrix.php-version }} - uses: shivammathur/setup-php@v2 - with: - php-version: '${{ matrix.php-version }}' - tools: composer - coverage: none - env: - # Always use latest available patch for the version - update: true - - - name: Setup cache - id: cache - uses: actions/cache@v3 - with: - path: | - ~/.composer - ./vendor - # Clear the cache if composer json (as composer.lock is in the repo) has been updated - key: tests-${{ matrix.php-version }}-${{ matrix.symfony-version }}-${{ hashFiles('composer.json') }} - - - name: Build - run: | - composer config minimum-stability dev \ - && composer require -W ${{ env.COMPOSER_OPTIONS }} \ - symfony/validator:^${{ matrix.symfony-version }} \ - && composer update ${{ env.COMPOSER_OPTIONS }} \ - && make build - - - name: Test - run: make test-unit && make test-functional + name: Tests + permissions: + contents: read + uses: ./.github/workflows/reusable-CI-workflow.yml diff --git a/.github/workflows/coverage-upload.yml b/.github/workflows/coverage-upload.yml new file mode 100644 index 0000000..0d66a5d --- /dev/null +++ b/.github/workflows/coverage-upload.yml @@ -0,0 +1,20 @@ +name: 'Coverage' +on: + workflow_run: + workflows: ["CI"] + types: [completed] + +permissions: + contents: read + checks: write # For the check run creation ! + +jobs: + coverage: + name: Coverage + permissions: + contents: read + checks: write # For the check run creation ! + secrets: + CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + uses: ./.github/workflows/reusable-coverage-upload-workflow.yml diff --git a/.github/workflows/dependabot-PRs.yml b/.github/workflows/dependabot-PRs.yml new file mode 100644 index 0000000..d803072 --- /dev/null +++ b/.github/workflows/dependabot-PRs.yml @@ -0,0 +1,33 @@ +name: Dependabot PRs +on: pull_request + +permissions: + contents: write + pull-requests: write + +jobs: + dependabot: + name: Auto-merge & Labels + if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'yoanm/php-jsonrpc-params-symfony-validator-sdk' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v2.4.0 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Add custom labels + run: gh pr edit "${{github.event.pull_request.html_url}}" --add-label "with-nightly-tests" + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: Enable auto-merge for Dependabot PRs + if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch'}} + run: gh pr merge --auto --squash "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pre-check-CI-updates.yml b/.github/workflows/pre-check-CI-updates.yml new file mode 100644 index 0000000..1a9abcc --- /dev/null +++ b/.github/workflows/pre-check-CI-updates.yml @@ -0,0 +1,42 @@ +name: 'Test CI updates' +# [DESCRIPTION] +# As CI workflow relies on `workflow_run` trigger for upload, this workflow is used in order to ease updates made on +# CI workflow (or linked workflows/actions). It's kind of pre-check to ensure once updates are merged on main branch, +# the `workflow_run` workflow execution will behave as expected. + +on: + pull_request: + types: + - opened + - synchronize + branches: [master] # Only for PR targeting master branch + paths: # /!\ Duplicate the same list as `on.pull_request.paths-ignore` property value for CI workflow ! + - '.github/workflows/pre-check-CI-updates.yml' # This workflow + - '.github/workflows/reusable-CI-workflow.yml' + - '.github/workflows/reusable-coverage-upload-workflow.yml' + +permissions: + contents: read + checks: write # For the check run creation ! + +concurrency: + group: "${{ github.workflow }}-${{ github.head_ref || github.ref }}" + cancel-in-progress: true + +jobs: + tests: + name: Tests + permissions: + contents: read + uses: ./.github/workflows/reusable-CI-workflow.yml + + coverage: + name: Coverage + needs: [tests] + permissions: + contents: read + checks: write # For the check run creation ! + secrets: + CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + uses: ./.github/workflows/reusable-coverage-upload-workflow.yml diff --git a/.github/workflows/reusable-CI-workflow.yml b/.github/workflows/reusable-CI-workflow.yml new file mode 100644 index 0000000..f194430 --- /dev/null +++ b/.github/workflows/reusable-CI-workflow.yml @@ -0,0 +1,298 @@ +name: 'CI reusable workflow' + +on: + workflow_call: + +permissions: + contents: read + +env: + COMPOSER_PREFER_STABLE: '1' + TEST_OUTPUT_STYLE: pretty + SUPPORTED_VERSIONS_FILE_PATH: .github/workflows/supported-versions.json + +jobs: + fetch-supported-versions: + name: Fetch supported versions + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + php-min: ${{ steps.fetch-php-versions.outputs.min }} + php-max: ${{ steps.fetch-php-versions.outputs.max }} + php-next: ${{ steps.fetch-php-versions.outputs.next }} + symfony-min: ${{ steps.fetch-symfony-versions.outputs.min }} + symfony-max: ${{ steps.fetch-symfony-versions.outputs.max }} + symfony-next: ${{ steps.fetch-symfony-versions.outputs.next }} + steps: + - name: Fetch supported versions file + id: fetch-file + uses: yoanm/gha-supported-versions-parser/github-downloader@v1 + with: + file-path: ${{ env.SUPPORTED_VERSIONS_FILE_PATH }} + + - name: Fetch PHP supported versions + id: fetch-php-versions + uses: yoanm/gha-supported-versions-parser@v1 + with: + path: ${{ steps.fetch-file.outputs.path }} + dependency: php + + - name: Fetch Symfony supported versions + id: fetch-symfony-versions + uses: yoanm/gha-supported-versions-parser@v1 + with: + path: ${{ steps.fetch-file.outputs.path }} + dependency: symfony + + tests: + name: PHP ${{ matrix.php-version }} & Sf ${{ matrix.symfony-version }} - ${{ matrix.job-name }} + needs: [fetch-supported-versions] + runs-on: ubuntu-latest + permissions: + contents: read + env: + COVERAGE_TYPE: none + COVERAGE_OUTPUT_STYLE: clover + strategy: + fail-fast: true + matrix: + include: + - job-name: Up to date versions # => Highest versions allowed by composer config + php-version: '${{ needs.fetch-supported-versions.outputs.php-max }}' + symfony-version: '${{ needs.fetch-supported-versions.outputs.symfony-max }}' + # Fix - behat/gherkin => Avoid issue with behat <-> gherkin packages (See https://github.com/Behat/Gherkin/issues/317) + pkg-extra-constraints: --with 'behat/gherkin:~4.12.0' + - job-name: Up to date versions - Sf 6.4 case + php-version: '${{ needs.fetch-supported-versions.outputs.php-max }}' + symfony-version: '6.4' + # Fix - behat/gherkin => Avoid issue with behat <-> gherkin packages (See https://github.com/Behat/Gherkin/issues/317) + pkg-extra-constraints: --with 'behat/gherkin:~4.12.0' + - job-name: Bare minimum # => Lowest versions allowed by composer config + php-version: '${{ needs.fetch-supported-versions.outputs.php-min }}' + symfony-version: '${{ needs.fetch-supported-versions.outputs.symfony-min }}' + - job-name: Bare minimum - Sf 6.4 case + # Fix - Sf 6.4 require php 8.1 minimum ! + php-version: ${{ ( needs.fetch-supported-versions.outputs.php-min == '8.0' ) && '8.1' || needs.fetch-supported-versions.outputs.php-min }} + symfony-version: '6.4' + - job-name: Late PHP migration # => Highest symfony version with lowest php version allowed by composer config + # Fix - Sf 7.3 require php 8.2 minimum ! + php-version: ${{ ( needs.fetch-supported-versions.outputs.symfony-max == '7.3' && needs.fetch-supported-versions.outputs.php-min == '8.0' ) && '8.2' || needs.fetch-supported-versions.outputs.php-min }} + symfony-version: '${{ needs.fetch-supported-versions.outputs.symfony-max }}' + - job-name: Late Symfony migration # => Lowest symfony version with highest php version allowed by composer config + php-version: '${{ needs.fetch-supported-versions.outputs.php-max }}' + symfony-version: '${{ needs.fetch-supported-versions.outputs.symfony-min }}' + # Fix - behat/gherkin => Avoid issue with behat <-> gherkin packages (See https://github.com/Behat/Gherkin/issues/317) + pkg-extra-constraints: --with 'behat/gherkin:~4.12.0' + steps: + - name: Check out code + uses: actions/checkout@v5 + + # Enable coverage only for specific version(s) ! + # Usually highest version(s), plus additional ones in case of code used only with specific versions + - name: Enable coverage + if: ${{ matrix.php-version == needs.fetch-supported-versions.outputs.php-max }} + run: | + echo "COVERAGE_TYPE=xdebug" >> $GITHUB_ENV + + - name: Setup PHP ${{ matrix.php-version }} + id: setup-php + uses: shivammathur/setup-php@v2 + env: + update: true # whether to use latest available patch for the version or not + fail-fast: true # step will fail if an extension or tool fails to set up + with: + php-version: ${{ matrix.php-version }} + tools: composer + coverage: ${{ env.COVERAGE_TYPE }} + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Setup cache for PHP ${{ steps.setup-php.outputs.php-version }} & Symfony ${{ matrix.symfony-version }} + uses: actions/cache@v4 + with: + path: | + ${{ steps.composer-cache.outputs.dir }} + # Clear the cache if composer.json (as composer.lock is not available) has been updated + key: tests-php${{ steps.setup-php.outputs.php-version }}-sf${{ matrix.symfony-version }}-${{ hashFiles('composer.json', env.SUPPORTED_VERSIONS_FILE_PATH) }} + + - name: Build with PHP ${{ steps.setup-php.outputs.php-version }} & Symfony ${{ matrix.symfony-version }} + run: | + # Rely on "composer update --with" rather than "composer require" ! + # => it ensures the tested version is actually allowed by constraints + # ("composer require" would override those constraints, which may not produce something actually installable by end-user) + SF_CONSTRAINT="~${{ matrix.symfony-version }}.0" + composer update --no-install --with-all-dependencies --minimal-changes \ + --with "symfony/validator:${SF_CONSTRAINT}" \ + ${{ matrix.pkg-extra-constraints }} \ + && make build + + - name: Tests + run: make test-unit && make test-functional + + - name: Create "unit tests" reports group + if: ${{ env.COVERAGE_TYPE == 'xdebug' }} + uses: yoanm/temp-reports-group-workspace/create-group@v0 + with: + name: unit-tests + format: clover + files: build/coverage-phpunit/unit.clover + flags: | + unit-tests + php-${{ matrix.php-version }} + sf-${{ matrix.symfony-version }} + path: build/coverage-groups + + - name: Create "functional tests" reports group + if: ${{ env.COVERAGE_TYPE == 'xdebug' }} + uses: yoanm/temp-reports-group-workspace/create-group@v0 + with: + name: functional-tests + format: clover + files: | + build/coverage-phpunit/functional.clover + build/coverage-behat/clover.xml + flags: | + functional-tests + php-${{ matrix.php-version }} + sf-${{ matrix.symfony-version }} + path: build/coverage-groups + + - name: Upload coverage reports + if: ${{ env.COVERAGE_TYPE == 'xdebug' }} + uses: actions/upload-artifact@v4 + with: + name: coverage-groups-php${{ steps.setup-php.outputs.php-version }}-sf${{ matrix.symfony-version }} + path: build/coverage-groups + if-no-files-found: error + + static-checks: + name: Static analysis + needs: [fetch-supported-versions] + runs-on: ubuntu-latest + permissions: + contents: read + env: + PHP_VERSION: ${{ needs.fetch-supported-versions.outputs.php-max }} + SYMFONY_VERSION: ${{ needs.fetch-supported-versions.outputs.symfony-max }} + steps: + - uses: actions/checkout@v5 + + - name: Setup PHP ${{ env.PHP_VERSION }} + id: setup-php + uses: shivammathur/setup-php@v2 + env: + update: true # Always use latest available patch for the version + fail-fast: true # step will fail if an extension or tool fails to set up + with: + php-version: ${{ env.PHP_VERSION }} + tools: composer + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Setup cache for PHP ${{ steps.setup-php.outputs.php-version }} & Symfony ${{ env.SYMFONY_VERSION }} + uses: actions/cache@v4 + with: + path: | + ${{ steps.composer-cache.outputs.dir }} + # Clear the cache if composer.json (as composer.lock is not available) has been updated + key: tests-php${{ steps.setup-php.outputs.php-version }}-sf${{ env.SYMFONY_VERSION }}-${{ hashFiles('composer.json', env.SUPPORTED_VERSIONS_FILE_PATH) }} + + - name: Build with PHP ${{ steps.setup-php.outputs.php-version }} & Symfony ${{ env.SYMFONY_VERSION }} + run: | + # Rely on "composer update --with" rather than "composer require" ! + # => it ensures the tested version is actually allowed by constraints + # ("composer require" would override those constraints, which may not produce something actually installable by end-user) + SF_CONSTRAINT="~${{ env.SYMFONY_VERSION }}.0" + composer update --no-install --with-all-dependencies --minimal-changes \ + --with "symfony/validator:${SF_CONSTRAINT}" \ + && make build + + - name: ComposerRequireChecker + uses: docker://webfactory/composer-require-checker:4.5.0 + + - name: Dependencies check + if: ${{ github.event_name == 'pull_request' }} + uses: actions/dependency-review-action@v4 + + nightly-tests: + name: Nightly - PHP ${{ matrix.php-version }} & Sf ${{ matrix.symfony-version }} - ${{ matrix.job-name }} + needs: [ fetch-supported-versions, tests ] + if: ${{ github.event_name == 'push' || ( github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'with-nightly-tests') ) }} + runs-on: ubuntu-latest + permissions: + contents: read + continue-on-error: true + env: + COMPOSER_IGNORE_PLATFORM_REQ: 'php+' + strategy: + fail-fast: false + matrix: + include: + - job-name: PHP with highest supported Symfony versions + php-version: ${{ needs.fetch-supported-versions.outputs.php-next }} + symfony-version: ${{ needs.fetch-supported-versions.outputs.symfony-max }} + # Fix - behat/gherkin => Avoid issue with behat <-> gherkin packages (See https://github.com/Behat/Gherkin/issues/317) + pkg-extra-constraints: behat/gherkin:~4.12.0 + - job-name: PHP with lowest supported Symfony versions + php-version: ${{ needs.fetch-supported-versions.outputs.php-next }} + symfony-version: ${{ needs.fetch-supported-versions.outputs.symfony-min }} + # Fix - behat/gherkin => Avoid issue with behat <-> gherkin packages (See https://github.com/Behat/Gherkin/issues/317) + pkg-extra-constraints: behat/gherkin:~4.12.0 + - job-name: Symfony with highest supported PHP version + php-version: ${{ needs.fetch-supported-versions.outputs.php-max }} + symfony-version: ${{ needs.fetch-supported-versions.outputs.symfony-next }} + # Fix - behat/gherkin => Avoid issue with behat <-> gherkin packages (See https://github.com/Behat/Gherkin/issues/317) + pkg-extra-constraints: behat/gherkin:~4.12.0 + - job-name: Symfony with lowest supported PHP version + # Fix - symfony/validator 7.4 require php 8.2 minimum ! + php-version: ${{ ( needs.fetch-supported-versions.outputs.symfony-next == '7.4' && needs.fetch-supported-versions.outputs.php-min == '8.0' ) && '8.2' || needs.fetch-supported-versions.outputs.php-min }} + symfony-version: ${{ needs.fetch-supported-versions.outputs.symfony-next }} + # Fix - behat/gherkin => Avoid issue with behat <-> gherkin packages (See https://github.com/Behat/Gherkin/issues/317) + pkg-extra-constraints: behat/gherkin:~4.12.0 + + steps: + - name: Check out code + uses: actions/checkout@v5 + + - name: Setup PHP ${{ matrix.php-version }} + id: setup-php + uses: shivammathur/setup-php@v2 + env: + update: true # whether to use latest available patch for the version or not + fail-fast: true # step will fail if an extension or tool fails to set up + with: + php-version: ${{ matrix.php-version }} + tools: composer + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Setup cache for PHP ${{ steps.setup-php.outputs.php-version }} & Symfony ${{ matrix.symfony-version }} + uses: actions/cache@v4 + with: + path: | + ${{ steps.composer-cache.outputs.dir }} + # Clear the cache if composer.json (as composer.lock is not available) has been updated + key: tests-php${{ steps.setup-php.outputs.php-version }}-sf${{ matrix.symfony-version }}-${{ hashFiles('composer.json', env.SUPPORTED_VERSIONS_FILE_PATH) }} + + - name: Build with PHP ${{ steps.setup-php.outputs.php-version }} & Symfony ${{ matrix.symfony-version }} + run: | + # For nightly builds, rely on "composer require" rather than "composer update --with" ! + # => tested version is likely outside of constraints, in that case "composer update --with" would fail + SF_CONSTRAINT="~${{ matrix.symfony-version }}.0@dev" + composer config minimum-stability dev \ + && composer require --no-install --with-all-dependencies --minimal-changes \ + symfony/validator:${SF_CONSTRAINT} \ + ${{ matrix.pkg-extra-constraints }} \ + && make build + + - name: Test + run: make test-unit && make test-functional diff --git a/.github/workflows/reusable-coverage-upload-workflow.yml b/.github/workflows/reusable-coverage-upload-workflow.yml new file mode 100644 index 0000000..a28b160 --- /dev/null +++ b/.github/workflows/reusable-coverage-upload-workflow.yml @@ -0,0 +1,71 @@ +name: 'Coverage upload reusable workflow' + +on: + workflow_call: + secrets: + CODACY_PROJECT_TOKEN: + required: true + CODECOV_TOKEN: + required: true + +permissions: + contents: read + checks: write # For the check run creation ! + +jobs: + fetch-info: + name: Fetch triggering workflow metadata + runs-on: ubuntu-latest + permissions: + contents: read + checks: write # For the check run creation ! + steps: + - name: 'Check run ○' + uses: yoanm/temp-reports-group-workspace/utils/attach-check-run-to-triggering-workflow@v0 + with: + name: 'Fetch triggering workflow metadata' + fails-on-triggering-workflow-failure: true + + - uses: yoanm/temp-reports-group-workspace/utils/fetch-workflow-metadata@v0 + id: fetch-workflow-metadata + + outputs: + commit-sha: ${{ steps.fetch-workflow-metadata.outputs.commit-sha }} + run-id: ${{ steps.fetch-workflow-metadata.outputs.run-id }} + branch: ${{ steps.fetch-workflow-metadata.outputs.branch }} + pull-request: ${{ steps.fetch-workflow-metadata.outputs.pull-request }} + + codacy-uploader: + name: Codacy + needs: [fetch-info] + uses: yoanm/temp-reports-group-workspace/.github/workflows/codacy-upload-from-artifacts.yml@v0 + permissions: + contents: read + checks: write # For the check run creation ! + secrets: + PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} + with: + artifacts-pattern: coverage-groups-* + run-id: ${{ needs.fetch-info.outputs.run-id }} + force-git-commit: ${{ needs.fetch-info.outputs.commit-sha }} + # force-uploader-language: ... + # force-uploader-coverage-parser: ... + # force-uploader-cli-version: ... + + codecov-uploader: + name: Codecov + needs: [fetch-info] + uses: yoanm/temp-reports-group-workspace/.github/workflows/codecov-upload-from-artifacts.yml@v0 + permissions: + contents: read + checks: write # For the check run creation ! + secrets: + TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + artifacts-pattern: coverage-groups-* + run-id: ${{ needs.fetch-info.outputs.run-id }} + force-git-commit: ${{ needs.fetch-info.outputs.commit-sha }} + force-git-branch: ${{ needs.fetch-info.outputs.branch }} + force-gh-pr: ${{ needs.fetch-info.outputs.pull-request }} + force-uploader-build: ${{ needs.fetch-info.outputs.run-id }} + force-uploader-build-url: ${{ needs.fetch-info.outputs.run-url }} diff --git a/.github/workflows/supported-versions.json b/.github/workflows/supported-versions.json new file mode 100644 index 0000000..9615147 --- /dev/null +++ b/.github/workflows/supported-versions.json @@ -0,0 +1,4 @@ +{ + "php": {"min": "8.0", "max": "8.4", "next": "8.5"}, + "symfony": {"min": "5.4", "max": "7.3", "next": "7.4"} +} diff --git a/.gitignore b/.gitignore index 457cea1..4cb177e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,9 @@ vendor build #A library must not provide a composer.lock file composer.lock + +# Demo app excluded dirs +features/demo_app/var/ + #Phpunit .phpunit.result.cache diff --git a/.remarkrc b/.remarkrc index 0527df5..5bf1fca 100644 --- a/.remarkrc +++ b/.remarkrc @@ -1,6 +1,10 @@ { "plugins": [ "remark-preset-lint-consistent", - "remark-preset-lint-recommended" + "remark-preset-lint-recommended", + [ + "remark-lint-list-item-indent", + "space" + ] ] } diff --git a/.scrutinizer.yml b/.scrutinizer.yml index b579dd2..938ad6a 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -41,7 +41,6 @@ build: variables: CI: 'true' TEST_OUTPUT_STYLE: 'pretty' - COMPOSER_OPTIONS: '--optimize-autoloader' COVERAGE_OUTPUT_STYLE: 'clover' COVERAGE_CLOVER_FILE_PATH: 'build/coverage/clover.xml' PHPCS_DISABLE_WARNING: 'true' diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index c4f2952..2d53c83 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -23,13 +23,13 @@ include: Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or - advances + advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic - address, without explicit permission + address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a - professional setting + professional setting ## Our Responsibilities diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 86dc163..8b86e31 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,33 +1,39 @@ # Contributing ## Getting Started - * Fork, then clone the repo: + +* Fork, then clone the repo: + ```bash git clone git@github.com:your-username/php-jsonrpc-params-symfony-validator-sdk.git -```` +``` + +* Make sure everything goes well: - * Make sure everything goes well: ```bash make build make test ``` - * Make your changes (Add/Update tests according to your changes). - * Make sure tests are still green: +* Make your changes (Add/Update tests according to your changes). +* Make sure tests are still green: + ```bash make test ``` - * To check code coverage, launch +* To check code coverage, launch + ```bash make coverage ``` - * Push to your fork and [submit a pull request](https://github.com/yoanm/php-jsonrpc-params-symfony-validator-sdk/compare/). - * Wait for feedback or merge. +* Push to your fork and [submit a pull request](https://github.com/yoanm/php-jsonrpc-params-symfony-validator-sdk/compare/). +* Wait for feedback or merge. + +Some stuff that will increase your pull request's acceptance: - Some stuff that will increase your pull request's acceptance: - * Write tests. - * Follow PSR-2 coding style. - * Write good commit messages. - * Do not rebase or squash your commits when a review has been made. +* Write tests. +* Follow PSR-2 coding style. +* Write good commit messages. +* Do not rebase or squash your commits when a review has been made. diff --git a/Makefile b/Makefile index fdbc8a1..0c3c84f 100644 --- a/Makefile +++ b/Makefile @@ -109,5 +109,13 @@ scrutinizer-behat: create-build-directories: mkdir -p ${PHPUNIT_COVERAGE_DIRECTORY} ${BEHAT_COVERAGE_DIRECTORY} ${REPORTS_DIRECTORY} +.PHONY: configure-dev-env +configure-dev-env: + npm install --global remark-cli remark-preset-lint-consistent remark-preset-lint-recommended remark-lint-list-item-indent + +.PHONY: lint-markdown +lint-markdown: + npx remark . --output + .PHONY: build install configure test test-unit test-functional codestyle create-build-directories scrutinizer-behat scrutinizer-phpunit .DEFAULT: build diff --git a/README.md b/README.md index 619e8f1..dfe14e0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # JSON-RPC params symfony validator + [![License](https://img.shields.io/github/license/yoanm/php-jsonrpc-params-symfony-validator-sdk.svg)](https://github.com/yoanm/php-jsonrpc-params-symfony-validator-sdk) [![Code size](https://img.shields.io/github/languages/code-size/yoanm/php-jsonrpc-params-symfony-validator-sdk.svg)](https://github.com/yoanm/php-jsonrpc-params-symfony-validator-sdk) -[![Dependabot Status](https://api.dependabot.com/badges/status?host=github\&repo=yoanm/php-jsonrpc-params-symfony-validator-sdk)](https://dependabot.com) +![Dependabot Status](https://flat.badgen.net/github/dependabot/yoanm/php-jsonrpc-params-symfony-validator-sdk) +![Last commit](https://badgen.net/github/last-commit/yoanm/php-jsonrpc-params-symfony-validator-sdk) [![Scrutinizer Build Status](https://img.shields.io/scrutinizer/build/g/yoanm/php-jsonrpc-params-symfony-validator-sdk.svg?label=Scrutinizer\&logo=scrutinizer)](https://scrutinizer-ci.com/g/yoanm/php-jsonrpc-params-symfony-validator-sdk/build-status/master) [![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/yoanm/php-jsonrpc-params-symfony-validator-sdk/master.svg?logo=scrutinizer)](https://scrutinizer-ci.com/g/yoanm/php-jsonrpc-params-symfony-validator-sdk/?branch=master) @@ -9,12 +11,11 @@ [![CI](https://github.com/yoanm/php-jsonrpc-params-symfony-validator-sdk/actions/workflows/CI.yml/badge.svg?branch=master)](https://github.com/yoanm/php-jsonrpc-params-symfony-validator-sdk/actions/workflows/CI.yml) [![codecov](https://codecov.io/gh/yoanm/php-jsonrpc-params-symfony-validator-sdk/branch/master/graph/badge.svg?token=NHdwEBUFK5)](https://codecov.io/gh/yoanm/php-jsonrpc-params-symfony-validator-sdk) -[![Symfony Versions](https://img.shields.io/badge/Symfony-v4.4%20%2F%20v5.4%2F%20v6.x-8892BF.svg?logo=github)](https://symfony.com/) +[![Symfony Versions](https://img.shields.io/badge/Symfony-v5.4%20%2F%20v6.4%20%2F%20v7.x-8892BF.svg?logo=github)](https://symfony.com/) [![Latest Stable Version](https://img.shields.io/packagist/v/yoanm/jsonrpc-params-symfony-validator-sdk.svg)](https://packagist.org/packages/yoanm/jsonrpc-params-symfony-validator-sdk) [![Packagist PHP version](https://img.shields.io/packagist/php-v/yoanm/jsonrpc-params-symfony-validator-sdk.svg)](https://packagist.org/packages/yoanm/jsonrpc-params-symfony-validator-sdk) - Simple JSON-RPC params validator that use Symfony validator component See [yoanm/symfony-jsonrpc-params-validator](https://github.com/yoanm/symfony-jsonrpc-params-validator) for automatic dependency injection. @@ -23,23 +24,28 @@ See [yoanm/jsonrpc-params-symfony-constraint-doc-sdk](https://github.com/yoanm/p ## Versions -* Symfony v3/4 - PHP >=7.1 : `^v1.0` -* Symfony v4/5 - PHP >=7.2 : `^v2.0` +* Symfony v3/4 - PHP >=7.1 : `^v1.0` + +* Symfony v4/5 - PHP >=7.2 : `^v2.0` - ⚠️⚠️ `v0.2.0` is replaced by `v1.0.0` ! ⚠️⚠️ + ⚠️⚠️ `v0.2.0` is replaced by `v1.0.0` ! ⚠️⚠️ - ⚠️⚠️ `v0.3.0` was badly taggued, used `v2.0.0` instead ! ⚠️⚠️ + ⚠️⚠️ `v0.3.0` was badly taggued, used `v2.0.0` instead ! ⚠️⚠️ -* Symfony v4.4/5.4/6.0 - PHP ^8.0 : `^v2.1` +* Symfony v4.4/5.4/6.0 - PHP ^8.0 : `^v2.1` +* Symfony v5.4/6.4/7.0 - PHP ^8.0 : `^v3.0` ## How to use -In order to be validated, a JSON-RPC method must : -* Implements `JsonRpcMethodInterface` from [`yoanm/jsonrpc-server-sdk`](https://github.com/yoanm/php-jsonrpc-server-sdk) -* Implements [`MethodWithValidatedParamsInterface`](./src/Infra/JsonRpcParamsValidator.php) +In order to be validated, a JSON-RPC method must : + +* Implements `JsonRpcMethodInterface` from [`yoanm/jsonrpc-server-sdk`](https://github.com/yoanm/php-jsonrpc-server-sdk) +* Implements [`MethodWithValidatedParamsInterface`](./src/Infra/JsonRpcParamsValidator.php) ### With [`yoanm/jsonrpc-server-sdk`](https://github.com/yoanm/php-jsonrpc-server-sdk) -Create the validator and inject it into request handler : + +Create the validator and inject it into request handler : + ```php $requestHandler->setMethodParamsValidator( new JsonRpcParamsValidator( @@ -50,7 +56,8 @@ $requestHandler->setMethodParamsValidator( Then you can send JSON-RPC request string to the server and any method wich implements `MethodWithValidatedParamsInterface` will be validated. -### Standalone +### Standalone + ```php use Symfony\Component\Validator\ValidatorBuilder; use Yoanm\JsonRpcParamsSymfonyValidator\Infra\JsonRpcParamsValidator; @@ -65,6 +72,7 @@ $violationList = $paramsValidator->validate($jsonRpcRequest, $jsonRpcMethod); ``` ### Params validation example + ```php use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\Collection; @@ -98,7 +106,9 @@ class MethodExample implements JsonRpcMethodInterface, MethodWithValidatedParams ``` ### Violations format + Each violations will have the following format : + ```php [ 'path' => 'property_path', @@ -108,4 +118,5 @@ Each violations will have the following format : ``` ## Contributing + See [contributing note](./CONTRIBUTING.md) diff --git a/composer.json b/composer.json index 4160bdf..3d0a62e 100644 --- a/composer.json +++ b/composer.json @@ -32,11 +32,11 @@ }, "require": { "php": "^8.0", - "symfony/validator": "^4.4 || ^5.4 || ^6.0", + "symfony/validator": "^5.4 || ^6.4 || ^7.0", "yoanm/jsonrpc-server-sdk": "^3.0" }, "require-dev": { - "behat/behat": "^3.9.0", + "behat/behat": "^3.9.0,<=3.16.1", "dvdoug/behat-code-coverage": "^5.0", "phpspec/prophecy": "^1.15", "phpspec/prophecy-phpunit": "^2.0", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 958d0be..0b44794 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,8 +1,7 @@ - - - - - - - - tests/Functional/* - - - tests/Technical/* - - - - - - src - - +> + + + src + + + + + + + + tests/Functional + + + tests/Technical + +