diff --git a/.gitattributes b/.gitattributes index 97fb776..a143f13 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,4 +12,4 @@ *.md export-ignore *.yml export-ignore .php-cs-fixer.dist.php export-ignore -Makefile export-ignore +Taskfile.yml export-ignore diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 3e320bf..a0ee0bf 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -1,30 +1,34 @@ -name: Static analysis -on: [push] +name: static-analysis +on: + pull_request: + push: + branches: ['main'] jobs: phpstan: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: shivammathur/setup-php@v2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # https://github.com/actions/checkout/releases/tag/v6.0.2 + - uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # https://github.com/shivammathur/setup-php/releases/tag/2.37.1 with: php-version: 8.4 - - run: composer update --prefer-stable --prefer-dist --no-interaction --no-suggest + extensions: -pdo_mysql, -mysqli + - run: composer update --prefer-stable --prefer-dist --no-interaction - run: composer phpstan php-cs-fixer: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # https://github.com/actions/checkout/releases/tag/v6.0.2 with: ref: ${{ github.head_ref }} - - name: Run PHP CS fixer + - name: 'Run PHP CS fixer' uses: ./.github/actions/php-cs-fixer with: workspace: ${{ github.workspace }} args: --config=.php-cs-fixer.dist.php --allow-risky=yes github-token: ${{ secrets.GITHUB_TOKEN }} - - name: Commit CS fixes + - name: 'Commit CS fixes' uses: craftzing/git-auto-commit-action@778341af668090896ca464160c2def5d1d1a3eb0 with: commit_message: Fix code style violations diff --git a/.github/workflows/tests.yml b/.github/workflows/test.yml similarity index 50% rename from .github/workflows/tests.yml rename to .github/workflows/test.yml index 5326d08..bf5aadf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,8 @@ -name: Tests -on: [push, pull_request] +name: test +on: + pull_request: + push: + branches: ['main'] jobs: tests: @@ -8,14 +11,15 @@ jobs: fail-fast: true matrix: os: [ubuntu-24.04] - php: [8.4] + php: [8.4, 8.5] dependency-version: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - ${{ matrix.dependency-version }} steps: - - uses: actions/checkout@v4 - - uses: shivammathur/setup-php@v2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # https://github.com/actions/checkout/releases/tag/v6.0.2 + - uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # https://github.com/shivammathur/setup-php/releases/tag/2.37.1 with: php-version: ${{ matrix.php }} coverage: pcov - - run: composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest + extensions: -pdo_mysql, -mysqli + - run: composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction - run: composer coverage:summary diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c5f6546..c2d4e78 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,9 +14,17 @@ Make sure to follow these rules when creating a pull request: - We follow [Semantic Versioning](http://semver.org/), so please send pull requests to the correct branch - Update the [CHANGELOG.md](CHANGELOG.md) file with any changes/additions/... and follow the [changelog standards](http://keepachangelog.com/) -## ๐Ÿงช Running tests +# ๐Ÿƒโ€โžก๏ธ Running locally -You can run the test suite with the following command: -```bash -vendor/bin/phpunit +This project is fully Dockerized, meaning [Docker](https://docs.docker.com) (or [Orbstack](https://orbstack.dev) for macOS users) is the only requirement +to run this project locally. Using Docker Compose, we set up a container for each supported PHP version. + +> [!TIP] +> While you can run Docker Compose commands directly, we highly recommend to use our predefined tasks using +> [Task](https://taskfile.dev). All docs will always refer to these tasks, but if you prefer not to install +> Task, you can inspect [Taskfile.yml](./Taskfile.yml) to see which Docker Compose commands are used under the hood. + +To explore all available tasks, run: +```shell +task ``` diff --git a/Makefile b/Makefile deleted file mode 100644 index bba2ce4..0000000 --- a/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -.PHONY: up -up: ## Up the project using Docker Composer - docker compose up --detach - docker compose exec php84 composer install - -.PHONY: down -down: ## Shutdown the project using Docker Composer - docker compose down - -.PHONY: php84 -php84: ## Open an interactive shell into the `php84` (service in docker-compose.yml) - docker compose up -d - docker compose exec php84 sh diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..7c2d679 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,61 @@ +# https://taskfile.dev +version: '3.50' + +vars: + PHP_VERSIONS: ['8.4', '8.5'] + DEFAULT_PHP_VERSION: '8.5' + +tasks: + default: + desc: 'List all available tasks' + silent: true + cmd: task --list + + up: + desc: 'Up the PHP container(s) and install all Composer dependencies' + cmds: + - docker compose up --detach + - docker compose exec php-{{ .DEFAULT_PHP_VERSION }} composer install + + down: + desc: 'Shutdown the PHP container(s)' + cmds: + - docker compose down + + php: + desc: 'Open an interactive shell into one of the `php` services (see docker-compose.yml)' + summary: | + Open an interactive shell into one of the `php` services (see docker-compose.yml). + + usage: + task php version= + requires: + vars: + - name: version + enum: + ref: .PHP_VERSIONS + cmds: + - docker compose up --detach + - docker compose exec php-{{ .version }} sh + + test: + desc: 'Run the testsuite on all or one of the supported PHP versions' + summary: | + Run the testsuite on all or one of the supported PHP versions. + + usage: + task test + task test version= + vars: + versions: |- + {{- if .version -}} + {{ .version }} + {{- else -}} + {{ join "," .PHP_VERSIONS }} + {{- end -}} + cmds: + - docker compose up --detach + - for: + var: versions + split: ',' + cmd: docker compose exec php-{{ .ITEM }} composer phpunit diff --git a/docker-compose.yml b/docker-compose.yml index 9896e09..ccfb45c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ services: - php84: + php-8.4: build: context: . dockerfile: docker/php84/Dockerfile @@ -9,3 +9,13 @@ services: working_dir: /code volumes: - ./:/code:delegated + php-8.5: + build: + context: . + dockerfile: docker/php85/Dockerfile + container_name: php-testbench.craftzing.php85 + restart: unless-stopped + tty: true + working_dir: /code + volumes: + - ./:/code:delegated diff --git a/docker/php84/Dockerfile b/docker/php84/Dockerfile index 98d3245..88c3e17 100644 --- a/docker/php84/Dockerfile +++ b/docker/php84/Dockerfile @@ -1,10 +1,10 @@ -FROM php:8.4-cli-alpine3.21 +FROM php:8.4-cli-alpine3.23 WORKDIR /code USER root COPY docker/setup.sh . RUN chmod u+x /code/setup.sh && /code/setup.sh && rm /code/setup.sh -COPY --from=composer:2.8 /usr/bin/composer /usr/local/bin/composer +COPY --from=composer:2.10 /usr/bin/composer /usr/local/bin/composer USER app diff --git a/docker/php85/Dockerfile b/docker/php85/Dockerfile new file mode 100644 index 0000000..43d7ceb --- /dev/null +++ b/docker/php85/Dockerfile @@ -0,0 +1,10 @@ +FROM php:8.5-cli-alpine3.23 + +WORKDIR /code + +USER root +COPY docker/setup.sh . +RUN chmod u+x /code/setup.sh && /code/setup.sh && rm /code/setup.sh +COPY --from=composer:2.10 /usr/bin/composer /usr/local/bin/composer + +USER app diff --git a/src/Factories/ImmutableFactory.php b/src/Factories/ImmutableFactory.php index b6303f5..40570dd 100644 --- a/src/Factories/ImmutableFactory.php +++ b/src/Factories/ImmutableFactory.php @@ -13,7 +13,7 @@ use function iterator_to_array; /** - * @template TClass + * @template TClass of object */ abstract class ImmutableFactory { @@ -34,6 +34,7 @@ final public function __construct( */ public function state(array $state): static { + // @phpstan-ignore-next-line return.type return new static($this->faker, [...$this->state, ...$state], $this->count); } @@ -42,6 +43,7 @@ public function state(array $state): static */ public function times(int $count): static { + // @phpstan-ignore-next-line return.type return new static($this->faker, $this->state, $count); } @@ -87,7 +89,7 @@ public function raw(array $attributes = []): array /** * @param array $attributes - * @return array + * @return array> */ public function rawMany(array $attributes = []): array { diff --git a/src/Factories/InstanceFactory.php b/src/Factories/InstanceFactory.php index 36371b2..21b414d 100644 --- a/src/Factories/InstanceFactory.php +++ b/src/Factories/InstanceFactory.php @@ -8,7 +8,7 @@ use ReflectionProperty; /** - * @template TClass + * @template TClass of object */ final readonly class InstanceFactory { diff --git a/src/PHPUnit/DataProviders/EnumCase.php b/src/PHPUnit/DataProviders/EnumCase.php index b2c7101..a5f5f34 100644 --- a/src/PHPUnit/DataProviders/EnumCase.php +++ b/src/PHPUnit/DataProviders/EnumCase.php @@ -26,10 +26,12 @@ */ private array $options; + /** + * @param TValue $instance + * @param TValue ...$options + */ public function __construct( - /* @var TValue */ public UnitEnum $instance, - /* @param array ...$options */ UnitEnum ...$options, ) { in_array($instance, $options, true) or throw new ValueError('Options should contain the given instance.'); @@ -58,7 +60,7 @@ public function differentInstance(): UnitEnum /** * @param class-string $enumFQCN - * @return iterable>> + * @return iterable}> */ public static function cases(string $enumFQCN): iterable { @@ -72,7 +74,7 @@ public static function cases(string $enumFQCN): iterable /** * @param TValue ...$options - * @return iterable>> + * @return iterable}> */ public static function options(UnitEnum ...$options): iterable { @@ -83,7 +85,7 @@ public static function options(UnitEnum ...$options): iterable /** * @param class-string $enumFQCN - * @return iterable>> + * @return iterable}> */ public static function except(string $enumFQCN, UnitEnum ...$except): iterable {