diff --git a/internal/boxcli/init.go b/internal/boxcli/init.go index 31ba559564f..1e14616c38d 100644 --- a/internal/boxcli/init.go +++ b/internal/boxcli/init.go @@ -36,7 +36,7 @@ func initCmd() *cobra.Command { path, _ = os.Getwd() } if errors.Is(err, os.ErrExist) { - ux.Fwarningf(cmd.ErrOrStderr(), "devbox.json already exists in %q.", path) + ux.Fwarningf(cmd.ErrOrStderr(), "A devbox config already exists in %q.", path) return nil } if err != nil { diff --git a/internal/boxcli/multi/multi.go b/internal/boxcli/multi/multi.go index 0a2cae34cdf..a98d28ef060 100644 --- a/internal/boxcli/multi/multi.go +++ b/internal/boxcli/multi/multi.go @@ -3,6 +3,7 @@ package multi import ( "io/fs" "path/filepath" + "slices" "go.jetify.com/devbox/internal/debug" "go.jetify.com/devbox/internal/devbox" @@ -14,6 +15,10 @@ func Open(opts *devopt.Opts) ([]*devbox.Devbox, error) { defer debug.FunctionTimer().End() var boxes []*devbox.Devbox + // A single directory may contain more than one recognized config name + // (e.g. both devbox.json and devbox.jsonc). Track the directories already + // opened so each project is opened exactly once. + seenDirs := map[string]bool{} err := filepath.WalkDir( ".", func(path string, dirEntry fs.DirEntry, err error) error { @@ -21,9 +26,17 @@ func Open(opts *devopt.Opts) ([]*devbox.Devbox, error) { return err } - if !dirEntry.IsDir() && filepath.Base(path) == configfile.DefaultName { + if !dirEntry.IsDir() && slices.Contains(configfile.ValidNames, filepath.Base(path)) { + dir := filepath.Dir(path) + if seenDirs[dir] { + return nil + } + seenDirs[dir] = true + optsCopy := *opts - optsCopy.Dir = path + // Open by directory so devconfig applies its filename + // precedence (devbox.json wins over devbox.jsonc). + optsCopy.Dir = dir box, err := devbox.Open(&optsCopy) if err != nil { return err diff --git a/internal/boxcli/multi/multi_test.go b/internal/boxcli/multi/multi_test.go new file mode 100644 index 00000000000..1ee18d52088 --- /dev/null +++ b/internal/boxcli/multi/multi_test.go @@ -0,0 +1,44 @@ +package multi + +import ( + "io" + "os" + "path/filepath" + "testing" + + "go.jetify.com/devbox/internal/devbox/devopt" + "go.jetify.com/devbox/internal/devconfig/configfile" +) + +// TestOpenDeduplicatesConfigsInSameDir ensures that a directory containing more +// than one recognized config name (e.g. both devbox.json and devbox.jsonc) is +// opened only once, so `--all-projects` commands don't run twice for it. +func TestOpenDeduplicatesConfigsInSameDir(t *testing.T) { + root := t.TempDir() + + // projBoth has both config names; projJSON has only devbox.json. + projBoth := filepath.Join(root, "projBoth") + projJSON := filepath.Join(root, "projJSON") + for _, dir := range []string{projBoth, projJSON} { + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, configfile.DefaultName), []byte(`{"packages": []}`), 0o644); err != nil { + t.Fatal(err) + } + } + if err := os.WriteFile(filepath.Join(projBoth, configfile.AltName), []byte(`{"packages": []}`), 0o644); err != nil { + t.Fatal(err) + } + + // multi.Open walks the current working directory. + t.Chdir(root) + + boxes, err := Open(&devopt.Opts{Stderr: io.Discard}) + if err != nil { + t.Fatalf("Open() error: %v", err) + } + if len(boxes) != 2 { + t.Errorf("Open() opened %d projects, want 2 (projBoth must be opened once despite having both config names)", len(boxes)) + } +} diff --git a/internal/devbox/devbox.go b/internal/devbox/devbox.go index c26b3257a65..50d49424123 100644 --- a/internal/devbox/devbox.go +++ b/internal/devbox/devbox.go @@ -502,6 +502,7 @@ func (d *Devbox) GenerateDevcontainer(ctx context.Context, generateOpts devopt.G IsDevcontainer: true, Pkgs: d.AllPackageNamesIncludingRemovedTriggerPackages(), LocalFlakeDirs: d.getLocalFlakesDirs(), + ConfigFileName: d.cfg.Root.FileName(), } // generate dockerfile @@ -541,6 +542,7 @@ func (d *Devbox) GenerateDockerfile(ctx context.Context, generateOpts devopt.Gen IsDevcontainer: false, Pkgs: d.AllPackageNamesIncludingRemovedTriggerPackages(), LocalFlakeDirs: d.getLocalFlakesDirs(), + ConfigFileName: d.cfg.Root.FileName(), } scripts := d.cfg.Scripts() diff --git a/internal/devbox/generate/devcontainer_util.go b/internal/devbox/generate/devcontainer_util.go index 9cbe36c1cbd..34b3317010c 100644 --- a/internal/devbox/generate/devcontainer_util.go +++ b/internal/devbox/generate/devcontainer_util.go @@ -23,6 +23,7 @@ import ( "github.com/samber/lo" "go.jetify.com/devbox/internal/boxcli/usererr" "go.jetify.com/devbox/internal/devbox/devopt" + "go.jetify.com/devbox/internal/devconfig/configfile" ) //go:embed tmpl/* @@ -34,6 +35,10 @@ type Options struct { IsDevcontainer bool Pkgs []string LocalFlakeDirs []string + // ConfigFileName is the basename of the project's config file + // (devbox.json or devbox.jsonc) so generated Dockerfiles copy the right + // one. Defaults to devbox.json when empty. + ConfigFileName string } type devcontainerObject struct { @@ -112,6 +117,7 @@ func (g *Options) CreateDockerfile( "IsDevcontainer": g.IsDevcontainer, "RootUser": g.RootUser, "LocalFlakeDirs": g.LocalFlakeDirs, + "ConfigFileName": cmp.Or(g.ConfigFileName, configfile.DefaultName), // The following are only used for prod Dockerfile "DevboxRunInstall": lo.Ternary(opts.HasInstall, "devbox run install", "echo 'No install script found, skipping'"), diff --git a/internal/devbox/generate/devcontainer_util_test.go b/internal/devbox/generate/devcontainer_util_test.go index f74edf88673..df81ecd7a9b 100644 --- a/internal/devbox/generate/devcontainer_util_test.go +++ b/internal/devbox/generate/devcontainer_util_test.go @@ -54,3 +54,32 @@ func generateDevDockerfile(t *testing.T, rootUser bool) string { } return string(contents) } + +// TestCreateDockerfileDevCopiesConfigFileName ensures the generated dev +// Dockerfile copies the project's actual config file, which may be named +// devbox.jsonc rather than devbox.json. +func TestCreateDockerfileDevCopiesConfigFileName(t *testing.T) { + for _, name := range []string{"", "devbox.json", "devbox.jsonc"} { + dir := t.TempDir() + g := &Options{Path: dir, ConfigFileName: name} + if err := g.CreateDockerfile(t.Context(), CreateDockerfileOptions{ForType: "dev"}); err != nil { + t.Fatalf("CreateDockerfile(ConfigFileName=%q) failed: %v", name, err) + } + contents, err := os.ReadFile(filepath.Join(dir, "Dockerfile")) + if err != nil { + t.Fatal(err) + } + want := name + if want == "" { + want = "devbox.json" + } + // Non-root images use `COPY --chown=... `; match on the + // trailing " " pair so both forms are covered. + if !strings.Contains(string(contents), " "+want+" "+want+"\n") { + t.Errorf("ConfigFileName=%q: Dockerfile should copy %s, got:\n%s", name, want, contents) + } + if want != "devbox.json" && strings.Contains(string(contents), " devbox.json devbox.json") { + t.Errorf("ConfigFileName=%q: Dockerfile should not also copy devbox.json, got:\n%s", name, contents) + } + } +} diff --git a/internal/devbox/generate/tmpl/dev.Dockerfile.tmpl b/internal/devbox/generate/tmpl/dev.Dockerfile.tmpl index 325b238e7f8..259d5fd0019 100644 --- a/internal/devbox/generate/tmpl/dev.Dockerfile.tmpl +++ b/internal/devbox/generate/tmpl/dev.Dockerfile.tmpl @@ -8,10 +8,10 @@ WORKDIR /code USER root:root RUN mkdir -p /code && chown ${DEVBOX_USER}:${DEVBOX_USER} /code USER ${DEVBOX_USER}:${DEVBOX_USER} -COPY --chown=${DEVBOX_USER}:${DEVBOX_USER} devbox.json devbox.json +COPY --chown=${DEVBOX_USER}:${DEVBOX_USER} {{.ConfigFileName}} {{.ConfigFileName}} COPY --chown=${DEVBOX_USER}:${DEVBOX_USER} devbox.lock devbox.lock {{- else}} -COPY devbox.json devbox.json +COPY {{.ConfigFileName}} {{.ConfigFileName}} COPY devbox.lock devbox.lock {{- end}} diff --git a/internal/devbox/generate/tmpl/envrcContent.tmpl b/internal/devbox/generate/tmpl/envrcContent.tmpl index b68bbbc7204..5b02f675799 100644 --- a/internal/devbox/generate/tmpl/envrcContent.tmpl +++ b/internal/devbox/generate/tmpl/envrcContent.tmpl @@ -1,6 +1,6 @@ use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias{{ if .EnvFlag }} {{ .EnvFlag }}{{ end }}{{ if .ConfigDir }} {{ .ConfigDir }}{{ end }})" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox {{ if .EnvFile }} diff --git a/internal/devconfig/config.go b/internal/devconfig/config.go index fd249780471..c60b1b8cd00 100644 --- a/internal/devconfig/config.go +++ b/internal/devconfig/config.go @@ -142,8 +142,7 @@ func Find(path string) (*Config, error) { // searchDir looks for a config file in dir. It does not search parent // directories. func searchDir(dir string) (*Config, error) { - try := []string{configfile.DefaultName} - for _, name := range try { + for _, name := range configfile.ValidNames { path := filepath.Join(dir, name) slog.Debug("trying config file", "path", path) @@ -156,7 +155,7 @@ func searchDir(dir string) (*Config, error) { if errors.Is(err, os.ErrNotExist) { continue } - // Ignore directories named devbox.json. + // Ignore directories that happen to share a config filename. if errors.Is(err, errIsDirectory) { continue } diff --git a/internal/devconfig/config_test.go b/internal/devconfig/config_test.go index 7303fbb8163..d7d8924d8ab 100644 --- a/internal/devconfig/config_test.go +++ b/internal/devconfig/config_test.go @@ -282,6 +282,86 @@ func TestFindError(t *testing.T) { }) } +func TestJSONCConfig(t *testing.T) { + const jsonc = "{\n // devbox lets you comment your config\n \"packages\": []\n}\n" + + t.Run("OpenDiscoversJSONC", func(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, configfile.AltName) + if err := os.WriteFile(path, []byte(jsonc), 0o644); err != nil { + t.Fatal(err) + } + + cfg, err := Open(dir) + if err != nil { + t.Fatalf("Open(%q) error: %v", dir, err) + } + if cfg.Root.AbsRootPath != path { + t.Errorf("cfg.Root.AbsRootPath = %q, want %q", cfg.Root.AbsRootPath, path) + } + }) + + t.Run("FindDiscoversJSONCInParent", func(t *testing.T) { + root, child, _ := mkNestedDirs(t) + path := filepath.Join(root, configfile.AltName) + if err := os.WriteFile(path, []byte(jsonc), 0o644); err != nil { + t.Fatal(err) + } + + cfg, err := Find(child) + if err != nil { + t.Fatalf("Find(%q) error: %v", child, err) + } + if cfg.Root.AbsRootPath != path { + t.Errorf("cfg.Root.AbsRootPath = %q, want %q", cfg.Root.AbsRootPath, path) + } + }) + + t.Run("DefaultNameWinsWhenBothExist", func(t *testing.T) { + dir := t.TempDir() + jsonPath := filepath.Join(dir, configfile.DefaultName) + if err := os.WriteFile(jsonPath, []byte(`{"packages": []}`), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, configfile.AltName), []byte(jsonc), 0o644); err != nil { + t.Fatal(err) + } + + cfg, err := Open(dir) + if err != nil { + t.Fatalf("Open(%q) error: %v", dir, err) + } + if cfg.Root.AbsRootPath != jsonPath { + t.Errorf("cfg.Root.AbsRootPath = %q, want %q", cfg.Root.AbsRootPath, jsonPath) + } + }) + + t.Run("SaveWritesBackToJSONC", func(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, configfile.AltName) + if err := os.WriteFile(path, []byte(jsonc), 0o644); err != nil { + t.Fatal(err) + } + + cfg, err := Open(dir) + if err != nil { + t.Fatalf("Open(%q) error: %v", dir, err) + } + if err := cfg.Root.SaveTo(dir); err != nil { + t.Fatalf("SaveTo(%q) error: %v", dir, err) + } + + // Saving must write back to devbox.jsonc, not create a devbox.json. + if _, err := os.Stat(filepath.Join(dir, configfile.DefaultName)); !errors.Is(err, fs.ErrNotExist) { + t.Errorf("SaveTo created a %s; want it to update %s in place", + configfile.DefaultName, configfile.AltName) + } + if _, err := os.Stat(path); err != nil { + t.Errorf("os.Stat(%q) after save: %v", path, err) + } + }) +} + // mkNestedDirs sets up a nested directory structure for Find and Open tests. func mkNestedDirs(t *testing.T) (root, child, nested string) { t.Helper() @@ -599,3 +679,20 @@ func (p *testLockProject) ConfigHash() (string, error) { return "", nil } func (p *testLockProject) Stdenv() flake.Ref { return flake.Ref{} } func (p *testLockProject) AllPackageNamesIncludingRemovedTriggerPackages() []string { return nil } func (p *testLockProject) ProjectDir() string { return p.dir } + +func TestInitRefusesWhenJSONCExists(t *testing.T) { + dir := t.TempDir() + jsoncPath := filepath.Join(dir, configfile.AltName) + if err := os.WriteFile(jsoncPath, []byte("{\n // comment\n \"packages\": []\n}\n"), 0o644); err != nil { + t.Fatal(err) + } + + _, err := Init(dir) + if !errors.Is(err, fs.ErrExist) { + t.Fatalf("Init() with existing %s: got err %v, want fs.ErrExist", configfile.AltName, err) + } + // Init must not have created a devbox.json that would shadow the jsonc. + if _, err := os.Stat(filepath.Join(dir, configfile.DefaultName)); !errors.Is(err, fs.ErrNotExist) { + t.Errorf("Init() created %s next to an existing %s", configfile.DefaultName, configfile.AltName) + } +} diff --git a/internal/devconfig/configfile/file.go b/internal/devconfig/configfile/file.go index 1bf94a4c190..a5e81927feb 100644 --- a/internal/devconfig/configfile/file.go +++ b/internal/devconfig/configfile/file.go @@ -21,8 +21,19 @@ import ( const ( DefaultName = "devbox.json" + // AltName is an alternate config filename that devbox also recognizes. + // devbox.json already permits comments (it is parsed as JSONC), but + // editors and GitHub diffs flag comments in a .json file as errors. Naming + // the file devbox.jsonc lets those tools highlight it correctly without any + // extra configuration. See https://github.com/jetify-com/devbox/issues/2602 + AltName = "devbox.jsonc" ) +// ValidNames are the config filenames devbox recognizes, in the order they are +// searched for within a directory. devbox.json is listed first so it wins when +// a directory happens to contain both files. +var ValidNames = []string{DefaultName, AltName} + // ConfigFile defines a devbox environment as JSON. type ConfigFile struct { // AbsRootPath is the absolute path to the devbox.json or plugin.json file @@ -114,9 +125,21 @@ func (c *ConfigFile) InitHook() *shellcmd.Commands { return c.Shell.InitHook } -// SaveTo writes the config to a file. -func (c *ConfigFile) SaveTo(path string) error { - return os.WriteFile(filepath.Join(path, DefaultName), c.Bytes(), 0o644) +// FileName returns the base name of the config file (e.g. "devbox.json" or +// "devbox.jsonc"). It preserves whatever name the config was loaded from so +// that saving writes back to the same file. It falls back to [DefaultName] when +// the config has no on-disk path (for example, a config loaded from a URL). +func (c *ConfigFile) FileName() string { + if c.AbsRootPath != "" { + return filepath.Base(c.AbsRootPath) + } + return DefaultName +} + +// SaveTo writes the config into the directory dir, using the config's original +// filename (see [ConfigFile.FileName]). +func (c *ConfigFile) SaveTo(dir string) error { + return os.WriteFile(filepath.Join(dir, c.FileName()), c.Bytes(), 0o644) } // TODO: Can we remove SaveTo and just use Save()? diff --git a/internal/devconfig/configfile/file_test.go b/internal/devconfig/configfile/file_test.go index c58f8a08086..66804c6e306 100644 --- a/internal/devconfig/configfile/file_test.go +++ b/internal/devconfig/configfile/file_test.go @@ -4,6 +4,8 @@ package configfile import ( "encoding/json" "io" + "os" + "path/filepath" "strings" "testing" @@ -782,3 +784,52 @@ func TestNixpkgsValidation(t *testing.T) { }) } } + +func TestFileName(t *testing.T) { + testCases := map[string]struct { + absRootPath string + want string + }{ + "empty_falls_back_to_default": {"", DefaultName}, + "json": {"/home/user/project/devbox.json", DefaultName}, + "jsonc": {"/home/user/project/devbox.jsonc", AltName}, + } + + for name, testCase := range testCases { + t.Run(name, func(t *testing.T) { + c := &ConfigFile{AbsRootPath: testCase.absRootPath} + if got := c.FileName(); got != testCase.want { + t.Errorf("FileName() = %q, want %q", got, testCase.want) + } + }) + } +} + +func TestSaveToPreservesFileName(t *testing.T) { + testCases := map[string]struct { + absRootPath string + wantName string + }{ + "json": {"/anywhere/devbox.json", DefaultName}, + "jsonc": {"/anywhere/devbox.jsonc", AltName}, + "no_path_uses_default": {"", DefaultName}, + } + + for name, testCase := range testCases { + t.Run(name, func(t *testing.T) { + in, err := LoadBytes([]byte(`{"packages": []}`)) + if err != nil { + t.Fatalf("LoadBytes error: %v", err) + } + in.AbsRootPath = testCase.absRootPath + + dir := t.TempDir() + if err := in.SaveTo(dir); err != nil { + t.Fatalf("SaveTo(%q) error: %v", dir, err) + } + if _, err := os.Stat(filepath.Join(dir, testCase.wantName)); err != nil { + t.Errorf("expected %q to be written: %v", testCase.wantName, err) + } + }) + } +} diff --git a/internal/devconfig/init.go b/internal/devconfig/init.go index 911ae3976be..fa3b59b2482 100644 --- a/internal/devconfig/init.go +++ b/internal/devconfig/init.go @@ -4,6 +4,7 @@ package devconfig import ( + "io/fs" "os" "path/filepath" @@ -11,6 +12,16 @@ import ( ) func Init(dir string) (*Config, error) { + // A project may already be configured under an alternate filename + // (devbox.jsonc). Creating devbox.json next to it would silently take + // precedence, so treat any recognized config name as "already exists". + for _, name := range configfile.ValidNames { + path := filepath.Join(dir, name) + if _, err := os.Stat(path); err == nil { + return nil, &fs.PathError{Op: "open", Path: path, Err: fs.ErrExist} + } + } + file, err := os.OpenFile( filepath.Join(dir, configfile.DefaultName), os.O_RDWR|os.O_CREATE|os.O_EXCL, diff --git a/internal/pullbox/files.go b/internal/pullbox/files.go index 1f30ed9be92..12e2c886a9b 100644 --- a/internal/pullbox/files.go +++ b/internal/pullbox/files.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path/filepath" + "slices" "strings" "github.com/pkg/errors" @@ -63,7 +64,7 @@ func profileIsNotEmpty(path string) (bool, error) { return false, errors.WithStack(err) } for _, entry := range entries { - if entry.Name() != configfile.DefaultName || + if !slices.Contains(configfile.ValidNames, entry.Name()) || isModifiedConfig(filepath.Join(path, entry.Name())) { return true, nil } @@ -72,7 +73,7 @@ func profileIsNotEmpty(path string) (bool, error) { } func isModifiedConfig(path string) bool { - if filepath.Base(path) == configfile.DefaultName { + if slices.Contains(configfile.ValidNames, filepath.Base(path)) { return !devconfig.IsDefault(path) } return false diff --git a/testscripts/generate/direnv-config-envflag.test.txt b/testscripts/generate/direnv-config-envflag.test.txt index dc5c9194b04..ea38393d78c 100644 --- a/testscripts/generate/direnv-config-envflag.test.txt +++ b/testscripts/generate/direnv-config-envflag.test.txt @@ -20,7 +20,7 @@ cmp stdout ../expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias --env x=y )" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-config.test.txt b/testscripts/generate/direnv-config.test.txt index 0211b3ff4ec..6ab07c4dabb 100644 --- a/testscripts/generate/direnv-config.test.txt +++ b/testscripts/generate/direnv-config.test.txt @@ -20,7 +20,7 @@ cmp stdout ../expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-envflag.test.txt b/testscripts/generate/direnv-envflag.test.txt index 2dd0aea9ff5..10b069e7c8f 100644 --- a/testscripts/generate/direnv-envflag.test.txt +++ b/testscripts/generate/direnv-envflag.test.txt @@ -15,7 +15,7 @@ cmp stdout expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias --env x=y )" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-envrcdir-config-parent.test.txt b/testscripts/generate/direnv-envrcdir-config-parent.test.txt index 161e14dff83..ff62cfc6ab8 100644 --- a/testscripts/generate/direnv-envrcdir-config-parent.test.txt +++ b/testscripts/generate/direnv-envrcdir-config-parent.test.txt @@ -21,7 +21,7 @@ cmp stdout ../expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-envrcdir-config-sibling.test.txt b/testscripts/generate/direnv-envrcdir-config-sibling.test.txt index 0e48471de7b..bf8a55062e3 100644 --- a/testscripts/generate/direnv-envrcdir-config-sibling.test.txt +++ b/testscripts/generate/direnv-envrcdir-config-sibling.test.txt @@ -19,7 +19,7 @@ cmp stdout ../expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias --config ../cfg)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-envrcdir-config-subdir-envflag.test.txt b/testscripts/generate/direnv-envrcdir-config-subdir-envflag.test.txt index 2dcab6115e1..61bab2e5dd1 100644 --- a/testscripts/generate/direnv-envrcdir-config-subdir-envflag.test.txt +++ b/testscripts/generate/direnv-envrcdir-config-subdir-envflag.test.txt @@ -18,7 +18,7 @@ cmp stdout ../expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias --env x=y --config cfg)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-envrcdir-config-subdir.test.txt b/testscripts/generate/direnv-envrcdir-config-subdir.test.txt index 83dbcd001fd..c7fba91c595 100644 --- a/testscripts/generate/direnv-envrcdir-config-subdir.test.txt +++ b/testscripts/generate/direnv-envrcdir-config-subdir.test.txt @@ -18,7 +18,7 @@ cmp stdout ../expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias --config cfg)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-envrcdir-current-config-sub.test.txt b/testscripts/generate/direnv-envrcdir-current-config-sub.test.txt index 0d6533486b7..ea5aabf8206 100644 --- a/testscripts/generate/direnv-envrcdir-current-config-sub.test.txt +++ b/testscripts/generate/direnv-envrcdir-current-config-sub.test.txt @@ -17,7 +17,7 @@ cmp stdout expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias --config cfg)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-envrcdir-parent.test.txt b/testscripts/generate/direnv-envrcdir-parent.test.txt index a49a6424a93..4bc2c3ade3c 100644 --- a/testscripts/generate/direnv-envrcdir-parent.test.txt +++ b/testscripts/generate/direnv-envrcdir-parent.test.txt @@ -20,7 +20,7 @@ cmp stdout expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias --config cfg)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-envrcdir.test.txt b/testscripts/generate/direnv-envrcdir.test.txt index 43cae344ce5..82dd4bc96d9 100644 --- a/testscripts/generate/direnv-envrcdir.test.txt +++ b/testscripts/generate/direnv-envrcdir.test.txt @@ -21,7 +21,7 @@ cmp stdout ../expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-printenvrc-config.test.txt b/testscripts/generate/direnv-printenvrc-config.test.txt index 89182a07f2c..72d6f917bdf 100644 --- a/testscripts/generate/direnv-printenvrc-config.test.txt +++ b/testscripts/generate/direnv-printenvrc-config.test.txt @@ -15,7 +15,7 @@ cmp stdout expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias --config config-dir)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv-printenvrc.test.txt b/testscripts/generate/direnv-printenvrc.test.txt index 9c66cda6302..b4f6546ded5 100644 --- a/testscripts/generate/direnv-printenvrc.test.txt +++ b/testscripts/generate/direnv-printenvrc.test.txt @@ -14,7 +14,7 @@ cmp stdout expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/generate/direnv.test.txt b/testscripts/generate/direnv.test.txt index f09a0d2b893..3885802fe8b 100644 --- a/testscripts/generate/direnv.test.txt +++ b/testscripts/generate/direnv.test.txt @@ -15,7 +15,7 @@ cmp stdout expected-results.txt -- expected-results.txt -- use_devbox() { eval "$(devbox shellenv --init-hook --install --no-refresh-alias)" - watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.lock + watch_file $DEVBOX_PROJECT_ROOT/devbox.json $DEVBOX_PROJECT_ROOT/devbox.jsonc $DEVBOX_PROJECT_ROOT/devbox.lock } use devbox diff --git a/testscripts/init/empty.test.txt b/testscripts/init/empty.test.txt index 74f9b0ce00a..6c64a6b6d47 100644 --- a/testscripts/init/empty.test.txt +++ b/testscripts/init/empty.test.txt @@ -8,7 +8,7 @@ json.superset devbox.json expected.json # Second init should be a no-op with a warning exec devbox init -stderr 'devbox.json already exists in' +stderr 'A devbox config already exists in' -- expected.json -- {