Skip to content

Commit 0de0504

Browse files
hyperpolymathclaude
andcommitted
feat: enable auto-merge on bot-created PRs
- robot-repo-automaton: enable_auto_merge() via GraphQL after PR creation - fleet-coordinator.sh: gh pr merge --auto --squash after PR creation - 10 key repos: allow_auto_merge=true enabled via GitHub API PRs now merge automatically when CI passes. No manual merge needed for bot-generated fixes (RSR compliance, security, dependencies). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent fec7a99 commit 0de0504

3 files changed

Lines changed: 85 additions & 0 deletions

File tree

fleet-coordinator.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,12 @@ PR_BODY
615615
)" \
616616
--repo hyperpolymath/hypatia 2>/dev/null && {
617617
log_bot "hypatia" " ✓ Rule approval PR created"
618+
# Enable auto-merge — PR merges automatically when CI passes
619+
gh pr merge --auto --squash --repo hyperpolymath/hypatia 2>/dev/null && {
620+
log_bot "hypatia" " ✓ Auto-merge enabled (squash on CI pass)"
621+
} || {
622+
log_bot "hypatia" " ⚠ Auto-merge not available (repo setting may be off)"
623+
}
618624
}
619625
fi
620626

robot-repo-automaton/src/github.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,81 @@ impl GitHubClient {
182182
Ok(pull_request)
183183
}
184184

185+
/// Enable auto-merge on a pull request (squash strategy).
186+
///
187+
/// Uses the GitHub GraphQL API because the REST API does not support
188+
/// enabling auto-merge. The PR will merge automatically once all
189+
/// required status checks pass.
190+
pub async fn enable_auto_merge(&self, repo: &str, pr_number: u64) -> Result<()> {
191+
// First get the PR node_id via REST (needed for GraphQL mutation)
192+
let pr_url = format!(
193+
"{}/repos/{}/{}/pulls/{}",
194+
self.base_url, self.org, repo, pr_number
195+
);
196+
197+
let response = self
198+
.client
199+
.get(&pr_url)
200+
.send()
201+
.await?
202+
.error_for_status()
203+
.map_err(|e| Error::GitHub(e.to_string()))?;
204+
205+
#[derive(Deserialize)]
206+
struct PrNodeId {
207+
node_id: String,
208+
}
209+
210+
let pr_info: PrNodeId = response.json().await?;
211+
212+
// GraphQL mutation to enable auto-merge
213+
let graphql_url = "https://api.github.com/graphql";
214+
215+
#[derive(Serialize)]
216+
struct GraphQLRequest {
217+
query: String,
218+
}
219+
220+
let mutation = GraphQLRequest {
221+
query: format!(
222+
r#"mutation {{
223+
enablePullRequestAutoMerge(input: {{
224+
pullRequestId: "{}",
225+
mergeMethod: SQUASH
226+
}}) {{
227+
pullRequest {{
228+
autoMergeRequest {{
229+
enabledAt
230+
}}
231+
}}
232+
}}
233+
}}"#,
234+
pr_info.node_id
235+
),
236+
};
237+
238+
let result = self
239+
.client
240+
.post(graphql_url)
241+
.json(&mutation)
242+
.send()
243+
.await?;
244+
245+
if result.status().is_success() {
246+
info!("Enabled auto-merge (squash) on PR #{} in {}", pr_number, repo);
247+
} else {
248+
let status = result.status();
249+
let body = result.text().await.unwrap_or_default();
250+
debug!("Auto-merge request returned {}: {}", status, body);
251+
info!(
252+
"Auto-merge not available for PR #{} in {} (repo may not have it enabled)",
253+
pr_number, repo
254+
);
255+
}
256+
257+
Ok(())
258+
}
259+
185260
/// Create a check run
186261
pub async fn create_check_run(
187262
&self,

robot-repo-automaton/src/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,10 @@ async fn cmd_fix(
440440
match github.create_pull_request(repo_name, pr).await {
441441
Ok(created_pr) => {
442442
println!("Created PR #{}: {}", created_pr.number, created_pr.html_url);
443+
// Enable auto-merge — PR merges automatically when CI passes
444+
if let Err(e) = github.enable_auto_merge(repo_name, created_pr.number).await {
445+
debug!("Auto-merge enable failed (non-fatal): {}", e);
446+
}
443447
}
444448
Err(e) => {
445449
error!("Failed to create PR: {}", e);

0 commit comments

Comments
 (0)