Merge pull request #10173 from glours/dry-run

Skeleton for dry-run under alpha command
This commit is contained in:
Guillaume Lours 2023-01-20 15:37:52 +01:00 committed by GitHub
commit d5d9f67547
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 651 additions and 6 deletions

View File

@ -15,6 +15,8 @@
package compose
import (
"context"
"github.com/docker/compose/v2/pkg/api"
"github.com/spf13/cobra"
)
@ -29,6 +31,27 @@ func alphaCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
"experimentalCLI": "true",
},
}
cmd.AddCommand(watchCommand(p, backend))
cmd.AddCommand(
watchCommand(p, backend),
dryRunRedirectCommand(p),
)
return cmd
}
// Temporary alpha command as the dry-run will be implemented with a flag
func dryRunRedirectCommand(p *ProjectOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "dry-run -- [COMMAND...]",
Short: "EXPERIMENTAL - Dry run command allow you to test a command without applying changes",
PreRunE: Adapt(func(ctx context.Context, args []string) error {
return nil
}),
RunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
rootCmd := cmd.Root()
rootCmd.SetArgs(append([]string{"compose", "--dry-run"}, args...))
return rootCmd.Execute()
}),
ValidArgsFunction: completeServiceNames(p),
}
return cmd
}

View File

@ -26,6 +26,8 @@ import (
"strings"
"syscall"
"github.com/docker/cli/cli/command"
"github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/types"
composegoutils "github.com/compose-spec/compose-go/utils"
@ -243,7 +245,7 @@ func RunningAsStandalone() bool {
}
// RootCommand returns the compose command with its child commands
func RootCommand(streams api.Streams, backend api.Service) *cobra.Command { //nolint:gocyclo
func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //nolint:gocyclo
// filter out useless commandConn.CloseWrite warning message that can occur
// when using a remote context that is unreachable: "commandConn.CloseWrite: commandconn: failed to wait: signal: killed"
// https://github.com/docker/cli/blob/e1f24d3c93df6752d3c27c8d61d18260f141310c/cli/connhelper/commandconn/commandconn.go#L203-L215
@ -261,6 +263,7 @@ func RootCommand(streams api.Streams, backend api.Service) *cobra.Command { //no
verbose bool
version bool
parallel int
dryRun bool
)
c := &cobra.Command{
Short: "Docker Compose",
@ -335,7 +338,7 @@ func RootCommand(streams api.Streams, backend api.Service) *cobra.Command { //no
if parallel > 0 {
backend.MaxConcurrency(parallel)
}
return nil
return backend.DryRunMode(dryRun)
},
}
@ -389,6 +392,8 @@ func RootCommand(streams api.Streams, backend api.Service) *cobra.Command { //no
c.Flags().MarkHidden("no-ansi") //nolint:errcheck
c.Flags().BoolVar(&verbose, "verbose", false, "Show more output")
c.Flags().MarkHidden("verbose") //nolint:errcheck
c.Flags().BoolVar(&dryRun, "dry-run", false, "Execute command in dry run mode")
c.Flags().MarkHidden("dry-run") //nolint:errcheck
return c
}

View File

@ -6,7 +6,8 @@ Experimental commands
### Subcommands
| Name | Description |
|:----------------------------------|:-----------------------------------------------------------------------------------------------------|
|:--------------------------------------|:-----------------------------------------------------------------------------------------------------|
| [`dry-run`](compose_alpha_dry-run.md) | EXPERIMENTAL - Dry run command allow you to test a command without applying changes |
| [`watch`](compose_alpha_watch.md) | EXPERIMENTAL - Watch build context for service and rebuild/refresh containers when files are updated |

View File

@ -0,0 +1,8 @@
# docker compose alpha dry-run
<!---MARKER_GEN_START-->
EXPERIMENTAL - Dry run command allow you to test a command without applying changes
<!---MARKER_GEN_END-->

View File

@ -178,6 +178,16 @@ options:
experimentalcli: false
kubernetes: false
swarm: false
- option: dry-run
value_type: bool
default_value: "false"
description: Execute command in dry run mode
deprecated: false
hidden: true
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
- option: env-file
value_type: string
description: Specify an alternate environment file.

View File

@ -4,8 +4,10 @@ long: Experimental commands
pname: docker compose
plink: docker_compose.yaml
cname:
- docker compose alpha dry-run
- docker compose alpha watch
clink:
- docker_compose_alpha_dry-run.yaml
- docker_compose_alpha_watch.yaml
deprecated: false
experimental: false

View File

@ -0,0 +1,14 @@
command: docker compose alpha dry-run
short: |
EXPERIMENTAL - Dry run command allow you to test a command without applying changes
long: |
EXPERIMENTAL - Dry run command allow you to test a command without applying changes
usage: docker compose alpha dry-run -- [COMMAND...]
pname: docker compose alpha
plink: docker_compose_alpha.yaml
deprecated: false
experimental: false
experimentalcli: true
kubernetes: false
swarm: false

View File

@ -77,6 +77,8 @@ type Service interface {
Images(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
// MaxConcurrency defines upper limit for concurrent operations against engine API
MaxConcurrency(parallel int)
// DryRunMode defines if dry run applies to the command
DryRunMode(dryRun bool) error
// Watch services' development context and sync/notify/rebuild/restart on changes
Watch(ctx context.Context, project *types.Project, services []string, options WatchOptions) error
}

539
pkg/api/dryrunclient.go Normal file
View File

@ -0,0 +1,539 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
import (
"context"
"io"
"net"
"net/http"
moby "github.com/docker/docker/api/types"
containerType "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
specs "github.com/opencontainers/image-spec/specs-go/v1"
)
var _ client.APIClient = &DryRunClient{}
// DryRunClient implements APIClient by delegating to implementation functions. This allows lazy init and per-method overrides
type DryRunClient struct {
apiClient client.APIClient
}
// NewDryRunClient produces a DryRunClient
func NewDryRunClient(apiClient client.APIClient) *DryRunClient {
return &DryRunClient{
apiClient: apiClient,
}
}
// All methods and functions which need to be overridden for dry run.
func (d *DryRunClient) ContainerAttach(ctx context.Context, container string, options moby.ContainerAttachOptions) (moby.HijackedResponse, error) {
return moby.HijackedResponse{}, ErrNotImplemented
}
func (d *DryRunClient) ContainerCreate(ctx context.Context, config *containerType.Config, hostConfig *containerType.HostConfig,
networkingConfig *network.NetworkingConfig, platform *specs.Platform, containerName string) (containerType.CreateResponse, error) {
return containerType.CreateResponse{}, ErrNotImplemented
}
func (d *DryRunClient) ContainerKill(ctx context.Context, container, signal string) error {
return ErrNotImplemented
}
func (d *DryRunClient) ContainerPause(ctx context.Context, container string) error {
return ErrNotImplemented
}
func (d *DryRunClient) ContainerRemove(ctx context.Context, container string, options moby.ContainerRemoveOptions) error {
return ErrNotImplemented
}
func (d *DryRunClient) ContainerRename(ctx context.Context, container, newContainerName string) error {
return ErrNotImplemented
}
func (d *DryRunClient) ContainerRestart(ctx context.Context, container string, options containerType.StopOptions) error {
return ErrNotImplemented
}
func (d *DryRunClient) ContainerStart(ctx context.Context, container string, options moby.ContainerStartOptions) error {
return ErrNotImplemented
}
func (d *DryRunClient) ContainerStop(ctx context.Context, container string, options containerType.StopOptions) error {
return ErrNotImplemented
}
func (d *DryRunClient) ContainerUnpause(ctx context.Context, container string) error {
return ErrNotImplemented
}
func (d *DryRunClient) CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, moby.ContainerPathStat, error) {
return nil, moby.ContainerPathStat{}, ErrNotImplemented
}
func (d *DryRunClient) CopyToContainer(ctx context.Context, container, path string, content io.Reader, options moby.CopyToContainerOptions) error {
return ErrNotImplemented
}
func (d *DryRunClient) ImageBuild(ctx context.Context, reader io.Reader, options moby.ImageBuildOptions) (moby.ImageBuildResponse, error) {
return moby.ImageBuildResponse{}, ErrNotImplemented
}
func (d *DryRunClient) ImagePull(ctx context.Context, ref string, options moby.ImagePullOptions) (io.ReadCloser, error) {
return nil, ErrNotImplemented
}
func (d *DryRunClient) ImagePush(ctx context.Context, ref string, options moby.ImagePushOptions) (io.ReadCloser, error) {
return nil, ErrNotImplemented
}
func (d *DryRunClient) ImageRemove(ctx context.Context, imageName string, options moby.ImageRemoveOptions) ([]moby.ImageDeleteResponseItem, error) {
return nil, ErrNotImplemented
}
func (d *DryRunClient) NetworkConnect(ctx context.Context, networkName, container string, config *network.EndpointSettings) error {
return ErrNotImplemented
}
func (d *DryRunClient) NetworkCreate(ctx context.Context, name string, options moby.NetworkCreate) (moby.NetworkCreateResponse, error) {
return moby.NetworkCreateResponse{}, ErrNotImplemented
}
func (d *DryRunClient) NetworkDisconnect(ctx context.Context, networkName, container string, force bool) error {
return ErrNotImplemented
}
func (d *DryRunClient) NetworkRemove(ctx context.Context, networkName string) error {
return ErrNotImplemented
}
func (d *DryRunClient) VolumeCreate(ctx context.Context, options volume.CreateOptions) (volume.Volume, error) {
return volume.Volume{}, ErrNotImplemented
}
func (d *DryRunClient) VolumeRemove(ctx context.Context, volumeID string, force bool) error {
return ErrNotImplemented
}
// Functions delegated to original APIClient (not used by Compose or not modifying the Compose stack
func (d *DryRunClient) ConfigList(ctx context.Context, options moby.ConfigListOptions) ([]swarm.Config, error) {
return d.apiClient.ConfigList(ctx, options)
}
func (d *DryRunClient) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (moby.ConfigCreateResponse, error) {
return d.apiClient.ConfigCreate(ctx, config)
}
func (d *DryRunClient) ConfigRemove(ctx context.Context, id string) error {
return d.apiClient.ConfigRemove(ctx, id)
}
func (d *DryRunClient) ConfigInspectWithRaw(ctx context.Context, name string) (swarm.Config, []byte, error) {
return d.apiClient.ConfigInspectWithRaw(ctx, name)
}
func (d *DryRunClient) ConfigUpdate(ctx context.Context, id string, version swarm.Version, config swarm.ConfigSpec) error {
return d.apiClient.ConfigUpdate(ctx, id, version, config)
}
func (d *DryRunClient) ContainerCommit(ctx context.Context, container string, options moby.ContainerCommitOptions) (moby.IDResponse, error) {
return d.apiClient.ContainerCommit(ctx, container, options)
}
func (d *DryRunClient) ContainerDiff(ctx context.Context, container string) ([]containerType.ContainerChangeResponseItem, error) {
return d.apiClient.ContainerDiff(ctx, container)
}
func (d *DryRunClient) ContainerExecAttach(ctx context.Context, execID string, config moby.ExecStartCheck) (moby.HijackedResponse, error) {
return d.apiClient.ContainerExecAttach(ctx, execID, config)
}
func (d *DryRunClient) ContainerExecCreate(ctx context.Context, container string, config moby.ExecConfig) (moby.IDResponse, error) {
return d.apiClient.ContainerExecCreate(ctx, container, config)
}
func (d *DryRunClient) ContainerExecInspect(ctx context.Context, execID string) (moby.ContainerExecInspect, error) {
return d.apiClient.ContainerExecInspect(ctx, execID)
}
func (d *DryRunClient) ContainerExecResize(ctx context.Context, execID string, options moby.ResizeOptions) error {
return d.apiClient.ContainerExecResize(ctx, execID, options)
}
func (d *DryRunClient) ContainerExecStart(ctx context.Context, execID string, config moby.ExecStartCheck) error {
return d.apiClient.ContainerExecStart(ctx, execID, config)
}
func (d *DryRunClient) ContainerExport(ctx context.Context, container string) (io.ReadCloser, error) {
return d.apiClient.ContainerExport(ctx, container)
}
func (d *DryRunClient) ContainerInspect(ctx context.Context, container string) (moby.ContainerJSON, error) {
return d.apiClient.ContainerInspect(ctx, container)
}
func (d *DryRunClient) ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (moby.ContainerJSON, []byte, error) {
return d.apiClient.ContainerInspectWithRaw(ctx, container, getSize)
}
func (d *DryRunClient) ContainerList(ctx context.Context, options moby.ContainerListOptions) ([]moby.Container, error) {
return d.apiClient.ContainerList(ctx, options)
}
func (d *DryRunClient) ContainerLogs(ctx context.Context, container string, options moby.ContainerLogsOptions) (io.ReadCloser, error) {
return d.apiClient.ContainerLogs(ctx, container, options)
}
func (d *DryRunClient) ContainerResize(ctx context.Context, container string, options moby.ResizeOptions) error {
return d.apiClient.ContainerResize(ctx, container, options)
}
func (d *DryRunClient) ContainerStatPath(ctx context.Context, container, path string) (moby.ContainerPathStat, error) {
return d.apiClient.ContainerStatPath(ctx, container, path)
}
func (d *DryRunClient) ContainerStats(ctx context.Context, container string, stream bool) (moby.ContainerStats, error) {
return d.apiClient.ContainerStats(ctx, container, stream)
}
func (d *DryRunClient) ContainerStatsOneShot(ctx context.Context, container string) (moby.ContainerStats, error) {
return d.apiClient.ContainerStatsOneShot(ctx, container)
}
func (d *DryRunClient) ContainerTop(ctx context.Context, container string, arguments []string) (containerType.ContainerTopOKBody, error) {
return d.apiClient.ContainerTop(ctx, container, arguments)
}
func (d *DryRunClient) ContainerUpdate(ctx context.Context, container string, updateConfig containerType.UpdateConfig) (containerType.ContainerUpdateOKBody, error) {
return d.apiClient.ContainerUpdate(ctx, container, updateConfig)
}
func (d *DryRunClient) ContainerWait(ctx context.Context, container string, condition containerType.WaitCondition) (<-chan containerType.WaitResponse, <-chan error) {
return d.apiClient.ContainerWait(ctx, container, condition)
}
func (d *DryRunClient) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (moby.ContainersPruneReport, error) {
return d.apiClient.ContainersPrune(ctx, pruneFilters)
}
func (d *DryRunClient) DistributionInspect(ctx context.Context, imageName, encodedRegistryAuth string) (registry.DistributionInspect, error) {
return d.apiClient.DistributionInspect(ctx, imageName, encodedRegistryAuth)
}
func (d *DryRunClient) BuildCachePrune(ctx context.Context, opts moby.BuildCachePruneOptions) (*moby.BuildCachePruneReport, error) {
return d.apiClient.BuildCachePrune(ctx, opts)
}
func (d *DryRunClient) BuildCancel(ctx context.Context, id string) error {
return d.apiClient.BuildCancel(ctx, id)
}
func (d *DryRunClient) ImageCreate(ctx context.Context, parentReference string, options moby.ImageCreateOptions) (io.ReadCloser, error) {
return d.apiClient.ImageCreate(ctx, parentReference, options)
}
func (d *DryRunClient) ImageHistory(ctx context.Context, imageName string) ([]image.HistoryResponseItem, error) {
return d.apiClient.ImageHistory(ctx, imageName)
}
func (d *DryRunClient) ImageImport(ctx context.Context, source moby.ImageImportSource, ref string, options moby.ImageImportOptions) (io.ReadCloser, error) {
return d.apiClient.ImageImport(ctx, source, ref, options)
}
func (d *DryRunClient) ImageInspectWithRaw(ctx context.Context, imageName string) (moby.ImageInspect, []byte, error) {
return d.apiClient.ImageInspectWithRaw(ctx, imageName)
}
func (d *DryRunClient) ImageList(ctx context.Context, options moby.ImageListOptions) ([]moby.ImageSummary, error) {
return d.apiClient.ImageList(ctx, options)
}
func (d *DryRunClient) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (moby.ImageLoadResponse, error) {
return d.apiClient.ImageLoad(ctx, input, quiet)
}
func (d *DryRunClient) ImageSearch(ctx context.Context, term string, options moby.ImageSearchOptions) ([]registry.SearchResult, error) {
return d.apiClient.ImageSearch(ctx, term, options)
}
func (d *DryRunClient) ImageSave(ctx context.Context, images []string) (io.ReadCloser, error) {
return d.apiClient.ImageSave(ctx, images)
}
func (d *DryRunClient) ImageTag(ctx context.Context, imageName, ref string) error {
return d.apiClient.ImageTag(ctx, imageName, ref)
}
func (d *DryRunClient) ImagesPrune(ctx context.Context, pruneFilter filters.Args) (moby.ImagesPruneReport, error) {
return d.apiClient.ImagesPrune(ctx, pruneFilter)
}
func (d *DryRunClient) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) {
return d.apiClient.NodeInspectWithRaw(ctx, nodeID)
}
func (d *DryRunClient) NodeList(ctx context.Context, options moby.NodeListOptions) ([]swarm.Node, error) {
return d.apiClient.NodeList(ctx, options)
}
func (d *DryRunClient) NodeRemove(ctx context.Context, nodeID string, options moby.NodeRemoveOptions) error {
return d.apiClient.NodeRemove(ctx, nodeID, options)
}
func (d *DryRunClient) NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error {
return d.apiClient.NodeUpdate(ctx, nodeID, version, node)
}
func (d *DryRunClient) NetworkInspect(ctx context.Context, networkName string, options moby.NetworkInspectOptions) (moby.NetworkResource, error) {
return d.apiClient.NetworkInspect(ctx, networkName, options)
}
func (d *DryRunClient) NetworkInspectWithRaw(ctx context.Context, networkName string, options moby.NetworkInspectOptions) (moby.NetworkResource, []byte, error) {
return d.apiClient.NetworkInspectWithRaw(ctx, networkName, options)
}
func (d *DryRunClient) NetworkList(ctx context.Context, options moby.NetworkListOptions) ([]moby.NetworkResource, error) {
return d.apiClient.NetworkList(ctx, options)
}
func (d *DryRunClient) NetworksPrune(ctx context.Context, pruneFilter filters.Args) (moby.NetworksPruneReport, error) {
return d.apiClient.NetworksPrune(ctx, pruneFilter)
}
func (d *DryRunClient) PluginList(ctx context.Context, filter filters.Args) (moby.PluginsListResponse, error) {
return d.apiClient.PluginList(ctx, filter)
}
func (d *DryRunClient) PluginRemove(ctx context.Context, name string, options moby.PluginRemoveOptions) error {
return d.apiClient.PluginRemove(ctx, name, options)
}
func (d *DryRunClient) PluginEnable(ctx context.Context, name string, options moby.PluginEnableOptions) error {
return d.apiClient.PluginEnable(ctx, name, options)
}
func (d *DryRunClient) PluginDisable(ctx context.Context, name string, options moby.PluginDisableOptions) error {
return d.apiClient.PluginDisable(ctx, name, options)
}
func (d *DryRunClient) PluginInstall(ctx context.Context, name string, options moby.PluginInstallOptions) (io.ReadCloser, error) {
return d.apiClient.PluginInstall(ctx, name, options)
}
func (d *DryRunClient) PluginUpgrade(ctx context.Context, name string, options moby.PluginInstallOptions) (io.ReadCloser, error) {
return d.apiClient.PluginUpgrade(ctx, name, options)
}
func (d *DryRunClient) PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error) {
return d.apiClient.PluginPush(ctx, name, registryAuth)
}
func (d *DryRunClient) PluginSet(ctx context.Context, name string, args []string) error {
return d.apiClient.PluginSet(ctx, name, args)
}
func (d *DryRunClient) PluginInspectWithRaw(ctx context.Context, name string) (*moby.Plugin, []byte, error) {
return d.apiClient.PluginInspectWithRaw(ctx, name)
}
func (d *DryRunClient) PluginCreate(ctx context.Context, createContext io.Reader, options moby.PluginCreateOptions) error {
return d.apiClient.PluginCreate(ctx, createContext, options)
}
func (d *DryRunClient) ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options moby.ServiceCreateOptions) (moby.ServiceCreateResponse, error) {
return d.apiClient.ServiceCreate(ctx, service, options)
}
func (d *DryRunClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, options moby.ServiceInspectOptions) (swarm.Service, []byte, error) {
return d.apiClient.ServiceInspectWithRaw(ctx, serviceID, options)
}
func (d *DryRunClient) ServiceList(ctx context.Context, options moby.ServiceListOptions) ([]swarm.Service, error) {
return d.apiClient.ServiceList(ctx, options)
}
func (d *DryRunClient) ServiceRemove(ctx context.Context, serviceID string) error {
return d.apiClient.ServiceRemove(ctx, serviceID)
}
func (d *DryRunClient) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options moby.ServiceUpdateOptions) (moby.ServiceUpdateResponse, error) {
return d.apiClient.ServiceUpdate(ctx, serviceID, version, service, options)
}
func (d *DryRunClient) ServiceLogs(ctx context.Context, serviceID string, options moby.ContainerLogsOptions) (io.ReadCloser, error) {
return d.apiClient.ServiceLogs(ctx, serviceID, options)
}
func (d *DryRunClient) TaskLogs(ctx context.Context, taskID string, options moby.ContainerLogsOptions) (io.ReadCloser, error) {
return d.apiClient.TaskLogs(ctx, taskID, options)
}
func (d *DryRunClient) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error) {
return d.apiClient.TaskInspectWithRaw(ctx, taskID)
}
func (d *DryRunClient) TaskList(ctx context.Context, options moby.TaskListOptions) ([]swarm.Task, error) {
return d.apiClient.TaskList(ctx, options)
}
func (d *DryRunClient) SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) {
return d.apiClient.SwarmInit(ctx, req)
}
func (d *DryRunClient) SwarmJoin(ctx context.Context, req swarm.JoinRequest) error {
return d.apiClient.SwarmJoin(ctx, req)
}
func (d *DryRunClient) SwarmGetUnlockKey(ctx context.Context) (moby.SwarmUnlockKeyResponse, error) {
return d.apiClient.SwarmGetUnlockKey(ctx)
}
func (d *DryRunClient) SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error {
return d.apiClient.SwarmUnlock(ctx, req)
}
func (d *DryRunClient) SwarmLeave(ctx context.Context, force bool) error {
return d.apiClient.SwarmLeave(ctx, force)
}
func (d *DryRunClient) SwarmInspect(ctx context.Context) (swarm.Swarm, error) {
return d.apiClient.SwarmInspect(ctx)
}
func (d *DryRunClient) SwarmUpdate(ctx context.Context, version swarm.Version, swarmSpec swarm.Spec, flags swarm.UpdateFlags) error {
return d.apiClient.SwarmUpdate(ctx, version, swarmSpec, flags)
}
func (d *DryRunClient) SecretList(ctx context.Context, options moby.SecretListOptions) ([]swarm.Secret, error) {
return d.apiClient.SecretList(ctx, options)
}
func (d *DryRunClient) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (moby.SecretCreateResponse, error) {
return d.apiClient.SecretCreate(ctx, secret)
}
func (d *DryRunClient) SecretRemove(ctx context.Context, id string) error {
return d.apiClient.SecretRemove(ctx, id)
}
func (d *DryRunClient) SecretInspectWithRaw(ctx context.Context, name string) (swarm.Secret, []byte, error) {
return d.apiClient.SecretInspectWithRaw(ctx, name)
}
func (d *DryRunClient) SecretUpdate(ctx context.Context, id string, version swarm.Version, secret swarm.SecretSpec) error {
return d.apiClient.SecretUpdate(ctx, id, version, secret)
}
func (d *DryRunClient) Events(ctx context.Context, options moby.EventsOptions) (<-chan events.Message, <-chan error) {
return d.apiClient.Events(ctx, options)
}
func (d *DryRunClient) Info(ctx context.Context) (moby.Info, error) {
return d.apiClient.Info(ctx)
}
func (d *DryRunClient) RegistryLogin(ctx context.Context, auth moby.AuthConfig) (registry.AuthenticateOKBody, error) {
return d.apiClient.RegistryLogin(ctx, auth)
}
func (d *DryRunClient) DiskUsage(ctx context.Context, options moby.DiskUsageOptions) (moby.DiskUsage, error) {
return d.apiClient.DiskUsage(ctx, options)
}
func (d *DryRunClient) Ping(ctx context.Context) (moby.Ping, error) {
return d.apiClient.Ping(ctx)
}
func (d *DryRunClient) VolumeInspect(ctx context.Context, volumeID string) (volume.Volume, error) {
return d.apiClient.VolumeInspect(ctx, volumeID)
}
func (d *DryRunClient) VolumeInspectWithRaw(ctx context.Context, volumeID string) (volume.Volume, []byte, error) {
return d.apiClient.VolumeInspectWithRaw(ctx, volumeID)
}
func (d *DryRunClient) VolumeList(ctx context.Context, filter filters.Args) (volume.ListResponse, error) {
return d.apiClient.VolumeList(ctx, filter)
}
func (d *DryRunClient) VolumesPrune(ctx context.Context, pruneFilter filters.Args) (moby.VolumesPruneReport, error) {
return d.apiClient.VolumesPrune(ctx, pruneFilter)
}
func (d *DryRunClient) VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error {
return d.apiClient.VolumeUpdate(ctx, volumeID, version, options)
}
func (d *DryRunClient) ClientVersion() string {
return d.apiClient.ClientVersion()
}
func (d *DryRunClient) DaemonHost() string {
return d.apiClient.DaemonHost()
}
func (d *DryRunClient) HTTPClient() *http.Client {
return d.apiClient.HTTPClient()
}
func (d *DryRunClient) ServerVersion(ctx context.Context) (moby.Version, error) {
return d.apiClient.ServerVersion(ctx)
}
func (d *DryRunClient) NegotiateAPIVersion(ctx context.Context) {
d.apiClient.NegotiateAPIVersion(ctx)
}
func (d *DryRunClient) NegotiateAPIVersionPing(ping moby.Ping) {
d.apiClient.NegotiateAPIVersionPing(ping)
}
func (d *DryRunClient) DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) {
return d.apiClient.DialHijack(ctx, url, proto, meta)
}
func (d *DryRunClient) Dialer() func(context.Context) (net.Conn, error) {
return d.apiClient.Dialer()
}
func (d *DryRunClient) Close() error {
return d.apiClient.Close()
}
func (d *DryRunClient) CheckpointCreate(ctx context.Context, container string, options moby.CheckpointCreateOptions) error {
return d.apiClient.CheckpointCreate(ctx, container, options)
}
func (d *DryRunClient) CheckpointDelete(ctx context.Context, container string, options moby.CheckpointDeleteOptions) error {
return d.apiClient.CheckpointDelete(ctx, container, options)
}
func (d *DryRunClient) CheckpointList(ctx context.Context, container string, options moby.CheckpointListOptions) ([]moby.Checkpoint, error) {
return d.apiClient.CheckpointList(ctx, container, options)
}

