diff --git a/src/main.rs b/src/main.rs index d5bb8ec..f6dd80c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ use utils::OptExt; mod utils; const COVER_LETTER_NAME: &str = "cover-letter"; +const STACKED_ON_NAME: &str = "stacked-on"; #[derive(Parser, Debug)] struct Arg { @@ -267,15 +268,22 @@ struct FormatPatch { short = 'D', long, help = "Perform the interdiff with an explicit reference", - conflicts_with = "diff" + conflicts_with = "diff", + conflicts_with = "stacked_on" )] diff_to: Option, extra_args: Vec, + #[arg( + short = 'S', + long, + help = "Fetch the revisions up to supplied branch and fill the template" + )] + stacked_on: Option, } impl FormatPatch { pub fn run( - self, + mut self, config: GsmConfig, git_cd: impl Fn(&[&str]) -> Result, patch_dir: &Path, @@ -323,6 +331,15 @@ impl FormatPatch { .into_diagnostic() .wrap_err("could not create branch dir")?; + let stacked_on_file = branch_dir.join(STACKED_ON_NAME); + if stacked_on_file.exists() { + self.stacked_on = Some( + std::fs::read_to_string(&stacked_on_file) + .into_diagnostic() + .wrap_err_with(|| format!("Could not read {stacked_on_file:?}"))?, + ); + } + let version = match self.version { Some(v) => Some(v), None => latest_version(&branch_dir) @@ -368,6 +385,13 @@ impl FormatPatch { let subject_prefix = format!(r#"--subject-prefix=PATCH {component}"#); format_patch_args.extend_from_slice(&[&subject_prefix, "--cover-letter"]); format_patch_args.extend_from_slice(extra_args); + let branch_ref = self + .stacked_on + .as_ref() + .map(|branch| format!("refs/heads/{branch}")); + if let Some(r) = &branch_ref { + format_patch_args.push(r); + } format_patch_args.extend(self.extra_args.iter().map(|s| s.deref())); git_cd(&format_patch_args)?; @@ -383,6 +407,7 @@ impl FormatPatch { (Some(patch_version), None) => { let base = self .base_diff + .or(self.stacked_on.clone()) .or(config.interdiff_base) .unwrap_or_else(|| String::from("origin/master")); @@ -461,7 +486,7 @@ impl FormatPatch { .ok_or(miette!("Interdiff patch path is not utf-8"))? .to_string(); - match path.contains("cover-letter") { + match path.ends_with(COVER_LETTER_NAME) || path.ends_with(STACKED_ON_NAME) { true => Ok(None), false => Ok(Some(path)), } @@ -484,12 +509,21 @@ impl FormatPatch { if let Some(ci_link) = &ci_link { cover_letter_template += &format!("CI: {ci_link}\n"); } + if let Some(branch) = &self.stacked_on { + cover_letter_template += &format!("Stacked on: {branch}"); + } std::fs::write(&cover_letter, cover_letter_template) .into_diagnostic() .wrap_err("Could not write cover letter")?; } + if let Some(stacked_on) = &self.stacked_on { + std::fs::write(stacked_on_file, stacked_on) + .into_diagnostic() + .wrap_err("Could not write stack base")?; + } + std::process::Command::new(config.editor) .arg(&cover_letter) .status() @@ -583,7 +617,7 @@ fn latest_version(branch_dir: &Path) -> Result> { let name = entry.file_name(); let name = name.to_str().expect("patch set entry is not utf8"); - if name == "cover-letter" { + if name == COVER_LETTER_NAME || name == STACKED_ON_NAME { None } else { Some(Ok(name.parse().expect("version is not an int")))