-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Support env format * Update test * Fix lint * Update test case * Update test cases * Remove convert array to flat value * Add missing test case
- Loading branch information
1 parent
3c764b6
commit 34d8117
Showing
11 changed files
with
332 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,8 +3,6 @@ name: CI | |
on: | ||
pull_request: | ||
push: | ||
branches: | ||
- master | ||
|
||
jobs: | ||
ci: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package env | ||
|
||
import ( | ||
"fmt" | ||
"github.com/pkg/errors" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
type Env struct{} | ||
|
||
func NewEnv() *Env { | ||
return &Env{} | ||
} | ||
|
||
// ToENV convert a map (JSON structure) to string | ||
// (concatenated by \n) | ||
// This function only support convert simple format | ||
// i.e: string, number | ||
// another types will be ignored | ||
// it will be converted to empty string. | ||
// The key and value will be concatenated by equal sign. | ||
func (e *Env) ToENV(src map[string]interface{}) []byte { | ||
var lines []string | ||
|
||
for key, value := range src { | ||
var raw string | ||
|
||
switch t := value.(type) { | ||
case int: | ||
raw = addQuote(fmt.Sprintf("%v", value)) | ||
case float64: | ||
raw = addQuote(fmt.Sprintf("%v", value)) | ||
case string: | ||
raw = addQuote(fmt.Sprintf("%v", value)) | ||
case bool: | ||
raw = addQuote(fmt.Sprintf("%v", value)) | ||
default: | ||
raw = "" | ||
fmt.Println("WARN: This type", t, "will be ignored") | ||
} | ||
lines = append(lines, fmt.Sprintf("export %s=%s", key, raw)) | ||
} | ||
|
||
content := strings.Join(lines, "\n") | ||
return []byte(content) | ||
} | ||
|
||
// addQuote to input string if it contains special characters | ||
func addQuote(s string) string { | ||
var isValid = regexp.MustCompile(`^[a-zA-Z0-9.,_-]+$`).MatchString | ||
if !isValid(s) { | ||
s = strconv.Quote(s) | ||
} | ||
return s | ||
} | ||
|
||
// ToJSON convert string lines to a map (JSON structure) | ||
// Each line should be formatted like export key=value or key=value | ||
// The value can be empty. The key should contain only | ||
// alphabet, number and underscore. | ||
// Comment lines will be ignored. | ||
func (e *Env) ToJSON(src []string) (map[string]interface{}, error) { | ||
content := make(map[string]interface{}) | ||
var isValid = regexp.MustCompile(`^[a-zA-Z0-9_]+$`).MatchString | ||
for _, line := range src { | ||
line := strings.TrimSpace(line) | ||
// Skip with line start with # or empty | ||
if len(line) == 0 || strings.HasPrefix(line, "#") { | ||
continue | ||
} | ||
|
||
// Remove export | ||
line = strings.TrimSpace(strings.TrimPrefix(line, "export")) | ||
|
||
v := strings.Split(line, "=") | ||
// Validate key | ||
if !isValid(v[0]) { | ||
return nil, errors.New(fmt.Sprintf("Env: Key %s is invalid format", v[0])) | ||
} | ||
|
||
value := "" | ||
if len(v) > 1 { | ||
value = strings.Join(v[1:], "=") | ||
} | ||
|
||
content[v[0]] = trimQuotes(value) | ||
} | ||
|
||
return content, nil | ||
} | ||
|
||
// trimQuotes remove quote from string | ||
func trimQuotes(s string) string { | ||
if len(s) >= 2 { | ||
if c := s[len(s)-1]; s[0] == c && (c == '"' || c == '\'') { | ||
return s[1 : len(s)-1] | ||
} | ||
} | ||
return s | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package env | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func TestEnv_ToENV(t *testing.T) { | ||
t.Run("With success case: return byte array", func(tc *testing.T) { | ||
e := NewEnv() | ||
input := map[string]interface{}{ | ||
"TEST": "TEST", | ||
"DATA": []int{1, 2, 3}, | ||
"STR": []string{"a", "b", "c"}, | ||
"EMPTY": map[string]interface{}{"test": true}, | ||
"FLOAT": 0.23, | ||
"STR_WITH_SPACE": "string with space", | ||
"BOOL": true, | ||
} | ||
|
||
expected := map[string]bool{ | ||
"export TEST=TEST": true, | ||
"export BOOL=true": true, | ||
"export DATA=": true, | ||
"export STR=": true, | ||
"export EMPTY=": true, | ||
"export FLOAT=0.23": true, | ||
"export STR_WITH_SPACE=\"string with space\"": true, | ||
} | ||
|
||
actual := strings.Split(string(e.ToENV(input)), "\n") | ||
|
||
assert.Equal(tc, len(expected), len(actual)) | ||
for _, a := range actual { | ||
assert.Contains(tc, expected, a) | ||
} | ||
}) | ||
} | ||
|
||
func TestEnv_ToJSON(t *testing.T) { | ||
t.Run("With success case: return a map", func(tc *testing.T) { | ||
e := NewEnv() | ||
input := []string{ | ||
"export TEST=true", | ||
"export DATA=1,2,3", | ||
"#export PASS=no", | ||
"CI=true=test", | ||
"T=", | ||
"export T1='test data'", | ||
"export T2=\"test data\"", | ||
} | ||
|
||
expected := map[string]interface{}{ | ||
"TEST": "true", | ||
"DATA": "1,2,3", | ||
"CI": "true=test", | ||
"T": "", | ||
"T1": "test data", | ||
"T2": "test data", | ||
} | ||
|
||
content, err := e.ToJSON(input) | ||
assert.NoError(tc, err) | ||
assert.Equal(tc, len(expected), len(content)) | ||
|
||
for k, v := range expected { | ||
assert.Contains(tc, content, k) | ||
assert.Equal(tc, v, content[k]) | ||
} | ||
}) | ||
|
||
t.Run("With error case: return an error key invalid", func(tc *testing.T) { | ||
e := NewEnv() | ||
input := []string{ | ||
"export test = true", | ||
} | ||
_, err := e.ToJSON(input) | ||
assert.Error(tc, err) | ||
assert.Contains(tc, err.Error(), "Env: Key test is invalid format") | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package pull | ||
|
||
import ( | ||
"fmt" | ||
"github.com/pkg/errors" | ||
envlib "github.com/vietanhduong/vault-converter/pkg/env" | ||
osext "github.com/vietanhduong/vault-converter/pkg/util/os" | ||
) | ||
|
||
type env struct { | ||
envLib *envlib.Env | ||
} | ||
|
||
func NewEnv() Converter { | ||
return &env{ | ||
envLib: envlib.NewEnv(), | ||
} | ||
} | ||
|
||
// Convert a source to ENV file | ||
// src input is a map. It should be a JSON format | ||
// output should be an absolute path | ||
func (e *env) Convert(src map[string]interface{}, output string) error { | ||
|
||
content := e.envLib.ToENV(src) | ||
|
||
if err := osext.MkdirP(output); err != nil { | ||
return errors.Wrap(err, "Pull: Create folder failed") | ||
} | ||
|
||
if err := osext.Write(content, output); err != nil { | ||
return errors.Wrap(err, fmt.Sprintf("Pull: Write to %s failed", output)) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package pull | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
osext "github.com/vietanhduong/vault-converter/pkg/util/os" | ||
"os" | ||
"testing" | ||
) | ||
|
||
func TestEnv_Convert(t *testing.T) { | ||
dir := os.TempDir() | ||
defer os.Remove(dir) | ||
|
||
t.Run("With success case: return no error", func(tc *testing.T) { | ||
e := NewEnv() | ||
raw := map[string]interface{}{ | ||
"test": "this is a str", | ||
"arr": []interface{}{ | ||
map[string]interface{}{ | ||
"node": 1, | ||
"ready": true, | ||
}, | ||
map[string]interface{}{ | ||
"node": 2, | ||
"ready": false, | ||
}, | ||
}, | ||
"bool_val": false, | ||
} | ||
outputPath := dir + "/.env" | ||
defer os.Remove(outputPath) | ||
err := e.Convert(raw, outputPath) | ||
assert.NoError(tc, err) | ||
|
||
content, _ := osext.Cat(outputPath) | ||
assert.Contains(tc, string(content), `export test="this is a str"`) | ||
assert.Contains(tc, string(content), `export bool_val=false`) | ||
assert.Contains(tc, string(content), `export arr=`) | ||
}) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package push | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
envlib "github.com/vietanhduong/vault-converter/pkg/env" | ||
"strings" | ||
) | ||
|
||
type env struct { | ||
envLib *envlib.Env | ||
} | ||
|
||
func NewEnv() Converter { | ||
return &env{ | ||
envLib: envlib.NewEnv(), | ||
} | ||
} | ||
|
||
// Convert an ENV file to JSON | ||
func (e *env) Convert(src []byte) (map[string]interface{}, error){ | ||
|
||
lines := strings.Split(string(src), "\n") | ||
|
||
content, err := e.envLib.ToJSON(lines) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "Push: Convert bytes to json failed") | ||
} | ||
|
||
return content, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package push | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func TestEnv_Convert(t *testing.T) { | ||
t.Run("With success case: return a map", func(tc *testing.T) { | ||
e := NewEnv() | ||
content, err := e.Convert([]byte(`export test=true | ||
data=1,2,3 | ||
export str='this is test string' | ||
`)) | ||
assert.NoError(tc, err) | ||
expected := map[string]interface{}{ | ||
"test": "true", | ||
"data": "1,2,3", | ||
"str": "this is test string", | ||
} | ||
assert.Equal(tc, len(expected), len(content)) | ||
for k, v := range expected { | ||
assert.Contains(tc, content, k) | ||
assert.Equal(tc, v, content[k]) | ||
} | ||
}) | ||
|
||
t.Run("With error case: src invalid", func(tc *testing.T) { | ||
e := NewTfvars() | ||
_, err := e.Convert([]byte(`export name = "test"`)) | ||
assert.Error(tc, err) | ||
assert.Contains(tc, err.Error(), "Push: Parse content to JSON failed") | ||
|
||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters