Skip to content
Merged
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
155 changes: 155 additions & 0 deletions inc/Abilities/WorkspaceAbilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use DataMachineCode\Support\PermissionHelper;
use DataMachineCode\Workspace\CleanupRunService;
use DataMachineCode\Workspace\RemoteWorkspaceBackend;
use DataMachineCode\Workspace\RunnerWorkspacePublisher;
use DataMachineCode\Workspace\Workspace;
use DataMachineCode\Workspace\WorkspaceReader;
use DataMachineCode\Workspace\WorkspaceWriter;
Expand All @@ -31,6 +32,12 @@
if ( ! class_exists(RuntimeCapabilities::class) ) {
require_once dirname(__DIR__) . '/Support/RuntimeCapabilities.php';
}
if ( ! class_exists(GitHubAbilities::class) ) {
require_once __DIR__ . '/GitHubAbilities.php';
}
if ( ! class_exists(RunnerWorkspacePublisher::class) ) {
require_once dirname(__DIR__) . '/Workspace/RunnerWorkspacePublisher.php';
}

class WorkspaceAbilities {

Expand Down Expand Up @@ -1043,6 +1050,20 @@ private function registerAbilities(): void {
)
);

AbilityRegistry::register(
'datamachine-code/publish-runner-workspace',
array(
'label' => 'Publish Runner Workspace',
'description' => 'Canonical Data Machine Code publication API for runner-owned workspace changes: stage/commit/push the workspace branch and open or reuse the pull request.',
'category' => 'datamachine-code-workspace',
'input_schema' => self::runnerWorkspacePublishInputSchema(),
'output_schema' => self::runnerWorkspacePublishOutputSchema(),
'execute_callback' => array( self::class, 'publishRunnerWorkspace' ),
'permission_callback' => fn() => PermissionHelper::can_manage(),
'meta' => array( 'show_in_rest' => false ),
)
);

AbilityRegistry::register(
'datamachine-code/workspace-git-rebase',
array(
Expand Down Expand Up @@ -3018,6 +3039,140 @@ public static function gitPush( array $input ): array|\WP_Error {
);
}

/**
* Publish runner-owned workspace changes through one canonical DMC API.
*
* @param array<string,mixed> $input Publication input.
* @return array<string,mixed>|\WP_Error
*/
public static function publishRunnerWorkspace( array $input ): array|\WP_Error {
return ( new RunnerWorkspacePublisher() )->publish($input);
}

/**
* @return array<string,mixed>
*/
private static function runnerWorkspacePublishInputSchema(): array {
return array(
'type' => 'object',
'required' => array( 'workspace_handle', 'target_repo', 'commit_message', 'pr_title' ),
'properties' => array(
'workspace_handle' => array(
'type' => 'string',
'description' => 'Workspace handle: <repo> or <repo>@<branch-slug>.',
),
'target_repo' => array(
'type' => 'string',
'description' => 'GitHub repository in owner/repo format for the pull request.',
),
'base' => array(
'type' => 'string',
'description' => 'Base branch/ref for the pull request.',
),
'base_branch' => array(
'type' => 'string',
'description' => 'Alias for base.',
),
'head' => array(
'type' => 'string',
'description' => 'Pull request head branch or owner:branch.',
),
'head_branch' => array(
'type' => 'string',
'description' => 'Head branch to push and publish.',
),
'branch' => array(
'type' => 'string',
'description' => 'Alias for head_branch.',
),
'commit_message' => array(
'type' => 'string',
'description' => 'Commit message for workspace changes.',
),
'pr_title' => array(
'type' => 'string',
'description' => 'Pull request title.',
),
'pr_body' => array(
'type' => 'string',
'description' => 'Pull request body.',
),
'labels' => array(
'type' => 'array',
'items' => array( 'type' => 'string' ),
'description' => 'Optional pull request labels.',
),
'draft' => array(
'type' => 'boolean',
'description' => 'Open the pull request as a draft.',
),
'maintainer_can_modify' => array(
'type' => 'boolean',
'description' => 'Allow maintainers to modify the pull request branch.',
),
'evidence_context' => array(
'type' => 'object',
'description' => 'Runner evidence metadata appended to the PR body and returned in the result.',
),
'artifact_context' => array(
'type' => 'object',
'description' => 'Alias for evidence_context.',
),
'run_artifacts' => array(
'type' => 'array',
'items' => array( 'type' => 'object' ),
'description' => 'Run artifacts forwarded to PR artifact egress handling.',
),
'run_artifact_policy' => array(
'type' => 'object',
'description' => 'Run artifact egress policy forwarded to PR creation.',
),
'paths' => array(
'type' => 'array',
'items' => array( 'type' => 'string' ),
'description' => 'Workspace paths to stage before commit. Defaults to all changes.',
),
'remote' => array(
'type' => 'string',
'description' => 'Git remote name for local workspaces. Default origin.',
),
'allow_primary_mutation' => array(
'type' => 'boolean',
'description' => 'Permit publication from a primary checkout. Default false.',
),
'force_with_lease' => array(
'type' => 'boolean',
'description' => 'Use --force-with-lease for local workspace push.',
),
'expected_sha' => array(
'type' => 'string',
'description' => 'Expected remote branch SHA for --force-with-lease.',
),
),
);
}

/**
* @return array<string,mixed>
*/
private static function runnerWorkspacePublishOutputSchema(): array {
return array(
'type' => 'object',
'properties' => array(
'success' => array( 'type' => 'boolean' ),
'kind' => array( 'type' => 'string' ),
'workspace' => array( 'type' => 'object' ),
'branch' => array( 'type' => 'object' ),
'commit' => array( 'type' => 'object' ),
'pull_request' => array( 'type' => 'object' ),
'evidence' => array( 'type' => 'object' ),
'message' => array( 'type' => 'string' ),
'failure_type' => array( 'type' => 'string' ),
'error' => array( 'type' => 'string' ),
),
);
}

/**
* Rebase a workspace repository.
*
Expand Down
124 changes: 124 additions & 0 deletions inc/Tools/WorkspaceTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public function __construct()
$this->registerTool('workspace_git_add', array( $this, 'getGitAddDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-git-add' ));
$this->registerTool('workspace_git_commit', array( $this, 'getGitCommitDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-git-commit' ));
$this->registerTool('workspace_git_push', array( $this, 'getGitPushDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-git-push' ));
$this->registerTool('workspace_publish_runner', array( $this, 'getPublishRunnerDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/publish-runner-workspace' ));
$this->registerTool('workspace_git_rebase', array( $this, 'getGitRebaseDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-git-rebase' ));
$this->registerTool('workspace_git_reset', array( $this, 'getGitResetDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-git-reset' ));
$this->registerTool('workspace_pr_status', array( $this, 'getPrStatusDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-pr-status' ));
Expand Down Expand Up @@ -608,6 +609,22 @@ public function handleGitPush( array $parameters ): array
return $this->executeAbility('datamachine-code/workspace-git-push', 'workspace_git_push', $input, array( 'name' ));
}

/**
* @param array<string,mixed> $parameters Tool parameters. @return array<string,mixed>
*/
public function handlePublishRunner( array $parameters ): array
{
$input = $parameters;
if (isset($parameters['name']) && ! isset($input['workspace_handle']) ) {
$input['workspace_handle'] = $parameters['name'];
}
if (isset($parameters['repo']) && ! isset($input['workspace_handle']) ) {
$input['workspace_handle'] = $parameters['repo'];
}

return $this->executeAbility('datamachine-code/publish-runner-workspace', 'workspace_publish_runner', $input, array( 'workspace_handle' ));
}

/**
* @param array<string,mixed> $parameters Tool parameters. @return array<string,mixed>
*/
Expand Down Expand Up @@ -1406,6 +1423,113 @@ public function getGitPushDefinition(): array
);
}

