-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Supports setting local environment vars (#167)
* Supports setting local environment vars Uses `.env` from current work dir to override or set new environment variables * Refactor environment functions Addresses code review suggestions and requests: * Using t.TempDir * Using cmp.Diff * Sorting slices on unit test * Returning errors on parsing environment variables Also: * Unexports some symbols that was only used by ./workspace * Remove illed-thought word from comment Thanks @zombiezen Co-authored-by: Ross Light <[email protected]> Co-authored-by: Ross Light <[email protected]>
- Loading branch information
Showing
8 changed files
with
223 additions
and
85 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
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
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,83 @@ | ||
package workspace | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"errors" | ||
"fmt" | ||
"os" | ||
"strings" | ||
"text/template" | ||
|
||
"github.com/joho/godotenv" | ||
"github.com/yourbase/yb/plumbing/log" | ||
"github.com/yourbase/yb/runtime" | ||
) | ||
|
||
// checkAndSplitEnvVar returns two empty strings and false | ||
// if env isn't formed as "something=.*" | ||
func checkAndSplitEnvVar(env string) (name, value string, sane bool) { | ||
s := strings.SplitN(env, "=", 2) | ||
if sane = (len(s) == 2); sane { | ||
name = s[0] | ||
value = s[1] | ||
} | ||
return | ||
} | ||
|
||
// parseEnvironment checks and process an arbitrary number of | ||
// environment vars lists, trying to not duplicate anything | ||
func parseEnvironment(ctx context.Context, envPath string, runtimeData runtime.RuntimeEnvironmentData, envPacks ...[]string) ([]string, error) { | ||
envMap := make(map[string]string) | ||
for _, envPack := range envPacks { | ||
for _, prop := range envPack { | ||
interpolated, err := templateToString(prop, runtimeData) | ||
if err == nil { | ||
prop = interpolated | ||
} else { | ||
return nil, err | ||
} | ||
if key, value, ok := checkAndSplitEnvVar(prop); ok { | ||
envMap[key] = value | ||
} else { | ||
return nil, errors.New("invalid enviroment var spec: " + prop) | ||
} | ||
} | ||
} | ||
|
||
// Check and load .env file | ||
localEnv, err := godotenv.Read(envPath) | ||
if err == nil { | ||
for k, v := range localEnv { | ||
envMap[k] = v | ||
} | ||
} else { | ||
log.Debugf("Dotenv load error: %v", err) | ||
if !os.IsNotExist(err) { | ||
return nil, fmt.Errorf("processing local .env: %w", err) | ||
} | ||
} | ||
|
||
result := make([]string, 0) | ||
for k, v := range envMap { | ||
result = append(result, k+"="+v) | ||
} | ||
return result, nil | ||
} | ||
|
||
// templateToString process data and apply passed in templateText | ||
// returning an interpolated string | ||
func templateToString(templateText string, data interface{}) (string, error) { | ||
t, err := template.New("generic").Parse(templateText) | ||
if err != nil { | ||
return "", err | ||
} | ||
var tpl bytes.Buffer | ||
if err := t.Execute(&tpl, data); err != nil { | ||
log.Errorf("Can't render template:: %v", err) | ||
return "", err | ||
} | ||
|
||
result := tpl.String() | ||
return result, 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,100 @@ | ||
package workspace | ||
|
||
import ( | ||
"context" | ||
"io/ioutil" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"github.com/google/go-cmp/cmp/cmpopts" | ||
"github.com/yourbase/yb/runtime" | ||
) | ||
|
||
func Test_parseEnvironment(t *testing.T) { | ||
type args struct { | ||
envPath string | ||
runtimeData runtime.RuntimeEnvironmentData | ||
envPacks [][]string | ||
} | ||
dummyRuntimeData := runtime.RuntimeEnvironmentData{Containers: runtime.ContainerData{}} | ||
egContents := []byte(`YB_PRECIOUS_SEKRET_KEY=something | ||
THERE=no | ||
YB_GITHUB_APP_ID=0000`) | ||
tempDir := t.TempDir() | ||
dotEnvFilePath := filepath.Join(tempDir, ".env") | ||
if err := ioutil.WriteFile(dotEnvFilePath, egContents, 0644); err != nil { | ||
t.Fatalf("Unable to write env file %s: %v", dotEnvFilePath, err) | ||
} | ||
t.Logf("Created %s for testing .env", dotEnvFilePath) | ||
|
||
tests := []struct { | ||
name string | ||
args args | ||
want []string | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "No dotenv", | ||
args: args{ | ||
envPath: ".env", | ||
runtimeData: dummyRuntimeData, | ||
envPacks: [][]string{ | ||
{ | ||
"DATABASE_URL=test-ME", | ||
"YB_GITHUB_APP_ID=38644", | ||
"YB_APP_URL=http://localhost:3000", | ||
}, | ||
{ | ||
"AWS_SOMETHING_SOME=agoegoejo+Ej185", | ||
}, | ||
}, | ||
}, | ||
want: []string{ | ||
"AWS_SOMETHING_SOME=agoegoejo+Ej185", | ||
"DATABASE_URL=test-ME", | ||
"YB_APP_URL=http://localhost:3000", | ||
"YB_GITHUB_APP_ID=38644", | ||
}, | ||
}, | ||
{ | ||
name: "With a dotenv", | ||
args: args{ | ||
envPath: dotEnvFilePath, | ||
runtimeData: dummyRuntimeData, | ||
envPacks: [][]string{ | ||
{ | ||
"DATABASE_URL=test-ME", | ||
"YB_GITHUB_APP_ID=38644", | ||
"YB_APP_URL=http://localhost:3000", | ||
}, | ||
{ | ||
"AWS_SOMETHING_SOME=agoegoejo+Ej185", | ||
}, | ||
}, | ||
}, | ||
want: []string{ | ||
"AWS_SOMETHING_SOME=agoegoejo+Ej185", | ||
"DATABASE_URL=test-ME", | ||
"THERE=no", | ||
"YB_APP_URL=http://localhost:3000", | ||
"YB_GITHUB_APP_ID=0000", | ||
"YB_PRECIOUS_SEKRET_KEY=something", | ||
}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := parseEnvironment(context.Background(), tt.args.envPath, tt.args.runtimeData, tt.args.envPacks...) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("parseEnvironment() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if diff := cmp.Diff(got, tt.want, cmpopts.SortSlices(func(i, j string) bool { | ||
return i < j | ||
})); diff != "" { | ||
t.Errorf("parseEnvironment(), diff: %v", diff) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.