Skip to content

Commit 7d1f2ac

Browse files
mikeland73jefft
authored andcommitted
[run] Add --all-projects flag (jetify-com#2543)
## Summary Allows running a script on all devbox projects nested in a directory. Useful for monorepos. Example: `devbox run --all-projects lint` Doing `devbox run --all-projects` without a script name shows all available scripts among all nested projects. @savil I kinda regret changing `run` to remove the need for `--`. It means that this flag only works for defined scripts, not for arbitrary commands :( ## How was it tested? `devbox run --all-projects fmt`
1 parent 189ebfe commit 7d1f2ac

File tree

3 files changed

+89
-22
lines changed

3 files changed

+89
-22
lines changed
Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,71 @@
11
{
22
"lockfile_version": "1",
33
"packages": {
4+
"darwin.apple_sdk.frameworks.CoreServices": {
5+
"resolved": "github:NixOS/nixpkgs/3a05eebede89661660945da1f151959900903b6a?narHash=sha256-Ly2fBL1LscV%2BKyCqPRufUBuiw%2BzmWrlJzpWOWbahplg%3D#darwin.apple_sdk.frameworks.CoreServices",
6+
"source": "nixpkg",
7+
"systems": {
8+
"aarch64-darwin": {
9+
"outputs": [
10+
{
11+
"path": "/nix/store/mpq140x7nsx9gz73h4nfp9kpp297mshh-CoreServices-11.0",
12+
"default": true
13+
}
14+
]
15+
}
16+
}
17+
},
418
"elixir@latest": {
5-
"last_modified": "2024-11-28T07:51:56Z",
19+
"last_modified": "2024-12-27T03:08:00Z",
620
"plugin_version": "0.0.1",
7-
"resolved": "github:NixOS/nixpkgs/226216574ada4c3ecefcbbec41f39ce4655f78ef#elixir",
21+
"resolved": "github:NixOS/nixpkgs/7cc0bff31a3a705d3ac4fdceb030a17239412210#elixir",
822
"source": "devbox-search",
9-
"version": "1.17.3",
23+
"version": "1.18.1",
1024
"systems": {
1125
"aarch64-darwin": {
1226
"outputs": [
1327
{
1428
"name": "out",
15-
"path": "/nix/store/91w79z55qsjkhnbs3a21l3h27va98mf6-elixir-1.17.3",
29+
"path": "/nix/store/hdd9x34p0gplcl1bramq80lqi76xrd87-elixir-1.18.1",
1630
"default": true
1731
}
1832
],
19-
"store_path": "/nix/store/91w79z55qsjkhnbs3a21l3h27va98mf6-elixir-1.17.3"
33+
"store_path": "/nix/store/hdd9x34p0gplcl1bramq80lqi76xrd87-elixir-1.18.1"
2034
},
2135
"aarch64-linux": {
2236
"outputs": [
2337
{
2438
"name": "out",
25-
"path": "/nix/store/pz4hk0sp4zj76waaprlfdmvc4xdblz55-elixir-1.17.3",
39+
"path": "/nix/store/a4g29icpil9b1hsniqspz5k110h4df8v-elixir-1.18.1",
2640
"default": true
2741
}
2842
],
29-
"store_path": "/nix/store/pz4hk0sp4zj76waaprlfdmvc4xdblz55-elixir-1.17.3"
43+
"store_path": "/nix/store/a4g29icpil9b1hsniqspz5k110h4df8v-elixir-1.18.1"
3044
},
3145
"x86_64-darwin": {
3246
"outputs": [
3347
{
3448
"name": "out",
35-
"path": "/nix/store/gnjg57wv71svvqw7s3rxyjc6lkps2r95-elixir-1.17.3",
49+
"path": "/nix/store/b3h6f36zd4gjivb76lvvs6a9bi1mq9q8-elixir-1.18.1",
3650
"default": true
3751
}
3852
],
39-
"store_path": "/nix/store/gnjg57wv71svvqw7s3rxyjc6lkps2r95-elixir-1.17.3"
53+
"store_path": "/nix/store/b3h6f36zd4gjivb76lvvs6a9bi1mq9q8-elixir-1.18.1"
4054
},
4155
"x86_64-linux": {
4256
"outputs": [
4357
{
4458
"name": "out",
45-
"path": "/nix/store/rx7qr8bar4qldx6yg3njvm8hn84d3yyk-elixir-1.17.3",
59+
"path": "/nix/store/3zd200bq28mv3pdbii7rijzmb0gmhhs3-elixir-1.18.1",
4660
"default": true
4761
}
4862
],
49-
"store_path": "/nix/store/rx7qr8bar4qldx6yg3njvm8hn84d3yyk-elixir-1.17.3"
63+
"store_path": "/nix/store/3zd200bq28mv3pdbii7rijzmb0gmhhs3-elixir-1.18.1"
5064
}
5165
}
66+
},
67+
"github:NixOS/nixpkgs/nixpkgs-unstable": {
68+
"resolved": "github:NixOS/nixpkgs/3a05eebede89661660945da1f151959900903b6a?lastModified=1740547748&narHash=sha256-Ly2fBL1LscV%2BKyCqPRufUBuiw%2BzmWrlJzpWOWbahplg%3D"
5269
}
5370
}
5471
}

internal/boxcli/run.go

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ import (
77
"fmt"
88
"log/slog"
99
"slices"
10+
"sort"
1011
"strings"
1112

13+
"github.com/pkg/errors"
1214
"github.com/samber/lo"
1315
"github.com/spf13/cobra"
1416
"github.com/spf13/pflag"
1517

18+
"go.jetify.com/devbox/internal/boxcli/multi"
1619
"go.jetify.com/devbox/internal/boxcli/usererr"
1720
"go.jetify.com/devbox/internal/devbox"
1821
"go.jetify.com/devbox/internal/devbox/devopt"
@@ -27,6 +30,7 @@ type runCmdFlags struct {
2730
pure bool
2831
listScripts bool
2932
recomputeEnv bool
33+
allProjects bool
3034
}
3135

3236
// runFlagDefaults are the flag default values that differ
@@ -65,24 +69,44 @@ func runCmd(defaults runFlagDefaults) *cobra.Command {
6569
)
6670
_ = command.Flags().MarkHidden("omit-nix-env")
6771
command.Flags().BoolVar(&flags.recomputeEnv, "recompute", true, "recompute environment if needed")
72+
command.Flags().BoolVar(
73+
&flags.allProjects,
74+
"all-projects",
75+
false,
76+
"run command in all projects in the working directory, recursively. If command is not found in any project, it will be skipped.",
77+
)
6878

6979
command.ValidArgs = listScripts(command, flags)
7080

7181
return command
7282
}
7383

7484
func listScripts(cmd *cobra.Command, flags runCmdFlags) []string {
75-
box, err := devbox.Open(&devopt.Opts{
85+
devboxOpts := &devopt.Opts{
7686
Dir: flags.config.path,
7787
Environment: flags.config.environment,
7888
Stderr: cmd.ErrOrStderr(),
7989
IgnoreWarnings: true,
80-
})
90+
}
91+
92+
if flags.allProjects {
93+
boxes, err := multi.Open(devboxOpts)
94+
if err != nil {
95+
slog.Error("failed to open devbox", "err", err)
96+
return nil
97+
}
98+
scripts := []string{}
99+
for _, box := range boxes {
100+
scripts = append(scripts, box.ListScripts()...)
101+
}
102+
sort.Strings(scripts)
103+
return lo.Uniq(scripts)
104+
}
105+
box, err := devbox.Open(devboxOpts)
81106
if err != nil {
82107
slog.Error("failed to open devbox", "err", err)
83108
return nil
84109
}
85-
86110
return box.ListScripts()
87111
}
88112

@@ -112,15 +136,25 @@ func runScriptCmd(cmd *cobra.Command, args []string, flags runCmdFlags) error {
112136
return err
113137
}
114138

115-
// Check the directory exists.
116-
box, err := devbox.Open(&devopt.Opts{
139+
boxes := []*devbox.Devbox{}
140+
devboxOpts := &devopt.Opts{
117141
Dir: path,
118142
Env: env,
119143
Environment: flags.config.environment,
120144
Stderr: cmd.ErrOrStderr(),
121-
})
122-
if err != nil {
123-
return redact.Errorf("error reading devbox.json: %w", err)
145+
}
146+
147+
if flags.allProjects {
148+
boxes, err = multi.Open(devboxOpts)
149+
if err != nil {
150+
return errors.WithStack(err)
151+
}
152+
} else {
153+
box, err := devbox.Open(devboxOpts)
154+
if err != nil {
155+
return redact.Errorf("error reading devbox.json: %w", err)
156+
}
157+
boxes = append(boxes, box)
124158
}
125159

126160
envOpts := devopt.EnvOptions{
@@ -140,8 +174,23 @@ func runScriptCmd(cmd *cobra.Command, args []string, flags runCmdFlags) error {
140174
Pure: flags.pure,
141175
SkipRecompute: !flags.recomputeEnv,
142176
}
143-
if err := box.RunScript(ctx, envOpts, script, scriptArgs); err != nil {
144-
return redact.Errorf("error running script %q in Devbox: %w", script, err)
177+
178+
if flags.allProjects {
179+
boxes = lo.Filter(boxes, func(box *devbox.Devbox, _ int) bool {
180+
return slices.Contains(box.ListScripts(), script)
181+
})
182+
}
183+
184+
for _, box := range boxes {
185+
ux.Finfof(
186+
cmd.ErrOrStderr(),
187+
"Running script %q on %s\n",
188+
script,
189+
box.ProjectDir(),
190+
)
191+
if err := box.RunScript(ctx, envOpts, script, scriptArgs); err != nil {
192+
return redact.Errorf("error running script %q in Devbox: %w", script, err)
193+
}
145194
}
146195
return nil
147196
}

internal/devbox/devbox.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,9 @@ func Open(opts *devopt.Opts) (*Devbox, error) {
165165
}
166166
ux.Fwarningf(
167167
os.Stderr, // Always stderr. box.writer should probably always be err.
168-
"Your devbox.json contains packages in legacy format. "+
168+
"Your devbox.json at %s contains packages in legacy format. "+
169169
"Please run `devbox %supdate` to update your devbox.json.\n",
170+
box.projectDir,
170171
lo.Ternary(box.projectDir == globalPath, "global ", ""),
171172
)
172173
}

0 commit comments

Comments
 (0)