Skip to content

Commit 9fa5445

Browse files
authored
Merge pull request #1279 from aFlyBird0/feat-env-var
feat: support env vars
2 parents c0b2d06 + b551edc commit 9fa5445

File tree

5 files changed

+213
-33
lines changed

5 files changed

+213
-33
lines changed

internal/pkg/configmanager/variables.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ func renderConfigWithVariables(fileContent string, variables map[string]interfac
1010

1111
str, err := template.New().
1212
FromContent(fileContent).
13-
AddProcessor(template.AddDotForVariablesInConfigProcessor()).
13+
AddDotForVariablesInConfigProcessor().
14+
AddQuoteForVariablesInConfigProcessor().
1415
SetDefaultRender(fileContent, variables).
1516
Render()
1617

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
package configmanager
22

33
import (
4+
"fmt"
5+
"os"
6+
47
. "github.com/onsi/ginkgo/v2"
58
. "github.com/onsi/gomega"
69
)
710

811
var _ = Describe("renderConfigWithVariables", func() {
9-
var vars = map[string]interface{}{
10-
"foo1": "bar1",
11-
"foo2": "bar2",
12-
}
1312
When("render a config with variables", func() {
1413
It("should works fine", func() {
14+
var vars = map[string]interface{}{
15+
"foo1": "bar1",
16+
"foo2": "bar2",
17+
}
1518
result1, err1 := renderConfigWithVariables("[[ foo1 ]]/[[ foo2]]", vars)
1619
result2, err2 := renderConfigWithVariables("a[[ foo1 ]]/[[ foo2]]b", vars)
1720
result3, err3 := renderConfigWithVariables(" [[ foo1 ]] [[ foo2]] ", vars)
@@ -23,4 +26,34 @@ var _ = Describe("renderConfigWithVariables", func() {
2326
Expect(result3).To(Equal([]byte(" bar1 bar2 ")))
2427
})
2528
})
29+
30+
When("there are env variables", func() {
31+
const (
32+
envKey1, envKey2 = "GITHUB_TOKEN", "GITLAB_TOKEN"
33+
envVal1, envVal2 = "123456", "abcdef"
34+
)
35+
BeforeEach(func() {
36+
DeferCleanup(os.Setenv, envKey1, os.Getenv(envKey1))
37+
DeferCleanup(os.Setenv, envKey2, os.Getenv(envKey2))
38+
})
39+
40+
It("should works fine", func() {
41+
err := os.Setenv(envKey1, envVal1)
42+
Expect(err).NotTo(HaveOccurred())
43+
err = os.Setenv(envKey2, envVal2)
44+
Expect(err).NotTo(HaveOccurred())
45+
46+
content := fmt.Sprintf(`
47+
githubToken: [[env %s]]
48+
gitlabToken: [[ env "%s"]]
49+
`, envKey1, envKey2)
50+
expected := fmt.Sprintf(`
51+
githubToken: %s
52+
gitlabToken: %s
53+
`, envVal1, envVal2)
54+
result, err := renderConfigWithVariables(content, nil)
55+
Expect(err).NotTo(HaveOccurred())
56+
Expect(result).To(Equal([]byte(expected)))
57+
})
58+
})
2659
})

pkg/util/template/processor.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@ import "regexp"
55
// this is because our variables' syntax is [[ varName ]]
66
// while Go's template is [[ .varName ]]
77
func addDotForVariablesInConfig(s string) string {
8-
// regex := `\[\[\s*(.*)\s*\]\]`
9-
// r := regexp.MustCompile(regex)
10-
// return r.ReplaceAllString(s, "[[ .$1 ]]")
11-
regex := `\[\[\s*`
8+
// add dot if there is only one word in [[ ]]
9+
regex := `\[\[\s*(\w+)\s*\]\]`
1210
r := regexp.MustCompile(regex)
13-
return r.ReplaceAllString(s, "[[ .")
11+
return r.ReplaceAllString(s, "[[ .$1 ]]")
1412
}
1513

1614
func AddDotForVariablesInConfigProcessor() Processor {
@@ -19,6 +17,28 @@ func AddDotForVariablesInConfigProcessor() Processor {
1917
}
2018
}
2119

20+
// When [[ ]] has two words and the first word don't contain quota, add quotes to the second word
21+
// e.g. [[ env GITHUB_TOKEN]] -> [[ env "GITHUB_TOKEN" ]]
22+
// [[ env 'GITHUB_TOKEN' ]] -> do nothing
23+
// [[ env "GITHUB_TOKEN" ]] -> do nothing
24+
// [[ "env" "GITHUB_TOKEN" ]] -> do nothing
25+
// [[ GITHUB_TOKEN ]] -> do nothing
26+
func addQuoteForVariablesInConfig(s string) string {
27+
regex := `\[\[\s*([^'"]\w+)\s+([^'"]\w+)\s*\]\]`
28+
r := regexp.MustCompile(regex)
29+
return r.ReplaceAllString(s, "[[ $1 \"$2\" ]]")
30+
}
31+
32+
func AddQuoteForVariablesInConfigProcessor() Processor {
33+
return func(bytes []byte) ([]byte, error) {
34+
return []byte(addQuoteForVariablesInConfig(string(bytes))), nil
35+
}
36+
}
37+
2238
func (r *rendererWithGetter) AddDotForVariablesInConfigProcessor() *rendererWithGetter {
2339
return r.AddProcessor(AddDotForVariablesInConfigProcessor())
2440
}
41+
42+
func (r *rendererWithGetter) AddQuoteForVariablesInConfigProcessor() *rendererWithGetter {
43+
return r.AddProcessor(AddQuoteForVariablesInConfigProcessor())
44+
}
Lines changed: 144 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,149 @@
11
package template
22

33
import (
4-
"testing"
5-
6-
"github.com/stretchr/testify/assert"
4+
. "github.com/onsi/ginkgo/v2"
5+
. "github.com/onsi/gomega"
76
)
87

9-
func TestAddDotForVariablesInConfigNormal(t *testing.T) {
10-
res := addDotForVariablesInConfig("[[varNameA]]")
11-
assert.Equal(t, "[[ .varNameA]]", res, "Adding dot for variable names passed.")
12-
}
13-
14-
func TestAddDotForVariablesInConfigWithSpaces(t *testing.T) {
15-
res := addDotForVariablesInConfig("[[ varNameA]]")
16-
assert.Equal(t, "[[ .varNameA]]", res, "Adding dot for variable names passed.")
17-
}
18-
19-
func TestAddDotForVariablesInConfigWithTrailingSpaces(t *testing.T) {
20-
res := addDotForVariablesInConfig("[[ varNameA ]]")
21-
assert.Equal(t, "[[ .varNameA ]]", res, "Adding dot for variable names passed.")
22-
}
23-
24-
func TestAddDotForVariablesInConfigMultipleVars(t *testing.T) {
25-
res := addDotForVariablesInConfig("[[ varNameA ]]/[[ varNameB ]]/[[ varNameC ]]")
26-
assert.Equal(t, "[[ .varNameA ]]/[[ .varNameB ]]/[[ .varNameC ]]", res, "Adding dot for variable names passed.")
27-
}
8+
var _ = Describe("addDotForVariablesInConfig", func() {
9+
var (
10+
origin, gotten, expected string
11+
)
12+
13+
JustBeforeEach(func() {
14+
gotten = addDotForVariablesInConfig(origin)
15+
})
16+
17+
When("config is normal", func() {
18+
BeforeEach(func() {
19+
origin = "[[varNameA]]"
20+
expected = "[[ .varNameA ]]"
21+
})
22+
It("should succeed", func() {
23+
Expect(gotten).To(Equal(expected))
24+
})
25+
})
26+
27+
When("config has spaces", func() {
28+
BeforeEach(func() {
29+
origin = "[[ varNameA ]]"
30+
expected = "[[ .varNameA ]]"
31+
})
32+
33+
It("should succeed", func() {
34+
Expect(gotten).To(Equal(expected))
35+
})
36+
})
37+
38+
When("config has trailing spaces", func() {
39+
BeforeEach(func() {
40+
origin = "[[ varNameA ]]"
41+
expected = "[[ .varNameA ]]"
42+
})
43+
44+
It("should succeed", func() {
45+
Expect(gotten).To(Equal(expected))
46+
})
47+
})
48+
49+
When("config has multiple variables", func() {
50+
BeforeEach(func() {
51+
origin = "[[ varNameA ]]/[[ varNameB ]]/[[ varNameC ]]"
52+
expected = "[[ .varNameA ]]/[[ .varNameB ]]/[[ .varNameC ]]"
53+
})
54+
55+
It("should succeed", func() {
56+
Expect(gotten).To(Equal(expected))
57+
})
58+
})
59+
60+
When("there are more than one words", func() {
61+
BeforeEach(func() {
62+
origin = "[[ func varNameA ]]"
63+
expected = origin
64+
})
65+
66+
It("should do nothing", func() {
67+
Expect(gotten).To(Equal(expected))
68+
})
69+
})
70+
})
71+
72+
var _ = Describe("addQuoteForVariablesInConfig", func() {
73+
var (
74+
origin, gotten, expected string
75+
)
76+
77+
JustBeforeEach(func() {
78+
gotten = addQuoteForVariablesInConfig(origin)
79+
})
80+
AfterEach(func() {
81+
Expect(gotten).To(Equal(expected))
82+
})
83+
84+
When("config is normal", func() {
85+
BeforeEach(func() {
86+
origin = `[[env GITHUB_TOKEN]]`
87+
expected = `[[ env "GITHUB_TOKEN" ]]`
88+
})
89+
90+
It("should succeed", func() {
91+
Expect(gotten).To(Equal(expected))
92+
})
93+
})
94+
95+
When("config has single quote", func() {
96+
BeforeEach(func() {
97+
origin = `[[ env 'GITHUB_TOKEN']]`
98+
expected = origin
99+
})
100+
101+
It("should do nothing", func() {
102+
Expect(gotten).To(Equal(expected))
103+
})
104+
})
105+
106+
When("config has quote", func() {
107+
BeforeEach(func() {
108+
origin = `[[ env "GITHUB_TOKEN"]]`
109+
expected = origin
110+
})
111+
112+
It("should do nothing", func() {
113+
Expect(gotten).To(Equal(expected))
114+
})
115+
})
116+
117+
When("config has multiple variables", func() {
118+
BeforeEach(func() {
119+
origin = `[[ env GITHUB_TOKEN]]/[[ env "GITLAB_TOKEN"]]`
120+
expected = `[[ env "GITHUB_TOKEN" ]]/[[ env "GITLAB_TOKEN"]]`
121+
})
122+
123+
It("should succeed", func() {
124+
Expect(gotten).To(Equal(expected))
125+
})
126+
})
127+
128+
When("the first word has quote", func() {
129+
BeforeEach(func() {
130+
origin = `[[ "env" GITHUB_TOKEN]]`
131+
expected = origin
132+
})
133+
134+
It("should do nothing", func() {
135+
Expect(gotten).To(Equal(expected))
136+
})
137+
})
138+
139+
When("there is only one word", func() {
140+
BeforeEach(func() {
141+
origin = `[[GITHUB_TOKEN]]`
142+
expected = origin
143+
})
144+
145+
It("should do nothing", func() {
146+
Expect(gotten).To(Equal(expected))
147+
})
148+
})
149+
})

pkg/util/template/render.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,23 @@ import (
55
"os"
66
"text/template"
77

8+
"github.com/Masterminds/sprig/v3"
9+
810
"github.com/devstream-io/devstream/pkg/util/log"
911
)
1012

1113
func Render(name, templateStr string, variable any, funcMaps ...template.FuncMap) (string, error) {
1214
t := template.New(name).Option("missingkey=error").Delims("[[", "]]")
1315

16+
// use sprig functions such as "env"
17+
t.Funcs(sprig.TxtFuncMap())
1418
for _, funcMap := range funcMaps {
1519
t.Funcs(funcMap)
1620
}
1721

1822
t, err := t.Parse(templateStr)
1923
if err != nil {
20-
log.Warnf("Template parse file failed: %s.", err)
24+
log.Warnf("Template parse file failed, template: %s, err: %s.", templateStr, err)
2125
return "", err
2226
}
2327

0 commit comments

Comments
 (0)