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

     1  package snippet
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/fastly/go-fastly/v9/fastly"
     7  
     8  	"github.com/fastly/cli/pkg/argparser"
     9  	"github.com/fastly/cli/pkg/errors"
    10  	"github.com/fastly/cli/pkg/global"
    11  	"github.com/fastly/cli/pkg/text"
    12  )
    13  
    14  // Locations is a list of VCL subroutines.
    15  var Locations = []string{"init", "recv", "hash", "hit", "miss", "pass", "fetch", "error", "deliver", "log", "none"}
    16  
    17  // NewCreateCommand returns a usable command registered under the parent.
    18  func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand {
    19  	c := CreateCommand{
    20  		Base: argparser.Base{
    21  			Globals: g,
    22  		},
    23  	}
    24  	c.CmdClause = parent.Command("create", "Create a snippet for a particular service and version").Alias("add")
    25  
    26  	// Required.
    27  	c.RegisterFlag(argparser.StringFlagOpts{
    28  		Name:        argparser.FlagVersionName,
    29  		Description: argparser.FlagVersionDesc,
    30  		Dst:         &c.serviceVersion.Value,
    31  		Required:    true,
    32  	})
    33  
    34  	// Optional.
    35  	c.RegisterAutoCloneFlag(argparser.AutoCloneFlagOpts{
    36  		Action: c.autoClone.Set,
    37  		Dst:    &c.autoClone.Value,
    38  	})
    39  	c.CmdClause.Flag("content", "VCL snippet passed as file path or content, e.g. $(< snippet.vcl)").Action(c.content.Set).StringVar(&c.content.Value)
    40  	c.CmdClause.Flag("dynamic", "Whether the VCL snippet is dynamic or versioned").Action(c.dynamic.Set).BoolVar(&c.dynamic.Value)
    41  	c.CmdClause.Flag("name", "The name of the VCL snippet").Action(c.name.Set).StringVar(&c.name.Value)
    42  	c.CmdClause.Flag("priority", "Priority determines execution order. Lower numbers execute first").Short('p').Action(c.priority.Set).IntVar(&c.priority.Value)
    43  
    44  	c.RegisterFlag(argparser.StringFlagOpts{
    45  		Name:        argparser.FlagServiceIDName,
    46  		Description: argparser.FlagServiceIDDesc,
    47  		Dst:         &g.Manifest.Flag.ServiceID,
    48  		Short:       's',
    49  	})
    50  	c.RegisterFlag(argparser.StringFlagOpts{
    51  		Action:      c.serviceName.Set,
    52  		Name:        argparser.FlagServiceName,
    53  		Description: argparser.FlagServiceDesc,
    54  		Dst:         &c.serviceName.Value,
    55  	})
    56  	c.CmdClause.Flag("type", "The location in generated VCL where the snippet should be placed").Action(c.location.Set).HintOptions(Locations...).EnumVar(&c.location.Value, Locations...)
    57  
    58  	return &c
    59  }
    60  
    61  // CreateCommand calls the Fastly API to create an appropriate resource.
    62  type CreateCommand struct {
    63  	argparser.Base
    64  
    65  	autoClone      argparser.OptionalAutoClone
    66  	content        argparser.OptionalString
    67  	dynamic        argparser.OptionalBool
    68  	location       argparser.OptionalString
    69  	name           argparser.OptionalString
    70  	priority       argparser.OptionalInt
    71  	serviceName    argparser.OptionalServiceNameID
    72  	serviceVersion argparser.OptionalServiceVersion
    73  }
    74  
    75  // Exec invokes the application logic for the command.
    76  func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error {
    77  	serviceID, serviceVersion, err := argparser.ServiceDetails(argparser.ServiceDetailsOpts{
    78  		AutoCloneFlag:      c.autoClone,
    79  		APIClient:          c.Globals.APIClient,
    80  		Manifest:           *c.Globals.Manifest,
    81  		Out:                out,
    82  		ServiceNameFlag:    c.serviceName,
    83  		ServiceVersionFlag: c.serviceVersion,
    84  		VerboseMode:        c.Globals.Flags.Verbose,
    85  	})
    86  	if err != nil {
    87  		c.Globals.ErrLog.AddWithContext(err, map[string]any{
    88  			"Service ID":      serviceID,
    89  			"Service Version": errors.ServiceVersion(serviceVersion),
    90  		})
    91  		return err
    92  	}
    93  
    94  	input := c.constructInput(serviceID, fastly.ToValue(serviceVersion.Number))
    95  
    96  	v, err := c.Globals.APIClient.CreateSnippet(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  	text.Success(out,
   106  		"Created VCL snippet '%s' (service: %s, version: %d, dynamic: %t, snippet id: %s, type: %s, priority: %d)",
   107  		fastly.ToValue(v.Name),
   108  		fastly.ToValue(v.ServiceID),
   109  		fastly.ToValue(v.ServiceVersion),
   110  		c.dynamic.WasSet,
   111  		fastly.ToValue(v.SnippetID),
   112  		c.location.Value,
   113  		fastly.ToValue(v.Priority),
   114  	)
   115  	return nil
   116  }
   117  
   118  // constructInput transforms values parsed from CLI flags into an object to be used by the API client library.
   119  func (c *CreateCommand) constructInput(serviceID string, serviceVersion int) *fastly.CreateSnippetInput {
   120  	input := fastly.CreateSnippetInput{
   121  		Dynamic:        fastly.ToPointer(0),
   122  		ServiceID:      serviceID,
   123  		ServiceVersion: serviceVersion,
   124  	}
   125  	if c.name.WasSet {
   126  		input.Name = &c.name.Value
   127  	}
   128  	if c.content.WasSet {
   129  		input.Content = fastly.ToPointer(argparser.Content(c.content.Value))
   130  	}
   131  	if c.location.WasSet {
   132  		sType := fastly.SnippetType(c.location.Value)
   133  		input.Type = &sType
   134  	}
   135  	if c.dynamic.WasSet {
   136  		input.Dynamic = fastly.ToPointer(1)
   137  	}
   138  	if c.priority.WasSet {
   139  		input.Priority = &c.priority.Value
   140  	}
   141  
   142  	return &input
   143  }