/**
* @return array<string,mixed>
*/
public function getPublishRunnerDefinition(): array
{
return $this->withRuntime(
array(
'class' => __CLASS__,
'method' => 'handlePublishRunner',
'description' => 'Publish runner-owned workspace changes through the canonical DMC API: stage, commit, push, then open or reuse a pull request.',
'parameters' => array(
'type' => 'object',
'required' => array( 'workspace_handle', 'target_repo', 'commit_message', 'pr_title' ),
'properties' => array(
'workspace_handle' => array(
'type' => 'string',
'description' => 'Workspace handle: <repo> or <repo>@<branch-slug>.',
),
'target_repo' => array(
'type' => 'string',
'description' => 'GitHub owner/repo for the PR.',
),
'base' => array(
'type' => 'string',
'description' => 'Base branch/ref.',
),
'head' => array(
'type' => 'string',
'description' => 'PR head branch or owner:branch.',
),
'head_branch' => array(
'type' => 'string',
'description' => 'Branch to push/publish.',
),
'branch' => array(
'type' => 'string',
'description' => 'Alias for head_branch.',
),
'commit_message' => array(
'type' => 'string',
'description' => 'Commit message.',
),
'pr_title' => array(
'type' => 'string',
'description' => 'Pull request title.',
),
'pr_body' => array(
'type' => 'string',
'description' => 'Pull request body.',
),
'labels' => array(
'type' => 'array',
'items' => array( 'type' => 'string' ),
'description' => 'Optional PR labels.',
),
'draft' => array(
'type' => 'boolean',
'description' => 'Open as draft.',
),
'maintainer_can_modify' => array(
'type' => 'boolean',
'description' => 'Allow maintainers to modify.',
),
'evidence_context' => array(
'type' => 'object',
'description' => 'Runner evidence/artifact context.',
),
'artifact_context' => array(
'type' => 'object',
'description' => 'Alias for evidence_context.',
),
'run_artifacts' => array(
'type' => 'array',
'items' => array( 'type' => 'object' ),
'description' => 'Run artifacts forwarded to PR artifact handling.',
),
'run_artifact_policy' => array(
'type' => 'object',
'description' => 'Artifact egress policy.',
),
'paths' => array(
'type' => 'array',
'items' => array( 'type' => 'string' ),
'description' => 'Paths to stage. Defaults to all.',
),
'remote' => array(
'type' => 'string',
'description' => 'Git remote for local workspaces.',
),
'allow_primary_mutation' => array(
'type' => 'boolean',
'description' => 'Permit primary checkout publication.',
),
'force_with_lease' => array(
'type' => 'boolean',
'description' => 'Use --force-with-lease.',
),
'expected_sha' => array(
'type' => 'string',
'description' => 'Expected remote branch SHA.',
),
),
),
), array( 'completion_signal' => 'complete' )
);
}

/**
* @return array<string,mixed>
*/
Expand Down
Loading
Loading