Skip to content

Commit 863631a

Browse files
committed
Add basic test and a new flag to support noninteractive tests
1 parent ca0961c commit 863631a

File tree

2 files changed

+100
-48
lines changed

2 files changed

+100
-48
lines changed

src/main.rs

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ struct Args {
5151
/// The maximum number of commits to show when looking for your merge point
5252
#[structopt(short = "m", long = "max-commits", default_value = "15")]
5353
max_commits: usize,
54+
55+
/// Specify a commit to ammend by the subject line of the commit
56+
#[structopt(short = "P", long)]
57+
commit_message_pattern: Option<String>,
5458
}
5559

5660
#[derive(Eq, PartialEq, Debug)]
@@ -64,7 +68,7 @@ fn main() {
6468
if env::args().next().unwrap().ends_with("squash") {
6569
args.squash = true
6670
}
67-
if let Err(e) = run(args.squash, args.max_commits) {
71+
if let Err(e) = run(args.squash, args.max_commits, args.commit_message_pattern) {
6872
// An empty message means don't display any error message
6973
let msg = e.to_string();
7074
if !msg.is_empty() {
@@ -73,7 +77,11 @@ fn main() {
7377
}
7478
}
7579

76-
fn run(squash: bool, max_commits: usize) -> Result<(), Box<dyn Error>> {
80+
fn run(
81+
squash: bool,
82+
max_commits: usize,
83+
message_pattern: Option<String>,
84+
) -> Result<(), Box<dyn Error>> {
7785
let repo = Repository::open(".")?;
7886
let head = repo
7987
.head()
@@ -82,8 +90,15 @@ fn run(squash: bool, max_commits: usize) -> Result<(), Box<dyn Error>> {
8290
let head_branch = Branch::wrap(head);
8391
let diff = repo.diff_tree_to_index(Some(&head_tree), None, None)?;
8492
let upstream = get_upstream(&repo, &head_branch)?;
85-
let commit_to_amend =
86-
create_fixup_commit(&repo, &head_branch, upstream, &diff, squash, max_commits)?;
93+
let commit_to_amend = create_fixup_commit(
94+
&repo,
95+
&head_branch,
96+
upstream,
97+
&diff,
98+
squash,
99+
max_commits,
100+
&message_pattern,
101+
)?;
87102
println!(
88103
"selected: {} {}",
89104
&commit_to_amend.id().to_string()[0..10],
@@ -143,6 +158,7 @@ fn create_fixup_commit<'a>(
143158
diff: &'a Diff,
144159
squash: bool,
145160
max_commits: usize,
161+
message_pattern: &Option<String>,
146162
) -> Result<Commit<'a>, Box<dyn Error>> {
147163
let diffstat = diff.stats()?;
148164
if diffstat.files_changed() == 0 {
@@ -166,7 +182,7 @@ fn create_fixup_commit<'a>(
166182
println!("Staged changes:");
167183
print_diff(Changes::Staged)?;
168184
}
169-
let commit_to_amend = select_commit_to_amend(&repo, upstream, max_commits)?;
185+
let commit_to_amend = select_commit_to_amend(&repo, upstream, max_commits, message_pattern)?;
170186
do_fixup_commit(&repo, &head_branch, &commit_to_amend, squash)?;
171187
Ok(commit_to_amend)
172188
}
@@ -195,6 +211,7 @@ fn select_commit_to_amend<'a>(
195211
repo: &'a Repository,
196212
upstream: Option<Object<'a>>,
197213
max_commits: usize,
214+
message_pattern: &Option<String>,
198215
) -> Result<Commit<'a>, anyhow::Error> {
199216
let mut walker = repo.revwalk()?;
200217
walker.push_head()?;
@@ -230,33 +247,49 @@ fn select_commit_to_amend<'a>(
230247
})
231248
})
232249
.collect();
233-
let rev_aliases = commits
234-
.iter()
235-
.enumerate()
236-
.map(|(i, commit)| {
237-
let bname = if i > 0 {
238-
branches
239-
.get(&commit.id())
240-
.map(|n| format!("({}) ", n))
241-
.unwrap_or_else(String::new)
242-
} else {
243-
String::new()
244-
};
245-
format!(
246-
"{} {}{}",
247-
&style(&commit.id().to_string()[0..10]).blue(),
248-
style(bname).green(),
249-
commit.summary().unwrap_or("no commit summary")
250-
)
251-
})
252-
.collect::<Vec<_>>();
253-
if upstream.is_none() {
254-
eprintln!("Select a commit to amend (no upstream for HEAD):");
250+
if let Some(message_pattern) = message_pattern.as_ref() {
251+
eprintln!(
252+
"trying to find message_pattern in {} commits",
253+
commits.len()
254+
);
255+
commits
256+
.into_iter()
257+
.find(|commit| {
258+
commit
259+
.summary()
260+
.map(|s| s.contains(message_pattern))
261+
.unwrap_or(false)
262+
})
263+
.ok_or_else(|| anyhow::anyhow!("No commit contains the pattern in its summary"))
255264
} else {
256-
eprintln!("Select a commit to amend:");
265+
let rev_aliases = commits
266+
.iter()
267+
.enumerate()
268+
.map(|(i, commit)| {
269+
let bname = if i > 0 {
270+
branches
271+
.get(&commit.id())
272+
.map(|n| format!("({}) ", n))
273+
.unwrap_or_else(String::new)
274+
} else {
275+
String::new()
276+
};
277+
format!(
278+
"{} {}{}",
279+
&style(&commit.id().to_string()[0..10]).blue(),
280+
style(bname).green(),
281+
commit.summary().unwrap_or("no commit summary")
282+
)
283+
})
284+
.collect::<Vec<_>>();
285+
if upstream.is_none() {
286+
eprintln!("Select a commit to amend (no upstream for HEAD):");
287+
} else {
288+
eprintln!("Select a commit to amend:");
289+
}
290+
let selected = Select::new().items(&rev_aliases).default(0).interact();
291+
Ok(repo.find_commit(commits[selected?].id())?)
257292
}
258-
let selected = Select::new().items(&rev_aliases).default(0).interact();
259-
Ok(repo.find_commit(commits[selected?].id())?)
260293
}
261294

