Skip to content
Merged
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
50 changes: 50 additions & 0 deletions internal/cmd/template/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Options struct {
file string
projectID string
skipValidation bool
vars map[string]string
}

func NewCmdDeploy(f *cmdutil.Factory) *cobra.Command {
Expand All @@ -40,6 +41,7 @@ func NewCmdDeploy(f *cmdutil.Factory) *cobra.Command {
cmd.Flags().StringVarP(&opts.file, "file", "f", "", "Template file")
cmd.Flags().StringVar(&opts.projectID, "project-id", "", "Project ID to deploy on")
cmd.Flags().BoolVar(&opts.skipValidation, "skip-validation", false, "Skip template validation")
cmd.Flags().StringToStringVar(&opts.vars, "var", nil, "Template variables (e.g. --var KEY=value)")

return cmd
}
Expand Down Expand Up @@ -118,7 +120,55 @@ func runDeploy(f *cmdutil.Factory, opts *Options) error {
}

vars := model.Map{}

// In non-interactive mode, check all required variables upfront
if !f.Interactive {
var missingVars []string
for _, v := range raw.Spec.Variables {
Comment on lines +124 to +127
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The upfront missing-variable check in non-interactive mode currently treats all template variables as required. This can break existing behavior for DOMAIN variables in region "sha1": later in the loop DOMAIN variables are explicitly skipped for sha1, but the pre-check will still fail unless the user provides --var for them. Align the pre-check with the actual per-variable handling (e.g., skip DOMAIN variables when project.Region.ID == "sha1", and generally only require vars that will actually be consumed).

Suggested change
// In non-interactive mode, check all required variables upfront
if !f.Interactive {
var missingVars []string
for _, v := range raw.Spec.Variables {
// In non-interactive mode, check all required variables upfront,
// but only for variables that will actually be consumed later.
if !f.Interactive {
var missingVars []string
for _, v := range raw.Spec.Variables {
// DOMAIN variables are skipped for region "sha1" later in the loop,
// so they should not be treated as required here either.
if project.Region != nil && project.Region.ID == "sha1" && v.Type == "DOMAIN" {
continue
}

Copilot uses AI. Check for mistakes.
if _, ok := opts.vars[v.Key]; !ok {
missingVars = append(missingVars, fmt.Sprintf(" --var %s=<value> (%s)", v.Key, v.Description))
Comment on lines +125 to +129

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip DOMAIN vars for sha1 in non-interactive precheck

In non-interactive mode this loop treats every template variable as required, but later in the same function DOMAIN variables are explicitly skipped when project.Region.ID == "sha1" (they’re not supported and the deploy proceeds without them). That means zeabur template deploy -i=false against a sha1 project will always fail with “missing required variables” if the template includes a DOMAIN variable, even though it would have been accepted interactively. Consider exempting DOMAIN vars for sha1 (or mirroring the later conditional) when building missingVars so CI deployments in that region don’t get blocked unnecessarily.

Useful? React with 👍 / 👎.

}
}
if len(missingVars) > 0 {
return fmt.Errorf("missing required variables in non-interactive mode:\n%s", strings.Join(missingVars, "\n"))
}
}

for _, v := range raw.Spec.Variables {
// Check if variable is provided via --var flag
if val, ok := opts.vars[v.Key]; ok {
// Validate DOMAIN type variables
if v.Type == "DOMAIN" {
// Skip domain validation for sha1 region
if project.Region.ID == "sha1" {
f.Log.Warnf("Selected region does not support generated domain, please bind a custom domain after template deployed.\n")
continue
}

s := spinner.New(cmdutil.SpinnerCharSet, cmdutil.SpinnerInterval,
spinner.WithColor(cmdutil.SpinnerColor),
spinner.WithSuffix(" Checking if domain "+val+".zeabur.app is available ..."),
)

s.Start()
available, _, err := f.ApiClient.CheckDomainAvailable(context.Background(), val, true, project.Region.ID)
s.Stop()

if err != nil {
return fmt.Errorf("check domain availability failed: %w", err)
}

if !available {
return fmt.Errorf("domain %s.zeabur.app is not available, please choose another one", val)
}

f.Log.Infof("Domain %s.zeabur.app is available!\n", val)
}

vars[v.Key] = val
continue
}

switch v.Type {
case "DOMAIN":
// Notice: flex shared cluster in China mainland (sha1) does not support generated domain
Expand Down
Loading