feat(git_commit): add git tag to module (#950)

This commit is contained in:
Miguel Ángel Melón Pérez 2020-10-23 17:49:19 +02:00 committed by GitHub
parent c938eac1d6
commit ea9f803018
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 157 additions and 11 deletions

View File

@ -1043,17 +1043,19 @@ truncation_symbol = ""
## Git Commit ## Git Commit
The `git_commit` module shows the current commit hash of the repo in your current directory. The `git_commit` module shows the current commit hash and also the tag (if any) of the repo in your current directory.
### Options ### Options
| Option | Default | Description | | Option | Default | Description |
| -------------------- | ------------------------ | ----------------------------------------------------- | | -------------------- | ---------------------------------------------- | ----------------------------------------------------- |
| `commit_hash_length` | `7` | The length of the displayed git commit hash. | | `commit_hash_length` | `7` | The length of the displayed git commit hash. |
| `format` | `'[\($hash\)]($style) '` | The format for the module. | | `format` | `"[\\($hash\\)]($style) [\\($tag\\)]($style)"` | The format for the module. |
| `style` | `"bold green"` | The style for the module. | | `style` | `"bold green"` | The style for the module. |
| `only_detached` | `true` | Only show git commit hash when in detached HEAD state | | `only_detached` | `true` | Only show git commit hash when in detached HEAD state |
| `disabled` | `false` | Disables the `git_commit` module. | | `tag_disabled` | `true` | Disables showing tag info in `git_commit` module. |
| `tag_symbol` | `"🏷 "` | Tag symbol prefixing the info shown |
| `disabled` | `false` | Disables the `git_commit` module. |
### Variables ### Variables
@ -1071,6 +1073,7 @@ The `git_commit` module shows the current commit hash of the repo in your curren
[git_commit] [git_commit]
commit_hash_length = 4 commit_hash_length = 4
tag_symbol = "🔖 "
``` ```
## Git State ## Git State

View File

@ -9,6 +9,8 @@ pub struct GitCommitConfig<'a> {
pub style: &'a str, pub style: &'a str,
pub only_detached: bool, pub only_detached: bool,
pub disabled: bool, pub disabled: bool,
pub tag_symbol: &'a str,
pub tag_disabled: bool,
} }
impl<'a> RootModuleConfig<'a> for GitCommitConfig<'a> { impl<'a> RootModuleConfig<'a> for GitCommitConfig<'a> {
@ -16,10 +18,12 @@ impl<'a> RootModuleConfig<'a> for GitCommitConfig<'a> {
GitCommitConfig { GitCommitConfig {
// be consistent with git by default, which has DEFAULT_ABBREV set to 7 // be consistent with git by default, which has DEFAULT_ABBREV set to 7
commit_hash_length: 7, commit_hash_length: 7,
format: "[\\($hash\\)]($style) ", format: "[\\($hash$tag\\)]($style) ",
style: "green bold", style: "green bold",
only_detached: true, only_detached: true,
disabled: false, disabled: false,
tag_symbol: "🏷 ",
tag_disabled: true,
} }
} }
} }

View File

