Skip to content

Commit 02f3efe

Browse files
committed
feat: merge all the .docker/runx.yaml files
Merge all the .docker/runx.yaml files we found from the current directory up to the root. Allow to define options for all the actions. Signed-off-by: Yves Brissaud <[email protected]>
1 parent aa97885 commit 02f3efe

File tree

5 files changed

+104
-7
lines changed

5 files changed

+104
-7
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ actions:
159159
- name: OPTION_NAME # Name of the option. Also used in the local override or with `--opt` flag.
160160
desc: DESCRIPTION # Description, rendered in the documentation of the action.
161161
prompt: PROMPT # A specific prompt to ask the user for the value.
162+
no-prompt: true|false # If set to true, the option will not be prompted to the user.
162163
required: true|false # If required, an empty value will not be accepted.
163164
values: # A list of possible values for the option. If set, a select will be displayed to the user.
164165
- VALUE
@@ -183,6 +184,8 @@ actions:
183184
A local file `.docker/runx.yaml` can be used to override the actions defined in the image manifest.
184185
This is useful to configure some actions for a specific project for instance.
185186

187+
`docker runx` will look for this file in the current directory and in all the parent directories. The different files will be merged together, the closer to the current directory will have the priority.
188+
186189
```yaml
187190
# Optional.
188191
# It allows to define a default reference to an image if none is provided by the user.
@@ -198,6 +201,12 @@ images:
198201
# This overrides the `default` action in the image `runx.yaml` configuration.
199202
default: ACTION_ID
200203
# Optional.
204+
# Allow to define common options for all the actions of the image.
205+
all-actions:
206+
opts:
207+
# Override the value of an option.
208+
OPTION_NAME: OPTION_VALUE
209+
# Optional.
201210
actions:
202211
# Specify the action to override.
203212
ACTION_ID:

docs/index.markdown

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ actions:
163163
- name: OPTION_NAME # Name of the option. Also used in the local override or with `--opt` flag.
164164
desc: DESCRIPTION # Description, rendered in the documentation of the action.
165165
prompt: PROMPT # A specific prompt to ask the user for the value.
166+
no-prompt: true|false # If set to true, the option will not be prompted to the user.
166167
required: true|false # If required, an empty value will not be accepted.
167168
values: # A list of possible values for the option. If set, a select will be displayed to the user.
168169
- VALUE
@@ -187,6 +188,8 @@ actions:
187188
A local file `.docker/runx.yaml` can be used to override the actions defined in the image manifest.
188189
This is useful to configure some actions for a specific project for instance.
189190

191+
`docker runx` will look for this file in the current directory and in all the parent directories. The different files will be merged together, the closer to the current directory will have the priority.
192+
190193
```yaml
191194
# Optional.
192195
# It allows to define a default reference to an image if none is provided by the user.
@@ -202,6 +205,12 @@ images:
202205
# This overrides the `default` action in the image `runx.yaml` configuration.
203206
default: ACTION_ID
204207
# Optional.
208+
# Allow to define common options for all the actions of the image.
209+
all-actions:
210+
opts:
211+
# Override the value of an option.
212+
OPTION_NAME: OPTION_VALUE
213+
# Optional.
205214
actions:
206215
# Specify the action to override.
207216
ACTION_ID:

