Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/qa.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
name: "QA"

on:
workflow_call:
inputs:
php-versions:
description: "JSON array of PHP versions to run the matrix against."
type: string
required: false
default: '["8.2", "8.3", "8.4", "8.5"]'
run-integration:
description: "Run the integration test suite in addition to the unit suite."
type: boolean
required: false
default: false
composer-options:
description: "Extra flags passed to composer install."
type: string
required: false
default: ""

jobs:
qa:
name: "PHP ${{ matrix.php }}"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ${{ fromJSON(inputs.php-versions) }}
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Set up PHP and Mago
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none
tools: mago

- name: Install dependencies
run: composer install --no-interaction --no-progress ${{ inputs.composer-options }}

# Overrides php-version from the consumer's mago.toml for each matrix leg
# without mutating the committed config file.
- name: Pin Mago PHP version
run: echo "MAGO_PHP_VERSION=${{ matrix.php }}" >> "$GITHUB_ENV"

- name: Check coding standards
run: composer cs-check

- name: Static analysis
if: success() || failure()
run: composer static-analysis

- name: Unit tests
if: success() || failure()
run: composer test

- name: Integration tests
if: inputs.run-integration && (success() || failure())
run: composer test-integration
4 changes: 4 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
/vendor/
composer.lock
.DS_Store
.idea/
28 changes: 28 additions & 0 deletions LICENSE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
BSD 3-Clause License

Copyright (c) 2026, php-db

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3 changes: 1 addition & 2 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -92,14 +92,13 @@ name: CI

on:
push:
branches: ["main"]
pull_request:

jobs:
qa:
uses: php-db/phpdb-qa-tools/.github/workflows/qa.yml@main
with:
php-versions: '["8.2", "8.3", "8.4"]'
php-versions: '["8.2", "8.3", "8.4", "8.5"]'
run-integration: false
```

Expand Down
27 changes: 27 additions & 0 deletions composer.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
{
"name": "php-db/phpdb-qa-tools",
"description": "Shared QA toolchain for php-db components: Mago formatting, linting and static analysis, plus the PHPUnit baseline and CI workflow.",
"license": "BSD-3-Clause",
"type": "library",
"keywords": [
"phpdb",
"qa",
"coding-standards",
"mago",
"linter",
"formatter",
"static-analysis"
],
"homepage": "https://github.com/php-db/phpdb-qa-tools",
"support": {
"issues": "https://github.com/php-db/phpdb-qa-tools/issues",
"source": "https://github.com/php-db/phpdb-qa-tools",
"forum": "https://github.com/php-db/phpdb-qa-tools/discussions"
},
"require": {
"php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
},
"suggest": {
"phpunit/phpunit": "To run the shared test configuration (^11.5 || ^12.0)"
}
}
76 changes: 76 additions & 0 deletions docs/migration.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
# Migrating from laminas-coding-standard

Repository-by-repository, in dependency order, using `phpdb-validator` as the template.

## Prerequisites

Install the Mago binary once per machine (see the [README](../README.md#prerequisite-install-mago)).

## Steps

### 1. Swap dev dependencies

```sh
composer remove --dev laminas/laminas-coding-standard
# also remove psalm/psalm, vimeo/psalm, or phpstan/phpstan if present
composer require --dev php-db/phpdb-qa-tools
```

### 2. Remove phpcs artifacts

```sh
rm -f phpcs.xml phpcs.xml.dist .phpcs-cache
```

Also remove any `psalm.xml` / `phpstan.neon` and their baselines.

### 3. Add the minimal mago.toml

```toml
extends = "vendor/php-db/phpdb-qa-tools/mago.toml"
php-version = "8.2.0"

