Skip to content

Commit c9ce3a2

Browse files
committed
Improve cleanup plan summary
1 parent 7f68ddd commit c9ce3a2

5 files changed

Lines changed: 435 additions & 6 deletions

File tree

inc/Cli/Commands/WorkspaceCommand.php

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,10 @@ public function adopt_repo( array $args, array $assoc_args ): void {
600600
* [--older-than=<duration>]
601601
* : Pass an age gate such as 7d or 24h into cleanup task params.
602602
*
603+
* [--top=<count>]
604+
* : For `plan`, number of largest reclaimable paths to show in the upfront
605+
* summary. Defaults to 10.
606+
*
603607
* [--limit=<count>]
604608
* : For DB-backed `apply` / `resume`, maximum pending rows to process in this
605609
* invocation (default 25, max 100). For `--mode=artifacts` pages, maximum
@@ -942,6 +946,9 @@ private function run_cleanup_plan( array $assoc_args ): void {
942946
if ( isset($assoc_args['older-than']) && '' !== trim( (string) $assoc_args['older-than']) ) {
943947
$input['worktree_older_than'] = trim( (string) $assoc_args['older-than']);
944948
}
949+
if ( isset($assoc_args['top']) ) {
950+
$input['top_n'] = (int) $assoc_args['top'];
951+
}
945952
if ( isset($assoc_args['force']) ) {
946953
$input['force_artifact_cleanup'] = (bool) $assoc_args['force'];
947954
}
@@ -1399,12 +1406,131 @@ private function render_cleanup_plan_result( array $result, array $assoc_args ):
13991406
WP_CLI::log(sprintf('Rows: %d', (int) ( $summary['total_rows'] ?? 0 )));
14001407
WP_CLI::log(sprintf('Bytes: %s', $this->format_bytes($summary['total_size_bytes'] ?? 0)));
14011408
WP_CLI::log(sprintf('Apply: wp datamachine-code workspace cleanup apply %s', (string) ( $result['run_id'] ?? '' )));
1409+
$this->render_cleanup_plan_category_totals( (array) ( $summary['category_totals'] ?? array() ) );
1410+
$this->render_cleanup_plan_top_reclaimable( (array) ( $summary['top_reclaimable'] ?? array() ) );
1411+
$this->render_cleanup_plan_blockers( (array) ( $summary['blockers'] ?? array() ) );
1412+
$this->render_cleanup_plan_recommended_commands( (array) ( $summary['recommended_commands'] ?? array() ), (string) ( $result['run_id'] ?? '' ) );
14021413
$inputs = (array) ( $result['inputs'] ?? array() );
14031414
if ( empty($inputs['include_artifacts']) ) {
14041415
WP_CLI::log('Artifacts: skipped for bounded retention planning; run `wp datamachine-code workspace cleanup plan --mode=artifacts` when you want artifact rows.');
14051416
}
14061417
}
14071418

1419+
/**
1420+
* Render reclaimable cleanup bytes by category.
1421+
*
1422+
* @param array<string,int> $totals Category totals.
1423+
*/
1424+
private function render_cleanup_plan_category_totals( array $totals ): void {
1425+
if ( array() === $totals ) {
1426+
return;
1427+
}
1428+
1429+
WP_CLI::log('');
1430+
WP_CLI::log('Reclaimable space by category:');
1431+
$labels = array(
1432+
'whole_worktrees' => 'whole worktrees',
1433+
'dependency_artifacts' => 'dependency artifacts',
1434+
'build_outputs' => 'build outputs',
1435+
'caches' => 'caches',
1436+
);
1437+
$rows = array();
1438+
foreach ( $labels as $category => $label ) {
1439+
$rows[] = array(
1440+
'category' => $label,
1441+
'bytes' => $this->format_bytes($totals[ $category ] ?? 0),
1442+
);
1443+
}
1444+
$this->format_items($rows, array( 'category', 'bytes' ), array( 'format' => 'table' ), 'category');
1445+
}
1446+
1447+
/**
1448+
* Render largest reclaimable paths.
1449+
*
1450+
* @param array<int,array<string,mixed>> $paths Top paths.
1451+
*/
1452+
private function render_cleanup_plan_top_reclaimable( array $paths ): void {
1453+
if ( array() === $paths ) {
1454+
return;
1455+
}
1456+
1457+
WP_CLI::log('');
1458+
WP_CLI::log('Top reclaimable paths:');
1459+
$rows = array_map(
1460+
fn( $row ) => array(
1461+
'size' => is_array($row) ? $this->format_bytes($row['size_bytes'] ?? 0) : '0 B',
1462+
'category' => is_array($row) ? (string) ( $row['category'] ?? '' ) : '',
1463+
'risk' => is_array($row) ? (string) ( $row['safety_class'] ?? '' ) : '',
1464+
'handle' => is_array($row) ? (string) ( $row['handle'] ?? '' ) : '',
1465+
'path' => is_array($row) ? (string) ( $row['path'] ?? '' ) : '',
1466+
),
1467+
$paths
1468+
);
1469+
$this->format_items($rows, array( 'size', 'category', 'risk', 'handle', 'path' ), array( 'format' => 'table' ), 'size');
1470+
}
1471+
1472+
/**
1473+
* Render blockers grouped by reason and repo.
1474+
*
1475+
* @param array<string,array<string,mixed>> $blockers Blocker buckets.
1476+
*/
1477+
private function render_cleanup_plan_blockers( array $blockers ): void {
1478+
if ( array() === $blockers ) {
1479+
return;
1480+
}
1481+
1482+
WP_CLI::log('');
1483+
WP_CLI::log('Blockers by reason and repo:');
1484+
$rows = array();
1485+
foreach ( $blockers as $reason => $bucket ) {
1486+
$bucket = (array) $bucket;
1487+
$repos = array();
1488+
foreach ( (array) ( $bucket['repos'] ?? array() ) as $repo => $repo_bucket ) {
1489+
$repo_bucket = (array) $repo_bucket;
1490+
$repos[] = sprintf('%s=%d', (string) $repo, (int) ( $repo_bucket['count'] ?? 0 ));
1491+
}
1492+
$rows[] = array(
1493+
'reason' => (string) $reason,
1494+
'count' => (int) ( $bucket['count'] ?? 0 ),
1495+
'bytes' => $this->format_bytes($bucket['size_bytes'] ?? 0),
1496+
'repos' => implode(', ', array_slice($repos, 0, 5)),
1497+
'examples' => implode(', ', array_slice(array_map('strval', (array) ( $bucket['examples'] ?? array() )), 0, 5)),
1498+
);
1499+
}
1500+
$this->format_items($rows, array( 'reason', 'count', 'bytes', 'repos', 'examples' ), array( 'format' => 'table' ), 'reason');
1501+
}
1502+
1503+
/**
1504+
* Render directly executable recommended cleanup commands.
1505+
*
1506+
* @param array<int,array<string,string>> $commands Recommended commands.
1507+
* @param string $run_id Cleanup run ID.
1508+
*/
1509+
private function render_cleanup_plan_recommended_commands( array $commands, string $run_id ): void {
1510+
if ( array() === $commands ) {
1511+
return;
1512+
}
1513+
1514+
WP_CLI::log('');
1515+
WP_CLI::log('Recommended commands:');
1516+
$rows = array_map(
1517+
function ( $row ) use ( $run_id ): array {
1518+
$row = (array) $row;
1519+
$command = (string) ( $row['command'] ?? '' );
1520+
if ( '' !== $run_id ) {
1521+
$command = str_replace('<run-id>', $run_id, $command);
1522+
}
1523+
return array(
1524+
'label' => (string) ( $row['label'] ?? '' ),
1525+
'risk' => (string) ( $row['risk'] ?? '' ),
1526+
'command' => $command,
1527+
);
1528+
},
1529+
$commands
1530+
);
1531+
$this->format_items($rows, array( 'label', 'risk', 'command' ), array( 'format' => 'table' ), 'label');
1532+
}
1533+
14081534
private function cleanup_run_id( int $job_id ): string {
14091535
return 'cleanup-run-' . $job_id;
14101536
}

inc/Workspace/CleanupRunService.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public function plan( array $opts = array() ): array|\WP_Error {
5353
if ( $run_id instanceof \WP_Error ) {
5454
return $run_id;
5555
}
56+
$plan['summary'] = $this->materialize_plan_recommended_commands( (array) ( $plan['summary'] ?? array() ), $run_id );
57+
$this->repository->update_run($run_id, array( 'summary' => $plan['summary'] ));
5658

5759
$inserted = $this->repository->add_items($run_id, $items);
5860
if ( $inserted instanceof \WP_Error ) {
@@ -70,6 +72,26 @@ public function plan( array $opts = array() ): array|\WP_Error {
7072
return $plan;
7173
}
7274

75+
/**
76+
* Replace run-id placeholders in persisted plan command recommendations.
77+
*
78+
* @param array<string,mixed> $summary Plan summary.
79+
* @param string $run_id Cleanup run ID.
80+
* @return array<string,mixed>
81+
*/
82+
private function materialize_plan_recommended_commands( array $summary, string $run_id ): array {
83+
$commands = array();
84+
foreach ( (array) ( $summary['recommended_commands'] ?? array() ) as $row ) {
85+
if ( ! is_array($row) ) {
86+
continue;
87+
}
88+
$row['command'] = str_replace('<run-id>', $run_id, (string) ( $row['command'] ?? '' ));
89+
$commands[] = $row;
90+
}
91+
$summary['recommended_commands'] = $commands;
92+
return $summary;
93+
}
94+
7395
/**
7496
* Apply pending rows from a DB-backed run.
7597
*

0 commit comments

Comments
 (0)