Skip to content

Commit 51657e8

Browse files
authored
Add runner workspace publication API (#626)
* add runner workspace publication API * fix runner publication lint
1 parent 9e4dfe4 commit 51657e8

4 files changed

Lines changed: 712 additions & 0 deletions

File tree

inc/Abilities/WorkspaceAbilities.php

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use DataMachineCode\Support\PermissionHelper;
1818
use DataMachineCode\Workspace\CleanupRunService;
1919
use DataMachineCode\Workspace\RemoteWorkspaceBackend;
20+
use DataMachineCode\Workspace\RunnerWorkspacePublisher;
2021
use DataMachineCode\Workspace\Workspace;
2122
use DataMachineCode\Workspace\WorkspaceReader;
2223
use DataMachineCode\Workspace\WorkspaceWriter;
@@ -31,6 +32,12 @@
3132
if ( ! class_exists(RuntimeCapabilities::class) ) {
3233
require_once dirname(__DIR__) . '/Support/RuntimeCapabilities.php';
3334
}
35+
if ( ! class_exists(GitHubAbilities::class) ) {
36+
require_once __DIR__ . '/GitHubAbilities.php';
37+
}
38+
if ( ! class_exists(RunnerWorkspacePublisher::class) ) {
39+
require_once dirname(__DIR__) . '/Workspace/RunnerWorkspacePublisher.php';
40+
}
3441

3542
class WorkspaceAbilities {
3643

@@ -1043,6 +1050,20 @@ private function registerAbilities(): void {
10431050
)
10441051
);
10451052

1053+
AbilityRegistry::register(
1054+
'datamachine-code/publish-runner-workspace',
1055+
array(
1056+
'label' => 'Publish Runner Workspace',
1057+
'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.',
1058+
'category' => 'datamachine-code-workspace',
1059+
'input_schema' => self::runnerWorkspacePublishInputSchema(),
1060+
'output_schema' => self::runnerWorkspacePublishOutputSchema(),
1061+
'execute_callback' => array( self::class, 'publishRunnerWorkspace' ),
1062+
'permission_callback' => fn() => PermissionHelper::can_manage(),
1063+
'meta' => array( 'show_in_rest' => false ),
1064+
)
1065+
);
1066+
10461067
AbilityRegistry::register(
10471068
'datamachine-code/workspace-git-rebase',
10481069
array(
@@ -3018,6 +3039,140 @@ public static function gitPush( array $input ): array|\WP_Error {
30183039
);
30193040
}
30203041

3042+
/**
3043+
* Publish runner-owned workspace changes through one canonical DMC API.
3044+
*
3045+
* @param array<string,mixed> $input Publication input.
3046+
* @return array<string,mixed>|\WP_Error
3047+
*/
3048+
public static function publishRunnerWorkspace( array $input ): array|\WP_Error {
3049+
return ( new RunnerWorkspacePublisher() )->publish($input);
3050+
}
3051+
3052+
/**
3053+
* @return array<string,mixed>
3054+
*/
3055+
private static function runnerWorkspacePublishInputSchema(): array {
3056+
return array(
3057+
'type' => 'object',
3058+
'required' => array( 'workspace_handle', 'target_repo', 'commit_message', 'pr_title' ),
3059+
'properties' => array(
3060+
'workspace_handle' => array(
3061+
'type' => 'string',
3062+
'description' => 'Workspace handle: <repo> or <repo>@<branch-slug>.',
3063+
),
3064+
'target_repo' => array(
3065+
'type' => 'string',
3066+
'description' => 'GitHub repository in owner/repo format for the pull request.',
3067+
),
3068+
'base' => array(
3069+
'type' => 'string',
3070+
'description' => 'Base branch/ref for the pull request.',
3071+
),
3072+
'base_branch' => array(
3073+
'type' => 'string',
3074+
'description' => 'Alias for base.',
3075+
),
3076+
'head' => array(
3077+
'type' => 'string',
3078+
'description' => 'Pull request head branch or owner:branch.',
3079+
),
3080+
'head_branch' => array(
3081+
'type' => 'string',
3082+
'description' => 'Head branch to push and publish.',
3083+
),
3084+
'branch' => array(
3085+
'type' => 'string',
3086+
'description' => 'Alias for head_branch.',
3087+
),
3088+
'commit_message' => array(
3089+
'type' => 'string',
3090+
'description' => 'Commit message for workspace changes.',
3091+
),
3092+
'pr_title' => array(
3093+
'type' => 'string',
3094+
'description' => 'Pull request title.',
3095+
),
3096+
'pr_body' => array(
3097+
'type' => 'string',
3098+
'description' => 'Pull request body.',
3099+
),
3100+
'labels' => array(
3101+
'type' => 'array',
3102+
'items' => array( 'type' => 'string' ),
3103+
'description' => 'Optional pull request labels.',
3104+
),
3105+
'draft' => array(
3106+
'type' => 'boolean',
3107+
'description' => 'Open the pull request as a draft.',
3108+
),
3109+
'maintainer_can_modify' => array(
3110+
'type' => 'boolean',
3111+
'description' => 'Allow maintainers to modify the pull request branch.',
3112+
),
3113+
'evidence_context' => array(
3114+
'type' => 'object',
3115+
'description' => 'Runner evidence metadata appended to the PR body and returned in the result.',
3116+
),
3117+
'artifact_context' => array(
3118+
'type' => 'object',
3119+
'description' => 'Alias for evidence_context.',
3120+
),
3121+
'run_artifacts' => array(
3122+
'type' => 'array',
3123+
'items' => array( 'type' => 'object' ),
3124+
'description' => 'Run artifacts forwarded to PR artifact egress handling.',
3125+
),
3126+
'run_artifact_policy' => array(
3127+
'type' => 'object',
3128+
'description' => 'Run artifact egress policy forwarded to PR creation.',
3129+
),
3130+
'paths' => array(
3131+
'type' => 'array',
3132+
'items' => array( 'type' => 'string' ),
3133+
'description' => 'Workspace paths to stage before commit. Defaults to all changes.',
3134+
),
3135+
'remote' => array(
3136+
'type' => 'string',
3137+
'description' => 'Git remote name for local workspaces. Default origin.',
3138+
),
3139+
'allow_primary_mutation' => array(
3140+
'type' => 'boolean',
3141+
'description' => 'Permit publication from a primary checkout. Default false.',
3142+
),
3143+
'force_with_lease' => array(
3144+
'type' => 'boolean',
3145+
'description' => 'Use --force-with-lease for local workspace push.',
3146+
),
3147+
'expected_sha' => array(
3148+
'type' => 'string',
3149+
'description' => 'Expected remote branch SHA for --force-with-lease.',
3150+
),
3151+
),
3152+
);
3153+
}
3154+
3155+
/**
3156+
* @return array<string,mixed>
3157+
*/
3158+
private static function runnerWorkspacePublishOutputSchema(): array {
3159+
return array(
3160+
'type' => 'object',
3161+
'properties' => array(
3162+
'success' => array( 'type' => 'boolean' ),
3163+
'kind' => array( 'type' => 'string' ),
3164+
'workspace' => array( 'type' => 'object' ),
3165+
'branch' => array( 'type' => 'object' ),
3166+
'commit' => array( 'type' => 'object' ),
3167+
'pull_request' => array( 'type' => 'object' ),
3168+
'evidence' => array( 'type' => 'object' ),
3169+
'message' => array( 'type' => 'string' ),
3170+
'failure_type' => array( 'type' => 'string' ),
3171+
'error' => array( 'type' => 'string' ),
3172+
),
3173+
);
3174+
}
3175+
30213176
/**
30223177
* Rebase a workspace repository.
30233178
*

inc/Tools/WorkspaceTools.php

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public function __construct()
9898
$this->registerTool('workspace_git_add', array( $this, 'getGitAddDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-git-add' ));
9999
$this->registerTool('workspace_git_commit', array( $this, 'getGitCommitDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-git-commit' ));
100100
$this->registerTool('workspace_git_push', array( $this, 'getGitPushDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-git-push' ));
101+
$this->registerTool('workspace_publish_runner', array( $this, 'getPublishRunnerDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/publish-runner-workspace' ));
101102
$this->registerTool('workspace_git_rebase', array( $this, 'getGitRebaseDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-git-rebase' ));
102103
$this->registerTool('workspace_git_reset', array( $this, 'getGitResetDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-git-reset' ));
103104
$this->registerTool('workspace_pr_status', array( $this, 'getPrStatusDefinition' ), $policy_contexts, $policy_meta + array( 'ability' => 'datamachine-code/workspace-pr-status' ));
@@ -608,6 +609,22 @@ public function handleGitPush( array $parameters ): array
608609
return $this->executeAbility('datamachine-code/workspace-git-push', 'workspace_git_push', $input, array( 'name' ));
609610
}
610611

612+
/**
613+
* @param array<string,mixed> $parameters Tool parameters. @return array<string,mixed>
614+
*/
615+
public function handlePublishRunner( array $parameters ): array
616+
{
617+
$input = $parameters;
618+
if (isset($parameters['name']) && ! isset($input['workspace_handle']) ) {
619+
$input['workspace_handle'] = $parameters['name'];
620+
}
621+
if (isset($parameters['repo']) && ! isset($input['workspace_handle']) ) {
622+
$input['workspace_handle'] = $parameters['repo'];
623+
}
624+
625+
return $this->executeAbility('datamachine-code/publish-runner-workspace', 'workspace_publish_runner', $input, array( 'workspace_handle' ));
626+
}
627+
611628
/**
612629
* @param array<string,mixed> $parameters Tool parameters. @return array<string,mixed>
613630
*/
@@ -1406,6 +1423,113 @@ public function getGitPushDefinition(): array
14061423
);
14071424
}
14081425

