Skip to content

feat(workflow): add pull request node - #650

Draft
brynary wants to merge 1 commit into
mainfrom
feat/in-run-pull-request
Draft

feat(workflow): add pull request node#650
brynary wants to merge 1 commit into
mainfrom
feat/in-run-pull-request

Conversation

@brynary

@brynary brynary commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

  • add a built-in type="pull_request" workflow node that creates or links a draft PR during a run and exposes its metadata through pull_request.* context
  • capture only the latest committed run snapshot, push the exact commit safely, validate remote ancestry, and reject unsupported parallel or non-GitHub contexts
  • allow fabro pr create --force to use eligible active or failed-run snapshots while preserving the existing terminal-only default behavior
  • make GitHub PR creation idempotent, including create-race recovery, and have post-run handling reuse an in-run PR instead of creating or mutating a duplicate
  • document the node and update the OpenAPI contract, generated TypeScript client, CLI help, events, and tests

An in-run PR intentionally remains draft. Post-run handling returns its URL without refreshing the body, marking it ready, or enabling auto-merge.

Verification

  • cargo +nightly-2026-04-14 fmt --check --all
  • cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings
  • cargo build --workspace
  • cargo nextest run -p fabro-workflow
  • cargo nextest run -p fabro-server
  • cargo nextest run -p fabro-cli
  • cargo nextest run -p fabro-github
  • cargo nextest run -p fabro-validate
  • bun run generate and bun run typecheck in lib/packages/fabro-api-client
  • git diff --check
  • no pending insta snapshots

Copilot AI review requested due to automatic review settings July 26, 2026 12:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a first-class type="pull_request" workflow node and expands PR-creation plumbing so runs can create/adopt a draft GitHub PR mid-run (with committed-snapshot safety) while keeping PR creation idempotent and consistent across workflow engine, server API, CLI, and generated clients.

Changes:

  • Introduces a new pull_request stage handler type end-to-end (Rust types, workflow registry, OpenAPI + generated TS client).
  • Adds “latest committed snapshot” support for --force/force=true PR creation while runs are active (running/blocked/paused), including remote ancestry validation.
  • Makes PR creation idempotent by detecting/linking an existing matching open PR and handling GitHub 422 create races.

Reviewed changes

Copilot reviewed 31 out of 32 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
lib/packages/fabro-api-client/src/models/stage-handler.ts Adds PULL_REQUEST stage handler wire value to TS client model.
lib/packages/fabro-api-client/src/models/create-run-pull-request-request.ts Updates TS client docs for force behavior (active snapshot + non-successful conclusions).
lib/packages/fabro-api-client/src/api/runs-api.ts Updates TS client endpoint docs to match new server semantics.
lib/foundation/fabro-types/tests/stage_handler.rs Extends stage-handler serialization/mapping tests for pull_request.
lib/foundation/fabro-types/src/stage_handler.rs Adds StageHandler::PullRequest and handler-type mapping.
lib/foundation/fabro-types/src/graph.rs Adds pull_request to known handler types.
lib/foundation/fabro-api/tests/stage_handler_round_trip.rs Ensures OpenAPI round-trip supports pull_request handler value.
lib/components/fabro-workflow/src/services.rs Threads run-scoped PR runtime inputs through RunServices.
lib/components/fabro-workflow/src/pull_request.rs Re-exports new snapshot/idempotency PR pipeline primitives.
lib/components/fabro-workflow/src/pipeline/pull_request.rs Implements committed snapshot capture + remote verification and idempotent PR open/link behavior.
lib/components/fabro-workflow/src/pipeline/mod.rs Re-exports new PR pipeline APIs.
lib/components/fabro-workflow/src/pipeline/initialize.rs Populates PullRequestRuntime from run options + sandbox env and injects into services.
lib/components/fabro-workflow/src/handler/pull_request.rs New built-in workflow node handler that creates/adopts a draft PR and exports pull_request.* context keys.
lib/components/fabro-workflow/src/handler/mod.rs Registers the new pull_request handler in the default registry.
lib/components/fabro-workflow/src/context.rs Adds pull_request.* workflow context keys.
lib/components/fabro-github/src/lib.rs Adds find_open_pull_request and structured create error for 422 race reconciliation.
lib/components/fabro-github/Cargo.toml Adds url dependency for query encoding in PR lookup.
lib/apps/fabro-server/src/server/tests.rs Expands server test coverage for PR adoption/idempotency and active snapshot force behavior.
lib/apps/fabro-server/src/server/handler/pull_requests.rs Extends PR create endpoint to support active committed snapshots and linking existing PRs.
lib/apps/fabro-server/src/run_files.rs Exposes reconnect_run_sandbox for server-side active snapshot creation.
lib/apps/fabro-cli/tests/it/cmd/pr.rs Updates CLI help text to reflect “from a run” semantics.
lib/apps/fabro-cli/tests/it/cmd/pr_create.rs Updates CLI help text for --force meaning.
lib/apps/fabro-cli/src/commands/run/runner.rs Soft-loads GitHub creds when graph contains an explicit pull_request node.
lib/apps/fabro-cli/src/commands/pr/create.rs Updates logging message to “Created or linked” PR semantics.
lib/apps/fabro-cli/src/args.rs Updates CLI arg docs and subcommand docs for PR create behavior.
docs/public/workflows/stages-and-nodes.mdx Documents the new type="pull_request" node and its semantics/requirements.
docs/public/reference/dot-language.mdx Adds pull_request as an explicit node type and documents attributes/constraints.
docs/public/reference/cli.mdx Updates CLI docs for fabro pr create and --force.
docs/public/execution/run-configuration.mdx Notes pull_request node requires run branch enabled + pushed.
docs/public/execution/context.mdx Documents pull_request.* context keys emitted by the node.
docs/public/api-reference/fabro-api.yaml Updates OpenAPI description and handler enum; clarifies force behavior and responses.
Cargo.lock Locks the new url dependency addition.
Comments suppressed due to low confidence (1)

lib/components/fabro-workflow/src/handler/pull_request.rs:126

  • When a run already has a stored pull request link, the handler falls back to base_branch="main" and head_branch="" if runtime capability is missing. That can publish incorrect pull_request.base_branch/pull_request.head_branch context (and an empty head branch) even though the run projection already carries git branch + run branch metadata.
            if let Some(link) = run_state.pull_request.as_ref() {
                let runtime = services.run.pull_request.as_ref();
                let base_branch = runtime
                    .and_then(|runtime| runtime.base_branch.as_deref())
                    .unwrap_or("main");
                let head_branch = runtime
                    .and_then(|runtime| runtime.head_branch.as_deref())
                    .unwrap_or("");
                return Ok(outcome_for_pull_request(link, base_branch, head_branch));

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +616 to +618
/// Capture the sandbox's committed `HEAD`, compute the cumulative diff from
/// `base_sha` to that exact commit, and ensure that commit is present on the
/// remote run branch. Dirty and untracked work is intentionally excluded.
Comment on lines +195 to +200
if !force {
return Err(ApiError::with_code(
StatusCode::BAD_REQUEST,
"Run is not finished yet. Pass --force to use its latest committed snapshot.",
"run_not_finished",
));
Comment on lines +64 to +73
fn validate_github_origin(origin_url: &str) -> Result<(), Error> {
let https_url = fabro_github::ssh_url_to_https(origin_url);
fabro_github::parse_github_owner_repo(&https_url)
.map(|_| ())
.map_err(|_| {
Error::Precondition(
"pull_request nodes require a valid github.com repo origin".to_string(),
)
})
}
@brynary brynary changed the title feat(workflow): add pull request stage feat(workflow): add pull request node Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants