diff --git a/commands/apps.go b/commands/apps.go index fa3f3e190..32eccbdfd 100644 --- a/commands/apps.go +++ b/commands/apps.go @@ -704,9 +704,9 @@ Optionally, pass a deployment ID to get the spec of that specific deployment.`, AddStringFlag(getCmd, doctl.ArgAppDeployment, "", "", "optional: a deployment ID") AddStringFlag(getCmd, doctl.ArgFormat, "", "yaml", `the format to output the spec in; either "yaml" or "json"`) - validateCmd := CmdBuilder(cmd, RunAppsSpecValidate, "validate ", "Validate an application spec", `Use this command to check whether a given app spec (YAML or JSON) is valid. + validateCmd := cmdBuilderWithInit(cmd, RunAppsSpecValidate, "validate ", "Validate an application spec", `Use this command to check whether a given app spec (YAML or JSON) is valid. -You may pass - as the filename to read from stdin.`, Writer) +You may pass - as the filename to read from stdin.`, Writer, false) AddBoolFlag(validateCmd, doctl.ArgSchemaOnly, "", false, "Only validate the spec schema and not the correctness of the spec.") return cmd @@ -762,6 +762,7 @@ func RunAppsSpecGet(c *CmdConfig) error { } // RunAppsSpecValidate validates an app spec file +// doesn't require auth & connection to the API with doctl.ArgSchemaOnly flag func RunAppsSpecValidate(c *CmdConfig) error { if len(c.Args) < 1 { return doctl.NewMissingArgsErr(c.NS) @@ -778,6 +779,7 @@ func RunAppsSpecValidate(c *CmdConfig) error { return err } + // validate schema only (offline) if schemaOnly { ymlSpec, err := yaml.Marshal(appSpec) if err != nil { @@ -787,6 +789,10 @@ func RunAppsSpecValidate(c *CmdConfig) error { return err } + // validate the spec against the API + if err := c.initServices(c); err != nil { + return err + } res, err := c.Apps().Propose(&godo.AppProposeRequest{ Spec: appSpec, }) diff --git a/integration/apps_spec_test.go b/integration/apps_spec_test.go index 2b74fe156..d32cd5441 100644 --- a/integration/apps_spec_test.go +++ b/integration/apps_spec_test.go @@ -197,6 +197,24 @@ var _ = suite("apps/spec/validate", func(t *testing.T, when spec.G, it spec.S) { expect.Equal(expectedOutput, strings.TrimSpace(string(output))) }) + it("schema-only works without auth", func() { + cmd := exec.Command(builtBinaryPath, + "-u", server.URL, + "apps", "spec", "validate", + "--schema-only", "-", + ) + byt, err := json.Marshal(testAppSpec) + expect.NoError(err) + + cmd.Stdin = bytes.NewReader(byt) + + output, err := cmd.CombinedOutput() + expect.NoError(err) + + expectedOutput := "name: test\nservices:\n- github:\n branch: main\n repo: digitalocean/doctl\n name: service" + expect.Equal(expectedOutput, strings.TrimSpace(string(output))) + }) + it("calls proposeapp", func() { cmd := exec.Command(builtBinaryPath, "-t", "some-magic-token",