From 70a508fc4537ef1b2d622384773388db7554a3b2 Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Tue, 10 Sep 2019 18:13:44 +0200 Subject: [PATCH] Add warnings for env_file entries not copied As 'env_file' entries are not taken in account, we warn the user to copy that and fix it's compose file. Signed-off-by: Ulysses Souza --- e2e/commands_test.go | 50 +++++++++++ ...it-output-warning-multiple-envfiles.golden | 3 + .../init-output-warning-single-envfile.golden | 2 + internal/packager/init.go | 83 +++++++++++++++---- 4 files changed, 124 insertions(+), 14 deletions(-) create mode 100644 e2e/testdata/init-output-warning-multiple-envfiles.golden create mode 100644 e2e/testdata/init-output-warning-single-envfile.golden diff --git a/e2e/commands_test.go b/e2e/commands_test.go index fdf283967..429676b4b 100644 --- a/e2e/commands_test.go +++ b/e2e/commands_test.go @@ -74,6 +74,56 @@ func TestRenderFormatters(t *testing.T) { golden.Assert(t, result.Stdout(), "expected-yaml-render.golden") } +func checkFileWarning(t *testing.T, goldenFile, composeData string) { + cmd, cleanup := dockerCli.createTestCmd() + defer cleanup() + + tmpDir := fs.NewDir(t, "app_input", + fs.WithFile(internal.ComposeFileName, composeData), + ) + defer tmpDir.Remove() + + cmd.Dir = tmpDir.Path() + cmd.Command = dockerCli.Command("app", "init", "app-test", + "--compose-file", tmpDir.Join(internal.ComposeFileName)) + stdOut := icmd.RunCmd(cmd).Assert(t, icmd.Success).Combined() + golden.Assert(t, stdOut, goldenFile) +} + +func TestInitWarningEnvFiles(t *testing.T) { + testCases := []struct { + name string + golden string + compose string + }{ + { + name: "initWarningMultipleEnvFilesTest", + golden: "init-output-warning-single-envfile.golden", + compose: `version: "3.2" +services: + nginx: + image: nginx:latest + env_file: myenv1.env`, + }, + { + name: "initWarningMultipleEnvFilesTest", + golden: "init-output-warning-multiple-envfiles.golden", + compose: `version: "3.2" +services: + nginx: + image: nginx:latest + env_file: + - myenv1.env + - myenv2.env`, + }, + } + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + checkFileWarning(t, test.golden, test.compose) + }) + } +} + func TestInit(t *testing.T) { cmd, cleanup := dockerCli.createTestCmd() defer cleanup() diff --git a/e2e/testdata/init-output-warning-multiple-envfiles.golden b/e2e/testdata/init-output-warning-multiple-envfiles.golden new file mode 100644 index 000000000..d17b11d27 --- /dev/null +++ b/e2e/testdata/init-output-warning-multiple-envfiles.golden @@ -0,0 +1,3 @@ +"env_file: myenv1.env" entry of service "nginx" will NOT be copied automatically! Please, copy the file inside the application folder and update your compose file referring to it. +"env_file: myenv2.env" entry of service "nginx" will NOT be copied automatically! Please, copy the file inside the application folder and update your compose file referring to it. +Created "app-test.dockerapp" diff --git a/e2e/testdata/init-output-warning-single-envfile.golden b/e2e/testdata/init-output-warning-single-envfile.golden new file mode 100644 index 000000000..ff1db6b8f --- /dev/null +++ b/e2e/testdata/init-output-warning-single-envfile.golden @@ -0,0 +1,2 @@ +"env_file: myenv1.env" entry of service "nginx" will NOT be copied automatically! Please, copy the file inside the application folder and update your compose file referring to it. +Created "app-test.dockerapp" diff --git a/internal/packager/init.go b/internal/packager/init.go index 76a3c02a3..20af13683 100644 --- a/internal/packager/init.go +++ b/internal/packager/init.go @@ -123,22 +123,51 @@ func checkComposeFileVersion(compose map[string]interface{}) error { return schema.Validate(compose, fmt.Sprintf("%v", version)) } -func initFromComposeFile(name string, composeFile string) error { - logrus.Debugf("Initializing from compose file %s", composeFile) - - dirName := internal.DirNameFromAppName(name) - - composeRaw, err := ioutil.ReadFile(composeFile) - if err != nil { - return errors.Wrap(err, "failed to read compose file") +func getEnvFiles(svcName string, envFileEntry interface{}) ([]string, error) { + var envFiles []string + switch envFileEntry.(type) { + case string: + envFiles = append(envFiles, envFileEntry.(string)) + case []interface{}: + for _, env := range envFileEntry.([]interface{}) { + envFiles = append(envFiles, env.(string)) + } + default: + return nil, fmt.Errorf("unknown entries in 'env_file' for service %s -> %v", + svcName, envFileEntry) } - cfgMap, err := composeloader.ParseYAML(composeRaw) - if err != nil { - return errors.Wrap(err, "failed to parse compose file") + return envFiles, nil +} + +func checkEnvFiles(cfgMap map[string]interface{}) error { + services := cfgMap["services"] + servicesMap, ok := services.(map[string]interface{}) + if !ok { + return fmt.Errorf("could not process the yaml file 1") } - if err := checkComposeFileVersion(cfgMap); err != nil { - return err + for svcName, svc := range servicesMap { + svcContent, ok := svc.(map[string]interface{}) + if !ok { + return fmt.Errorf("could not process the yaml file 2") + } + envFileEntry, ok := svcContent["env_file"] + if !ok { + continue + } + envFiles, err := getEnvFiles(svcName, envFileEntry) + if err != nil { + return errors.Wrap(err, "could not process the yaml file 4") + } + for _, envFilePath := range envFiles { + fmt.Printf("\"env_file: %s\" entry of service %q will NOT be copied automatically! "+ + "Please, copy the file inside the application folder and update your compose file "+ + "referring to it.\n", envFilePath, svcName) + } } + return nil +} + +func getParamsFromDefaultEnvFile(composeFile string, composeRaw []byte) (map[string]string, bool, error) { params := make(map[string]string) envs, err := opts.ParseEnvFile(filepath.Join(filepath.Dir(composeFile), ".env")) if err == nil { @@ -151,7 +180,7 @@ func initFromComposeFile(name string, composeFile string) error { } vars, err := compose.ExtractVariables(composeRaw, compose.ExtrapolationPattern) if err != nil { - return errors.Wrap(err, "failed to parse compose file") + return nil, false, errors.Wrap(err, "failed to parse compose file") } needsFilling := false for k, v := range vars { @@ -164,6 +193,32 @@ func initFromComposeFile(name string, composeFile string) error { } } } + return params, needsFilling, nil +} + +func initFromComposeFile(name string, composeFile string) error { + logrus.Debugf("Initializing from compose file %s", composeFile) + + dirName := internal.DirNameFromAppName(name) + + composeRaw, err := ioutil.ReadFile(composeFile) + if err != nil { + return errors.Wrap(err, "failed to read compose file") + } + cfgMap, err := composeloader.ParseYAML(composeRaw) + if err != nil { + return errors.Wrap(err, "failed to parse compose file") + } + if err := checkComposeFileVersion(cfgMap); err != nil { + return err + } + if err := checkEnvFiles(cfgMap); err != nil { + return err + } + params, needsFilling, err := getParamsFromDefaultEnvFile(composeFile, composeRaw) + if err != nil { + return err + } expandedParams, err := parameters.FromFlatten(params) if err != nil { return errors.Wrap(err, "failed to expand parameters")