feat(create-pr): align with gh-aw create-pull-request implementation#155
feat(create-pr): align with gh-aw create-pull-request implementation#155jamesadevine wants to merge 3 commits intomainfrom
Conversation
Closes the gap between ado-aw and gh-aw's create-pull-request safe output: Security/Correctness: - Add file protection system blocking manifests (package.json, go.mod, Cargo.toml, etc.), CI configs (.github/, .pipelines/), and agent instruction files (.agents/, .claude/, .copilot/) by default - Add max-files limit per PR (default: 100, configurable) - Add 3-way merge fallback when patch application fails on conflicts - Replace predictable timestamp-based branch suffix with cryptographic random hex (rand crate) Feature Parity: - Add draft PR support (default: true, operator-enforced via isDraft) - Add fallback-as-work-item: record branch info on PR creation failure - Add excluded-files glob config to filter files from patches - Add if-no-changes config (warn/error/ignore) for empty patches - Add allowed-labels allowlist to restrict agent-provided labels - Add title-prefix config for operator branding - Add agent-provided labels parameter validated against allowed-labels Patch Format: - Migrate from raw git diff to git format-patch for proper commit metadata, rename detection, and binary file handling - Stage 2 applies patches via git am --3way with git apply fallback - Add collect_changes_from_diff_tree for committed patch changes - Add git to default bash command allowlist so agents can commit - Update tool description to encourage staging commits before PR creation Other: - Add provenance footer to PR body with timestamp and compiler version - Add ExecutionResult::failure_with_data for structured error responses Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
0b26f4d to
3caf5d7
Compare
🔍 Rust PR ReviewSummary: Mostly solid — the feature parity work is well-structured and the security additions are a real improvement — but there are two correctness bugs and an edge case worth addressing before merge. Findings🐛 Bugs / Logic Issues
|
- Fix if-no-changes 'warn' mode: add ExecutionResult::warning() with dedicated exit code 2. Pipeline step maps exit code 2 to ##vso[task.complete result=SucceededWithIssues;] for yellow badge. Previously 'warn' was identical to 'error' (both returned failure). - Propagate git reset HEAD~1 failure in generate_patch instead of silently swallowing it. A failed reset would leave a synthetic commit in the repo, breaking subsequent operations. - Fix path extraction for filenames with spaces: switch extract_paths_from_patch and filter_excluded_files_from_patch from parsing 'diff --git' headers (breaks on quoted paths) to using '--- a/' and '+++ b/' lines which handle spaces correctly. - Remove dead find_disallowed_files function (was cfg(test) only, never wired into production executor). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔍 Rust PR ReviewSummary: Needs changes — good security additions, but the patch generation approach has a fundamental design conflict between the implementation and the updated tool description, plus binary file support is incomplete despite being claimed. Findings🐛 Bugs / Logic Issues
|
… globs, validation - Fix format-patch to capture both committed and uncommitted changes by diffing against merge-base instead of only the last synthetic commit. Previously, if the agent committed changes per the tool description, the working tree was clean and format-patch produced an empty patch. - Add git identity flags (-c user.email/user.name) to synthetic commit to avoid "Please tell me who you are" errors in fresh environments. - Handle binary files in Stage 2 by falling back to base64 encoding when read_to_string fails (non-UTF-8 content). Uses ADO API contentType: "base64encoded" for binary files. - Fix renamed+modified files losing content changes. When diff-tree reports R<score> with score < 100, emit both a rename and an edit change entry with the new file content. - Fix fragile success_count - warning_count usize subtraction in execution summary. Count success as success && !warning directly instead of subtracting, preventing potential underflow. - Normalize excluded-files glob patterns by auto-prepending **/ to patterns without /, so *.lock matches subdir/Cargo.lock. - Validate if-no-changes and protected-files string values at execution time, rejecting typos with a clear error message. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔍 Rust PR ReviewSummary: Solid implementation with good security thinking, but has one correctness bug in the merge-base fallback, a misleading feature name, and a couple of edge cases worth addressing. Findings🐛 Bugs / Logic Issues
|
Summary
Closes the gap between ado-aw and gh-aw's
create-pull-requestsafe output implementation. Identified via a systematic comparison of both codebases.Security/Correctness
package.json,go.mod,Cargo.toml, etc.), CI configs (.github/,.pipelines/), and agent instruction files (.agents/,.claude/,.copilot/) by default. Override withprotected-files: allowed.max-files)git am --3waywithgit apply --3wayfallback instead of hard failurerandcrate instead of predictable timestampFeature Parity
draft: true, operator-enforced via ADOisDraftfieldexcluded-files:glob patterns strip files from patches before applicationif-no-changes: warn|error|ignorecontrols behavior on empty patcheslabelsin tool params, validated againstallowed-labelsallowlist. Operatorlabelsalways applied unconditionally.title-prefix: "[Bot] "prepended to all PR titlesPatch Format Upgrade
git difftogit format-patchfor proper commit metadata, rename detection, and binary file handlinggit am --3waywithgit apply --3wayfallbackgitto default bash command allowlist so agents can commitOther
ExecutionResult::failure_with_datafor structured error responsesNew Config Fields
Testing
All 651 tests pass (599 unit + 35 compiler + 8 mcp-http + 9 proxy).