Skip to content
This repository was archived by the owner on Jun 11, 2021. It is now read-only.

Commit 9924a88

Browse files
authored
WIP: Add function to return module version from a slice of string versions (#17)
* Add function to return module version from a slice of string versions * Add functionality for testing if a version is a valid conditional version * Add functionality for testing if a version is a valid version * Refactor registry code to make use module version code * Add comment to make return statement clearer * Rename GetRegistryVersions to be a bit clearer * Test versions returned by GetRegistrySource
1 parent 5494509 commit 9924a88

File tree

5 files changed

+151
-41
lines changed

5 files changed

+151
-41
lines changed

Terrafile.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ vendor_dir: vendor/modules
22

33
terrafile-test-registry:
44
source: "terraform-digitalocean-modules/droplet/digitalocean"
5-
version: "0.1.x"
5+
#version: "0.1.x"
66
terrafile-test-https:
77
source: "github.com/terraform-digitalocean-modules/terraform-digitalocean-droplet.git"
88
terrafile-test-tag:

pkg/module_version.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright © 2019 Tim Birkett <[email protected]>
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package xterrafile
22+
23+
import (
24+
"errors"
25+
26+
"github.com/blang/semver"
27+
)
28+
29+
func isValidVersion(version string) bool {
30+
_, err := semver.ParseTolerant(version)
31+
if err != nil {
32+
return false
33+
}
34+
return true
35+
}
36+
37+
func isConditionalVersion(versionConditional string) bool {
38+
_, err := semver.ParseRange(versionConditional)
39+
if err != nil {
40+
return false
41+
}
42+
return true
43+
}
44+
45+
func getModuleVersion(sourceVersions []string, versionConditional string) (string, error) {
46+
var validSourceVersions []semver.Version
47+
48+
for _, sourceVersion := range sourceVersions {
49+
v, err := semver.ParseTolerant(sourceVersion)
50+
if err != nil {
51+
continue
52+
}
53+
validSourceVersions = append(validSourceVersions, v)
54+
}
55+
56+
semver.Sort(validSourceVersions)
57+
58+
// Assume latest if we get passed an empty string
59+
if versionConditional == "" {
60+
return validSourceVersions[len(validSourceVersions)-1].String(), nil
61+
}
62+
63+
validModuleVersionRange, err := semver.ParseRange(versionConditional)
64+
if err != nil {
65+
return "", err
66+
}
67+
68+
for i := range validSourceVersions {
69+
v := validSourceVersions[len(validSourceVersions)-1-i]
70+
if validModuleVersionRange(v) {
71+
return v.String(), nil
72+
}
73+
}
74+
75+
err = errors.New("Unable to find a valid version of this module")
76+
return "", err
77+
}

pkg/module_version_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package xterrafile
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestIsValidVersion(t *testing.T) {
10+
assert.False(t, isValidVersion("2e6b9729f3f6ea3ef5190bac0b0e1544a01fd80f"))
11+
assert.False(t, isValidVersion(">= 2.0.0 < 2.2.0"))
12+
assert.True(t, isValidVersion("1.1.1"))
13+
}
14+
15+
func TestIsConditionalVersion(t *testing.T) {
16+
assert.False(t, isConditionalVersion("2e6b9729f3f6ea3ef5190bac0b0e1544a01fd80f"))
17+
assert.True(t, isConditionalVersion(">= 2.0.0 < 2.2.0"))
18+
assert.True(t, isConditionalVersion("1.1.1"))
19+
}
20+
21+
func TestGetModuleVersion(t *testing.T) {
22+
var version string
23+
var err error
24+
25+
version, _ = getModuleVersion([]string{"1.1.1", "2.1.1", "2.0.1"}, "1.1.1")
26+
assert.Equal(t, "1.1.1", version, "version should be 1.1.1")
27+
28+
version, _ = getModuleVersion([]string{"1.1.1", "2.1.1", "2.0.1"}, "")
29+
assert.Equal(t, "2.1.1", version, "version should be 2.1.1")
30+
31+
version, _ = getModuleVersion([]string{"1.1.1", "not-a-version", "2.1.1", "2.0.1"}, ">= 2.0.0 < 2.2.0")
32+
assert.Equal(t, "2.1.1", version, "version should be 2.1.1")
33+
34+
_, err = getModuleVersion([]string{"1.1.1", "2.1.1", "2.0.1"}, ">= no < version")
35+
assert.EqualError(t, err, "Could not get version from string: \">=no\"")
36+
37+
_, err = getModuleVersion([]string{"not", "a", "version"}, ">= 2.0.0 < 2.2.0")
38+
assert.EqualError(t, err, "Unable to find a valid version of this module")
39+
40+
_, err = getModuleVersion([]string{}, ">= 2.0.0 < 2.2.0")
41+
assert.EqualError(t, err, "Unable to find a valid version of this module")
42+
}

pkg/registry.go

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@
2121
package xterrafile
2222

2323
import (
24-
"fmt"
2524
"io/ioutil"
2625
"log"
2726

28-
"github.com/blang/semver"
2927
"github.com/hashicorp/terraform/registry"
3028
"github.com/hashicorp/terraform/registry/regsrc"
3129
"github.com/hashicorp/terraform/svchost/disco"
@@ -42,14 +40,22 @@ func IsRegistrySourceAddr(addr string) bool {
4240

4341
// GetRegistrySource retrieves a modules download source from a Terraform registry
4442
func GetRegistrySource(name string, source string, version string, services *disco.Disco) (string, string) {
43+
var modVersions []string
4544

4645
modSrc, err := getModSrc(source)
4746
CheckIfError(name, err)
4847

4948
regClient := registry.NewClient(services, nil)
5049

51-
version, err = getRegistryVersion(regClient, modSrc, version)
52-
CheckIfError(name, err)
50+
switch {
51+
case isValidVersion(version):
52+
_ = version
53+
default:
54+
modVersions = getRegistryModuleVersions(regClient, modSrc)
55+
version, err = getModuleVersion(modVersions, version)
56+
CheckIfError(name, err)
57+
}
58+
5359
jww.INFO.Printf("[%s] Found module version %s at %s", name, version, modSrc.Host())
5460

5561
regSrc, err := regClient.ModuleLocation(modSrc, version)
@@ -59,35 +65,22 @@ func GetRegistrySource(name string, source string, version string, services *dis
5965
return regSrc, version
6066
}
6167

62-
// Helper function to return a valid version
63-
func getRegistryVersion(c *registry.Client, modSrc *regsrc.Module, version string) (string, error) {
68+
// Helper function to return a list of available module versions
69+
func getRegistryModuleVersions(c *registry.Client, modSrc *regsrc.Module) []string {
6470
// Don't log from Terraform's HTTP client
6571
log.SetFlags(0)
6672
log.SetOutput(ioutil.Discard)
6773

68-
validModuleVersionRange, err := semver.ParseRange(version)
69-
if err != nil {
70-
return "", err
71-
}
72-
73-
regClientResp, err := c.ModuleVersions(modSrc)
74-
if err != nil {
75-
return "", err
76-
}
74+
regClientResp, _ := c.ModuleVersions(modSrc)
7775

7876
regModule := regClientResp.Modules[0]
79-
for _, moduleVersion := range regModule.Versions {
80-
v, _ := semver.ParseTolerant(moduleVersion.Version)
77+
moduleVersions := []string{}
8178

82-
if validModuleVersionRange(v) {
83-
return v.String(), nil
84-
}
79+
for _, moduleVersion := range regModule.Versions {
80+
moduleVersions = append(moduleVersions, moduleVersion.Version)
8581
}
86-
err = fmt.Errorf(
87-
"Unable to find a valid version at %s newest version is %s",
88-
modSrc.Host(),
89-
regModule.Versions[0].Version)
90-
return "", err
82+
83+
return moduleVersions
9184
}
9285

9386
// Helper function to parse and return a module source

pkg/registry_test.go

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,17 @@ func TestGetRegistrySource(t *testing.T) {
2626
server := test.Registry()
2727
defer server.Close()
2828

29-
module1Src, module1Version := GetRegistrySource("droplet", "example.com/test-versions/name/provider", "2.1.x", test.Disco(server))
29+
module1Src, module1Version := GetRegistrySource("droplet", "example.com/test-versions/name/provider", "1.2.x", test.Disco(server))
3030
assert.IsType(t, "string", module1Src, "download URL should be a string")
31-
assert.IsType(t, "string", module1Version, "download version should be a string")
31+
assert.Equal(t, "1.2.2", module1Version)
32+
33+
module2Src, module2Version := GetRegistrySource("droplet", "example.com/test-versions/name/provider", "2.1.0", test.Disco(server))
34+
assert.IsType(t, "string", module2Src, "download URL should be a string")
35+
assert.Equal(t, "2.1.0", module2Version)
36+
37+
module3Src, module3Version := GetRegistrySource("droplet", "example.com/test-versions/name/provider", "", test.Disco(server))
38+
assert.IsType(t, "string", module3Src, "download URL should be a string")
39+
assert.Equal(t, "2.2.0", module3Version)
3240

3341
}
3442

@@ -49,23 +57,13 @@ func TestGetModSrc(t *testing.T) {
4957
assert.Panics(t, func() { module3Src.Host().Normalized() }, "accessing host should panic")
5058
}
5159

52-
func TestGetRegistryVersion(t *testing.T) {
60+
func TestGetRegistryModuleVersions(t *testing.T) {
5361
server := test.Registry()
5462
defer server.Close()
5563

5664
testClient := registry.NewClient(test.Disco(server), nil)
5765

5866
modSrc, _ := getModSrc("example.com/test-versions/name/provider")
59-
version, _ := getRegistryVersion(testClient, modSrc, ">= 2.0.0 < 2.2.0")
60-
assert.Equal(t, "2.1.1", version, "version should be >= 2.0.0 < 2.2.0")
61-
62-
_, err := getRegistryVersion(testClient, modSrc, ">= 3.0.0")
63-
assert.Error(t, err, "should have returned an error")
64-
65-
_, err = getRegistryVersion(testClient, modSrc, "not.a.version")
66-
assert.Error(t, err, "should return an error")
67-
68-
modSrc, _ = getModSrc("invalid.com/test-versions/name/provider")
69-
_, err = getRegistryVersion(testClient, modSrc, ">= 3.0.0")
70-
assert.Error(t, err, "should return an error")
67+
versions := getRegistryModuleVersions(testClient, modSrc)
68+
assert.Equal(t, []string{"2.2.0", "2.1.1", "1.2.2", "1.2.1"}, versions)
7169
}

0 commit comments

Comments
 (0)