From 0acf3cdb88c51278d7e3157d60bbdd7dfcee1ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 10 Jul 2026 16:39:15 +0200 Subject: [PATCH] Allow setting squashed commit message to the PR body --- src/bors/command/mod.rs | 12 +++++++- src/bors/command/parser.rs | 60 ++++++++++++++++++++++++++----------- src/bors/handlers/help.rs | 3 +- src/bors/handlers/squash.rs | 12 ++++++-- src/bors/mod.rs | 3 +- 5 files changed, 66 insertions(+), 24 deletions(-) diff --git a/src/bors/command/mod.rs b/src/bors/command/mod.rs index 833472b0..cc12e183 100644 --- a/src/bors/command/mod.rs +++ b/src/bors/command/mod.rs @@ -100,6 +100,16 @@ pub struct DelegateCommand { pub permission: DelegatedPermission, } +#[derive(Debug, PartialEq)] +pub enum SquashCommitMessage { + /// Automatically generate a commit message based on the messages of the squashed commits. + AutoGenerate, + /// Set the commit message to the PR body. + PullRequestDescription, + /// Set an explicit commit message. + Explicit(String), +} + /// Bors command specified by a user. /// /// When modifying commands, remember to also update: @@ -162,5 +172,5 @@ pub enum BorsCommand { /// Cancel an auto build currently running on a given PR (without removing it from the queue). Cancel, /// Squash all commits of a pull request into a single commit. - Squash { commit_message: Option }, + Squash { commit_message: SquashCommitMessage }, } diff --git a/src/bors/command/parser.rs b/src/bors/command/parser.rs index 12862c72..9a94ec11 100644 --- a/src/bors/command/parser.rs +++ b/src/bors/command/parser.rs @@ -1,7 +1,7 @@ //! Defines parsers for bors commands. use crate::bors::command::{ - Approver, BorsCommand, CommandPrefix, DelegateCommand, Delegatee, Parent, + Approver, BorsCommand, CommandPrefix, DelegateCommand, Delegatee, Parent, SquashCommitMessage, }; use crate::database::DelegatedPermission; use crate::github::CommitSha; @@ -630,7 +630,7 @@ fn parser_squash(command: &CommandPart<'_>, parts: &[CommandPart<'_>]) -> ParseR match command { CommandPart::Bare("squash") => match parts { &[] => Some(Ok(BorsCommand::Squash { - commit_message: None, + commit_message: SquashCommitMessage::AutoGenerate, })), &[ CommandPart::KeyValue { @@ -638,12 +638,20 @@ fn parser_squash(command: &CommandPart<'_>, parts: &[CommandPart<'_>]) -> ParseR value, }, .., - ] => Some(Ok(BorsCommand::Squash { - commit_message: Some(value.to_owned()), - })), + ] => { + if value == "description" { + Some(Ok(BorsCommand::Squash { + commit_message: SquashCommitMessage::PullRequestDescription, + })) + } else { + Some(Ok(BorsCommand::Squash { + commit_message: SquashCommitMessage::Explicit(value.to_owned()), + })) + } + } [part, ..] => Some(Err(CommandParseError::UnknownArg { arg: part.as_key().to_owned(), - did_you_mean: "squash [msg|message=\"\"]".to_string(), + did_you_mean: "squash [msg|message=\"\"|description]".to_string(), })), }, _ => None, @@ -1896,13 +1904,15 @@ for the crater", #[test] fn parse_squash() { let cmds = parse_commands("@bors squash"); - assert_eq!(cmds.len(), 1); - assert_eq!( - cmds[0], - Ok(BorsCommand::Squash { - commit_message: None - }) - ); + insta::assert_debug_snapshot!(cmds, @" + [ + Ok( + Squash { + commit_message: AutoGenerate, + }, + ), + ] + "); } #[test] @@ -1912,7 +1922,7 @@ for the crater", [ Ok( Squash { - commit_message: Some( + commit_message: Explicit( "foo", ), }, @@ -1928,7 +1938,7 @@ for the crater", [ Ok( Squash { - commit_message: Some( + commit_message: Explicit( "foo", ), }, @@ -1944,7 +1954,7 @@ for the crater", [ Ok( Squash { - commit_message: Some( + commit_message: Explicit( "foo bar baz", ), }, @@ -1953,6 +1963,20 @@ for the crater", "#); } + #[test] + fn parse_squash_msg_description() { + let cmds = parse_commands("@bors squash msg=description"); + insta::assert_debug_snapshot!(cmds, @" + [ + Ok( + Squash { + commit_message: PullRequestDescription, + }, + ), + ] + "); + } + #[test] fn parse_squash_unknown_arg() { let cmds = parse_commands("@bors squash commit=foo"); @@ -1961,7 +1985,7 @@ for the crater", Err( UnknownArg { arg: "commit", - did_you_mean: "squash [msg|message=\"\"]", + did_you_mean: "squash [msg|message=\"\"|description]", }, ), ] @@ -1975,7 +1999,7 @@ for the crater", [ Ok( Squash { - commit_message: Some( + commit_message: Explicit( "foo", ), }, diff --git a/src/bors/handlers/help.rs b/src/bors/handlers/help.rs index b90f915a..5985ba09 100644 --- a/src/bors/handlers/help.rs +++ b/src/bors/handlers/help.rs @@ -61,8 +61,9 @@ mod tests { - `try cancel`: Cancel a running try build on the current PR. - `retry`: Clear a failed auto build status from an approved PR. This will cause the merge queue to eventually attempt to merge the PR again. - `cancel` | `yield`: Cancel a running auto build on the current PR. - - `squash [msg|message=]`: Squash the commits of a PR into a single commit. + - `squash [msg|message=|description]`: Squash the commits of a PR into a single commit. - Optionally, you can specify a `` for the created commit. If not specified, the commit messages of all squashed commits will be combined. + - If you specify `msg=description`, then the PR body will be used as the squashed commit message. - `info`: Get information about the current PR ## Repository management diff --git a/src/bors/handlers/squash.rs b/src/bors/handlers/squash.rs index 1c52d1b5..1167d492 100644 --- a/src/bors/handlers/squash.rs +++ b/src/bors/handlers/squash.rs @@ -1,4 +1,5 @@ use crate::PgDbClient; +use crate::bors::command::SquashCommitMessage; use crate::bors::comment::CommentTag; use crate::bors::gitops_queue::{ GitOpsCommand, GitOpsQueueSender, PullRequestId, PushCallback, PushCommand, @@ -27,7 +28,7 @@ pub(super) async fn command_squash( db: Arc, pr: PullRequestData<'_>, author: &GithubUser, - commit_message: Option, + commit_message: SquashCommitMessage, bot_prefix: &CommandPrefix, gitops_queue: &GitOpsQueueSender, ) -> anyhow::Result<()> { @@ -142,8 +143,13 @@ pub(super) async fn command_squash( // Create the squashed commit on the source repository. // We take the parents of the first commit, and the tree of the last commit, to create the // squashed commit. - let commit_msg = - commit_message.unwrap_or_else(|| generate_squashed_commit_msg(&pr.github.title, &commits)); + let commit_msg = match commit_message { + SquashCommitMessage::AutoGenerate => { + generate_squashed_commit_msg(&pr.github.title, &commits) + } + SquashCommitMessage::PullRequestDescription => pr.github.message.clone(), + SquashCommitMessage::Explicit(msg) => msg, + }; let commit_msg = add_coauthored_authors(commit_msg, &commits, &commit_author); let commit = match repo_state .client diff --git a/src/bors/mod.rs b/src/bors/mod.rs index f528e389..2656ce38 100644 --- a/src/bors/mod.rs +++ b/src/bors/mod.rs @@ -127,8 +127,9 @@ You can use the following commands: - `try cancel`: Cancel a running try build on the current PR. - `retry`: Clear a failed auto build status from an approved PR. This will cause the merge queue to eventually attempt to merge the PR again. - `cancel` | `yield`: Cancel a running auto build on the current PR. -- `squash [msg|message=]`: Squash the commits of a PR into a single commit. +- `squash [msg|message=|description]`: Squash the commits of a PR into a single commit. - Optionally, you can specify a `` for the created commit. If not specified, the commit messages of all squashed commits will be combined. + - If you specify `msg=description`, then the PR body will be used as the squashed commit message. - `info`: Get information about the current PR ## Repository management