@@ -45,6 +45,11 @@ public class TerraformProviderCodegen extends AbstractGoCodegen {
4545 protected String providerAddress = "registry.terraform.io/example/example" ;
4646 protected String providerVersion = "0.1.0" ;
4747
48+ // Track which tags qualify as resources vs data sources so we can
49+ // delete non-qualifying files in postProcessFile.
50+ private final Set <String > resourceNames = new HashSet <>();
51+ private final Set <String > dataSourceNames = new HashSet <>();
52+
4853 @ Override
4954 public CodegenType getTag () {
5055 return CodegenType .CLIENT ;
@@ -122,6 +127,9 @@ public TerraformProviderCodegen() {
122127 public void processOpts () {
123128 super .processOpts ();
124129
130+ // Enable postProcessFile so we can delete non-qualifying API files
131+ this .setEnablePostProcessFile (true );
132+
125133 if (additionalProperties .containsKey (PROVIDER_NAME )) {
126134 providerName = additionalProperties .get (PROVIDER_NAME ).toString ();
127135 }
@@ -272,6 +280,14 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
272280 objectMap .put ("hasDelete" , deleteOp != null );
273281 objectMap .put ("hasList" , listOp != null );
274282
283+ // A tag qualifies as a Terraform resource only if it has a create
284+ // operation; without one the resource cannot be instantiated.
285+ // A tag qualifies as a data source if it has a read (show) operation.
286+ boolean isResource = (createOp != null );
287+ boolean isDataSource = (readOp != null );
288+ objectMap .put ("isResource" , isResource );
289+ objectMap .put ("isDataSource" , isDataSource );
290+
275291 // Store CRUD operation details at tag level for simplified template access
276292 if (createOp != null ) {
277293 objectMap .put ("createMethod" , createOp .vendorExtensions .get ("x-terraform-http-method" ));
@@ -312,6 +328,13 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
312328 objectMap .put ("resourceName" , resourceName );
313329 objectMap .put ("resourceClassName" , camelize (resourceName ));
314330
331+ if (isResource ) {
332+ resourceNames .add (resourceName );
333+ }
334+ if (isDataSource ) {
335+ dataSourceNames .add (resourceName );
336+ }
337+
315338 // Detect ID field from read operation path params
316339 String idField = "id" ;
317340 if (readOp != null && readOp .pathParams != null && !readOp .pathParams .isEmpty ()) {
@@ -354,7 +377,7 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
354377 attr .put ("goType" , prop .dataType );
355378 attr .put ("terraformType" , goTypeToTerraformType (prop .dataType ));
356379 attr .put ("terraformAttrType" , goTypeToTerraformAttrType (prop .dataType , prop ));
357- attr .put ("isRequired" , prop .required );
380+ attr .put ("isRequired" , prop .required && ! prop . isReadOnly );
358381 attr .put ("isComputed" , prop .isReadOnly );
359382 attr .put ("isOptional" , !prop .required && !prop .isReadOnly );
360383 attr .put ("description" , prop .description != null ? prop .description : "" );
@@ -407,11 +430,19 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
407430 if ("id" .equalsIgnoreCase (prop .baseName )) {
408431 idModelGoName = camelize (prop .baseName );
409432 idModelGoType = prop .dataType ;
433+ idResolved = true ;
410434 break ;
411435 }
412436 }
413437 }
414438
439+ if (!idResolved ) {
440+ LOGGER .warn ("Could not resolve ID field '{}' in response model '{}' for resource '{}'. "
441+ + "The generated code will not compile. Add an '{}' property to the response "
442+ + "schema or use x-terraform-id-field to specify the correct property." ,
443+ idField , responseModel , resourceName , idField );
444+ }
445+
415446 break ;
416447 }
417448 }
@@ -482,6 +513,42 @@ public ModelsMap postProcessModels(ModelsMap objs) {
482513 return objs ;
483514 }
484515
516+ @ Override
517+ public void postProcessFile (File file , String fileType ) {
518+ super .postProcessFile (file , fileType );
519+ if (file == null || !file .exists () || !"api" .equals (fileType )) {
520+ return ;
521+ }
522+
523+ String fileName = file .getName ();
524+
525+ if (fileName .endsWith ("_resource.go" )) {
526+ String tag = fileName .substring (0 , fileName .length () - "_resource.go" .length ());
527+ if (!resourceNames .contains (tag )) {
528+ LOGGER .info ("Skipping non-resource file: {}" , file .getAbsolutePath ());
529+ file .delete ();
530+ return ;
531+ }
532+ }
533+
534+ if (fileName .endsWith ("_data_source.go" )) {
535+ String tag = fileName .substring (0 , fileName .length () - "_data_source.go" .length ());
536+ if (!dataSourceNames .contains (tag )) {
537+ LOGGER .info ("Skipping non-data-source file: {}" , file .getAbsolutePath ());
538+ file .delete ();
539+ return ;
540+ }
541+ }
542+
543+ if (fileName .endsWith ("_model.go" )) {
544+ String tag = fileName .substring (0 , fileName .length () - "_model.go" .length ());
545+ if (!resourceNames .contains (tag ) && !dataSourceNames .contains (tag )) {
546+ LOGGER .info ("Skipping unused model file: {}" , file .getAbsolutePath ());
547+ file .delete ();
548+ }
549+ }
550+ }
551+
485552 private String goTypeToTerraformType (String goType ) {
486553 if (goType == null ) return "types.String" ;
487554 switch (goType ) {
0 commit comments