Add support for stacked branches

This commit is contained in:
Quentin Boyer 2025-12-11 16:33:45 +01:00
parent 7cd2c82837
commit 1520e2353a

View file

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