fix(scale, run): resolve DOCKER_DEFAULT_PLATFORM like up does

scale and run were the only container-creating commands that never
called applyPlatforms, yet both go through the regular create path and
its config-hash comparison (run for the dependencies it starts). With
DOCKER_DEFAULT_PLATFORM set, they hashed an empty service Platform where
up had hashed the resolved one, so every invocation recreated the
affected containers. run's project preparation is extracted to a helper
to keep runCommand under the complexity threshold.

No unit test: neither command has a test harness and the fix is the one
missing call, aligned on create/watch; the config-hash equality is
covered by the reconciler tests.

Signed-off-by: Guillaume Lours <glours@users.noreply.github.com>
This commit is contained in:
Guillaume Lours 2026-08-06 16:36:52 +02:00 • committed by Guillaume Lours
parent a9d054fb17
commit 4b7f6149eb
2 changed files with 29 additions and 6 deletions

View file

@ -204,12 +204,7 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backen
return err
}
project, _, err := p.ToProject(ctx, dockerCli, backend, []string{options.Service}, composecli.WithoutEnvironmentResolution)
if err != nil {
return err
}
project, err = project.WithServicesEnvironmentResolved(true)
project, err := runProject(ctx, dockerCli, backend, p, options.Service)
if err != nil {
return err
}
@ -269,6 +264,27 @@ func normalizeRunFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(name)
}
// runProject loads and prepares the project for a one-off run: environment
// resolved after service selection (so env_file of unrelated services doesn't
// need to exist) and DOCKER_DEFAULT_PLATFORM resolved into service.Platform
// exactly like `up`/`create` do — Platform feeds the config-hash of the
// dependencies started by run, so hashing a different value would recreate
// their containers.
func runProject(ctx context.Context, dockerCli command.Cli, backend api.Compose, p *ProjectOptions, service string) (*types.Project, error) {
project, _, err := p.ToProject(ctx, dockerCli, backend, []string{service}, composecli.WithoutEnvironmentResolution)
if err != nil {
return nil, err
}
project, err = project.WithServicesEnvironmentResolved(true)
if err != nil {
return nil, err
}
if err := applyPlatforms(project, true); err != nil {
return nil, err
}
return project, nil
}
func runRun(ctx context.Context, backend api.Compose, project *types.Project, options runOptions, createOpts createOptions, buildOpts buildOptions, dockerCli command.Cli) error {
project, err := options.apply(project)
if err != nil {

View file

@ -80,6 +80,13 @@ func runScale(ctx context.Context, dockerCli command.Cli, backendOptions *Backen
return err
}
// resolve DOCKER_DEFAULT_PLATFORM into service.Platform exactly like
// `up`/`create` do: Platform feeds the service config-hash, so scale
// hashing a different value would recreate every container
if err := applyPlatforms(project, true); err != nil {
return err
}
if opts.noDeps {
if project, err = project.WithSelectedServices(services, types.IgnoreDependencies); err != nil {
return err