diff --git a/crates/but/src/command/legacy/commit2.rs b/crates/but/src/command/legacy/commit2.rs index f0d7763447c..f3eaeddb529 100644 --- a/crates/but/src/command/legacy/commit2.rs +++ b/crates/but/src/command/legacy/commit2.rs @@ -10,7 +10,7 @@ use but_rebase::graph_rebase::mutate::{InsertSide, RelativeTo}; use but_transaction::{IntermediateCommitCreateResult, Transaction}; use but_workspace::{RefInfo, branch::create_reference::Anchor}; use gitbutler_oplog::entry::{OperationKind, SnapshotDetails}; -use gix::refs::FullName; +use gix::{prelude::ObjectIdExt as _, refs::FullName}; use nonempty::NonEmpty; use serde::Serialize; @@ -36,6 +36,7 @@ use crate::{ #[must_use] pub struct CommitOutcome { pub new_commit: gix::ObjectId, + pub change_id: but_core::ChangeId, pub branch_name: Option, } @@ -49,24 +50,26 @@ pub enum BranchNameTarget { impl CliOutputHuman for CommitOutcome { fn on_human(self, out: &mut dyn WriteWithUtils, _theme: &Theme) -> anyhow::Result<()> { let Self { - new_commit, + new_commit: _, + change_id, branch_name, } = self; + let change_id = theme::ChangeId(&change_id); match branch_name { Some(BranchNameTarget::New(branch_name)) => writeln!( out, "Created commit {} on new branch {}", - theme::Commit(new_commit), + change_id, theme::Branch(branch_name), )?, Some(BranchNameTarget::Existing(branch_name)) => writeln!( out, "Created commit {} on branch {}", - theme::Commit(new_commit), + change_id, theme::Branch(branch_name), )?, - None => writeln!(out, "Created commit {}", theme::Commit(new_commit))?, + None => writeln!(out, "Created commit {change_id}")?, } Ok(()) @@ -76,10 +79,11 @@ impl CliOutputHuman for CommitOutcome { impl CliOutput for CommitOutcome { fn on_shell(self, out: &mut dyn WriteWithUtils) -> anyhow::Result<()> { let Self { - new_commit, + new_commit: _, + change_id, branch_name: _, } = self; - writeln!(out, "{}", new_commit.to_hex_with_len(7))?; + writeln!(out, "{change_id}")?; Ok(()) } @@ -87,12 +91,14 @@ impl CliOutput for CommitOutcome { #[derive(Serialize)] struct Output { commit: HexHash, + change_id: String, #[serde(skip_serializing_if = "Option::is_none")] branch: Option, } let Self { new_commit, + change_id, branch_name, } = self; @@ -103,6 +109,7 @@ impl CliOutput for CommitOutcome { Output { commit: new_commit.into(), + change_id: change_id.to_string(), branch: branch_name, } } @@ -285,8 +292,12 @@ pub fn run( }, )?; + let repo = ctx.repo.get()?; + let change_id = but_core::Commit::from_id(new_commit.attach(&repo))?.change_id(); + Ok(CommitOutcome { new_commit, + change_id, branch_name, }) } diff --git a/crates/but/src/command/legacy/status/tui/app/commit_mode.rs b/crates/but/src/command/legacy/status/tui/app/commit_mode.rs index 9124af4950a..64b06b30418 100644 --- a/crates/but/src/command/legacy/status/tui/app/commit_mode.rs +++ b/crates/but/src/command/legacy/status/tui/app/commit_mode.rs @@ -537,6 +537,7 @@ where let commit2::CommitOutcome { new_commit, + change_id: _, branch_name: _, } = commit2::run( ctx, diff --git a/crates/but/src/id/mod.rs b/crates/but/src/id/mod.rs index 111daf264a2..dec648eb294 100644 --- a/crates/but/src/id/mod.rs +++ b/crates/but/src/id/mod.rs @@ -19,9 +19,12 @@ use gix::hash::hasher; use nonempty::NonEmpty; use self_cell::self_cell; -use crate::id::{ - file_info::FileInfo, id_usage::UintId, stacks_info::StacksInfo, - uncommitted_info::UncommittedInfo, +use crate::{ + id::{ + file_info::FileInfo, id_usage::UintId, stacks_info::StacksInfo, + uncommitted_info::UncommittedInfo, + }, + theme::MIN_DISPLAYED_CHANGE_ID_CHARS, }; mod file_info; @@ -265,10 +268,6 @@ pub struct ChangeIdWithShortId { pub short_id: ShortId, } -/// The minimum number of change ID characters displayed for a commit, so that -/// short IDs remain visually distinctive. -pub(crate) const MIN_DISPLAYED_CHANGE_ID_CHARS: usize = 3; - impl ChangeIdWithShortId { /// The short ID padded with further change ID characters to /// [`MIN_DISPLAYED_CHANGE_ID_CHARS`], matching how the change ID is diff --git a/crates/but/src/theme.rs b/crates/but/src/theme.rs index a7a415f299c..c94ea077204 100644 --- a/crates/but/src/theme.rs +++ b/crates/but/src/theme.rs @@ -616,15 +616,26 @@ where } } +/// Minimum number of change ID characters shown in human-readable output. +pub(crate) const MIN_DISPLAYED_CHANGE_ID_CHARS: usize = 3; + +pub struct ChangeId<'a>(pub &'a but_core::ChangeId); + +impl Display for ChangeId<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let short_id = self.0[..MIN_DISPLAYED_CHANGE_ID_CHARS.min(self.0.len())].to_str_lossy(); + write!(f, "{}", get().change_id.paint(short_id)) + } +} + pub struct Commit(pub gix::ObjectId); impl Display for Commit { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let t = get(); write!( f, "{}", - t.commit_id.paint(self.0.to_hex_with_len(7).to_string()) + get().commit_id.paint(self.0.to_hex_with_len(7).to_string()) ) } } @@ -639,11 +650,10 @@ impl Display for Branch { impl Display for Branch<&FullName> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let t = get(); write!( f, "'{}'", - t.local_branch.paint(self.0.shorten().to_str_lossy()) + get().local_branch.paint(self.0.shorten().to_str_lossy()) ) } } @@ -652,6 +662,12 @@ impl Display for Branch<&FullName> { mod tests { use super::*; + #[test] + fn change_id_is_shortened_to_three_characters() { + let change_id = but_core::ChangeId::from_number_for_testing(123456); + assert_eq!(ChangeId(&change_id).to_string(), "123"); + } + #[test] fn round_trip_default_theme_through_json() { let theme = Theme::default(); diff --git a/crates/but/tests/but/command/commit2.rs b/crates/but/tests/but/command/commit2.rs index ce47f0dfbc7..e8b6242b2f4 100644 --- a/crates/but/tests/but/command/commit2.rs +++ b/crates/but/tests/but/command/commit2.rs @@ -36,7 +36,7 @@ fn no_args_single_head_no_message_human_output() { .assert() .success() .stdout_eq(snapbox::str![[r#" -Created commit 7bbfdca on branch 'A' +Created commit 1 on branch 'A' "#]]); @@ -58,6 +58,23 @@ Hint: run `but help` for all commands "#]]); } +#[test] +fn human_output_shortens_change_id_to_three_characters() { + let env = Sandbox::init_scenario_with_target_and_default_settings("one-stack"); + env.setup_metadata(&["A"]); + env.invoke_git("config --local gitbutler.testing.changeId 123456"); + + env.file("file.txt", "Some text"); + + env.but("_commit2 --no-message") + .assert() + .success() + .stdout_eq(snapbox::str![[r#" +Created commit 123 on branch 'A' + +"#]]); +} + #[test] fn no_args_single_head_no_message_shell_output() { let env = Sandbox::init_scenario_with_target_and_default_settings("one-stack"); @@ -69,7 +86,7 @@ fn no_args_single_head_no_message_shell_output() { .assert() .success() .stdout_eq(snapbox::str![[r#" -7bbfdca +1 "#]]); } @@ -86,7 +103,8 @@ fn no_args_single_head_no_message_json_output() { .success() .stdout_eq(snapbox::str![[r#" { - "commit": "7bbfdca68284535242b93595db5f6a5bc885a124" + "commit": "7bbfdca68284535242b93595db5f6a5bc885a124", + "change_id": "1" } "#]]); @@ -477,6 +495,7 @@ fn newly_created_branches_are_included_in_json_output() { .stdout_eq(snapbox::str![[r#" { "commit": "5a6fc56305c69edc974a5ed2d100c525db8fd288", + "change_id": "1", "branch": "foo" }