From 9fdef76ee3997bee83603b73a56ad8cf4d18fcc0 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Fri, 20 Mar 2026 11:06:41 -0400 Subject: [PATCH 1/6] feat(vcl/snippet): add support for the snippet describe --context flag The --context flag will allow users to extract the raw VCL contents from a snippet so it can be used directly with other commands or tools. --- pkg/commands/service/vcl/snippet/describe.go | 22 ++++++++++++ .../service/vcl/snippet/snippet_test.go | 34 +++++++++++++++++++ pkg/errors/errors.go | 7 ++++ 3 files changed, 63 insertions(+) diff --git a/pkg/commands/service/vcl/snippet/describe.go b/pkg/commands/service/vcl/snippet/describe.go index 815077d62..d77a9bd7c 100644 --- a/pkg/commands/service/vcl/snippet/describe.go +++ b/pkg/commands/service/vcl/snippet/describe.go @@ -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) @@ -57,6 +58,7 @@ type DescribeCommand struct { argparser.JSONOutput dynamic argparser.OptionalBool + content argparser.OptionalBool name string serviceName argparser.OptionalServiceNameID serviceVersion argparser.OptionalServiceVersion @@ -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 --contenet flag is not used + // with --verbose or --json + if c.Globals.Verbose() && c.content.WasSet { + return fsterr.ErrInvalidContentCombo + } + if c.JSONOutput.Enabled && c.content.WasSet { + return fsterr.ErrInvalidContentCombo + } serviceID, serviceVersion, err := argparser.ServiceDetails(argparser.ServiceDetailsOpts{ APIClient: c.Globals.APIClient, @@ -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 --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))) @@ -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 --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)) } diff --git a/pkg/commands/service/vcl/snippet/snippet_test.go b/pkg/commands/service/vcl/snippet/snippet_test.go index de27b87cf..9fb9c62b2 100644 --- a/pkg/commands/service/vcl/snippet/snippet_test.go +++ b/pkg/commands/service/vcl/snippet/snippet_test.go @@ -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) diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index 111bd9f3a..d429116d2 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -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`.", } +// ErrInvalidContentCombo means the user provided --content along with the +// --verbose or --json flag which are mutually exclusive behaviours. +var ErrInvalidContentCombo = RemediationError{ + Inner: fmt.Errorf("invalid flag combination, --content cannot be used together with --json or --verbose"), + Remediation: "Use either --content, --verbose or --json seperately.", +} + // ErrInvalidVerboseJSONCombo means the user provided both a --verbose and // --json flag which are mutually exclusive behaviours. var ErrInvalidVerboseJSONCombo = RemediationError{ From 855ee83248f8365224f5b024ae2d432c4f450356 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Fri, 20 Mar 2026 11:10:51 -0400 Subject: [PATCH 2/6] changelog update --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d90c8cf7a..637b3ae54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ### Enhancements: +- feat(vcl/snippet): add support for the '--context' flag, allowing for the raw outout 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) From 669e39ebb84ef63d8a6db4f9db2cec176bd1cb59 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Fri, 20 Mar 2026 11:13:09 -0400 Subject: [PATCH 3/6] minor comment cleanup --- pkg/commands/service/vcl/snippet/describe.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/commands/service/vcl/snippet/describe.go b/pkg/commands/service/vcl/snippet/describe.go index d77a9bd7c..e3cdd21c0 100644 --- a/pkg/commands/service/vcl/snippet/describe.go +++ b/pkg/commands/service/vcl/snippet/describe.go @@ -179,7 +179,7 @@ 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 --content flag is set, output only the raw VCL content + // 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 @@ -199,7 +199,7 @@ 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 --content flag is set, output only the raw VCL content + // 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 From 988d5507f0b3bd6669c537c5f45d03f3c43067be Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Fri, 20 Mar 2026 11:35:50 -0400 Subject: [PATCH 4/6] fixed typos --- CHANGELOG.md | 2 +- pkg/errors/errors.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 637b3ae54..e90c0fe48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ ### Enhancements: -- feat(vcl/snippet): add support for the '--context' flag, allowing for the raw outout of VCL. [#1706](https://github.com/fastly/cli/pull/1706) +- 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: diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index d429116d2..ec110b39e 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -132,7 +132,7 @@ var ErrPostBuildStopped = RemediationError{ // --verbose or --json flag which are mutually exclusive behaviours. var ErrInvalidContentCombo = RemediationError{ Inner: fmt.Errorf("invalid flag combination, --content cannot be used together with --json or --verbose"), - Remediation: "Use either --content, --verbose or --json seperately.", + Remediation: "Use either --content, --verbose or --json separately.", } // ErrInvalidVerboseJSONCombo means the user provided both a --verbose and From f2664f756ab0370a93ad5790e4d4be49184dc108 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Fri, 20 Mar 2026 12:57:08 -0400 Subject: [PATCH 5/6] bump test --- pkg/errors/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index ec110b39e..3b25bbacd 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -129,7 +129,7 @@ var ErrPostBuildStopped = RemediationError{ } // ErrInvalidContentCombo means the user provided --content along with the -// --verbose or --json flag which are mutually exclusive behaviours. +// --verbose or --json flags, which are mutually exclusive behaviours. var ErrInvalidContentCombo = RemediationError{ Inner: fmt.Errorf("invalid flag combination, --content cannot be used together with --json or --verbose"), Remediation: "Use either --content, --verbose or --json separately.", From d5e1d9bae6328bd558fad39d38debedb0560a71a Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Mon, 23 Mar 2026 10:23:22 -0400 Subject: [PATCH 6/6] Corrected comment and renamed ErrInvalidContentOutputCombo error --- pkg/commands/service/vcl/snippet/describe.go | 6 +++--- pkg/errors/errors.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/commands/service/vcl/snippet/describe.go b/pkg/commands/service/vcl/snippet/describe.go index e3cdd21c0..dd7cd81aa 100644 --- a/pkg/commands/service/vcl/snippet/describe.go +++ b/pkg/commands/service/vcl/snippet/describe.go @@ -70,13 +70,13 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { if c.Globals.Verbose() && c.JSONOutput.Enabled { return fsterr.ErrInvalidVerboseJSONCombo } - // Ensure that the --contenet flag is not used + // Ensure that the --content flag is not used // with --verbose or --json if c.Globals.Verbose() && c.content.WasSet { - return fsterr.ErrInvalidContentCombo + return fsterr.ErrInvalidContentOutputCombo } if c.JSONOutput.Enabled && c.content.WasSet { - return fsterr.ErrInvalidContentCombo + return fsterr.ErrInvalidContentOutputCombo } serviceID, serviceVersion, err := argparser.ServiceDetails(argparser.ServiceDetailsOpts{ diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index 3b25bbacd..14347a600 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -128,9 +128,9 @@ 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`.", } -// ErrInvalidContentCombo means the user provided --content along with the +// ErrInvalidContentOutputCombo means the user provided --content along with the // --verbose or --json flags, which are mutually exclusive behaviours. -var ErrInvalidContentCombo = RemediationError{ +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.", }