diff --git a/CHANGELOG.md b/CHANGELOG.md index b5682bbd2..9fc0ba451 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - feat(rust): Allow testing with prerelease Rust versions ([#1604](https://github.com/fastly/cli/pull/1604)) - feat(compute/hashfiles): remove hashsum subcommand ([#1608](https://github.com/fastly/cli/pull/1608)) - feat(commands/ngwaf/rules): add support for CRUD operations for NGWAF rules ([#1578](https://github.com/fastly/cli/pull/1605)) +- feat(compute/deploy): added the `--no-default-domain` flag to allow for the skipping of automatic domain creation when deploying a Compute service([#1610](https://github.com/fastly/cli/pull/1610)) ### Bug fixes: diff --git a/pkg/commands/compute/deploy.go b/pkg/commands/compute/deploy.go index eecf3646b..773950951 100644 --- a/pkg/commands/compute/deploy.go +++ b/pkg/commands/compute/deploy.go @@ -53,6 +53,7 @@ type DeployCommand struct { Dir string Domain string Env string + NoDefaultDomain argparser.OptionalBool PackagePath string ServiceName argparser.OptionalServiceNameID ServiceVersion argparser.OptionalServiceVersion @@ -93,6 +94,7 @@ func NewDeployCommand(parent argparser.Registerer, g *global.Data) *DeployComman c.CmdClause.Flag("dir", "Project directory (default: current directory)").Short('C').StringVar(&c.Dir) c.CmdClause.Flag("domain", "The name of the domain associated to the package").StringVar(&c.Domain) c.CmdClause.Flag("env", "The manifest environment config to use (e.g. 'stage' will attempt to read 'fastly.stage.toml')").StringVar(&c.Env) + c.CmdClause.Flag("no-default-domain", "Skip default domain creation").Action(c.NoDefaultDomain.Set).BoolVar(&c.NoDefaultDomain.Value) c.CmdClause.Flag("package", "Path to a package tar.gz").Short('p').StringVar(&c.PackagePath) c.CmdClause.Flag("status-check-code", "Set the expected status response for the service availability check").IntVar(&c.StatusCheckCode) c.CmdClause.Flag("status-check-off", "Disable the service availability check").BoolVar(&c.StatusCheckOff) @@ -233,16 +235,17 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) { // It's part of the implementation so that we can utilise the same interface. // A domain is required regardless of whether it's a new service or existing. sr.domains = &setup.Domains{ - APIClient: c.Globals.APIClient, - AcceptDefaults: c.Globals.Flags.AcceptDefaults, - NonInteractive: c.Globals.Flags.NonInteractive, - PackageDomain: c.Domain, - RetryLimit: 5, - ServiceID: serviceID, - ServiceVersion: serviceVersionNumber, - Stdin: in, - Stdout: out, - Verbose: c.Globals.Verbose(), + APIClient: c.Globals.APIClient, + AcceptDefaults: c.Globals.Flags.AcceptDefaults, + NoDefaultDomain: c.NoDefaultDomain.WasSet, + NonInteractive: c.Globals.Flags.NonInteractive, + PackageDomain: c.Domain, + RetryLimit: 5, + ServiceID: serviceID, + ServiceVersion: serviceVersionNumber, + Stdin: in, + Stdout: out, + Verbose: c.Globals.Verbose(), } if err = sr.domains.Validate(); err != nil { errLogService(c.Globals.ErrLog, err, serviceID, serviceVersionNumber) @@ -304,7 +307,7 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - if !c.StatusCheckOff && noExistingService { + if !c.StatusCheckOff && noExistingService && serviceURL != "" { c.StatusCheck(serviceURL, spinner, out) } @@ -345,7 +348,9 @@ func (c *DeployCommand) StatusCheck(serviceURL string, spinner text.Spinner, out func displayDeployOutput(out io.Writer, manageServiceBaseURL, serviceID, serviceURL string, serviceVersion int) { text.Description(out, "Manage this service at", fmt.Sprintf("%s%s", manageServiceBaseURL, serviceID)) - text.Description(out, "View this service at", serviceURL) + if serviceURL != "" { + text.Description(out, "View this service at", serviceURL) + } text.Success(out, "Deployed package (service %s, version %v)", serviceID, serviceVersion) } @@ -1065,6 +1070,9 @@ func (c *DeployCommand) GetServiceURL(serviceID string, serviceVersion int) (str if err != nil { return "", err } + if len(latestDomains) == 0 { + return "", nil + } name := fastly.ToValue(latestDomains[0].Name) if segs := strings.Split(name, "*."); len(segs) > 1 { name = segs[1] diff --git a/pkg/commands/compute/deploy_test.go b/pkg/commands/compute/deploy_test.go index 441b0c1e1..890e358f6 100644 --- a/pkg/commands/compute/deploy_test.go +++ b/pkg/commands/compute/deploy_test.go @@ -697,6 +697,79 @@ func TestDeploy(t *testing.T) { "Deployed package (service 123, version 4)", }, }, + { + name: "success with --no-default-domain flag for new service", + args: args("compute deploy --no-default-domain --token 123"), + api: mock.API{ + ActivateVersionFn: activateVersionOk, + CreateBackendFn: createBackendOK, + CreateServiceFn: createServiceOK, + DeleteServiceFn: deleteServiceOK, + GetPackageFn: getPackageOk, + ListDomainsFn: listDomainsNone, + UpdatePackageFn: updatePackageOk, + }, + stdin: []string{ + "Y", // when prompted to create a new service + }, + wantOutput: []string{ + "Deployed package (service 12345, version 1)", + }, + dontWantOutput: []string{ + "Creating domain", + "Domain:", + }, + }, + { + name: "success with --no-default-domain but explicit --domain provided", + args: args("compute deploy --token 123 --no-default-domain --domain example.com"), + api: mock.API{ + ActivateVersionFn: activateVersionOk, + CreateBackendFn: createBackendOK, + CreateDomainFn: createDomainOK, + CreateServiceFn: createServiceOK, + GetPackageFn: getPackageOk, + ListDomainsFn: listDomainsNone, + UpdatePackageFn: updatePackageOk, + }, + httpClientRes: []*http.Response{ + mock.NewHTTPResponse(http.StatusNoContent, nil, nil), + mock.NewHTTPResponse(http.StatusOK, nil, io.NopCloser(strings.NewReader("success"))), + }, + httpClientErr: []error{ + nil, + nil, + }, + stdin: []string{ + "Y", // when prompted to create a new service + }, + wantOutput: []string{ + "Creating domain 'example.com'", + "Deployed package (service 12345, version 1)", + }, + }, + { + name: "success with --no-default-domain and existing service", + args: args("compute deploy --service-id 123 --token 123 --no-default-domain"), + api: mock.API{ + ActivateVersionFn: activateVersionOk, + CloneVersionFn: testutil.CloneVersionResult(4), + GetPackageFn: getPackageOk, + GetServiceDetailsFn: getServiceDetailsWasm, + GetServiceFn: getServiceOK, + ListDomainsFn: listDomainsOk, + ListVersionsFn: testutil.ListVersions, + UpdatePackageFn: updatePackageOk, + }, + wantOutput: []string{ + "Uploading package", + "Activating service", + "Deployed package (service 123, version 4)", + }, + dontWantOutput: []string{ + "Creating domain", + }, + }, // The following test doesn't provide a Service ID by either a flag nor the // manifest, so this will result in the deploy script attempting to create // a new service. Our fastly.toml is configured with a [setup] section so diff --git a/pkg/commands/compute/publish.go b/pkg/commands/compute/publish.go index 88e6710c6..5d4cb5815 100644 --- a/pkg/commands/compute/publish.go +++ b/pkg/commands/compute/publish.go @@ -30,6 +30,7 @@ type PublishCommand struct { comment argparser.OptionalString domain argparser.OptionalString env argparser.OptionalString + noDefaultDomain argparser.OptionalBool pkg argparser.OptionalString serviceName argparser.OptionalServiceNameID serviceVersion argparser.OptionalServiceVersion @@ -55,6 +56,7 @@ func NewPublishCommand(parent argparser.Registerer, g *global.Data, build *Build c.CmdClause.Flag("domain", "The name of the domain associated to the package").Action(c.domain.Set).StringVar(&c.domain.Value) c.CmdClause.Flag("env", "The manifest environment config to use (e.g. 'stage' will attempt to read 'fastly.stage.toml')").Action(c.env.Set).StringVar(&c.env.Value) c.CmdClause.Flag("include-source", "Include source code in built package").Action(c.includeSrc.Set).BoolVar(&c.includeSrc.Value) + c.CmdClause.Flag("no-default-domain", "Skip default domain creation").Action(c.noDefaultDomain.Set).BoolVar(&c.noDefaultDomain.Value) c.CmdClause.Flag("language", "Language type").Action(c.lang.Set).StringVar(&c.lang.Value) c.CmdClause.Flag("metadata-disable", "Disable Wasm binary metadata annotations").Action(c.metadataDisable.Set).BoolVar(&c.metadataDisable.Value) c.CmdClause.Flag("metadata-filter-envvars", "Redact specified environment variables from [scripts.env_vars] using comma-separated list").Action(c.metadataFilterEnvVars.Set).StringVar(&c.metadataFilterEnvVars.Value) @@ -187,6 +189,9 @@ func (c *PublishCommand) Deploy(in io.Reader, out io.Writer) error { if c.env.WasSet { c.deploy.Env = c.env.Value } + if c.noDefaultDomain.WasSet { + c.deploy.NoDefaultDomain = c.noDefaultDomain + } if c.comment.WasSet { c.deploy.Comment = c.comment } diff --git a/pkg/commands/compute/setup/domain.go b/pkg/commands/compute/setup/domain.go index 8791ebd80..e6452b33d 100644 --- a/pkg/commands/compute/setup/domain.go +++ b/pkg/commands/compute/setup/domain.go @@ -26,17 +26,18 @@ var domainNameRegEx = regexp.MustCompile(`(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9]) // NOTE: It implements the setup.Interface interface. type Domains struct { // Public - APIClient api.Interface - AcceptDefaults bool - NonInteractive bool - PackageDomain string - Spinner text.Spinner - RetryLimit int - ServiceID string - ServiceVersion int - Stdin io.Reader - Stdout io.Writer - Verbose bool + APIClient api.Interface + AcceptDefaults bool + NoDefaultDomain bool + NonInteractive bool + PackageDomain string + Spinner text.Spinner + RetryLimit int + ServiceID string + ServiceVersion int + Stdin io.Reader + Stdout io.Writer + Verbose bool // Private available []*fastly.Domain @@ -54,6 +55,12 @@ type Domain struct { // // NOTE: If --domain flag is used we'll use that as the domain to create. func (d *Domains) Configure() error { + // Don't generate a domain if --no-default-domain is set and no domain is provided + if d.NoDefaultDomain && d.PackageDomain == "" { + d.missing = false + return nil + } + // PackageDomain is the --domain flag value. if d.PackageDomain != "" { d.required = append(d.required, Domain{ @@ -134,7 +141,10 @@ func (d *Domains) Validate() error { } d.available = available if len(d.available) == 0 { - d.missing = true + // Only mark as missing if we're not intentionally skipping domain creation + if !d.NoDefaultDomain || d.PackageDomain != "" { + d.missing = true + } } return nil }