@@ -113,7 +113,7 @@ func (cli *CLI) inspectModule(opts Options, dir string, filterFiles []string) (t
113
113
}
114
114
115
115
// Launch plugin processes
116
- rulesetPlugin , err := launchPlugins (cli .config , opts .Fix )
116
+ rulesetPlugin , sdkVersions , err := launchPlugins (cli .config , opts .Fix )
117
117
if rulesetPlugin != nil {
118
118
defer rulesetPlugin .Clean ()
119
119
go cli .registerShutdownHandler (func () {
@@ -125,22 +125,18 @@ func (cli *CLI) inspectModule(opts Options, dir string, filterFiles []string) (t
125
125
return issues , changes , err
126
126
}
127
127
128
- // Check preconditions
129
- sdkVersions := map [string ]* version.Version {}
130
- for name , ruleset := range rulesetPlugin .RuleSets {
131
- sdkVersion , err := ruleset .SDKVersion ()
132
- if err != nil {
133
- if st , ok := status .FromError (err ); ok && st .Code () == codes .Unimplemented {
134
- // SDKVersion endpoint is available in tflint-plugin-sdk v0.14+.
135
- return issues , changes , fmt .Errorf (`Plugin "%s" SDK version is incompatible. Compatible versions: %s` , name , plugin .SDKVersionConstraints )
136
- } else {
137
- return issues , changes , fmt .Errorf (`Failed to get plugin "%s" SDK version; %w` , name , err )
128
+ // Check if we're using a JSON config file and if any plugins need SDK updates
129
+ if cli .config .IsJSONConfig () && len (sdkVersions ) > 0 {
130
+ minVersion := version .Must (version .NewVersion ("0.23.0" ))
131
+ hasIncompatible , incompatiblePlugins := checkPluginSDKVersions (sdkVersions , minVersion )
132
+ if hasIncompatible {
133
+ // Log warning for JSON config with older SDK versions
134
+ fmt .Fprintf (cli .errStream , "WARNING: JSON configuration detected with plugin(s) using SDK < 0.23.0:\n " )
135
+ for _ , plugin := range incompatiblePlugins {
136
+ fmt .Fprintf (cli .errStream , " - %s\n " , plugin )
138
137
}
138
+ fmt .Fprintf (cli .errStream , "Please update your plugins for full JSON configuration support.\n \n " )
139
139
}
140
- if ! plugin .SDKVersionConstraints .Check (sdkVersion ) {
141
- return issues , changes , fmt .Errorf (`Plugin "%s" SDK version (%s) is incompatible. Compatible versions: %s` , name , sdkVersion , plugin .SDKVersionConstraints )
142
- }
143
- sdkVersions [name ] = sdkVersion
144
140
}
145
141
146
142
// Run inspection
@@ -254,11 +250,32 @@ func (cli *CLI) setupRunners(opts Options, dir string) (*tflint.Runner, []*tflin
254
250
return runner , moduleRunners , nil
255
251
}
256
252
257
- func launchPlugins (config * tflint.Config , fix bool ) (* plugin.Plugin , error ) {
253
+ func launchPlugins (config * tflint.Config , fix bool ) (* plugin.Plugin , map [ string ] * version. Version , error ) {
258
254
// Lookup plugins
259
255
rulesetPlugin , err := plugin .Discovery (config )
260
256
if err != nil {
261
- return nil , fmt .Errorf ("Failed to initialize plugins; %w" , err )
257
+ return nil , nil , fmt .Errorf ("Failed to initialize plugins; %w" , err )
258
+ }
259
+
260
+ // Collect SDK versions from all plugins
261
+ sdkVersions := map [string ]* version.Version {}
262
+ for name , ruleset := range rulesetPlugin .RuleSets {
263
+ sdkVersion , err := ruleset .SDKVersion ()
264
+ if err != nil {
265
+ if st , ok := status .FromError (err ); ok && st .Code () == codes .Unimplemented {
266
+ // SDKVersion endpoint is available in tflint-plugin-sdk v0.14+.
267
+ // Assume old version for compatibility checking
268
+ sdkVersions [name ] = version .Must (version .NewVersion ("0.13.0" ))
269
+ } else {
270
+ return nil , nil , fmt .Errorf (`Failed to get plugin "%s" SDK version; %w` , name , err )
271
+ }
272
+ } else {
273
+ // Check SDK version compatibility with TFLint
274
+ if ! plugin .SDKVersionConstraints .Check (sdkVersion ) {
275
+ return nil , nil , fmt .Errorf (`Plugin "%s" SDK version (%s) is incompatible. Compatible versions: %s` , name , sdkVersion , plugin .SDKVersionConstraints )
276
+ }
277
+ sdkVersions [name ] = sdkVersion
278
+ }
262
279
}
263
280
264
281
rulesets := []tflint.RuleSet {}
@@ -271,44 +288,44 @@ func launchPlugins(config *tflint.Config, fix bool) (*plugin.Plugin, error) {
271
288
if err != nil {
272
289
if st , ok := status .FromError (err ); ok && st .Code () == codes .Unimplemented {
273
290
// VersionConstraints endpoint is available in tflint-plugin-sdk v0.14+.
274
- return rulesetPlugin , fmt .Errorf (`Plugin "%s" SDK version is incompatible. Compatible versions: %s` , name , plugin .SDKVersionConstraints )
291
+ return rulesetPlugin , sdkVersions , fmt .Errorf (`Plugin "%s" SDK version is incompatible. Compatible versions: %s` , name , plugin .SDKVersionConstraints )
275
292
} else {
276
- return rulesetPlugin , fmt .Errorf (`Failed to get TFLint version constraints to "%s" plugin; %w` , name , err )
293
+ return rulesetPlugin , sdkVersions , fmt .Errorf (`Failed to get TFLint version constraints to "%s" plugin; %w` , name , err )
277
294
}
278
295
}
279
296
if ! constraints .Check (tflint .Version ) {
280
- return rulesetPlugin , fmt .Errorf ("Failed to satisfy version constraints; tflint-ruleset-%s requires %s, but TFLint version is %s" , name , constraints , tflint .Version )
297
+ return rulesetPlugin , sdkVersions , fmt .Errorf ("Failed to satisfy version constraints; tflint-ruleset-%s requires %s, but TFLint version is %s" , name , constraints , tflint .Version )
281
298
}
282
299
283
300
if err := ruleset .ApplyGlobalConfig (pluginConf ); err != nil {
284
- return rulesetPlugin , fmt .Errorf (`Failed to apply global config to "%s" plugin; %w` , name , err )
301
+ return rulesetPlugin , sdkVersions , fmt .Errorf (`Failed to apply global config to "%s" plugin; %w` , name , err )
285
302
}
286
303
configSchema , err := ruleset .ConfigSchema ()
287
304
if err != nil {
288
- return rulesetPlugin , fmt .Errorf (`Failed to fetch config schema from "%s" plugin; %w` , name , err )
305
+ return rulesetPlugin , sdkVersions , fmt .Errorf (`Failed to fetch config schema from "%s" plugin; %w` , name , err )
289
306
}
290
307
content := & hclext.BodyContent {}
291
308
if plugin , exists := config .Plugins [name ]; exists {
292
309
var diags hcl.Diagnostics
293
310
content , diags = plugin .Content (configSchema )
294
311
if diags .HasErrors () {
295
- return rulesetPlugin , fmt .Errorf (`Failed to parse "%s" plugin config; %w` , name , diags )
312
+ return rulesetPlugin , sdkVersions , fmt .Errorf (`Failed to parse "%s" plugin config; %w` , name , diags )
296
313
}
297
314
}
298
315
err = ruleset .ApplyConfig (content , config .Sources ())
299
316
if err != nil {
300
- return rulesetPlugin , fmt .Errorf (`Failed to apply config to "%s" plugin; %w` , name , err )
317
+ return rulesetPlugin , sdkVersions , fmt .Errorf (`Failed to apply config to "%s" plugin; %w` , name , err )
301
318
}
302
319
303
320
rulesets = append (rulesets , ruleset )
304
321
}
305
322
306
323
// Validate config for plugins
307
324
if err := config .ValidateRules (rulesets ... ); err != nil {
308
- return rulesetPlugin , fmt .Errorf ("Failed to check rule config; %w" , err )
325
+ return rulesetPlugin , sdkVersions , fmt .Errorf ("Failed to check rule config; %w" , err )
309
326
}
310
327
311
- return rulesetPlugin , nil
328
+ return rulesetPlugin , sdkVersions , nil
312
329
}
313
330
314
331
func writeChanges (changes map [string ][]byte ) error {
@@ -334,6 +351,22 @@ func writeChanges(changes map[string][]byte) error {
334
351
}
335
352
336
353
// Checks if the given issues contain severities above or equal to the given minimum failure opt. Defaults to true if an error occurs
354
+ // checkPluginSDKVersions checks if plugin SDK versions meet the minimum requirement
355
+ // Returns true if any plugins are below the minimum version, along with a list of incompatible plugins
356
+ func checkPluginSDKVersions (sdkVersions map [string ]* version.Version , minVersion * version.Version ) (bool , []string ) {
357
+ hasIncompatiblePlugins := false
358
+ incompatiblePlugins := []string {}
359
+
360
+ for name , sdkVersion := range sdkVersions {
361
+ if sdkVersion .LessThan (minVersion ) {
362
+ hasIncompatiblePlugins = true
363
+ incompatiblePlugins = append (incompatiblePlugins , fmt .Sprintf ("%s (v%s)" , name , sdkVersion ))
364
+ }
365
+ }
366
+
367
+ return hasIncompatiblePlugins , incompatiblePlugins
368
+ }
369
+
337
370
func exceedsMinimumFailure (issues tflint.Issues , minimumFailureOpt string ) bool {
338
371
if minimumFailureOpt != "" {
339
372
minSeverity , err := tflint .NewSeverity (minimumFailureOpt )
0 commit comments