introduce generate command as alpha command
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
This commit is contained in:
parent
fafaa9c5b8
commit
51ebeb5441
@ -33,6 +33,7 @@ func alphaCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
|||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
vizCommand(p, dockerCli, backend),
|
vizCommand(p, dockerCli, backend),
|
||||||
publishCommand(p, dockerCli, backend),
|
publishCommand(p, dockerCli, backend),
|
||||||
|
generateCommand(p, backend),
|
||||||
)
|
)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
82
cmd/compose/generate.go
Normal file
82
cmd/compose/generate.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 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 compose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/docker/compose/v2/pkg/api"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
type generateOptions struct {
|
||||||
|
*ProjectOptions
|
||||||
|
Format string
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||||
|
opts := generateOptions{
|
||||||
|
ProjectOptions: p,
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "generate [OPTIONS] [CONTAINERS...]",
|
||||||
|
Short: "EXPERIMENTAL - Generate a Compose file from existing containers",
|
||||||
|
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||||
|
return runGenerate(ctx, backend, opts, args)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Flags().StringVar(&opts.ProjectName, "name", "", "Project name to set in the Compose file")
|
||||||
|
cmd.Flags().StringVar(&opts.ProjectDir, "project-dir", "", "Directory to use for the project")
|
||||||
|
cmd.Flags().StringVar(&opts.Format, "format", "yaml", "Format the output. Values: [yaml | json]")
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGenerate(ctx context.Context, backend api.Service, opts generateOptions, containers []string) error {
|
||||||
|
_, _ = fmt.Fprintln(os.Stderr, "generate command is EXPERIMENTAL")
|
||||||
|
if len(containers) == 0 {
|
||||||
|
return fmt.Errorf("at least one container must be specified")
|
||||||
|
}
|
||||||
|
project, err := backend.Generate(ctx, api.GenerateOptions{
|
||||||
|
Containers: containers,
|
||||||
|
ProjectName: opts.ProjectName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var content []byte
|
||||||
|
switch opts.Format {
|
||||||
|
case "json":
|
||||||
|
content, err = project.MarshalJSON()
|
||||||
|
case "yaml":
|
||||||
|
content, err = project.MarshalYAML()
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported format %q", opts.Format)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(string(content))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
17
docs/reference/compose_alpha_generate.md
Normal file
17
docs/reference/compose_alpha_generate.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# docker compose alpha generate
|
||||||
|
|
||||||
|
<!---MARKER_GEN_START-->
|
||||||
|
EXPERIMENTAL - Generate a Compose file from existing containers
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
| Name | Type | Default | Description |
|
||||||
|
|:----------------|:---------|:--------|:------------------------------------------|
|
||||||
|
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||||
|
| `--format` | `string` | `yaml` | Format the output. Values: [yaml \| json] |
|
||||||
|
| `--name` | `string` | | Project name to set in the Compose file |
|
||||||
|
| `--project-dir` | `string` | | Directory to use for the project |
|
||||||
|
|
||||||
|
|
||||||
|
<!---MARKER_GEN_END-->
|
||||||
|
|
@ -4,9 +4,11 @@ long: Experimental commands
|
|||||||
pname: docker compose
|
pname: docker compose
|
||||||
plink: docker_compose.yaml
|
plink: docker_compose.yaml
|
||||||
cname:
|
cname:
|
||||||
|
- docker compose alpha generate
|
||||||
- docker compose alpha publish
|
- docker compose alpha publish
|
||||||
- docker compose alpha viz
|
- docker compose alpha viz
|
||||||
clink:
|
clink:
|
||||||
|
- docker_compose_alpha_generate.yaml
|
||||||
- docker_compose_alpha_publish.yaml
|
- docker_compose_alpha_publish.yaml
|
||||||
- docker_compose_alpha_viz.yaml
|
- docker_compose_alpha_viz.yaml
|
||||||
inherited_options:
|
inherited_options:
|
||||||
|
53
docs/reference/docker_compose_alpha_generate.yaml
Normal file
53
docs/reference/docker_compose_alpha_generate.yaml
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
command: docker compose alpha generate
|
||||||
|
short: EXPERIMENTAL - Generate a Compose file from existing containers
|
||||||
|
long: EXPERIMENTAL - Generate a Compose file from existing containers
|
||||||
|
usage: docker compose alpha generate [OPTIONS] [CONTAINERS...]
|
||||||
|
pname: docker compose alpha
|
||||||
|
plink: docker_compose_alpha.yaml
|
||||||
|
options:
|
||||||
|
- option: format
|
||||||
|
value_type: string
|
||||||
|
default_value: yaml
|
||||||
|
description: 'Format the output. Values: [yaml | json]'
|
||||||
|
deprecated: false
|
||||||
|
hidden: false
|
||||||
|
experimental: false
|
||||||
|
experimentalcli: false
|
||||||
|
kubernetes: false
|
||||||
|
swarm: false
|
||||||
|
- option: name
|
||||||
|
value_type: string
|
||||||
|
description: Project name to set in the Compose file
|
||||||
|
deprecated: false
|
||||||
|
hidden: false
|
||||||
|
experimental: false
|
||||||
|
experimentalcli: false
|
||||||
|
kubernetes: false
|
||||||
|
swarm: false
|
||||||
|
- option: project-dir
|
||||||
|
value_type: string
|
||||||
|
description: Directory to use for the project
|
||||||
|
deprecated: false
|
||||||
|
hidden: false
|
||||||
|
experimental: false
|
||||||
|
experimentalcli: false
|
||||||
|
kubernetes: false
|
||||||
|
swarm: false
|
||||||
|
inherited_options:
|
||||||
|
- option: dry-run
|
||||||
|
value_type: bool
|
||||||
|
default_value: "false"
|
||||||
|
description: Execute command in dry run mode
|
||||||
|
deprecated: false
|
||||||
|
hidden: false
|
||||||
|
experimental: false
|
||||||
|
experimentalcli: false
|
||||||
|
kubernetes: false
|
||||||
|
swarm: false
|
||||||
|
deprecated: false
|
||||||
|
hidden: false
|
||||||
|
experimental: false
|
||||||
|
experimentalcli: true
|
||||||
|
kubernetes: false
|
||||||
|
swarm: false
|
||||||
|
|
@ -92,6 +92,8 @@ type Service interface {
|
|||||||
Scale(ctx context.Context, project *types.Project, options ScaleOptions) error
|
Scale(ctx context.Context, project *types.Project, options ScaleOptions) error
|
||||||
// Export a service container's filesystem as a tar archive
|
// Export a service container's filesystem as a tar archive
|
||||||
Export(ctx context.Context, projectName string, options ExportOptions) error
|
Export(ctx context.Context, projectName string, options ExportOptions) error
|
||||||
|
// Generate generates a Compose Project from existing containers
|
||||||
|
Generate(ctx context.Context, options GenerateOptions) (*types.Project, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScaleOptions struct {
|
type ScaleOptions struct {
|
||||||
@ -563,6 +565,13 @@ type ExportOptions struct {
|
|||||||
Output string
|
Output string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GenerateOptions struct {
|
||||||
|
// ProjectName to set in the Compose file
|
||||||
|
ProjectName string
|
||||||
|
// Containers passed in the command line to be used as reference for service definition
|
||||||
|
Containers []string
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// STARTING indicates that stack is being deployed
|
// STARTING indicates that stack is being deployed
|
||||||
STARTING string = "Starting"
|
STARTING string = "Starting"
|
||||||
|
@ -176,7 +176,10 @@ func (s *composeService) projectFromName(containers Containers, projectName stri
|
|||||||
}
|
}
|
||||||
set := types.Services{}
|
set := types.Services{}
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
serviceLabel := c.Labels[api.ServiceLabel]
|
serviceLabel, ok := c.Labels[api.ServiceLabel]
|
||||||
|
if !ok {
|
||||||
|
serviceLabel = getCanonicalContainerName(c)
|
||||||
|
}
|
||||||
service, ok := set[serviceLabel]
|
service, ok := set[serviceLabel]
|
||||||
if !ok {
|
if !ok {
|
||||||
service = types.ServiceConfig{
|
service = types.ServiceConfig{
|
||||||
|
247
pkg/compose/generate.go
Normal file
247
pkg/compose/generate.go
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 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 compose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/compose-spec/compose-go/v2/types"
|
||||||
|
"github.com/docker/compose/v2/pkg/api"
|
||||||
|
"github.com/docker/compose/v2/pkg/utils"
|
||||||
|
moby "github.com/docker/docker/api/types"
|
||||||
|
containerType "github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/docker/docker/api/types/mount"
|
||||||
|
"github.com/docker/docker/api/types/network"
|
||||||
|
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *composeService) Generate(ctx context.Context, options api.GenerateOptions) (*types.Project, error) {
|
||||||
|
filtersListNames := filters.NewArgs()
|
||||||
|
filtersListIDs := filters.NewArgs()
|
||||||
|
for _, containerName := range options.Containers {
|
||||||
|
filtersListNames.Add("name", containerName)
|
||||||
|
filtersListIDs.Add("id", containerName)
|
||||||
|
}
|
||||||
|
containers, err := s.apiClient().ContainerList(ctx, containerType.ListOptions{
|
||||||
|
Filters: filtersListNames,
|
||||||
|
All: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
containersByIds, err := s.apiClient().ContainerList(ctx, containerType.ListOptions{
|
||||||
|
Filters: filtersListIDs,
|
||||||
|
All: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, container := range containersByIds {
|
||||||
|
if !utils.Contains(containers, container) {
|
||||||
|
containers = append(containers, container)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(containers) == 0 {
|
||||||
|
return nil, fmt.Errorf("no container(s) found with the following name(s): %s", strings.Join(options.Containers, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.createProjectFromContainers(containers, options.ProjectName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *composeService) createProjectFromContainers(containers []moby.Container, projectName string) (*types.Project, error) {
|
||||||
|
project := &types.Project{}
|
||||||
|
services := types.Services{}
|
||||||
|
networks := types.Networks{}
|
||||||
|
volumes := types.Volumes{}
|
||||||
|
secrets := types.Secrets{}
|
||||||
|
|
||||||
|
if projectName != "" {
|
||||||
|
project.Name = projectName
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range containers {
|
||||||
|
// if the container is from a previous Compose application, use the existing service name
|
||||||
|
serviceLabel, ok := c.Labels[api.ServiceLabel]
|
||||||
|
if !ok {
|
||||||
|
serviceLabel = getCanonicalContainerName(c)
|
||||||
|
}
|
||||||
|
service, ok := services[serviceLabel]
|
||||||
|
if !ok {
|
||||||
|
service = types.ServiceConfig{
|
||||||
|
Name: serviceLabel,
|
||||||
|
Image: c.Image,
|
||||||
|
Labels: c.Labels,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
service.Scale = increment(service.Scale)
|
||||||
|
|
||||||
|
inspect, err := s.apiClient().ContainerInspect(context.Background(), c.ID)
|
||||||
|
if err != nil {
|
||||||
|
services[serviceLabel] = service
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.extractComposeConfiguration(&service, inspect, volumes, secrets, networks)
|
||||||
|
service.Labels = cleanDockerPreviousLabels(service.Labels)
|
||||||
|
services[serviceLabel] = service
|
||||||
|
}
|
||||||
|
|
||||||
|
project.Services = services
|
||||||
|
project.Networks = networks
|
||||||
|
project.Volumes = volumes
|
||||||
|
project.Secrets = secrets
|
||||||
|
return project, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *composeService) extractComposeConfiguration(service *types.ServiceConfig, inspect moby.ContainerJSON, volumes types.Volumes, secrets types.Secrets, networks types.Networks) {
|
||||||
|
service.Environment = types.NewMappingWithEquals(inspect.Config.Env)
|
||||||
|
if inspect.Config.Healthcheck != nil {
|
||||||
|
healthConfig := inspect.Config.Healthcheck
|
||||||
|
service.HealthCheck = s.toComposeHealthCheck(healthConfig)
|
||||||
|
}
|
||||||
|
if len(inspect.Mounts) > 0 {
|
||||||
|
detectedVolumes, volumeConfigs, detectedSecrets, secretsConfigs := s.toComposeVolumes(inspect.Mounts)
|
||||||
|
service.Volumes = append(service.Volumes, volumeConfigs...)
|
||||||
|
service.Secrets = append(service.Secrets, secretsConfigs...)
|
||||||
|
maps.Copy(volumes, detectedVolumes)
|
||||||
|
maps.Copy(secrets, detectedSecrets)
|
||||||
|
}
|
||||||
|
if len(inspect.NetworkSettings.Networks) > 0 {
|
||||||
|
detectedNetworks, networkConfigs := s.toComposeNetwork(inspect.NetworkSettings.Networks)
|
||||||
|
service.Networks = networkConfigs
|
||||||
|
maps.Copy(networks, detectedNetworks)
|
||||||
|
}
|
||||||
|
if len(inspect.HostConfig.PortBindings) > 0 {
|
||||||
|
for key, portBindings := range inspect.HostConfig.PortBindings {
|
||||||
|
for _, portBinding := range portBindings {
|
||||||
|
service.Ports = append(service.Ports, types.ServicePortConfig{
|
||||||
|
Target: uint32(key.Int()),
|
||||||
|
Published: portBinding.HostPort,
|
||||||
|
Protocol: key.Proto(),
|
||||||
|
HostIP: portBinding.HostIP,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *composeService) toComposeHealthCheck(healthConfig *containerType.HealthConfig) *types.HealthCheckConfig {
|
||||||
|
var healthCheck types.HealthCheckConfig
|
||||||
|
healthCheck.Test = healthConfig.Test
|
||||||
|
if healthConfig.Timeout != 0 {
|
||||||
|
timeout := types.Duration(healthConfig.Timeout)
|
||||||
|
healthCheck.Timeout = &timeout
|
||||||
|
}
|
||||||
|
if healthConfig.Interval != 0 {
|
||||||
|
interval := types.Duration(healthConfig.Interval)
|
||||||
|
healthCheck.Interval = &interval
|
||||||
|
}
|
||||||
|
if healthConfig.StartPeriod != 0 {
|
||||||
|
startPeriod := types.Duration(healthConfig.StartPeriod)
|
||||||
|
healthCheck.StartPeriod = &startPeriod
|
||||||
|
}
|
||||||
|
if healthConfig.StartInterval != 0 {
|
||||||
|
startInterval := types.Duration(healthConfig.StartInterval)
|
||||||
|
healthCheck.StartInterval = &startInterval
|
||||||
|
}
|
||||||
|
if healthConfig.Retries != 0 {
|
||||||
|
retries := uint64(healthConfig.Retries)
|
||||||
|
healthCheck.Retries = &retries
|
||||||
|
}
|
||||||
|
return &healthCheck
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *composeService) toComposeVolumes(volumes []moby.MountPoint) (map[string]types.VolumeConfig,
|
||||||
|
[]types.ServiceVolumeConfig, map[string]types.SecretConfig, []types.ServiceSecretConfig) {
|
||||||
|
volumeConfigs := make(map[string]types.VolumeConfig)
|
||||||
|
secretConfigs := make(map[string]types.SecretConfig)
|
||||||
|
var serviceVolumeConfigs []types.ServiceVolumeConfig
|
||||||
|
var serviceSecretConfigs []types.ServiceSecretConfig
|
||||||
|
|
||||||
|
for _, volume := range volumes {
|
||||||
|
serviceVC := types.ServiceVolumeConfig{
|
||||||
|
Type: string(volume.Type),
|
||||||
|
Source: volume.Source,
|
||||||
|
Target: volume.Destination,
|
||||||
|
ReadOnly: !volume.RW,
|
||||||
|
}
|
||||||
|
switch volume.Type {
|
||||||
|
case mount.TypeVolume:
|
||||||
|
serviceVC.Source = volume.Name
|
||||||
|
vol := types.VolumeConfig{}
|
||||||
|
if volume.Driver != "local" {
|
||||||
|
vol.Driver = volume.Driver
|
||||||
|
vol.Name = volume.Name
|
||||||
|
}
|
||||||
|
volumeConfigs[volume.Name] = vol
|
||||||
|
serviceVolumeConfigs = append(serviceVolumeConfigs, serviceVC)
|
||||||
|
case mount.TypeBind:
|
||||||
|
if strings.HasPrefix(volume.Destination, "/run/secrets") {
|
||||||
|
destination := strings.Split(volume.Destination, "/")
|
||||||
|
secret := types.SecretConfig{
|
||||||
|
Name: destination[len(destination)-1],
|
||||||
|
File: strings.TrimPrefix(volume.Source, "/host_mnt"),
|
||||||
|
}
|
||||||
|
secretConfigs[secret.Name] = secret
|
||||||
|
serviceSecretConfigs = append(serviceSecretConfigs, types.ServiceSecretConfig{
|
||||||
|
Source: secret.Name,
|
||||||
|
Target: volume.Destination,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
serviceVolumeConfigs = append(serviceVolumeConfigs, serviceVC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return volumeConfigs, serviceVolumeConfigs, secretConfigs, serviceSecretConfigs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *composeService) toComposeNetwork(networks map[string]*network.EndpointSettings) (map[string]types.NetworkConfig, map[string]*types.ServiceNetworkConfig) {
|
||||||
|
networkConfigs := make(map[string]types.NetworkConfig)
|
||||||
|
serviceNetworkConfigs := make(map[string]*types.ServiceNetworkConfig)
|
||||||
|
|
||||||
|
for name, net := range networks {
|
||||||
|
inspect, err := s.apiClient().NetworkInspect(context.Background(), name, network.InspectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
networkConfigs[name] = types.NetworkConfig{}
|
||||||
|
} else {
|
||||||
|
networkConfigs[name] = types.NetworkConfig{
|
||||||
|
Internal: inspect.Internal,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
serviceNetworkConfigs[name] = &types.ServiceNetworkConfig{
|
||||||
|
Aliases: net.Aliases,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return networkConfigs, serviceNetworkConfigs
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanDockerPreviousLabels(labels types.Labels) types.Labels {
|
||||||
|
cleanedLabels := types.Labels{}
|
||||||
|
for key, value := range labels {
|
||||||
|
if !strings.HasPrefix(key, "com.docker.compose.") && !strings.HasPrefix(key, "desktop.docker.io") {
|
||||||
|
cleanedLabels[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cleanedLabels
|
||||||
|
}
|
@ -169,6 +169,21 @@ func (mr *MockServiceMockRecorder) Export(ctx, projectName, options any) *gomock
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Export", reflect.TypeOf((*MockService)(nil).Export), ctx, projectName, options)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Export", reflect.TypeOf((*MockService)(nil).Export), ctx, projectName, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate mocks base method.
|
||||||
|
func (m *MockService) Generate(ctx context.Context, options api.GenerateOptions) (*types.Project, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Generate", ctx, options)
|
||||||
|
ret0, _ := ret[0].(*types.Project)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate indicates an expected call of Generate.
|
||||||
|
func (mr *MockServiceMockRecorder) Generate(ctx, options any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Generate", reflect.TypeOf((*MockService)(nil).Generate), ctx, options)
|
||||||
|
}
|
||||||
|
|
||||||
// Images mocks base method.
|
// Images mocks base method.
|
||||||
func (m *MockService) Images(ctx context.Context, projectName string, options api.ImagesOptions) ([]api.ImageSummary, error) {
|
func (m *MockService) Images(ctx context.Context, projectName string, options api.ImagesOptions) ([]api.ImageSummary, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user