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
149 changes: 79 additions & 70 deletions cmd/servicecreate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,26 @@ import (
servicetypes "github.com/render-oss/cli/pkg/types/service"
)

var ServiceCreateCmd = &cobra.Command{
Use: "create",
Args: cobra.NoArgs,
Short: "Create a new service or clone an existing one",
Long: `Create a new service on Render. This command only runs in non-interactive modes. Provide configuration options with flags.`,
Example: ` # Create a service from repository configuration
var ServiceCreateCmd = newServiceCreateCmd()

func init() {
servicesCmd.AddCommand(ServiceCreateCmd)
}

func newServiceCreateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Args: cobra.NoArgs,
Short: "Create a new service or clone an existing one",
Long: `Create a new service on Render. This command only runs in non-interactive modes. Provide configuration options with flags.`,
Example: ` # Create a service from repository configuration
render services create --name my-api --type web_service --repo https://github.com/org/repo --runtime node --build-command "npm install" --start-command "npm start" --output json

# Clone configuration from an existing service
render services create --from srv-abc123 --name my-api-clone --output json`,
}

func init() {
servicesCmd.AddCommand(ServiceCreateCmd)
}

ServiceCreateCmd.RunE = func(cmd *cobra.Command, args []string) error {
cmd.RunE = func(cmd *cobra.Command, args []string) error {
var cliInput servicetypes.ServiceCreateInput
if err := command.ParseCommand(cmd, args, &cliInput); err != nil {
return fmt.Errorf("failed to parse command: %w", err)
Expand Down Expand Up @@ -59,69 +63,71 @@ func init() {
return fmt.Errorf("interactive mode not yet implemented")
}

ServiceCreateCmd.Flags().String("name", "", "Set the service name")
cmd.Flags().String("name", "", "Set the service name")
serviceTypeFlag := command.NewEnumInput(servicetypes.ServiceTypeValues(), false)
ServiceCreateCmd.Flags().Var(serviceTypeFlag, "type", "Set the service type")
ServiceCreateCmd.Flags().String("from", "", "Clone configuration from an existing service ID or name and override cloned values with other flags")
ServiceCreateCmd.Flags().String("repo", "", "Set the Git repository URL")
ServiceCreateCmd.Flags().String("branch", "", "Set the Git branch")
ServiceCreateCmd.Flags().String("image", "", "Set the Docker image URL")
cmd.Flags().Var(serviceTypeFlag, "type", "Set the service type")
cmd.Flags().String("from", "", "Clone configuration from an existing service ID or name and override cloned values with other flags")
cmd.Flags().String("repo", "", "Set the Git repository URL")
cmd.Flags().String("branch", "", "Set the Git branch")
cmd.Flags().String("image", "", "Set the Docker image URL")
regionFlag := command.NewEnumInput(types.RegionValues(), false)
ServiceCreateCmd.Flags().Var(regionFlag, "region", "Set the deployment region")
ServiceCreateCmd.Flags().String("plan", "", "Set the service plan")
cmd.Flags().Var(regionFlag, "region", "Set the deployment region")
cmd.Flags().String("plan", "", "Set the service plan")
runtimeFlag := command.NewEnumInput(servicetypes.ServiceRuntimeValues(), false)
ServiceCreateCmd.Flags().Var(runtimeFlag, "runtime", "Set the runtime environment")
ServiceCreateCmd.Flags().String("root-directory", "", "Set the root directory")
ServiceCreateCmd.Flags().String("build-command", "", "Set the build command")
ServiceCreateCmd.Flags().String("start-command", "", "Set the start command")
ServiceCreateCmd.Flags().String("health-check-path", "", "Set the health check path")
ServiceCreateCmd.Flags().String("publish-directory", "", "Set the publish directory")
ServiceCreateCmd.Flags().String("cron-command", "", "Set the cron command")
ServiceCreateCmd.Flags().String("cron-schedule", "", "Set the cron schedule")
ServiceCreateCmd.Flags().String("environment-id", "", "Set the environment ID")
ServiceCreateCmd.Flags().StringArray("env-var", nil, "Set environment variables in KEY=VALUE format (can be specified multiple times)")
ServiceCreateCmd.Flags().StringArray("secret-file", nil, "Set secret files in NAME:LOCAL_PATH format (can be specified multiple times)")
ServiceCreateCmd.Flags().String("registry-credential", "", "Set the registry credential")
ServiceCreateCmd.Flags().Bool("auto-deploy", true, "Enable auto-deploy")
ServiceCreateCmd.Flags().String("pre-deploy-command", "", "Set the pre-deploy command")
ServiceCreateCmd.Flags().StringArray("build-filter-path", nil, "Set build filter paths (can be specified multiple times)")
ServiceCreateCmd.Flags().StringArray("build-filter-ignored-path", nil, "Set build filter ignored paths (can be specified multiple times)")
ServiceCreateCmd.Flags().Int("num-instances", 0, "Set the number of instances")
ServiceCreateCmd.Flags().Int("max-shutdown-delay", 0, "Set max shutdown delay in seconds")
cmd.Flags().Var(runtimeFlag, "runtime", "Set the runtime environment")
cmd.Flags().String("root-directory", "", "Set the root directory")
cmd.Flags().String("build-command", "", "Set the build command")
cmd.Flags().String("start-command", "", "Set the start command")
cmd.Flags().String("health-check-path", "", "Set the health check path")
cmd.Flags().String("publish-directory", "", "Set the publish directory")
cmd.Flags().String("cron-command", "", "Set the cron command")
cmd.Flags().String("cron-schedule", "", "Set the cron schedule")
cmd.Flags().String("environment-id", "", "Set the environment ID")
cmd.Flags().StringArray("env-var", nil, "Set environment variables in KEY=VALUE format (can be specified multiple times)")
cmd.Flags().StringArray("secret-file", nil, "Set secret files in NAME:LOCAL_PATH format (can be specified multiple times)")
cmd.Flags().String("registry-credential", "", "Set the registry credential")
cmd.Flags().Bool("auto-deploy", true, "Enable auto-deploy")
cmd.Flags().String("pre-deploy-command", "", "Set the pre-deploy command")
cmd.Flags().StringArray("build-filter-path", nil, "Set build filter paths (can be specified multiple times)")
cmd.Flags().StringArray("build-filter-ignored-path", nil, "Set build filter ignored paths (can be specified multiple times)")
cmd.Flags().Int("num-instances", 0, "Set the number of instances")
cmd.Flags().Int("max-shutdown-delay", 0, "Set max shutdown delay in seconds")
previewsFlag := command.NewEnumInput(servicetypes.PreviewsGenerationValues(), false)
ServiceCreateCmd.Flags().Var(previewsFlag, "previews", "Set preview generation mode")
ServiceCreateCmd.Flags().Bool("maintenance-mode", false, "Enable maintenance mode")
ServiceCreateCmd.Flags().String("maintenance-mode-uri", "", "Set the maintenance mode URI")
ServiceCreateCmd.Flags().StringArray("ip-allow-list", nil, "Set IP allow list entries in cidr=..., description=... format (can be specified multiple times)")

setFlagPlaceholder(ServiceCreateCmd.Flags(), "name", "NAME")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "type", "TYPE")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "from", "SERVICE_ID")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "repo", "REPO_URL")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "branch", "BRANCH")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "image", "IMAGE_URL")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "region", "REGION")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "plan", "PLAN")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "runtime", "RUNTIME")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "root-directory", "PATH")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "build-command", "COMMAND")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "start-command", "COMMAND")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "health-check-path", "PATH")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "publish-directory", "PATH")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "cron-command", "COMMAND")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "cron-schedule", "SCHEDULE")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "environment-id", "ENVIRONMENT_ID")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "env-var", "KEY_VALUE")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "secret-file", "NAME_PATH")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "registry-credential", "CREDENTIAL")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "pre-deploy-command", "COMMAND")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "build-filter-path", "PATHS")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "build-filter-ignored-path", "PATHS")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "num-instances", "COUNT")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "max-shutdown-delay", "SECONDS")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "previews", "PREVIEWS")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "maintenance-mode-uri", "URI")
setFlagPlaceholder(ServiceCreateCmd.Flags(), "ip-allow-list", "CIDR_DESCRIPTION")
cmd.Flags().Var(previewsFlag, "previews", "Set preview generation mode")
cmd.Flags().Bool("maintenance-mode", false, "Enable maintenance mode")
cmd.Flags().String("maintenance-mode-uri", "", "Set the maintenance mode URI")
cmd.Flags().StringArray("ip-allow-list", nil, "Set IP allow list entries in cidr=..., description=... format (can be specified multiple times)")

setFlagPlaceholder(cmd.Flags(), "name", "NAME")
setFlagPlaceholder(cmd.Flags(), "type", "TYPE")
setFlagPlaceholder(cmd.Flags(), "from", "SERVICE_ID")
setFlagPlaceholder(cmd.Flags(), "repo", "REPO_URL")
setFlagPlaceholder(cmd.Flags(), "branch", "BRANCH")
setFlagPlaceholder(cmd.Flags(), "image", "IMAGE_URL")
setFlagPlaceholder(cmd.Flags(), "region", "REGION")
setFlagPlaceholder(cmd.Flags(), "plan", "PLAN")
setFlagPlaceholder(cmd.Flags(), "runtime", "RUNTIME")
setFlagPlaceholder(cmd.Flags(), "root-directory", "PATH")
setFlagPlaceholder(cmd.Flags(), "build-command", "COMMAND")
setFlagPlaceholder(cmd.Flags(), "start-command", "COMMAND")
setFlagPlaceholder(cmd.Flags(), "health-check-path", "PATH")
setFlagPlaceholder(cmd.Flags(), "publish-directory", "PATH")
setFlagPlaceholder(cmd.Flags(), "cron-command", "COMMAND")
setFlagPlaceholder(cmd.Flags(), "cron-schedule", "SCHEDULE")
setFlagPlaceholder(cmd.Flags(), "environment-id", "ENVIRONMENT_ID")
setFlagPlaceholder(cmd.Flags(), "env-var", "KEY_VALUE")
setFlagPlaceholder(cmd.Flags(), "secret-file", "NAME_PATH")
setFlagPlaceholder(cmd.Flags(), "registry-credential", "CREDENTIAL")
setFlagPlaceholder(cmd.Flags(), "pre-deploy-command", "COMMAND")
setFlagPlaceholder(cmd.Flags(), "build-filter-path", "PATHS")
setFlagPlaceholder(cmd.Flags(), "build-filter-ignored-path", "PATHS")
setFlagPlaceholder(cmd.Flags(), "num-instances", "COUNT")
setFlagPlaceholder(cmd.Flags(), "max-shutdown-delay", "SECONDS")
setFlagPlaceholder(cmd.Flags(), "previews", "PREVIEWS")
setFlagPlaceholder(cmd.Flags(), "maintenance-mode-uri", "URI")
setFlagPlaceholder(cmd.Flags(), "ip-allow-list", "CIDR_DESCRIPTION")

return cmd
}

func createServiceNonInteractive(ctx context.Context, cliInput servicetypes.ServiceCreateInput) (*client.Service, error) {
Expand All @@ -134,9 +140,12 @@ func createServiceNonInteractive(ctx context.Context, cliInput servicetypes.Serv
return nil, err
}

rawInput := cliInput
cliInput = servicetypes.NormalizeServiceCreateCLIInput(cliInput)

if cliInput.From != nil {
// A blank clearable flag replaces the source's value instead of inheriting it.
cliInput = servicetypes.NormalizeServiceCloneCLIInput(rawInput)
if err := getConfigFromService(ctx, serviceRepo, &cliInput); err != nil {
return nil, fmt.Errorf("failed to clone configuration from source service %q: %w", *cliInput.From, err)
}
Expand Down
Loading