Skip to content

Commit 5496bdd

Browse files
fbenksteinjpgrayson
authored andcommitted
feat: new "name" subcommand
Add a "stg name" command that works like "stg id" but returns the patch name instead of the revision. This can be useful for scripting and some command aliases. This is a generalization of the "stg next" command: "stg next" is now equivalent to "stg name +1".
1 parent 7594d78 commit 5496bdd

File tree

3 files changed

+146
-0
lines changed

3 files changed

+146
-0
lines changed

src/cmd/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub(crate) mod id;
2525
pub(crate) mod import;
2626
pub(crate) mod init;
2727
pub(crate) mod log;
28+
pub(crate) mod name;
2829
pub(crate) mod new;
2930
pub(crate) mod next;
3031
pub(crate) mod patches;
@@ -101,6 +102,7 @@ pub(crate) const STGIT_COMMANDS: &[StGitCommand] = &[
101102
import::STGIT_COMMAND,
102103
init::STGIT_COMMAND,
103104
log::STGIT_COMMAND,
105+
name::STGIT_COMMAND,
104106
new::STGIT_COMMAND,
105107
next::STGIT_COMMAND,
106108
patches::STGIT_COMMAND,

src/cmd/name.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
//! `stg name` implementation.
4+
5+
use std::io::Write;
6+
7+
use anyhow::{anyhow, Result};
8+
use clap::{Arg, ArgMatches};
9+
use termcolor::WriteColor;
10+
11+
use crate::{
12+
argset,
13+
branchloc::BranchLocator,
14+
ext::RepositoryExtended,
15+
patch::SingleRevisionSpec,
16+
stack::{InitializationPolicy, Stack, StackAccess, StackStateAccess},
17+
};
18+
19+
pub(super) const STGIT_COMMAND: super::StGitCommand = super::StGitCommand {
20+
name: "name",
21+
category: super::CommandCategory::PatchInspection,
22+
make,
23+
run,
24+
};
25+
26+
fn make() -> clap::Command {
27+
clap::Command::new(STGIT_COMMAND.name)
28+
.about("Print patch name of a StGit revision")
29+
.long_about(
30+
"Print the patch name of a StGit revision.\n\
31+
\n\
32+
Try to get the name of the patch in the current \
33+
branch as specified by a StGit revision. Revisions \
34+
can be specified in the all the forms accepted by \
35+
\"stg id\" command.",
36+
)
37+
.arg(argset::branch_arg())
38+
.arg(
39+
Arg::new("show-branch")
40+
.long("showbranch")
41+
.help("Display the branch name with the patch")
42+
.action(clap::ArgAction::SetTrue),
43+
)
44+
.arg(
45+
Arg::new("no-show-branch")
46+
.long("no-showbranch")
47+
.help("Do not display branch name")
48+
.hide(true)
49+
.action(clap::ArgAction::SetTrue)
50+
.overrides_with("show-branch"),
51+
)
52+
.arg(
53+
Arg::new("stgit-revision")
54+
.value_name("revision")
55+
.allow_hyphen_values(true)
56+
.value_parser(clap::value_parser!(SingleRevisionSpec))
57+
.help("StGit revision"),
58+
)
59+
}
60+
61+
fn run(matches: &ArgMatches) -> Result<()> {
62+
let repo = gix::Repository::open()?;
63+
64+
let stack = Stack::from_branch_locator(
65+
&repo,
66+
matches.get_one::<BranchLocator>("branch"),
67+
InitializationPolicy::RequireInitialized,
68+
)?;
69+
70+
let oid = matches
71+
.get_one::<SingleRevisionSpec>("stgit-revision")
72+
.map(|spec| spec.resolve_object(&repo, &stack).map(|object| object.id))
73+
.transpose()?
74+
.unwrap_or_else(|| stack.get_branch_head().id);
75+
76+
let Some(patch_name) = (oid == stack.base().id).then_some("{base}").or_else(|| {
77+
stack
78+
.all_patches()
79+
.find(|name| oid == stack.get_patch_commit_id(name))
80+
.map(|name| name.as_ref())
81+
}) else {
82+
return Err(anyhow!("patch name not found for revision `{oid}`"));
83+
};
84+
85+
let mut stdout = crate::color::get_color_stdout(matches);
86+
let mut color_spec = termcolor::ColorSpec::new();
87+
color_spec.set_bold(true);
88+
stdout.set_color(&color_spec)?;
89+
90+
if matches.get_flag("show-branch") {
91+
write!(stdout, "{}:", stack.get_branch_name())?;
92+
}
93+
94+
write!(stdout, "{patch_name}")?;
95+
color_spec.clear();
96+
stdout.set_color(&color_spec)?;
97+
writeln!(stdout)?;
98+
99+
Ok(())
100+
}

t/t3700-name.sh

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/sh
2+
3+
test_description="Test 'stg name'"
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success 'Test on uninitialized repo' '
8+
command_error stg name 2>err &&
9+
grep "stack not initialized" err
10+
'
11+
12+
test_expect_success 'Init repo' '
13+
echo "foo" >foo.txt &&
14+
git add foo.txt &&
15+
git commit -m "initial" &&
16+
git commit --allow-empty -m "base" &&
17+
git branch nostack &&
18+
for i in 1 2; do
19+
echo "line $i" >>foo.txt &&
20+
stg new -m "patch-$i" &&
21+
stg refresh || return 1
22+
done &&
23+
stg branch -C cloned &&
24+
stg branch -c forked &&
25+
stg branch master
26+
'
27+
28+
test_expect_success 'Get patch names' '
29+
test "$(stg name)" = "patch-2" &&
30+
test "$(stg name -1)" = "patch-1" &&
31+
test "$(stg name 0~1)" = "{base}" &&
32+
test "$(stg name --showbranch)" = "master:patch-2" &&
33+
test "$(stg name -b cloned --showbranch)" = "cloned:patch-2" &&
34+
test "$(stg name -b forked --showbranch)" = "forked:{base}"
35+
'
36+
37+
test_expect_success 'Fail to get patch names' '
38+
command_error stg name -b nostack --showbranch 2>err &&
39+
grep "stack not initialized" err &&
40+
command_error stg name 0~2 2>err &&
41+
grep "patch name not found" err
42+
'
43+
44+
test_done

0 commit comments

Comments
 (0)