diff --git a/commands/command_config.go b/commands/command_config.go index 3fbfc8e5a..cc2c002d3 100644 --- a/commands/command_config.go +++ b/commands/command_config.go @@ -41,18 +41,16 @@ type CmdConfig struct { componentBuilderFactory builder.ComponentBuilderFactory // services - Keys func() do.KeysService - Sizes func() do.SizesService - Regions func() do.RegionsService - Images func() do.ImagesService - ImageActions func() do.ImageActionsService - LoadBalancers func() do.LoadBalancersService - MicroDroplets func() do.MicroDropletsService - MicroDropletImages func() do.MicroDropletImagesService - ReservedIPs func() do.ReservedIPsService - ReservedIPActions func() do.ReservedIPActionsService - ReservedIPv6s func() do.ReservedIPv6sService - BYOIPPrefixes func() do.BYOIPPrefixsService + Keys func() do.KeysService + Sizes func() do.SizesService + Regions func() do.RegionsService + Images func() do.ImagesService + ImageActions func() do.ImageActionsService + LoadBalancers func() do.LoadBalancersService + ReservedIPs func() do.ReservedIPsService + ReservedIPActions func() do.ReservedIPActionsService + ReservedIPv6s func() do.ReservedIPv6sService + BYOIPPrefixes func() do.BYOIPPrefixsService Droplets func() do.DropletsService DropletActions func() do.DropletActionsService @@ -166,10 +164,6 @@ func NewCmdConfig(ns string, dc doctl.Config, out io.Writer, args []string, init } c.Nfs = func() do.NfsService { return do.NewNfsService(godoClient) } c.NfsActions = func() do.NfsActionsService { return do.NewNfsActionsService(godoClient) } - c.MicroDroplets = func() do.MicroDropletsService { return do.NewMicroDropletsService(godoClient) } - c.MicroDropletImages = func() do.MicroDropletImagesService { - return do.NewMicroDropletImagesService(godoClient) - } c.Security = func() do.SecurityService { return do.NewSecurityService(godoClient) } c.Secrets = func() do.SecretsService { return do.NewSecretsService(godoClient) } return nil diff --git a/commands/commands_test.go b/commands/commands_test.go index e096de574..b27c16cee 100644 --- a/commands/commands_test.go +++ b/commands/commands_test.go @@ -296,8 +296,6 @@ type tcMocks struct { inference *domocks.MockInferenceService nfs *domocks.MockNfsService nfsActions *domocks.MockNfsActionsService - microDroplets *domocks.MockMicroDropletsService - microDropletImages *domocks.MockMicroDropletImagesService security *domocks.MockSecurityService secrets *domocks.MockSecretsService vectorDBs *domocks.MockVectorDBsService @@ -360,8 +358,6 @@ func withTestClient(t *testing.T, tFn testFn) { inference: domocks.NewMockInferenceService(ctrl), nfs: domocks.NewMockNfsService(ctrl), nfsActions: domocks.NewMockNfsActionsService(ctrl), - microDroplets: domocks.NewMockMicroDropletsService(ctrl), - microDropletImages: domocks.NewMockMicroDropletImagesService(ctrl), security: domocks.NewMockSecurityService(ctrl), secrets: domocks.NewMockSecretsService(ctrl), vectorDBs: domocks.NewMockVectorDBsService(ctrl), @@ -432,8 +428,6 @@ func withTestClient(t *testing.T, tFn testFn) { Inference: func() do.InferenceService { return tm.inference }, Nfs: func() do.NfsService { return tm.nfs }, NfsActions: func() do.NfsActionsService { return tm.nfsActions }, - MicroDroplets: func() do.MicroDropletsService { return tm.microDroplets }, - MicroDropletImages: func() do.MicroDropletImagesService { return tm.microDropletImages }, Security: func() do.SecurityService { return tm.security }, Secrets: func() do.SecretsService { return tm.secrets }, VectorDBs: func() do.VectorDBsService { return tm.vectorDBs }, diff --git a/commands/displayers/micro_droplet.go b/commands/displayers/micro_droplet.go deleted file mode 100644 index ff637644c..000000000 --- a/commands/displayers/micro_droplet.go +++ /dev/null @@ -1,112 +0,0 @@ -/* -Copyright 2025 The Doctl Authors All rights reserved. -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 displayers - -import ( - "io" - - "github.com/digitalocean/doctl/do" -) - -type MicroDroplet struct { - MicroDroplets do.MicroDroplets -} - -var _ Displayable = &MicroDroplet{} - -func (m *MicroDroplet) JSON(out io.Writer) error { - return writeJSON(m.MicroDroplets, out) -} - -func (m *MicroDroplet) Cols() []string { - return []string{ - "ID", "Name", "Region", "State", "Size", "Networking", "Image", "Endpoint", "Created", - } -} - -func (m *MicroDroplet) ColMap() map[string]string { - return map[string]string{ - "ID": "ID", - "Name": "Name", - "Region": "Region", - "State": "State", - "Size": "Size", - "Networking": "Networking", - "Image": "Image", - "Endpoint": "Endpoint", - "Created": "Created At", - } -} - -func (m *MicroDroplet) KV() []map[string]any { - out := make([]map[string]any, 0, len(m.MicroDroplets)) - for _, md := range m.MicroDroplets { - out = append(out, map[string]any{ - "ID": md.ID, - "Name": md.Name, - "Region": md.Region, - "State": string(md.State), - "Size": md.Size, - "Networking": string(md.Networking), - "Image": md.Image, - "Endpoint": md.Endpoint, - "Created": md.Created, - }) - } - return out -} - -type MicroDropletCheckpoint struct { - Checkpoints do.MicroDropletCheckpoints -} - -var _ Displayable = &MicroDropletCheckpoint{} - -func (c *MicroDropletCheckpoint) JSON(out io.Writer) error { - return writeJSON(c.Checkpoints, out) -} - -func (c *MicroDropletCheckpoint) Cols() []string { - return []string{ - "ID", "MicroDropletID", "Name", "Status", "MemoryBytes", "DiskBytes", "Created", - } -} - -func (c *MicroDropletCheckpoint) ColMap() map[string]string { - return map[string]string{ - "ID": "ID", - "MicroDropletID": "MicroDroplet ID", - "Name": "Name", - "Status": "Status", - "MemoryBytes": "Memory Bytes", - "DiskBytes": "Disk Bytes", - "Created": "Created At", - } -} - -func (c *MicroDropletCheckpoint) KV() []map[string]any { - out := make([]map[string]any, 0, len(c.Checkpoints)) - for _, cp := range c.Checkpoints { - out = append(out, map[string]any{ - "ID": cp.ID, - "MicroDropletID": cp.MicroDropletID, - "Name": cp.Name, - "Status": string(cp.Status), - "MemoryBytes": cp.MemoryBytes, - "DiskBytes": cp.DiskBytes, - "Created": cp.Created, - }) - } - return out -} diff --git a/commands/displayers/micro_droplet_image.go b/commands/displayers/micro_droplet_image.go deleted file mode 100644 index 0c148340f..000000000 --- a/commands/displayers/micro_droplet_image.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 2025 The Doctl Authors All rights reserved. -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 displayers - -import ( - "io" - - "github.com/digitalocean/doctl/do" -) - -type MicroDropletImage struct { - Images do.MicroDropletImages -} - -var _ Displayable = &MicroDropletImage{} - -func (i *MicroDropletImage) JSON(out io.Writer) error { - return writeJSON(i.Images, out) -} - -func (i *MicroDropletImage) Cols() []string { - return []string{"ID", "Name", "Source", "Status", "Created"} -} - -func (i *MicroDropletImage) ColMap() map[string]string { - return map[string]string{ - "ID": "ID", - "Name": "Name", - "Source": "Source", - "Status": "Status", - "Created": "Created At", - } -} - -func (i *MicroDropletImage) KV() []map[string]any { - out := make([]map[string]any, 0, len(i.Images)) - for _, img := range i.Images { - out = append(out, map[string]any{ - "ID": img.ID, - "Name": img.Name, - "Source": img.Source, - "Status": string(img.Status), - "Created": img.Created, - }) - } - return out -} diff --git a/commands/doit.go b/commands/doit.go index 2f22c79f9..1893b9b13 100644 --- a/commands/doit.go +++ b/commands/doit.go @@ -219,7 +219,6 @@ func computeCmd() *Command { cmd.AddCommand(Droplet()) cmd.AddCommand(DropletAutoscale()) cmd.AddCommand(Domain()) - cmd.AddCommand(MicroDroplet()) cmd.AddCommand(VPCNATGateway()) cmd.AddCommand(Firewall()) cmd.AddCommand(ReservedIP()) diff --git a/commands/microdroplets.go b/commands/microdroplets.go deleted file mode 100644 index bcc341a62..000000000 --- a/commands/microdroplets.go +++ /dev/null @@ -1,419 +0,0 @@ -/* -Copyright 2025 The Doctl Authors All rights reserved. -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 commands - -import ( - "fmt" - "strings" - - "github.com/digitalocean/doctl" - "github.com/digitalocean/doctl/commands/displayers" - "github.com/digitalocean/doctl/do" - "github.com/digitalocean/godo" - "github.com/spf13/cobra" -) - -// MicroDroplet creates the microdroplet command tree. -func MicroDroplet() *Command { - cmd := &Command{ - Command: &cobra.Command{ - Use: "microdroplet", - Short: "Manage MicroDroplets", - Long: `The subcommands under ` + "`" + `doctl compute microdroplet` + "`" + ` manage MicroDroplets — lightweight ` + - `microVM sandboxes that pause when idle and resume on demand. Use these commands to ` + - `create, inspect, pause, resume, and delete MicroDroplets, and to list their checkpoints.`, - }, - } - - cmdMicroDropletList := CmdBuilder(cmd, RunMicroDropletList, "list", - "List MicroDroplets on your account", - "Retrieves a list of MicroDroplets on your account, optionally filtered by region.", - Writer, aliasOpt("ls"), displayerType(&displayers.MicroDroplet{})) - AddStringFlag(cmdMicroDropletList, doctl.ArgRegionSlug, "", "", - "Filter MicroDroplets by region slug, such as `nyc1`") - - CmdBuilder(cmd, RunMicroDropletGet, "get ", - "Retrieve information about a MicroDroplet", - "Retrieves information about a MicroDroplet by its UUID.", - Writer, aliasOpt("g"), displayerType(&displayers.MicroDroplet{})) - - cmdMicroDropletCreate := CmdBuilder(cmd, RunMicroDropletCreate, "create ", - "Create a new MicroDroplet", - "Creates a new MicroDroplet in the specified region from the specified image. "+ - "`--region`, `--size`, and `--image` are required. The MicroDroplet UUID and current state are returned on success.", - Writer, aliasOpt("c"), displayerType(&displayers.MicroDroplet{})) - AddStringFlag(cmdMicroDropletCreate, doctl.ArgRegionSlug, "", "", - "A `slug` specifying the region to create the MicroDroplet in, such as `nyc1`", requiredOpt()) - AddStringFlag(cmdMicroDropletCreate, doctl.ArgSizeSlug, "", "", - "A `slug` indicating the MicroDroplet's size", requiredOpt()) - AddStringFlag(cmdMicroDropletCreate, doctl.ArgImage, "", "", - "The URN or UUID of a MicroDroplet image to launch", requiredOpt()) - AddStringFlag(cmdMicroDropletCreate, "networking", "", "", - "Networking mode for the MicroDroplet: `public` or `vpc`") - AddStringFlag(cmdMicroDropletCreate, doctl.ArgVPCUUID, "", "", - "The UUID of a non-default VPC to place the MicroDroplet in (only valid when `--networking=vpc`)") - AddBoolFlag(cmdMicroDropletCreate, "auto-pause", "", false, - "Enable auto-pause when the MicroDroplet is idle") - AddStringFlag(cmdMicroDropletCreate, "auto-pause-idle-timeout", "", "", - "Idle duration before auto-pause (e.g. `5m`, `30s`); requires `--auto-pause`") - AddBoolFlag(cmdMicroDropletCreate, "auto-resume", "", false, - "Enable auto-resume when the MicroDroplet is paused and receives traffic") - AddIntFlag(cmdMicroDropletCreate, "http-port", "", 0, - "HTTP port exposed by the MicroDroplet workload") - AddStringFlag(cmdMicroDropletCreate, "http-protocol", "", "", - "HTTP protocol served by the MicroDroplet: `http` or `http2`") - AddStringSliceFlag(cmdMicroDropletCreate, "env", "", []string{}, - "Environment variables to inject, in `KEY=VALUE` form. Repeatable.") - AddStringSliceFlag(cmdMicroDropletCreate, doctl.ArgTag, "", []string{}, - "Tags to apply to the MicroDroplet. Repeatable.") - - CmdBuilder(cmd, RunMicroDropletPause, "pause ", - "Pause a running MicroDroplet", - "Requests that the MicroDroplet transition to the `paused` state. Returns the mutated MicroDroplet.", - Writer, displayerType(&displayers.MicroDroplet{})) - - CmdBuilder(cmd, RunMicroDropletResume, "resume ", - "Resume a paused MicroDroplet", - "Requests that the MicroDroplet transition to the `running` state. Returns the mutated MicroDroplet.", - Writer, displayerType(&displayers.MicroDroplet{})) - - cmdMicroDropletDelete := CmdBuilder(cmd, RunMicroDropletDelete, "delete ...", - "Permanently delete one or more MicroDroplets", - "Permanently deletes the specified MicroDroplets. This is irreversible.", - Writer, aliasOpt("d", "rm")) - AddBoolFlag(cmdMicroDropletDelete, doctl.ArgForce, doctl.ArgShortForce, false, - "Delete the MicroDroplet(s) without a confirmation prompt") - - CmdBuilder(cmd, RunMicroDropletCheckpoints, "checkpoints ", - "List checkpoints for a MicroDroplet", - "Retrieves a list of checkpoints for the specified MicroDroplet. "+ - "Checkpoints are captured automatically by DigitalOcean when a MicroDroplet is paused; "+ - "each one preserves the memory and disk state required to resume.", - Writer, aliasOpt("cp"), displayerType(&displayers.MicroDropletCheckpoint{})) - - cmd.AddCommand(microDropletImages()) - - return cmd -} - -func microDropletImages() *Command { - cmd := &Command{ - Command: &cobra.Command{ - Use: "image", - Short: "Manage MicroDroplet images", - Long: `The subcommands under ` + "`" + `doctl compute microdroplet image` + "`" + ` manage OCI images ` + - `imported for use with MicroDroplets.`, - }, - } - - CmdBuilder(cmd, RunMicroDropletImageList, "list", - "List MicroDroplet images on your account", - "Retrieves a list of MicroDroplet images on your account.", - Writer, aliasOpt("ls"), displayerType(&displayers.MicroDropletImage{})) - - CmdBuilder(cmd, RunMicroDropletImageGet, "get ", - "Retrieve information about a MicroDroplet image", - "Retrieves information about a MicroDroplet image by its UUID.", - Writer, aliasOpt("g"), displayerType(&displayers.MicroDropletImage{})) - - cmdImageCreate := CmdBuilder(cmd, RunMicroDropletImageCreate, "create ", - "Import a new MicroDroplet image", - "Imports a new MicroDroplet image from a public OCI ref or a DOCR ref. Import is asynchronous.", - Writer, aliasOpt("c"), displayerType(&displayers.MicroDropletImage{})) - AddStringFlag(cmdImageCreate, "source", "", "", - "The OCI or DOCR source ref for the image", requiredOpt()) - - cmdImageDelete := CmdBuilder(cmd, RunMicroDropletImageDelete, "delete ...", - "Permanently delete one or more MicroDroplet images", - "Permanently deletes the specified MicroDroplet images. This is irreversible.", - Writer, aliasOpt("d", "rm")) - AddBoolFlag(cmdImageDelete, doctl.ArgForce, doctl.ArgShortForce, false, - "Delete the image(s) without a confirmation prompt") - - return cmd -} - -// RunMicroDropletList lists MicroDroplets, optionally filtered by region. -func RunMicroDropletList(c *CmdConfig) error { - region, err := c.Doit.GetString(c.NS, doctl.ArgRegionSlug) - if err != nil { - return err - } - - svc := c.MicroDroplets() - - var list do.MicroDroplets - if region != "" { - list, err = svc.ListByRegion(region) - } else { - list, err = svc.List() - } - if err != nil { - return err - } - - return c.Display(&displayers.MicroDroplet{MicroDroplets: list}) -} - -// RunMicroDropletGet retrieves a MicroDroplet by its UUID. -func RunMicroDropletGet(c *CmdConfig) error { - if err := ensureOneArg(c); err != nil { - return err - } - md, err := c.MicroDroplets().Get(c.Args[0]) - if err != nil { - return err - } - return c.Display(&displayers.MicroDroplet{MicroDroplets: do.MicroDroplets{*md}}) -} - -// RunMicroDropletCreate creates a MicroDroplet with the provided configuration. -func RunMicroDropletCreate(c *CmdConfig) error { - if len(c.Args) < 1 { - return doctl.NewMissingArgsErr(c.NS) - } - name := c.Args[0] - - region, err := c.Doit.GetString(c.NS, doctl.ArgRegionSlug) - if err != nil { - return err - } - size, err := c.Doit.GetString(c.NS, doctl.ArgSizeSlug) - if err != nil { - return err - } - image, err := c.Doit.GetString(c.NS, doctl.ArgImage) - if err != nil { - return err - } - networking, err := c.Doit.GetString(c.NS, "networking") - if err != nil { - return err - } - vpcUUID, err := c.Doit.GetString(c.NS, doctl.ArgVPCUUID) - if err != nil { - return err - } - autoPauseEnabled, err := c.Doit.GetBool(c.NS, "auto-pause") - if err != nil { - return err - } - autoPauseIdle, err := c.Doit.GetString(c.NS, "auto-pause-idle-timeout") - if err != nil { - return err - } - autoResumeEnabled, err := c.Doit.GetBool(c.NS, "auto-resume") - if err != nil { - return err - } - httpPort, err := c.Doit.GetInt(c.NS, "http-port") - if err != nil { - return err - } - httpProtocol, err := c.Doit.GetString(c.NS, "http-protocol") - if err != nil { - return err - } - envPairs, err := c.Doit.GetStringSlice(c.NS, "env") - if err != nil { - return err - } - tags, err := c.Doit.GetStringSlice(c.NS, doctl.ArgTag) - if err != nil { - return err - } - - req := &godo.MicroDropletCreateRequest{ - Name: name, - Region: region, - Size: size, - Image: image, - } - if networking != "" { - req.Networking = godo.MicroDropletNetworking(networking) - } - if vpcUUID != "" { - req.VPCUUID = vpcUUID - } - if autoPauseIdle != "" && !autoPauseEnabled { - return fmt.Errorf("--auto-pause-idle-timeout requires --auto-pause") - } - if autoPauseEnabled { - enabled := true - req.AutoPause = &godo.AutoPauseConfig{ - Enabled: &enabled, - IdleTimeout: autoPauseIdle, - } - } - if autoResumeEnabled { - enabled := true - req.AutoResume = &enabled - } - if httpPort > 0 { - req.HTTPPort = uint32(httpPort) - } - if httpProtocol != "" { - req.HTTPProtocol = godo.MicroDropletHTTPProtocol(httpProtocol) - } - if len(envPairs) > 0 { - env, err := parseEnvPairs(envPairs) - if err != nil { - return err - } - req.Environment = env - } - if len(tags) > 0 { - req.Tags = tags - } - - md, err := c.MicroDroplets().Create(req) - if err != nil { - return err - } - return c.Display(&displayers.MicroDroplet{MicroDroplets: do.MicroDroplets{*md}}) -} - -// RunMicroDropletPause transitions a MicroDroplet to the paused state. -func RunMicroDropletPause(c *CmdConfig) error { - if err := ensureOneArg(c); err != nil { - return err - } - md, err := c.MicroDroplets().Pause(c.Args[0]) - if err != nil { - return err - } - return c.Display(&displayers.MicroDroplet{MicroDroplets: do.MicroDroplets{*md}}) -} - -// RunMicroDropletResume transitions a MicroDroplet to the running state. -func RunMicroDropletResume(c *CmdConfig) error { - if err := ensureOneArg(c); err != nil { - return err - } - md, err := c.MicroDroplets().Resume(c.Args[0]) - if err != nil { - return err - } - return c.Display(&displayers.MicroDroplet{MicroDroplets: do.MicroDroplets{*md}}) -} - -// RunMicroDropletDelete deletes one or more MicroDroplets by UUID. -func RunMicroDropletDelete(c *CmdConfig) error { - if len(c.Args) < 1 { - return doctl.NewMissingArgsErr(c.NS) - } - force, err := c.Doit.GetBool(c.NS, doctl.ArgForce) - if err != nil { - return err - } - if !(force || AskForConfirmDelete("MicroDroplet", len(c.Args)) == nil) { - return errOperationAborted - } - - svc := c.MicroDroplets() - for _, id := range c.Args { - if err := svc.Delete(id); err != nil { - return fmt.Errorf("Unable to delete MicroDroplet %s: %v", id, err) - } - } - return nil -} - -// RunMicroDropletCheckpoints lists checkpoints for a MicroDroplet. -func RunMicroDropletCheckpoints(c *CmdConfig) error { - if err := ensureOneArg(c); err != nil { - return err - } - checkpoints, err := c.MicroDroplets().ListCheckpoints(c.Args[0]) - if err != nil { - return err - } - return c.Display(&displayers.MicroDropletCheckpoint{Checkpoints: checkpoints}) -} - -// RunMicroDropletImageList lists MicroDroplet images. -func RunMicroDropletImageList(c *CmdConfig) error { - imgs, err := c.MicroDropletImages().List() - if err != nil { - return err - } - return c.Display(&displayers.MicroDropletImage{Images: imgs}) -} - -// RunMicroDropletImageGet retrieves a MicroDroplet image by UUID. -func RunMicroDropletImageGet(c *CmdConfig) error { - if err := ensureOneArg(c); err != nil { - return err - } - img, err := c.MicroDropletImages().Get(c.Args[0]) - if err != nil { - return err - } - return c.Display(&displayers.MicroDropletImage{Images: do.MicroDropletImages{*img}}) -} - -// RunMicroDropletImageCreate imports a MicroDroplet image from an OCI ref. -func RunMicroDropletImageCreate(c *CmdConfig) error { - if len(c.Args) < 1 { - return doctl.NewMissingArgsErr(c.NS) - } - source, err := c.Doit.GetString(c.NS, "source") - if err != nil { - return err - } - img, err := c.MicroDropletImages().Create(&godo.MicroDropletImageCreateRequest{ - Name: c.Args[0], - Source: source, - }) - if err != nil { - return err - } - return c.Display(&displayers.MicroDropletImage{Images: do.MicroDropletImages{*img}}) -} - -// RunMicroDropletImageDelete deletes one or more MicroDroplet images. -func RunMicroDropletImageDelete(c *CmdConfig) error { - if len(c.Args) < 1 { - return doctl.NewMissingArgsErr(c.NS) - } - force, err := c.Doit.GetBool(c.NS, doctl.ArgForce) - if err != nil { - return err - } - if !(force || AskForConfirmDelete("MicroDroplet image", len(c.Args)) == nil) { - return errOperationAborted - } - - svc := c.MicroDropletImages() - for _, id := range c.Args { - if err := svc.Delete(id); err != nil { - return fmt.Errorf("Unable to delete MicroDroplet image %s: %v", id, err) - } - } - return nil -} - -// parseEnvPairs turns "KEY=VALUE" pairs into a map, returning an error on -// malformed entries. -func parseEnvPairs(pairs []string) (map[string]string, error) { - out := make(map[string]string, len(pairs)) - for _, p := range pairs { - key, value, ok := strings.Cut(p, "=") - if !ok || key == "" { - return nil, fmt.Errorf("invalid --env value %q: expected KEY=VALUE", p) - } - out[key] = value - } - return out, nil -} diff --git a/commands/microdroplets_test.go b/commands/microdroplets_test.go deleted file mode 100644 index a2c4f781b..000000000 --- a/commands/microdroplets_test.go +++ /dev/null @@ -1,307 +0,0 @@ -/* -Copyright 2025 The Doctl Authors All rights reserved. -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 commands - -import ( - "testing" - - "github.com/digitalocean/doctl" - "github.com/digitalocean/doctl/do" - "github.com/digitalocean/godo" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var ( - testMicroDropletID = "b2a2f7a4-8d34-4c1c-9c66-3f2b7f8f38f2" - - testMicroDroplet = do.MicroDroplet{ - MicroDroplet: &godo.MicroDroplet{ - ID: testMicroDropletID, - Name: "sammy-microdroplet", - Region: "nyc1", - State: godo.MicroDropletStateRunning, - Size: "md-1vcpu-512mb", - Networking: godo.MicroDropletNetworkingPublic, - Image: "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000", - Endpoint: "https://sammy.microdroplets.digitalocean.app", - Created: "2026-07-16T10:00:00Z", - }, - } - - testMicroDropletList = do.MicroDroplets{testMicroDroplet} - - testMicroDropletCheckpoint = do.MicroDropletCheckpoint{ - MicroDropletCheckpoint: &godo.MicroDropletCheckpoint{ - ID: "8f7a9a3f-5555-4444-9999-000000000001", - MicroDropletID: testMicroDropletID, - Name: "sammy-checkpoint", - Status: godo.MicroDropletCheckpointStatusAvailable, - MemoryBytes: 512 * 1024 * 1024, - DiskBytes: 1024 * 1024 * 1024, - Created: "2026-07-16T10:05:00Z", - }, - } - - testMicroDropletImage = do.MicroDropletImage{ - MicroDropletImage: &godo.MicroDropletImage{ - ID: "aa11bb22-cc33-dd44-ee55-ff6600000000", - Name: "hello-world", - Source: "docker.io/library/hello-world:latest", - Status: godo.MicroDropletImageStatusAvailable, - Created: "2026-07-16T09:00:00Z", - }, - } -) - -func TestMicroDropletCommand(t *testing.T) { - cmd := MicroDroplet() - assert.NotNil(t, cmd) - assertCommandNames(t, cmd, - "checkpoints", "create", "delete", "get", "image", "list", "pause", "resume", - ) -} - -func TestMicroDropletImageCommand(t *testing.T) { - cmd := microDropletImages() - assert.NotNil(t, cmd) - assertCommandNames(t, cmd, "create", "delete", "get", "list") -} - -func TestMicroDropletsList(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.microDroplets.EXPECT().List().Return(testMicroDropletList, nil) - err := RunMicroDropletList(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletsListByRegion(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.microDroplets.EXPECT().ListByRegion("nyc1").Return(testMicroDropletList, nil) - config.Doit.Set(config.NS, doctl.ArgRegionSlug, "nyc1") - err := RunMicroDropletList(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletGet(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.microDroplets.EXPECT().Get(testMicroDropletID).Return(&testMicroDroplet, nil) - config.Args = append(config.Args, testMicroDropletID) - err := RunMicroDropletGet(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletGet_missingArg(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - err := RunMicroDropletGet(config) - require.Error(t, err) - }) -} - -func TestMicroDropletCreate(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - enabled := true - expected := &godo.MicroDropletCreateRequest{ - Name: "sammy-microdroplet", - Region: "nyc1", - Size: "md-1vcpu-512mb", - Image: "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000", - Networking: godo.MicroDropletNetworkingVPC, - VPCUUID: "vpc-uuid-1234", - AutoPause: &godo.AutoPauseConfig{Enabled: &enabled, IdleTimeout: "5m"}, - AutoResume: &enabled, - HTTPPort: 8080, - HTTPProtocol: godo.MicroDropletHTTPProtocolHTTP2, - Environment: map[string]string{"FOO": "bar", "BAZ": "qux"}, - Tags: []string{"prod", "web"}, - } - tm.microDroplets.EXPECT().Create(expected).Return(&testMicroDroplet, nil) - - config.Args = append(config.Args, "sammy-microdroplet") - config.Doit.Set(config.NS, doctl.ArgRegionSlug, "nyc1") - config.Doit.Set(config.NS, doctl.ArgSizeSlug, "md-1vcpu-512mb") - config.Doit.Set(config.NS, doctl.ArgImage, "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000") - config.Doit.Set(config.NS, "networking", "vpc") - config.Doit.Set(config.NS, doctl.ArgVPCUUID, "vpc-uuid-1234") - config.Doit.Set(config.NS, "auto-pause", true) - config.Doit.Set(config.NS, "auto-pause-idle-timeout", "5m") - config.Doit.Set(config.NS, "auto-resume", true) - config.Doit.Set(config.NS, "http-port", 8080) - config.Doit.Set(config.NS, "http-protocol", "http2") - config.Doit.Set(config.NS, "env", []string{"FOO=bar", "BAZ=qux"}) - config.Doit.Set(config.NS, doctl.ArgTag, []string{"prod", "web"}) - - err := RunMicroDropletCreate(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletCreate_minimal(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - expected := &godo.MicroDropletCreateRequest{ - Name: "sammy-microdroplet", - Region: "nyc1", - Size: "md-1vcpu-512mb", - Image: "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000", - } - tm.microDroplets.EXPECT().Create(expected).Return(&testMicroDroplet, nil) - - config.Args = append(config.Args, "sammy-microdroplet") - config.Doit.Set(config.NS, doctl.ArgRegionSlug, "nyc1") - config.Doit.Set(config.NS, doctl.ArgSizeSlug, "md-1vcpu-512mb") - config.Doit.Set(config.NS, doctl.ArgImage, "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000") - - err := RunMicroDropletCreate(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletCreate_badEnv(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - config.Args = append(config.Args, "sammy-microdroplet") - config.Doit.Set(config.NS, doctl.ArgRegionSlug, "nyc1") - config.Doit.Set(config.NS, doctl.ArgSizeSlug, "md-1vcpu-512mb") - config.Doit.Set(config.NS, doctl.ArgImage, "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000") - config.Doit.Set(config.NS, "env", []string{"MALFORMED"}) - - err := RunMicroDropletCreate(config) - require.Error(t, err) - }) -} - -// --auto-pause-idle-timeout has no meaning without --auto-pause, so setting -// it alone is rejected before any API call is made. -func TestMicroDropletCreate_idleTimeoutRequiresAutoPause(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - config.Args = append(config.Args, "sammy-microdroplet") - config.Doit.Set(config.NS, doctl.ArgRegionSlug, "nyc1") - config.Doit.Set(config.NS, doctl.ArgSizeSlug, "md-1vcpu-512mb") - config.Doit.Set(config.NS, doctl.ArgImage, "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000") - config.Doit.Set(config.NS, "auto-pause-idle-timeout", "5m") - - err := RunMicroDropletCreate(config) - require.Error(t, err) - require.Contains(t, err.Error(), "--auto-pause-idle-timeout requires --auto-pause") - }) -} - -func TestMicroDropletPause(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.microDroplets.EXPECT().Pause(testMicroDropletID).Return(&testMicroDroplet, nil) - - config.Args = append(config.Args, testMicroDropletID) - err := RunMicroDropletPause(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletResume(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.microDroplets.EXPECT().Resume(testMicroDropletID).Return(&testMicroDroplet, nil) - - config.Args = append(config.Args, testMicroDropletID) - err := RunMicroDropletResume(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletDelete(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.microDroplets.EXPECT().Delete(testMicroDropletID).Return(nil) - - config.Args = append(config.Args, testMicroDropletID) - config.Doit.Set(config.NS, doctl.ArgForce, true) - - err := RunMicroDropletDelete(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletDelete_multiple(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - ids := []string{testMicroDropletID, "aabbccdd-1111-2222-3333-444455556666"} - for _, id := range ids { - tm.microDroplets.EXPECT().Delete(id).Return(nil) - } - - config.Args = append(config.Args, ids...) - config.Doit.Set(config.NS, doctl.ArgForce, true) - - err := RunMicroDropletDelete(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletCheckpoints(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.microDroplets.EXPECT().ListCheckpoints(testMicroDropletID).Return( - do.MicroDropletCheckpoints{testMicroDropletCheckpoint}, nil, - ) - - config.Args = append(config.Args, testMicroDropletID) - err := RunMicroDropletCheckpoints(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletImageList(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.microDropletImages.EXPECT().List().Return( - do.MicroDropletImages{testMicroDropletImage}, nil, - ) - err := RunMicroDropletImageList(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletImageGet(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.microDropletImages.EXPECT().Get(testMicroDropletImage.ID).Return(&testMicroDropletImage, nil) - - config.Args = append(config.Args, testMicroDropletImage.ID) - err := RunMicroDropletImageGet(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletImageCreate(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - expected := &godo.MicroDropletImageCreateRequest{ - Name: "hello-world", - Source: "docker.io/library/hello-world:latest", - } - tm.microDropletImages.EXPECT().Create(expected).Return(&testMicroDropletImage, nil) - - config.Args = append(config.Args, "hello-world") - config.Doit.Set(config.NS, "source", "docker.io/library/hello-world:latest") - - err := RunMicroDropletImageCreate(config) - require.NoError(t, err) - }) -} - -func TestMicroDropletImageDelete(t *testing.T) { - withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.microDropletImages.EXPECT().Delete(testMicroDropletImage.ID).Return(nil) - - config.Args = append(config.Args, testMicroDropletImage.ID) - config.Doit.Set(config.NS, doctl.ArgForce, true) - - err := RunMicroDropletImageDelete(config) - require.NoError(t, err) - }) -} diff --git a/do/micro_droplet_images.go b/do/micro_droplet_images.go deleted file mode 100644 index 599efa0e5..000000000 --- a/do/micro_droplet_images.go +++ /dev/null @@ -1,98 +0,0 @@ -/* -Copyright 2025 The Doctl Authors All rights reserved. -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 do - -import ( - "context" - - "github.com/digitalocean/godo" -) - -// MicroDropletImage wraps a godo.MicroDropletImage. -type MicroDropletImage struct { - *godo.MicroDropletImage -} - -// MicroDropletImages is a slice of MicroDropletImage. -type MicroDropletImages []MicroDropletImage - -// MicroDropletImagesService is an interface for interacting with DigitalOcean's -// MicroDroplet image API. -type MicroDropletImagesService interface { - List() (MicroDropletImages, error) - Get(id string) (*MicroDropletImage, error) - Create(req *godo.MicroDropletImageCreateRequest) (*MicroDropletImage, error) - Delete(id string) error -} - -type microDropletImagesService struct { - client *godo.Client -} - -var _ MicroDropletImagesService = µDropletImagesService{} - -// NewMicroDropletImagesService builds a MicroDropletImagesService backed by -// the provided godo client. -func NewMicroDropletImagesService(client *godo.Client) MicroDropletImagesService { - return µDropletImagesService{client: client} -} - -func (s *microDropletImagesService) List() (MicroDropletImages, error) { - f := func(opt *godo.ListOptions) ([]any, *godo.Response, error) { - list, resp, err := s.client.MicroDropletImages.List(context.TODO(), opt) - if err != nil { - return nil, nil, err - } - - si := make([]any, len(list)) - for i := range list { - si[i] = list[i] - } - - return si, resp, err - } - - si, err := PaginateResp(f) - if err != nil { - return nil, err - } - - list := make(MicroDropletImages, len(si)) - for i := range si { - img := si[i].(godo.MicroDropletImage) - list[i] = MicroDropletImage{MicroDropletImage: &img} - } - return list, nil -} - -func (s *microDropletImagesService) Get(id string) (*MicroDropletImage, error) { - img, _, err := s.client.MicroDropletImages.Get(context.TODO(), id) - if err != nil { - return nil, err - } - return &MicroDropletImage{MicroDropletImage: img}, nil -} - -func (s *microDropletImagesService) Create(req *godo.MicroDropletImageCreateRequest) (*MicroDropletImage, error) { - img, _, err := s.client.MicroDropletImages.Create(context.TODO(), req) - if err != nil { - return nil, err - } - return &MicroDropletImage{MicroDropletImage: img}, nil -} - -func (s *microDropletImagesService) Delete(id string) error { - _, err := s.client.MicroDropletImages.Delete(context.TODO(), id) - return err -} diff --git a/do/microdroplets.go b/do/microdroplets.go deleted file mode 100644 index c8030ca09..000000000 --- a/do/microdroplets.go +++ /dev/null @@ -1,173 +0,0 @@ -/* -Copyright 2025 The Doctl Authors All rights reserved. -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 do - -import ( - "context" - - "github.com/digitalocean/godo" -) - -// MicroDroplet wraps a godo.MicroDroplet. -type MicroDroplet struct { - *godo.MicroDroplet -} - -// MicroDroplets is a slice of MicroDroplet. -type MicroDroplets []MicroDroplet - -// MicroDropletCheckpoint wraps a godo.MicroDropletCheckpoint. -type MicroDropletCheckpoint struct { - *godo.MicroDropletCheckpoint -} - -// MicroDropletCheckpoints is a slice of MicroDropletCheckpoint. -type MicroDropletCheckpoints []MicroDropletCheckpoint - -// MicroDropletsService is an interface for interacting with DigitalOcean's -// MicroDroplet API. -type MicroDropletsService interface { - List() (MicroDroplets, error) - ListByRegion(region string) (MicroDroplets, error) - ListByName(name string) (MicroDroplets, error) - Get(id string) (*MicroDroplet, error) - Create(req *godo.MicroDropletCreateRequest) (*MicroDroplet, error) - Pause(id string) (*MicroDroplet, error) - Resume(id string) (*MicroDroplet, error) - Delete(id string) error - ListCheckpoints(id string) (MicroDropletCheckpoints, error) -} - -type microDropletsService struct { - client *godo.Client -} - -var _ MicroDropletsService = µDropletsService{} - -// NewMicroDropletsService builds a MicroDropletsService backed by the provided -// godo client. -func NewMicroDropletsService(client *godo.Client) MicroDropletsService { - return µDropletsService{client: client} -} - -func (s *microDropletsService) List() (MicroDroplets, error) { - return s.paginate(func(opt *godo.ListOptions) ([]godo.MicroDroplet, *godo.Response, error) { - return s.client.MicroDroplets.List(context.TODO(), opt) - }) -} - -func (s *microDropletsService) ListByRegion(region string) (MicroDroplets, error) { - return s.paginate(func(opt *godo.ListOptions) ([]godo.MicroDroplet, *godo.Response, error) { - return s.client.MicroDroplets.ListByRegion(context.TODO(), region, opt) - }) -} - -func (s *microDropletsService) ListByName(name string) (MicroDroplets, error) { - return s.paginate(func(opt *godo.ListOptions) ([]godo.MicroDroplet, *godo.Response, error) { - return s.client.MicroDroplets.ListByName(context.TODO(), name, opt) - }) -} - -func (s *microDropletsService) paginate(lister func(*godo.ListOptions) ([]godo.MicroDroplet, *godo.Response, error)) (MicroDroplets, error) { - f := func(opt *godo.ListOptions) ([]any, *godo.Response, error) { - list, resp, err := lister(opt) - if err != nil { - return nil, nil, err - } - - si := make([]any, len(list)) - for i := range list { - si[i] = list[i] - } - - return si, resp, err - } - - si, err := PaginateResp(f) - if err != nil { - return nil, err - } - - list := make(MicroDroplets, len(si)) - for i := range si { - md := si[i].(godo.MicroDroplet) - list[i] = MicroDroplet{MicroDroplet: &md} - } - return list, nil -} - -func (s *microDropletsService) Get(id string) (*MicroDroplet, error) { - md, _, err := s.client.MicroDroplets.Get(context.TODO(), id) - if err != nil { - return nil, err - } - return &MicroDroplet{MicroDroplet: md}, nil -} - -func (s *microDropletsService) Create(req *godo.MicroDropletCreateRequest) (*MicroDroplet, error) { - md, _, err := s.client.MicroDroplets.Create(context.TODO(), req) - if err != nil { - return nil, err - } - return &MicroDroplet{MicroDroplet: md}, nil -} - -func (s *microDropletsService) Pause(id string) (*MicroDroplet, error) { - md, _, err := s.client.MicroDroplets.Pause(context.TODO(), id) - if err != nil { - return nil, err - } - return &MicroDroplet{MicroDroplet: md}, nil -} - -func (s *microDropletsService) Resume(id string) (*MicroDroplet, error) { - md, _, err := s.client.MicroDroplets.Resume(context.TODO(), id) - if err != nil { - return nil, err - } - return &MicroDroplet{MicroDroplet: md}, nil -} - -func (s *microDropletsService) Delete(id string) error { - _, err := s.client.MicroDroplets.Delete(context.TODO(), id) - return err -} - -func (s *microDropletsService) ListCheckpoints(id string) (MicroDropletCheckpoints, error) { - f := func(opt *godo.ListOptions) ([]any, *godo.Response, error) { - list, resp, err := s.client.MicroDroplets.ListCheckpoints(context.TODO(), id, opt) - if err != nil { - return nil, nil, err - } - - si := make([]any, len(list)) - for i := range list { - si[i] = list[i] - } - - return si, resp, err - } - - si, err := PaginateResp(f) - if err != nil { - return nil, err - } - - list := make(MicroDropletCheckpoints, len(si)) - for i := range si { - cp := si[i].(godo.MicroDropletCheckpoint) - list[i] = MicroDropletCheckpoint{MicroDropletCheckpoint: &cp} - } - return list, nil -} diff --git a/do/mocks/MicroDropletImagesService.go b/do/mocks/MicroDropletImagesService.go deleted file mode 100644 index 7032f44f6..000000000 --- a/do/mocks/MicroDropletImagesService.go +++ /dev/null @@ -1,101 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: micro_droplet_images.go -// -// Generated by this command: -// -// mockgen -source micro_droplet_images.go -package=mocks MicroDropletImagesService -// - -// Package mocks is a generated GoMock package. -package mocks - -import ( - reflect "reflect" - - do "github.com/digitalocean/doctl/do" - godo "github.com/digitalocean/godo" - gomock "go.uber.org/mock/gomock" -) - -// MockMicroDropletImagesService is a mock of MicroDropletImagesService interface. -type MockMicroDropletImagesService struct { - ctrl *gomock.Controller - recorder *MockMicroDropletImagesServiceMockRecorder - isgomock struct{} -} - -// MockMicroDropletImagesServiceMockRecorder is the mock recorder for MockMicroDropletImagesService. -type MockMicroDropletImagesServiceMockRecorder struct { - mock *MockMicroDropletImagesService -} - -// NewMockMicroDropletImagesService creates a new mock instance. -func NewMockMicroDropletImagesService(ctrl *gomock.Controller) *MockMicroDropletImagesService { - mock := &MockMicroDropletImagesService{ctrl: ctrl} - mock.recorder = &MockMicroDropletImagesServiceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockMicroDropletImagesService) EXPECT() *MockMicroDropletImagesServiceMockRecorder { - return m.recorder -} - -// Create mocks base method. -func (m *MockMicroDropletImagesService) Create(req *godo.MicroDropletImageCreateRequest) (*do.MicroDropletImage, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", req) - ret0, _ := ret[0].(*do.MicroDropletImage) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Create indicates an expected call of Create. -func (mr *MockMicroDropletImagesServiceMockRecorder) Create(req any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockMicroDropletImagesService)(nil).Create), req) -} - -// Delete mocks base method. -func (m *MockMicroDropletImagesService) Delete(id string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", id) - ret0, _ := ret[0].(error) - return ret0 -} - -// Delete indicates an expected call of Delete. -func (mr *MockMicroDropletImagesServiceMockRecorder) Delete(id any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockMicroDropletImagesService)(nil).Delete), id) -} - -// Get mocks base method. -func (m *MockMicroDropletImagesService) Get(id string) (*do.MicroDropletImage, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", id) - ret0, _ := ret[0].(*do.MicroDropletImage) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Get indicates an expected call of Get. -func (mr *MockMicroDropletImagesServiceMockRecorder) Get(id any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockMicroDropletImagesService)(nil).Get), id) -} - -// List mocks base method. -func (m *MockMicroDropletImagesService) List() (do.MicroDropletImages, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "List") - ret0, _ := ret[0].(do.MicroDropletImages) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// List indicates an expected call of List. -func (mr *MockMicroDropletImagesServiceMockRecorder) List() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockMicroDropletImagesService)(nil).List)) -} diff --git a/do/mocks/MicroDropletsService.go b/do/mocks/MicroDropletsService.go deleted file mode 100644 index ce9761ef1..000000000 --- a/do/mocks/MicroDropletsService.go +++ /dev/null @@ -1,176 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: microdroplets.go -// -// Generated by this command: -// -// mockgen -source microdroplets.go -package=mocks MicroDropletsService -// - -// Package mocks is a generated GoMock package. -package mocks - -import ( - reflect "reflect" - - do "github.com/digitalocean/doctl/do" - godo "github.com/digitalocean/godo" - gomock "go.uber.org/mock/gomock" -) - -// MockMicroDropletsService is a mock of MicroDropletsService interface. -type MockMicroDropletsService struct { - ctrl *gomock.Controller - recorder *MockMicroDropletsServiceMockRecorder - isgomock struct{} -} - -// MockMicroDropletsServiceMockRecorder is the mock recorder for MockMicroDropletsService. -type MockMicroDropletsServiceMockRecorder struct { - mock *MockMicroDropletsService -} - -// NewMockMicroDropletsService creates a new mock instance. -func NewMockMicroDropletsService(ctrl *gomock.Controller) *MockMicroDropletsService { - mock := &MockMicroDropletsService{ctrl: ctrl} - mock.recorder = &MockMicroDropletsServiceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockMicroDropletsService) EXPECT() *MockMicroDropletsServiceMockRecorder { - return m.recorder -} - -// Create mocks base method. -func (m *MockMicroDropletsService) Create(req *godo.MicroDropletCreateRequest) (*do.MicroDroplet, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", req) - ret0, _ := ret[0].(*do.MicroDroplet) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Create indicates an expected call of Create. -func (mr *MockMicroDropletsServiceMockRecorder) Create(req any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockMicroDropletsService)(nil).Create), req) -} - -// Delete mocks base method. -func (m *MockMicroDropletsService) Delete(id string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", id) - ret0, _ := ret[0].(error) - return ret0 -} - -// Delete indicates an expected call of Delete. -func (mr *MockMicroDropletsServiceMockRecorder) Delete(id any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockMicroDropletsService)(nil).Delete), id) -} - -// Get mocks base method. -func (m *MockMicroDropletsService) Get(id string) (*do.MicroDroplet, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", id) - ret0, _ := ret[0].(*do.MicroDroplet) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Get indicates an expected call of Get. -func (mr *MockMicroDropletsServiceMockRecorder) Get(id any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockMicroDropletsService)(nil).Get), id) -} - -// List mocks base method. -func (m *MockMicroDropletsService) List() (do.MicroDroplets, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "List") - ret0, _ := ret[0].(do.MicroDroplets) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// List indicates an expected call of List. -func (mr *MockMicroDropletsServiceMockRecorder) List() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockMicroDropletsService)(nil).List)) -} - -// ListByName mocks base method. -func (m *MockMicroDropletsService) ListByName(name string) (do.MicroDroplets, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListByName", name) - ret0, _ := ret[0].(do.MicroDroplets) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ListByName indicates an expected call of ListByName. -func (mr *MockMicroDropletsServiceMockRecorder) ListByName(name any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListByName", reflect.TypeOf((*MockMicroDropletsService)(nil).ListByName), name) -} - -// ListByRegion mocks base method. -func (m *MockMicroDropletsService) ListByRegion(region string) (do.MicroDroplets, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListByRegion", region) - ret0, _ := ret[0].(do.MicroDroplets) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ListByRegion indicates an expected call of ListByRegion. -func (mr *MockMicroDropletsServiceMockRecorder) ListByRegion(region any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListByRegion", reflect.TypeOf((*MockMicroDropletsService)(nil).ListByRegion), region) -} - -// ListCheckpoints mocks base method. -func (m *MockMicroDropletsService) ListCheckpoints(id string) (do.MicroDropletCheckpoints, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListCheckpoints", id) - ret0, _ := ret[0].(do.MicroDropletCheckpoints) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ListCheckpoints indicates an expected call of ListCheckpoints. -func (mr *MockMicroDropletsServiceMockRecorder) ListCheckpoints(id any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListCheckpoints", reflect.TypeOf((*MockMicroDropletsService)(nil).ListCheckpoints), id) -} - -// Pause mocks base method. -func (m *MockMicroDropletsService) Pause(id string) (*do.MicroDroplet, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Pause", id) - ret0, _ := ret[0].(*do.MicroDroplet) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Pause indicates an expected call of Pause. -func (mr *MockMicroDropletsServiceMockRecorder) Pause(id any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pause", reflect.TypeOf((*MockMicroDropletsService)(nil).Pause), id) -} - -// Resume mocks base method. -func (m *MockMicroDropletsService) Resume(id string) (*do.MicroDroplet, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Resume", id) - ret0, _ := ret[0].(*do.MicroDroplet) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Resume indicates an expected call of Resume. -func (mr *MockMicroDropletsServiceMockRecorder) Resume(id any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Resume", reflect.TypeOf((*MockMicroDropletsService)(nil).Resume), id) -} diff --git a/integration/microdroplet_create_test.go b/integration/microdroplet_create_test.go deleted file mode 100644 index 5cdb4fa82..000000000 --- a/integration/microdroplet_create_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package integration - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "net/http/httptest" - "net/http/httputil" - "os/exec" - "strings" - "testing" - - "github.com/sclevine/spec" - "github.com/stretchr/testify/require" -) - -var _ = suite("compute/microdroplet/create", func(t *testing.T, when spec.G, it spec.S) { - var ( - expect *require.Assertions - server *httptest.Server - ) - - it.Before(func() { - expect = require.New(t) - - server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - switch req.URL.Path { - case "/v2/microdroplets/instances": - auth := req.Header.Get("Authorization") - if auth != "Bearer some-magic-token" { - w.WriteHeader(http.StatusUnauthorized) - return - } - - if req.Method != http.MethodPost { - w.WriteHeader(http.StatusMethodNotAllowed) - return - } - - reqBody, err := io.ReadAll(req.Body) - expect.NoError(err) - - var got map[string]any - expect.NoError(json.Unmarshal(reqBody, &got)) - expect.Equal("sammy-microdroplet", got["name"]) - expect.Equal("nyc1", got["region"]) - expect.Equal("md-1vcpu-512mb", got["size"]) - expect.Equal("do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000", got["image"]) - - w.WriteHeader(http.StatusCreated) - w.Write([]byte(microDropletCreateResponse)) - default: - dump, err := httputil.DumpRequest(req, true) - if err != nil { - t.Fatal("failed to dump request") - } - - t.Fatalf("received unknown request: %s", dump) - } - })) - }) - - when("all required flags are passed", func() { - it("creates a microdroplet", func() { - cmd := exec.Command(builtBinaryPath, - "-t", "some-magic-token", - "-u", server.URL, - "compute", "microdroplet", "create", "sammy-microdroplet", - "--region", "nyc1", - "--size", "md-1vcpu-512mb", - "--image", "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000", - ) - - output, err := cmd.CombinedOutput() - expect.NoError(err, fmt.Sprintf("received error output: %s", output)) - expect.Equal(strings.TrimSpace(microDropletCreateOutput), strings.TrimSpace(string(output))) - }) - }) - - when("missing required flags", func() { - it("returns an error", func() { - cmd := exec.Command(builtBinaryPath, - "-t", "some-magic-token", - "-u", "https://www.example.com", - "compute", "microdroplet", "create", "sammy-microdroplet", - ) - - output, err := cmd.CombinedOutput() - expect.Error(err) - expect.Contains(string(output), "missing required arguments") - }) - }) -}) - -const ( - microDropletCreateOutput = ` -ID Name Region State Size Networking Image Endpoint Created At -b2a2f7a4-8d34-4c1c-9c66-3f2b7f8f38f2 sammy-microdroplet nyc1 creating md-1vcpu-512mb public do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000 2026-07-16T10:00:00Z -` - microDropletCreateResponse = ` -{ - "micro_droplet": { - "id": "b2a2f7a4-8d34-4c1c-9c66-3f2b7f8f38f2", - "name": "sammy-microdroplet", - "region": "nyc1", - "state": "creating", - "size": "md-1vcpu-512mb", - "networking": "public", - "image": "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000", - "created_at": "2026-07-16T10:00:00Z" - } -} -` -) diff --git a/integration/microdroplet_list_test.go b/integration/microdroplet_list_test.go deleted file mode 100644 index b3de41d51..000000000 --- a/integration/microdroplet_list_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package integration - -import ( - "fmt" - "net/http" - "net/http/httptest" - "net/http/httputil" - "os/exec" - "strings" - "testing" - - "github.com/sclevine/spec" - "github.com/stretchr/testify/require" -) - -var _ = suite("compute/microdroplet/list", func(t *testing.T, when spec.G, it spec.S) { - var ( - expect *require.Assertions - server *httptest.Server - ) - - it.Before(func() { - expect = require.New(t) - - server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - switch req.URL.Path { - case "/v2/microdroplets/instances": - auth := req.Header.Get("Authorization") - if auth != "Bearer some-magic-token" { - w.WriteHeader(http.StatusUnauthorized) - return - } - - if req.Method != http.MethodGet { - w.WriteHeader(http.StatusMethodNotAllowed) - return - } - - if region := req.URL.Query().Get("region"); region == "nyc1" { - w.Write([]byte(microDropletListResponse)) - return - } - - w.Write([]byte(microDropletListResponse)) - default: - dump, err := httputil.DumpRequest(req, true) - if err != nil { - t.Fatal("failed to dump request") - } - - t.Fatalf("received unknown request: %s", dump) - } - })) - }) - - when("no flags are passed", func() { - it("lists all microdroplets", func() { - cmd := exec.Command(builtBinaryPath, - "-t", "some-magic-token", - "-u", server.URL, - "compute", "microdroplet", "list", - ) - - output, err := cmd.CombinedOutput() - expect.NoError(err, fmt.Sprintf("received error output: %s", output)) - expect.Equal(strings.TrimSpace(microDropletListOutput), strings.TrimSpace(string(output))) - }) - }) - - when("a region is provided", func() { - it("filters microdroplets by region", func() { - cmd := exec.Command(builtBinaryPath, - "-t", "some-magic-token", - "-u", server.URL, - "compute", "microdroplet", "list", - "--region", "nyc1", - ) - - output, err := cmd.CombinedOutput() - expect.NoError(err, fmt.Sprintf("received error output: %s", output)) - expect.Equal(strings.TrimSpace(microDropletListOutput), strings.TrimSpace(string(output))) - }) - }) -}) - -const ( - microDropletListOutput = ` -ID Name Region State Size Networking Image Endpoint Created At -b2a2f7a4-8d34-4c1c-9c66-3f2b7f8f38f2 sammy-microdroplet nyc1 running md-1vcpu-512mb public do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000 https://sammy.microdroplets.digitalocean.app 2026-07-16T10:00:00Z -` - microDropletListResponse = ` -{ - "micro_droplets": [ - { - "id": "b2a2f7a4-8d34-4c1c-9c66-3f2b7f8f38f2", - "name": "sammy-microdroplet", - "region": "nyc1", - "state": "running", - "size": "md-1vcpu-512mb", - "networking": "public", - "image": "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000", - "endpoint": "https://sammy.microdroplets.digitalocean.app", - "created_at": "2026-07-16T10:00:00Z" - } - ], - "links": {}, - "meta": {"total": 1} -} -` -) diff --git a/integration/microdroplet_pause_test.go b/integration/microdroplet_pause_test.go deleted file mode 100644 index 87b01661a..000000000 --- a/integration/microdroplet_pause_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package integration - -import ( - "fmt" - "io" - "net/http" - "net/http/httptest" - "net/http/httputil" - "os/exec" - "strings" - "testing" - - "github.com/sclevine/spec" - "github.com/stretchr/testify/require" -) - -var _ = suite("compute/microdroplet/pause", func(t *testing.T, when spec.G, it spec.S) { - var ( - expect *require.Assertions - server *httptest.Server - ) - - it.Before(func() { - expect = require.New(t) - - server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - switch req.URL.Path { - case "/v2/microdroplets/instances/b2a2f7a4-8d34-4c1c-9c66-3f2b7f8f38f2/pause": - auth := req.Header.Get("Authorization") - if auth != "Bearer some-magic-token" { - w.WriteHeader(http.StatusUnauthorized) - return - } - - if req.Method != http.MethodPost { - w.WriteHeader(http.StatusMethodNotAllowed) - return - } - - reqBody, err := io.ReadAll(req.Body) - expect.NoError(err) - expect.Empty(strings.TrimSpace(string(reqBody)), "pause request body should be empty") - - w.Write([]byte(microDropletPauseResponse)) - default: - dump, err := httputil.DumpRequest(req, true) - if err != nil { - t.Fatal("failed to dump request") - } - - t.Fatalf("received unknown request: %s", dump) - } - })) - }) - - when("the id is provided", func() { - it("pauses the microdroplet", func() { - cmd := exec.Command(builtBinaryPath, - "-t", "some-magic-token", - "-u", server.URL, - "compute", "microdroplet", "pause", - "b2a2f7a4-8d34-4c1c-9c66-3f2b7f8f38f2", - ) - - output, err := cmd.CombinedOutput() - expect.NoError(err, fmt.Sprintf("received error output: %s", output)) - expect.Equal(strings.TrimSpace(microDropletPauseOutput), strings.TrimSpace(string(output))) - }) - }) -}) - -const ( - microDropletPauseOutput = ` -ID Name Region State Size Networking Image Endpoint Created At -b2a2f7a4-8d34-4c1c-9c66-3f2b7f8f38f2 sammy-microdroplet nyc1 paused md-1vcpu-512mb public do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000 https://sammy.microdroplets.digitalocean.app 2026-07-16T10:00:00Z -` - microDropletPauseResponse = ` -{ - "micro_droplet": { - "id": "b2a2f7a4-8d34-4c1c-9c66-3f2b7f8f38f2", - "name": "sammy-microdroplet", - "region": "nyc1", - "state": "paused", - "size": "md-1vcpu-512mb", - "networking": "public", - "image": "do:microdroplet-image:0f0f0f0f-0000-0000-0000-000000000000", - "endpoint": "https://sammy.microdroplets.digitalocean.app", - "created_at": "2026-07-16T10:00:00Z" - } -} -` -) diff --git a/scripts/regenmocks.sh b/scripts/regenmocks.sh index 1621a6438..5e97e3ed4 100755 --- a/scripts/regenmocks.sh +++ b/scripts/regenmocks.sh @@ -53,8 +53,6 @@ mockgen -source gradientai.go -package=mocks GradientAIService > mocks/GradientA mockgen -source inference.go -package=mocks InferenceService > mocks/InferenceService.go mockgen -source nfs.go -package=mocks NfsService > mocks/NfsService.go mockgen -source nfs_actions.go -package=mocks NfsActionsService > mocks/NfsActionsService.go -mockgen -source microdroplets.go -package=mocks MicroDropletsService > mocks/MicroDropletsService.go -mockgen -source micro_droplet_images.go -package=mocks MicroDropletImagesService > mocks/MicroDropletImagesService.go mockgen -source security.go -package=mocks SecurityService > mocks/SecurityService.go mockgen -source secrets.go -package=mocks SecretsService > mocks/SecretsService.go mockgen -source vector_databases.go -package=mocks VectorDBsService > mocks/VectorDBsService.go