internal/commands/root/root.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,18 @@ func getValuesLocal(src, action string) map[string]string {
173173
if !ok {
174174
return localOpts
175175
}
176+
177+
if img.AllActions.Opts != nil {
178+
localOpts = img.AllActions.Opts
179+
}
180+
176181
act, ok := img.Actions[action]
177-
if !ok {
178-
return localOpts
182+
if ok {
183+
for k, v := range act.Opts {
184+
localOpts[k] = v
185+
}
179186
}
180-
return act.Opts
187+
return localOpts
181188
}
182189

183190
func run(ctx context.Context, out io.Writer, src string, rk *runkit.RunKit, action string) error {

runkit/config.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package runkit
22

33
import (
4+
"cmp"
45
"errors"
56
"fmt"
67
"os"
8+
"path/filepath"
79
"sync"
810

911
"gopkg.in/yaml.v2"
@@ -31,7 +33,76 @@ func GetLocalConfig() LocalConfig {
3133
}
3234

3335
func getLocalConfig() (LocalConfig, error) {
34-
data, err := os.ReadFile(DefaultLocalConfigFile)
36+
lc := LocalConfig{}
37+
38+
wd, err := os.Getwd()
39+
if err != nil {
40+
return lc, err
41+
}
42+
43+
p := wd
44+
45+
for {
46+
c, err := read(filepath.Join(p, DefaultLocalConfigFile))
47+
if err != nil {
48+
return lc, err
49+
}
50+
51+
lc = merge(c, lc)
52+
53+
if p == "/" {
54+
break
55+
}
56+
57+
p = filepath.Clean(filepath.Join(p, ".."))
58+
}
59+
60+
return lc, nil
61+
}
62+
63+
func merge(a, b LocalConfig) LocalConfig {
64+
a.Ref = cmp.Or(b.Ref, a.Ref)
65+
if a.Images == nil {
66+
a.Images = b.Images
67+
return a
68+
}
69+
for imgName, img := range b.Images {
70+
i, ok := a.Images[imgName]
71+
if !ok {
72+
a.Images[imgName] = img
73+
continue
74+
}
75+
i.Default = cmp.Or(img.Default, i.Default)
76+
i.AllActions.Opts = mergeOpts(i.AllActions.Opts, img.AllActions.Opts)
77+
i.Actions = mergeActions(i.Actions, img.Actions)
78+
a.Images[imgName] = i
79+
}
80+
81+
return a
82+
}
83+
84+
func mergeOpts(a, b map[string]string) map[string]string {
85+
for k, v := range b {
86+
a[k] = v
87+
}
88+
return a
89+
}
90+
91+
func mergeActions(a, b map[string]ConfigAction) map[string]ConfigAction {
92+
for k, v := range b {
93+
actA, ok := a[k]
94+
if !ok {
95+
a[k] = v
96+
continue
97+
}
98+
actA.Opts = mergeOpts(actA.Opts, v.Opts)
99+
a[k] = actA
100+
}
101+
return a
102+
}
103+
104+
func read(filePath string) (LocalConfig, error) {
105+
data, err := os.ReadFile(filePath)
35106
if err != nil {
36107
if errors.Is(err, os.ErrNotExist) {
37108
// in this case we just don't have a config file, so use everything as default

runkit/types.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ type (
3030
Opt struct {
3131
Name string `yaml:"name" json:"name"`
3232
Description string `yaml:"desc" json:"desc,omitempty"`
33-
NoPrompt bool `yaml:"no-prompt,omitempty" json:"no_prompt,omitempty"`
33+
NoPrompt bool `yaml:"no-prompt,omitempty" json:"no-prompt,omitempty"`
3434
Prompt string `yaml:"prompt,omitempty" json:"prompt,omitempty"`
3535
Required bool `yaml:"required,omitempty" json:"required,omitempty"`
3636
Values []string `yaml:"values,omitempty" json:"values,omitempty"`
@@ -44,8 +44,9 @@ type (
4444
}
4545

4646
ConfigImage struct {
47-
Default string `yaml:"default,omitempty" json:"default,omitempty"`
48-
Actions map[string]ConfigAction `yaml:"actions,omitempty" json:"actions,omitempty"`
47+
Default string `yaml:"default,omitempty" json:"default,omitempty"`
48+
AllActions ConfigAction `yaml:"all-actions,omitempty" json:"all-actions,omitempty"`
49+
Actions map[string]ConfigAction `yaml:"actions,omitempty" json:"actions,omitempty"`
4950
}
5051

5152
ConfigAction struct {

0 commit comments

Comments
 (0)