Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ tempfile = "3"
which = "8"

# Text processing
comrak = { version = "0.50.0", default-features = false }
pulldown-cmark = "0.13"
regex = "1"

Expand Down
38 changes: 35 additions & 3 deletions src/bors/handlers/squash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use crate::bors::gitops_queue::{
GitOpsCommand, GitOpsQueueSender, PullRequestId, PushCallback, PushCommand,
};
use crate::bors::handlers::{PullRequestData, unapprove_pr};
use crate::bors::{CommandPrefix, Comment, RepositoryState, bors_commit_author};
use crate::bors::{
CommandPrefix, Comment, RepositoryState, bors_commit_author, format_commit_message,
};
use crate::database::BuildStatus;
use crate::github::api::CommitAuthor;
use crate::github::api::operations::Commit;
Expand Down Expand Up @@ -117,8 +119,10 @@ 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 {
Some(msg) => format_commit_message(&msg),
None => generate_squashed_commit_msg(&pr.github.title, &commits),
};
let commit = match repo_state
.client
.create_commit(
Expand Down Expand Up @@ -528,6 +532,34 @@ mod tests {
.await;
}

#[sqlx::test]
async fn squash_long_message(pool: sqlx::PgPool) {
run_test((pool, squash_state()), async |ctx: &mut BorsTester| {
ctx.modify_pr_in_gh((), |pr| {
pr.add_commits(vec![Commit::from_sha("sha2")]);
});
ctx.approve(()).await?;
ctx.post_comment(
"@bors squash msg=\"This is a squashed commit.\n\nLorem ipsum dolor sit amet, \
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et \
dolore\"",
)
.await?;
ctx.run_gitop_queue().await?;
ctx.expect_comments((), 1).await;
insta::assert_snapshot!(
ctx.pr(()).await.get_gh_pr().head_branch_copy().get_commit().message(),
@"This is a squashed commit

Lorem ipsum dolor sit amet,
"
);

Ok(())
})
.await;
}

fn squash_state() -> GitHub {
let gh = GitHub::default();
let pr_author = User::default_pr_author();
Expand Down
42 changes: 42 additions & 0 deletions src/bors/merge_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1667,6 +1667,48 @@ also include this pls"
.await;
}

#[sqlx::test]
async fn commit_message_reflow(pool: sqlx::PgPool) {
run_test(pool, async |ctx: &mut BorsTester| {
ctx.edit_pr((), |pr| {
pr.description = "This is a very good PR, but it has a rather long description.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut \
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris \
nisi ut aliquip ex ea commodo consequat.

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt \
mollit anim id est laborum.
"
.to_string();
})
.await?;

ctx.approve(()).await?;
ctx.start_and_finish_auto_build(()).await?;

insta::assert_snapshot!(ctx.auto_branch().get_commit().message(), @"
Auto merge of #1 - default-user:pr/1, r=default-user

Title of PR 1

This is a very good PR, but it has a rather long description.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
");
Ok(())
})
.await;
}

#[sqlx::test]
async fn cancel_try_again(pool: sqlx::PgPool) {
run_test(pool, async |ctx: &mut BorsTester| {
Expand Down
19 changes: 17 additions & 2 deletions src/bors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ pub fn make_text_ignored_by_bors(text: &str) -> String {
format!("{IGNORE_BLOCK_START}\n{text}\n{IGNORE_BLOCK_END}")
}

/// Remove homu-ignore blocks from the merge message
/// Remove homu-ignore blocks from the merge message, then rewrap the text.
pub fn normalize_merge_message(message: &str) -> String {
static IGNORE_REGEX: LazyLock<Regex> = LazyLock::new(|| {
RegexBuilder::new(r"<!--\s*homu-ignore:start\s*-->.*?<!--\s*homu-ignore:end\s*-->")
Expand All @@ -326,7 +326,22 @@ pub fn normalize_merge_message(message: &str) -> String {
.build()
.unwrap()
});
IGNORE_REGEX.replace_all(message, "").to_string()
let cleaned = IGNORE_REGEX.replace_all(message, "");
format_commit_message(&cleaned)
}

/// Rewrap PR bodies to standard commit message width.
pub fn format_commit_message(message: &str) -> String {
let mut opts = comrak::Options::default();
opts.render.width = 72;
opts.render.list_style = comrak::options::ListStyleType::Star;

let mut out = String::new();
let arena = comrak::Arena::new();
let node = comrak::parse_document(&arena, message, &opts);
comrak::format_commonmark(&node, &opts, &mut out).unwrap();

out
}

pub fn create_merge_commit_message(pr: handlers::PullRequestData, merge_type: MergeType) -> String {
Expand Down
Loading