View File

@ -52,6 +52,7 @@ type ServiceProxy struct {
ImagesFn func(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
WatchFn func(ctx context.Context, project *types.Project, services []string, options WatchOptions) error
MaxConcurrencyFn func(parallel int)
DryRunModeFn func(dryRun bool) error
interceptors []Interceptor
}
@ -91,6 +92,7 @@ func (s *ServiceProxy) WithService(service Service) *ServiceProxy {
s.ImagesFn = service.Images
s.WatchFn = service.Watch
s.MaxConcurrencyFn = service.MaxConcurrency
s.DryRunModeFn = service.DryRunMode
return s
}
@ -324,3 +326,7 @@ func (s *ServiceProxy) Watch(ctx context.Context, project *types.Project, servic
func (s *ServiceProxy) MaxConcurrency(i int) {
s.MaxConcurrencyFn(i)
}
func (s *ServiceProxy) DryRunMode(dryRun bool) error {
return s.DryRunModeFn(dryRun)
}

View File

@ -27,6 +27,7 @@ import (
"github.com/distribution/distribution/v3/reference"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/flags"
"github.com/docker/cli/cli/streams"
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@ -43,12 +44,14 @@ func NewComposeService(dockerCli command.Cli) api.Service {
return &composeService{
dockerCli: dockerCli,
maxConcurrency: -1,
dryRun: false,
}
}
type composeService struct {
dockerCli command.Cli
maxConcurrency int
dryRun bool
}
func (s *composeService) apiClient() client.APIClient {
@ -63,6 +66,24 @@ func (s *composeService) MaxConcurrency(i int) {
s.maxConcurrency = i
}
func (s *composeService) DryRunMode(dryRun bool) error {
if dryRun {
cli, err := command.NewDockerCli()
if err != nil {
return err
}
err = cli.Initialize(flags.NewClientOptions(), command.WithInitializeClient(func(cli *command.DockerCli) (client.APIClient, error) {
dryRunClient := api.NewDryRunClient(s.apiClient())
return dryRunClient, nil
}))
if err != nil {
return err
}
s.dockerCli = cli
}
return nil
}
func (s *composeService) stdout() *streams.Out {
return s.dockerCli.Out()
}

View File

@ -107,6 +107,20 @@ func (mr *MockServiceMockRecorder) Down(ctx, projectName, options interface{}) *
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Down", reflect.TypeOf((*MockService)(nil).Down), ctx, projectName, options)
}
// DryRunMode mocks base method.
func (m *MockService) DryRunMode(dryRun bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DryRunMode", dryRun)
ret0, _ := ret[0].(error)
return ret0
}
// DryRunMode indicates an expected call of DryRunMode.
func (mr *MockServiceMockRecorder) DryRunMode(dryRun interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DryRunMode", reflect.TypeOf((*MockService)(nil).DryRunMode), dryRun)
}
// Events mocks base method.
func (m *MockService) Events(ctx context.Context, projectName string, options api.EventsOptions) error {
m.ctrl.T.Helper()