Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
126a613
Add initial lock implementation
defunctl Jun 23, 2026
3fbad29
WIP: foundation-database
defunctl Jun 23, 2026
b83f270
Add missing phpstan stubfile
defunctl Jun 23, 2026
51469bd
Properly fix phpstan issues
defunctl Jun 23, 2026
92bbcc1
Add more test coverage
defunctl Jun 23, 2026
8bdae5d
Ignore generated codeception files when linting
defunctl Jun 23, 2026
07ecb42
Lint everything
defunctl Jun 23, 2026
7ce88ed
Add missing methods
defunctl Jun 23, 2026
35af811
Bump di52 in container to >=4.1
defunctl Jun 24, 2026
ab63542
Add wpcli and integration test suites, use phpcov to combine code cov…
defunctl Jun 24, 2026
ca2d996
Use pcov for code coverage now that slic 2.3.0 is out
defunctl Jun 25, 2026
3e2fe48
Update docs to remove xdebug coverage in place of pcov
defunctl Jun 25, 2026
49c8a4b
Clean up DatabaseProvider + add agents rules
defunctl Jun 26, 2026
6c7e8ac
Convert migrations to a collection
defunctl Jun 26, 2026
9c064de
Convert to single point of entry, Migrator to run migrations
defunctl Jun 26, 2026
9f8fc55
Add more column types to TableDefinition.php
defunctl Jun 26, 2026
6d5425d
Add foundation cli `make:database-migration` and `make:database-table…
defunctl Jun 26, 2026
0fb1370
Add foundation cli `make:database-provider`, refactor namespaces, add…
defunctl Jun 26, 2026
cc63d8a
Add `foundation-identifier` package
defunctl Jun 29, 2026
df126ac
Bring in dataprovider attribute
defunctl Jun 29, 2026
9a7b880
Merge remote-tracking branch 'origin/main' into feat/add-new-packages
defunctl Jul 1, 2026
3d9824a
Merge branch 'main' into feat/add-new-packages
defunctl Jul 2, 2026
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
1 change: 1 addition & 0 deletions .env.testing.slic
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ SLIC_PHP_VERSION=8.3
ENVIRONMENT=tests
TEST_LOG_CHANNEL=stack
TEST_LOG_LEVEL=debug
TEST_COMMAND_PREFIX=nxtest

WP_VERSION=latest
WP_ROOT_FOLDER=/var/www/html
Expand Down
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
/.gitignore export-ignore
/.github export-ignore
/docs export-ignore
/dev export-ignore
/.env.testing.slic export-ignore
/.env.slic.local export-ignore
/.env.slic.run export-ignore
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ jobs:

- name: Run code style checks
if: ${{ steps.filter.outputs.php == 'true' }}
run: composer lint ${{ steps.filter.outputs.php_files }}
run: composer lint

- name: Run static analysis
run: composer analyze

23 changes: 18 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,20 +106,33 @@ jobs:
run: |
"${SLIC_BIN}" run feature --ext DotReporter

- name: Run integration tests
if: github.event_name != 'pull_request'
run: |
"${SLIC_BIN}" run integration --ext DotReporter

- name: Run wpunit tests
if: github.event_name != 'pull_request'
run: |
"${SLIC_BIN}" run wpunit --ext DotReporter

- name: Enable Xdebug for coverage
if: github.event_name == 'pull_request'
- name: Run wpcli tests
if: github.event_name != 'pull_request'
run: |
"${SLIC_BIN}" xdebug on
"${SLIC_BIN}" run wpcli --ext DotReporter

- name: Run Codeception tests with coverage
if: github.event_name == 'pull_request'
run: |
"${SLIC_BIN}" run --coverage --coverage-xml clover.xml --disable-coverage-php --ext DotReporter
composer run coverage:phpcov-install
composer run coverage:prepare
"${SLIC_BIN}" pcov on --yes
"${SLIC_BIN}" run unit --coverage coverage/unit.cov --ext DotReporter
"${SLIC_BIN}" run feature --coverage coverage/feature.cov --ext DotReporter
"${SLIC_BIN}" run integration --coverage coverage/integration.cov --ext DotReporter
"${SLIC_BIN}" run wpunit --coverage coverage/wpunit.cov --ext DotReporter
"${SLIC_BIN}" run wpcli --coverage coverage/wpcli.cov --ext DotReporter
"${SLIC_BIN}" composer run coverage:merge

- name: Monitor coverage
if: github.event_name == 'pull_request'
Expand All @@ -128,7 +141,7 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}
comment_footer: false
coverage_format: clover
coverage_path: tests/_output/clover.xml
coverage_path: clover.xml
threshold_alert: 90
threshold_warning: 95
threshold_metric: "lines"
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ vendor
/coverage/
/tests/_output/*
!/tests/_output/.gitkeep
/tests/CodeceptionSupport/
!/tests/_output/coverage/
!/tests/_output/coverage/.gitignore
/tests/_data/temp/*
!/tests/_data/temp/.gitkeep
25 changes: 21 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ Initial packages:

- `stellarwp/foundation-container`
- `stellarwp/foundation-log`
- `stellarwp/foundation-lock`
- `stellarwp/foundation-database`
- `stellarwp/foundation-identifier`
- `stellarwp/foundation-pipeline`
- `stellarwp/foundation-wpcli`
- `stellarwp/foundation-cli`
Expand Down Expand Up @@ -43,7 +46,13 @@ Feature-local interfaces should live in a `Contracts/` folder inside the feature

Shared infrastructure interfaces should live under that shared namespace's `Contracts/` folder, for example `Process/Contracts/ProcessRunner.php`.

Generator commands should be grouped by the `make:*` workflow under `src/Cli/Commands/Make/`, for example `src/Cli/Commands/Make/WPCliCommand.php`. Shared generation infrastructure that is not itself a console command should live under `src/Cli/Generation/`.
Avoid `use ... as ...` import aliases unless they resolve a real class-name collision or ambiguity. Prefer importing the class by its actual short name. The standing exception is `use lucatume\DI52\Container as C;`, which may be used for concise container factory callbacks.

Exceptions should live in an `Exceptions/` folder. Put shared package exceptions at the package root, for example `src/Database/Exceptions/DatabaseException.php`; put feature-only exceptions under that feature's `Exceptions/` folder only when they are not shared outside that feature.

Generator commands should be grouped by the `make:*` workflow under `src/Cli/Commands/Make/`, for example `src/Cli/Commands/Make/WPCliCommand.php`. When a make feature grows beyond a single command class or needs private collaborators, group that feature under its own namespace such as `src/Cli/Commands/Make/Database/`. Command-specific collaborators should live inside that feature namespace, not beside unrelated command classes in `Commands/Make/`.

Shared generation infrastructure that is not itself a console command and is reused across command features should live under `src/Cli/Generation/`.

Default stubs should live with the package that owns the generated class shape. For example, WP-CLI command stubs live in `src/WPCli/stubs/` because the WPCli package owns the base `Command` API. The CLI package owns resolving, rendering, and writing generated files.

Expand Down Expand Up @@ -73,10 +82,16 @@ When writing providers or container registration code, prefer container-driven c

Use contextual bindings with `$this->container->when()->needs()->give()` for scalar constructor arguments, command lists, or feature-specific substitutions. Use a factory closure only when the value must be computed or resolved from the container, and keep that closure focused on supplying the constructor dependency rather than constructing the full object.

Classes should take the dependencies they need directly. Do not make constructor dependencies nullable just to instantiate fallback concrete classes internally, for example `?Dependency $dependency = null` with `$this->dependency = $dependency ?? new Dependency()`. Register default implementations and aliases in a provider instead so consumers can replace them through container configuration.

Organize provider registration by feature or capability, not by container mechanism. The main `register()` method should call focused private methods such as `registerConfiguration()`, `registerMigrations()`, `registerLocks()`, or `registerCliCommands()`. Keep each feature's contextual bindings beside the classes they configure. Avoid generic methods such as `configureContextualBindings()` that group unrelated bindings only because they use the same container API.

## Split Packages

Split packages live in `src/<Package>/` and are split to read-only repositories named `stellarwp/foundation-<package>`.

`stellarwp/foundation-database` is a WordPress-backed database package. Keep its runtime implementation centered on `wpdb`, `dbDelta()`, WordPress table prefixes, and WP-CLI integration. If the project later needs file storage, Redis storage, PDO database support, or another non-WordPress backend, prefer a separate package or explicit driver package instead of making `foundation-database` a generic DBAL-style abstraction.

When adding a new split package, set its package `composer.json` PHP constraint to `>=8.3` unless the user explicitly says otherwise. PHP 7.4 release compatibility will be handled later by an automated Rector downgrade workflow, not by lowering the package PHP constraint during development.

When adding external dependencies for split packages, choose version constraints whose package line supports PHP 7.4. Use `>=` constraints for those dependencies instead of caret constraints when preserving the PHP 7.4-compatible floor matters. For example, use a Symfony component version such as `>=5.4` rather than a newer line that requires PHP 8+.
Expand Down Expand Up @@ -151,13 +166,15 @@ Reusable test fixtures, sample classes, and test doubles should live under `test

