@@ -91,7 +91,7 @@ func Execute(ctx context.Context) error {
91
91
92
92
if strings .Contains (err .Error (), "maximum number of projects" ) {
93
93
projectName := "<name>"
94
- provider , err := getProvider (ctx )
94
+ provider , err := getProvider (ctx , nil )
95
95
if err != nil {
96
96
return err
97
97
}
@@ -385,7 +385,8 @@ var whoamiCmd = &cobra.Command{
385
385
Args : cobra .NoArgs ,
386
386
Short : "Show the current user" ,
387
387
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 )
389
390
if err != nil {
390
391
return err
391
392
}
@@ -412,7 +413,7 @@ var certGenerateCmd = &cobra.Command{
412
413
Short : "Generate a TLS certificate" ,
413
414
RunE : func (cmd * cobra.Command , args []string ) error {
414
415
loader := configureLoader (cmd )
415
- provider , err := getProvider (cmd .Context ())
416
+ provider , err := getProvider (cmd .Context (), loader )
416
417
if err != nil {
417
418
return err
418
419
}
@@ -660,7 +661,7 @@ var configSetCmd = &cobra.Command{
660
661
661
662
// Make sure we have a project to set config for before asking for a value
662
663
loader := configureLoader (cmd )
663
- provider , err := getProvider (cmd .Context ())
664
+ provider , err := getProvider (cmd .Context (), loader )
664
665
if err != nil {
665
666
return err
666
667
}
@@ -737,7 +738,7 @@ var configDeleteCmd = &cobra.Command{
737
738
Short : "Removes one or more config values" ,
738
739
RunE : func (cmd * cobra.Command , names []string ) error {
739
740
loader := configureLoader (cmd )
740
- provider , err := getProvider (cmd .Context ())
741
+ provider , err := getProvider (cmd .Context (), loader )
741
742
if err != nil {
742
743
return err
743
744
}
@@ -764,7 +765,7 @@ var configListCmd = &cobra.Command{
764
765
Short : "List configs" ,
765
766
RunE : func (cmd * cobra.Command , args []string ) error {
766
767
loader := configureLoader (cmd )
767
- provider , err := getProvider (cmd .Context ())
768
+ provider , err := getProvider (cmd .Context (), loader )
768
769
if err != nil {
769
770
return err
770
771
}
@@ -781,7 +782,7 @@ var debugCmd = &cobra.Command{
781
782
etag , _ := cmd .Flags ().GetString ("etag" )
782
783
783
784
loader := configureLoader (cmd )
784
- provider , err := getProvider (cmd .Context ())
785
+ provider , err := getProvider (cmd .Context (), loader )
785
786
if err != nil {
786
787
return err
787
788
}
@@ -800,7 +801,7 @@ var deleteCmd = &cobra.Command{
800
801
var tail , _ = cmd .Flags ().GetBool ("tail" )
801
802
802
803
loader := configureLoader (cmd )
803
- provider , err := getProvider (cmd .Context ())
804
+ provider , err := getProvider (cmd .Context (), loader )
804
805
if err != nil {
805
806
return err
806
807
}
@@ -902,7 +903,7 @@ var cdDestroyCmd = &cobra.Command{
902
903
Short : "Destroy the service stack" ,
903
904
RunE : func (cmd * cobra.Command , args []string ) error {
904
905
loader := configureLoader (cmd )
905
- provider , err := getProvider (cmd .Context ())
906
+ provider , err := getProvider (cmd .Context (), loader )
906
907
if err != nil {
907
908
return err
908
909
}
@@ -916,7 +917,7 @@ var cdDownCmd = &cobra.Command{
916
917
Short : "Refresh and then destroy the service stack" ,
917
918
RunE : func (cmd * cobra.Command , args []string ) error {
918
919
loader := configureLoader (cmd )
919
- provider , err := getProvider (cmd .Context ())
920
+ provider , err := getProvider (cmd .Context (), loader )
920
921
if err != nil {
921
922
return err
922
923
}
@@ -930,7 +931,7 @@ var cdRefreshCmd = &cobra.Command{
930
931
Short : "Refresh the service stack" ,
931
932
RunE : func (cmd * cobra.Command , args []string ) error {
932
933
loader := configureLoader (cmd )
933
- provider , err := getProvider (cmd .Context ())
934
+ provider , err := getProvider (cmd .Context (), loader )
934
935
if err != nil {
935
936
return err
936
937
}
@@ -944,7 +945,7 @@ var cdCancelCmd = &cobra.Command{
944
945
Short : "Cancel the current CD operation" ,
945
946
RunE : func (cmd * cobra.Command , args []string ) error {
946
947
loader := configureLoader (cmd )
947
- provider , err := getProvider (cmd .Context ())
948
+ provider , err := getProvider (cmd .Context (), loader )
948
949
if err != nil {
949
950
return err
950
951
}
@@ -959,7 +960,8 @@ var cdTearDownCmd = &cobra.Command{
959
960
RunE : func (cmd * cobra.Command , args []string ) error {
960
961
force , _ := cmd .Flags ().GetBool ("force" )
961
962
962
- provider , err := getProvider (cmd .Context ())
963
+ loader := configureLoader (cmd )
964
+ provider , err := getProvider (cmd .Context (), loader )
963
965
if err != nil {
964
966
return err
965
967
}
@@ -976,7 +978,7 @@ var cdListCmd = &cobra.Command{
976
978
remote , _ := cmd .Flags ().GetBool ("remote" )
977
979
978
980
loader := configureLoader (cmd )
979
- provider , err := getProvider (cmd .Context ())
981
+ provider , err := getProvider (cmd .Context (), loader )
980
982
if err != nil {
981
983
return err
982
984
}
@@ -994,7 +996,7 @@ var cdPreviewCmd = &cobra.Command{
994
996
Short : "Preview the changes that will be made by the CD task" ,
995
997
RunE : func (cmd * cobra.Command , args []string ) error {
996
998
loader := configureLoader (cmd )
997
- provider , err := getProvider (cmd .Context ())
999
+ provider , err := getProvider (cmd .Context (), loader )
998
1000
if err != nil {
999
1001
return err
1000
1002
}
@@ -1076,30 +1078,29 @@ var providerDescription = map[cliClient.ProviderID]string{
1076
1078
cliClient .ProviderDO : "Deploy to DigitalOcean using the DIGITALOCEAN_TOKEN, SPACES_ACCESS_KEY_ID, and SPACES_SECRET_ACCESS_KEY environment variables." ,
1077
1079
}
1078
1080
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
+
1080
1097
switch providerID {
1081
1098
case cliClient .ProviderAuto :
1082
1099
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 {
1097
1102
return nil , err
1098
1103
}
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 )
1103
1104
} else {
1104
1105
// Defaults to defang provider in non-interactive mode
1105
1106
if awsInEnv () {
@@ -1120,8 +1121,58 @@ func getProvider(ctx context.Context) (cliClient.Provider, error) {
1120
1121
}
1121
1122
case cliClient .ProviderDefang :
1122
1123
// Ignore any env vars when explicitly using the Defang playground provider
1124
+ extraMsg = "; consider using BYOC (https://s.defang.io/byoc)"
1123
1125
}
1124
1126
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
+ }
1126
1132
return provider , nil
1127
1133
}
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