Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions internal/devbox/devbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,21 @@ func (d *Devbox) configEnvs(
}
}
}
} else if d.cfg.Root.IsdotEnvEnabled() {
// if env_from points to a .env file, parse and add it
parsedEnvs, err := d.cfg.Root.ParseEnvsFromDotEnv()
if err != nil {
// it's fine to include the error ParseEnvsFromDotEnv here because
// the error message is relevant to the user
return nil, usererr.New(
"failed parsing %s file. Error: %v",
d.cfg.Root.EnvFrom,
err,
)
}
for k, v := range parsedEnvs {
env[k] = v
}
} else if d.cfg.Root.EnvFrom != "" {
return nil, usererr.New(
"unknown from_env value: %s. Supported value is: %q.",
Expand Down
61 changes: 59 additions & 2 deletions internal/devconfig/configfile/env.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,63 @@
package configfile

import (
"bufio"
"fmt"
"os"
"path/filepath"
"strings"
)

func (c *ConfigFile) IsEnvsecEnabled() bool {
// envsec for legacy.
return c.EnvFrom == "envsec" || c.EnvFrom == "jetpack-cloud"
// envsec for legacy. jetpack-cloud for legacy
return c.EnvFrom == "envsec" || c.EnvFrom == "jetpack-cloud" || c.EnvFrom == "jetify-cloud"
}

func (c *ConfigFile) IsdotEnvEnabled() bool {
// filename has to end with .env
return filepath.Ext(c.EnvFrom) == ".env"
}

func (c *ConfigFile) ParseEnvsFromDotEnv() (map[string]string, error) {
// This check should never happen because we call IsdotEnvEnabled
// before calling this method. But having it makes it more robust
// in case if anyone uses this method without the IsdotEnvEnabled
if !c.IsdotEnvEnabled() {
return nil, fmt.Errorf("env file does not have a .env extension")
}

file, err := os.Open(c.EnvFrom)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail if devbox is call from any other directory that is not where the devbox.json is. I don't think it makes sense to make this relative from the working directory, it should be relative from the config file directory.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, my project failed due to it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@varunpalekar thanks for reminding on the issue. I made a PR to fix this, once merged it will be available in the next version of devbox.

if err != nil {
return nil, fmt.Errorf("failed to open file: %s", c.EnvFrom)
}
defer file.Close()

envMap := map[string]string{}

// Read the file line by line
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
// Ideally .env file shouldn't have empty lines and comments but
// this check makes it allowed.
if strings.TrimSpace(line) == "" || strings.HasPrefix(line, "#") {
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
return nil, fmt.Errorf("invalid line in .env file: %s", line)
}
// Also ideally, .env files should not have space in their `key=value` format
// but this allows `key = value` to pass through as well
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])

// Add the parsed key-value pair to the map
envMap[key] = value
}

if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("failed to read env file: %v", err)
}
return envMap, nil
}
36 changes: 36 additions & 0 deletions testscripts/run/envfrom.test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Tests related to setting the env_from for devbox run.

exec devbox run test
stdout 'BAR'

exec devbox run test2
stdout 'BAZ'

exec devbox run test3
stdout 'BAS'

exec devbox run test4
stdout ''

-- test.env --
FOO=BAR
FOO2 = BAZ
FOO3=ToBeOverwrittenByDevboxJSON
# FOO4=comment shouldn't be processed

-- devbox.json --
{
"packages": [],
"env": {
"FOO3": "BAS"
},
"shell": {
"scripts": {
"test": "echo $FOO",
"test2": "echo $FOO2",
"test3": "echo $FOO3",
"test4": "echo $FOO4"
}
},
"env_from": "test.env"
}