Skip to content

Commit 7c0e2ec

Browse files
authored
Merge pull request #12372 from gitbutlerapp/inclusive-review-naming
Be oh-so-inclusive with the review terminology
2 parents 1d7393b + d32e350 commit 7c0e2ec

File tree

3 files changed

+52
-40
lines changed

3 files changed

+52
-40
lines changed

crates/but/src/args/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -531,10 +531,10 @@ pub enum Subcommands {
531531
id: String,
532532
},
533533

534-
/// Commands for creating and managing pull requests on a forge.
534+
/// Commands for creating and managing reviews on a forge, e.g. GitHub PRs or GitLab MRs.
535535
///
536536
/// If you are authenticated with a forge using `but config forge auth`, you can use
537-
/// the `but pr` commands to create pull requests (or merge requests) on
537+
/// the `but pr` or `but mr` commands to create pull requests (or merge requests) on
538538
/// the remote repository for your branches.
539539
///
540540
/// Running `but pr` without a subcommand defaults to `but pr new`, which

crates/but/src/command/legacy/forge/review.rs

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,18 @@ pub fn set_review_template(
6060
Ok(())
6161
}
6262

63-
/// Create a new PR for a branch.
63+
/// Create a new forge review for a branch.
6464
/// If no branch is specified, prompts the user to select one.
65-
/// If there is only one branch without a PR, asks for confirmation.
65+
/// If there is only one branch without a an acco, asks for confirmation.
6666
#[allow(clippy::too_many_arguments)]
67-
pub async fn create_pr(
67+
pub async fn create_review(
6868
ctx: &mut Context,
6969
branch: Option<String>,
7070
skip_force_push_protection: bool,
7171
with_force: bool,
7272
run_hooks: bool,
7373
default: bool,
74-
message: Option<PrMessage>,
74+
message: Option<ForgeReviewMessage>,
7575
out: &mut OutputChannel,
7676
) -> anyhow::Result<()> {
7777
// Fail fast if no forge user is authenticated, before pushing or prompting.
@@ -90,7 +90,7 @@ pub async fn create_pr(
9090

9191
if branches_without_prs.is_empty() {
9292
if let Some(out) = out.for_human() {
93-
writeln!(out, "All branches already have PRs.")?;
93+
writeln!(out, "All branches already have reviews.")?;
9494
}
9595
return Ok(());
9696
} else if branches_without_prs.len() == 1 {
@@ -100,7 +100,7 @@ pub async fn create_pr(
100100
.prepare_for_terminal_input()
101101
.context("Terminal input not available. Please specify a branch using command line arguments.")?;
102102
if inout.confirm(
103-
format!("Do you want to open a new PR on branch '{branch_name}'?"),
103+
format!("Do you want to open a new review on branch '{branch_name}'?"),
104104
ConfirmDefault::Yes,
105105
)? == Confirm::Yes
106106
{
@@ -149,14 +149,27 @@ async fn ensure_forge_authentication(ctx: &mut Context) -> Result<(), anyhow::Er
149149
let account_validity =
150150
but_forge::check_forge_account_is_valid(preferred_forge_user, &forge_repo_info, &storage).await?;
151151

152+
let forge_display_name = match forge_repo_info.forge {
153+
but_forge::ForgeName::Azure => {
154+
anyhow::bail!("Azure is unsupported at the minute. Sorry 😞.");
155+
}
156+
but_forge::ForgeName::Bitbucket => {
157+
anyhow::bail!("Bitbucket is unsupported at the minute. Sorry 😞.");
158+
}
159+
but_forge::ForgeName::GitHub => "GitHub",
160+
but_forge::ForgeName::GitLab => "GitLab",
161+
};
162+
152163
match account_validity {
153164
but_forge::ForgeAccountValidity::Invalid => Err(anyhow::anyhow!(
154-
"Known account is not correctly authenticated.\nRun '{}' to authenticate with GitHub or GitLab.",
155-
"but config forge auth"
165+
"Known account is not correctly authenticated.\nRun '{}' to authenticate with {}.",
166+
"but config forge auth",
167+
forge_display_name
156168
)),
157169
but_forge::ForgeAccountValidity::NoCredentials => Err(anyhow::anyhow!(
158-
"No authenticated forge users found.\nRun '{}' to authenticate with GitHub or GitLab.",
159-
"but config forge auth"
170+
"No authenticated forge users found.\nRun '{}' to authenticate with {}.",
171+
"but config forge auth",
172+
forge_display_name
160173
)),
161174
but_forge::ForgeAccountValidity::Valid => {
162175
// All good, continue
@@ -212,7 +225,7 @@ pub async fn handle_multiple_branches_in_workspace(
212225
with_force: bool,
213226
run_hooks: bool,
214227
default_message: bool,
215-
message: Option<&PrMessage>,
228+
message: Option<&ForgeReviewMessage>,
216229
out: &mut OutputChannel,
217230
selected_branches: Option<Vec<String>>,
218231
) -> anyhow::Result<()> {
@@ -371,7 +384,7 @@ async fn publish_reviews_for_branch_and_dependents(
371384
with_force: bool,
372385
run_hooks: bool,
373386
default_message: bool,
374-
message: Option<&PrMessage>,
387+
message: Option<&ForgeReviewMessage>,
375388
out: &mut OutputChannel,
376389
) -> Result<PublishReviewsOutcome, anyhow::Error> {
377390
let base_branch = gitbutler_branch_actions::base::get_base_branch_data(ctx)?;
@@ -543,12 +556,12 @@ enum PublishReviewResult {
543556
}
544557

545558
#[derive(Clone, Debug)]
546-
pub struct PrMessage {
559+
pub struct ForgeReviewMessage {
547560
pub title: String,
548561
pub body: String,
549562
}
550563

551-
pub fn parse_pr_message(content: &str) -> anyhow::Result<PrMessage> {
564+
pub fn parse_review_message(content: &str) -> anyhow::Result<ForgeReviewMessage> {
552565
let mut lines = content.lines();
553566
let title = lines.next().unwrap_or("").trim().to_string();
554567

@@ -564,7 +577,7 @@ pub fn parse_pr_message(content: &str) -> anyhow::Result<PrMessage> {
564577
.trim()
565578
.to_string();
566579

567-
Ok(PrMessage { title, body })
580+
Ok(ForgeReviewMessage { title, body })
568581
}
569582

570583
async fn publish_review_for_branch(
@@ -574,7 +587,7 @@ async fn publish_review_for_branch(
574587
target_branch: &str,
575588
review_map: &std::collections::HashMap<String, Vec<but_forge::ForgeReview>>,
576589
default_message: bool,
577-
message: Option<&PrMessage>,
590+
message: Option<&ForgeReviewMessage>,
578591
) -> anyhow::Result<PublishReviewResult> {
579592
// Check if a review already exists for the branch.
580593
// If it does, skip publishing a new review.
@@ -746,7 +759,7 @@ fn get_pr_title_and_body_from_editor(
746759
template.push_str("#\n");
747760

748761
let content = get_text::from_editor_no_comments("pr_message", &template)?.to_string();
749-
let message = parse_pr_message(&content)?;
762+
let message = parse_review_message(&content)?;
750763
Ok((message.title, message.body))
751764
}
752765

@@ -835,56 +848,56 @@ mod tests {
835848

836849
#[test]
837850
fn parse_pr_message_title_only() {
838-
let msg = parse_pr_message("My PR Title").unwrap();
851+
let msg = parse_review_message("My PR Title").unwrap();
839852
assert_eq!(msg.title, "My PR Title");
840853
assert_eq!(msg.body, "");
841854
}
842855

843856
#[test]
844857
fn parse_pr_message_title_and_body() {
845-
let msg = parse_pr_message("My PR Title\n\nThis is the body.").unwrap();
858+
let msg = parse_review_message("My PR Title\n\nThis is the body.").unwrap();
846859
assert_eq!(msg.title, "My PR Title");
847860
assert_eq!(msg.body, "This is the body.");
848861
}
849862

850863
#[test]
851864
fn parse_pr_message_multiline_body() {
852-
let msg = parse_pr_message("Title\n\nLine 1\nLine 2\nLine 3").unwrap();
865+
let msg = parse_review_message("Title\n\nLine 1\nLine 2\nLine 3").unwrap();
853866
assert_eq!(msg.title, "Title");
854867
assert_eq!(msg.body, "Line 1\nLine 2\nLine 3");
855868
}
856869

857870
#[test]
858871
fn parse_pr_message_skips_blank_lines_between_title_and_body() {
859-
let msg = parse_pr_message("Title\n\n\n\nBody starts here").unwrap();
872+
let msg = parse_review_message("Title\n\n\n\nBody starts here").unwrap();
860873
assert_eq!(msg.title, "Title");
861874
assert_eq!(msg.body, "Body starts here");
862875
}
863876

864877
#[test]
865878
fn parse_pr_message_trims_whitespace() {
866-
let msg = parse_pr_message(" Title with spaces \n\n Body with spaces ").unwrap();
879+
let msg = parse_review_message(" Title with spaces \n\n Body with spaces ").unwrap();
867880
assert_eq!(msg.title, "Title with spaces");
868881
assert_eq!(msg.body, "Body with spaces");
869882
}
870883

871884
#[test]
872885
fn parse_pr_message_empty_string_fails() {
873-
let result = parse_pr_message("");
886+
let result = parse_review_message("");
874887
assert!(result.is_err());
875888
assert!(result.unwrap_err().to_string().contains("empty PR title"));
876889
}
877890

878891
#[test]
879892
fn parse_pr_message_whitespace_only_fails() {
880-
let result = parse_pr_message(" \n\n ");
893+
let result = parse_review_message(" \n\n ");
881894
assert!(result.is_err());
882895
assert!(result.unwrap_err().to_string().contains("empty PR title"));
883896
}
884897

885898
#[test]
886899
fn parse_pr_message_blank_first_line_fails() {
887-
let result = parse_pr_message("\nActual title on second line");
900+
let result = parse_review_message("\nActual title on second line");
888901
assert!(result.is_err());
889902
assert!(result.unwrap_err().to_string().contains("empty PR title"));
890903
}

crates/but/src/lib.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -805,52 +805,51 @@ async fn match_subcommand(
805805
}) => {
806806
// Read message content from file or inline
807807
let message_content = match &file {
808-
Some(path) => Some(
809-
std::fs::read_to_string(path)
810-
.with_context(|| format!("Failed to read PR message from file: {}", path.display()))?,
811-
),
808+
Some(path) => Some(std::fs::read_to_string(path).with_context(|| {
809+
format!("Failed to read forge review message from file: {}", path.display())
810+
})?),
812811
None => message.clone(),
813812
};
814813
// Parse early to fail fast on invalid content
815-
let pr_message = match message_content {
816-
Some(content) => Some(command::legacy::forge::review::parse_pr_message(&content)?),
814+
let review_message = match message_content {
815+
Some(content) => Some(command::legacy::forge::review::parse_review_message(&content)?),
817816
None => None,
818817
};
819818
// Check for non-interactive environment
820819
if !out.can_prompt() {
821820
if branch.is_none() {
822821
anyhow::bail!("Non-interactive environment detected. Please specify a branch.");
823822
}
824-
if pr_message.is_none() && !default {
823+
if review_message.is_none() && !default {
825824
anyhow::bail!(
826825
"Non-interactive environment detected. Provide one of: --message (-m), --file (-F), or --default (-t)."
827826
);
828827
}
829828
}
830-
command::legacy::forge::review::create_pr(
829+
command::legacy::forge::review::create_review(
831830
&mut ctx,
832831
branch,
833832
skip_force_push_protection,
834833
with_force,
835834
run_hooks,
836835
default,
837-
pr_message,
836+
review_message,
838837
out,
839838
)
840839
.await
841-
.context("Failed to create PR for branch.")
840+
.context("Failed to create forge review for branch.")
842841
.emit_metrics(metrics_ctx)
843842
}
844843
Some(forge::pr::Subcommands::Template { template_path }) => {
845844
command::legacy::forge::review::set_review_template(&mut ctx, template_path, out)
846-
.context("Failed to set PR template.")
845+
.context("Failed to set forge review template.")
847846
.emit_metrics(metrics_ctx)
848847
}
849848
None => {
850849
// Default to `pr new` when no subcommand is provided
851-
command::legacy::forge::review::create_pr(&mut ctx, None, false, true, true, false, None, out)
850+
command::legacy::forge::review::create_review(&mut ctx, None, false, true, true, false, None, out)
852851
.await
853-
.context("Failed to create PR for branch.")
852+
.context("Failed to create forge review for branch.")
854853
.emit_metrics(metrics_ctx)
855854
}
856855
}

0 commit comments

Comments
 (0)