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
17 changes: 17 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ permissions:
contents: read

jobs:
quality:
name: Mago formatter, linter and analyzer
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
coverage: none
- name: Install development dependencies
run: composer install --prefer-dist --no-progress --no-interaction
- name: Run formatter, linter and analyzer without a baseline
run: composer check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

run:
runs-on: ${{ matrix.operating-system }}

Expand Down
64 changes: 64 additions & 0 deletions MAGO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Mago checks

Install development dependencies with `composer install`, then run:

```sh
composer check # formatting, linter, analyzer for source and tests
composer format # apply formatting
composer lint
composer analyze
```

Mago is pinned to **1.47.4**, the newest published version verified for this upgrade.
Update the pin deliberately and run the full checks before upgrading. Composer installs the
platform-specific launcher; its first invocation downloads the matching binary.
CI provides `GITHUB_TOKEN` for that download. Scripts invoke the project-local PHP
launcher explicitly so an older system-wide binary cannot be used accidentally.
There is no baseline.

The formatter, linter, and analyzer have been run successfully with 1.47.4 against
both configurations. On Windows, the Composer launcher needs PHP's ZIP extension
and a configured trusted CA certificate bundle to download and extract its binary.

`mago.toml` targets PHP 8.1 for library code. `mago-tests.toml` targets PHP 8.2 because
some fixtures intentionally exercise readonly classes and traits; PHPUnit skips
the applicable tests on PHP 8.1. Both configurations read dependency declarations
without checking vendor code. Generated AOP cache and coverage files are excluded.

The linter uses its default correctness, consistency, and maintainability checks.
Exceptions in configuration are explicit design choices: mandatory strict types
would change coercion behavior; named arguments and boolean flags are existing API
choices; `isset` intentionally distinguishes null; aggregate complexity metrics
are left to review. Analyzer missing-type checks are enabled. CI fails on all
reported severities. No analyzer issue codes are ignored globally.

The vendor type patch in `tools/mago/patches/CodeTransformerKernel.php` models its
dependency injection callback as a generic extension point. The default remains
the original one-argument callback returning a Transformer. AopKernel specializes
it to its established two-argument callback returning an aspect or transformer.
This replaces the previous callback suppression without changing runtime code or
loosening TransformerManager's contract. `composer check-mago-types` checks valid
callbacks and rejects scalar returns and incorrect default transformer callbacks.
It runs as part of `composer check`, including in CI. Its deliberately invalid
fixtures live in `tools/mago/tests` and are checked separately from library code.

Two narrow `@mago-expect` annotations still cover four property-access diagnostics.
These are explicit analyzer exceptions, not fixes to the analyzer's limitations:

- Two property-access closures operate on a declaration validated through reflection.
Mago cannot prove a runtime property name exists on the subject. Reference, scope,
uninitialized-property, and unset behavior have runtime regression tests.

These expectations name individual diagnostics at the affected operations. Mago
reports an unfulfilled expectation if a future release stops producing a diagnostic,
so stale exceptions fail CI. No baseline, file exclusions for these operations, or
global analyzer diagnostic suppressions are used.

An extension experiment confirmed that Mago 1.47.4 does not dispatch property type
providers for these unresolved runtime operations. The experiment was discarded;
no custom extension or issue filter is installed.

Performance fixture generation now uses a shared service interface and validates
generated service instantiation through reflection. Its construction work is part
of the class-loading measurement; compare loading results only against runs using
the same harness. The timed method-execution loop is unchanged.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,8 @@ $firstLog = $logs[0];


## Testing

Development quality checks: see [Mago setup and commands](MAGO.md).
- Run `composer run-script test`<br>
or
- Run `composer run-script test-coverage`
Expand Down
11 changes: 9 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@
"scripts": {
"test": "phpunit --testsuite=Tests --display-notices",
"test-performance": "phpunit --testsuite=Performance --display-notices",
"test-coverage": "phpunit --testsuite=Tests --coverage-html tests/coverage --display-notices"
"test-coverage": "phpunit --testsuite=Tests --coverage-html tests/coverage --display-notices",
"format": ["@php vendor/bin/mago format", "@php vendor/bin/mago --config mago-tests.toml format"],
"format-check": ["@php vendor/bin/mago format --check", "@php vendor/bin/mago --config mago-tests.toml format --check"],
"lint": ["@php vendor/bin/mago lint --minimum-fail-level note", "@php vendor/bin/mago --config mago-tests.toml lint --minimum-fail-level note"],
"analyze": ["@php vendor/bin/mago analyze --minimum-fail-level note", "@php vendor/bin/mago --config mago-tests.toml analyze --minimum-fail-level note"],
"check-mago-types": "@php tools/mago/check.php",
"check": ["@format-check", "@lint", "@analyze", "@check-mago-types"]
},
"require": {
"php": ">=8.1",
Expand All @@ -30,7 +36,8 @@
"okapi/singleton": "^1.0",
"php-di/php-di": "^7.0"
},
"require-dev": {
"require-dev": {
"carthage-software/mago": "1.47.4",
"phpunit/phpunit": "^10.3",
"symfony/var-dumper": "^6.3",
"symfony/console": "^6.3"
Expand Down
35 changes: 35 additions & 0 deletions mago-tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
php-version = "8.2"

[source]
paths = ["tests"]
includes = ["src", "vendor"]
patches = ["tools/mago/patches"]
excludes = ["tests/cache", "tests/coverage"]

[linter]
integrations = ["phpunit"]

# Preserve the library's coercion contract and existing public call signatures.
[linter.rules.strict-types]
enabled = false
[linter.rules.literal-named-argument]
enabled = false
[linter.rules.no-boolean-flag-parameter]
enabled = false
# isset intentionally distinguishes null from a usable value throughout this code.
[linter.rules.no-isset]
enabled = false
# Complexity metrics are review aids, not correctness gates for a weaving engine.
[linter.rules.halstead]
enabled = false
[linter.rules.kan-defect]
enabled = false
[linter.rules.cyclomatic-complexity]
enabled = false
[linter.rules.too-many-methods]
enabled = false
[linter.rules.excessive-parameter-list]
threshold = 10

[analyzer]
check-missing-type-hints = true
35 changes: 35 additions & 0 deletions mago.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
php-version = "8.1"

[source]
paths = ["src", "tools/mago/check.php"]
includes = ["vendor"]
patches = ["tools/mago/patches"]
excludes = ["tests/cache", "tests/coverage"]

[linter]
integrations = ["phpunit"]

# Preserve the library's coercion contract and existing public call signatures.
[linter.rules.strict-types]
enabled = false
[linter.rules.literal-named-argument]
enabled = false
[linter.rules.no-boolean-flag-parameter]
enabled = false
# isset intentionally distinguishes null from a usable value throughout this code.
[linter.rules.no-isset]
enabled = false
# Complexity metrics are review aids, not correctness gates for a weaving engine.
[linter.rules.halstead]
enabled = false
[linter.rules.kan-defect]
enabled = false
[linter.rules.cyclomatic-complexity]
enabled = false
[linter.rules.too-many-methods]
enabled = false
[linter.rules.excessive-parameter-list]
threshold = 10

[analyzer]
check-missing-type-hints = true
4 changes: 2 additions & 2 deletions src/Advice/AdviceType.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ enum AdviceType
case Before;
case Around;
case After;
// TODO: implement
// Reserved for future after-returning advice support.
case AfterReturning;
// TODO: implement
// Reserved for future after-throwing advice support.
case AfterThrowing;
}
Loading
Loading