From 0b20a534da423c3bfab3cc1f88d13c98e53c16aa Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Thu, 11 Jun 2026 21:40:51 -0400 Subject: [PATCH] Fix listed primary workspace fallback --- inc/Abilities/WorkspaceAbilities.php | 35 +++-- tests/smoke-workspace-local-fallback.php | 188 +++++++++++++++++++++++ 2 files changed, 212 insertions(+), 11 deletions(-) create mode 100644 tests/smoke-workspace-local-fallback.php diff --git a/inc/Abilities/WorkspaceAbilities.php b/inc/Abilities/WorkspaceAbilities.php index 8374722f..50a420f5 100644 --- a/inc/Abilities/WorkspaceAbilities.php +++ b/inc/Abilities/WorkspaceAbilities.php @@ -2494,7 +2494,10 @@ public static function getCapabilities( array $input ): array { // phpcs:ignor */ public static function showRepo( array $input ): array|\WP_Error { if ( RemoteWorkspaceBackend::should_handle() ) { - return ( new RemoteWorkspaceBackend() )->show($input['name'] ?? ''); + $result = ( new RemoteWorkspaceBackend() )->show($input['name'] ?? ''); + if ( ! self::shouldFallbackToLocalWorkspace($result) ) { + return $result; + } } $workspace = new Workspace(); @@ -3398,16 +3401,6 @@ public static function prRebase( array $input ): array|\WP_Error { * @return array */ public static function worktreeAdd( array $input ): array|\WP_Error { - if ( RemoteWorkspaceBackend::should_handle() ) { - $result = ( new RemoteWorkspaceBackend() )->worktree_add( - $input['repo'] ?? '', - $input['branch'] ?? '', - $input['from'] ?? null - ); - return self::decorate_remote_workspace_result('worktree_add', $result); - } - - $workspace = new Workspace(); // Default inject_context=true; only false when explicitly provided. $inject_context = array_key_exists('inject_context', $input) ? (bool) $input['inject_context'] : true; // Default bootstrap=true; only false when explicitly provided. @@ -3424,6 +3417,19 @@ public static function worktreeAdd( array $input ): array|\WP_Error { if ( isset($input['task_ref']) && '' !== trim( (string) $input['task_ref']) ) { $task['task_ref'] = (string) $input['task_ref']; } + + if ( RemoteWorkspaceBackend::should_handle() ) { + $result = ( new RemoteWorkspaceBackend() )->worktree_add( + $input['repo'] ?? '', + $input['branch'] ?? '', + $input['from'] ?? null + ); + if ( ! self::shouldFallbackToLocalWorkspace($result) ) { + return self::decorate_remote_workspace_result('worktree_add', $result); + } + } + + $workspace = new Workspace(); return $workspace->worktree_add( $input['repo'] ?? '', $input['branch'] ?? '', @@ -3437,6 +3443,13 @@ public static function worktreeAdd( array $input ): array|\WP_Error { ); } + /** + * Whether a remote-backend lookup miss should be retried against local workspace discovery. + */ + private static function shouldFallbackToLocalWorkspace( mixed $result ): bool { + return is_wp_error($result) && 'remote_workspace_repo_not_found' === $result->get_error_code(); + } + /** * Refresh a worktree's injected context from the originating site. * diff --git a/tests/smoke-workspace-local-fallback.php b/tests/smoke-workspace-local-fallback.php new file mode 100644 index 00000000..381e3e42 --- /dev/null +++ b/tests/smoke-workspace-local-fallback.php @@ -0,0 +1,188 @@ + true, + 'name' => $handle, + 'repo' => $handle, + 'is_worktree' => false, + 'path' => '/Users/chubes/Developer/' . $handle, + 'branch' => 'main', + 'remote' => 'git@github.a8c.com:Automattic/wpcom-codebox.git', + 'commit' => 'abc123 listed primary', + 'dirty' => 0, + ); + } + + public function worktree_add( + string $repo, + string $branch, + ?string $from = null, + bool $inject_context = true, + bool $bootstrap = true, + bool $allow_stale = false, + bool $rebase_base = false, + bool $force = false, + array $task = array() + ): array { + self::$worktree_input = compact('repo', 'branch', 'from', 'inject_context', 'bootstrap', 'allow_stale', 'rebase_base', 'force', 'task'); + return array( + 'success' => true, + 'handle' => $repo . '@' . str_replace('/', '-', $branch), + 'path' => '/Users/chubes/Developer/' . $repo . '@' . str_replace('/', '-', $branch), + ); + } + } +} + +namespace DataMachineCode\Support { + class RuntimeCapabilities + { + } + + class GitRunner + { + } +} + +namespace { + if ( ! defined('ABSPATH') ) { + define('ABSPATH', __DIR__); + } + + class WP_Error + { + public function __construct( private string $code, private string $message, private array $data = array() ) + { + } + + public function get_error_code(): string + { + return $this->code; + } + + public function get_error_message(): string + { + return $this->message; + } + + public function get_error_data(): array + { + return $this->data; + } + } + + function is_wp_error( $value ): bool + { + return $value instanceof WP_Error; + } + + require __DIR__ . '/../inc/Abilities/WorkspaceAbilities.php'; + + $failures = array(); + $assert = function ( string $label, bool $condition ) use ( &$failures ): void { + if ( $condition ) { + echo " ok {$label}\n"; + return; + } + + $failures[] = $label; + echo " fail {$label}\n"; + }; + + echo "Workspace local fallback - smoke\n"; + + $show = \DataMachineCode\Abilities\WorkspaceAbilities::showRepo( + array( + 'name' => 'wpcom-codebox', + ) + ); + + $assert('remote show attempted first', 'wpcom-codebox' === ( \DataMachineCode\Workspace\RemoteWorkspaceBackend::$show_input['handle'] ?? '' )); + $assert('local show fallback attempted', 'wpcom-codebox' === ( \DataMachineCode\Workspace\Workspace::$show_input['handle'] ?? '' )); + $assert('show returns local listed primary', is_array($show) && '/Users/chubes/Developer/wpcom-codebox' === ( $show['path'] ?? '' )); + + $worktree = \DataMachineCode\Abilities\WorkspaceAbilities::worktreeAdd( + array( + 'repo' => 'wpcom-codebox', + 'branch' => 'fix/listed-primary-resolution', + 'from' => 'origin/main', + 'inject_context' => false, + 'bootstrap' => false, + 'allow_stale' => true, + 'rebase_base' => true, + 'force' => true, + 'task_url' => 'https://github.com/Extra-Chill/data-machine-code/issues/635', + ) + ); + + $assert('remote worktree add attempted first', 'wpcom-codebox' === ( \DataMachineCode\Workspace\RemoteWorkspaceBackend::$worktree_input['repo_name'] ?? '' )); + $assert('local worktree add fallback attempted', 'wpcom-codebox' === ( \DataMachineCode\Workspace\Workspace::$worktree_input['repo'] ?? '' )); + $assert('worktree add preserves base ref', 'origin/main' === ( \DataMachineCode\Workspace\Workspace::$worktree_input['from'] ?? '' )); + $assert('worktree add preserves local options', false === ( \DataMachineCode\Workspace\Workspace::$worktree_input['inject_context'] ?? null ) && true === ( \DataMachineCode\Workspace\Workspace::$worktree_input['allow_stale'] ?? null )); + $assert('worktree add returns local worktree result', is_array($worktree) && 'wpcom-codebox@fix-listed-primary-resolution' === ( $worktree['handle'] ?? '' )); + + if ( $failures ) { + echo "\nFailures:\n"; + foreach ( $failures as $failure ) { + echo " - {$failure}\n"; + } + exit(1); + } + + echo "\nOK\n"; +}