Tests that need writable temporary files or directories should use a test-specific subdirectory under `tests/_data/temp` instead of `sys_get_temp_dir()`. Use `$this->temp_dir('<name>')` when only the path is needed; it mirrors `codecept_data_dir()` and does not create the directory. Use `$this->prepare_temp_dir('<name>')` in `setUp()` to create a unique clean directory under that name and register it for automatic cleanup by the base test case. Only call `$this->remove_temp_dir('<name>')` manually when a test needs to remove the prepared directories before teardown.

Codeception tests run through SLIC. Use `.env.testing.slic` as the SLIC/Codeception environment file. First-time local setup is `slic here` from the directory that contains this repository, `slic use foundation` from the repository, `slic composer install`, and `slic cc build`. If host-installed dependencies conflict with the SLIC PHP version, run `slic composer update --with-all-dependencies` inside the container. Run suites with `slic run unit`, `slic run feature`, and `composer test:wpunit` or `slic run wpunit`.
Codeception tests run through SLIC. Use SLIC 2.3.0 or newer so PCOV-backed coverage commands are available. Use `.env.testing.slic` as the SLIC/Codeception environment file. First-time local setup is `slic here` from the directory that contains this repository, `slic use foundation` from the repository, `slic composer install`, and `slic cc build`. If host-installed dependencies conflict with the SLIC PHP version, run `slic composer update --with-all-dependencies` inside the container. Run suites with `slic run unit`, `slic run feature`, `composer test:integration` or `slic run integration`, `composer test:wpunit` or `slic run wpunit`, and `composer test:wpcli` or `slic run wpcli`.