@ -24,7 +24,9 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let head_commit = git_head.peel_to_commit().ok()?; let head_commit = git_head.peel_to_commit().ok()?;
let commit_oid = head_commit.id(); let commit_oid = head_commit.id();
let parsed = StringFormatter::new(config.format).and_then(|formatter| { let mut parsed;
parsed = StringFormatter::new(config.format).and_then(|formatter| {
formatter formatter
.map_style(|variable| match variable { .map_style(|variable| match variable {
"style" => Some(Ok(config.style)), "style" => Some(Ok(config.style)),
@ -40,6 +42,48 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
.parse(None) .parse(None)
}); });
if !config.tag_disabled {
// Let's get repo tags names
let tag_names = git_repo.tag_names(None).ok()?;
let tag_and_refs = tag_names.iter().flat_map(|name| {
let full_tag = format!("refs/tags/{}", name.unwrap());
git_repo
.find_reference(&full_tag)
.map(|reference| (String::from(name.unwrap()), reference))
});
let mut tag_name = String::new();
// Let's check if HEAD has some tag. If several, only gets first...
for (name, reference) in tag_and_refs {
if commit_oid == reference.peel_to_commit().ok()?.id() {
tag_name = name;
break;
}
}
// If we have tag...
if !tag_name.is_empty() {
parsed = StringFormatter::new(config.format).and_then(|formatter| {
formatter
.map_style(|variable| match variable {
"style" => Some(Ok(config.style)),
_ => None,
})
.map(|variable| match variable {
"hash" => Some(Ok(id_to_hex_abbrev(
commit_oid.as_bytes(),
config.commit_hash_length,
))),
_ => None,
})
.map(|variable| match variable {
"tag" => Some(Ok(format!(" {}{}", &config.tag_symbol, &tag_name))),
_ => None,
})
.parse(None)
});
}
};
module.set_segments(match parsed { module.set_segments(match parsed {
Ok(segments) => segments, Ok(segments) => segments,
Err(error) => { Err(error) => {
@ -196,4 +240,99 @@ mod tests {
assert_eq!(expected, actual); assert_eq!(expected, actual);
repo_dir.close() repo_dir.close()
} }
#[test]
fn test_render_commit_hash_with_tag_enabled() -> io::Result<()> {
let repo_dir = fixture_repo(FixtureProvider::GIT)?;
let mut git_commit = Command::new("git")
.args(&["rev-parse", "HEAD"])
.current_dir(&repo_dir.path())
.output()?
.stdout;
git_commit.truncate(7);
let commit_output = str::from_utf8(&git_commit).unwrap().trim();
let git_tag = Command::new("git")
.args(&["describe", "--tags", "--exact-match", "HEAD"])
.current_dir(&repo_dir.path())
.output()?
.stdout;
let tag_output = str::from_utf8(&git_tag).unwrap().trim();
let expected_output = format!("{} {}", commit_output, tag_output);
let actual = ModuleRenderer::new("git_commit")
.config(toml::toml! {
[git_commit]
only_detached = false
tag_disabled = false
tag_symbol = ""
})
.path(&repo_dir.path())
.collect();
let expected = Some(format!(
"{} ",
Color::Green
.bold()
.paint(format!("({})", expected_output.trim()))
.to_string()
));
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn test_render_commit_hash_only_detached_on_detached_with_tag_enabled() -> io::Result<()> {
let repo_dir = fixture_repo(FixtureProvider::GIT)?;
Command::new("git")
.args(&["checkout", "@~1"])
.current_dir(&repo_dir.path())
.output()?;
Command::new("git")
.args(&["tag", "tagOnDetached", "-m", "Testing tags on detached"])
.current_dir(&repo_dir.path())
.output()?;
let mut git_commit = Command::new("git")
.args(&["rev-parse", "HEAD"])
.current_dir(&repo_dir.path())
.output()?
.stdout;
git_commit.truncate(7);
let commit_output = str::from_utf8(&git_commit).unwrap().trim();
let git_tag = Command::new("git")
.args(&["describe", "--tags", "--exact-match", "HEAD"])
.current_dir(&repo_dir.path())
.output()?
.stdout;
let tag_output = str::from_utf8(&git_tag).unwrap().trim();
let expected_output = format!("{} {}", commit_output, tag_output);
let actual = ModuleRenderer::new("git_commit")
.config(toml::toml! {
[git_commit]
tag_disabled = false
tag_symbol = ""
})
.path(&repo_dir.path())
.collect();
let expected = Some(format!(
"{} ",
Color::Green
.bold()
.paint(format!("({})", expected_output.trim()))
.to_string()
));
assert_eq!(expected, actual);
Ok(())
}
} }

View File

@ -155,7 +155,7 @@ pub fn description(module: &str) -> &'static str {
"erlang" => "Current OTP version", "erlang" => "Current OTP version",
"gcloud" => "The current GCP client configuration", "gcloud" => "The current GCP client configuration",
"git_branch" => "The active branch of the repo in your current directory", "git_branch" => "The active branch of the repo in your current directory",
"git_commit" => "The active commit of the repo in your current directory", "git_commit" => "The active commit (and tag if any) of the repo in your current directory",
"git_state" => "The current git operation, and it's progress", "git_state" => "The current git operation, and it's progress",
"git_status" => "Symbol representing the state of the repo", "git_status" => "Symbol representing the state of the repo",
"golang" => "The currently installed version of Golang", "golang" => "The currently installed version of Golang",