feat: load every environment from --env-file to workflow (#184)
* feat: load every environment from --env-file to workflow * fix: pass dotenv's environments through by context * updates to support --secret-file Co-authored-by: Casey Lee <cplee@nektos.com>
This commit is contained in:
parent
f6e37a8d67
commit
2f395475b0
|
@ -15,3 +15,4 @@ dist/
|
||||||
.todo
|
.todo
|
||||||
|
|
||||||
*.nupkg
|
*.nupkg
|
||||||
|
.vscode/
|
||||||
|
|
|
@ -18,6 +18,7 @@ type Input struct {
|
||||||
forcePull bool
|
forcePull bool
|
||||||
noOutput bool
|
noOutput bool
|
||||||
envfile string
|
envfile string
|
||||||
|
secretfile string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Input) resolve(path string) string {
|
func (i *Input) resolve(path string) string {
|
||||||
|
@ -39,6 +40,11 @@ func (i *Input) Envfile() string {
|
||||||
return i.resolve(i.envfile)
|
return i.resolve(i.envfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Secretfile returns path to secrets
|
||||||
|
func (i *Input) Secretfile() string {
|
||||||
|
return i.resolve(i.secretfile)
|
||||||
|
}
|
||||||
|
|
||||||
// Workdir returns path to workdir
|
// Workdir returns path to workdir
|
||||||
func (i *Input) Workdir() string {
|
func (i *Input) Workdir() string {
|
||||||
return i.resolve(".")
|
return i.resolve(".")
|
||||||
|
|
35
cmd/root.go
35
cmd/root.go
|
@ -46,7 +46,8 @@ func Execute(ctx context.Context, version string) {
|
||||||
rootCmd.PersistentFlags().BoolP("verbose", "v", false, "verbose output")
|
rootCmd.PersistentFlags().BoolP("verbose", "v", false, "verbose output")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&input.noOutput, "quiet", "q", false, "disable logging of output from steps")
|
rootCmd.PersistentFlags().BoolVarP(&input.noOutput, "quiet", "q", false, "disable logging of output from steps")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&input.dryrun, "dryrun", "n", false, "dryrun mode")
|
rootCmd.PersistentFlags().BoolVarP(&input.dryrun, "dryrun", "n", false, "dryrun mode")
|
||||||
rootCmd.PersistentFlags().StringVarP(&input.envfile, "env-file", "", ".env", "environment file to read")
|
rootCmd.PersistentFlags().StringVarP(&input.secretfile, "secret-file", "", "", "file with list of secrets to read from")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&input.envfile, "env-file", "", ".env", "environment file to read and use as env in the containers")
|
||||||
rootCmd.SetArgs(args())
|
rootCmd.SetArgs(args())
|
||||||
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
@ -92,16 +93,29 @@ func setupLogging(cmd *cobra.Command, args []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readEnvs(path string, envs map[string]string) bool {
|
||||||
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
env, err := godotenv.Read(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error loading from %s: %v", path, err)
|
||||||
|
}
|
||||||
|
for k, v := range env {
|
||||||
|
envs[k] = v
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []string) error {
|
func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []string) error {
|
||||||
return func(cmd *cobra.Command, args []string) error {
|
return func(cmd *cobra.Command, args []string) error {
|
||||||
envfile := input.Envfile()
|
log.Debugf("Loading environment from %s", input.Envfile())
|
||||||
if _, err := os.Stat(envfile); err == nil {
|
envs := make(map[string]string)
|
||||||
log.Debugf("Loading environment from %s", envfile)
|
_ = readEnvs(input.Envfile(), envs)
|
||||||
err := godotenv.Load(envfile)
|
|
||||||
if err != nil {
|
log.Debugf("Loading secrets from %s", input.Secretfile())
|
||||||
log.Fatalf("Error loading environment from %s: %v", envfile, err)
|
secrets := newSecrets(input.secrets)
|
||||||
}
|
_ = readEnvs(input.Secretfile(), secrets)
|
||||||
}
|
|
||||||
|
|
||||||
planner, err := model.NewWorkflowPlanner(input.WorkflowsPath())
|
planner, err := model.NewWorkflowPlanner(input.WorkflowsPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -149,7 +163,8 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
|
||||||
Workdir: input.Workdir(),
|
Workdir: input.Workdir(),
|
||||||
BindWorkdir: input.bindWorkdir,
|
BindWorkdir: input.bindWorkdir,
|
||||||
LogOutput: !input.noOutput,
|
LogOutput: !input.noOutput,
|
||||||
Secrets: newSecrets(input.secrets),
|
Env: envs,
|
||||||
|
Secrets: secrets,
|
||||||
Platforms: input.newPlatforms(),
|
Platforms: input.newPlatforms(),
|
||||||
}
|
}
|
||||||
runner, err := runner.New(config)
|
runner, err := runner.New(config)
|
||||||
|
|
|
@ -45,7 +45,7 @@ type stepResult struct {
|
||||||
// GetEnv returns the env for the context
|
// GetEnv returns the env for the context
|
||||||
func (rc *RunContext) GetEnv() map[string]string {
|
func (rc *RunContext) GetEnv() map[string]string {
|
||||||
if rc.Env == nil {
|
if rc.Env == nil {
|
||||||
rc.Env = mergeMaps(rc.Run.Workflow.Env, rc.Run.Job().Env)
|
rc.Env = mergeMaps(rc.Config.Env, rc.Run.Workflow.Env, rc.Run.Job().Env)
|
||||||
}
|
}
|
||||||
return rc.Env
|
return rc.Env
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ type Config struct {
|
||||||
ReuseContainers bool // reuse containers to maintain state
|
ReuseContainers bool // reuse containers to maintain state
|
||||||
ForcePull bool // force pulling of the image, if already present
|
ForcePull bool // force pulling of the image, if already present
|
||||||
LogOutput bool // log the output from docker run
|
LogOutput bool // log the output from docker run
|
||||||
|
Env map[string]string // env for containers
|
||||||
Secrets map[string]string // list of secrets
|
Secrets map[string]string // list of secrets
|
||||||
Platforms map[string]string // list of platforms
|
Platforms map[string]string // list of platforms
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package runner
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -110,18 +109,8 @@ func TestRunEventSecrets(t *testing.T) {
|
||||||
workdir, err := filepath.Abs("testdata")
|
workdir, err := filepath.Abs("testdata")
|
||||||
assert.NilError(t, err, workflowPath)
|
assert.NilError(t, err, workflowPath)
|
||||||
|
|
||||||
_ = godotenv.Load(filepath.Join(workdir, workflowPath, ".env"))
|
env, _ := godotenv.Read(filepath.Join(workdir, workflowPath, ".env"))
|
||||||
|
secrets, _ := godotenv.Read(filepath.Join(workdir, workflowPath, ".secrets"))
|
||||||
secrets := make(map[string]string)
|
|
||||||
for _, secret := range []string{
|
|
||||||
"MY_SECRET",
|
|
||||||
"MULTILINE_SECRET",
|
|
||||||
"JSON_SECRET",
|
|
||||||
} {
|
|
||||||
if env, ok := os.LookupEnv(secret); ok && env != "" {
|
|
||||||
secrets[secret] = env
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runnerConfig := &Config{
|
runnerConfig := &Config{
|
||||||
Workdir: workdir,
|
Workdir: workdir,
|
||||||
|
@ -129,6 +118,7 @@ func TestRunEventSecrets(t *testing.T) {
|
||||||
Platforms: platforms,
|
Platforms: platforms,
|
||||||
ReuseContainers: false,
|
ReuseContainers: false,
|
||||||
Secrets: secrets,
|
Secrets: secrets,
|
||||||
|
Env: env,
|
||||||
}
|
}
|
||||||
runner, err := New(runnerConfig)
|
runner, err := New(runnerConfig)
|
||||||
assert.NilError(t, err, workflowPath)
|
assert.NilError(t, err, workflowPath)
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
-W .
|
-W .
|
||||||
-s MY_SECRET
|
--secret-file .secrets
|
||||||
-s MULTILINE_SECRET
|
|
||||||
-s JSON_SECRET
|
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
MY_SECRET=top-secret
|
HELLO=WORLD
|
||||||
MULTILINE_SECRET="foo\nbar\nbaz"
|
MULTILINE_ENV="foo\nbar\nbaz"
|
||||||
JSON_SECRET={"foo": "bar"}
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
MY_SECRET=top-secret
|
||||||
|
MULTILINE_SECRET="foo\nbar\nbaz"
|
||||||
|
JSON_SECRET={"foo": "bar"}
|
|
@ -11,3 +11,7 @@ jobs:
|
||||||
echo "${{secrets.MULTILINE_SECRET}}" | wc -l | grep 3
|
echo "${{secrets.MULTILINE_SECRET}}" | wc -l | grep 3
|
||||||
- run: |
|
- run: |
|
||||||
echo '${{secrets.JSON_SECRET}}' | grep "{\"foo\": \"bar\"}"
|
echo '${{secrets.JSON_SECRET}}' | grep "{\"foo\": \"bar\"}"
|
||||||
|
- run: |
|
||||||
|
echo '${{env.HELLO}}' | grep "WORLD"
|
||||||
|
- run: |
|
||||||
|
echo "${{env.MULTILINE_ENV}}" | wc -l | grep 3
|
||||||
|
|
Loading…
Reference in New Issue