generator-jhipster 8.0.0-rc.1 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/dist/cli/environment-builder.mjs +3 -3
- package/dist/cli/jhipster-command.mjs +7 -3
- package/dist/cli/program.mjs +1 -1
- package/dist/generators/angular/generator.mjs +8 -7
- package/dist/generators/angular/resources/package.json +10 -9
- package/dist/generators/angular/templates/package.json.ejs +4 -8
- package/dist/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.html.ejs +6 -10
- package/dist/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.ts.ejs +1 -1
- package/dist/generators/angular/templates/src/main/webapp/app/layouts/navbar/navbar.component.scss.ejs +1 -1
- package/dist/generators/angular/templates/webpack/webpack.microfrontend.js.ejs +48 -126
- package/dist/generators/app/support/config.mjs +3 -3
- package/dist/generators/base/generator.mjs +0 -3
- package/dist/generators/base/support/config.mjs +6 -6
- package/dist/generators/base/support/jhipster7-context.mjs +3 -3
- package/dist/generators/base-application/generator.mjs +2 -2
- package/dist/generators/base-application/support/enum.mjs +1 -1
- package/dist/generators/base-application/support/prepare-entity.mjs +14 -10
- package/dist/generators/base-application/support/prepare-field.mjs +11 -7
- package/dist/generators/base-application/support/prepare-relationship.mjs +12 -14
- package/dist/generators/base-workspaces/internal/docker-prompts.mjs +13 -12
- package/dist/generators/bootstrap/generator.mjs +64 -43
- package/dist/generators/bootstrap/support/auto-crlf-transform.mjs +34 -21
- package/dist/generators/bootstrap/support/eslint-transform.mjs +2 -5
- package/dist/generators/bootstrap/support/java-unused-imports-transform.mjs +2 -2
- package/dist/generators/bootstrap/support/multi-step-transform/index.mjs +17 -28
- package/dist/generators/bootstrap/support/multi-step-transform/template-file-fs.mjs +12 -6
- package/dist/generators/bootstrap/support/multi-step-transform/template-file.mjs +1 -0
- package/dist/generators/bootstrap/support/prettier-support.mjs +2 -2
- package/dist/generators/bootstrap-application/generator.mjs +10 -3
- package/dist/generators/bootstrap-application-base/generator.mjs +9 -6
- package/dist/generators/bootstrap-application-server/generator.mjs +2 -2
- package/dist/generators/client/resources/package.json +3 -3
- package/dist/generators/client/templates/src/main/webapp/content/css/loading.css.ejs +1 -1
- package/dist/generators/client/templates/webpack/webpack.microfrontend.js.jhi.ejs +14 -1
- package/dist/generators/common/files.mjs +1 -1
- package/dist/generators/common/generator.mjs +29 -7
- package/dist/generators/common/resources/package.json +3 -3
- package/dist/generators/common/templates/.lintstagedrc.cjs.ejs +21 -0
- package/dist/generators/common/templates/.prettierrc.ejs +1 -1
- package/dist/generators/common/templates/README.md.jhi.ejs +2 -0
- package/dist/generators/cypress/templates/src/test/javascript/cypress/e2e/account/settings-page.cy.ts.ejs +3 -0
- package/dist/generators/entity/prompts.mjs +123 -306
- package/dist/generators/generator-constants.mjs +5 -5
- package/dist/generators/heroku/generator.mjs +318 -595
- package/dist/generators/heroku/templates/Procfile.ejs +1 -1
- package/dist/generators/heroku/templates/application-heroku.yml.ejs +0 -12
- package/dist/generators/info/generator.mjs +6 -4
- package/dist/generators/init/generator.mjs +2 -2
- package/dist/generators/java/entity-files.mjs +1 -1
- package/dist/generators/java/generator.mjs +12 -13
- package/dist/generators/java/support/package-info-transform.mjs +20 -6
- package/dist/generators/java/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs +24 -28
- package/dist/generators/java/templates/src/main/java/_package_/_entityPackage_/domain/enumeration/_enumName_.java.ejs +3 -3
- package/dist/generators/java/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_Test.java.ejs +86 -8
- package/dist/generators/java/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_TestSamples.java.ejs +85 -0
- package/dist/generators/jdl/generator.mjs +14 -5
- package/dist/generators/kubernetes/templates/ingress.yml.ejs +0 -1
- package/dist/generators/languages/command.mjs +5 -0
- package/dist/generators/languages/generator.mjs +20 -13
- package/dist/generators/languages/translation-data.mjs +8 -13
- package/dist/generators/liquibase/generator.mjs +7 -3
- package/dist/generators/project-name/generator.mjs +1 -1
- package/dist/generators/react/generator.mjs +18 -10
- package/dist/generators/react/resources/package.json +19 -18
- package/dist/generators/react/templates/package.json.ejs +4 -5
- package/dist/generators/react/templates/src/main/webapp/app/config/icon-loader.ts.ejs +35 -33
- package/dist/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.tsx.ejs +7 -2
- package/dist/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.reducer.ts.ejs +1 -1
- package/dist/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.tsx.ejs +1 -1
- package/dist/generators/react/templates/src/main/webapp/app/modules/home/home.tsx.ejs +1 -1
- package/dist/generators/react/templates/src/main/webapp/app/routes.tsx.ejs +9 -2
- package/dist/generators/react/templates/src/main/webapp/app/shared/layout/header/header-components.tsx.ejs +1 -1
- package/dist/generators/react/templates/src/main/webapp/app/shared/layout/header/header.scss.ejs +5 -4
- package/dist/generators/react/templates/src/main/webapp/app/shared/layout/menus/entities.tsx.ejs +10 -1
- package/dist/generators/react/templates/tsconfig.test.json.ejs +1 -1
- package/dist/generators/react/templates/webpack/webpack.microfrontend.js.jhi.react.ejs +13 -58
- package/dist/generators/server/generator.mjs +13 -4
- package/dist/generators/server/resources/Dockerfile +7 -7
- package/dist/generators/server/resources/gradle/libs.versions.toml +1 -1
- package/dist/generators/server/resources/pom.xml +11 -11
- package/dist/generators/server/support/config.mjs +4 -4
- package/dist/generators/server/support/prepare-entity.mjs +5 -5
- package/dist/generators/server/support/prepare-field.mjs +20 -0
- package/dist/generators/server/support/relationship.mjs +2 -1
- package/dist/generators/server/support/templates/field-values.mjs +5 -2
- package/dist/generators/server/templates/README.md.jhi.spring-boot.ejs +0 -1
- package/dist/generators/server/templates/package.json.ejs +0 -5
- package/dist/generators/server/templates/pom.xml.ejs +1 -8
- package/dist/generators/server/templates/src/main/java/_package_/_entityPackage_/_partials_entity_/get_all_template.ejs +3 -3
- package/dist/generators/server/templates/src/main/java/_package_/_entityPackage_/service/dto/_dtoClass_.java.ejs +2 -2
- package/dist/generators/server/templates/src/main/java/_package_/_entityPackage_/web/rest/_entityClass_Resource.java.ejs +11 -11
- package/dist/generators/server/templates/src/main/java/_package_/config/JacksonConfiguration.java.ejs +2 -1
- package/dist/generators/server/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs +1 -1
- package/dist/generators/server/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs +2 -0
- package/dist/generators/server/templates/src/main/java/_package_/service/MailService.java.ejs +10 -4
- package/dist/generators/server/templates/src/main/java/_package_/web/rest/PublicUserResource.java.ejs +3 -4
- package/dist/generators/server/templates/src/main/java/_package_/web/rest/UserResource.java.ejs +0 -2
- package/dist/generators/server/templates/src/main/java/_package_/web/rest/errors/ExceptionTranslator.java.ejs +4 -7
- package/dist/generators/server/templates/src/test/java/_package_/_entityPackage_/web/rest/_entityClass_ResourceIT.java.ejs +3 -3
- package/dist/generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT.java.ejs +4 -4
- package/dist/generators/spring-data-elasticsearch/templates/src/main/java/_package_/_entityPackage_/repository/search/_entityClass_SearchRepository.java.ejs +0 -2
- package/dist/generators/spring-data-neo4j/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.spring_data_neo4j.ejs +3 -37
- package/dist/generators/vue/generator.mjs +25 -16
- package/dist/generators/vue/resources/package.json +17 -16
- package/dist/generators/vue/templates/package.json.ejs +3 -5
- package/dist/generators/vue/templates/src/main/webapp/app/core/jhi-navbar/jhi-navbar.component.ts.ejs +10 -3
- package/dist/generators/vue/templates/src/main/webapp/app/core/jhi-navbar/jhi-navbar.vue.ejs +3 -4
- package/dist/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.service.ts.ejs +1 -1
- package/dist/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.vue.ejs +12 -0
- package/dist/generators/vue/templates/src/main/webapp/app/router/index.ts.ejs +8 -1
- package/dist/generators/vue/templates/webpack/webpack.microfrontend.js.jhi.vue.ejs +19 -34
- package/dist/jdl/converters/jdl-to-json/jdl-to-json-option-converter.js +2 -2
- package/dist/jdl/converters/jdl-to-json/jdl-to-json-relationship-converter.js +1 -1
- package/dist/jdl/converters/jdl-to-json/jdl-without-application-to-json-converter.js +1 -1
- package/dist/jdl/converters/parsed-jdl-to-jdl-object/application-converter.js +1 -17
- package/dist/jdl/exporters/applications/jhipster-application-formatter.js +17 -1
- package/dist/jdl/exporters/config.js +11 -0
- package/dist/jdl/exporters/export-utils.js +2 -13
- package/dist/jdl/index.js +1 -0
- package/dist/jdl/jdl-importer.js +6 -2
- package/dist/jdl/models/jdl-application-configuration-factory.js +34 -2
- package/dist/jdl/models/jdl-application-configuration.js +6 -3
- package/dist/jdl/models/jdl-application-factory.js +2 -2
- package/dist/jdl/models/jdl-application.js +12 -3
- package/dist/jdl/parsing/jdl-ast-builder-visitor.js +63 -7
- package/dist/jdl/parsing/jdl-parser.js +52 -6
- package/dist/jdl/parsing/lexer/application-tokens.js +1 -1
- package/dist/jdl/validators/entity-validator.js +4 -2
- package/dist/jdl/validators/enum-validator.js +4 -2
- package/dist/jdl/validators/jdl-with-application-validator.js +18 -8
- package/dist/jdl/validators/jdl-without-application-validator.js +30 -29
- package/dist/jdl/validators/validator.js +1 -1
- package/dist/types/generators/base/support/config.d.mts +3 -3
- package/dist/types/generators/base-application/support/prepare-entity.d.mts +6 -1
- package/dist/types/generators/bootstrap/support/auto-crlf-transform.d.mts +3 -2
- package/dist/types/generators/bootstrap/support/multi-step-transform/index.d.mts +3 -20
- package/dist/types/generators/bootstrap/support/multi-step-transform/template-file-fs.d.mts +15 -9
- package/dist/types/generators/bootstrap/support/multi-step-transform/template-file.d.mts +1 -0
- package/dist/types/generators/generator-constants.d.mts +3 -3
- package/dist/types/generators/java/support/package-info-transform.d.mts +1 -4
- package/dist/types/generators/server/support/templates/field-values.d.mts +1 -1
- package/dist/types/jdl/exporters/config.d.ts +1 -0
- package/dist/types/jdl/index.d.ts +1 -0
- package/dist/types/jdl/jdl-importer.d.ts +1 -0
- package/dist/types/jdl/models/jdl-application-configuration-factory.d.ts +1 -0
- package/dist/types/jdl/models/jdl-application-configuration-option.d.ts +2 -2
- package/dist/types/jdl/models/jdl-application-configuration.d.ts +8 -6
- package/dist/types/jdl/models/jdl-application-factory.d.ts +1 -1
- package/dist/types/jdl/models/jdl-application.d.ts +8 -4
- package/dist/types/jdl/models/jdl-object.d.ts +1 -1
- package/dist/types/jdl/models/list-jdl-application-configuration-option.d.ts +1 -1
- package/dist/types/jdl/parsing/jdl-ast-builder-visitor.d.ts +10 -0
- package/dist/types/jdl/parsing/jdl-parser.d.ts +3 -0
- package/dist/types/jdl/parsing/lexer/application-tokens.d.ts +1 -0
- package/dist/types/jdl/validators/entity-validator.d.ts +2 -2
- package/dist/types/jdl/validators/enum-validator.d.ts +2 -2
- package/dist/types/jdl/validators/validator.d.ts +4 -1
- package/package.json +31 -31
|
@@ -17,36 +17,26 @@
|
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
19
|
/* eslint-disable consistent-return */
|
|
20
|
-
import
|
|
21
|
-
import fs from 'fs';
|
|
22
|
-
import ChildProcess from 'child_process';
|
|
23
|
-
import util from 'util';
|
|
24
|
-
import * as _ from 'lodash-es';
|
|
20
|
+
import { kebabCase } from 'lodash-es';
|
|
25
21
|
import chalk from 'chalk';
|
|
26
22
|
import { glob } from 'glob';
|
|
27
|
-
import
|
|
28
|
-
import BaseGenerator from '../base/index.mjs';
|
|
23
|
+
import BaseGenerator from '../base-application/index.mjs';
|
|
29
24
|
import statistics from '../statistics.mjs';
|
|
30
|
-
import {
|
|
31
|
-
import { GENERATOR_HEROKU } from '../generator-list.mjs';
|
|
32
|
-
import { authenticationTypes, buildToolTypes, cacheTypes, databaseTypes, searchEngineTypes, serviceDiscoveryTypes, } from '../../jdl/jhipster/index.mjs';
|
|
25
|
+
import { JAVA_COMPATIBLE_VERSIONS, JAVA_VERSION, SERVER_MAIN_RES_DIR } from '../generator-constants.mjs';
|
|
26
|
+
import { GENERATOR_BOOTSTRAP_APPLICATION, GENERATOR_HEROKU } from '../generator-list.mjs';
|
|
33
27
|
import { mavenProfileContent } from './templates.mjs';
|
|
34
28
|
import { createPomStorage } from '../maven/support/pom-store.mjs';
|
|
35
29
|
import { addGradlePluginCallback, applyFromGradleCallback } from '../gradle/internal/needles.mjs';
|
|
36
|
-
import { getFrontendAppName } from '../base/support/index.mjs';
|
|
37
|
-
import { loadAppConfig, loadDerivedAppConfig } from '../app/support/index.mjs';
|
|
38
|
-
import { loadDerivedPlatformConfig, loadDerivedServerConfig, loadPlatformConfig, loadServerConfig } from '../server/support/index.mjs';
|
|
39
|
-
import { loadLanguagesConfig } from '../languages/support/index.mjs';
|
|
40
|
-
const cacheProviderOptions = cacheTypes;
|
|
41
|
-
const { MEMCACHED, REDIS } = cacheTypes;
|
|
42
|
-
const { OAUTH2 } = authenticationTypes;
|
|
43
|
-
const { GRADLE, MAVEN } = buildToolTypes;
|
|
44
|
-
const { ELASTICSEARCH } = searchEngineTypes;
|
|
45
|
-
const { MARIADB, MYSQL, POSTGRESQL } = databaseTypes;
|
|
46
|
-
const { EUREKA } = serviceDiscoveryTypes;
|
|
47
|
-
const NO_CACHE_PROVIDER = cacheProviderOptions.NO;
|
|
48
|
-
const execCmd = util.promisify(ChildProcess.exec);
|
|
49
30
|
export default class HerokuGenerator extends BaseGenerator {
|
|
31
|
+
hasHerokuCli;
|
|
32
|
+
herokuAppName;
|
|
33
|
+
herokuDeployType;
|
|
34
|
+
herokuJavaVersion;
|
|
35
|
+
herokuRegion;
|
|
36
|
+
herokuAppExists;
|
|
37
|
+
herokuSkipDeploy;
|
|
38
|
+
herokuSkipBuild;
|
|
39
|
+
dynoSize;
|
|
50
40
|
constructor(args, options, features) {
|
|
51
41
|
super(args, options, features);
|
|
52
42
|
this.option('skip-build', {
|
|
@@ -62,7 +52,6 @@ export default class HerokuGenerator extends BaseGenerator {
|
|
|
62
52
|
if (this.options.help) {
|
|
63
53
|
return;
|
|
64
54
|
}
|
|
65
|
-
this.randomPassword = crypto.randomBytes(20).toString('hex');
|
|
66
55
|
this.herokuSkipBuild = this.options.skipBuild;
|
|
67
56
|
this.herokuSkipDeploy = this.options.skipDeploy || this.options.skipBuild;
|
|
68
57
|
}
|
|
@@ -70,520 +59,338 @@ export default class HerokuGenerator extends BaseGenerator {
|
|
|
70
59
|
if (!this.fromBlueprint) {
|
|
71
60
|
await this.composeWithBlueprints(GENERATOR_HEROKU);
|
|
72
61
|
}
|
|
62
|
+
if (!this.delegateToBlueprint) {
|
|
63
|
+
await this.dependsOnJHipster(GENERATOR_BOOTSTRAP_APPLICATION);
|
|
64
|
+
}
|
|
73
65
|
}
|
|
74
66
|
get initializing() {
|
|
75
|
-
return {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
67
|
+
return this.asInitializingTaskGroup({
|
|
68
|
+
async checkInstallation() {
|
|
69
|
+
const { exitCode } = await this.spawnHerokuCommand('--version', { verboseInfo: false });
|
|
70
|
+
this.hasHerokuCli = exitCode === 0;
|
|
71
|
+
if (!this.hasHerokuCli) {
|
|
72
|
+
const error = "You don't have the Heroku CLI installed. See https://devcenter.heroku.com/articles/heroku-cli#install-the-heroku-cli to learn how to install it.";
|
|
73
|
+
if (this.skipChecks) {
|
|
74
|
+
this.log.warn(error);
|
|
75
|
+
this.log.warn('Generation will continue with limited support');
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
throw new Error(`${error} To ignore this error run 'jhipster heroku --skip-checks'`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
async herokuLogin() {
|
|
83
|
+
if (!this.hasHerokuCli)
|
|
84
|
+
return;
|
|
85
|
+
const { exitCode } = await this.spawnHerokuCommand('whoami', { verboseInfo: false });
|
|
86
|
+
if (exitCode !== 0) {
|
|
87
|
+
this.log.log(chalk.bold('Log in to Heroku to continue.'));
|
|
88
|
+
await this.spawnHerokuCommand('login', { reject: true, stdio: 'inherit' });
|
|
89
|
+
}
|
|
84
90
|
},
|
|
85
91
|
initializing() {
|
|
86
92
|
this.log.log(chalk.bold('Heroku configuration is starting'));
|
|
87
|
-
|
|
88
|
-
this.
|
|
89
|
-
this.cacheProvider = this.cacheProvider || NO_CACHE_PROVIDER;
|
|
90
|
-
this.enableHibernateCache = this.enableHibernateCache && ![NO_CACHE_PROVIDER, MEMCACHED].includes(this.cacheProvider);
|
|
91
|
-
this.frontendAppName = getFrontendAppName({ baseName: this.jhipsterConfig.baseName });
|
|
92
|
-
this.herokuAppName = configuration.get('herokuAppName');
|
|
93
|
-
this.dynoSize = 'Free';
|
|
94
|
-
this.herokuDeployType = configuration.get('herokuDeployType');
|
|
95
|
-
this.herokuJavaVersion = configuration.get('herokuJavaVersion');
|
|
96
|
-
this.useOkta = configuration.get('useOkta');
|
|
97
|
-
this.oktaAdminLogin = configuration.get('oktaAdminLogin');
|
|
98
|
-
this.oktaAdminPassword = configuration.get('oktaAdminPassword');
|
|
93
|
+
this.dynoSize = 'Basic';
|
|
94
|
+
this.herokuAppExists = Boolean(this.jhipsterConfig.herokuAppName);
|
|
99
95
|
},
|
|
100
|
-
};
|
|
96
|
+
});
|
|
101
97
|
}
|
|
102
98
|
get [BaseGenerator.INITIALIZING]() {
|
|
103
99
|
return this.delegateTasksToBlueprint(() => this.initializing);
|
|
104
100
|
}
|
|
105
101
|
get prompting() {
|
|
106
|
-
return {
|
|
107
|
-
askForApp
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (err) {
|
|
112
|
-
this.abort = true;
|
|
113
|
-
this.log.error(`Could not find application: ${chalk.cyan(this.herokuAppName)}`);
|
|
114
|
-
this.log.error('Run the generator again to create a new application.');
|
|
115
|
-
this.herokuAppName = null;
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
const json = JSON.parse(stdout);
|
|
119
|
-
this.herokuAppName = json.app.name;
|
|
120
|
-
if (json.dynos.length > 0) {
|
|
121
|
-
this.dynoSize = json.dynos[0].size;
|
|
122
|
-
}
|
|
123
|
-
this.log.verboseInfo(`Deploying as existing application: ${chalk.bold(this.herokuAppName)}`);
|
|
124
|
-
this.herokuAppExists = true;
|
|
125
|
-
this.config.set({
|
|
126
|
-
herokuAppName: this.herokuAppName,
|
|
127
|
-
herokuDeployType: this.herokuDeployType,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
done();
|
|
102
|
+
return this.asPromptingTaskGroup({
|
|
103
|
+
async askForApp() {
|
|
104
|
+
if (this.hasHerokuCli && this.herokuAppExists) {
|
|
105
|
+
const { stdout, exitCode } = await this.spawnHeroku(['apps:info', '--json', this.jhipsterConfig.herokuAppName], {
|
|
106
|
+
verboseInfo: false,
|
|
131
107
|
});
|
|
108
|
+
if (exitCode !== 0) {
|
|
109
|
+
this.log.error(`Could not find application: ${chalk.cyan(this.jhipsterConfig.herokuAppName)}`);
|
|
110
|
+
this.herokuAppName = null;
|
|
111
|
+
throw new Error('Run the generator again to create a new application.');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
const json = JSON.parse(stdout);
|
|
115
|
+
this.herokuAppName = json.app.name;
|
|
116
|
+
if (json.dynos.length > 0) {
|
|
117
|
+
this.dynoSize = json.dynos[0].size;
|
|
118
|
+
}
|
|
119
|
+
this.log.verboseInfo(`Deploying as existing application: ${chalk.bold(this.herokuAppName)}`);
|
|
120
|
+
this.config.set({
|
|
121
|
+
herokuAppName: this.herokuAppName,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
132
124
|
}
|
|
133
125
|
else {
|
|
134
|
-
|
|
126
|
+
await this.prompt([
|
|
135
127
|
{
|
|
136
128
|
type: 'input',
|
|
137
129
|
name: 'herokuAppName',
|
|
138
130
|
message: 'Name to deploy as:',
|
|
139
131
|
default: this.baseName,
|
|
140
132
|
},
|
|
133
|
+
], this.config);
|
|
134
|
+
const answers = await this.prompt([
|
|
141
135
|
{
|
|
142
136
|
type: 'list',
|
|
143
137
|
name: 'herokuRegion',
|
|
144
|
-
message: 'On which region do you want to deploy
|
|
138
|
+
message: 'On which region do you want to deploy?',
|
|
145
139
|
choices: ['us', 'eu'],
|
|
146
140
|
default: 0,
|
|
147
141
|
},
|
|
148
|
-
];
|
|
149
|
-
this.
|
|
150
|
-
this.herokuAppName = _.kebabCase(props.herokuAppName);
|
|
151
|
-
this.herokuRegion = props.herokuRegion;
|
|
152
|
-
this.herokuAppExists = false;
|
|
153
|
-
done();
|
|
154
|
-
});
|
|
142
|
+
]);
|
|
143
|
+
this.herokuRegion = answers.herokuRegion;
|
|
155
144
|
}
|
|
156
|
-
}
|
|
157
|
-
askForHerokuDeployType() {
|
|
158
|
-
|
|
159
|
-
return null;
|
|
160
|
-
if (this.herokuDeployType)
|
|
161
|
-
return null;
|
|
162
|
-
const prompts = [
|
|
145
|
+
},
|
|
146
|
+
async askForHerokuDeployType() {
|
|
147
|
+
await this.prompt([
|
|
163
148
|
{
|
|
164
149
|
type: 'list',
|
|
165
150
|
name: 'herokuDeployType',
|
|
166
|
-
message: 'Which type of deployment do you want
|
|
151
|
+
message: 'Which type of deployment do you want?',
|
|
167
152
|
choices: [
|
|
168
|
-
{
|
|
169
|
-
|
|
170
|
-
name: 'Git (compile on Heroku)',
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
value: 'jar',
|
|
174
|
-
name: 'JAR (compile locally)',
|
|
175
|
-
},
|
|
153
|
+
{ value: 'git', name: 'Git (compile on Heroku)' },
|
|
154
|
+
{ value: 'jar', name: 'JAR (compile locally)' },
|
|
176
155
|
],
|
|
177
156
|
default: 0,
|
|
178
157
|
},
|
|
179
|
-
];
|
|
180
|
-
return this.prompt(prompts).then(props => {
|
|
181
|
-
this.herokuDeployType = props.herokuDeployType;
|
|
182
|
-
});
|
|
158
|
+
], this.config);
|
|
183
159
|
},
|
|
184
|
-
askForHerokuJavaVersion() {
|
|
185
|
-
|
|
186
|
-
return null;
|
|
187
|
-
if (this.herokuJavaVersion)
|
|
188
|
-
return null;
|
|
189
|
-
const prompts = [
|
|
160
|
+
async askForHerokuJavaVersion() {
|
|
161
|
+
await this.prompt([
|
|
190
162
|
{
|
|
191
163
|
type: 'list',
|
|
192
164
|
name: 'herokuJavaVersion',
|
|
193
|
-
message: 'Which Java version would you like to use to build and run your app
|
|
165
|
+
message: 'Which Java version would you like to use to build and run your app?',
|
|
194
166
|
choices: JAVA_COMPATIBLE_VERSIONS.map(version => ({ value: version })),
|
|
195
167
|
default: JAVA_VERSION,
|
|
196
168
|
},
|
|
197
|
-
];
|
|
198
|
-
return this.prompt(prompts).then(props => {
|
|
199
|
-
this.herokuJavaVersion = props.herokuJavaVersion;
|
|
200
|
-
});
|
|
169
|
+
], this.config);
|
|
201
170
|
},
|
|
202
|
-
|
|
203
|
-
if (this.abort)
|
|
204
|
-
return null;
|
|
205
|
-
if (this.authenticationType !== OAUTH2)
|
|
206
|
-
return null;
|
|
207
|
-
if (this.useOkta)
|
|
208
|
-
return null;
|
|
209
|
-
const prompts = [
|
|
210
|
-
{
|
|
211
|
-
type: 'list',
|
|
212
|
-
name: 'useOkta',
|
|
213
|
-
message: 'You are using OAuth 2.0. Do you want to use Okta? When you choose Okta, the automated configuration of users and groups requires cURL and jq.',
|
|
214
|
-
choices: [
|
|
215
|
-
{
|
|
216
|
-
value: true,
|
|
217
|
-
name: 'Yes, provision the Okta add-on',
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
value: false,
|
|
221
|
-
name: 'No, I want to configure my identity provider manually',
|
|
222
|
-
},
|
|
223
|
-
],
|
|
224
|
-
default: 1,
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
when: answers => answers.useOkta,
|
|
228
|
-
type: 'input',
|
|
229
|
-
name: 'oktaAdminLogin',
|
|
230
|
-
message: 'Login (valid email) for the JHipster Admin user:',
|
|
231
|
-
validate: input => {
|
|
232
|
-
if (!input) {
|
|
233
|
-
return 'You must enter a login for the JHipster admin';
|
|
234
|
-
}
|
|
235
|
-
return true;
|
|
236
|
-
},
|
|
237
|
-
},
|
|
238
|
-
];
|
|
239
|
-
return this.prompt(prompts).then(props => {
|
|
240
|
-
this.useOkta = props.useOkta;
|
|
241
|
-
if (this.useOkta) {
|
|
242
|
-
this.oktaAdminLogin = props.oktaAdminLogin;
|
|
243
|
-
this.oktaAdminPassword = this.randomPassword;
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
},
|
|
247
|
-
};
|
|
171
|
+
});
|
|
248
172
|
}
|
|
249
173
|
get [BaseGenerator.PROMPTING]() {
|
|
250
174
|
return this.delegateTasksToBlueprint(() => this.prompting);
|
|
251
175
|
}
|
|
252
|
-
get
|
|
253
|
-
return {
|
|
254
|
-
checkInstallation: runAsync(function () {
|
|
255
|
-
if (this.abort)
|
|
256
|
-
return;
|
|
257
|
-
const done = this.async();
|
|
258
|
-
ChildProcess.exec('heroku --version', err => {
|
|
259
|
-
if (err) {
|
|
260
|
-
this.log.error("You don't have the Heroku CLI installed. Download it from https://cli.heroku.com/");
|
|
261
|
-
this.abort = true;
|
|
262
|
-
}
|
|
263
|
-
done();
|
|
264
|
-
});
|
|
265
|
-
}),
|
|
176
|
+
get loading() {
|
|
177
|
+
return this.asConfiguringTaskGroup({
|
|
266
178
|
saveConfig() {
|
|
267
|
-
this.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
herokuJavaVersion: this.herokuJavaVersion,
|
|
271
|
-
useOkta: this.useOkta,
|
|
272
|
-
oktaAdminLogin: this.oktaAdminLogin,
|
|
273
|
-
});
|
|
179
|
+
this.herokuAppName = kebabCase(this.jhipsterConfig.herokuAppName);
|
|
180
|
+
this.herokuJavaVersion = this.jhipsterConfig.herokuJavaVersion;
|
|
181
|
+
this.herokuDeployType = this.jhipsterConfig.herokuDeployType;
|
|
274
182
|
},
|
|
275
|
-
};
|
|
183
|
+
});
|
|
276
184
|
}
|
|
277
|
-
get [BaseGenerator.
|
|
278
|
-
return this.delegateTasksToBlueprint(() => this.
|
|
185
|
+
get [BaseGenerator.LOADING]() {
|
|
186
|
+
return this.delegateTasksToBlueprint(() => this.loading);
|
|
279
187
|
}
|
|
280
188
|
get default() {
|
|
281
|
-
return {
|
|
189
|
+
return this.asDefaultTaskGroup({
|
|
282
190
|
insight() {
|
|
283
191
|
statistics.sendSubGenEvent('generator', GENERATOR_HEROKU);
|
|
284
192
|
},
|
|
285
|
-
gitInit
|
|
286
|
-
if (this.
|
|
193
|
+
async gitInit() {
|
|
194
|
+
if (!this.herokuDeployType === 'git')
|
|
287
195
|
return;
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
fs.lstatSync('.git');
|
|
196
|
+
const git = this.createGit();
|
|
197
|
+
if (await git.checkIsRepo()) {
|
|
291
198
|
this.log.log(chalk.bold('\nUsing existing Git repository'));
|
|
292
|
-
done();
|
|
293
199
|
}
|
|
294
|
-
|
|
295
|
-
// An exception is thrown if the folder doesn't exist
|
|
200
|
+
else {
|
|
296
201
|
this.log.log(chalk.bold('\nInitializing Git repository'));
|
|
297
|
-
|
|
298
|
-
done();
|
|
299
|
-
});
|
|
300
|
-
child.stdout.on('data', data => {
|
|
301
|
-
this.log.verboseInfo(data.toString());
|
|
302
|
-
});
|
|
202
|
+
await git.init();
|
|
303
203
|
}
|
|
304
|
-
}
|
|
305
|
-
installHerokuDeployPlugin
|
|
306
|
-
if (this.
|
|
204
|
+
},
|
|
205
|
+
async installHerokuDeployPlugin() {
|
|
206
|
+
if (!this.hasHerokuCli)
|
|
307
207
|
return;
|
|
308
|
-
const done = this.async();
|
|
309
208
|
const cliPlugin = 'heroku-cli-deploy';
|
|
310
|
-
|
|
311
|
-
|
|
209
|
+
const { stdout, stderr, exitCode } = await this.spawnHerokuCommand('plugins', { stdio: 'pipe' });
|
|
210
|
+
if (exitCode !== 0) {
|
|
211
|
+
if (stdout.includes(cliPlugin)) {
|
|
312
212
|
this.log.log('\nHeroku CLI deployment plugin already installed');
|
|
313
|
-
done();
|
|
314
213
|
}
|
|
315
214
|
else {
|
|
316
215
|
this.log.log(chalk.bold('\nInstalling Heroku CLI deployment plugin'));
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
done();
|
|
323
|
-
});
|
|
324
|
-
child.stdout.on('data', data => {
|
|
325
|
-
this.log.verboseInfo(data.toString());
|
|
326
|
-
});
|
|
216
|
+
const { exitCode } = await this.spawnHerokuCommand(`plugins:install ${cliPlugin}`);
|
|
217
|
+
if (exitCode !== 0) {
|
|
218
|
+
throw new Error(stderr);
|
|
219
|
+
}
|
|
327
220
|
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
herokuCreate
|
|
331
|
-
if (this.
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
async herokuCreate() {
|
|
224
|
+
if (!this.hasHerokuCli || this.herokuAppExists)
|
|
332
225
|
return;
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
this.log.error(err);
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
this.log.verboseInfo(stdout.trim());
|
|
367
|
-
this.config.set({
|
|
368
|
-
herokuAppName: this.herokuAppName,
|
|
369
|
-
herokuDeployType: this.herokuDeployType,
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
done();
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
else {
|
|
376
|
-
ChildProcess.exec(`heroku create ${regionParams}`, (err, stdout) => {
|
|
377
|
-
if (err) {
|
|
378
|
-
this.abort = true;
|
|
379
|
-
this.log.error(err);
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
// Extract from "Created random-app-name-1234... done"
|
|
383
|
-
this.herokuAppName = stdout.substring(stdout.indexOf('https://') + 8, stdout.indexOf('.herokuapp'));
|
|
384
|
-
this.log.verboseInfo(stdout.trim());
|
|
385
|
-
// ensure that the git remote is the same as the appName
|
|
386
|
-
ChildProcess.exec(`heroku git:remote --app ${this.herokuAppName}`, err => {
|
|
387
|
-
if (err) {
|
|
388
|
-
this.abort = true;
|
|
389
|
-
this.log.error(err);
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
392
|
-
this.config.set({
|
|
393
|
-
herokuAppName: this.herokuAppName,
|
|
394
|
-
herokuDeployType: this.herokuDeployType,
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
done();
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
});
|
|
226
|
+
const regionParams = this.herokuRegion !== 'us' ? ['--region', this.herokuRegion] : [];
|
|
227
|
+
this.log.log(chalk.bold('\nCreating Heroku application and setting up Node environment'));
|
|
228
|
+
const { stdout, stderr, exitCode } = await this.spawnHeroku(['create', this.herokuAppName, ...regionParams]);
|
|
229
|
+
if (stdout.includes('Heroku credentials')) {
|
|
230
|
+
throw new Error("Error: Not authenticated. Run 'heroku login' to log in to your Heroku account and try again.");
|
|
231
|
+
}
|
|
232
|
+
if (exitCode !== 0) {
|
|
233
|
+
if (stderr.includes('is already taken')) {
|
|
234
|
+
const prompts = [
|
|
235
|
+
{
|
|
236
|
+
type: 'list',
|
|
237
|
+
name: 'herokuForceName',
|
|
238
|
+
message: `The Heroku application "${chalk.cyan(this.herokuAppName)}" already exists! Use it anyways?`,
|
|
239
|
+
choices: [
|
|
240
|
+
{
|
|
241
|
+
value: 'Yes',
|
|
242
|
+
name: 'Yes, I have access to it',
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
value: 'No',
|
|
246
|
+
name: 'No, generate a random name',
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
default: 0,
|
|
250
|
+
},
|
|
251
|
+
];
|
|
252
|
+
this.log.log('');
|
|
253
|
+
const props = await this.prompt(prompts);
|
|
254
|
+
if (props.herokuForceName === 'Yes') {
|
|
255
|
+
await this.spawnHeroku(['git:remote', '--app', this.herokuAppName], { reject: true });
|
|
403
256
|
}
|
|
404
257
|
else {
|
|
405
|
-
this.
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
this.log.error(err);
|
|
412
|
-
}
|
|
258
|
+
const { stdout } = await this.spawnHeroku(['create', ...regionParams]);
|
|
259
|
+
// Extract from "Created random-app-name-1234... done"
|
|
260
|
+
this.herokuAppName = stdout.substring(stdout.lastIndexOf('/') + 1, stdout.indexOf('.git'));
|
|
261
|
+
// ensure that the git remote is the same as the appName
|
|
262
|
+
await this.spawnHeroku(['git:remote', '--app', this.herokuAppName]);
|
|
263
|
+
this.jhipsterConfig.herokuAppName = this.herokuAppName;
|
|
413
264
|
}
|
|
414
265
|
}
|
|
415
|
-
else {
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
child.stdout.on('data', data => {
|
|
420
|
-
const output = data.toString();
|
|
421
|
-
if (data.search('Heroku credentials') >= 0) {
|
|
422
|
-
this.abort = true;
|
|
423
|
-
this.log.error("Error: Not authenticated. Run 'heroku login' to login to your heroku account and try again.");
|
|
424
|
-
done();
|
|
266
|
+
else if (stderr.includes('Invalid credentials')) {
|
|
267
|
+
this.log.error("Error: Not authenticated. Run 'heroku login' to log in to your Heroku account and try again.");
|
|
425
268
|
}
|
|
426
269
|
else {
|
|
427
|
-
|
|
270
|
+
throw new Error(stderr);
|
|
428
271
|
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
herokuAddonsCreate
|
|
432
|
-
if (this.
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
async herokuAddonsCreate({ application }) {
|
|
275
|
+
if (!this.hasHerokuCli || this.herokuAppExists)
|
|
433
276
|
return;
|
|
434
|
-
const done = this.async();
|
|
435
|
-
const addonCreateCallback = (addon, err) => {
|
|
436
|
-
if (err) {
|
|
437
|
-
const verifyAccountUrl = 'https://heroku.com/verify';
|
|
438
|
-
if (_.includes(err, verifyAccountUrl)) {
|
|
439
|
-
this.abort = true;
|
|
440
|
-
this.log.error(`Account must be verified to use addons. Please go to: ${verifyAccountUrl}`);
|
|
441
|
-
this.log.error(err);
|
|
442
|
-
}
|
|
443
|
-
else {
|
|
444
|
-
this.log.verboseInfo(`No new ${addon} addon created`);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
else {
|
|
448
|
-
this.log.verboseInfo(`Created ${addon} addon`);
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
277
|
this.log.log(chalk.bold('\nProvisioning addons'));
|
|
452
|
-
if (
|
|
278
|
+
if (application.searchEngineElasticsearch) {
|
|
453
279
|
this.log.log(chalk.bold('\nProvisioning bonsai elasticsearch addon'));
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
});
|
|
280
|
+
const { stdout, stderr } = await this.spawn('heroku', [
|
|
281
|
+
'addons:create',
|
|
282
|
+
'bonsai:sandbox-6',
|
|
283
|
+
'--as',
|
|
284
|
+
'BONSAI',
|
|
285
|
+
'--app',
|
|
286
|
+
this.herokuAppName,
|
|
287
|
+
]);
|
|
288
|
+
this.checkAddOnReturn({ addOn: 'Elasticsearch', stdout, stderr });
|
|
463
289
|
}
|
|
464
290
|
let dbAddOn;
|
|
465
|
-
if (
|
|
466
|
-
dbAddOn = 'heroku-postgresql
|
|
291
|
+
if (application.prodDatabaseTypePostgresql) {
|
|
292
|
+
dbAddOn = 'heroku-postgresql';
|
|
467
293
|
}
|
|
468
|
-
else if (
|
|
469
|
-
dbAddOn = 'jawsdb:kitefin
|
|
294
|
+
else if (application.prodDatabaseTypeMysql) {
|
|
295
|
+
dbAddOn = 'jawsdb:kitefin';
|
|
470
296
|
}
|
|
471
|
-
else if (
|
|
472
|
-
dbAddOn = 'jawsdb-maria:kitefin
|
|
297
|
+
else if (application.prodDatabaseTypeMariadb) {
|
|
298
|
+
dbAddOn = 'jawsdb-maria:kitefin';
|
|
473
299
|
}
|
|
474
300
|
if (dbAddOn) {
|
|
475
301
|
this.log.log(chalk.bold(`\nProvisioning database addon ${dbAddOn}`));
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
302
|
+
const { stdout, stderr } = await this.spawn('heroku', [
|
|
303
|
+
'addons:create',
|
|
304
|
+
dbAddOn,
|
|
305
|
+
'--as',
|
|
306
|
+
'DATABASE',
|
|
307
|
+
'--app',
|
|
308
|
+
this.herokuAppName,
|
|
309
|
+
]);
|
|
310
|
+
this.checkAddOnReturn({ addOn: 'Database', stdout, stderr });
|
|
479
311
|
}
|
|
480
312
|
else {
|
|
481
313
|
this.log.log(chalk.bold(`\nNo suitable database addon for database ${this.prodDatabaseType} available.`));
|
|
482
314
|
}
|
|
483
315
|
let cacheAddOn;
|
|
484
|
-
if (
|
|
485
|
-
cacheAddOn = 'memcachier:dev --as MEMCACHIER';
|
|
316
|
+
if (application.cacheProviderMemcached) {
|
|
317
|
+
cacheAddOn = ['memcachier:dev', '--as', 'MEMCACHIER'];
|
|
486
318
|
}
|
|
487
|
-
else if (
|
|
488
|
-
cacheAddOn = 'heroku-redis:hobby-dev --as REDIS';
|
|
319
|
+
else if (application.cacheProviderRedis) {
|
|
320
|
+
cacheAddOn = ['heroku-redis:hobby-dev', '--as', 'REDIS'];
|
|
489
321
|
}
|
|
490
322
|
if (cacheAddOn) {
|
|
491
|
-
this.log.log(chalk.bold(`\nProvisioning cache addon ${cacheAddOn}`));
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
});
|
|
323
|
+
this.log.log(chalk.bold(`\nProvisioning cache addon '${cacheAddOn}'`));
|
|
324
|
+
const { stdout, stderr } = await this.spawn('heroku', ['addons:create', ...cacheAddOn, '--app', this.herokuAppName]);
|
|
325
|
+
this.checkAddOnReturn({ addOn: 'Cache', stdout, stderr });
|
|
495
326
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
done();
|
|
500
|
-
}),
|
|
501
|
-
configureJHipsterRegistry() {
|
|
502
|
-
if (this.abort || this.herokuAppExists)
|
|
327
|
+
},
|
|
328
|
+
async configureJHipsterRegistry({ application }) {
|
|
329
|
+
if (!this.hasHerokuCli || this.herokuAppExists || !application.serviceDiscoveryEureka)
|
|
503
330
|
return undefined;
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const configSetCmd = `heroku config:set JHIPSTER_REGISTRY_URL=${herokuJHipsterRegistry} --app ${this.herokuAppName}`;
|
|
532
|
-
const child = ChildProcess.exec(configSetCmd, err => {
|
|
533
|
-
if (err) {
|
|
534
|
-
this.abort = true;
|
|
535
|
-
this.log.error(err);
|
|
536
|
-
}
|
|
537
|
-
});
|
|
538
|
-
child.stdout.on('data', data => {
|
|
539
|
-
this.log.verboseInfo(data.toString());
|
|
540
|
-
});
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
return undefined;
|
|
331
|
+
this.log.log('');
|
|
332
|
+
const answers = await this.prompt([
|
|
333
|
+
{
|
|
334
|
+
type: 'input',
|
|
335
|
+
name: 'herokuJHipsterRegistryApp',
|
|
336
|
+
message: 'What is the name of your JHipster Registry Heroku application?',
|
|
337
|
+
default: 'jhipster-registry',
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
type: 'input',
|
|
341
|
+
name: 'herokuJHipsterRegistryUsername',
|
|
342
|
+
message: 'What is your JHipster Registry username?',
|
|
343
|
+
default: 'admin',
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
type: 'input',
|
|
347
|
+
name: 'herokuJHipsterRegistryPassword',
|
|
348
|
+
message: 'What is your JHipster Registry password?',
|
|
349
|
+
default: 'password',
|
|
350
|
+
},
|
|
351
|
+
]);
|
|
352
|
+
// Encode username/password to avoid errors caused by spaces
|
|
353
|
+
const herokuJHipsterRegistryUsername = encodeURIComponent(answers.herokuJHipsterRegistryUsername);
|
|
354
|
+
const herokuJHipsterRegistryPassword = encodeURIComponent(answers.herokuJHipsterRegistryPassword);
|
|
355
|
+
const herokuJHipsterRegistry = `https://${herokuJHipsterRegistryUsername}:${herokuJHipsterRegistryPassword}@${answers.herokuJHipsterRegistryApp}.herokuapp.com`;
|
|
356
|
+
const configSetCmd = ['config:set', 'JHIPSTER_REGISTRY_URL', herokuJHipsterRegistry, '--app', this.herokuAppName];
|
|
357
|
+
await this.spawnHeroku(configSetCmd, { stdio: 'pipe' });
|
|
544
358
|
},
|
|
545
|
-
};
|
|
359
|
+
});
|
|
546
360
|
}
|
|
547
361
|
get [BaseGenerator.DEFAULT]() {
|
|
548
362
|
return this.delegateTasksToBlueprint(() => this.default);
|
|
549
363
|
}
|
|
550
364
|
get writing() {
|
|
551
365
|
return this.asWritingTaskGroup({
|
|
552
|
-
copyHerokuFiles() {
|
|
553
|
-
if (this.abort)
|
|
554
|
-
return;
|
|
366
|
+
copyHerokuFiles({ application }) {
|
|
555
367
|
this.log.log(chalk.bold('\nCreating Heroku deployment files'));
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
this.
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
});
|
|
368
|
+
const context = {
|
|
369
|
+
...application,
|
|
370
|
+
herokuAppName: this.herokuAppName,
|
|
371
|
+
dynoSize: this.dynoSize,
|
|
372
|
+
herokuJavaVersion: this.herokuJavaVersion,
|
|
373
|
+
herokuDeployType: this.herokuDeployType,
|
|
374
|
+
};
|
|
375
|
+
this.writeFile('bootstrap-heroku.yml.ejs', `${SERVER_MAIN_RES_DIR}/config/bootstrap-heroku.yml`, context);
|
|
376
|
+
this.writeFile('application-heroku.yml.ejs', `${SERVER_MAIN_RES_DIR}/config/application-heroku.yml`, context);
|
|
377
|
+
this.writeFile('Procfile.ejs', 'Procfile', context);
|
|
378
|
+
this.writeFile('system.properties.ejs', 'system.properties', context);
|
|
379
|
+
if (application.buildToolGradle) {
|
|
380
|
+
this.writeFile('heroku.gradle.ejs', 'gradle/heroku.gradle', context);
|
|
570
381
|
}
|
|
571
382
|
},
|
|
572
|
-
addHerokuBuildPlugin() {
|
|
573
|
-
if (
|
|
574
|
-
return;
|
|
575
|
-
if (this.buildTool !== GRADLE)
|
|
383
|
+
addHerokuBuildPlugin({ application }) {
|
|
384
|
+
if (!application.buildToolGradle)
|
|
576
385
|
return;
|
|
577
386
|
// TODO addGradlePluginCallback is an internal api, switch to source api when converted to BaseApplicationGenerator
|
|
578
|
-
this.editFile('build.gradle', addGradlePluginCallback({
|
|
387
|
+
this.editFile('build.gradle', addGradlePluginCallback({ id: 'com.heroku.sdk.heroku-gradle', version: '1.0.4' }));
|
|
579
388
|
// TODO applyFromGradleCallback is an internal api, switch to source api when converted to BaseApplicationGenerator
|
|
580
389
|
this.editFile('build.gradle', applyFromGradleCallback({ script: 'gradle/heroku.gradle' }));
|
|
581
390
|
},
|
|
582
|
-
addHerokuMavenProfile() {
|
|
583
|
-
if (
|
|
584
|
-
|
|
585
|
-
if (this.buildTool === MAVEN) {
|
|
586
|
-
this.addMavenProfile('heroku', mavenProfileContent(this));
|
|
391
|
+
addHerokuMavenProfile({ application }) {
|
|
392
|
+
if (application.buildToolMaven) {
|
|
393
|
+
this.addMavenProfile('heroku', mavenProfileContent(application));
|
|
587
394
|
}
|
|
588
395
|
},
|
|
589
396
|
});
|
|
@@ -593,151 +400,47 @@ export default class HerokuGenerator extends BaseGenerator {
|
|
|
593
400
|
}
|
|
594
401
|
get end() {
|
|
595
402
|
return this.asEndTaskGroup({
|
|
596
|
-
makeScriptExecutable() {
|
|
597
|
-
if (this.abort)
|
|
598
|
-
return;
|
|
599
|
-
if (this.useOkta) {
|
|
600
|
-
try {
|
|
601
|
-
fs.chmodSync('provision-okta-addon.sh', '755');
|
|
602
|
-
}
|
|
603
|
-
catch (err) {
|
|
604
|
-
this.log.warn(`${chalk.yellow.bold('WARNING!')}Failed to make 'provision-okta-addon.sh' executable, you may need to run 'chmod +x provison-okta-addon.sh'`);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
},
|
|
608
403
|
async productionBuild() {
|
|
609
|
-
if (this.abort)
|
|
610
|
-
return;
|
|
611
404
|
if (this.herokuSkipBuild || this.herokuDeployType === 'git') {
|
|
612
405
|
this.log.log(chalk.bold('\nSkipping build'));
|
|
613
406
|
return;
|
|
614
407
|
}
|
|
615
408
|
this.log.log(chalk.bold('\nBuilding application'));
|
|
616
409
|
// Use npm script so blueprints just need to override it.
|
|
617
|
-
await this.spawnCommand('npm run java:jar:prod', { stdio: '
|
|
410
|
+
await this.printChildOutput(this.spawnCommand('npm run java:jar:prod', { stdio: 'pipe' }));
|
|
618
411
|
},
|
|
619
|
-
async productionDeploy() {
|
|
620
|
-
if (this.
|
|
621
|
-
return;
|
|
622
|
-
if (this.herokuSkipDeploy) {
|
|
412
|
+
async productionDeploy({ application }) {
|
|
413
|
+
if (this.herokuSkipDeploy || !this.hasHerokuCli) {
|
|
623
414
|
this.log.log(chalk.bold('\nSkipping deployment'));
|
|
624
415
|
return;
|
|
625
416
|
}
|
|
626
417
|
if (this.herokuDeployType === 'git') {
|
|
627
418
|
try {
|
|
628
419
|
this.log.log(chalk.bold('\nUpdating Git repository'));
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
-
const gitAdd = execCmd(gitAddCmd);
|
|
632
|
-
gitAdd.child.stdout.on('data', data => {
|
|
633
|
-
this.log.verboseInfo(data);
|
|
634
|
-
});
|
|
635
|
-
gitAdd.child.stderr.on('data', data => {
|
|
636
|
-
this.log.verboseInfo(data);
|
|
637
|
-
});
|
|
638
|
-
await gitAdd;
|
|
639
|
-
const gitCommitCmd = 'git commit -m "Deploy to Heroku" --allow-empty';
|
|
640
|
-
this.log.log(chalk.cyan(gitCommitCmd));
|
|
641
|
-
const gitCommit = execCmd(gitCommitCmd);
|
|
642
|
-
gitCommit.child.stdout.on('data', data => {
|
|
643
|
-
this.log.verboseInfo(data);
|
|
644
|
-
});
|
|
645
|
-
gitCommit.child.stderr.on('data', data => {
|
|
646
|
-
this.log.verboseInfo(data);
|
|
647
|
-
});
|
|
648
|
-
await gitCommit;
|
|
420
|
+
const git = this.createGit().outputHandler((_command, stdout, stderr) => this.printChildOutput({ stdout, stderr }));
|
|
421
|
+
await git.add('.').commit('Deploy to Heroku', { '--allow-empty': null });
|
|
649
422
|
let buildpack = 'heroku/java';
|
|
650
|
-
let
|
|
651
|
-
|
|
423
|
+
let configName = 'MAVEN_CUSTOM_OPTS';
|
|
424
|
+
let configValues = '-Pprod,heroku -DskipTests';
|
|
425
|
+
if (application.buildToolGradle) {
|
|
652
426
|
buildpack = 'heroku/gradle';
|
|
653
|
-
|
|
427
|
+
configName = 'GRADLE_TASK';
|
|
428
|
+
configValues = 'stage -Pprod -PnodeInstall';
|
|
654
429
|
}
|
|
655
430
|
this.log.log(chalk.bold('\nConfiguring Heroku'));
|
|
656
|
-
await
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
this.logger.info(data);
|
|
660
|
-
// remote: ! The following add-ons were automatically provisioned: . These add-ons may incur additional cost,
|
|
661
|
-
// which is prorated to the second. Run `heroku addons` for more info.
|
|
662
|
-
if (data.includes('Run `heroku addons` for more info.')) {
|
|
663
|
-
await execCmd('heroku addons');
|
|
664
|
-
}
|
|
665
|
-
this.log('');
|
|
666
|
-
const prompts = [
|
|
667
|
-
{
|
|
668
|
-
type: 'list',
|
|
669
|
-
name: 'userDeployDecision',
|
|
670
|
-
message: 'Continue to deploy?',
|
|
671
|
-
choices: [
|
|
672
|
-
{
|
|
673
|
-
value: 'Yes',
|
|
674
|
-
name: 'Yes, I confirm',
|
|
675
|
-
},
|
|
676
|
-
{
|
|
677
|
-
value: 'No',
|
|
678
|
-
name: 'No, abort (Recommended)',
|
|
679
|
-
},
|
|
680
|
-
],
|
|
681
|
-
default: 0,
|
|
682
|
-
},
|
|
683
|
-
];
|
|
684
|
-
this.log('');
|
|
685
|
-
const props = await this.prompt(prompts);
|
|
686
|
-
if (props.userDeployDecision === 'Yes') {
|
|
687
|
-
this.log.info(chalk.bold('Continuing deployment...'));
|
|
688
|
-
}
|
|
689
|
-
else {
|
|
690
|
-
this.log(this.logger);
|
|
691
|
-
this.log.info(chalk.bold('You aborted deployment!'));
|
|
692
|
-
this.abort = true;
|
|
693
|
-
this.herokuAppName = null;
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
this.log('');
|
|
431
|
+
const { stdout: configData } = await this.spawnHeroku(['config:get', configName, '--app', this.herokuAppName]);
|
|
432
|
+
if (!configData) {
|
|
433
|
+
await this.spawnHeroku(['config:set', `${configName}=${configValues}`, '--app', this.herokuAppName]);
|
|
697
434
|
}
|
|
698
|
-
this.
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
this.log.verboseInfo(data);
|
|
705
|
-
});
|
|
706
|
-
await herokuPush;
|
|
435
|
+
const { stdout: buildpackData } = await this.spawnHeroku(['buildpacks', '--app', this.herokuAppName]);
|
|
436
|
+
if (!buildpackData.includes(buildpack)) {
|
|
437
|
+
await this.spawnHeroku(['buildpacks:add', buildpack, '--app', this.herokuAppName]);
|
|
438
|
+
}
|
|
439
|
+
this.log.log(chalk.bold('\nDeploying application...'));
|
|
440
|
+
await git.push('heroku', 'HEAD:main');
|
|
707
441
|
this.log.log(chalk.green(`\nYour app should now be live. To view it run\n\t${chalk.bold('heroku open')}`));
|
|
708
442
|
this.log.log(chalk.yellow(`And you can view the logs with this command\n\t${chalk.bold('heroku logs --tail')}`));
|
|
709
443
|
this.log.log(chalk.yellow(`After application modification, redeploy it with\n\t${chalk.bold('jhipster heroku')}`));
|
|
710
|
-
if (this.useOkta) {
|
|
711
|
-
let curlAvailable = false;
|
|
712
|
-
let jqAvailable = false;
|
|
713
|
-
try {
|
|
714
|
-
await execCmd('curl --help');
|
|
715
|
-
curlAvailable = true;
|
|
716
|
-
}
|
|
717
|
-
catch (err) {
|
|
718
|
-
this.log.log(chalk.red('cURL is not available but required. See https://curl.haxx.se/download.html for installation guidance.'));
|
|
719
|
-
this.log.log(chalk.yellow('After you have installed curl execute ./provision-okta-addon.sh manually.'));
|
|
720
|
-
}
|
|
721
|
-
try {
|
|
722
|
-
await execCmd('jq --help');
|
|
723
|
-
jqAvailable = true;
|
|
724
|
-
}
|
|
725
|
-
catch (err) {
|
|
726
|
-
this.log.log(chalk.red('jq is not available but required. See https://stedolan.github.io/jq/download/ for installation guidance.'));
|
|
727
|
-
this.log.log(chalk.yellow('After you have installed jq execute ./provision-okta-addon.sh manually.'));
|
|
728
|
-
}
|
|
729
|
-
if (curlAvailable && jqAvailable) {
|
|
730
|
-
this.log.log(chalk.green('Running ./provision-okta-addon.sh to create all required roles and users for JHipster.'));
|
|
731
|
-
try {
|
|
732
|
-
await execCmd('./provision-okta-addon.sh');
|
|
733
|
-
this.log.log(chalk.bold('\nOkta configured successfully!'));
|
|
734
|
-
this.log.log(chalk.green(`\nUse ${chalk.bold(`${this.oktaAdminLogin}/${this.oktaAdminPassword}`)} to login.\n`));
|
|
735
|
-
}
|
|
736
|
-
catch (err) {
|
|
737
|
-
this.log.log(chalk.red('Failed to execute ./provision-okta-addon.sh. Make sure to setup okta according to https://www.jhipster.tech/heroku/.'));
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
444
|
}
|
|
742
445
|
catch (err) {
|
|
743
446
|
this.log.error(err);
|
|
@@ -746,58 +449,18 @@ export default class HerokuGenerator extends BaseGenerator {
|
|
|
746
449
|
else {
|
|
747
450
|
this.log.log(chalk.bold('\nDeploying application'));
|
|
748
451
|
let jarFileWildcard = 'target/*.jar';
|
|
749
|
-
if (
|
|
452
|
+
if (application.buildToolGradle) {
|
|
750
453
|
jarFileWildcard = 'build/libs/*.jar';
|
|
751
454
|
}
|
|
752
455
|
const files = glob.sync(jarFileWildcard, {});
|
|
753
456
|
const jarFile = files[0];
|
|
754
|
-
const herokuDeployCommand = `heroku deploy:jar ${jarFile} --app ${this.herokuAppName}`;
|
|
755
|
-
const herokuSetBuildpackCommand = 'heroku buildpacks:set heroku/jvm';
|
|
756
457
|
this.log.log(chalk.bold(`\nUploading your application code.\nThis may take ${chalk.cyan('several minutes')} depending on your connection speed...`));
|
|
757
458
|
try {
|
|
758
|
-
await
|
|
759
|
-
|
|
760
|
-
herokuDeploy.child.stdout.on('data', data => {
|
|
761
|
-
this.log.verboseInfo(data);
|
|
762
|
-
});
|
|
763
|
-
herokuDeploy.child.stderr.on('data', data => {
|
|
764
|
-
this.log.verboseInfo(data);
|
|
765
|
-
});
|
|
766
|
-
await herokuDeploy;
|
|
459
|
+
await this.spawnHeroku(['deploy:jar', jarFile, '--app', this.herokuAppName], { stdio: 'pipe' });
|
|
460
|
+
await this.spawnHerokuCommand('buildpacks:set heroku/jvm', { stdio: 'pipe' });
|
|
767
461
|
this.log.log(chalk.green(`\nYour app should now be live. To view it run\n\t${chalk.bold('heroku open')}`));
|
|
768
462
|
this.log.log(chalk.yellow(`And you can view the logs with this command\n\t${chalk.bold('heroku logs --tail')}`));
|
|
769
463
|
this.log.log(chalk.yellow(`After application modification, redeploy it with\n\t${chalk.bold('jhipster heroku')}`));
|
|
770
|
-
if (this.useOkta) {
|
|
771
|
-
let curlAvailable = false;
|
|
772
|
-
let jqAvailable = false;
|
|
773
|
-
try {
|
|
774
|
-
await execCmd('curl --help');
|
|
775
|
-
curlAvailable = true;
|
|
776
|
-
}
|
|
777
|
-
catch (err) {
|
|
778
|
-
this.log.log(chalk.red('cURL is not available but required. See https://curl.haxx.se/download.html for installation guidance.'));
|
|
779
|
-
this.log.log(chalk.yellow('After you have installed curl execute ./provision-okta-addon.sh manually.'));
|
|
780
|
-
}
|
|
781
|
-
try {
|
|
782
|
-
await execCmd('jq --help');
|
|
783
|
-
jqAvailable = true;
|
|
784
|
-
}
|
|
785
|
-
catch (err) {
|
|
786
|
-
this.log.log(chalk.red('jq is not available but required. See https://stedolan.github.io/jq/download/ for installation guidance.'));
|
|
787
|
-
this.log.log(chalk.yellow('After you have installed jq execute ./provision-okta-addon.sh manually.'));
|
|
788
|
-
}
|
|
789
|
-
if (curlAvailable && jqAvailable) {
|
|
790
|
-
this.log.log(chalk.green('Running ./provision-okta-addon.sh to create all required roles and users for JHipster.'));
|
|
791
|
-
try {
|
|
792
|
-
await execCmd('./provision-okta-addon.sh');
|
|
793
|
-
this.log.log(chalk.bold('\nOkta configured successfully!'));
|
|
794
|
-
this.log.log(chalk.green(`\nUse ${chalk.bold(`${this.oktaAdminLogin}/${this.oktaAdminPassword}`)} to login.`));
|
|
795
|
-
}
|
|
796
|
-
catch (err) {
|
|
797
|
-
this.log.log(chalk.red('Failed to execute ./provision-okta-addon.sh. Make sure to set up Okta according to https://www.jhipster.tech/heroku/.'));
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
464
|
}
|
|
802
465
|
catch (err) {
|
|
803
466
|
this.log.error(err);
|
|
@@ -820,4 +483,64 @@ export default class HerokuGenerator extends BaseGenerator {
|
|
|
820
483
|
addMavenProfile(profileId, other) {
|
|
821
484
|
createPomStorage(this).addProfile({ id: profileId, content: other });
|
|
822
485
|
}
|
|
486
|
+
/**
|
|
487
|
+
* @param {string} command
|
|
488
|
+
* @param {import('execa').Options} opt
|
|
489
|
+
* @returns {ReturnType<BaseGenerator['spawnCommand']>}
|
|
490
|
+
*/
|
|
491
|
+
spawnHerokuCommand(command, opt) {
|
|
492
|
+
opt = { stdio: 'pipe', reject: false, ...opt };
|
|
493
|
+
const { verboseInfo, ...spawnOptions } = opt;
|
|
494
|
+
const child = this.spawnCommand(`heroku ${command}`, spawnOptions);
|
|
495
|
+
if (opt.stdio !== 'pipe' || verboseInfo === false) {
|
|
496
|
+
return child;
|
|
497
|
+
}
|
|
498
|
+
return this.printChildOutput(child);
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* @param {string[]} args
|
|
502
|
+
* @param {import('execa').Options} opt
|
|
503
|
+
* @returns {ReturnType<BaseGenerator['spawn']>}
|
|
504
|
+
*/
|
|
505
|
+
spawnHeroku(args, opt) {
|
|
506
|
+
opt = { stdio: 'pipe', reject: false, ...opt };
|
|
507
|
+
const { verboseInfo, ...spawnOptions } = opt;
|
|
508
|
+
const child = this.spawn('heroku', args, spawnOptions);
|
|
509
|
+
if (spawnOptions.stdio !== 'pipe' || verboseInfo === false) {
|
|
510
|
+
return child;
|
|
511
|
+
}
|
|
512
|
+
return this.printChildOutput(child);
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* @template {{stdout: any; stderr: any}} T
|
|
516
|
+
* @param {T} child
|
|
517
|
+
* @param {(chunk: any) => void} child
|
|
518
|
+
* @returns {T}
|
|
519
|
+
*/
|
|
520
|
+
printChildOutput(child, log = data => this.log.verboseInfo(data)) {
|
|
521
|
+
const { stdout, stderr } = child;
|
|
522
|
+
stdout.on('data', data => {
|
|
523
|
+
data.toString().split(/\r?\n/).filter(Boolean).forEach(log);
|
|
524
|
+
});
|
|
525
|
+
stderr.on('data', data => {
|
|
526
|
+
data.toString().split(/\r?\n/).filter(Boolean).forEach(log);
|
|
527
|
+
});
|
|
528
|
+
return child;
|
|
529
|
+
}
|
|
530
|
+
checkAddOnReturn({ addOn, stdout, stderr }) {
|
|
531
|
+
if (stdout) {
|
|
532
|
+
this.log.ok(`Created ${addOn.valueOf()} add-on`);
|
|
533
|
+
this.log.ok(stdout);
|
|
534
|
+
}
|
|
535
|
+
else if (stderr) {
|
|
536
|
+
const verifyAccountUrl = 'https://heroku.com/verify';
|
|
537
|
+
if (stderr.includes(verifyAccountUrl)) {
|
|
538
|
+
this.log.error(`Account must be verified to use addons. Please go to: ${verifyAccountUrl}`);
|
|
539
|
+
throw new Error(stderr);
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
this.log.verboseInfo(`No new ${addOn.valueOf()} add-on created`);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
823
546
|
}
|