support multiple tags per commit (#62)

* support multiple tags per commit
* update changelog
* make sure clippy works in CI
This commit is contained in:
Stephan Dilly 2020-05-16 20:14:27 +02:00 committed by GitHub
parent 3375128d91
commit 8b096fb9e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 62 additions and 11 deletions

View file

@ -26,6 +26,7 @@ jobs:
- name: Run clippy - name: Run clippy
run: | run: |
rustup component add clippy rustup component add clippy
cargo clean
make clippy make clippy
- name: Build Release - name: Build Release
run: make build-release run: make build-release

View file

@ -15,6 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- better error message when trying to run outside of a valid git repo ([#56](https://github.com/extrawurst/gitui/issues/56)) - better error message when trying to run outside of a valid git repo ([#56](https://github.com/extrawurst/gitui/issues/56))
- improve ctrl+c handling so it is checked first and no component needs to worry of blocking it - improve ctrl+c handling so it is checked first and no component needs to worry of blocking it
### Fixed
- support multiple tags per commit in log ([#61](https://github.com/extrawurst/gitui/issues/61))
## [0.2.3] - 2020-05-12 ## [0.2.3] - 2020-05-12
### Added ### Added
- support more navigation keys: home/end/pageUp/pageDown ([#43](https://github.com/extrawurst/gitui/issues/43)) - support more navigation keys: home/end/pageUp/pageDown ([#43](https://github.com/extrawurst/gitui/issues/43))

View file

@ -26,7 +26,7 @@ test:
cargo test --workspace cargo test --workspace
clippy: clippy:
cargo clean cargo clean -p gitui -p asyncgit -p scopetime
cargo clippy --all-features cargo clippy --all-features
clippy-pedantic: clippy-pedantic:

View file

@ -3,14 +3,21 @@ use crate::error::Result;
use scopetime::scope_time; use scopetime::scope_time;
use std::collections::HashMap; use std::collections::HashMap;
/// hashmap of tag target commit hash to tag name /// hashmap of tag target commit hash to tag names
pub type Tags = HashMap<String, String>; pub type Tags = HashMap<String, Vec<String>>;
/// returns `Tags` type filled with all tags found in repo /// returns `Tags` type filled with all tags found in repo
pub fn get_tags(repo_path: &str) -> Result<Tags> { pub fn get_tags(repo_path: &str) -> Result<Tags> {
scope_time!("get_tags"); scope_time!("get_tags");
let mut res = Tags::new(); let mut res = Tags::new();
let mut adder = |key: String, value: String| {
if let Some(key) = res.get_mut(&key) {
key.push(value)
} else {
res.insert(key, vec![value]);
}
};
let repo = repo(repo_path)?; let repo = repo(repo_path)?;
@ -21,10 +28,50 @@ pub fn get_tags(repo_path: &str) -> Result<Tags> {
if let Some(tag) = obj.as_tag() { if let Some(tag) = obj.as_tag() {
let target_hash = tag.target_id().to_string(); let target_hash = tag.target_id().to_string();
let tag_name = String::from(name); let tag_name = String::from(name);
res.insert(target_hash, tag_name); adder(target_hash, tag_name);
} }
} }
} }
Ok(res) Ok(res)
} }
#[cfg(test)]
mod tests {
use super::*;
use crate::sync::tests::repo_init;
use git2::ObjectType;
#[test]
fn test_smoke() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
assert_eq!(get_tags(repo_path).unwrap().is_empty(), true);
}
#[test]
fn test_multitags() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
let sig = repo.signature().unwrap();
let head_id = repo.head().unwrap().target().unwrap();
let target = repo
.find_object(
repo.head().unwrap().target().unwrap(),
Some(ObjectType::Commit),
)
.unwrap();
repo.tag("a", &target, &sig, "", false).unwrap();
repo.tag("b", &target, &sig, "", false).unwrap();
assert_eq!(
get_tags(repo_path).unwrap()[&head_id.to_string()],
vec!["a", "b"]
);
}
}

View file

@ -167,7 +167,7 @@ impl Revlog {
e: &'a LogEntry, e: &'a LogEntry,
selected: bool, selected: bool,
txt: &mut Vec<Text<'a>>, txt: &mut Vec<Text<'a>>,
tag: &'a str, tags: Option<String>,
) { ) {
let count_before = txt.len(); let count_before = txt.len();
@ -209,10 +209,10 @@ impl Revlog {
)); ));
txt.push(splitter.clone()); txt.push(splitter.clone());
txt.push(Text::Styled( txt.push(Text::Styled(
Cow::from(if tag.is_empty() { Cow::from(if let Some(tags) = tags {
String::from("") format!(" {}", tags)
} else { } else {
format!(" {}", tag) String::from("")
}), }),
if selected { if selected {
STYLE_TAG_SELECTED STYLE_TAG_SELECTED
@ -250,10 +250,10 @@ impl DrawableComponent for Revlog {
let mut txt = Vec::new(); let mut txt = Vec::new();
for (idx, e) in self.items.items.iter().enumerate() { for (idx, e) in self.items.items.iter().enumerate() {
let tag = if let Some(tag_name) = self.tags.get(&e.hash) { let tag = if let Some(tags) = self.tags.get(&e.hash) {
tag_name.as_str() Some(tags.join(" "))
} else { } else {
"" None
}; };
Self::add_entry(e, idx == selection, &mut txt, tag); Self::add_entry(e, idx == selection, &mut txt, tag);
} }