Test suite meanings: `Unit` is isolated class/package behavior, `Feature` is Foundation feature behavior without bootstrapping WordPress, `integration` is multi-provider/container behavior that may require WordPress runtime APIs such as hooks, `wpdb`, `dbDelta()`, or globals, `wpunit` is lower-level WordPress-loaded behavior through wp-browser, and `wpcli` is the shared monorepo suite for testing WP-CLI commands through wp-browser's WPCLI module. If a PHPUnit test uses `#[DataProvider]` and must run under Codeception, also include the matching `@dataProvider` docblock because Codeception's PHPUnit loader reads docblock providers for these tests.

Test suite meanings: `Unit` is isolated class/package behavior, `Feature` is Foundation feature behavior without bootstrapping WordPress, and `wpunit` is WordPress-loaded behavior through wp-browser. If a PHPUnit test uses `#[DataProvider]` and must run under Codeception, also include the matching `@dataProvider` docblock because Codeception's PHPUnit loader reads docblock providers for these tests.
Use `integration` for behavior where multiple providers/packages must be registered together to prove the container graph works. Use `wpunit` for a single package/class where the main concern is direct WordPress API behavior. Use `wpcli` for real WP-CLI command execution shared across packages. Keep unit tests focused on portable package behavior and pure collaborators; do not build large fake WordPress runtimes in unit tests when the behavior can be covered with wp-browser.

