Repository: jhipster/generator-jhipster (ts)

Issue:
Entity module always override blueprint's custom config.
##### **Overview of the feature request**

There is no easy way to create a permanent config for entities.

##### **Motivation for or Use Case**

I am creating a blueprint that creates a new permanent configuration for some entities, but the Entity module always creates and saves a new config.

https://github.com/jhipster/generator-jhipster/blob/d25818cdca9a6337fc0e0374d437b8c70aa9a98e/generators/entity/index.js#L623

https://github.com/jhipster/generator-jhipster/blob/d25818cdca9a6337fc0e0374d437b8c70aa9a98e/generators/entity/index.js#L650

##### **Related issues or PR**

https://github.com/jhipster/generator-jhipster/issues/10160

-   [x] Checking this box is mandatory (this is just to show you read everything)

<!-- Love JHipster? Please consider supporting our collective:
👉  https://opencollective.com/generator-jhipster/donate -->


Pull request:
Entity blueprint: allow blueprints to create custom configs.
Fixes #10162

-   Please make sure the below checklist is followed for Pull Requests.

-   [x] [Travis tests](https://travis-ci.org/jhipster/generator-jhipster/pull_requests) are green
-   [x] Tests are added where necessary
-   [x] Documentation is added/updated where necessary
-   [x] Coding Rules & Commit Guidelines as per our [CONTRIBUTING.md document](https://github.com/jhipster/generator-jhipster/blob/master/CONTRIBUTING.md) are followed

<!--
Please also reference the issue number in a commit message to [automatically close the related Github issue](https://help.github.com/articles/closing-issues-via-commit-messages/)

Note: It is also possible to add `[skip ci]` to your commit message to skip Travis tests
-->


Patch:
diff --git a/generators/entity/index.js b/generators/entity/index.js
index 93928aecb8..8703838aa4 100644
--- a/generators/entity/index.js
+++ b/generators/entity/index.js
@@ -622,34 +622,48 @@ class EntityGenerator extends BaseBlueprintGenerator {
                 if (_.isUndefined(context.changelogDate) && ['sql', 'cassandra'].includes(context.databaseType)) {
                     context.changelogDate = this.dateFormatForLiquibase();
                 }
-                this.data = {};
-                this.data.fluentMethods = context.fluentMethods;
-                this.data.clientRootFolder = context.clientRootFolder;
-                this.data.relationships = context.relationships;
-                this.data.fields = context.fields;
-                this.data.changelogDate = context.changelogDate;
-                this.data.dto = context.dto;
-                this.data.searchEngine = context.searchEngine;
-                this.data.service = context.service;
-                this.data.entityTableName = context.entityTableName;
-                this.data.databaseType = context.databaseType;
-                this.copyFilteringFlag(context, this.data, context);
+
+                // Keep existing config by cloning fileData
+                const storageData = this.context.fileData ? { ...this.context.fileData } : {};
+                storageData.fluentMethods = context.fluentMethods;
+                storageData.clientRootFolder = context.clientRootFolder;
+                storageData.relationships = context.relationships;
+                storageData.fields = context.fields;
+                storageData.changelogDate = context.changelogDate;
+                storageData.dto = context.dto;
+                storageData.searchEngine = context.searchEngine;
+                storageData.service = context.service;
+                storageData.entityTableName = context.entityTableName;
+                storageData.databaseType = context.databaseType;
+                this.copyFilteringFlag(context, storageData, context);
                 if (['sql', 'mongodb', 'couchbase'].includes(context.databaseType)) {
-                    this.data.pagination = context.pagination;
+                    storageData.pagination = context.pagination;
                 } else {
-                    this.data.pagination = 'no';
+                    storageData.pagination = 'no';
                 }
-                this.data.javadoc = context.javadoc;
+                storageData.javadoc = context.javadoc;
                 if (context.entityAngularJSSuffix) {
-                    this.data.angularJSSuffix = context.entityAngularJSSuffix;
+                    storageData.angularJSSuffix = context.entityAngularJSSuffix;
                 }
                 if (context.applicationType === 'microservice' || context.applicationType === 'uaa') {
-                    this.data.microserviceName = context.baseName;
+                    storageData.microserviceName = context.baseName;
                 }
                 if (context.applicationType === 'gateway' && context.useMicroserviceJson) {
-                    this.data.microserviceName = context.microserviceName;
+                    storageData.microserviceName = context.microserviceName;
+                }
+
+                if (this.storageData) {
+                    // Override storageData configs with existing this.storageData
+                    // So that blueprints can create it and override fields.
+                    this.storageData = { ...storageData, ...this.storageData };
+                } else {
+                    this.storageData = storageData;
                 }
-                this.fs.writeJSON(context.filename, this.data, null, 4);
+
+                this.fs.writeJSON(context.filename, this.storageData, null, 4);
+
+                // Keep this.data for compatibility with existing blueprints
+                this.data = this.storageData;
             },
 
             loadInMemoryData() {
@@ -1151,7 +1165,10 @@ class EntityGenerator extends BaseBlueprintGenerator {
                         this.log(`\n${chalk.bold.green('Running post run module hooks\n')}`);
                         // form the data to be passed to modules
                         const context = this.context;
-                        context.data = context.data || context.fileData;
+
+                        // Keep context.data for unexpected compatibility issue.
+                        context.data = context.data || this.storageData || context.fileData;
+
                         // run through all post entity creation module hooks
                         this.callHooks(
                             'entity',


Test patch:
diff --git a/test/blueprint/entity-blueprint.spec.js b/test/blueprint/entity-blueprint.spec.js
index e3333894fd..eb5822d16d 100644
--- a/test/blueprint/entity-blueprint.spec.js
+++ b/test/blueprint/entity-blueprint.spec.js
@@ -25,14 +25,29 @@ const mockBlueprintSubGen = class extends EntityGenerator {
 
     get initializing() {
         const phaseFromJHipster = super._initializing();
-        const customPhaseSteps = {
+        const customPrePhaseSteps = {
+            // Create a custom persistent entity config.
+            createCustomConfig() {
+                // Simulate data loaded from file
+                this.context.fileData = this.context.fileData || {};
+                this.context.fileData.customPreConfigKey = 'customPreConfigValue';
+                this.context.fileData.customBlueprintConfigKey = 'customPreConfigValue';
+
+                // Override with new value
+                this.storageData = {
+                    customBlueprintConfigKey: 'customBlueprintConfigValue'
+                };
+            }
+        };
+        const customPostPhaseSteps = {
             changeProperty() {
                 this.context.angularAppName = 'awesomeAngularAppName';
             }
         };
         return {
+            ...customPrePhaseSteps,
             ...phaseFromJHipster,
-            ...customPhaseSteps
+            ...customPostPhaseSteps
         };
     }
 
@@ -99,6 +114,14 @@ describe('JHipster entity generator with blueprint', () => {
             it('contains the specific change added by the blueprint', () => {
                 assert.fileContent(`${CLIENT_MAIN_SRC_DIR}i18n/en/foo.json`, /awesomeAngularAppName/);
             });
+
+            // Verify if the custom entity config is persisted.
+            it('contains the specific config added', () => {
+                assert.fileContent('.jhipster/Foo.json', /"customPreConfigKey": "customPreConfigValue"/);
+            });
+            it('contains the specific config added by the blueprint', () => {
+                assert.fileContent('.jhipster/Foo.json', /"customBlueprintConfigKey": "customBlueprintConfigValue"/);
+            });
         });
     });