@@ -124,15 +124,54 @@ func downloadBinaryAssets(ctx context.Context, binaryAssetsDirectory, binaryAsse
124124 }
125125 }
126126
127+ var requestedRange semver.Range
128+ if binaryAssetsVersion != "" {
129+ binaryAssetsVersion = strings .TrimPrefix (binaryAssetsVersion , "v" )
130+ parsedVersion , errV := semver .ParseTolerant (binaryAssetsVersion )
131+ parsedRange , errR := semver .ParseRange (binaryAssetsVersion )
132+
133+ switch {
134+ // When an exact version is requested, don't look for it in the release index.
135+ case errV == nil && parsedVersion .String () == binaryAssetsVersion :
136+ requestedRange = nil
137+
138+ // When the version looks like a range, apply it to the index.
139+ case errR == nil :
140+ requestedRange = parsedRange
141+
142+ // When the version isn't exact, turn it into a range.
143+ //
144+ // The `setup-envtest` tool interprets a partial version to mean "latest stable with that prefix."
145+ // For example, "1" and "1.2" are akin to "1.x.x" and "1.2.x" in [semver.ParseRange].
146+ // [semver.ParseTolerant] fills in missing minor or patch with "0", so this replaces those with "x".
147+ //
148+ // That *should* produce a valid range. If it doesn't, use the original value and skip the index.
149+ case errV == nil :
150+ suffix := strings .TrimPrefix (parsedVersion .FinalizeVersion (), binaryAssetsVersion )
151+ suffix = strings .ReplaceAll (suffix , "0" , "x" )
152+ parsedRange , errR = semver .ParseRange (binaryAssetsVersion + suffix )
153+
154+ if errR == nil {
155+ requestedRange = parsedRange
156+ } else {
157+ requestedRange = nil
158+ }
159+ }
160+ } else {
161+ // When no version is requested, look for one in the release index.
162+ requestedRange = semver .MustParseRange (">0.0.0" )
163+ }
164+
165+ // When a range a versions is requested, select one from the release index.
127166 var binaryAssetsIndex * index
128- if binaryAssetsVersion == "" || strings . Count ( binaryAssetsVersion , "." ) < 2 {
167+ if requestedRange != nil {
129168 var err error
130169 binaryAssetsIndex , err = getIndex (ctx , binaryAssetsIndexURL )
131170 if err != nil {
132171 return "" , "" , "" , err
133172 }
134173
135- binaryAssetsVersion , err = latestStableVersionFromIndex (binaryAssetsIndex , binaryAssetsVersion )
174+ binaryAssetsVersion , err = latestStableVersionFromIndex (binaryAssetsIndex , requestedRange )
136175 if err != nil {
137176 return "" , "" , "" , err
138177 }
@@ -219,6 +258,8 @@ func fileExists(path string) bool {
219258}
220259
221260func downloadBinaryAssetsArchive (ctx context.Context , index * index , version string , out io.Writer ) error {
261+ version = "v" + strings .TrimPrefix (version , "v" )
262+
222263 archives , ok := index .Releases [version ]
223264 if ! ok {
224265 return fmt .Errorf ("failed to find envtest binaries for version %s" , version )
@@ -252,26 +293,20 @@ func downloadBinaryAssetsArchive(ctx context.Context, index *index, version stri
252293 return readBody (resp , out , archiveName , archive .Hash )
253294}
254295
255- func latestStableVersionFromIndex (index * index , prefix string ) (string , error ) {
296+ func latestStableVersionFromIndex (index * index , satisfying semver. Range ) (string , error ) {
256297 if len (index .Releases ) == 0 {
257298 return "" , fmt .Errorf ("failed to find latest stable version from index: index is empty" )
258299 }
259300
260- prefix = strings .TrimPrefix (prefix , "v" )
261301 parsedVersions := []semver.Version {}
262302 for releaseVersion := range index .Releases {
263- // Filter on prefix.
264- if ! strings .HasPrefix (strings .TrimPrefix (releaseVersion , "v" ), prefix ) {
265- continue
266- }
267-
268303 v , err := semver .ParseTolerant (releaseVersion )
269304 if err != nil {
270305 return "" , fmt .Errorf ("failed to parse version %q: %w" , releaseVersion , err )
271306 }
272307
273- // Filter out pre-releases.
274- if len (v .Pre ) > 0 {
308+ // Filter out pre-releases and undesirable versions .
309+ if len (v .Pre ) > 0 || ! satisfying ( v ) {
275310 continue
276311 }
277312
0 commit comments