@@ -1040,5 +1040,198 @@ private void CheckSupportsEnvironmentsCommands()
10401040 }
10411041 }
10421042
1043+ // Config options overloads
1044+ public override async Task < ConfigValue > GetConfigWithOptionsAsync ( string stackName , string key , ConfigOptions ? options = null , CancellationToken cancellationToken = default )
1045+ {
1046+ var args = new List < string > { "config" , "get" , key , "--json" , "--stack" , stackName } ;
1047+ if ( options != null )
1048+ {
1049+ if ( options . Path ) args . Add ( "--path" ) ;
1050+ if ( ! string . IsNullOrEmpty ( options . ConfigFile ) ) { args . Add ( "--config-file" ) ; args . Add ( options . ConfigFile ! ) ; }
1051+ // Note: --show-secrets flag is not supported for 'config get' command,
1052+ // it's only for 'config' command (get all)
1053+ }
1054+ var result = await this . RunCommandAsync ( args , null , null , null , null , cancellationToken ) . ConfigureAwait ( false ) ;
1055+
1056+ if ( string . IsNullOrWhiteSpace ( result . StandardOutput ) )
1057+ {
1058+ return new ConfigValue ( string . Empty ) ;
1059+ }
1060+
1061+ try
1062+ {
1063+ var jsonOptions = new System . Text . Json . JsonSerializerOptions
1064+ {
1065+ PropertyNameCaseInsensitive = true
1066+ } ;
1067+
1068+ // Try deserializing as ConfigValue object with value/secret properties
1069+ var configValue = System . Text . Json . JsonSerializer . Deserialize < ConfigValueModel > (
1070+ result . StandardOutput , jsonOptions ) ;
1071+
1072+ if ( configValue != null )
1073+ {
1074+ return new ConfigValue ( configValue . Value ?? string . Empty , configValue . Secret ) ;
1075+ }
1076+
1077+ // If that fails, might be a plain string value
1078+ return new ConfigValue ( result . StandardOutput . Trim ( '"' ) ) ;
1079+ }
1080+ catch ( System . Text . Json . JsonException )
1081+ {
1082+ // If JSON parsing fails, return the raw value trimmed
1083+ return new ConfigValue ( result . StandardOutput . Trim ( ) ) ;
1084+ }
1085+ }
1086+
1087+ // Helper class to deserialize JSON response from pulumi config get --json
1088+ private class ConfigValueModel
1089+ {
1090+ public string ? Value { get ; set ; }
1091+ public bool Secret { get ; set ; }
1092+ }
1093+
1094+ public override async Task SetConfigWithOptionsAsync ( string stackName , string key , ConfigValue value , ConfigOptions ? options = null , CancellationToken cancellationToken = default )
1095+ {
1096+ var args = new List < string > { "config" , "set" , key , value . Value , "--stack" , stackName } ;
1097+ if ( options != null )
1098+ {
1099+ if ( options . Path ) args . Add ( "--path" ) ;
1100+ if ( ! string . IsNullOrEmpty ( options . ConfigFile ) ) { args . Add ( "--config-file" ) ; args . Add ( options . ConfigFile ! ) ; }
1101+ }
1102+ if ( value . IsSecret ) args . Add ( "--secret" ) ;
1103+ await this . RunCommandAsync ( args , null , null , null , null , cancellationToken ) . ConfigureAwait ( false ) ;
1104+ }
1105+
1106+ public override async Task RemoveConfigWithOptionsAsync ( string stackName , string key , ConfigOptions ? options = null , CancellationToken cancellationToken = default )
1107+ {
1108+ var args = new List < string > { "config" , "rm" , key , "--stack" , stackName } ;
1109+ if ( options != null )
1110+ {
1111+ if ( options . Path ) args . Add ( "--path" ) ;
1112+ if ( ! string . IsNullOrEmpty ( options . ConfigFile ) ) { args . Add ( "--config-file" ) ; args . Add ( options . ConfigFile ! ) ; }
1113+ }
1114+ await this . RunCommandAsync ( args , null , null , null , null , cancellationToken ) . ConfigureAwait ( false ) ;
1115+ }
1116+
1117+ public override async Task < ImmutableDictionary < string , ConfigValue > > GetAllConfigWithOptionsAsync ( string stackName , GetAllConfigOptions ? options = null , CancellationToken cancellationToken = default )
1118+ {
1119+ var args = new List < string > { "config" , "--json" , "--stack" , stackName } ;
1120+ if ( options != null )
1121+ {
1122+ if ( options . Path ) args . Add ( "--path" ) ;
1123+ if ( ! string . IsNullOrEmpty ( options . ConfigFile ) ) { args . Add ( "--config-file" ) ; args . Add ( options . ConfigFile ! ) ; }
1124+ if ( options . ShowSecrets ) args . Add ( "--show-secrets" ) ;
1125+ }
1126+ var result = await this . RunCommandAsync ( args , null , null , null , null , cancellationToken ) . ConfigureAwait ( false ) ;
1127+
1128+ if ( string . IsNullOrWhiteSpace ( result . StandardOutput ) )
1129+ {
1130+ return ImmutableDictionary < string , ConfigValue > . Empty ;
1131+ }
1132+
1133+ try
1134+ {
1135+ // Parse JSON response into Dictionary<string, JsonElement> first to handle various value types
1136+ var jsonOptions = new System . Text . Json . JsonSerializerOptions
1137+ {
1138+ PropertyNameCaseInsensitive = true
1139+ } ;
1140+
1141+ var configValues = System . Text . Json . JsonSerializer . Deserialize < Dictionary < string , System . Text . Json . JsonElement > > (
1142+ result . StandardOutput , jsonOptions ) ;
1143+
1144+ if ( configValues == null )
1145+ {
1146+ return ImmutableDictionary < string , ConfigValue > . Empty ;
1147+ }
1148+
1149+ // Convert each entry to a ConfigValue
1150+ var builder = ImmutableDictionary . CreateBuilder < string , ConfigValue > ( ) ;
1151+ foreach ( var entry in configValues )
1152+ {
1153+ if ( entry . Value . ValueKind == System . Text . Json . JsonValueKind . Object )
1154+ {
1155+ // For secret values, look for a structure like {"value":"secretvalue","secret":true}
1156+ var isSecret = false ;
1157+ var value = string . Empty ;
1158+
1159+ if ( entry . Value . TryGetProperty ( "secret" , out var secretProp ) &&
1160+ secretProp . ValueKind == System . Text . Json . JsonValueKind . True )
1161+ {
1162+ isSecret = true ;
1163+ }
1164+
1165+ if ( entry . Value . TryGetProperty ( "value" , out var valueProp ) &&
1166+ valueProp . ValueKind == System . Text . Json . JsonValueKind . String )
1167+ {
1168+ value = valueProp . GetString ( ) ?? string . Empty ;
1169+ }
1170+
1171+ builder . Add ( entry . Key , new ConfigValue ( value , isSecret ) ) ;
1172+ }
1173+ else if ( entry . Value . ValueKind == System . Text . Json . JsonValueKind . String )
1174+ {
1175+ // Plain string value
1176+ builder . Add ( entry . Key , new ConfigValue ( entry . Value . GetString ( ) ?? string . Empty ) ) ;
1177+ }
1178+ else
1179+ {
1180+ // Convert any other value to string
1181+ builder . Add ( entry . Key , new ConfigValue ( entry . Value . ToString ( ) ) ) ;
1182+ }
1183+ }
1184+
1185+ return builder . ToImmutable ( ) ;
1186+ }
1187+ catch ( System . Text . Json . JsonException ex )
1188+ {
1189+ throw new InvalidOperationException ( $ "Could not parse config values: { ex . Message } ") ;
1190+ }
1191+ }
1192+
1193+ public override async Task SetAllConfigWithOptionsAsync ( string stackName , IDictionary < string , ConfigValue > configMap , ConfigOptions ? options = null , CancellationToken cancellationToken = default )
1194+ {
1195+ if ( configMap == null || ! configMap . Any ( ) )
1196+ {
1197+ return ;
1198+ }
1199+
1200+ var args = new List < string > { "config" , "set-all" , "--stack" , stackName } ;
1201+ if ( options != null )
1202+ {
1203+ if ( options . Path ) args . Add ( "--path" ) ;
1204+ if ( ! string . IsNullOrEmpty ( options . ConfigFile ) ) { args . Add ( "--config-file" ) ; args . Add ( options . ConfigFile ! ) ; }
1205+ }
1206+
1207+ // For each config value, add as either secret or plaintext
1208+ foreach ( var kvp in configMap )
1209+ {
1210+ args . Add ( kvp . Value . IsSecret ? "--secret" : "--plaintext" ) ;
1211+ args . Add ( $ "{ kvp . Key } ={ kvp . Value . Value } ") ;
1212+ }
1213+
1214+ await this . RunCommandAsync ( args , null , null , null , null , cancellationToken ) . ConfigureAwait ( false ) ;
1215+ }
1216+
1217+ public override async Task RemoveAllConfigWithOptionsAsync ( string stackName , IEnumerable < string > keys , ConfigOptions ? options = null , CancellationToken cancellationToken = default )
1218+ {
1219+ if ( keys == null || ! keys . Any ( ) )
1220+ {
1221+ return ;
1222+ }
1223+
1224+ var args = new List < string > { "config" , "rm-all" , "--stack" , stackName } ;
1225+ if ( options != null )
1226+ {
1227+ if ( options . Path ) args . Add ( "--path" ) ;
1228+ if ( ! string . IsNullOrEmpty ( options . ConfigFile ) ) { args . Add ( "--config-file" ) ; args . Add ( options . ConfigFile ! ) ; }
1229+ }
1230+
1231+ // Add all keys to remove
1232+ args . AddRange ( keys ) ;
1233+
1234+ await this . RunCommandAsync ( args , null , null , null , null , cancellationToken ) . ConfigureAwait ( false ) ;
1235+ }
10431236 }
10441237}
0 commit comments