[source]
paths = ["src", "test"]
includes = ["vendor"]
```

Append repository-specific `[analyzer]` settings (e.g. `class-initializers`) as needed.

### 4. Adopt the PHPUnit baseline

```sh
cp vendor/php-db/phpdb-qa-tools/templates/phpunit.xml.dist .
```

Adjust test-suite paths only if the repository cannot follow the standard
`test/unit` / `test/integration` layout.

### 5. Update composer scripts

Adopt the standard `check` / `cs-check` / `cs-fix` / `static-analysis` / `test`
scripts (see the README).

### 6. Reformat in a single isolated commit

```sh
composer cs-fix
git add -A
git commit -m "Apply mago formatting"
git rev-parse HEAD >> .git-blame-ignore-revs
git add .git-blame-ignore-revs
git commit -m "Ignore mago reformat in git blame"
```

Keeping the mechanical reformat isolated (and recorded in `.git-blame-ignore-revs`)
keeps `git blame` useful.

### 7. Triage remaining findings

Fix or explicitly suppress remaining lint/analyzer findings in follow-up commits.
Large repositories may temporarily relax specific rules in their local `mago.toml`
(child settings override the base) — open a tracking issue to remove the relaxation.

### 8. Update CI

Replace the phpcs/psalm workflow steps with the standard QA workflow (see the README).
66 changes: 66 additions & 0 deletions docs/rules.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
# Rule rationale

Why the non-default choices in the shared `mago.toml` are what they are. The
configuration was extracted from the `phpdb-validator` refactor — the first
php-db component migrated to Mago — and reflects what survived contact with a
real codebase.

## Formatter

- **`print-width = 120`, 4-space indentation** — carried over from the
laminas-coding-standard era; matches the existing codebase style.
- **`preserve-breaking-*` family** — intentional line breaks (broken argument
lists, member-access chains, arrays, conditionals) survive reformatting
instead of being collapsed when they fit the print width. This dramatically
reduces diff churn on already-formatted code.
- **`align-assignment-like` / `sort-class-methods`** — opinionated readability
choices ratified during the validator refactor. `sort-class-methods` makes
method order deterministic, eliminating "where does this method go" review
comments.
- **`space-after-logical-not-unary-prefix-operator`** — `! $foo` over `!$foo`,
matching the laminas-coding-standard convention.

## Linter

- **`minimum-fail-level = "Help"`** — everything the linter reports fails the
build. Rules relegated to `level = "Help"` are still enforced; the level only
affects display severity.
- **`integrations = ["laminas", "phpunit"]`** — enables framework-aware rules
for the two ecosystems every php-db component sits in.
- **Naming rules** (`class-name`, `interface-name`, `trait-name` with
`psr = true`; camelCase methods/variables) — direct continuation of the
PSR-12/laminas-coding-standard naming policy.
- **`yoda-conditions`** — ratified during the refactor; guards against
accidental assignment in conditions.
- **`function-name` excludes `src/functions/*`** — free functions in the
conventional functions directory may use snake_case, matching common
PHP library practice.
- **`too-many-methods` excludes `test/`** — test cases legitimately accumulate
many test methods.

## Analyzer

- **`excludes = ["test"]`** — analysis focuses on shipped code; tests are
covered by the linter (including the `phpunit` integration) and by running.
- **`check-throws` + shared `unchecked-exceptions`** — enforces documented
`@throws` for checked exceptions. `Error`, `LogicException` (programmer
errors), and PHPUnit's internal exceptions are unchecked, as is
`Laminas\Validator\Exception\RuntimeException` which laminas-validator
throws pervasively.
- **`enforce-class-finality` / `require-api-or-internal`** — every class is
final unless deliberately opened; every symbol declares whether it is public
API. These are the strictest choices in the base and the most likely
migration friction; repositories may relax them locally with a tracking
issue.
- **`class-initializers`** — the base lists only the one initializer every
php-db component shares, `PHPUnit\Framework\TestCase::setUp`. Because arrays
concatenate on merge, repositories append their own (e.g. Laminas'
`Element::init` / `BaseInputFilter::init`, ...) without repeating the base
list.

## Versioning policy

Following laminas-coding-standard's precedent: enabling new rules (or
tightening existing ones) lands only in **major** releases of this package.
Minor and patch releases may fix documentation, templates, or relax/adjust
rules in a backwards-compatible direction.
Loading