1426+
/**
1427+
* @return array<string,mixed>
1428+
*/
1429+
public function getPublishRunnerDefinition(): array
1430+
{
1431+
return $this->withRuntime(
1432+
array(
1433+
'class' => __CLASS__,
1434+
'method' => 'handlePublishRunner',
1435+
'description' => 'Publish runner-owned workspace changes through the canonical DMC API: stage, commit, push, then open or reuse a pull request.',
1436+
'parameters' => array(
1437+
'type' => 'object',
1438+
'required' => array( 'workspace_handle', 'target_repo', 'commit_message', 'pr_title' ),
1439+
'properties' => array(
1440+
'workspace_handle' => array(
1441+
'type' => 'string',
1442+
'description' => 'Workspace handle: <repo> or <repo>@<branch-slug>.',
1443+
),
1444+
'target_repo' => array(
1445+
'type' => 'string',
1446+
'description' => 'GitHub owner/repo for the PR.',
1447+
),
1448+
'base' => array(
1449+
'type' => 'string',
1450+
'description' => 'Base branch/ref.',
1451+
),
1452+
'head' => array(
1453+
'type' => 'string',
1454+
'description' => 'PR head branch or owner:branch.',
1455+
),
1456+
'head_branch' => array(
1457+
'type' => 'string',
1458+
'description' => 'Branch to push/publish.',
1459+
),
1460+
'branch' => array(
1461+
'type' => 'string',
1462+
'description' => 'Alias for head_branch.',
1463+
),
1464+
'commit_message' => array(
1465+
'type' => 'string',
1466+
'description' => 'Commit message.',
1467+
),
1468+
'pr_title' => array(
1469+
'type' => 'string',
1470+
'description' => 'Pull request title.',
1471+
),
1472+
'pr_body' => array(
1473+
'type' => 'string',
1474+
'description' => 'Pull request body.',
1475+
),
1476+
'labels' => array(
1477+
'type' => 'array',
1478+
'items' => array( 'type' => 'string' ),
1479+
'description' => 'Optional PR labels.',
1480+
),
1481+
'draft' => array(
1482+
'type' => 'boolean',
1483+
'description' => 'Open as draft.',
1484+
),
1485+
'maintainer_can_modify' => array(
1486+
'type' => 'boolean',
1487+
'description' => 'Allow maintainers to modify.',
1488+
),
1489+
'evidence_context' => array(
1490+
'type' => 'object',
1491+
'description' => 'Runner evidence/artifact context.',
1492+
),
1493+
'artifact_context' => array(
1494+
'type' => 'object',
1495+
'description' => 'Alias for evidence_context.',
1496+
),
1497+
'run_artifacts' => array(
1498+
'type' => 'array',
1499+
'items' => array( 'type' => 'object' ),
1500+
'description' => 'Run artifacts forwarded to PR artifact handling.',
1501+
),
1502+
'run_artifact_policy' => array(
1503+
'type' => 'object',
1504+
'description' => 'Artifact egress policy.',
1505+
),
1506+
'paths' => array(
1507+
'type' => 'array',
1508+
'items' => array( 'type' => 'string' ),
1509+
'description' => 'Paths to stage. Defaults to all.',
1510+
),
1511+
'remote' => array(
1512+
'type' => 'string',
1513+
'description' => 'Git remote for local workspaces.',
1514+
),
1515+
'allow_primary_mutation' => array(
1516+
'type' => 'boolean',
1517+
'description' => 'Permit primary checkout publication.',
1518+
),
1519+
'force_with_lease' => array(
1520+
'type' => 'boolean',
1521+
'description' => 'Use --force-with-lease.',
1522+
),
1523+
'expected_sha' => array(
1524+
'type' => 'string',
1525+
'description' => 'Expected remote branch SHA.',
1526+
),
1527+
),
1528+
),
1529+
), array( 'completion_signal' => 'complete' )
1530+
);
1531+
}
1532+
14091533
/**
14101534
* @return array<string,mixed>
14111535
*/

0 commit comments

Comments
 (0)