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

Commit 7b90513

Browse files
authored
feat(versions): Add conditional versioning to Git tags
I added the ability to use conditional versions for Terraform registry models in v2.0.0 of xterrafile. I wanted to see if the same functionality would be possible for git tags. As long as they follow a semver (examples: 1.0.0 or v1.2.0) pattern this is now possible. It's functional and performant but... I'm not 100% happy with some of the code and will come back to improve on it as my experiences and understandings grow.
1 parent 3afb30f commit 7b90513

File tree

5 files changed

+124
-3
lines changed

5 files changed

+124
-3
lines changed

Terrafile.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ terrafile-test-https:
77
source: "github.com/terraform-digitalocean-modules/terraform-digitalocean-droplet.git"
88
terrafile-test-tag:
99
source: "git@github.com:terraform-digitalocean-modules/terraform-digitalocean-droplet.git"
10-
version: "v0.1.7"
10+
version: "> 0.0.2 < 0.1.1"
1111
terrafile-test-branch:
1212
source: "git@github.com:terraform-digitalocean-modules/terraform-digitalocean-droplet.git?ref=branch_test"
1313
terrafile-test-commit:

cmd/install.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ func getModule(moduleName string, moduleMeta module, wg *sync.WaitGroup) {
8181
case xt.IsRegistrySourceAddr(moduleSource):
8282
source, version := xt.GetRegistrySource(moduleName, moduleSource, moduleVersion, nil)
8383
xt.GetWithGoGetter(moduleName, source, version, directory)
84+
case xt.IsGitSourceAddr(moduleSource):
85+
source, version := xt.GetGitSource(moduleName, moduleSource, moduleVersion)
86+
xt.GetWithGoGetter(moduleName, source, version, directory)
8487
default:
8588
xt.GetWithGoGetter(moduleName, moduleSource, moduleVersion, directory)
8689
}

pkg/git.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright © 2019 Tim Birkett <tim.birkett@devopsmakers.com>
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+
"bufio"
25+
"bytes"
26+
"os/exec"
27+
"regexp"
28+
"strings"
29+
30+
jww "github.com/spf13/jwalterweatherman"
31+
)
32+
33+
var gitSourcePrefixes = []string{
34+
"git::",
35+
"git@",
36+
}
37+
38+
// IsGitSourceAddr returns true if the address is a git source
39+
func IsGitSourceAddr(addr string) bool {
40+
jww.DEBUG.Printf("Testing if %s is a local source", addr)
41+
for _, prefix := range gitSourcePrefixes {
42+
if strings.HasPrefix(addr, prefix) || strings.HasSuffix(addr, ".git") {
43+
return true
44+
}
45+
}
46+
return false
47+
}
48+
49+
// GetGitSource returns the source uri and version of a module from git
50+
func GetGitSource(name string, source string, version string) (string, string) {
51+
var gitVersion string
52+
53+
switch {
54+
case isConditionalVersion(version):
55+
var err error
56+
tagVersions := getGitTags(name, source)
57+
gitVersion, err = getModuleVersion(tagVersions, version)
58+
CheckIfError(name, err)
59+
default:
60+
gitVersion = version
61+
}
62+
return source, gitVersion
63+
}
64+
65+
func getGitTags(name string, source string) []string {
66+
var stdoutbuf bytes.Buffer
67+
cmd := exec.Command("git", "ls-remote", "--tags", source)
68+
cmd.Stdout = &stdoutbuf
69+
err := cmd.Run()
70+
CheckIfError(name, err)
71+
72+
var tagRegexp = regexp.MustCompile(`refs/tags/(.*)`)
73+
tags := []string{}
74+
75+
tagScanner := bufio.NewScanner(&stdoutbuf)
76+
for tagScanner.Scan() {
77+
tag := tagRegexp.FindStringSubmatch(tagScanner.Text())
78+
if tag != nil {
79+
tags = append(tags, tag[1])
80+
}
81+
}
82+
return tags
83+
}

pkg/git_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package xterrafile
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestIsGitSourceAddr(t *testing.T) {
10+
assert.True(t, IsGitSourceAddr("git@github.com:terraform-digitalocean-modules/terraform-digitalocean-droplet.git"))
11+
assert.True(t, IsGitSourceAddr("git::https://github.com/terraform-digitalocean-modules/terraform-digitalocean-droplet.git"))
12+
assert.True(t, IsGitSourceAddr("https://github.com/terraform-digitalocean-modules/terraform-digitalocean-droplet.git"))
13+
assert.False(t, IsGitSourceAddr("/some/absolute/path"), "absolute path should be false")
14+
assert.False(t, IsGitSourceAddr("https://something"), "http source should be false")
15+
}
16+
17+
func TestGetGitTags(t *testing.T) {
18+
assert.Contains(t, getGitTags("droplet", "git@github.com:terraform-digitalocean-modules/terraform-digitalocean-droplet.git"), "v0.1.7")
19+
assert.Contains(t, getGitTags("droplet", "git@github.com:terraform-digitalocean-modules/terraform-digitalocean-droplet.git"), "v0.0.2")
20+
}
21+
22+
func TestGetGitSource(t *testing.T) {
23+
module1Src, module1Version := GetGitSource("droplet", "git@github.com:terraform-digitalocean-modules/terraform-digitalocean-droplet.git", "> 0.1.2 <= 0.1.7")
24+
assert.Equal(t, "git@github.com:terraform-digitalocean-modules/terraform-digitalocean-droplet.git", module1Src)
25+
assert.Equal(t, "v0.1.7", module1Version)
26+
27+
module2Src, module2Version := GetGitSource("droplet", "git@github.com:terraform-digitalocean-modules/terraform-digitalocean-droplet.git", "39bda6c7aabac9226ec6628339463aa1708bef85")
28+
assert.Equal(t, "git@github.com:terraform-digitalocean-modules/terraform-digitalocean-droplet.git", module2Src)
29+
assert.Equal(t, "39bda6c7aabac9226ec6628339463aa1708bef85", module2Version)
30+
}

pkg/module_version.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package xterrafile
2222

2323
import (
2424
"errors"
25+
"sort"
2526

2627
"github.com/blang/semver"
2728
)
@@ -44,20 +45,23 @@ func isConditionalVersion(versionConditional string) bool {
4445

4546
func getModuleVersion(sourceVersions []string, versionConditional string) (string, error) {
4647
var validSourceVersions []semver.Version
48+
var originalVersions []string
4749

4850
for _, sourceVersion := range sourceVersions {
4951
v, err := semver.ParseTolerant(sourceVersion)
5052
if err != nil {
5153
continue
5254
}
5355
validSourceVersions = append(validSourceVersions, v)
56+
originalVersions = append(originalVersions, sourceVersion)
5457
}
5558

5659
semver.Sort(validSourceVersions)
60+
sort.Strings(originalVersions)
5761

5862
// Assume latest if we get passed an empty string
5963
if versionConditional == "" {
60-
return validSourceVersions[len(validSourceVersions)-1].String(), nil
64+
return originalVersions[len(originalVersions)-1], nil
6165
}
6266

6367
validModuleVersionRange, err := semver.ParseRange(versionConditional)
@@ -67,8 +71,9 @@ func getModuleVersion(sourceVersions []string, versionConditional string) (strin
6771

6872
for i := range validSourceVersions {
6973
v := validSourceVersions[len(validSourceVersions)-1-i]
74+
o := originalVersions[len(originalVersions)-1-i]
7075
if validModuleVersionRange(v) {
71-
return v.String(), nil
76+
return o, nil
7277
}
7378
}
7479

0 commit comments

Comments
 (0)