├── .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 | [](https://github.com/jakzal/phpqa/actions) [](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 |
--------------------------------------------------------------------------------