Skip to content

Commit ec9cc4e

Browse files
authored
Fix workspace alias compatibility coverage (#509)
1 parent 48d02d8 commit ec9cc4e

2 files changed

Lines changed: 116 additions & 1 deletion

File tree

inc/Tools/WorkspaceTools.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,11 @@ private function resolveWorkspaceInputAliases( array $input, array $handle_keys
737737
* naturally use paths like /workspace/example/README.md even though the
738738
* canonical workspace tools accept repo=example and path=README.md.
739739
*
740+
* This is the model-facing compatibility boundary for workspace file tools:
741+
* DMC accepts mounted absolute paths under DATAMACHINE_WORKSPACE_PATH and
742+
* the documented workspace_edit aliases search/replace and old/new. It does
743+
* not infer unrelated required inputs from ambient context.
744+
*
740745
* @param array<string,mixed> $input Tool input.
741746
* @param string[] $handle_keys Keys that hold workspace handles.
742747
* @return array<string,mixed>

tests/smoke-workspace-alias-tools.php

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
$GLOBALS['dmc_workspace_alias_filters'] = array();
1919
$GLOBALS['dmc_workspace_alias_ability'] = null;
20+
$GLOBALS['dmc_workspace_alias_registered_abilities'] = array();
21+
$GLOBALS['dmc_workspace_alias_remote_edit_input'] = array();
2022

2123
function add_filter( string $tag, callable $callback, int $priority = 10, int $accepted_args = 1 ): void
2224
{
@@ -49,9 +51,82 @@ function wp_get_ability( string $name )
4951
return $GLOBALS['dmc_workspace_alias_ability'];
5052
}
5153

54+
function wp_register_ability( string $name, array $definition ): void
55+
{
56+
$GLOBALS['dmc_workspace_alias_registered_abilities'][ $name ] = $definition;
57+
}
58+
59+
function add_action( string $hook, callable $callback, int $priority = 10 ): void
60+
{
61+
}
62+
63+
function doing_action( string $hook ): bool
64+
{
65+
return 'wp_abilities_api_init' === $hook;
66+
}
67+
5268
function is_wp_error( $value ): bool
5369
{
54-
return false;
70+
return $value instanceof WP_Error;
71+
}
72+
73+
class WP_Error
74+
{
75+
private string $code;
76+
private string $message;
77+
78+
public function __construct( string $code, string $message, array $data = array() )
79+
{
80+
$this->code = $code;
81+
$this->message = $message;
82+
}
83+
84+
public function get_error_code(): string
85+
{
86+
return $this->code;
87+
}
88+
89+
public function get_error_message(): string
90+
{
91+
return $this->message;
92+
}
93+
}
94+
}
95+
96+
namespace DataMachine\Abilities {
97+
class PermissionHelper
98+
{
99+
public static function can_manage(): bool
100+
{
101+
return true;
102+
}
103+
}
104+
}
105+
106+
namespace DataMachineCode\Workspace {
107+
class Workspace
108+
{
109+
public const ARTIFACT_CLEANUP_DEFAULT_LIMIT = 100;
110+
public const MAX_READ_SIZE = 1048576;
111+
}
112+
113+
class RemoteWorkspaceBackend
114+
{
115+
public static function should_handle(): bool
116+
{
117+
return true;
118+
}
119+
120+
public function edit_file( string $handle, string $path, string $old_string, string $new_string, bool $replace_all = false ): array
121+
{
122+
$GLOBALS['dmc_workspace_alias_remote_edit_input'] = compact('handle', 'path', 'old_string', 'new_string', 'replace_all');
123+
return array(
124+
'success' => true,
125+
'name' => $handle,
126+
'path' => $path,
127+
'replacements' => 1,
128+
);
129+
}
55130
}
56131
}
57132

@@ -74,6 +149,7 @@ protected function buildErrorResponse( string $message, string $tool_name ): arr
74149

75150
namespace {
76151
include __DIR__ . '/../inc/Workspace/WorkspaceAliasResolver.php';
152+
include __DIR__ . '/../inc/Abilities/WorkspaceAbilities.php';
77153
include __DIR__ . '/../inc/Tools/WorkspaceTools.php';
78154
include __DIR__ . '/../inc/Tools/WorkspaceDiffTools.php';
79155

@@ -130,12 +206,22 @@ public function execute( array $input ): array
130206
$ability = new DataMachineCodeWorkspaceAliasFakeAbility();
131207
$GLOBALS['dmc_workspace_alias_ability'] = $ability;
132208
$tools = new \DataMachineCode\Tools\WorkspaceTools();
209+
new \DataMachineCode\Abilities\WorkspaceAbilities();
133210
$read_definition = $tools->getReadDefinition();
134211
$grep_definition = $tools->getGrepDefinition();
212+
$edit_definition = $tools->getEditDefinition();
135213
$git_diff_definition = $tools->getGitDiffDefinition();
214+
$ability_edit_schema = $GLOBALS['dmc_workspace_alias_registered_abilities']['datamachine/workspace-edit']['input_schema'] ?? array();
136215
$assert('workspace_read schema allows path-only mounted workspace calls', array( 'path' ) === ( $read_definition['parameters']['required'] ?? null ));
137216
$assert('workspace_grep schema allows path-only mounted workspace calls', array( 'pattern' ) === ( $grep_definition['parameters']['required'] ?? null ));
138217
$assert('workspace_git_diff schema allows path-only mounted workspace calls', array() === ( $git_diff_definition['parameters']['required'] ?? null ));
218+
$assert('workspace_edit wrapper schema keeps edit text optional for aliases', array( 'path' ) === ( $edit_definition['parameters']['required'] ?? null ));
219+
$assert('workspace_edit ability schema keeps edit text optional for aliases', array( 'path' ) === ( $ability_edit_schema['required'] ?? null ));
220+
foreach ( array( 'old_string', 'new_string', 'search', 'replace', 'old', 'new' ) as $property ) {
221+
$assert("workspace_edit wrapper schema exposes {$property}", isset($edit_definition['parameters']['properties'][ $property ]));
222+
$assert("workspace_edit ability schema exposes {$property}", isset($ability_edit_schema['properties'][ $property ]));
223+
}
224+
$assert('workspace_edit schema does not expose broad find alias', ! isset($edit_definition['parameters']['properties']['find']) && ! isset($ability_edit_schema['properties']['find']));
139225

140226
$absolute_read = $tools->handleRead(array( 'path' => '/workspace/homeboy-extensions/wordpress/scripts/build/build.sh' ));
141227
$assert('absolute workspace path read succeeds', true === ( $absolute_read['success'] ?? false ));
@@ -174,6 +260,30 @@ public function execute( array $input ): array
174260
$assert('workspace_edit maps old to old_string', 'npm install --silent' === ( $ability->last_input['old_string'] ?? '' ));
175261
$assert('workspace_edit maps new to new_string', 'npm install --legacy-peer-deps' === ( $ability->last_input['new_string'] ?? '' ));
176262

263+
$ability_mounted_edit = \DataMachineCode\Abilities\WorkspaceAbilities::editFile(
264+
array(
265+
'path' => '/workspace/homeboy-extensions/wordpress/scripts/build/build.sh',
266+
'old' => 'npm install --silent',
267+
'new' => 'npm install --legacy-peer-deps',
268+
)
269+
);
270+
$assert('workspace_edit ability accepts mounted absolute path', ! is_wp_error($ability_mounted_edit) && true === ( $ability_mounted_edit['success'] ?? false ));
271+
$assert('workspace_edit ability infers repo from mounted path', 'homeboy-extensions' === ( $GLOBALS['dmc_workspace_alias_remote_edit_input']['handle'] ?? '' ));
272+
$assert('workspace_edit ability converts mounted path to relative path', 'wordpress/scripts/build/build.sh' === ( $GLOBALS['dmc_workspace_alias_remote_edit_input']['path'] ?? '' ));
273+
$assert('workspace_edit ability maps old alias to old_string', 'npm install --silent' === ( $GLOBALS['dmc_workspace_alias_remote_edit_input']['old_string'] ?? '' ));
274+
$assert('workspace_edit ability maps new alias to new_string', 'npm install --legacy-peer-deps' === ( $GLOBALS['dmc_workspace_alias_remote_edit_input']['new_string'] ?? '' ));
275+
276+
$unsupported_alias = \DataMachineCode\Abilities\WorkspaceAbilities::editFile(
277+
array(
278+
'repo' => 'homeboy-extensions',
279+
'path' => 'wordpress/scripts/build/build.sh',
280+
'find' => 'npm install --silent',
281+
'replace' => 'npm install --legacy-peer-deps',
282+
)
283+
);
284+
$assert('unsupported edit aliases fail at ability layer', is_wp_error($unsupported_alias));
285+
$assert('unsupported edit alias error is actionable', is_wp_error($unsupported_alias) && 'old_string is required.' === $unsupported_alias->get_error_message());
286+
177287
$result = $tools->handleGitStatus(array( 'name' => 'current-project' ));
178288
$data = $result['data'] ?? array();
179289

0 commit comments

Comments
 (0)