Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

### Enhancements:

- feat(vcl/snippet): add support for the '--content' flag, allowing for the raw output of VCL. [#1706](https://github.com/fastly/cli/pull/1706)

### Dependencies:

## [v14.1.1](https://github.com/fastly/cli/releases/tag/v14.1.1) (2026-03-18)
Expand Down
22 changes: 22 additions & 0 deletions pkg/commands/service/vcl/snippet/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func NewDescribeCommand(parent argparser.Registerer, g *global.Data) *DescribeCo
})

// Optional.
c.CmdClause.Flag("content", "Outputs the raw content of the identified snippet").Action(c.content.Set).BoolVar(&c.content.Value)
c.CmdClause.Flag("dynamic", "Whether the VCL snippet is dynamic or versioned").Action(c.dynamic.Set).BoolVar(&c.dynamic.Value)
c.RegisterFlagBool(c.JSONFlag()) // --json
c.CmdClause.Flag("name", "The name of the VCL snippet").StringVar(&c.name)
Expand All @@ -57,6 +58,7 @@ type DescribeCommand struct {
argparser.JSONOutput

dynamic argparser.OptionalBool
content argparser.OptionalBool
name string
serviceName argparser.OptionalServiceNameID
serviceVersion argparser.OptionalServiceVersion
Expand All @@ -68,6 +70,14 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error {
if c.Globals.Verbose() && c.JSONOutput.Enabled {
return fsterr.ErrInvalidVerboseJSONCombo
}
// Ensure that the --content flag is not used
// with --verbose or --json
if c.Globals.Verbose() && c.content.WasSet {
return fsterr.ErrInvalidContentOutputCombo
}
if c.JSONOutput.Enabled && c.content.WasSet {
return fsterr.ErrInvalidContentOutputCombo
}

serviceID, serviceVersion, err := argparser.ServiceDetails(argparser.ServiceDetailsOpts{
APIClient: c.Globals.APIClient,
Expand Down Expand Up @@ -169,6 +179,12 @@ func (c *DescribeCommand) constructInput(serviceID string, serviceVersion int) (

// print displays the 'dynamic' information returned from the API.
func (c *DescribeCommand) printDynamic(out io.Writer, ds *fastly.DynamicSnippet) error {
// If the --content flag is set, output only the raw VCL content.
if c.content.WasSet {
fmt.Fprint(out, fastly.ToValue(ds.Content))
return nil
}

fmt.Fprintf(out, "\nService ID: %s\n", fastly.ToValue(ds.ServiceID))
fmt.Fprintf(out, "ID: %s\n", fastly.ToValue(ds.SnippetID))
fmt.Fprintf(out, "Content: \n%s\n", text.SanitizeTerminalOutput(fastly.ToValue(ds.Content)))
Expand All @@ -183,6 +199,12 @@ func (c *DescribeCommand) printDynamic(out io.Writer, ds *fastly.DynamicSnippet)

// print displays the information returned from the API.
func (c *DescribeCommand) print(out io.Writer, s *fastly.Snippet) error {
// If the --content flag is set, output only the raw VCL content.
if c.content.WasSet {
fmt.Fprint(out, fastly.ToValue(s.Content))
return nil
}

if !c.Globals.Verbose() {
fmt.Fprintf(out, "\nService ID: %s\n", fastly.ToValue(s.ServiceID))
}
Expand Down
34 changes: 34 additions & 0 deletions pkg/commands/service/vcl/snippet/snippet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,40 @@ func TestVCLSnippetDescribe(t *testing.T) {
Args: "--dynamic --service-id 123 --snippet-id 456 --version 3",
WantOutput: "\nService ID: 123\nID: 456\nContent: \n# some vcl content\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\n",
},
{
Name: "validate --content flag outputs raw VCL only for versioned snippet",
API: &mock.API{
ListVersionsFn: testutil.ListVersions,
GetSnippetFn: getSnippet,
},
Args: "--content --name foobar --service-id 123 --version 3",
WantOutput: "# some vcl content",
},
{
Name: "validate --content flag outputs raw VCL only for dynamic snippet",
API: &mock.API{
ListVersionsFn: testutil.ListVersions,
GetDynamicSnippetFn: getDynamicSnippet,
},
Args: "--content --dynamic --service-id 123 --snippet-id 456 --version 3",
WantOutput: "# some vcl content",
},
{
Name: "validate --content flag with --verbose returns error",
API: &mock.API{
ListVersionsFn: testutil.ListVersions,
},
Args: "--content --name foobar --service-id 123 --verbose --version 3",
WantError: "invalid flag combination, --content cannot be used together with --json or --verbose",
},
{
Name: "validate --content flag with --json returns error",
API: &mock.API{
ListVersionsFn: testutil.ListVersions,
},
Args: "--content --json --name foobar --service-id 123 --version 3",
WantError: "invalid flag combination, --content cannot be used together with --json or --verbose",
},
}

testutil.RunCLIScenarios(t, []string{top.CommandName, root.CommandName, sub.CommandName, "describe"}, scenarios)
Expand Down
7 changes: 7 additions & 0 deletions pkg/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ var ErrPostBuildStopped = RemediationError{
Remediation: "Check the [scripts.post_build] in the fastly.toml manifest is safe to execute or skip this prompt using either `--auto-yes` or `--non-interactive`.",
}

// ErrInvalidContentOutputCombo means the user provided --content along with the
// --verbose or --json flags, which are mutually exclusive behaviours.
var ErrInvalidContentOutputCombo = RemediationError{
Inner: fmt.Errorf("invalid flag combination, --content cannot be used together with --json or --verbose"),
Remediation: "Use either --content, --verbose or --json separately.",
}

// ErrInvalidVerboseJSONCombo means the user provided both a --verbose and
// --json flag which are mutually exclusive behaviours.
var ErrInvalidVerboseJSONCombo = RemediationError{
Expand Down
Loading