Skip to content
Merged
Show file tree
Hide file tree
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: 2 additions & 0 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ type CreateOptions struct {
Timeout *time.Duration
// QuietPull makes the pulling process quiet
QuietPull bool
// SkipProviders skips provider services during convergence (e.g. watch rebuild)
SkipProviders bool
}

// StartOptions group options of the Start API
Expand Down
6 changes: 6 additions & 0 deletions pkg/compose/convergence.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ func (c *convergence) apply(ctx context.Context, project *types.Project, options
return err
}

// Skip provider services when the caller opted out (e.g. watch rebuild),
// since providers were already set up during initial "up".
if service.Provider != nil && options.SkipProviders {
return nil
}
Comment on lines +103 to +107
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New SkipProviders behavior is introduced here, but there doesn’t appear to be any test exercising convergence when provider services are present and SkipProviders is true. Given how central convergence is, adding a unit test that asserts provider services are not invoked (and dependent services still converge) would help prevent regressions.

Copilot uses AI. Check for mistakes.

return tracing.SpanWrapFunc("service/apply", tracing.ServiceOptions(service), func(ctx context.Context) error {
strategy := options.RecreateDependencies
if slices.Contains(options.Services, name) {
Expand Down
13 changes: 11 additions & 2 deletions pkg/compose/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ func (s *composeService) executePlugin(cmd *exec.Cmd, command string, service ty
}
switch msg.Type {
case ErrorType:
s.events.On(newEvent(service.Name, api.Error, msg.Message))
s.events.On(newEvent(service.Name, api.Error, firstLine(msg.Message)))
return nil, errors.New(msg.Message)
case InfoType:
s.events.On(newEvent(service.Name, api.Working, msg.Message))
s.events.On(newEvent(service.Name, api.Working, firstLine(msg.Message)))
case SetEnvType:
key, val, found := strings.Cut(msg.Message, "=")
if !found {
Expand Down Expand Up @@ -281,3 +281,12 @@ func (c CommandMetadata) CheckRequiredParameters(provider types.ServiceProviderC
}
return nil
}

// firstLine returns the first line of s, stripping any trailing newlines.
func firstLine(s string) string {
s = strings.TrimRight(s, "\n")
if i := strings.IndexByte(s, '\n'); i >= 0 {
return s[:i]
Comment on lines +287 to +289
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

firstLine only trims \n, so CRLF messages ("\r\n") will leave a trailing \r in the returned first line. That can still interfere with TTY cursor control and makes the doc comment (“stripping any trailing newlines”) inaccurate on Windows. Consider trimming "\r\n" and/or explicitly stripping a trailing \r from the first line segment.

Suggested change
s = strings.TrimRight(s, "\n")
if i := strings.IndexByte(s, '\n'); i >= 0 {
return s[:i]
s = strings.TrimRight(s, "\r\n")
if i := strings.IndexByte(s, '\n'); i >= 0 {
return strings.TrimRight(s[:i], "\r")

Copilot uses AI. Check for mistakes.
}
return s
}
7 changes: 4 additions & 3 deletions pkg/compose/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -662,9 +662,10 @@ func (s *composeService) rebuild(ctx context.Context, project *types.Project, se
options.LogTo.Log(api.WatchLogger, fmt.Sprintf("service(s) %q successfully built", services))

err = s.create(ctx, project, api.CreateOptions{
Services: services,
Inherit: true,
Recreate: api.RecreateForce,
Services: services,
Inherit: true,
Recreate: api.RecreateForce,
SkipProviders: true,
})
if err != nil {
options.LogTo.Log(api.WatchLogger, fmt.Sprintf("Failed to recreate services after update. Error: %v", err))
Expand Down
Loading