@@ -85,17 +85,78 @@ public Tag ToTagClient(LibGit2Sharp.Tag tag)
8585 {
8686 using ( Context . BeginOperationScope ( ) )
8787 {
88- var result = GetProject ( _projectId , ProjectPermission . View ) . Repository . GetTags ( ) ;
88+ IEnumerable < LibGit2Sharp . Tag > result = GetProject ( _projectId , ProjectPermission . View ) . Repository . GetTags ( ) ;
8989 if ( query != null )
9090 {
91- if ( ! string . IsNullOrEmpty ( query . Sort ) )
92- throw new NotImplementedException ( ) ;
93-
94- if ( ! string . IsNullOrEmpty ( query . OrderBy ) )
95- throw new NotImplementedException ( ) ;
91+ result = ApplyQuery ( result , query . OrderBy , query . Sort ) ;
9692 }
9793
98- return GitLabCollectionResponse . Create ( result . Select ( tag => ToTagClient ( tag ) ) . ToArray ( ) ) ;
94+ return GitLabCollectionResponse . Create ( result . Select ( ToTagClient ) . ToArray ( ) ) ;
95+ }
96+
97+ static IEnumerable < LibGit2Sharp . Tag > ApplyQuery ( IEnumerable < LibGit2Sharp . Tag > tags , string orderBy , string direction )
98+ {
99+ tags = orderBy switch
100+ {
101+ "name" => tags . OrderBy ( t => t . FriendlyName , StringComparer . Ordinal ) ,
102+ "version" => tags . OrderBy ( t => t . FriendlyName , SemanticVersionComparer . Instance ) ,
103+ null => tags ,
104+
105+ // LibGitSharp does not really expose tag creation time, so hard to sort using that annotation,
106+ "updated" => throw new NotSupportedException ( "Sorting by 'updated' is not supported since the info is not available in LibGit2Sharp." ) ,
107+ _ => throw new NotSupportedException ( $ "Sorting by '{ orderBy } ' is not supported.") ,
108+ } ;
109+
110+ if ( string . IsNullOrEmpty ( direction ) )
111+ direction = "desc" ;
112+
113+ return direction switch
114+ {
115+ "desc" => tags . Reverse ( ) ,
116+ "asc" => tags ,
117+ _ => throw new NotSupportedException ( $ "Sort direction must be 'asc' or 'desc', got '{ direction } ' instead") ,
118+ } ;
119+ }
120+ }
121+
122+ private sealed class SemanticVersionComparer : IComparer < string >
123+ {
124+ public static SemanticVersionComparer Instance { get ; } = new ( ) ;
125+
126+ public int Compare ( string x , string y )
127+ {
128+ var versionX = ParseVersion ( x ) ;
129+ var versionY = ParseVersion ( y ) ;
130+
131+ var majorCmp = versionX . Major . CompareTo ( versionY . Major ) ;
132+ if ( majorCmp != 0 )
133+ return majorCmp ;
134+
135+ var minorCmp = versionX . Minor . CompareTo ( versionY . Minor ) ;
136+ if ( minorCmp != 0 )
137+ return minorCmp ;
138+
139+ return versionX . Patch . CompareTo ( versionY . Patch ) ;
140+ }
141+
142+ private static ( int Major , int Minor , int Patch ) ParseVersion ( string version )
143+ {
144+ if ( string . IsNullOrEmpty ( version ) )
145+ return ( 0 , 0 , 0 ) ;
146+
147+ // Strip leading 'v' or 'V' if present
148+ if ( version . StartsWith ( "v" , StringComparison . OrdinalIgnoreCase ) )
149+ version = version [ 1 ..] ;
150+
151+ if ( version . IndexOf ( '-' ) is int dashIndex and not - 1 )
152+ version = version [ ..dashIndex ] ;
153+
154+ var parts = version . Split ( '.' ) ;
155+ var major = parts . Length > 0 && int . TryParse ( parts [ 0 ] , out var m ) ? m : 0 ;
156+ var minor = parts . Length > 1 && int . TryParse ( parts [ 1 ] , out var n ) ? n : 0 ;
157+ var patch = parts . Length > 2 && int . TryParse ( parts [ 2 ] , out var p ) ? p : 0 ;
158+
159+ return ( major , minor , patch ) ;
99160 }
100161 }
101162}
0 commit comments