Skip to content

Commit

Permalink
Add support for multiple <<includes(file)>> and embedded <<includes(f…
Browse files Browse the repository at this point in the history
…ile)>>
  • Loading branch information
Mongey committed Jun 15, 2022
1 parent dd4bed1 commit da0e4ed
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 23 deletions.
27 changes: 18 additions & 9 deletions integration_tests/features/orb_pack.feature
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,27 @@ Feature: Orb pack
And the exit status should be 0

@mocked_home_directory
Scenario: Orb pack with multiple includes fails
Scenario: Orb pack with multiple includes
Given a file named "src/@orb.yml" with:
"""
commands:
test:
steps:
- run:
command: <<include(script.sh)>> <<include(script.sh)>>
command: <<include(script.sh)>> <<include(script2.sh)>>
"""
Given a file named "src/script.sh" with "echo Hello, world!"
Given a file named "src/script.sh" with "echo Hello,"
Given a file named "src/script2.sh" with "world!"
When I run `circleci orb pack src`
Then the output should contain:
"""
Error: An unexpected error occurred: multiple include statements: '<<include(script.sh)>> <<include(script.sh)>>'
commands:
test:
steps:
- run:
command: echo Hello, world!
"""
And the exit status should be 255
And the exit status should be 0

@mocked_home_directory
Scenario: Orb pack with include statement in bigger string
Expand All @@ -47,15 +52,19 @@ Feature: Orb pack
test:
steps:
- run:
command: include <<include(script.sh)>>
command: echo "<<include(script.sh)>>"
"""
Given a file named "src/script.sh" with "echo Hello, world!"
Given a file named "src/script.sh" with "Hello, world!"
When I run `circleci orb pack src`
Then the output should contain:
"""
Error: An unexpected error occurred: entire string must be include statement: 'include <<include(script.sh)>>'
commands:
test:
steps:
- run:
command: echo "Hello, world!"
"""
And the exit status should be 255
And the exit status should be 0

@mocked_home_directory
Scenario: Missing @orb.yml for orb packing
Expand Down
19 changes: 5 additions & 14 deletions process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,20 @@ func MaybeIncludeFile(s string, orbDirectory string) (string, error) {
// View: https://regexr.com/599mq
includeRegex := regexp.MustCompile(`<<[\s]*include\(([-\w\/\.]+)\)?[\s]*>>`)

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

if len(includeMatches) == 1 {
match := includeMatches[0]
for _, match := range includeMatches {
fullMatch, subMatch := match[0], match[1]

// throw an error if the entire string wasn't matched
if fullMatch != s {
return "", fmt.Errorf("entire string must be include statement: '%s'", s)
}

filepath := filepath.Join(orbDirectory, subMatch)
file, err := ioutil.ReadFile(filepath)

if err != nil {
return "", fmt.Errorf("could not open %s for inclusion", filepath)
}
escaped := strings.ReplaceAll(string(file), "<<", "\\<<")

return escaped, nil
escaped := strings.ReplaceAll(string(file), "<<", "\\<<")
s = strings.ReplaceAll(s, fullMatch, escaped)
}

return s, nil
Expand Down
86 changes: 86 additions & 0 deletions process/process_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package process

import (
"io/ioutil"
"os"
"testing"
)

func Test_MaybeIncludeFile(t *testing.T) {
testCases := []struct {
description string
template string
expected string
files map[string]string
errExpected bool
}{
{
description: "File gets replaced",
template: "<<include(example.txt)>>",
expected: "world",
files: map[string]string{
"example.txt": "world",
},
errExpected: false,
},
{
description: "Partial line include",
template: "hello <<include(example-2.txt)>>",
expected: "hello world",
files: map[string]string{
"example-2.txt": "world",
},
errExpected: false,
},
{
description: "Multiple includes",
template: "<<include(example-1.txt)>> <<include(example-2.txt)>>",
expected: "hello world",
files: map[string]string{
"example-1.txt": "hello",
"example-2.txt": "world",
},
errExpected: false,
},
{
description: "File does not exist",
template: "<<include(file-that-does-not-exist.txt)>>",
files: map[string]string{},
errExpected: true,
},
{
description: "Included files are escaped",
template: "<<include(example-1.txt)>> world",
expected: "\\<< hello world",
files: map[string]string{
"example-1.txt": "<< hello",
},
errExpected: false,
},
}

for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
dir, err := ioutil.TempDir("", "circleci-cli-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
for name, content := range tc.files {
if err := ioutil.WriteFile(dir+"/"+name, []byte(content), 0644); err != nil {
t.Fatal(err)
}
}

orbDirectory := dir
res, err := MaybeIncludeFile(tc.template, orbDirectory)
if err != nil && !tc.errExpected {
t.Errorf("Unexpected error: %v", err)
}

if !tc.errExpected && res != tc.expected {
t.Errorf("expected '%s', got '%s'", tc.expected, res)
}
})
}
}

0 comments on commit da0e4ed

Please sign in to comment.