@@ -19,8 +19,11 @@ package libgit2
19
19
import (
20
20
"context"
21
21
"fmt"
22
+ "sort"
23
+ "time"
22
24
23
- "github.com/blang/semver/v4"
25
+ "github.com/Masterminds/semver/v3"
26
+ "github.com/fluxcd/pkg/version"
24
27
git2go "github.com/libgit2/git2go/v31"
25
28
26
29
"github.com/fluxcd/pkg/gitutil"
@@ -168,7 +171,7 @@ type CheckoutSemVer struct {
168
171
}
169
172
170
173
func (c * CheckoutSemVer ) Checkout (ctx context.Context , path , url string , auth * git.Auth ) (git.Commit , string , error ) {
171
- rng , err := semver .ParseRange (c .semVer )
174
+ verConstraint , err := semver .NewConstraint (c .semVer )
172
175
if err != nil {
173
176
return nil , "" , fmt .Errorf ("semver parse range error: %w" , err )
174
177
}
@@ -186,28 +189,61 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, auth *g
186
189
return nil , "" , fmt .Errorf ("unable to clone '%s', error: %w" , url , err )
187
190
}
188
191
189
- repoTags , err := repo .Tags .List ()
190
- if err != nil {
191
- return nil , "" , fmt .Errorf ("git list tags error: %w" , err )
192
- }
192
+ tags := make (map [string ]string )
193
+ tagTimestamps := make (map [string ]time.Time )
194
+ if err := repo .Tags .Foreach (func (name string , id * git2go.Oid ) error {
195
+ tag , err := repo .LookupTag (id )
196
+ if err != nil {
197
+ return nil
198
+ }
193
199
194
- svTags := make (map [string ]string )
195
- var svers []semver.Version
196
- for _ , tag := range repoTags {
197
- v , _ := semver .ParseTolerant (tag )
198
- if rng (v ) {
199
- svers = append (svers , v )
200
- svTags [v .String ()] = tag
200
+ commit , err := tag .Peel (git2go .ObjectCommit )
201
+ if err != nil {
202
+ return fmt .Errorf ("can't get commit for tag %s: %w" , name , err )
201
203
}
204
+ c , err := commit .AsCommit ()
205
+ if err != nil {
206
+ return err
207
+ }
208
+ tagTimestamps [tag .Name ()] = c .Committer ().When
209
+ tags [tag .Name ()] = name
210
+ return nil
211
+ }); err != nil {
212
+ return nil , "" , err
202
213
}
203
214
204
- if len (svers ) == 0 {
215
+ var matchedVersions semver.Collection
216
+ for tag , _ := range tags {
217
+ v , err := version .ParseVersion (tag )
218
+ if err != nil {
219
+ continue
220
+ }
221
+ if ! verConstraint .Check (v ) {
222
+ continue
223
+ }
224
+ matchedVersions = append (matchedVersions , v )
225
+ }
226
+ if len (matchedVersions ) == 0 {
205
227
return nil , "" , fmt .Errorf ("no match found for semver: %s" , c .semVer )
206
228
}
207
229
208
- semver .Sort (svers )
209
- v := svers [len (svers )- 1 ]
210
- t := svTags [v .String ()]
230
+ // Sort versions
231
+ sort .SliceStable (matchedVersions , func (i , j int ) bool {
232
+ left := matchedVersions [i ]
233
+ right := matchedVersions [j ]
234
+
235
+ if ! left .Equal (right ) {
236
+ return left .LessThan (right )
237
+ }
238
+
239
+ // Having tag target timestamps at our disposal, we further try to sort
240
+ // versions into a chronological order. This is especially important for
241
+ // versions that differ only by build metadata, because it is not considered
242
+ // a part of the comparable version in Semver
243
+ return tagTimestamps [left .String ()].Before (tagTimestamps [right .String ()])
244
+ })
245
+ v := matchedVersions [len (matchedVersions )- 1 ]
246
+ t := v .Original ()
211
247
212
248
ref , err := repo .References .Dwim (t )
213
249
if err != nil {
0 commit comments