Skip to content
Draft
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
22 changes: 22 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Progress Planner

Progress Planner (PP) is being withdrawn from wordpress.org. It reaches users as a Composer dependency of **pp-hosts** (private repo `ProgressPlanner/pp-hosts`, which requires this repo's `pp-hosts` branch). A change here is only done once it works inside pp-hosts.

## Branches

- `develop`: development. `main`: stable. `pp-hosts`: what pp-hosts installs (merge `develop` into it to release to pp-hosts).

## pp-hosts contract

`tests/contract/pp-hosts-contract.json` lists the PP API surface pp-hosts depends on: hooks it listens to, parent classes it extends (overridden methods, used properties and constants), `progress_planner()->get_*()` services and the methods called on them, constants, dashboard widget IDs and assets.

- `tests/phpunit/test-pp-hosts-contract.php` runs on every PR (in the normal PHPUnit suite) and fails if PP stops providing any of it.
- The same check runs without WordPress or a database: `php tests/contract/check-pp-hosts-contract.php [contract.json]`.
- **If it fails:** prefer keeping the old API (deprecate it; don't remove it). If the break is intended, change pp-hosts in the same release. Then regenerate the contract in pp-hosts (`php bin/build-pp-contract.php`) and copy it here.
- **Don't edit the JSON by hand.** It's generated from pp-hosts. `known_issues` in it comes from pp-hosts `tests/contract/known-issues.json`.

## Testing a PP change inside pp-hosts

From a pp-hosts checkout, run `bin/pp-integration.sh <pp-ref|working>`. It builds pp-hosts with that PP ref and runs these gates: contract, lint, PHPStan and Playwright e2e. Add `--ai` for a Claude impact report and a browser smoke test. See pp-hosts `CLAUDE.md`.

Run it after merging notable PRs to `develop`, and always before merging `develop` into `pp-hosts`.
77 changes: 77 additions & 0 deletions tests/contract/check-pp-hosts-contract.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
/**
* CLI: check Progress Planner against the pp-hosts contract, without WordPress.
*
* Usage:
* php tests/contract/check-pp-hosts-contract.php [contract.json] [--json]
*
* Defaults to tests/contract/pp-hosts-contract.json. Exits 1 on failures.
* The pp-hosts integration runner (pp-hosts/bin/pp-integration.sh) calls this
* with the contract freshly generated from the pp-hosts branch under test.
*
* @package Progress_Planner\Tests
*/

// phpcs:disable WordPress.WP.AlternativeFunctions, WordPress.Security.EscapeOutput.OutputNotEscaped -- CLI script.

if ( 'cli' !== \PHP_SAPI ) {
exit( 1 );
}

$prpl_pp_dir = \dirname( __DIR__, 2 );
$prpl_args = \array_slice( $argv, 1 );
$prpl_json = \in_array( '--json', $prpl_args, true );
$prpl_files = \array_values( \array_diff( $prpl_args, [ '--json' ] ) );
$prpl_file = $prpl_files[0] ?? __DIR__ . '/pp-hosts-contract.json';

// Minimal shims so the autoloader works outside WordPress.
if ( ! \function_exists( 'esc_html' ) ) {
/**
* Shim.
*
* @param string $text Text.
* @return string
*/
function esc_html( $text ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- WP shim, only defined outside WordPress.
return \htmlspecialchars( (string) $text, \ENT_QUOTES );
}
}
if ( ! \defined( 'PROGRESS_PLANNER_DIR' ) ) {
\define( 'PROGRESS_PLANNER_DIR', $prpl_pp_dir );
}

require_once $prpl_pp_dir . '/autoload.php';
require_once __DIR__ . '/class-pp-hosts-contract-checker.php';

$prpl_checker = new \Progress_Planner\Tests\PP_Hosts_Contract_Checker( $prpl_pp_dir, $prpl_file );
$prpl_failures = $prpl_checker->check();
$prpl_known = $prpl_checker->get_known();

if ( $prpl_json ) {
echo \json_encode(
[
'failures' => (object) $prpl_failures,
'known' => (object) $prpl_known,
],
\JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES
) . "\n";
exit( empty( $prpl_failures ) ? 0 : 1 );
}

foreach ( $prpl_known as $prpl_message => $prpl_reason ) {
echo "known issue: {$prpl_message}\n ({$prpl_reason})\n";
}

if ( empty( $prpl_failures ) ) {
echo "pp-hosts contract: OK\n";
} else {
echo "pp-hosts contract: FAILED\n";
foreach ( $prpl_failures as $prpl_section => $prpl_messages ) {
echo "\n[{$prpl_section}]\n";
foreach ( $prpl_messages as $prpl_message ) {
echo " - {$prpl_message}\n";
}
}
}

exit( empty( $prpl_failures ) ? 0 : 1 );
Loading
Loading