github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/vcl/custom/update.go (about)

     1  package custom
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/fastly/go-fastly/v9/fastly"
     8  
     9  	"github.com/fastly/cli/pkg/argparser"
    10  	fsterr "github.com/fastly/cli/pkg/errors"
    11  	"github.com/fastly/cli/pkg/global"
    12  	"github.com/fastly/cli/pkg/text"
    13  )
    14  
    15  // NewUpdateCommand returns a usable command registered under the parent.
    16  func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateCommand {
    17  	c := UpdateCommand{
    18  		Base: argparser.Base{
    19  			Globals: g,
    20  		},
    21  	}
    22  	c.CmdClause = parent.Command("update", "Update the uploaded VCL for a particular service and version")
    23  
    24  	// Required.
    25  	c.CmdClause.Flag("name", "The name of the VCL to update").Required().StringVar(&c.name)
    26  	c.RegisterFlag(argparser.StringFlagOpts{
    27  		Name:        argparser.FlagVersionName,
    28  		Description: argparser.FlagVersionDesc,
    29  		Dst:         &c.serviceVersion.Value,
    30  		Required:    true,
    31  	})
    32  
    33  	// Optional.
    34  	c.RegisterAutoCloneFlag(argparser.AutoCloneFlagOpts{
    35  		Action: c.autoClone.Set,
    36  		Dst:    &c.autoClone.Value,
    37  	})
    38  	c.CmdClause.Flag("new-name", "New name for the VCL").Action(c.newName.Set).StringVar(&c.newName.Value)
    39  	c.CmdClause.Flag("content", "VCL passed as file path or content, e.g. $(< main.vcl)").Action(c.content.Set).StringVar(&c.content.Value)
    40  	c.RegisterFlag(argparser.StringFlagOpts{
    41  		Name:        argparser.FlagServiceIDName,
    42  		Description: argparser.FlagServiceIDDesc,
    43  		Dst:         &g.Manifest.Flag.ServiceID,
    44  		Short:       's',
    45  	})
    46  	c.RegisterFlag(argparser.StringFlagOpts{
    47  		Action:      c.serviceName.Set,
    48  		Name:        argparser.FlagServiceName,
    49  		Description: argparser.FlagServiceDesc,
    50  		Dst:         &c.serviceName.Value,
    51  	})
    52  
    53  	return &c
    54  }
    55  
    56  // UpdateCommand calls the Fastly API to update an appropriate resource.
    57  type UpdateCommand struct {
    58  	argparser.Base
    59  
    60  	autoClone      argparser.OptionalAutoClone
    61  	content        argparser.OptionalString
    62  	name           string
    63  	newName        argparser.OptionalString
    64  	serviceName    argparser.OptionalServiceNameID
    65  	serviceVersion argparser.OptionalServiceVersion
    66  }
    67  
    68  // Exec invokes the application logic for the command.
    69  func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error {
    70  	serviceID, serviceVersion, err := argparser.ServiceDetails(argparser.ServiceDetailsOpts{
    71  		AutoCloneFlag:      c.autoClone,
    72  		APIClient:          c.Globals.APIClient,
    73  		Manifest:           *c.Globals.Manifest,
    74  		Out:                out,
    75  		ServiceNameFlag:    c.serviceName,
    76  		ServiceVersionFlag: c.serviceVersion,
    77  		VerboseMode:        c.Globals.Flags.Verbose,
    78  	})
    79  	if err != nil {
    80  		c.Globals.ErrLog.AddWithContext(err, map[string]any{
    81  			"Service ID":      serviceID,
    82  			"Service Version": fsterr.ServiceVersion(serviceVersion),
    83  		})
    84  		return err
    85  	}
    86  
    87  	input, err := c.constructInput(serviceID, fastly.ToValue(serviceVersion.Number))
    88  	if err != nil {
    89  		c.Globals.ErrLog.AddWithContext(err, map[string]any{
    90  			"Service ID":      serviceID,
    91  			"Service Version": fastly.ToValue(serviceVersion.Number),
    92  		})
    93  		return err
    94  	}
    95  
    96  	v, err := c.Globals.APIClient.UpdateVCL(input)
    97  	if err != nil {
    98  		c.Globals.ErrLog.AddWithContext(err, map[string]any{
    99  			"Service ID":      serviceID,
   100  			"Service Version": fastly.ToValue(serviceVersion.Number),
   101  		})
   102  		return err
   103  	}
   104  
   105  	if input.NewName != nil && *input.NewName != "" {
   106  		text.Success(out,
   107  			"Updated custom VCL '%s' (previously: '%s', service: %s, version: %d)",
   108  			fastly.ToValue(v.Name),
   109  			input.Name,
   110  			fastly.ToValue(v.ServiceID),
   111  			fastly.ToValue(v.ServiceVersion),
   112  		)
   113  	} else {
   114  		text.Success(out,
   115  			"Updated custom VCL '%s' (service: %s, version: %d)",
   116  			fastly.ToValue(v.Name),
   117  			fastly.ToValue(v.ServiceID),
   118  			fastly.ToValue(v.ServiceVersion),
   119  		)
   120  	}
   121  	return nil
   122  }
   123  
   124  // constructInput transforms values parsed from CLI flags into an object to be used by the API client library.
   125  func (c *UpdateCommand) constructInput(serviceID string, serviceVersion int) (*fastly.UpdateVCLInput, error) {
   126  	var input fastly.UpdateVCLInput
   127  
   128  	input.Name = c.name
   129  	input.ServiceID = serviceID
   130  	input.ServiceVersion = serviceVersion
   131  
   132  	if !c.newName.WasSet && !c.content.WasSet {
   133  		return nil, fmt.Errorf("error parsing arguments: must provide either --new-name or --content to update the VCL")
   134  	}
   135  	if c.newName.WasSet {
   136  		input.NewName = &c.newName.Value
   137  	}
   138  	if c.content.WasSet {
   139  		input.Content = fastly.ToPointer(argparser.Content(c.content.Value))
   140  	}
   141  
   142  	return &input, nil
   143  }