262295
fn format_ref(rf: &git2::Reference<'_>) -> Result<String, anyhow::Error> {

tests/basic.rs

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
use std::process::Output;
2+
13
use assert_cmd::Command;
24
use assert_fs::prelude::*;
35
use itertools::Itertools;
46

57
#[test]
68
fn test_can_compile() {
7-
let mut cmd = fixup();
9+
let td = assert_fs::TempDir::new().unwrap();
10+
let mut cmd = fixup(&td);
811
let ex = cmd.arg("--help").output().unwrap();
912
let out = String::from_utf8(ex.stdout).unwrap();
1013
let err = String::from_utf8(ex.stderr).unwrap();
@@ -23,18 +26,8 @@ fn test_straightforward() {
2326

2427
git_file_commit("a", &td);
2528
git_file_commit("b", &td);
26-
let out = git_log(&td);
27-
assert_eq!(
28-
out,
29-
"\
30-
* b HEAD -> main
31-
* a
32-
",
33-
"log:\n{}",
34-
out
35-
);
36-
3729
git(&["checkout", "-b", "changes", "HEAD~"], &td);
30+
git(&["branch", "-u", "main"], &td);
3831
for n in &["c", "d", "e"] {
3932
git_file_commit(&n, &td);
4033
}
@@ -55,20 +48,40 @@ fn test_straightforward() {
5548
);
5649

5750
td.child("new").touch().unwrap();
51+
git(&["add", "new"], &td);
52+
53+
fixup(&td).args(&["-P", "d"]).output().unwrap();
5854

59-
let cmd = fixup().write_stdin("q\n\n\n").unwrap();
60-
let err = string(cmd.stderr);
55+
let shown = git_out(
56+
&["diff-tree", "--no-commit-id", "--name-only", "-r", ":/d"],
57+
&td,
58+
);
59+
let files = string(shown.stdout);
60+
let err = string(shown.stderr);
6161

62-
assert_eq!(err, "nope", "err: {}", err);
62+
assert_eq!(
63+
files,
64+
"\
65+
file_d
66+
new
67+
",
68+
"out: {} err: {}",
69+
files,
70+
err
71+
);
6372
}
73+
///////////////////////////////////////////////////////////////////////////////
74+
// Helpers
6475

6576
fn git_init(tempdir: &assert_fs::TempDir) {
6677
git(&["init", "--initial-branch=main"], &tempdir);
78+
git(&["config", "user.email", "[email protected]"], &tempdir);
79+
git(&["config", "user.name", "nobody"], &tempdir);
6780
}
6881

6982
/// Create a file and commit it with a mesage that is just the name of the file
7083
fn git_file_commit(name: &str, tempdir: &assert_fs::TempDir) {
71-
tempdir.child(name).touch().unwrap();
84+
tempdir.child(format!("file_{}", name)).touch().unwrap();
7285
git(&["add", "-A"], &tempdir);
7386
git(&["commit", "-m", &name], &tempdir);
7487
}
@@ -78,6 +91,10 @@ fn git(args: &[&str], tempdir: &assert_fs::TempDir) {
7891
git_inner(args, tempdir).ok().unwrap();
7992
}
8093

94+
fn git_out(args: &[&str], tempdir: &assert_fs::TempDir) -> Output {
95+
git_inner(args, tempdir).output().unwrap()
96+
}
97+
8198
fn git_log(tempdir: &assert_fs::TempDir) -> String {
8299
let mut s = String::from_utf8(
83100
git_inner(&["log", "--all", "--format=%s %D", "--graph"], &tempdir)
@@ -104,6 +121,8 @@ fn git_inner(args: &[&str], tempdir: &assert_fs::TempDir) -> Command {
104121
}
105122

106123
/// Get something that can get args added to it
107-
fn fixup() -> Command {
108-
Command::cargo_bin("git-fixup").unwrap()
124+
fn fixup(dir: &assert_fs::TempDir) -> Command {
125+
let mut c = Command::cargo_bin("git-fixup").unwrap();
126+
c.current_dir(&dir.path());
127+
c
109128
}

0 commit comments

Comments
 (0)