Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduced include to filter files considered by watch #12584

Merged
merged 2 commits into from
Mar 3, 2025
Merged
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ require (
github.com/Microsoft/go-winio v0.6.2
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/buger/goterm v1.0.4
github.com/compose-spec/compose-go/v2 v2.4.9-0.20250225151507-331db8fefcb7
github.com/compose-spec/compose-go/v2 v2.4.9-0.20250302154753-e508c724a35f
github.com/containerd/containerd/v2 v2.0.2
github.com/containerd/platforms v1.0.0-rc.1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -81,8 +81,8 @@ github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
github.com/compose-spec/compose-go/v2 v2.4.9-0.20250225151507-331db8fefcb7 h1:7NlxAsQcWvLpFlEHsBo80sJ1UMMs84kkf0yXGs6de2k=
github.com/compose-spec/compose-go/v2 v2.4.9-0.20250225151507-331db8fefcb7/go.mod h1:6k5l/0TxCg0/2uLEhRVEsoBWBprS2uvZi32J7xub3lo=
github.com/compose-spec/compose-go/v2 v2.4.9-0.20250302154753-e508c724a35f h1:kbmTPhf7d9kTnmH0ghAQTqxs1zenKnwKczJlC4z5WSc=
github.com/compose-spec/compose-go/v2 v2.4.9-0.20250302154753-e508c724a35f/go.mod h1:6k5l/0TxCg0/2uLEhRVEsoBWBprS2uvZi32J7xub3lo=
github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
21 changes: 21 additions & 0 deletions pkg/compose/watch.go
Original file line number Diff line number Diff line change
@@ -81,6 +81,7 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv

type watchRule struct {
types.Trigger
include watch.PathMatcher
ignore watch.PathMatcher
service string
}
@@ -90,6 +91,15 @@ func (r watchRule) Matches(event watch.FileEvent) *sync.PathMapping {
if !pathutil.IsChild(r.Path, hostPath) {
return nil
}
included, err := r.include.Matches(hostPath)
if err != nil {
logrus.Warnf("error include matching %q: %v", hostPath, err)
return nil
}
if !included {
logrus.Debugf("%s is not matching include pattern", hostPath)
return nil
}
isIgnored, err := r.ignore.Matches(hostPath)
if err != nil {
logrus.Warnf("error ignore matching %q: %v", hostPath, err)
@@ -244,8 +254,19 @@ func getWatchRules(config *types.DevelopConfig, service types.ServiceConfig) ([]
return nil, err
}

var include watch.PathMatcher
if len(trigger.Include) == 0 {
include = watch.AnyMatcher{}
} else {
include, err = watch.NewDockerPatternMatcher(trigger.Path, trigger.Include)
if err != nil {
return nil, err
}
}

rules = append(rules, watchRule{
Trigger: trigger,
include: include,
ignore: watch.NewCompositeMatcher(
dockerIgnores,
watch.EphemeralPathMatcher(),
12 changes: 12 additions & 0 deletions pkg/e2e/fixtures/watch/include.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
services:
a:
build:
dockerfile_inline: |
FROM nginx
RUN mkdir /data/
develop:
watch:
- path: .
include: A.*
target: /data/
action: sync
37 changes: 37 additions & 0 deletions pkg/e2e/watch_test.go
Original file line number Diff line number Diff line change
@@ -368,3 +368,40 @@ func TestWatchMultiServices(t *testing.T) {

c.RunDockerComposeCmdNoCheck(t, "-p", projectName, "kill", "-s", "9")
}

func TestWatchIncludes(t *testing.T) {
c := NewCLI(t)
const projectName = "test_watch_includes"

defer c.cleanupWithDown(t, projectName)

tmpdir := t.TempDir()
composeFilePath := filepath.Join(tmpdir, "compose.yaml")
CopyFile(t, filepath.Join("fixtures", "watch", "include.yaml"), composeFilePath)

cmd := c.NewDockerComposeCmd(t, "-p", projectName, "-f", composeFilePath, "up", "--watch")
buffer := bytes.NewBuffer(nil)
cmd.Stdout = buffer
watch := icmd.StartCmd(cmd)

poll.WaitOn(t, func(l poll.LogT) poll.Result {
if strings.Contains(watch.Stdout(), "Attaching to ") {
return poll.Success()
}
return poll.Continue("%v", watch.Stdout())
})

require.NoError(t, os.WriteFile(filepath.Join(tmpdir, "B.test"), []byte("test"), 0o600))
require.NoError(t, os.WriteFile(filepath.Join(tmpdir, "A.test"), []byte("test"), 0o600))

poll.WaitOn(t, func(l poll.LogT) poll.Result {
cat := c.RunDockerComposeCmdNoCheck(t, "-p", projectName, "exec", "a", "ls", "/data/")
if strings.Contains(cat.Stdout(), "A.test") {
assert.Check(t, !strings.Contains(cat.Stdout(), "B.test"))
return poll.Success()
}
return poll.Continue("%v", cat.Combined())
})

c.RunDockerComposeCmdNoCheck(t, "-p", projectName, "kill", "-s", "9")
}
9 changes: 9 additions & 0 deletions pkg/watch/notify.go
Original file line number Diff line number Diff line change
@@ -68,6 +68,15 @@ type PathMatcher interface {
MatchesEntireDir(file string) (bool, error)
}

// AnyMatcher is a PathMatcher to match any path
type AnyMatcher struct{}

func (AnyMatcher) Matches(f string) (bool, error) { return true, nil }
func (AnyMatcher) MatchesEntireDir(f string) (bool, error) { return true, nil }

var _ PathMatcher = AnyMatcher{}

// EmptyMatcher is a PathMatcher to match no path
type EmptyMatcher struct{}

func (EmptyMatcher) Matches(f string) (bool, error) { return false, nil }
Loading
Oops, something went wrong.