Skip to content

Commit 15ccb87

Browse files
committed
Revert Path to string and convert path list to watch config list
Signed-off-by: Joana Hrotkó <[email protected]>
1 parent a66c385 commit 15ccb87

File tree

7 files changed

+96
-121
lines changed

7 files changed

+96
-121
lines changed

loader/loader_test.go

+7-39
Original file line numberDiff line numberDiff line change
@@ -3096,7 +3096,7 @@ services:
30963096
assert.DeepEqual(t, *frontend.Develop, types.DevelopConfig{
30973097
Watch: []types.Trigger{
30983098
{
3099-
Path: []string{"./webapp/html"},
3099+
Path: "./webapp/html",
31003100
Action: types.WatchActionSync,
31013101
Target: "/var/www",
31023102
Ignore: []string{"node_modules/"},
@@ -3111,7 +3111,11 @@ services:
31113111
assert.DeepEqual(t, *backend.Develop, types.DevelopConfig{
31123112
Watch: []types.Trigger{
31133113
{
3114-
Path: []string{"./backend/src", "./backend"},
3114+
Path: "./backend/src",
3115+
Action: types.WatchActionRebuild,
3116+
},
3117+
{
3118+
Path: "./backend",
31153119
Action: types.WatchActionRebuild,
31163120
},
31173121
},
@@ -3121,7 +3125,7 @@ services:
31213125
assert.DeepEqual(t, *proxy.Develop, types.DevelopConfig{
31223126
Watch: []types.Trigger{
31233127
{
3124-
Path: []string{"./proxy/proxy.conf"},
3128+
Path: "./proxy/proxy.conf",
31253129
Action: types.WatchActionSyncRestart,
31263130
Target: "/etc/nginx/proxy.conf",
31273131
},
@@ -3148,42 +3152,6 @@ services:
31483152
})
31493153
assert.ErrorContains(t, err, "validating filename0.yml: services.frontend.develop.watch.0 action is required")
31503154
})
3151-
3152-
t.Run("should return an error when cannot resolve path", func(t *testing.T) {
3153-
b, err := os.ReadFile("testdata/watch/compose-test-watch-star.yaml")
3154-
assert.NilError(t, err)
3155-
3156-
configDetails := types.ConfigDetails{
3157-
WorkingDir: "testdata",
3158-
ConfigFiles: []types.ConfigFile{
3159-
{Filename: "watch/compose-test-watch-star.yaml", Content: b},
3160-
},
3161-
Environment: map[string]string{},
3162-
}
3163-
expServices := types.Services{
3164-
"app": {
3165-
Name: "app",
3166-
Image: "example/app",
3167-
Environment: types.MappingWithEquals{},
3168-
Networks: map[string]*types.ServiceNetworkConfig{"default": nil},
3169-
Develop: &types.DevelopConfig{
3170-
Watch: []types.Trigger{
3171-
{
3172-
Path: []string{
3173-
filepath.FromSlash("testdata/watch/other.txt"),
3174-
filepath.FromSlash("testdata/watch/some-text.txt"),
3175-
},
3176-
Action: types.WatchActionRebuild,
3177-
},
3178-
},
3179-
},
3180-
},
3181-
}
3182-
3183-
actual, err := LoadWithContext(context.Background(), configDetails)
3184-
assert.NilError(t, err)
3185-
assert.DeepEqual(t, actual.Services, expServices)
3186-
})
31873155
}
31883156

31893157
func TestBadServiceConfig(t *testing.T) {

loader/validate.go

-4
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,6 @@ func checkConsistency(project *types.Project) error { //nolint:gocyclo
170170
if watch.Action != types.WatchActionRebuild && watch.Action != types.WatchActionRestart {
171171
if watch.Target == "" {
172172
return fmt.Errorf("services.%s.develop.watch: target is required for %s, %s and %s actions: %w", s.Name, types.WatchActionSync, types.WatchActionSyncExec, types.WatchActionSyncRestart, errdefs.ErrInvalid)
173-
174-
}
175-
if len(watch.Path) > 1 {
176-
return fmt.Errorf("services.%s.develop.watch: detected multiple paths %s for action %s. Multiple files are only valid for %s and %s actions: %w", s.Name, watch.Path, watch.Action, types.WatchActionRebuild, types.WatchActionRestart, errdefs.ErrInvalid)
177173
}
178174
}
179175
}

loader/validate_test.go

+5-27
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ func TestValidateWatch(t *testing.T) {
292292
Watch: []types.Trigger{
293293
{
294294
Action: types.WatchActionSync,
295-
Path: []string{"/app"},
295+
Path: "/app",
296296
Target: "/container/app",
297297
},
298298
},
@@ -364,7 +364,7 @@ func TestValidateWatch(t *testing.T) {
364364
Watch: []types.Trigger{
365365
{
366366
Action: tt.action,
367-
Path: []string{"/app"},
367+
Path: "/app",
368368
// Missing Target
369369
},
370370
},
@@ -375,28 +375,6 @@ func TestValidateWatch(t *testing.T) {
375375
err := checkConsistency(&project)
376376
assert.Error(t, err, "services.myservice.develop.watch: target is required for sync, sync+exec and sync+restart actions: invalid compose project")
377377
})
378-
379-
t.Run(fmt.Sprintf("watch config is INVALID with one or more paths for %s action", tt.action), func(t *testing.T) {
380-
project := types.Project{
381-
Services: types.Services{
382-
"myservice": {
383-
Name: "myservice",
384-
Image: "scratch",
385-
Develop: &types.DevelopConfig{
386-
Watch: []types.Trigger{
387-
{
388-
Action: tt.action,
389-
Path: []string{"/app", "/app2"}, // should only be one path
390-
Target: "/container/app",
391-
},
392-
},
393-
},
394-
},
395-
},
396-
}
397-
err := checkConsistency(&project)
398-
assert.ErrorContains(t, err, "services.myservice.develop.watch: detected multiple paths")
399-
})
400378
}
401379
tests = []WatchActionTest{
402380
{action: types.WatchActionRebuild},
@@ -413,7 +391,7 @@ func TestValidateWatch(t *testing.T) {
413391
Watch: []types.Trigger{
414392
{
415393
Action: tt.action,
416-
Path: []string{"/app"},
394+
Path: "/app",
417395
},
418396
},
419397
},
@@ -434,11 +412,11 @@ func TestValidateWatch(t *testing.T) {
434412
Watch: []types.Trigger{
435413
{
436414
Action: tt.action,
437-
Path: []string{"/app"},
415+
Path: "/app",
438416
},
439417
{
440418
Action: tt.action,
441-
Path: []string{"/app", "/app2"},
419+
Path: "/app2",
442420
},
443421
},
444422
},

paths/unix.go

+4-37
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package paths
1818

1919
import (
20-
"fmt"
2120
"path"
2221
"path/filepath"
2322

@@ -50,41 +49,9 @@ func (r *relativePathsResolver) absSymbolicLink(value any) (any, error) {
5049
if err != nil {
5150
return nil, err
5251
}
53-
switch t := abs.(type) {
54-
case string:
55-
// this can return []string if * matches more than one file
56-
return resolveAbsStarPath(t)
57-
case []any:
58-
var res []any
59-
for _, tt := range t {
60-
s, _ := tt.(string)
61-
r, err := resolveAbsStarPath(s)
62-
if err != nil {
63-
return nil, err
64-
}
65-
res = append(res, r...)
66-
}
67-
return res, nil
68-
}
69-
70-
return abs, nil
71-
}
72-
73-
func resolveAbsStarPath(t string) ([]any, error) {
74-
matches, err := filepath.Glob(t)
75-
if err != nil {
76-
return nil, err
77-
}
78-
if len(matches) == 0 {
79-
return nil, fmt.Errorf("could not resolve %s. Please make sure it exists?", t)
80-
}
81-
res := make([]any, len(matches))
82-
for i, m := range matches {
83-
symb, err := utils.ResolveSymbolicLink(m)
84-
if err != nil {
85-
return nil, err
86-
}
87-
res[i] = symb
52+
str, ok := abs.(string)
53+
if !ok {
54+
return abs, nil
8855
}
89-
return res, nil
56+
return utils.ResolveSymbolicLink(str)
9057
}

transform/canonical.go

+46-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func init() {
3636
transformers["services.*.networks"] = transformServiceNetworks
3737
transformers["services.*.volumes.*"] = transformVolumeMount
3838
transformers["services.*.dns"] = transformStringOrList
39-
transformers["services.*.develop.watch.*.path"] = transformStringOrList
39+
transformers["services.*.develop.watch"] = transformWatch
4040
transformers["services.*.devices.*"] = transformDeviceMapping
4141
transformers["services.*.secrets.*"] = transformFileMount
4242
transformers["services.*.configs.*"] = transformFileMount
@@ -52,6 +52,51 @@ func init() {
5252
transformers["include.*"] = transformInclude
5353
}
5454

55+
func transformWatch(data any, _ tree.Path, _ bool) (any, error) {
56+
t, ok := data.([]interface{})
57+
if !ok {
58+
return data, nil
59+
}
60+
61+
for i, w := range t {
62+
watchConf, ok := w.(map[string]interface{})
63+
if !ok {
64+
continue
65+
}
66+
path, ok := watchConf["path"]
67+
if !ok {
68+
// This should not happen
69+
continue
70+
}
71+
paths, ok := path.([]interface{})
72+
if !ok {
73+
// if path is a string there is nothing to do
74+
continue
75+
}
76+
77+
// remove the current path that is a list
78+
if i == len(t)-1 {
79+
t = t[:i]
80+
} else {
81+
t = append(t[:i], t[i+1:])
82+
}
83+
84+
// transform each element into a watch item
85+
for _, p := range paths {
86+
extend := make(map[string]interface{})
87+
for k, v := range watchConf {
88+
if k == "path" {
89+
extend[k] = p
90+
continue
91+
}
92+
extend[k] = v
93+
}
94+
t = append(t, extend)
95+
}
96+
}
97+
return t, nil
98+
}
99+
55100
func transformStringOrList(data any, _ tree.Path, _ bool) (any, error) {
56101
switch t := data.(type) {
57102
case string:

types/develop.go

+30-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616

1717
package types
1818

19+
import (
20+
"path/filepath"
21+
"strings"
22+
)
23+
1924
type DevelopConfig struct {
2025
Watch []Trigger `yaml:"watch,omitempty" json:"watch,omitempty"`
2126

@@ -33,10 +38,34 @@ const (
3338
)
3439

3540
type Trigger struct {
36-
Path StringList `yaml:"path" json:"path"`
41+
Path string `yaml:"path" json:"path"`
3742
Action WatchAction `yaml:"action" json:"action"`
3843
Target string `yaml:"target,omitempty" json:"target,omitempty"`
3944
Exec ServiceHook `yaml:"exec,omitempty" json:"exec,omitempty"`
4045
Ignore []string `yaml:"ignore,omitempty" json:"ignore,omitempty"`
4146
Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
4247
}
48+
49+
func (t Trigger) AnchorPath() string {
50+
if t.IsGlobPath() {
51+
pathList := strings.Split(filepath.FromSlash(t.Path), "/")
52+
path := []string{}
53+
54+
for _, a := range pathList {
55+
if strings.Contains(a, "*") {
56+
break
57+
}
58+
path = append(path, a)
59+
}
60+
return strings.Join(path, string(filepath.Separator))
61+
}
62+
return t.Path
63+
}
64+
65+
func (t Trigger) IsGlobPath() bool {
66+
return strings.Contains(t.Path, "*")
67+
}
68+
69+
func (t Trigger) IsSyncAction() bool {
70+
return t.Action == WatchActionSync || t.Action == WatchActionSyncRestart
71+
}

validation/validation.go

+4-12
Original file line numberDiff line numberDiff line change
@@ -89,19 +89,11 @@ func checkFileObject(keys ...string) checkerFunc {
8989
}
9090

9191
func checkPath(value any, p tree.Path) error {
92-
switch v := value.(type) {
93-
case string:
94-
if v == "" {
95-
return fmt.Errorf("%s: value can't be blank", p)
96-
}
97-
case []interface{}:
98-
for _, el := range v {
99-
e := el.(string)
100-
if e == "" {
101-
return fmt.Errorf("%s: value in paths can't be blank", e)
102-
}
103-
}
92+
v := value.(string)
93+
if v == "" {
94+
return fmt.Errorf("%s: value can't be blank", p)
10495
}
96+
10597
return nil
10698
}
10799

0 commit comments

Comments
 (0)