@@ -91,7 +91,7 @@ func Execute(ctx context.Context) error {
9191
9292 if strings .Contains (err .Error (), "maximum number of projects" ) {
9393 projectName := "<name>"
94- provider , err := getProvider (ctx )
94+ provider , err := getProvider (ctx , nil )
9595 if err != nil {
9696 return err
9797 }
@@ -385,7 +385,8 @@ var whoamiCmd = &cobra.Command{
385385 Args : cobra .NoArgs ,
386386 Short : "Show the current user" ,
387387 RunE : func (cmd * cobra.Command , args []string ) error {
388- provider , err := getProvider (cmd .Context ())
388+ loader := configureLoader (cmd )
389+ provider , err := getProvider (cmd .Context (), loader )
389390 if err != nil {
390391 return err
391392 }
@@ -412,7 +413,7 @@ var certGenerateCmd = &cobra.Command{
412413 Short : "Generate a TLS certificate" ,
413414 RunE : func (cmd * cobra.Command , args []string ) error {
414415 loader := configureLoader (cmd )
415- provider , err := getProvider (cmd .Context ())
416+ provider , err := getProvider (cmd .Context (), loader )
416417 if err != nil {
417418 return err
418419 }
@@ -660,7 +661,7 @@ var configSetCmd = &cobra.Command{
660661
661662 // Make sure we have a project to set config for before asking for a value
662663 loader := configureLoader (cmd )
663- provider , err := getProvider (cmd .Context ())
664+ provider , err := getProvider (cmd .Context (), loader )
664665 if err != nil {
665666 return err
666667 }
@@ -737,7 +738,7 @@ var configDeleteCmd = &cobra.Command{
737738 Short : "Removes one or more config values" ,
738739 RunE : func (cmd * cobra.Command , names []string ) error {
739740 loader := configureLoader (cmd )
740- provider , err := getProvider (cmd .Context ())
741+ provider , err := getProvider (cmd .Context (), loader )
741742 if err != nil {
742743 return err
743744 }
@@ -764,7 +765,7 @@ var configListCmd = &cobra.Command{
764765 Short : "List configs" ,
765766 RunE : func (cmd * cobra.Command , args []string ) error {
766767 loader := configureLoader (cmd )
767- provider , err := getProvider (cmd .Context ())
768+ provider , err := getProvider (cmd .Context (), loader )
768769 if err != nil {
769770 return err
770771 }
@@ -781,7 +782,7 @@ var debugCmd = &cobra.Command{
781782 etag , _ := cmd .Flags ().GetString ("etag" )
782783
783784 loader := configureLoader (cmd )
784- provider , err := getProvider (cmd .Context ())
785+ provider , err := getProvider (cmd .Context (), loader )
785786 if err != nil {
786787 return err
787788 }
@@ -800,7 +801,7 @@ var deleteCmd = &cobra.Command{
800801 var tail , _ = cmd .Flags ().GetBool ("tail" )
801802
802803 loader := configureLoader (cmd )
803- provider , err := getProvider (cmd .Context ())
804+ provider , err := getProvider (cmd .Context (), loader )
804805 if err != nil {
805806 return err
806807 }
@@ -902,7 +903,7 @@ var cdDestroyCmd = &cobra.Command{
902903 Short : "Destroy the service stack" ,
903904 RunE : func (cmd * cobra.Command , args []string ) error {
904905 loader := configureLoader (cmd )
905- provider , err := getProvider (cmd .Context ())
906+ provider , err := getProvider (cmd .Context (), loader )
906907 if err != nil {
907908 return err
908909 }
@@ -916,7 +917,7 @@ var cdDownCmd = &cobra.Command{
916917 Short : "Refresh and then destroy the service stack" ,
917918 RunE : func (cmd * cobra.Command , args []string ) error {
918919 loader := configureLoader (cmd )
919- provider , err := getProvider (cmd .Context ())
920+ provider , err := getProvider (cmd .Context (), loader )
920921 if err != nil {
921922 return err
922923 }
@@ -930,7 +931,7 @@ var cdRefreshCmd = &cobra.Command{
930931 Short : "Refresh the service stack" ,
931932 RunE : func (cmd * cobra.Command , args []string ) error {
932933 loader := configureLoader (cmd )
933- provider , err := getProvider (cmd .Context ())
934+ provider , err := getProvider (cmd .Context (), loader )
934935 if err != nil {
935936 return err
936937 }
@@ -944,7 +945,7 @@ var cdCancelCmd = &cobra.Command{
944945 Short : "Cancel the current CD operation" ,
945946 RunE : func (cmd * cobra.Command , args []string ) error {
946947 loader := configureLoader (cmd )
947- provider , err := getProvider (cmd .Context ())
948+ provider , err := getProvider (cmd .Context (), loader )
948949 if err != nil {
949950 return err
950951 }
@@ -959,7 +960,8 @@ var cdTearDownCmd = &cobra.Command{
959960 RunE : func (cmd * cobra.Command , args []string ) error {
960961 force , _ := cmd .Flags ().GetBool ("force" )
961962
962- provider , err := getProvider (cmd .Context ())
963+ loader := configureLoader (cmd )
964+ provider , err := getProvider (cmd .Context (), loader )
963965 if err != nil {
964966 return err
965967 }
@@ -976,7 +978,7 @@ var cdListCmd = &cobra.Command{
976978 remote , _ := cmd .Flags ().GetBool ("remote" )
977979
978980 loader := configureLoader (cmd )
979- provider , err := getProvider (cmd .Context ())
981+ provider , err := getProvider (cmd .Context (), loader )
980982 if err != nil {
981983 return err
982984 }
@@ -994,7 +996,7 @@ var cdPreviewCmd = &cobra.Command{
994996 Short : "Preview the changes that will be made by the CD task" ,
995997 RunE : func (cmd * cobra.Command , args []string ) error {
996998 loader := configureLoader (cmd )
997- provider , err := getProvider (cmd .Context ())
999+ provider , err := getProvider (cmd .Context (), loader )
9981000 if err != nil {
9991001 return err
10001002 }
@@ -1076,30 +1078,29 @@ var providerDescription = map[cliClient.ProviderID]string{
10761078 cliClient .ProviderDO : "Deploy to DigitalOcean using the DIGITALOCEAN_TOKEN, SPACES_ACCESS_KEY_ID, and SPACES_SECRET_ACCESS_KEY environment variables." ,
10771079}
10781080
1079- func getProvider (ctx context.Context ) (cliClient.Provider , error ) {
1081+ func getProvider (ctx context.Context , loader * compose.Loader ) (cliClient.Provider , error ) {
1082+ extraMsg := ""
1083+ source := ""
1084+
1085+ if val , ok := os .LookupEnv ("DEFANG_PROVIDER" ); ok && val == providerID .String () {
1086+ // Sanitize the provider value from the environment variable
1087+ if err := providerID .Set (val ); err != nil {
1088+ return nil , fmt .Errorf ("invalid provider '%v' in environment variable DEFANG_PROVIDER, supported providers are: %v" , val , cliClient .AllProviders ())
1089+ }
1090+ source = "environment variable"
1091+ }
1092+
1093+ if RootCmd .PersistentFlags ().Changed ("provider" ) {
1094+ source = "command line flag"
1095+ }
1096+
10801097 switch providerID {
10811098 case cliClient .ProviderAuto :
10821099 if ! nonInteractive {
1083- // Prompt the user to choose a provider if in interactive mode
1084- options := []string {}
1085- for _ , p := range cliClient .AllProviders () {
1086- options = append (options , p .String ())
1087- }
1088- var optionValue string
1089- if err := survey .AskOne (& survey.Select {
1090- Message : "Choose a cloud provider:" ,
1091- Options : options ,
1092- Help : "The provider you choose will be used for deploying services." ,
1093- Description : func (value string , i int ) string {
1094- return providerDescription [cliClient .ProviderID (value )]
1095- },
1096- }, & optionValue ); err != nil {
1100+ var err error
1101+ if source , err = determineProviderID (ctx , loader ); err != nil {
10971102 return nil , err
10981103 }
1099- if err := providerID .Set (optionValue ); err != nil {
1100- panic (err )
1101- }
1102- term .Printf ("To skip this prompt, set the DEFANG_PROVIDER=%s in your environment, or use:\n \n defang --provider=%s\n \n " , optionValue , optionValue )
11031104 } else {
11041105 // Defaults to defang provider in non-interactive mode
11051106 if awsInEnv () {
@@ -1120,8 +1121,58 @@ func getProvider(ctx context.Context) (cliClient.Provider, error) {
11201121 }
11211122 case cliClient .ProviderDefang :
11221123 // Ignore any env vars when explicitly using the Defang playground provider
1124+ extraMsg = "; consider using BYOC (https://s.defang.io/byoc)"
11231125 }
11241126
1125- provider := cli .NewProvider (ctx , providerID , client )
1127+ term .Infof ("Using %s provider from %s%s" , providerID .Name (), source , extraMsg )
1128+ provider , err := cli .NewProvider (ctx , providerID , client )
1129+ if err != nil {
1130+ return nil , err
1131+ }
11261132 return provider , nil
11271133}
1134+
1135+ func determineProviderID (ctx context.Context , loader * compose.Loader ) (string , error ) {
1136+ projName , err := loader .LoadProjectName (ctx )
1137+ if err != nil {
1138+ term .Warn ("Unable to load project:" , err )
1139+ } else if ! RootCmd .PersistentFlags ().Changed ("provider" ) { // If user manually selected auto provider, do not load from remote
1140+ resp , err := client .GetSelectedProvider (ctx , & defangv1.GetSelectedProviderRequest {Project : projName })
1141+ if err != nil {
1142+ term .Warn ("Unable to get selected provider:" , err )
1143+ } else if resp .Provider != defangv1 .Provider_PROVIDER_UNSPECIFIED {
1144+ providerID .SetEnumValue (resp .Provider )
1145+ return "defang server" , nil
1146+ }
1147+ }
1148+
1149+ // Prompt the user to choose a provider if in interactive mode
1150+ options := []string {}
1151+ for _ , p := range cliClient .AllProviders () {
1152+ options = append (options , p .String ())
1153+ }
1154+ var optionValue string
1155+ if err := survey .AskOne (& survey.Select {
1156+ Message : "Choose a cloud provider:" ,
1157+ Options : options ,
1158+ Help : "The provider you choose will be used for deploying services." ,
1159+ Description : func (value string , i int ) string {
1160+ return providerDescription [cliClient .ProviderID (value )]
1161+ },
1162+ }, & optionValue ); err != nil {
1163+ return "" , err
1164+ }
1165+ if err := providerID .Set (optionValue ); err != nil {
1166+ panic (err )
1167+ }
1168+
1169+ // Save the selected provider to the fabric
1170+ if projName != "" {
1171+ if err := client .SetSelectedProvider (ctx , & defangv1.SetSelectedProviderRequest {Project : projName , Provider : providerID .EnumValue ()}); err != nil {
1172+ term .Warn ("Unable to save selected provider to defang server:" , err )
1173+ } else {
1174+ term .Printf ("%v is now the default provider for project %v and will auto-select next time if no other provider is specified. Use --provider=auto to reselect." , providerID , projName )
1175+ }
1176+ }
1177+ return "interactive prompt" , nil
1178+ }
0 commit comments