Skip to content

Commit 0726bfc

Browse files
committed
Add support for multiple <<includes(file)>> and embedded <<includes(file)>>
1 parent e81d968 commit 0726bfc

File tree

2 files changed

+91
-14
lines changed

2 files changed

+91
-14
lines changed

process/process.go

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,20 @@ func MaybeIncludeFile(s string, orbDirectory string) (string, error) {
1515
// View: https://regexr.com/599mq
1616
includeRegex := regexp.MustCompile(`<<[\s]*include\(([-\w\/\.]+)\)?[\s]*>>`)
1717

18-
// only find up to 2 matches, because we throw an error if we find >1
19-
includeMatches := includeRegex.FindAllStringSubmatch(s, 2)
20-
if len(includeMatches) > 1 {
21-
return "", fmt.Errorf("multiple include statements: '%s'", s)
22-
}
18+
includeMatches := includeRegex.FindAllStringSubmatch(s, -1)
2319

24-
if len(includeMatches) == 1 {
25-
match := includeMatches[0]
20+
for _, match := range includeMatches {
2621
fullMatch, subMatch := match[0], match[1]
2722

28-
// throw an error if the entire string wasn't matched
29-
if fullMatch != s {
30-
return "", fmt.Errorf("entire string must be include statement: '%s'", s)
31-
}
32-
3323
filepath := filepath.Join(orbDirectory, subMatch)
3424
file, err := ioutil.ReadFile(filepath)
25+
3526
if err != nil {
3627
return "", fmt.Errorf("could not open %s for inclusion", filepath)
3728
}
38-
escaped := strings.ReplaceAll(string(file), "<<", "\\<<")
3929

40-
return escaped, nil
30+
escaped := strings.ReplaceAll(string(file), "<<", "\\<<")
31+
s = strings.ReplaceAll(s, fullMatch, escaped)
4132
}
4233

4334
return s, nil

process/process_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package process
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"testing"
7+
)
8+
9+
func Test_MaybeIncludeFile(t *testing.T) {
10+
testCases := []struct {
11+
description string
12+
template string
13+
expected string
14+
files map[string]string
15+
errExpected bool
16+
}{
17+
{
18+
description: "File gets replaced",
19+
template: "<<include(example.txt)>>",
20+
expected: "world",
21+
files: map[string]string{
22+
"example.txt": "world",
23+
},
24+
errExpected: false,
25+
},
26+
{
27+
description: "Partial line include",
28+
template: "hello <<include(example-2.txt)>>",
29+
expected: "hello world",
30+
files: map[string]string{
31+
"example-2.txt": "world",
32+
},
33+
errExpected: false,
34+
},
35+
{
36+
description: "Multiple includes",
37+
template: "<<include(example-1.txt)>> <<include(example-2.txt)>>",
38+
expected: "hello world",
39+
files: map[string]string{
40+
"example-1.txt": "hello",
41+
"example-2.txt": "world",
42+
},
43+
errExpected: false,
44+
},
45+
{
46+
description: "File does not exist",
47+
template: "<<include(file-that-does-not-exist.txt)>>",
48+
files: map[string]string{},
49+
errExpected: true,
50+
},
51+
{
52+
description: "Included files are escaped",
53+
template: "<<include(example-1.txt)>> world",
54+
expected: "\\<< hello world",
55+
files: map[string]string{
56+
"example-1.txt": "<< hello",
57+
},
58+
errExpected: false,
59+
},
60+
}
61+
62+
for _, tc := range testCases {
63+
t.Run(tc.description, func(t *testing.T) {
64+
dir, err := ioutil.TempDir("", "circleci-cli-test")
65+
if err != nil {
66+
t.Fatal(err)
67+
}
68+
defer os.RemoveAll(dir)
69+
for name, content := range tc.files {
70+
if err := ioutil.WriteFile(dir+"/"+name, []byte(content), 0644); err != nil {
71+
t.Fatal(err)
72+
}
73+
}
74+
75+
orbDirectory := dir
76+
res, err := MaybeIncludeFile(tc.template, orbDirectory)
77+
if err != nil && !tc.errExpected {
78+
t.Errorf("Unexpected error: %v", err)
79+
}
80+
81+
if !tc.errExpected && res != tc.expected {
82+
t.Errorf("expected '%s', got '%s'", tc.expected, res)
83+
}
84+
})
85+
}
86+
}

0 commit comments

Comments
 (0)