Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
### Enhancements:

- feat(service/backend): Add support for IAM authentication ([#1963](https://github.com/fastly/cli/pull/1963))
- feat(vcl): add `vcl check`, `vcl run`, and `vcl serve` to compile and test VCL code ([#1964](https://github.com/fastly/cli/pull/1964))

### Dependencies:

Expand Down
2 changes: 2 additions & 0 deletions pkg/app/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,8 @@ func commandRequiresToken(command argparser.Command) bool {
return false
case "compute build", "compute hash-files", "compute install-tools", "compute metadata", "compute pack", "compute serve", "compute validate":
return false
case "vcl check", "vcl run", "vcl serve":
return false
}
commandName = strings.Split(commandName, " ")[0]
switch commandName {
Expand Down
1 change: 1 addition & 0 deletions pkg/app/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ update
user
version
whoami
vcl
`,
},
}
Expand Down
17 changes: 12 additions & 5 deletions pkg/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ import (
domainTools "github.com/fastly/cli/pkg/commands/tools/domain"
"github.com/fastly/cli/pkg/commands/update"
"github.com/fastly/cli/pkg/commands/user"
vcltesting "github.com/fastly/cli/pkg/commands/vcl"
"github.com/fastly/cli/pkg/commands/version"
"github.com/fastly/cli/pkg/commands/whoami"
"github.com/fastly/cli/pkg/env"
Expand Down Expand Up @@ -1043,21 +1044,24 @@ func Define( // nolint:revive // function-length
aliasServiceAuthDescribe := aliasserviceauth.NewDescribeCommand(aliasServiceAuthRoot.CmdClause, data)
aliasServiceAuthList := aliasserviceauth.NewListCommand(aliasServiceAuthRoot.CmdClause, data)
aliasServiceAuthUpdate := aliasserviceauth.NewUpdateCommand(aliasServiceAuthRoot.CmdClause, data)
aliasVclRoot := aliasvcl.NewRootCommand(app, data)
aliasVclDescribe := aliasvcl.NewDescribeCommand(aliasVclRoot.CmdClause, data)
aliasVclConditionRoot := aliasvclcondition.NewRootCommand(aliasVclRoot.CmdClause, data)
vclRoot := vcltesting.NewRootCommand(app, data)
vclCheck := vcltesting.NewCheckCommand(vclRoot.CmdClause, data)
vclRun := vcltesting.NewRunCommand(vclRoot.CmdClause, data)
vclServe := vcltesting.NewServeCommand(vclRoot.CmdClause, data)
aliasVclDescribe := aliasvcl.NewDescribeCommand(vclRoot.CmdClause, data)
aliasVclConditionRoot := aliasvclcondition.NewRootCommand(vclRoot.CmdClause, data)
aliasVclConditionCreate := aliasvclcondition.NewCreateCommand(aliasVclConditionRoot.CmdClause, data)
aliasVclConditionDelete := aliasvclcondition.NewDeleteCommand(aliasVclConditionRoot.CmdClause, data)
aliasVclConditionDescribe := aliasvclcondition.NewDescribeCommand(aliasVclConditionRoot.CmdClause, data)
aliasVclConditionList := aliasvclcondition.NewListCommand(aliasVclConditionRoot.CmdClause, data)
aliasVclConditionUpdate := aliasvclcondition.NewUpdateCommand(aliasVclConditionRoot.CmdClause, data)
aliasVclCustomRoot := aliasvclcustom.NewRootCommand(aliasVclRoot.CmdClause, data)
aliasVclCustomRoot := aliasvclcustom.NewRootCommand(vclRoot.CmdClause, data)
aliasVclCustomCreate := aliasvclcustom.NewCreateCommand(aliasVclCustomRoot.CmdClause, data)
aliasVclCustomDelete := aliasvclcustom.NewDeleteCommand(aliasVclCustomRoot.CmdClause, data)
aliasVclCustomDescribe := aliasvclcustom.NewDescribeCommand(aliasVclCustomRoot.CmdClause, data)
aliasVclCustomList := aliasvclcustom.NewListCommand(aliasVclCustomRoot.CmdClause, data)
aliasVclCustomUpdate := aliasvclcustom.NewUpdateCommand(aliasVclCustomRoot.CmdClause, data)
aliasVclSnippetRoot := aliasvclsnippet.NewRootCommand(aliasVclRoot.CmdClause, data)
aliasVclSnippetRoot := aliasvclsnippet.NewRootCommand(vclRoot.CmdClause, data)
aliasVclSnippetCreate := aliasvclsnippet.NewCreateCommand(aliasVclSnippetRoot.CmdClause, data)
aliasVclSnippetDelete := aliasvclsnippet.NewDeleteCommand(aliasVclSnippetRoot.CmdClause, data)
aliasVclSnippetDescribe := aliasvclsnippet.NewDescribeCommand(aliasVclSnippetRoot.CmdClause, data)
Expand Down Expand Up @@ -2012,6 +2016,9 @@ func Define( // nolint:revive // function-length
aliasServiceAuthDescribe,
aliasServiceAuthList,
aliasServiceAuthUpdate,
vclCheck,
vclRun,
vclServe,
aliasVclDescribe,
aliasVclConditionCreate,
aliasVclConditionDelete,
Expand Down
70 changes: 70 additions & 0 deletions pkg/commands/vcl/check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package vcl

import (
"context"
"io"

"github.com/fastly/cli/pkg/argparser"
"github.com/fastly/cli/pkg/global"
"github.com/fastly/cli/pkg/text"
)

// CheckCommand compiles VCL with the real Fastly compiler and reports any problems, without running it.
type CheckCommand struct {
argparser.Base
argparser.JSONOutput

spec specFlags
files []string
}

// NewCheckCommand returns a usable command registered under the parent.
func NewCheckCommand(parent argparser.Registerer, g *global.Data) *CheckCommand {
c := CheckCommand{
Base: argparser.Base{
Globals: g,
SuppressVerbose: true,
},
}
c.CmdClause = parent.Command("check", "Check that VCL compiles, using the real Fastly VCL compiler (no service or API token needed)")

// Optional.
c.CmdClause.Arg("file", "VCL files holding subroutine bodies, named after their subroutine (recv.vcl, fetch.vcl, ...)").StringsVar(&c.files)
c.spec.register(c.CmdClause)
c.RegisterFlagBool(c.JSONFlag()) // --json
return &c
}

// Exec invokes the application logic for the command.
func (c *CheckCommand) Exec(_ io.Reader, out io.Writer) error {
vcl, sources, err := c.spec.buildVCL(c.files)
if err != nil {
return err
}
origins, err := c.spec.buildOrigins()
if err != nil {
return err
}

state := loadSandboxState(c.Globals)
saved, err := publish(context.Background(), c.spec.client(c.Globals), newSpec(origins, vcl), &state)
if err != nil {
c.Globals.ErrLog.Add(err)
return err
}

diags := flattenDiagnostics(saved.LintStatus, sources)
if ok, err := c.WriteJSON(out, compileResult{saved.Valid, diags}); ok {
if err == nil && !saved.Valid {
return errCompileFailed
}
return err
}

printDiagnostics(out, diags)
if !saved.Valid {
return errCompileFailed
}
text.Success(out, "VCL compiled cleanly.")
return nil
}
Loading
Loading