diff --git a/lib/crates/arc-cli/src/init.rs b/lib/crates/arc-cli/src/init.rs index 713deb961..2c8612529 100644 --- a/lib/crates/arc-cli/src/init.rs +++ b/lib/crates/arc-cli/src/init.rs @@ -39,6 +39,11 @@ root = \"arc/\" # Disable retrospective analysis after workflow runs: # retro = false + +# Auto-create pull requests on successful workflow runs: +# [pull_request] +# enabled = true +# draft = true ", ) .with_context(|| format!("failed to write {}", arc_toml.display()))?; diff --git a/lib/crates/arc-workflows/src/cli/project_config.rs b/lib/crates/arc-workflows/src/cli/project_config.rs index 1e23818a6..e77a69ccc 100644 --- a/lib/crates/arc-workflows/src/cli/project_config.rs +++ b/lib/crates/arc-workflows/src/cli/project_config.rs @@ -3,6 +3,8 @@ use std::path::{Path, PathBuf}; use anyhow::{bail, Context}; use serde::Deserialize; +use super::run_config::PullRequestConfig; + const CONFIG_FILENAME: &str = "arc.toml"; #[derive(Debug, Deserialize, PartialEq)] @@ -11,6 +13,7 @@ pub struct ProjectConfig { pub version: u32, #[serde(default)] pub arc: ProjectArcConfig, + pub pull_request: Option, } #[derive(Debug, Deserialize, PartialEq)] @@ -199,6 +202,7 @@ mod tests { root: ".".to_string(), retro: true, }, + pull_request: None, } ); } @@ -224,6 +228,20 @@ mod tests { ); } + #[test] + fn parse_pull_request_config() { + let config = + parse_project_config("version = 1\n\n[pull_request]\nenabled = true\ndraft = false\n") + .unwrap(); + assert_eq!( + config.pull_request, + Some(PullRequestConfig { + enabled: true, + draft: false, + }) + ); + } + #[test] fn parse_unknown_field_rejected() { let err = parse_project_config("version = 1\nfoo = \"bar\"\n").unwrap_err(); @@ -269,6 +287,7 @@ mod tests { root: "arc/".to_string(), ..Default::default() }, + pull_request: None, }; assert_eq!( resolve_arc_root(config_path, &config), @@ -285,6 +304,7 @@ mod tests { root: ".".to_string(), ..Default::default() }, + pull_request: None, }; assert_eq!(resolve_arc_root(config_path, &config), Path::new("/repo/.")); } diff --git a/lib/crates/arc-workflows/src/cli/run.rs b/lib/crates/arc-workflows/src/cli/run.rs index 3cd3b4c2e..44fee26f7 100644 --- a/lib/crates/arc-workflows/src/cli/run.rs +++ b/lib/crates/arc-workflows/src/cli/run.rs @@ -262,7 +262,7 @@ struct CostAccumulator { /// Returns an error if the workflow cannot be read, parsed, validated, or executed. pub async fn run_command( args: RunArgs, - run_defaults: RunDefaults, + mut run_defaults: RunDefaults, styles: &'static Styles, github_app: Option, git_author: crate::git::GitAuthor, @@ -278,6 +278,20 @@ pub async fn run_command( .ok_or_else(|| anyhow::anyhow!("--workflow is required unless --run-branch is provided"))?; let workflow_path = &super::project_config::resolve_workflow_arg(workflow_path)?; + // Apply project-level config overrides (arc.toml) on top of CLI defaults. + // Workflow-level config (workflow.toml) still wins via apply_defaults below. + if let Ok(Some((_config_path, project_config))) = + super::project_config::discover_project_config(&std::env::current_dir().unwrap_or_default()) + { + if project_config.pull_request.is_some() { + tracing::debug!( + pull_request = ?project_config.pull_request, + "Applying pull_request config from arc.toml" + ); + run_defaults.pull_request = project_config.pull_request; + } + } + // 0. Load run config if TOML, resolve DOT path, apply defaults let (dot_path, run_cfg) = if workflow_path.extension().is_some_and(|ext| ext == "toml") { let mut cfg = run_config::load_run_config(workflow_path)?;