├── .gitignore ├── .github ├── FUNDING.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── update-toolbox.yml │ ├── release.yml │ └── build.yml ├── docs └── cookbook │ ├── options.md │ ├── README.md │ ├── starter-kits.md │ ├── gitlab-ci.md │ ├── debugger-and-code-coverage.md │ ├── bitbucket-pipelines.md │ ├── github-actions.md │ ├── customising-the-image.md │ ├── ampq.md │ └── xdebug.md ├── CONTRIBUTING.md ├── LICENSE ├── CODE_OF_CONDUCT.md ├── Makefile ├── Dockerfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /devkit 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [jakzal] 2 | 3 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /docs/cookbook/options.md: -------------------------------------------------------------------------------- 1 | # Options 2 | 3 | *Contributed by [alexislefebvre](https://github.com/alexislefebvre).* 4 | 5 | For tools that don’t require Composer dependencies, e.g. `php-cs-fixer`, 6 | you can skip the automatic `composer install` (1) 7 | by defining the value `SKIP_COMPOSER_INSTALL` to `true` (it’s a string). 8 | 9 | (1) it’s configured in the [`Dockerfile`](https://github.com/jakzal/phpqa/blob/master/Dockerfile). 10 | -------------------------------------------------------------------------------- /docs/cookbook/README.md: -------------------------------------------------------------------------------- 1 | # Cookbook 2 | 3 | Here you will find a list of tips & tricks that are too long to be put in the main README. 4 | 5 | ## Index 6 | 7 | - [Debugger & Code Coverage](debugger-and-code-coverage.md) 8 | - [Customising the image](customising-the-image.md) 9 | - [Install AMPQ in PHPQA](ampq.md) 10 | - [Install Xdebug in PHPQA](xdebug.md) 11 | - [GitHub Actions](github-actions.md) 12 | - [Bitbucket Pipelines](bitbucket-pipelines.md) 13 | - [Gitlab CI](gitlab-ci.md) 14 | - [Starter Kits](starter-kits.md) 15 | - [Options](options.md) 16 | -------------------------------------------------------------------------------- /docs/cookbook/starter-kits.md: -------------------------------------------------------------------------------- 1 | # Starter-kits / Templates 2 | 3 | *Contributed by [ro0NL](https://github.com/ro0NL).* 4 | 5 | ## [`ro0NL/php-package-starter-kit`](https://github.com/ro0NL/php-package-starter-kit) 6 | 7 | A template repository for agnostic PHP libraries. It utilizes the PHPQA image into a `Makefile` and configures some 8 | tools by default. 9 | 10 | ## [`ro0NL/symfony-docker`](https://github.com/ro0NL/symfony-docker) 11 | 12 | A template repository for Docker based [Symfony](https://symfony.com) applications. It utilizes the PHPQA image into 13 | a `Dockerfile` and integrates in the composed landscape. 14 | -------------------------------------------------------------------------------- /.github/workflows/update-toolbox.yml: -------------------------------------------------------------------------------- 1 | name: Update toolbox 2 | 3 | on: 4 | schedule: 5 | - cron: '30 1 * * *' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | nightly-builds: 10 | runs-on: ubuntu-latest 11 | name: Update 12 | steps: 13 | - uses: actions/checkout@v4 14 | - run: git config user.email 'jakub@zalas.pl' && git config user.name 'Jakub Zalas' 15 | - run: sudo apt-get update && sudo apt-get install -y hub 16 | - run: make update-toolbox-pr 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 19 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository send a new pull request. 4 | If your change is big or complex, or you simply want to suggest an improvement, 5 | please discuss the change you wish to make via an issue. 6 | 7 | Please note we have a [code of conduct](CODE_OF_CONDUCT.md). Please follow it in all your interactions with the project. 8 | 9 | ## Pull Request Process 10 | 11 | * Add any new tools to the [`jakzal/toolbox` repository](https://github.com/jakzal/toolbox) 12 | * Provide a good commit message describing what you've done. 13 | * Ensure any install or build dependencies are removed before the end of the layer when doing a build. 14 | -------------------------------------------------------------------------------- /docs/cookbook/gitlab-ci.md: -------------------------------------------------------------------------------- 1 | # Gitlab CI 2 | 3 | *Contributed by [RVxLab](https://github.com/RVxLab).* 4 | 5 | The example below demonstrates how phpqa can be used in the Gitlab CI. 6 | 7 | ```yaml 8 | # .gitlab-ci.yml 9 | image: php:8.2-fpm-alpine3.15 10 | 11 | stages: 12 | - style 13 | 14 | php-cs-fixer: 15 | stage: style 16 | image: jakzal/phpqa:php8.2-alpine 17 | variables: 18 | # set to “true” if the tool can work without Composer dependencies 19 | SKIP_COMPOSER_INSTALL: false 20 | script: 21 | - php-cs-fixer fix --dry-run --stop-on-violation 22 | 23 | phpstan: 24 | stage: style 25 | image: jakzal/phpqa:php8.2-alpine 26 | script: 27 | - phpstan analyze 28 | ``` 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | schedule: 5 | - cron: '0 3 * * 1' 6 | workflow_dispatch: 7 | inputs: 8 | next_release: 9 | type: string 10 | description: The version to release 11 | 12 | jobs: 13 | release: 14 | runs-on: ubuntu-latest 15 | name: Release 16 | steps: 17 | - uses: actions/checkout@v4 18 | - run: git config user.email 'jakub@zalas.pl' && git config user.name 'Jakub Zalas' 19 | - run: sudo apt-get update && sudo apt-get install -y hub 20 | - run: make auto-release NEXT_RELEASE="${{ github.event.inputs.next_release }}" 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 23 | -------------------------------------------------------------------------------- /docs/cookbook/debugger-and-code-coverage.md: -------------------------------------------------------------------------------- 1 | # Debugger & Code Coverage 2 | 3 | *Contributed by [jakzal](https://github.com/jakzal).* 4 | 5 | The [pcov](https://github.com/krakjoe/pcov) code coverage extension, 6 | as well as the [php-dbg debugger](http://php.net/manual/en/debugger-about.php), 7 | are provided on the image out of the box. 8 | 9 | pcov is disabled by default so it doesn't affect performance when it's not needed, 10 | and doesn't break interoperability with other coverage extensions. 11 | It can be enabled by setting `pcov.enabled=1`: 12 | 13 | ``` 14 | phpqa php -d pcov.enabled=1 ./vendor/bin/phpunit --coverage-text 15 | ``` 16 | 17 | Infection users will need to define initial php options: 18 | 19 | ``` 20 | phpqa /tools/infection run --initial-tests-php-options='-dpcov.enabled=1' 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/cookbook/bitbucket-pipelines.md: -------------------------------------------------------------------------------- 1 | # Bitbucket Pipelines 2 | 3 | *Contributed by [jakzal](https://github.com/jakzal).* 4 | 5 | Here is an example configuration of a bitbucket pipeline using the phpqa image: 6 | 7 | ```yaml 8 | # bitbucket-pipelines.yml 9 | image: jakzal/phpqa:php8.2-alpine 10 | pipelines: 11 | default: 12 | - step: 13 | name: Static analysis 14 | caches: 15 | - composer 16 | script: 17 | - composer install --no-scripts --no-progress 18 | - phpstan analyze src/ -l 1 19 | - php-cs-fixer --dry-run --allow-risky=yes --no-interaction --ansi fix 20 | - deptrac --no-interaction --ansi --formatter-graphviz-display=0 21 | ``` 22 | 23 | Unfortunately, bitbucket overrides the docker entrypoint so composer needs to be 24 | explicitly invoked as in the above example. 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Jakub Zalas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /docs/cookbook/github-actions.md: -------------------------------------------------------------------------------- 1 | # GitHub actions 2 | 3 | *Contributed by [jakzal](https://github.com/jakzal).* 4 | 5 | The image can be used with GitHub actions. 6 | Below is an example for several static analysis tools. 7 | 8 | ```yaml 9 | # .github/workflows/static-code-analysis.yml 10 | name: Static code analysis 11 | 12 | on: [pull_request] 13 | 14 | jobs: 15 | static-code-analysis: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@master 19 | - name: PHPStan 20 | uses: docker://jakzal/phpqa:php8.2-alpine 21 | with: 22 | args: phpstan analyze src/ -l 1 23 | - name: PHP-CS-Fixer 24 | uses: docker://jakzal/phpqa:php8.2-alpine 25 | with: 26 | args: php-cs-fixer --dry-run --allow-risky=yes --no-interaction --ansi fix 27 | env: 28 | # set to “true” if the tool can work without Composer dependencies 29 | SKIP_COMPOSER_INSTALL: false 30 | - name: Deptrac 31 | uses: docker://jakzal/phpqa:php8.2-alpine 32 | with: 33 | args: deptrac --no-interaction --ansi --formatter-graphviz-display=0 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/cookbook/customising-the-image.md: -------------------------------------------------------------------------------- 1 | # Customising the image 2 | 3 | *Contributed by [jakzal](https://github.com/jakzal).* 4 | 5 | It's often needed to customise the image with project specific extensions. 6 | To achieve that simply create a new image based on `jakzal/phpqa`: 7 | 8 | ``` 9 | FROM jakzal/phpqa:alpine 10 | 11 | RUN apk add --no-cache libxml2-dev \ 12 | && docker-php-ext-install soap 13 | ``` 14 | 15 | Next, build it: 16 | 17 | ``` 18 | docker build -t foo/phpqa . 19 | ``` 20 | 21 | Finally, use your customised image instead of the default one: 22 | 23 | ``` 24 | docker run --init -it --rm -v "$(pwd):/project" -w /project foo/phpqa phpmetrics . 25 | ``` 26 | 27 | ## Adding PHPStan extensions 28 | 29 | A number of PHPStan extensions is available on the image in `/tools/.composer/vendor-bin/phpstan/vendor` out of the box. 30 | You can find them with the command below: 31 | 32 | ``` 33 | phpqa find /tools/.composer/vendor-bin/phpstan/vendor/ -iname 'rules.neon' -or -iname 'extension.neon' 34 | ``` 35 | 36 | Use the composer-bin-plugin to install any additional PHPStan extensions in the `phpstan` namespace: 37 | 38 | ``` 39 | FROM jakzal/phpqa:alpine 40 | 41 | RUN composer global bin phpstan require phpstan/phpstan-phpunit 42 | ``` 43 | 44 | You'll be able to include them in your PHPStan configuration from the `/tools/.composer/vendor-bin/phpstan/vendor` path: 45 | 46 | ```yaml 47 | includes: 48 | - /tools/.composer/vendor-bin/phpstan/vendor/phpstan/phpstan-phpunit/extension.neon 49 | ``` -------------------------------------------------------------------------------- /docs/cookbook/ampq.md: -------------------------------------------------------------------------------- 1 | # AMPQ 2 | 3 | *Contributed by [dgoosens](https://github.com/dgoosens).* 4 | 5 | Some extension do take a little time before they are ready for the latest and greatest version of PHP. 6 | If you really need those extensions and can not wait, you will have to compile them yourself. 7 | 8 | This can easily be done with PHPQA as well. 9 | 10 | *The procedure below uses a [Docker MultiStage Build](https://docs.docker.com/develop/develop-images/multistage-build/) and the resulting build will therefore barely be any bigger than the original PHPQA.* 11 | 12 | As instructed in the [Customising the image recipe](customising-the-image.md), one has to create a new `Dockerfile` to customize it. 13 | 14 | ## Debian Dockerfile 15 | 16 | ```Dockerfile 17 | FROM jakzal/phpqa:debian AS ext-amqp 18 | ENV EXT_AMQP_VERSION=master 19 | 20 | RUN docker-php-source extract 21 | RUN apt-get update 22 | RUN apt-get install -qq -y build-essential autoconf librabbitmq-dev 23 | RUN git clone --branch $EXT_AMQP_VERSION --depth 1 https://github.com/php-amqp/php-amqp.git /usr/src/php/ext/amqp 24 | RUN cd /usr/src/php/ext/amqp && git submodule update --init 25 | RUN docker-php-ext-install amqp 26 | 27 | RUN ls -al /usr/local/lib/php/extensions/ 28 | 29 | FROM jakzal/phpqa:debian 30 | 31 | COPY --from=ext-amqp /usr/local/etc/php/conf.d/docker-php-ext-amqp.ini /usr/local/etc/php/conf.d/docker-php-ext-amqp.ini 32 | COPY --from=ext-amqp /usr/local/lib/php/extensions/no-debug-non-zts-20210902/amqp.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/amqp.so 33 | 34 | RUN apt-get update 35 | RUN apt-get install -qq -y librabbitmq-dev 36 | ``` 37 | 38 | ## Alpine Dockerfile 39 | 40 | ```Dockerfile 41 | FROM jakzal/phpqa:alpine AS ext-amqp 42 | ENV EXT_AMQP_VERSION=master 43 | 44 | RUN docker-php-source extract 45 | RUN apk -Uu add rabbitmq-c-dev 46 | RUN git clone --branch $EXT_AMQP_VERSION --depth 1 https://github.com/php-amqp/php-amqp.git /usr/src/php/ext/amqp 47 | RUN cd /usr/src/php/ext/amqp && git submodule update --init 48 | RUN docker-php-ext-install amqp 49 | 50 | RUN ls -al /usr/local/lib/php/extensions/ 51 | 52 | FROM jakzal/phpqa:alpine 53 | 54 | COPY --from=ext-amqp /usr/local/etc/php/conf.d/docker-php-ext-amqp.ini /usr/local/etc/php/conf.d/docker-php-ext-amqp.ini 55 | COPY --from=ext-amqp /usr/local/lib/php/extensions/no-debug-non-zts-20210902/amqp.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/amqp.so 56 | 57 | RUN apk -Uu add rabbitmq-c-dev 58 | ``` 59 | 60 | ## About the extension path 61 | 62 | Please note that the `no-debug-non-zts-20210902` in the above extension path, that is copied, changes with every release... 63 | This is why the `RUN ls -al /usr/local/lib/php/extensions/` is issued as it will list the content of that directory and inform the user what the exact path should be. 64 | 65 | ## Source 66 | 67 | Highly inspired by this [blog post](https://exploit.cz/how-to-compile-amqp-extension-for-php-8-0-via-multistage-dockerfile/) by Patrick from [exploit.cz](https://exploit.cz/) -------------------------------------------------------------------------------- /docs/cookbook/xdebug.md: -------------------------------------------------------------------------------- 1 | # Xdebug 2 | 3 | *Contributed by [dgoosens](https://github.com/dgoosens).* 4 | 5 | This procedure is similar to the one explained for [AMPQ](ampq.md). 6 | 7 | ## Debian Dockerfile 8 | 9 | ```Dockerfile 10 | FROM jakzal/phpqa:debian AS ext-xdebug 11 | 12 | RUN docker-php-source extract 13 | RUN apt-get update 14 | RUN apt-get install -qq -y build-essential autoconf 15 | 16 | RUN pecl install xdebug 17 | RUN docker-php-ext-enable xdebug 18 | 19 | RUN ls -al /usr/local/lib/php/extensions/ 20 | 21 | FROM jakzal/phpqa:debian 22 | 23 | COPY --from=ext-xdebug /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini 24 | COPY --from=ext-xdebug /usr/local/lib/php/extensions/no-debug-non-zts-20210902/xdebug.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/xdebug.so 25 | ``` 26 | 27 | ## Alpine Dockerfile 28 | 29 | ```Dockerfile 30 | FROM jakzal/phpqa:alpine AS ext-xdebug 31 | 32 | RUN docker-php-source extract 33 | RUN apk -Uu add autoconf build-base 34 | RUN pecl install xdebug 35 | RUN docker-php-ext-enable xdebug 36 | 37 | RUN ls -al /usr/local/lib/php/extensions/ 38 | 39 | FROM jakzal/phpqa:alpine 40 | 41 | COPY --from=ext-xdebug /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini 42 | COPY --from=ext-xdebug /usr/local/lib/php/extensions/no-debug-non-zts-20210902/xdebug.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/xdebug.so 43 | ``` 44 | 45 | ## About the extension path 46 | 47 | Please note that the `no-debug-non-zts-20210902` in the above extension path, that is copied, changes with every release... 48 | This is why the `RUN ls -al /usr/local/lib/php/extensions/` is issued as it will list the content of that directory and inform the user what the exact path should be. 49 | 50 | ## Note 51 | 52 | If you need to include multiple extensions, you will have to bundle the commands together. 53 | For instance, for [AMPQ](ampq.md) **AND** XDebug, the Debian `Dockerfile` will look like this: 54 | 55 | ```Dockerfile 56 | FROM jakzal/phpqa:debian AS ext-multi 57 | ENV EXT_AMQP_VERSION=master 58 | 59 | RUN docker-php-source extract 60 | RUN apt-get update 61 | RUN apt-get install -qq -y build-essential autoconf 62 | 63 | # xdebug 64 | RUN pecl install xdebug 65 | RUN docker-php-ext-enable xdebug 66 | 67 | # ampq 68 | RUN apt-get install -qq -y librabbitmq-dev 69 | RUN git clone --branch $EXT_AMQP_VERSION --depth 1 https://github.com/php-amqp/php-amqp.git /usr/src/php/ext/amqp 70 | RUN cd /usr/src/php/ext/amqp && git submodule update --init 71 | RUN docker-php-ext-install amqp 72 | 73 | 74 | RUN ls -al /usr/local/lib/php/extensions/ 75 | 76 | FROM jakzal/phpqa:debian 77 | 78 | # xdebug 79 | COPY --from=ext-multi /usr/local/etc/php/conf.d/docker-php-ext-multi.ini /usr/local/etc/php/conf.d/docker-php-ext-multi.ini 80 | COPY --from=ext-multi /usr/local/lib/php/extensions/no-debug-non-zts-20210902/xdebug.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/xdebug.so 81 | 82 | # ampq 83 | COPY --from=ext-amqp /usr/local/etc/php/conf.d/docker-php-ext-amqp.ini /usr/local/etc/php/conf.d/docker-php-ext-amqp.ini 84 | COPY --from=ext-amqp /usr/local/lib/php/extensions/no-debug-non-zts-20210902/amqp.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/amqp.so 85 | RUN apt-get update 86 | RUN apt-get install -qq -y librabbitmq-dev 87 | ``` 88 | 89 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at oss@zalas.pl. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MAKEFLAGS += --no-print-directory 2 | PHP_VERSIONS := 8.2 8.3 8.4 8.5 3 | PHP_VERSION ?= $(lastword $(sort $(PHP_VERSIONS))) 4 | COMPOSER_AUTHDIR ?= $(shell composer config --global home) 5 | ifneq ("", "$(COMPOSER_AUTHDIR)") 6 | COMPOSER_SECRET ?= --secret=id=composer.auth,src=$(COMPOSER_AUTHDIR)/auth.json 7 | endif 8 | 9 | default: build 10 | 11 | build: build-debian build-alpine 12 | .PHONY: build 13 | 14 | build-debian: BUILD_TAG ?= jakzal/phpqa:latest 15 | build-debian: 16 | docker buildx build --load -t $(BUILD_TAG) $(COMPOSER_SECRET) --build-arg PHP_VERSION=$(PHP_VERSION) --build-arg FLAVOUR=debian . 17 | .PHONY: build-debian 18 | 19 | build-alpine: BUILD_TAG ?= jakzal/phpqa:alpine 20 | build-alpine: 21 | docker buildx build --load -t $(BUILD_TAG) $(COMPOSER_SECRET) --build-arg PHP_VERSION=$(PHP_VERSION) --build-arg FLAVOUR=alpine . 22 | .PHONY: build-alpine 23 | 24 | clean: 25 | @rm devkit 26 | .PHONY: clean 27 | 28 | devkit: 29 | curl -s https://api.github.com/repos/jakzal/toolbox/releases/latest | grep "browser_download_url.*devkit.phar" | cut -d '"' -f 4 | xargs curl -Ls -o devkit && chmod +x devkit 30 | 31 | update-readme-tools: devkit 32 | ./devkit update:readme --readme README.md 33 | .PHONY: update-readme-tools 34 | 35 | readme-release: 36 | @cat README.md | grep 'jakzal/phpqa/blob/v' | sed -e 's/^[^`]*`\([^`\-]*\).*/\1/' | head -n 1 37 | .PHONY: readme-release 38 | 39 | next-patch-release: NEXT_PATCH_RELEASE ?= 40 | next-patch-release: 41 | ifeq ($(NEXT_PATCH_RELEASE),) 42 | @$(MAKE) readme-release | awk -F. -v OFS=. '{$$NF++;print}' 43 | else 44 | @echo $(NEXT_PATCH_RELEASE) 45 | endif 46 | .PHONY: next-patch-release 47 | 48 | release: NEXT_RELEASE ?= 49 | release: 50 | $(eval LATEST_RELEASE=$(shell $(MAKE) next-patch-release NEXT_PATCH_RELEASE=$(NEXT_RELEASE))) 51 | @$(MAKE) update-readme-release LATEST_RELEASE=$(LATEST_RELEASE) 52 | git add README.md 53 | git commit -m 'Release v$(LATEST_RELEASE)' 54 | git tag -a v$(LATEST_RELEASE) -m 'Tag v$(LATEST_RELEASE)' 55 | git push origin master 56 | hub release create -m '$(LATEST_RELEASE)' -m '' -m ':robot: Automagically created release.' v$(LATEST_RELEASE) 57 | .PHONY: release 58 | 59 | auto-release: 60 | @curl -s 'https://api.github.com/repos/jakzal/phpqa/actions/runs?branch=master' | \ 61 | jq '[.workflow_runs[] | select(.name == "Build") | {id, name, conclusion, html_url, created_at, updated_at} ] | first' | \ 62 | jq -r '.conclusion' | \ 63 | grep -q success && \ 64 | ( \ 65 | echo "The last build has succeeded. Making the release." && \ 66 | $(MAKE) release \ 67 | ) || \ 68 | ( \ 69 | echo "The last build has failed. Skipping the release." && \ 70 | exit 1 \ 71 | ) 72 | .PHONY: auto-release 73 | 74 | update-readme-release: LATEST_RELEASE ?= 0.0.0 75 | update-readme-release: 76 | $(eval LATEST_RELEASE_MINOR=$(shell echo $(LATEST_RELEASE) | cut -f1,2 -d.)) 77 | $(eval README_RELEASE=$(shell $(MAKE) readme-release)) 78 | $(eval README_RELEASE_MINOR=$(shell echo $(README_RELEASE) | cut -f1,2 -d.)) 79 | sed -i.bkp -e '/^*/s/$(README_RELEASE)/$(LATEST_RELEASE)/g' README.md 80 | sed -i.bkp -e '/^*/s/$(README_RELEASE_MINOR)/$(LATEST_RELEASE_MINOR)/g' README.md 81 | @rm README.md.bkp 82 | .PHONY: update-readme-release 83 | 84 | update-toolbox-version: 85 | $(eval LATEST_TOOLBOX_VERSION=$(shell curl -H'Authorization: token '$(GITHUB_TOKEN) -Ls 'https://api.github.com/repos/jakzal/toolbox/releases/latest' | jq -r .tag_name | cut -c 2-)) 86 | $(eval CURRENT_TOOLBOX_VERSION=$(shell cat Dockerfile | grep 'TOOLBOX_VERSION=' | head -n 1 | sed -e 's/.*"\(.*\)"/\1/')) 87 | @[ "$(LATEST_TOOLBOX_VERSION)" != "" ] || (echo "Failed to check the latest toolbox release" && exit 1) 88 | [ "$(CURRENT_TOOLBOX_VERSION)" = "$(LATEST_TOOLBOX_VERSION)" ] || ( \ 89 | sed -e 's/$(CURRENT_TOOLBOX_VERSION)/$(LATEST_TOOLBOX_VERSION)/g' -i'.bkp' Dockerfile \ 90 | && rm -f Dockerfile.bkp \ 91 | ) 92 | .PHONY: update-toolbox-version 93 | 94 | update-toolbox-pr: update-toolbox-version update-readme-tools 95 | $(eval VERSION_CHANGE=$(shell git diff --name-only Dockerfile | head -n 1 | xargs git diff | grep TOOLBOX_VERSION | sed -e 's/.*"\(.*\)"/\1/g' | xargs echo | sed -e 's/ / -> /')) 96 | [ "$(VERSION_CHANGE)" = "" ] || \ 97 | ( \ 98 | $(eval PR_MESSAGE=$(shell curl -H'Authorization: token '$(GITHUB_TOKEN) -Ls 'https://api.github.com/repos/jakzal/toolbox/releases/latest' | jq -r .body | awk 'BEGIN { RS="\n";} { gsub(/\r/, ""); gsub(/#/, "\\#"); gsub(/"/, "\\\\\\\""); print "-m \""$$0"\""}')) \ 99 | git checkout -b toolbox-update && \ 100 | git add Dockerfile README.md && \ 101 | git commit -m "Update toolbox $(VERSION_CHANGE)" -m "" $(PR_MESSAGE) && \ 102 | git push origin toolbox-update && \ 103 | hub pull-request -h toolbox-update -a jakzal -m 'Update toolbox $(VERSION_CHANGE)' -m '' -m ':robot: This pull request was automagically sent from a Github action.' -m '' $(PR_MESSAGE) \ 104 | ) 105 | .PHONY: update-toolbox-pr 106 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.4 2 | 3 | ARG PHP_VERSION=8.5 4 | ARG TOOLBOX_EXCLUDED_TAGS="exclude-php:${PHP_VERSION}" 5 | ARG TOOLBOX_VERSION="1.104.1" 6 | ARG FLAVOUR="alpine" 7 | 8 | 9 | # Debian PHP with dependencies needed for final image 10 | FROM php:${PHP_VERSION}-cli AS php-base-debian 11 | ARG DEBIAN_LIB_DEPS="zlib1g-dev libzip-dev libbz2-dev libicu-dev" 12 | ARG DEBIAN_TOOL_DEPS="git graphviz make unzip gpg dirmngr gpg-agent openssh-client" 13 | ARG TARGETARCH 14 | RUN rm /etc/apt/apt.conf.d/docker-clean # enables apt caching 15 | RUN --mount=type=cache,target=/var/cache/apt,target=/var/cache/apt,sharing=locked,id=apt-${TARGETARCH} \ 16 | --mount=type=cache,target=/var/lib/apt/lists,target=/var/lib/apt/lists,sharing=locked,id=apt-lists-${TARGETARCH} \ 17 | apt-get update \ 18 | && apt-get install -y --no-install-recommends ${DEBIAN_TOOL_DEPS} ${DEBIAN_LIB_DEPS} 19 | 20 | 21 | # Alpine PHP with dependencies needed for final image 22 | FROM php:${PHP_VERSION}-alpine as php-base-alpine 23 | ARG ALPINE_LIB_DEPS="zlib-dev libzip-dev bzip2-dev icu-dev" 24 | ARG ALPINE_TOOL_DEPS="git graphviz ttf-freefont make unzip gpgme gnupg-dirmngr openssh-client" 25 | ARG TARGETARCH 26 | RUN --mount=type=cache,target=/var/cache/apk,sharing=locked,id=apk-${TARGETARCH} \ 27 | apk add --no-cache ${ALPINE_TOOL_DEPS} ${ALPINE_LIB_DEPS} 28 | 29 | 30 | # PHP with dependencies needed for final image 31 | FROM php-base-${FLAVOUR} AS php-base 32 | 33 | 34 | # Debian PHP with dependencies needed for building the tools 35 | FROM php-base-debian AS builder-base-debian 36 | ARG TARGETARCH 37 | RUN --mount=type=cache,target=/var/cache/apt,target=/var/cache/apt,sharing=locked,id=apt-${TARGETARCH} \ 38 | --mount=type=cache,target=/var/lib/apt/lists,target=/var/lib/apt/lists,sharing=locked,id=apt-lists-${TARGETARCH} \ 39 | apt-get install -y --no-install-recommends ${PHPIZE_DEPS} 40 | 41 | 42 | # Alpine PHP with dependencies needed for building the tools 43 | FROM php-base-alpine AS builder-base-alpine 44 | ARG TARGETARCH 45 | RUN --mount=type=cache,target=/var/cache/apk,sharing=locked,id=apk-${TARGETARCH} \ 46 | apk add --no-cache ${PHPIZE_DEPS} 47 | 48 | 49 | # PHP with dependencies needed for building the tools 50 | FROM builder-base-${FLAVOUR} as builder-base 51 | RUN docker-php-source extract 52 | 53 | 54 | # Stage containing the AST extension source 55 | FROM --platform=${BUILDPLATFORM} alpine AS ast-downloader 56 | ARG TARGETARCH 57 | WORKDIR / 58 | RUN --mount=type=cache,target=/var/cache/apk,sharing=locked,id=apk-${TARGETARCH} \ 59 | apk add --no-cache git 60 | RUN git clone https://github.com/nikic/php-ast.git 61 | 62 | 63 | # Stage that builds the AST extension from downloaded src 64 | FROM builder-base AS ast-builder 65 | WORKDIR /build 66 | COPY --from=ast-downloader /php-ast . 67 | RUN phpize \ 68 | && ./configure \ 69 | && make \ 70 | && make install 71 | RUN docker-php-ext-enable ast 72 | 73 | 74 | # Stage that builds the pcov extension from PECL 75 | FROM builder-base AS pcov-builder 76 | RUN pecl install pcov && docker-php-ext-enable pcov 77 | 78 | 79 | # Stage that builds bcmath 80 | FROM builder-base AS bcmath-builder 81 | RUN docker-php-ext-install bcmath 82 | 83 | 84 | # Stage that builds intl 85 | FROM builder-base AS intl-builder 86 | RUN docker-php-ext-install intl 87 | 88 | 89 | # Stage that builds zip 90 | FROM builder-base AS zip-builder 91 | RUN docker-php-ext-install zip 92 | 93 | 94 | # Stage that builds pcntl 95 | FROM builder-base AS pcntl-builder 96 | RUN docker-php-ext-install pcntl 97 | 98 | 99 | # Stage that builds bz2 100 | FROM builder-base AS bz2-builder 101 | RUN docker-php-ext-install bz2 102 | 103 | 104 | # Stage with PHP extensions, all validated 105 | FROM php-base AS all-extensions 106 | 107 | COPY --link --from=ast-builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions 108 | COPY --link --from=ast-builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d 109 | COPY --link --from=pcov-builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions 110 | COPY --link --from=pcov-builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d 111 | COPY --link --from=bcmath-builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions 112 | COPY --link --from=bcmath-builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d 113 | COPY --link --from=intl-builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions 114 | COPY --link --from=intl-builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d 115 | COPY --link --from=zip-builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions 116 | COPY --link --from=zip-builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d 117 | COPY --link --from=pcntl-builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions 118 | COPY --link --from=pcntl-builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d 119 | COPY --link --from=bz2-builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions 120 | COPY --link --from=bz2-builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d 121 | 122 | # Validate the extension configuration 123 | RUN php --re ast 124 | RUN php --re pcov 125 | RUN php --re bcmath 126 | RUN php --re intl 127 | RUN php --re zip 128 | RUN php --re pcntl 129 | RUN php --re bz2 130 | 131 | 132 | # Stage containing the downloaded toolbox PHAR 133 | FROM --platform=${BUILDPLATFORM} alpine AS toolbox-downloader 134 | WORKDIR / 135 | ARG TOOLBOX_VERSION 136 | RUN wget https://github.com/jakzal/toolbox/releases/download/v${TOOLBOX_VERSION}/toolbox.phar 137 | 138 | 139 | # PHP with all extensions needed, correctly configured 140 | FROM php-base as php-configured 141 | 142 | # Install extensions + extension config 143 | COPY --link --from=all-extensions /usr/local/lib/php/extensions /usr/local/lib/php/extensions 144 | COPY --link --from=all-extensions /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d 145 | 146 | # Base php.ini 147 | COPY --link <> $GITHUB_OUTPUT 70 | echo "tags=${TAGS}" >> $GITHUB_OUTPUT 71 | echo "created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT 72 | echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT 73 | echo "push=${{ (startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master') && github.repository_owner == 'jakzal' }}" >> $GITHUB_OUTPUT 74 | env: 75 | PHP_VERSION: ${{ matrix.php }} 76 | IMAGE_FLAVOUR: ${{ matrix.flavour }} 77 | 78 | - name: Set up QEMU 79 | uses: docker/setup-qemu-action@v3 80 | 81 | - name: Set up Docker Buildx 82 | uses: docker/setup-buildx-action@v3 83 | 84 | - name: Login to DockerHub 85 | if: steps.version.outputs.push == 'true' 86 | uses: docker/login-action@v3 87 | with: 88 | username: jakzal 89 | password: ${{ secrets.DOCKER_HUB_TOKEN }} 90 | 91 | - name: Build 92 | uses: docker/build-push-action@v5 93 | with: 94 | platforms: linux/amd64,linux/arm64 95 | tags: ${{ steps.version.outputs.tags }} 96 | build-args: | 97 | PHP_VERSION=${{ matrix.php }} 98 | INSTALLATION_DATE=${{ steps.version.outputs.date }} 99 | FLAVOUR=${{ matrix.flavour }} 100 | secrets: | 101 | "composer.auth={""github-oauth"":{""github.com"":""${{ secrets.GITHUB_TOKEN }}""} }" 102 | "phive.auth=" 103 | labels: | 104 | org.opencontainers.image.source=${{ github.event.repository.html_url }} 105 | org.opencontainers.image.created=${{ steps.version.outputs.created }} 106 | org.opencontainers.image.revision=${{ github.sha }} 107 | cache-from: type=gha,scope=${{ github.workflow }}-${{ matrix.php }}-${{ matrix.flavour }} 108 | cache-to: type=gha,scope=${{ github.workflow }}-${{ matrix.php }}-${{ matrix.flavour }},mode=max 109 | 110 | - name: Load 111 | uses: docker/build-push-action@v5 112 | with: 113 | load: true 114 | platforms: linux/amd64 115 | tags: ${{ steps.version.outputs.tags }} 116 | build-args: | 117 | PHP_VERSION=${{ matrix.php }} 118 | INSTALLATION_DATE=${{ steps.version.outputs.date }} 119 | FLAVOUR=${{ matrix.flavour }} 120 | cache-from: type=gha,scope=${{ github.workflow }}-${{ matrix.php }}-${{ matrix.flavour }} 121 | 122 | - name: Test 123 | run: | 124 | echo "::group::Images" 125 | docker images 126 | echo "::endgroup::" 127 | 128 | echo "::group::$BUILD_TAG" 129 | docker inspect $BUILD_TAG 130 | echo "::endgroup::" 131 | 132 | echo "::group::PHP Version $PHP_VERSION" 133 | docker run --rm --pull never $BUILD_TAG php -v | grep 'PHP '$PHP_VERSION 134 | echo "::endgroup::" 135 | 136 | echo "::group::Tests" 137 | docker run --rm --pull never $BUILD_TAG php /tools/toolbox test 138 | echo "::endgroup::" 139 | 140 | echo "::group::Tools" 141 | docker run --rm --pull never $BUILD_TAG 142 | echo "::endgroup::" 143 | env: 144 | PHP_VERSION: ${{ matrix.php }} 145 | BUILD_TAG: jakzal/phpqa:php${{ matrix.php }}-${{ matrix.flavour }} 146 | 147 | - name: Push 148 | uses: docker/build-push-action@v5 149 | if: steps.version.outputs.push == 'true' 150 | with: 151 | push: ${{ steps.version.outputs.push }} 152 | platforms: linux/amd64,linux/arm64 153 | tags: ${{ steps.version.outputs.tags }} 154 | build-args: | 155 | PHP_VERSION=${{ matrix.php }} 156 | INSTALLATION_DATE=${{ steps.version.outputs.date }} 157 | FLAVOUR=${{ matrix.flavour }} 158 | labels: | 159 | org.opencontainers.image.source=${{ github.event.repository.html_url }} 160 | org.opencontainers.image.created=${{ steps.version.outputs.created }} 161 | org.opencontainers.image.revision=${{ github.sha }} 162 | cache-from: type=gha,scope=${{ github.workflow }}-${{ matrix.php }}-${{ matrix.flavour }} 163 | 164 | verify: 165 | runs-on: ubuntu-latest 166 | name: Verify 167 | needs: build 168 | if: needs.build.outputs.push == 'true' 169 | strategy: 170 | fail-fast: false 171 | matrix: 172 | flavour: [debian, alpine] 173 | php: ['8.2', '8.3', '8.4', '8.5'] 174 | platform: ['linux/arm64','linux/amd64'] 175 | include: 176 | - platform: 'linux/arm64' 177 | needs-qemu: true 178 | steps: 179 | 180 | - name: Set up QEMU 181 | if: ${{ matrix.needs-qemu == true }} 182 | uses: docker/setup-qemu-action@v3 183 | 184 | - name: Test if pushed 185 | run: | 186 | echo "::group::Tests" 187 | docker run --rm --platform=${{ matrix.platform }} $BUILD_TAG php /tools/toolbox test 188 | echo "::endgroup::" 189 | env: 190 | BUILD_TAG: jakzal/phpqa:php${{ matrix.php }}-${{ matrix.flavour }} 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Static Analysis Tools for PHP 2 | 3 | Docker image providing static analysis tools for PHP. 4 | The list of available tools and the installer are actually managed in the [`jakzal/toolbox` repository](https://github.com/jakzal/toolbox). 5 | 6 | [![Build Status](https://github.com/jakzal/phpqa/actions/workflows/build.yml/badge.svg)](https://github.com/jakzal/phpqa/actions) [![Docker Pulls](https://img.shields.io/docker/pulls/jakzal/phpqa)](https://hub.docker.com/r/jakzal/phpqa/) 7 | 8 | ## Supported platforms and PHP versions 9 | 10 | Docker hub repository: https://hub.docker.com/r/jakzal/phpqa/ 11 | 12 | ### Debian 13 | 14 | * `latest`, `debian` ([Dockerfile](https://github.com/jakzal/phpqa/blob/master/Dockerfile)) 15 | * `1.119.0`, `1.119`, `1.119.0-debian`, `1.119-debian` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.119.0/Dockerfile)) 16 | * `1.119.0-php8.2`, `1.119-php8.2`, `php8.2-debian`, `php8.2` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.119.0/Dockerfile)) 17 | * `1.119.0-php8.3`, `1.119-php8.3`, `php8.3-debian`, `php8.3` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.119.0/Dockerfile)) 18 | * `1.119.0-php8.4`, `1.119-php8.4`, `php8.4-debian`, `php8.4` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.119.0/Dockerfile)) 19 | * `1.119.0-php8.5`, `1.119-php8.5`, `php8.5-debian`, `php8.5` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.119.0/Dockerfile)) 20 | 21 | ### Alpine 22 | 23 | * `alpine` ([Dockerfile](https://github.com/jakzal/phpqa/blob/master/Dockerfile)) 24 | * `1.119.0-alpine`, `1.119-alpine`, ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.119.0/Dockerfile)) 25 | * `1.119.0-php8.2-alpine`, `1.119-php8.2-alpine`, `php8.2-alpine` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.119.0/Dockerfile)) 26 | * `1.119.0-php8.3-alpine`, `1.119-php8.3-alpine`, `php8.3-alpine` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.119.0/Dockerfile)) 27 | * `1.119.0-php8.4-alpine`, `1.119-php8.4-alpine`, `php8.4-alpine` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.119.0/Dockerfile)) 28 | * `1.119.0-php8.5-alpine`, `1.119-php8.5-alpine`, `php8.5-alpine` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.119.0/Dockerfile)) 29 | 30 | 31 | Updated daily: `latest`, `debian`, `alpine`, `php8.5`, `php8.5-alpine`, etc. 32 | Updated on patch version change: `1.61`, `1.61-php8.5`, `1.61-php8.5-alpine`, etc. 33 | Never updated: `1.61.0`, `1.61.0-php8.5`, `1.61.0-php8.5-alpine`, etc. 34 | 35 | ### Legacy 36 | 37 | These are the latest tags for PHP versions that are no longer supported: 38 | 39 | - `1.105.0-php8.1`, `1.105-php8.1`, `php8.1-debian`, `php8.1` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.105.0/Dockerfile)) 40 | - `1.105.0-php8.1-alpine`, `1.105-php8.1-alpine`, `php8.1-alpine` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.105.0/Dockerfile)) 41 | - `1.92.7-php8.0`, `1.93-php8.0`, `php8.0-debian`, `php8.0` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.92.7/Dockerfile)) 42 | - `1.92.7-php8.0-alpine`, `1.93-php8.0-alpine`, `php8.0-alpine` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.92.7/Dockerfile)) 43 | - `1.80.0-php7.4`, `1.80-php7.4`, `php7.4-debian`, `php7.4` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.80.0/Dockerfile)) 44 | - `1.80.0-php7.4-alpine`, `1.80-php7.4-alpine`, `php7.4-alpine` ([Dockerfile](https://github.com/jakzal/phpqa/blob/v1.80.0/Dockerfile)) 45 | - `1.61.2-php7.3`, `1.61-php7.3`, `php7.3-debian`, `php7.3` ([debian/Dockerfile](https://github.com/jakzal/phpqa/blob/v1.61.2/debian/Dockerfile)) 46 | - `1.61.2-php7.3-alpine`, `1.61-php7.3-alpine`, `php7.3-alpine` ([alpine/Dockerfile](https://github.com/jakzal/phpqa/blob/v1.61.2/alpine/Dockerfile)) 47 | - `1.44.0-php7.2`, `1.44-php7.2`, `php7.2` ([7.2/debian/Dockerfile](https://github.com/jakzal/phpqa/blob/v1.44.0/7.2/debian/Dockerfile)) 48 | - `1.44.0-php7.2-alpine`, `1.44-php7.2-alpine`, `php7.2-alpine` ([7.2/alpine/Dockerfile](https://github.com/jakzal/phpqa/blob/v1.44.0/7.2/alpine/Dockerfile)) 49 | - `1.26.0-php7.1`, `1.26-php7.1`, `php7.1` ([7.1/debian/Dockerfile](https://github.com/jakzal/phpqa/blob/v1.26.0/7.1/debian/Dockerfile)) 50 | - `1.26.0-php7.1-alpine`, `1.26-php7.1-alpine`, `php7.1-alpine` ([7.1/alpine/Dockerfile](https://github.com/jakzal/phpqa/blob/v1.26.0/7.1/alpine/Dockerfile)) 51 | 52 | ## Available tools 53 | 54 | | Name | Description | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 | 55 | | :--- | :---------- | :------ | :------ | :------ | :------ | 56 | | behat | [Helps to test business expectations](http://behat.org/) | ✅ | ✅ | ✅ | ✅ | 57 | | box | [Fast, zero config application bundler with PHARs](https://github.com/humbug/box) | ✅ | ✅ | ✅ | ✅ | 58 | | churn | [Discovers good candidates for refactoring](https://github.com/bmitch/churn-php) | ✅ | ✅ | ✅ | ✅ | 59 | | codeception | [Codeception is a BDD-styled PHP testing framework](https://codeception.com/) | ✅ | ✅ | ✅ | ❌ | 60 | | composer | [Dependency Manager for PHP](https://getcomposer.org/) | ✅ | ✅ | ✅ | ✅ | 61 | | composer-bin-plugin | [Composer plugin to install bin vendors in isolated locations](https://github.com/bamarni/composer-bin-plugin) | ✅ | ✅ | ✅ | ✅ | 62 | | composer-lock-diff | [Composer plugin to check what has changed after a composer update](https://github.com/davidrjonas/composer-lock-diff) | ✅ | ✅ | ✅ | ✅ | 63 | | composer-normalize | [Composer plugin to normalize composer.json files](https://github.com/ergebnis/composer-normalize) | ✅ | ✅ | ✅ | ✅ | 64 | | composer-require-checker | [Verify that no unknown symbols are used in the sources of a package.](https://github.com/maglnet/ComposerRequireChecker) | ❌ | ✅ | ✅ | ✅ | 65 | | composer-require-checker-3 | [Verify that no unknown symbols are used in the sources of a package.](https://github.com/maglnet/ComposerRequireChecker) | ✅ | ✅ | ✅ | ✅ | 66 | | composer-unused | [Show unused packages by scanning your code](https://github.com/icanhazstring/composer-unused) | ✅ | ✅ | ✅ | ✅ | 67 | | cyclonedx-php-composer | [Composer plugin to create Software-Bill-of-Materials (SBOM) in CycloneDX format](https://github.com/CycloneDX/cyclonedx-php-composer) | ✅ | ✅ | ✅ | ✅ | 68 | | dephpend | [Detect flaws in your architecture](https://dephpend.com/) | ✅ | ✅ | ✅ | ✅ | 69 | | deprecation-detector | [Finds usages of deprecated code](https://github.com/sensiolabs-de/deprecation-detector) | ✅ | ✅ | ✅ | ✅ | 70 | | deptrac | [Enforces dependency rules between software layers](https://github.com/deptrac/deptrac) | ✅ | ✅ | ✅ | ✅ | 71 | | diffFilter | [Applies QA tools to run on a single pull request](https://github.com/exussum12/coverageChecker) | ✅ | ✅ | ✅ | ✅ | 72 | | ecs | [Sets up and runs coding standard checks](https://github.com/Symplify/EasyCodingStandard) | ✅ | ✅ | ✅ | ✅ | 73 | | gherkin-lint-php | [Gherkin linter for PHP](https://github.com/dantleech/gherkin-lint-php) | ✅ | ✅ | ✅ | ✅ | 74 | | infection | [AST based PHP Mutation Testing Framework](https://infection.github.io/) | ✅ | ✅ | ✅ | ✅ | 75 | | jack | [Helps to upgrade outdated Composer dependencies incrementally](https://github.com/rectorphp/jack) | ✅ | ✅ | ✅ | ✅ | 76 | | kahlan | [Kahlan is a full-featured Unit & BDD test framework a la RSpec/JSpec](https://kahlan.github.io/docs/) | ✅ | ✅ | ✅ | ✅ | 77 | | larastan | [PHPStan extension for Laravel](https://github.com/nunomaduro/larastan) | ✅ | ✅ | ✅ | ✅ | 78 | | lines | [CLI tool for quick metrics of PHP projects](https://github.com/tomasVotruba/lines) | ✅ | ✅ | ✅ | ✅ | 79 | | local-php-security-checker | [Checks composer dependencies for known security vulnerabilities](https://github.com/fabpot/local-php-security-checker) | ✅ | ✅ | ✅ | ✅ | 80 | | parallel-lint | [Checks PHP file syntax](https://github.com/php-parallel-lint/PHP-Parallel-Lint) | ✅ | ✅ | ✅ | ✅ | 81 | | paratest | [Parallel testing for PHPUnit](https://github.com/paratestphp/paratest) | ✅ | ✅ | ✅ | ✅ | 82 | | pdepend | [Static Analysis Tool](https://pdepend.org/) | ✅ | ✅ | ✅ | ✅ | 83 | | phan | [Static Analysis Tool](https://github.com/phan/phan) | ✅ | ✅ | ✅ | ✅ | 84 | | phive | [PHAR Installation and Verification Environment](https://phar.io/) | ✅ | ✅ | ✅ | ✅ | 85 | | php-cs-fixer | [PHP Coding Standards Fixer](http://cs.symfony.com/) | ✅ | ✅ | ✅ | ✅ | 86 | | php-fuzzer | [A fuzzer for PHP, which can be used to find bugs in libraries by feeding them 'random' inputs](https://github.com/nikic/PHP-Fuzzer) | ✅ | ✅ | ✅ | ✅ | 87 | | php-semver-checker | [Suggests a next version according to semantic versioning](https://github.com/tomzx/php-semver-checker) | ✅ | ✅ | ✅ | ✅ | 88 | | phpa | [Checks for weak assumptions](https://github.com/rskuipers/php-assumptions) | ✅ | ✅ | ✅ | ✅ | 89 | | phparkitect | [Helps to put architectural constraints in a PHP code base](https://github.com/phparkitect/arkitect) | ✅ | ✅ | ✅ | ✅ | 90 | | phpat | [Easy to use architecture testing tool](https://github.com/carlosas/phpat) | ✅ | ✅ | ✅ | ✅ | 91 | | phpbench | [PHP Benchmarking framework](https://github.com/phpbench/phpbench) | ✅ | ✅ | ✅ | ✅ | 92 | | phpca | [Finds usage of non-built-in extensions](https://github.com/wapmorgan/PhpCodeAnalyzer) | ✅ | ✅ | ✅ | ✅ | 93 | | phpcb | [PHP Code Browser](https://github.com/mayflower/PHP_CodeBrowser) | ✅ | ✅ | ✅ | ✅ | 94 | | phpcbf | [Automatically corrects coding standard violations](https://github.com/PHPCSStandards/PHP_CodeSniffer) | ✅ | ✅ | ✅ | ✅ | 95 | | phpcodesniffer-composer-install | [Easy installation of PHP_CodeSniffer coding standards (rulesets).](https://github.com/PHPCSStandards/composer-installer) | ✅ | ✅ | ✅ | ✅ | 96 | | phpcov | [a command-line frontend for the PHP_CodeCoverage library](https://github.com/sebastianbergmann/phpcov) | ❌ | ✅ | ✅ | ✅ | 97 | | phpcpd | [Copy/Paste Detector](https://github.com/sebastianbergmann/phpcpd) | ✅ | ✅ | ✅ | ✅ | 98 | | phpcs | [Detects coding standard violations](https://github.com/PHPCSStandards/PHP_CodeSniffer) | ✅ | ✅ | ✅ | ✅ | 99 | | phpcs-security-audit | [Finds vulnerabilities and weaknesses related to security in PHP code](https://github.com/FloeDesignTechnologies/phpcs-security-audit) | ✅ | ✅ | ✅ | ✅ | 100 | | phpdd | [Finds usage of deprecated features](http://wapmorgan.github.io/PhpDeprecationDetector) | ✅ | ✅ | ✅ | ✅ | 101 | | phpDocumentor | [Documentation generator](https://www.phpdoc.org/) | ✅ | ✅ | ✅ | ✅ | 102 | | phpinsights | [Analyses code quality, style, architecture and complexity](https://phpinsights.com/) | ✅ | ✅ | ✅ | ✅ | 103 | | phplint | [Lints php files in parallel](https://github.com/overtrue/phplint) | ✅ | ✅ | ✅ | ✅ | 104 | | phploc | [A tool for quickly measuring the size of a PHP project](https://github.com/sebastianbergmann/phploc) | ✅ | ✅ | ✅ | ✅ | 105 | | phpmd | [A tool for finding problems in PHP code](https://phpmd.org/) | ✅ | ✅ | ✅ | ✅ | 106 | | phpmetrics | [Static Analysis Tool](http://www.phpmetrics.org/) | ✅ | ✅ | ✅ | ✅ | 107 | | phpmnd | [Helps to detect magic numbers](https://github.com/povils/phpmnd) | ✅ | ✅ | ✅ | ✅ | 108 | | phpspec | [SpecBDD Framework](http://www.phpspec.net/) | ✅ | ✅ | ✅ | ❌ | 109 | | phpstan | [Static Analysis Tool](https://github.com/phpstan/phpstan) | ✅ | ✅ | ✅ | ✅ | 110 | | phpstan-banned-code | [PHPStan rules for detecting calls to specific functions you don't want in your project](https://github.com/ekino/phpstan-banned-code) | ✅ | ✅ | ✅ | ✅ | 111 | | phpstan-beberlei-assert | [PHPStan extension for beberlei/assert](https://github.com/phpstan/phpstan-beberlei-assert) | ✅ | ✅ | ✅ | ✅ | 112 | | phpstan-deprecation-rules | [PHPStan rules for detecting deprecated code](https://github.com/phpstan/phpstan-deprecation-rules) | ✅ | ✅ | ✅ | ✅ | 113 | | phpstan-doctrine | [Doctrine extensions for PHPStan](https://github.com/phpstan/phpstan-doctrine) | ✅ | ✅ | ✅ | ✅ | 114 | | phpstan-ergebnis-rules | [Additional rules for PHPstan](https://github.com/ergebnis/phpstan-rules) | ✅ | ✅ | ✅ | ✅ | 115 | | phpstan-larastan | [Separate installation of phpstan for larastan](https://github.com/phpstan/phpstan) | ✅ | ✅ | ✅ | ✅ | 116 | | phpstan-phpunit | [PHPUnit extensions and rules for PHPStan](https://github.com/phpstan/phpstan-phpunit) | ✅ | ✅ | ✅ | ✅ | 117 | | phpstan-strict-rules | [Extra strict and opinionated rules for PHPStan](https://github.com/phpstan/phpstan-strict-rules) | ✅ | ✅ | ✅ | ✅ | 118 | | phpstan-symfony | [Symfony extension for PHPStan](https://github.com/phpstan/phpstan-symfony) | ✅ | ✅ | ✅ | ✅ | 119 | | phpstan-webmozart-assert | [PHPStan extension for webmozart/assert](https://github.com/phpstan/phpstan-webmozart-assert) | ✅ | ✅ | ✅ | ✅ | 120 | | phpunit | [The PHP testing framework](https://phpunit.de/) | ❌ | ✅ | ✅ | ✅ | 121 | | phpunit-10 | [The PHP testing framework (10.x version)](https://phpunit.de/) | ✅ | ✅ | ✅ | ✅ | 122 | | phpunit-11 | [The PHP testing framework (11.x version)](https://phpunit.de/) | ✅ | ✅ | ✅ | ✅ | 123 | | phpunit-8 | [The PHP testing framework (8.x version)](https://phpunit.de/) | ✅ | ✅ | ✅ | ✅ | 124 | | phpunit-9 | [The PHP testing framework (9.x version)](https://phpunit.de/) | ✅ | ✅ | ✅ | ✅ | 125 | | pint | [Opinionated PHP code style fixer for Laravel](https://github.com/laravel/pint) | ✅ | ✅ | ✅ | ✅ | 126 | | psalm | [Finds errors in PHP applications](https://psalm.dev/) | ✅ | ✅ | ✅ | ✅ | 127 | | psalm-plugin-doctrine | [Stubs to let Psalm understand Doctrine better](https://github.com/weirdan/doctrine-psalm-plugin) | ✅ | ✅ | ✅ | ✅ | 128 | | psalm-plugin-phpunit | [Psalm plugin for PHPUnit](https://github.com/psalm/psalm-plugin-phpunit) | ✅ | ✅ | ✅ | ✅ | 129 | | psalm-plugin-symfony | [Psalm Plugin for Symfony](https://github.com/psalm/psalm-plugin-symfony) | ✅ | ✅ | ✅ | ✅ | 130 | | psecio-parse | [Scans code for potential security-related issues](https://github.com/psecio/parse) | ✅ | ✅ | ✅ | ✅ | 131 | | rector | [Tool for instant code upgrades and refactoring](https://github.com/rectorphp/rector) | ✅ | ✅ | ✅ | ✅ | 132 | | roave-backward-compatibility-check | [Tool to compare two revisions of a class API to check for BC breaks](https://github.com/Roave/BackwardCompatibilityCheck) | ✅ | ✅ | ✅ | ✅ | 133 | | simple-phpunit | [Provides utilities to report legacy tests and usage of deprecated code](https://symfony.com/doc/current/components/phpunit_bridge.html) | ✅ | ✅ | ✅ | ✅ | 134 | | twig-cs-fixer | [Automatically corrects twig files following the official coding standard rules](https://github.com/VincentLanglet/Twig-CS-Fixer) | ✅ | ✅ | ✅ | ✅ | 135 | | twig-lint | [Standalone cli twig 1.X linter](https://github.com/asm89/twig-lint) | ✅ | ✅ | ✅ | ✅ | 136 | | twig-linter | [Standalone cli twig 3.X linter](https://github.com/sserbin/twig-linter) | ✅ | ✅ | ✅ | ✅ | 137 | | twigcs | [The missing checkstyle for twig!](https://github.com/friendsoftwig/twigcs) | ✅ | ✅ | ✅ | ❌ | 138 | | yaml-lint | [Compact command line utility for checking YAML file syntax](https://github.com/j13k/yaml-lint) | ✅ | ✅ | ✅ | ✅ | 139 | 140 | ## More tools 141 | 142 | Some tools are not included in the docker image, to use them refer to their documentation: 143 | 144 | * exakat - [a real time PHP static analyser](https://www.exakat.io) 145 | 146 | ### Removed tools 147 | 148 | | Name | Summary | 149 | | :--- | :------ | 150 | | analyze | [Visualizes metrics and source code](https://github.com/Qafoo/QualityAnalyzer) | 151 | | box-legacy | [Legacy version of box](https://box-project.github.io/box2/) | 152 | | design-pattern | [Detects design patterns](https://github.com/Halleck45/DesignPatternDetector) | 153 | | parallel-lint | [Checks PHP file syntax](https://github.com/JakubOnderka/PHP-Parallel-Lint) | 154 | | pest | [The elegant PHP Testing Framework](https://github.com/pestphp/pest) | 155 | | php-coupling-detector | [Detects code coupling issues](https://akeneo.github.io/php-coupling-detector/) | 156 | | php-formatter | [Custom coding standards fixer](https://github.com/mmoreram/php-formatter) | 157 | | phpcf | [Finds usage of deprecated features](http://wapmorgan.github.io/PhpCodeFixer/) | 158 | | phpda | [Generates dependency graphs](https://mamuz.github.io/PhpDependencyAnalysis/) | 159 | | phpdoc-to-typehint | [Automatically adds type hints and return types based on PHPDocs](https://github.com/dunglas/phpdoc-to-typehint) | 160 | | phpstan-exception-rules | [PHPStan rules for checked and unchecked exceptions](https://github.com/pepakriz/phpstan-exception-rules) | 161 | | phpstan-localheinz-rules | [Additional rules for PHPstan](https://github.com/localheinz/phpstan-rules) | 162 | | security-checker | [Checks composer dependencies for known security vulnerabilities](https://github.com/sensiolabs/security-checker) | 163 | | testability | [Analyses and reports testability issues of a php codebase](https://github.com/edsonmedina/php_testability) | 164 | 165 | ## Running tools 166 | 167 | Pull the image: 168 | 169 | ```bash 170 | docker pull jakzal/phpqa 171 | ``` 172 | 173 | The default command will list available tools: 174 | 175 | ```bash 176 | docker run -it --rm jakzal/phpqa 177 | ``` 178 | 179 | To run the selected tool inside the container, you'll need to mount 180 | the project directory on the container with `-v "$(pwd):/project"`. 181 | Some tools like to write to the `/tmp` directory (like PHPStan, or Behat in some cases), therefore it's often useful 182 | to share it between docker runs, i.e. with `-v "$(pwd)/tmp-phpqa:/tmp"`. 183 | If you want to be able to interrupt the selected tool if it takes too much time to complete, you can use the 184 | `--init` option. Please refer to the [docker run documentation](https://docs.docker.com/engine/reference/commandline/run/) for more information. 185 | 186 | ```bash 187 | docker run --init -it --rm -v "$(pwd):/project" -v "$(pwd)/tmp-phpqa:/tmp" -w /project jakzal/phpqa phpstan analyse src 188 | ``` 189 | 190 | You might want to tweak this command to your needs and create an alias for convenience: 191 | 192 | ```bash 193 | alias phpqa='docker run --init -it --rm -v "$(pwd):/project" -v "$(pwd)/tmp-phpqa:/tmp" -w /project jakzal/phpqa:alpine' 194 | ``` 195 | 196 | Add it to your `~/.bashrc` so it's defined every time you start a new terminal session. 197 | 198 | Now the command becomes a lot simpler: 199 | 200 | ```bash 201 | phpqa phpstan analyse src 202 | ``` 203 | 204 | ## Building the image 205 | 206 | ```bash 207 | git clone https://github.com/jakzal/phpqa.git 208 | cd phpqa 209 | make build-debian 210 | ``` 211 | 212 | To build the alpine version: 213 | 214 | ``` 215 | make build-alpine 216 | ``` 217 | 218 | ## Cookbook 219 | 220 | Please check out the [cookbook](docs/cookbook/README.md) for further tips & tricks. 221 | 222 | ## Contributing 223 | 224 | Please read the [Contributing guide](CONTRIBUTING.md) to learn about contributing to this project. 225 | Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). 226 | By participating in this project you agree to abide by its terms. 227 | --------------------------------------------------------------------------------