Use `tests/WPUnitSupport/WPTestCase.php` as the base class for wpunit tests instead of extending Codeception's `WPTestCase` directly. Keep Codeception-generated actor files in `tests/CodeceptionSupport/`; that directory is ignored and excluded from lint/static analysis.

After completing a feature, run `composer test:coverage`, review `clover.xml` for missed source coverage, and add meaningful tests for uncovered behavior before considering the feature complete.
After completing a feature, run `composer test:coverage`, review `clover.xml` for missed source coverage, and add meaningful tests for uncovered behavior before considering the feature complete. Coverage uses SLIC 2.3.0+ PCOV support, runs each SLIC suite separately, and merges the serialized `.cov` artifacts with `phpcov`; run the merge through `slic composer run coverage:merge` or `slic composer run coverage:merge-html` because the coverage files contain container paths like `/var/www/html/wp-content/plugins/foundation`.

## Releases

Expand Down
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Foundation is a StellarWP Composer monorepo for reusable PHP packages intended f
- [stellarwp/foundation-container-wordpress](https://github.com/stellarwp/foundation-container-wordpress)
- [stellarwp/foundation-pipeline](https://github.com/stellarwp/foundation-pipeline)
- [stellarwp/foundation-log](https://github.com/stellarwp/foundation-log)
- [stellarwp/foundation-lock](https://github.com/stellarwp/foundation-lock)
- [stellarwp/foundation-database](https://github.com/stellarwp/foundation-database)
- [stellarwp/foundation-identifier](https://github.com/stellarwp/foundation-identifier)
- [stellarwp/foundation-wpcli](https://github.com/stellarwp/foundation-wpcli)
- [stellarwp/foundation-cli](https://github.com/stellarwp/foundation-cli)

Expand Down Expand Up @@ -53,7 +56,9 @@ Run the Codeception suites with SLIC:
```bash
slic run unit
slic run feature
composer test:integration
composer test:wpunit
composer test:wpcli
```

The first time you run the WordPress suite locally, point SLIC at the directory that contains this repository and select the `foundation` project:
Expand All @@ -65,7 +70,9 @@ cd foundation
slic use foundation
slic composer install
slic cc build
composer test:integration
composer test:wpunit
composer test:wpcli
```

If dependencies were installed on a different host PHP version and the SLIC container reports Composer platform conflicts, refresh them inside SLIC:
Expand All @@ -76,14 +83,16 @@ slic composer update --with-all-dependencies

Run `slic cc build` again after changing Codeception suite configuration or modules. Generated Codeception actor files are written to `tests/CodeceptionSupport/` and are intentionally ignored.

The `unit` and `feature` SLIC suites run the same tests as `composer test:unit` and `composer test:feature`. The `wpunit` suite runs WordPress-loaded tests through wp-browser.
The `unit` and `feature` SLIC suites run the same tests as `composer test:unit` and `composer test:feature`. The `integration` suite covers multi-provider/container behavior that needs WordPress runtime APIs. The `wpunit` suite runs lower-level WordPress-loaded tests through wp-browser. The `wpcli` suite is shared across the monorepo for WP-CLI command tests and uses wp-browser's WPCLI module without the full wpunit module stack.

Generate the test coverage HTML dashboard (XDEBUG required to be enabled on your machine):
Generate the test coverage HTML dashboard:

```bash
composer test:coverage-html
```

Coverage uses SLIC 2.3.0+ PCOV support for faster collection. It runs each SLIC suite separately, writes serialized `.cov` artifacts, and merges them with `phpcov` so multiple WordPress-loaded suites can contribute to one Clover or HTML report.

### Code Quality

Check your code style:
Expand Down
Loading
Loading