diff --git a/inc/Abilities/WorkspaceAbilities.php b/inc/Abilities/WorkspaceAbilities.php index 4ac040c..2deece2 100644 --- a/inc/Abilities/WorkspaceAbilities.php +++ b/inc/Abilities/WorkspaceAbilities.php @@ -194,17 +194,17 @@ private function registerAbilities(): void { 'output_schema' => array( 'type' => 'object', 'properties' => array( - 'success' => array( 'type' => 'boolean' ), - 'name' => array( 'type' => 'string' ), - 'repo' => array( 'type' => 'string' ), - 'is_worktree' => array( 'type' => 'boolean' ), - 'path' => array( 'type' => 'string' ), + 'success' => array( 'type' => 'boolean' ), + 'name' => array( 'type' => 'string' ), + 'repo' => array( 'type' => 'string' ), + 'is_worktree' => array( 'type' => 'boolean' ), + 'path' => array( 'type' => 'string' ), // Nullable: detached HEAD has no branch; local-only repos // have no remote; freshly-init'd repos have no commit yet. - 'branch' => array( 'type' => array( 'string', 'null' ) ), - 'remote' => array( 'type' => array( 'string', 'null' ) ), - 'commit' => array( 'type' => array( 'string', 'null' ) ), - 'dirty' => array( 'type' => 'integer' ), + 'branch' => array( 'type' => array( 'string', 'null' ) ), + 'remote' => array( 'type' => array( 'string', 'null' ) ), + 'commit' => array( 'type' => array( 'string', 'null' ) ), + 'dirty' => array( 'type' => 'integer' ), 'primary_freshness' => self::primaryFreshnessSchema(), ), ), @@ -390,19 +390,19 @@ private function registerAbilities(): void { 'input_schema' => array( 'type' => 'object', 'properties' => array( - 'url' => array( + 'url' => array( 'type' => 'string', 'description' => 'Git repository URL to clone.', ), - 'name' => array( + 'name' => array( 'type' => 'string', 'description' => 'Directory name override (derived from URL if omitted).', ), - 'full' => array( + 'full' => array( 'type' => 'boolean', 'description' => 'Disable the default blobless partial clone for remote repositories.', ), - 'auth_token_env' => array( + 'auth_token_env' => array( 'type' => 'string', 'description' => 'Optional environment variable name containing a bearer token for HTTPS clone authentication.', ), @@ -2665,6 +2665,7 @@ public static function removeRepo( array $input ): array|\WP_Error { * @return array Result. */ public static function writeFile( array $input ): array|\WP_Error { + $input = self::normalize_mounted_workspace_path_input($input, array( 'repo' )); if ( RemoteWorkspaceBackend::should_handle() ) { $result = ( new RemoteWorkspaceBackend() )->write_file( $input['repo'] ?? '', diff --git a/tests/smoke-workspace-alias-tools.php b/tests/smoke-workspace-alias-tools.php index 4dc66a6..7e0b2fd 100644 --- a/tests/smoke-workspace-alias-tools.php +++ b/tests/smoke-workspace-alias-tools.php @@ -19,6 +19,7 @@ $GLOBALS['dmc_workspace_alias_ability'] = null; $GLOBALS['dmc_workspace_alias_registered_abilities'] = array(); $GLOBALS['dmc_workspace_alias_remote_edit_input'] = array(); + $GLOBALS['dmc_workspace_alias_remote_write_input'] = array(); function add_filter( string $tag, callable $callback, int $priority = 10, int $accepted_args = 1 ): void { @@ -127,6 +128,16 @@ public function edit_file( string $handle, string $path, string $old_string, str 'replacements' => 1, ); } + + public function write_file( string $handle, string $path, string $content ): array + { + $GLOBALS['dmc_workspace_alias_remote_write_input'] = compact('handle', 'path', 'content'); + return array( + 'success' => true, + 'name' => $handle, + 'path' => $path, + ); + } } } @@ -273,6 +284,17 @@ public function execute( array $input ): array $assert('workspace_edit ability maps old alias to old_string', 'npm install --silent' === ( $GLOBALS['dmc_workspace_alias_remote_edit_input']['old_string'] ?? '' )); $assert('workspace_edit ability maps new alias to new_string', 'npm install --legacy-peer-deps' === ( $GLOBALS['dmc_workspace_alias_remote_edit_input']['new_string'] ?? '' )); + $ability_mounted_write = \DataMachineCode\Abilities\WorkspaceAbilities::writeFile( + array( + 'path' => '/workspace/example-plugin/wordpress/scripts/build/generated.sh', + 'content' => '#!/bin/sh', + ) + ); + $assert('workspace_write ability accepts mounted absolute path', ! is_wp_error($ability_mounted_write) && true === ( $ability_mounted_write['success'] ?? false )); + $assert('workspace_write ability infers repo from mounted path', 'example-plugin' === ( $GLOBALS['dmc_workspace_alias_remote_write_input']['handle'] ?? '' )); + $assert('workspace_write ability converts mounted path to relative path', 'wordpress/scripts/build/generated.sh' === ( $GLOBALS['dmc_workspace_alias_remote_write_input']['path'] ?? '' )); + $assert('workspace_write ability preserves content', '#!/bin/sh' === ( $GLOBALS['dmc_workspace_alias_remote_write_input']['content'] ?? '' )); + $unsupported_alias = \DataMachineCode\Abilities\WorkspaceAbilities::editFile( array( 'repo' => 'example-plugin',