1
- use super :: { utils:: repo, CommitId } ;
1
+ use super :: { get_commits_info , utils:: repo, CommitId } ;
2
2
use crate :: error:: Result ;
3
3
use scopetime:: scope_time;
4
- use std:: collections:: BTreeMap ;
4
+ use std:: collections:: { BTreeMap , HashMap , HashSet } ;
5
5
6
6
/// all tags pointing to a single commit
7
7
pub type CommitTags = Vec < String > ;
8
8
/// hashmap of tag target commit hash to tag names
9
9
pub type Tags = BTreeMap < CommitId , CommitTags > ;
10
10
11
+ ///
12
+ pub struct TagWithMetadata {
13
+ ///
14
+ pub name : String ,
15
+ ///
16
+ pub author : String ,
17
+ ///
18
+ pub time : i64 ,
19
+ ///
20
+ pub message : String ,
21
+ ///
22
+ pub commit_id : CommitId ,
23
+ }
24
+
25
+ static MAX_MESSAGE_WIDTH : usize = 100 ;
26
+
11
27
/// returns `Tags` type filled with all tags found in repo
12
28
pub fn get_tags ( repo_path : & str ) -> Result < Tags > {
13
29
scope_time ! ( "get_tags" ) ;
@@ -31,8 +47,12 @@ pub fn get_tags(repo_path: &str) -> Result<Tags> {
31
47
//NOTE: find_tag (git_tag_lookup) only works on annotated tags
32
48
// lightweight tags `id` already points to the target commit
33
49
// see https://github.com/libgit2/libgit2/issues/5586
34
- if let Ok ( tag) = repo. find_tag ( id) {
35
- adder ( CommitId :: new ( tag. target_id ( ) ) , name) ;
50
+ if let Ok ( commit) = repo
51
+ . find_tag ( id)
52
+ . and_then ( |tag| tag. target ( ) )
53
+ . and_then ( |target| target. peel_to_commit ( ) )
54
+ {
55
+ adder ( CommitId :: new ( commit. id ( ) ) , name) ;
36
56
} else if repo. find_commit ( id) . is_ok ( ) {
37
57
adder ( CommitId :: new ( id) , name) ;
38
58
}
@@ -45,6 +65,69 @@ pub fn get_tags(repo_path: &str) -> Result<Tags> {
45
65
Ok ( res)
46
66
}
47
67
68
+ ///
69
+ pub fn get_tags_with_metadata (
70
+ repo_path : & str ,
71
+ ) -> Result < Vec < TagWithMetadata > > {
72
+ scope_time ! ( "get_tags_with_metadata" ) ;
73
+
74
+ let tags_grouped_by_commit_id = get_tags ( repo_path) ?;
75
+
76
+ let tags_with_commit_id: Vec < ( & str , & CommitId ) > =
77
+ tags_grouped_by_commit_id
78
+ . iter ( )
79
+ . flat_map ( |( commit_id, tags) | {
80
+ tags. iter ( )
81
+ . map ( |tag| ( tag. as_ref ( ) , commit_id) )
82
+ . collect :: < Vec < ( & str , & CommitId ) > > ( )
83
+ } )
84
+ . collect ( ) ;
85
+
86
+ let unique_commit_ids: HashSet < _ > = tags_with_commit_id
87
+ . iter ( )
88
+ . copied ( )
89
+ . map ( |( _, & commit_id) | commit_id)
90
+ . collect ( ) ;
91
+ let mut commit_ids = Vec :: with_capacity ( unique_commit_ids. len ( ) ) ;
92
+ commit_ids. extend ( unique_commit_ids) ;
93
+
94
+ let commit_infos =
95
+ get_commits_info ( repo_path, & commit_ids, MAX_MESSAGE_WIDTH ) ?;
96
+ let unique_commit_infos: HashMap < _ , _ > = commit_infos
97
+ . iter ( )
98
+ . map ( |commit_info| ( commit_info. id , commit_info) )
99
+ . collect ( ) ;
100
+
101
+ let mut tags: Vec < TagWithMetadata > = tags_with_commit_id
102
+ . into_iter ( )
103
+ . filter_map ( |( tag, commit_id) | {
104
+ unique_commit_infos. get ( commit_id) . map ( |commit_info| {
105
+ TagWithMetadata {
106
+ name : String :: from ( tag) ,
107
+ author : commit_info. author . clone ( ) ,
108
+ time : commit_info. time ,
109
+ message : commit_info. message . clone ( ) ,
110
+ commit_id : * commit_id,
111
+ }
112
+ } )
113
+ } )
114
+ . collect ( ) ;
115
+
116
+ tags. sort_unstable_by ( |a, b| b. time . cmp ( & a. time ) ) ;
117
+
118
+ Ok ( tags)
119
+ }
120
+
121
+ ///
122
+ pub fn delete_tag ( repo_path : & str , tag_name : & str ) -> Result < ( ) > {
123
+ scope_time ! ( "delete_tag" ) ;
124
+
125
+ let repo = repo ( repo_path) ?;
126
+ repo. tag_delete ( tag_name) ?;
127
+
128
+ Ok ( ( ) )
129
+ }
130
+
48
131
#[ cfg( test) ]
49
132
mod tests {
50
133
use super :: * ;
@@ -82,5 +165,26 @@ mod tests {
82
165
get_tags( repo_path) . unwrap( ) [ & CommitId :: new( head_id) ] ,
83
166
vec![ "a" , "b" ]
84
167
) ;
168
+
169
+ let tags = get_tags_with_metadata ( repo_path) . unwrap ( ) ;
170
+
171
+ assert_eq ! ( tags. len( ) , 2 ) ;
172
+ assert_eq ! ( tags[ 0 ] . name, "a" ) ;
173
+ assert_eq ! ( tags[ 0 ] . message, "initial" ) ;
174
+ assert_eq ! ( tags[ 1 ] . name, "b" ) ;
175
+ assert_eq ! ( tags[ 1 ] . message, "initial" ) ;
176
+ assert_eq ! ( tags[ 0 ] . commit_id, tags[ 1 ] . commit_id) ;
177
+
178
+ delete_tag ( repo_path, "a" ) . unwrap ( ) ;
179
+
180
+ let tags = get_tags ( repo_path) . unwrap ( ) ;
181
+
182
+ assert_eq ! ( tags. len( ) , 1 ) ;
183
+
184
+ delete_tag ( repo_path, "b" ) . unwrap ( ) ;
185
+
186
+ let tags = get_tags ( repo_path) . unwrap ( ) ;
187
+
188
+ assert_eq ! ( tags. len( ) , 0 ) ;
85
189
}
86
190
}
0 commit comments