github.com/supabase/cli@v1.168.1/internal/projects/create/create.go (about)

     1  package create
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/go-errors/errors"
    10  	"github.com/spf13/afero"
    11  	"github.com/spf13/viper"
    12  	"github.com/supabase/cli/internal/utils"
    13  	"github.com/supabase/cli/internal/utils/credentials"
    14  	"github.com/supabase/cli/internal/utils/flags"
    15  	"github.com/supabase/cli/pkg/api"
    16  )
    17  
    18  func Run(ctx context.Context, params api.V1CreateProjectBody, fsys afero.Fs) error {
    19  	if err := promptMissingParams(ctx, &params); err != nil {
    20  		return err
    21  	}
    22  
    23  	resp, err := utils.GetSupabase().CreateProjectWithResponse(ctx, params)
    24  	if err != nil {
    25  		return errors.Errorf("failed to create project: %w", err)
    26  	}
    27  	if resp.JSON201 == nil {
    28  		return errors.New("Unexpected error creating project: " + string(resp.Body))
    29  	}
    30  
    31  	flags.ProjectRef = resp.JSON201.Id
    32  	viper.Set("DB_PASSWORD", params.DbPass)
    33  	if err := credentials.Set(flags.ProjectRef, params.DbPass); err != nil {
    34  		fmt.Fprintln(os.Stderr, "Failed to save database password:", err)
    35  	}
    36  
    37  	projectUrl := fmt.Sprintf("%s/project/%s", utils.GetSupabaseDashboardURL(), resp.JSON201.Id)
    38  	fmt.Printf("Created a new project %s at %s\n", utils.Aqua(resp.JSON201.Name), utils.Bold(projectUrl))
    39  	return nil
    40  }
    41  
    42  func printKeyValue(key, value string) string {
    43  	indent := 20 - len(key)
    44  	spaces := strings.Repeat(" ", indent)
    45  	return key + ":" + spaces + value
    46  }
    47  
    48  func promptMissingParams(ctx context.Context, body *api.V1CreateProjectBody) error {
    49  	var err error
    50  	if len(body.Name) == 0 {
    51  		if body.Name, err = promptProjectName(); err != nil {
    52  			return err
    53  		}
    54  	} else {
    55  		fmt.Fprintln(os.Stderr, printKeyValue("Creating project", body.Name))
    56  	}
    57  	if len(body.OrganizationId) == 0 {
    58  		if body.OrganizationId, err = promptOrgId(ctx); err != nil {
    59  			return err
    60  		}
    61  		fmt.Fprintln(os.Stderr, printKeyValue("Selected org-id", body.OrganizationId))
    62  	}
    63  	if len(body.Region) == 0 {
    64  		if body.Region, err = promptProjectRegion(ctx); err != nil {
    65  			return err
    66  		}
    67  		fmt.Fprintln(os.Stderr, printKeyValue("Selected region", string(body.Region)))
    68  	}
    69  	if len(body.DbPass) == 0 {
    70  		body.DbPass = flags.PromptPassword(os.Stdin)
    71  	}
    72  	return nil
    73  }
    74  
    75  func promptProjectName() (string, error) {
    76  	title := "Enter your project name: "
    77  	if name := utils.NewConsole().PromptText(title); len(name) > 0 {
    78  		return name, nil
    79  	}
    80  	return "", errors.New("project name cannot be empty")
    81  }
    82  
    83  func promptOrgId(ctx context.Context) (string, error) {
    84  	title := "Which organisation do you want to create the project for?"
    85  	resp, err := utils.GetSupabase().GetOrganizationsWithResponse(ctx)
    86  	if err != nil {
    87  		return "", err
    88  	}
    89  	if resp.JSON200 == nil {
    90  		return "", errors.New("Unexpected error retrieving organizations: " + string(resp.Body))
    91  	}
    92  	items := make([]utils.PromptItem, len(*resp.JSON200))
    93  	for i, org := range *resp.JSON200 {
    94  		items[i] = utils.PromptItem{Summary: org.Name, Details: org.Id}
    95  	}
    96  	choice, err := utils.PromptChoice(ctx, title, items)
    97  	if err != nil {
    98  		return "", err
    99  	}
   100  	return choice.Details, nil
   101  }
   102  
   103  func promptProjectRegion(ctx context.Context) (api.V1CreateProjectBodyRegion, error) {
   104  	title := "Which region do you want to host the project in?"
   105  	items := make([]utils.PromptItem, len(utils.RegionMap))
   106  	i := 0
   107  	for k, v := range utils.RegionMap {
   108  		items[i] = utils.PromptItem{Summary: k, Details: v}
   109  		i++
   110  	}
   111  	choice, err := utils.PromptChoice(ctx, title, items)
   112  	if err != nil {
   113  		return "", err
   114  	}
   115  	return api.V1CreateProjectBodyRegion(choice.Summary), nil
   116  }