osdd:check
osdd:check reads the PHP files of every layer and fails when a layer uses a class of a layer it does not require in its composer.json, or when layers require each other. See Boundaries for the rule and what is read.
php artisan osdd:check
ERROR functional/orders uses functional/billing but does not require it.
functional/orders/src/Checkout.php:7 ........ Functional\Billing\Models\Invoice
functional/orders/tests/CheckoutTest.php:5 .. Functional\Billing\Models\Invoice
WARN functional/billing requires technical/core but does not use it.
ERROR 1 boundary violation in 4 layers (1 unused requirement).
A cycle shows as ERROR Cycle in the layer requirements: functional/orders -> functional/users -> functional/orders.. Without violation, the command prints No boundary violation in 4 layers..
Options
| Option | Description |
|---|---|
--layer | Only check these layers. Full or package name, repeated (--layer=orders --layer=billing) or comma-separated (--layer=orders,billing). |
--transitive | Also allow the layers that the required layers require. By default, only the layers in the layer's own require are allowed. |
--format | text (default), json or github. |
php artisan osdd:check --layer=orders,billing
php artisan osdd:check --transitive
php artisan osdd:check --format=json
php artisan osdd:check --format=github
Exit codes
| Code | When |
|---|---|
0 | No undeclared dependency and no cycle. Unused requirements are warnings and do not fail. |
1 | At least one undeclared dependency or cycle; or an unknown --layer, an unknown --format, an invalid osdd.boundaries.ignore entry or an invalid layer composer.json. |
JSON format
php artisan osdd:check --format=json
{
"layers": ["functional/billing", "functional/orders", "functional/users", "technical/core"],
"strict": true,
"undeclared": [
{
"layer": "functional/orders",
"uses": "functional/billing",
"class": "Functional\\Billing\\Models\\Invoice",
"file": "functional/orders/src/Checkout.php",
"line": 7
}
],
"unused": [
{"layer": "functional/billing", "requires": "technical/core", "section": "require"}
],
"cycles": [
["functional/orders", "functional/users", "functional/orders"]
]
}
strictisfalsewith--transitive.fileis relative to the project. Each file reports a class once, at its first reference.sectionisrequireorrequire-dev.
GitHub format
--format=github prints GitHub Actions workflow commands, so each violation shows as an annotation on the pull request:
::error file=functional/orders/src/Checkout.php,line=7,title=Undeclared layer dependency::functional/orders uses Functional\Billing\Models\Invoice from functional/billing but does not require functional/billing.
::error title=Layer cycle::Cycle in the layer requirements: functional/orders -> functional/users -> functional/orders.
::warning file=functional/billing/composer.json,title=Unused layer requirement::functional/billing requires technical/core but does not use it.
2 boundary violations in 4 layers (1 unused requirement).
Add it as a step of the job that installs the application:
- name: Check layer boundaries
run: php artisan osdd:check --format=github
The annotation paths are relative to the Laravel root. Run the step from the repository root, or set working-directory when the application lives in a sub-folder.
Ignoring a dependency
osdd.boundaries.ignore lists class prefixes and layer pairs that osdd:check does not report. See Ignoring a dependency.