generator-fastboot
Version:
Spring Boot + Angular/React/Vue in one handy generator
446 lines (406 loc) • 16.7 kB
JavaScript
/**
* Copyright 2013-2021 the original author or authors from the JHipster project.
*
* This file is part of the JHipster project, see https://www.jhipster.tech/
* for more information.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require('fs');
const exec = require('child_process').exec;
const chalk = require('chalk');
const BaseGenerator = require('../generator-base');
const statistics = require('../statistics');
const constants = require('../generator-constants');
const { OptionNames } = require('../../jdl/jhipster/application-options');
const cacheTypes = require('../../jdl/jhipster/cache-types');
const { MEMCACHED } = require('../../jdl/jhipster/cache-types');
const NO_CACHE_PROVIDER = cacheTypes.NO;
const { MAVEN, GRADLE } = require('../../jdl/jhipster/build-tool-types');
const { JWT } = require('../../jdl/jhipster/authentication-types');
module.exports = class extends BaseGenerator {
constructor(args, opts) {
super(args, opts);
this.option('skip-build', {
desc: 'Skips building the application',
type: Boolean,
defaults: false,
});
this.option('skip-deploy', {
desc: 'Skips deployment to Azure Spring Cloud',
type: Boolean,
defaults: false,
});
this.azureSpringCloudSkipBuild = this.options.skipBuild;
this.azureSpringCloudSkipDeploy = this.options.skipDeploy || this.options.skipBuild;
}
initializing() {
if (!this.options.fromCli) {
this.warning(
`Deprecated: JHipster seems to be invoked using Yeoman command. Please use the JHipster CLI. Run ${chalk.red(
'jhipster <command>'
)} instead of ${chalk.red('yo jhipster:<command>')}`
);
}
this.log(chalk.bold('Azure Spring Cloud configuration is starting'));
this.env.options.appPath = this.config.get('appPath') || constants.CLIENT_MAIN_SRC_DIR;
this.baseName = this.config.get(OptionNames.BASE_NAME);
this.packageName = this.config.get(OptionNames.PACKAGE_NAME);
this.packageFolder = this.config.get(OptionNames.PACKAGE_FOLDER);
this.authenticationType = this.config.get(OptionNames.AUTHENTICATION_TYPE);
this.jwtSecretKey = this.config.get(OptionNames.JWT_SECRET_KEY);
this.cacheProvider = this.config.get(OptionNames.CACHE_PROVIDER) || NO_CACHE_PROVIDER;
this.enableHibernateCache =
this.config.get(OptionNames.ENABLE_HIBERNATE_CACHE) && ![NO_CACHE_PROVIDER, MEMCACHED].includes(this.cacheProvider);
this.databaseType = this.config.get(OptionNames.DATABASE_TYPE);
this.prodDatabaseType = this.config.get(OptionNames.PROD_DATABASE_TYPE);
this.searchEngine = this.config.get(OptionNames.SEARCH_ENGINE);
this.frontendAppName = this.getFrontendAppName();
this.buildTool = this.config.get(OptionNames.BUILD_TOOL);
this.applicationType = this.config.get(OptionNames.APPLICATION_TYPE);
this.serviceDiscoveryType = this.config.get(OptionNames.SERVICE_DISCOVERY_TYPE);
this.azureSpringCloudResourceGroupName = ''; // This is not saved, as it is better to get the Azure default variable
this.azureSpringCloudServiceName = ''; // This is not saved, as it is better to get the Azure default variable
this.azureSpringCloudAppName = this.config.get('azureSpringCloudAppName');
this.azureSpringCloudDeploymentType = this.config.get('azureSpringCloudDeploymentType');
}
get prompting() {
return {
checkBuildTool() {
if (this.abort) return;
const done = this.async();
if (this.buildTool !== MAVEN) {
this.log.error('Sorry, this sub-generator only works with Maven projects for the moment.');
this.abort = true;
}
done();
},
checkInstallation() {
if (this.abort) return;
const done = this.async();
exec('az --version', err => {
if (err) {
this.log.error(
`You don't have the Azure CLI installed.
Download it from:
${chalk.red('https://docs.microsoft.com/en-us/cli/azure/install-azure-cli/?WT.mc_id=generator-jhipster-judubois')}`
);
this.abort = true;
}
done();
});
},
checkExtensionInstallation() {
if (this.abort) return;
const done = this.async();
exec('az extension show --name spring-cloud', err => {
if (err) {
this.log.error(
`You don't have the Azure Spring Cloud extension installed in your Azure CLI.
Install it by running:
${chalk.red('az extension add --name spring-cloud')}`
);
this.abort = true;
}
done();
});
},
checkClusterAvailability() {
if (this.abort) return;
const done = this.async();
exec('az spring-cloud app list', err => {
if (err) {
this.log.error(`${chalk.red('Your Azure Spring Cloud cluster is not available!')}\n ${err}`);
this.abort = true;
}
done();
});
},
getAzureSpringCloudDefaults() {
if (this.abort) return;
const done = this.async();
exec('az configure --list-defaults true', (err, stdout) => {
if (err) {
this.config.set({
azureSpringCloudResourceGroupName: null,
});
this.abort = true;
this.log.error('Could not retrieve your Azure default configuration.');
} else {
const json = JSON.parse(stdout);
Object.keys(json).forEach(key => {
if (json[key].name === 'group') {
this.azureSpringCloudResourceGroupName = json[key].value;
}
if (json[key].name === 'spring-cloud') {
this.azureSpringCloudServiceName = json[key].value;
}
});
if (this.azureSpringCloudResourceGroupName === '') {
this.log.info(
`Your default Azure resource group is not set up. We recommend doing it using the command
'${chalk.yellow('az configure --defaults group=<resource group name>')}`
);
this.azureSpringCloudResourceGroupName = '';
}
if (this.azureSpringCloudServiceName === '') {
this.log.info(
`Your default Azure Spring Cloud service name is not set up. We recommend doing it using the command
'${chalk.yellow('az configure --defaults spring-cloud=<service instance name>')}`
);
this.azureSpringCloudServiceName = '';
}
}
done();
});
},
askForazureSpringCloudVariables() {
if (this.abort) return;
const done = this.async();
const prompts = [
{
type: 'input',
name: 'azureSpringCloudResourceGroupName',
message: 'Azure resource group name:',
default: this.azureSpringCloudResourceGroupName,
},
{
type: 'input',
name: 'azureSpringCloudServiceName',
message: 'Azure Spring Cloud service name (the name of your cluster):',
default: this.azureSpringCloudServiceName,
},
{
type: 'input',
name: 'azureSpringCloudAppName',
message: 'Azure Spring Cloud application name:',
default: this.azureSpringCloudAppName || this.baseName,
},
];
this.prompt(prompts).then(props => {
this.azureSpringCloudResourceGroupName = props.azureSpringCloudResourceGroupName;
this.azureSpringCloudServiceName = props.azureSpringCloudServiceName;
this.azureSpringCloudAppName = props.azureSpringCloudAppName;
done();
});
},
askForAzureDeployType() {
if (this.abort) return;
const done = this.async();
const prompts = [
{
type: 'list',
name: 'azureSpringCloudDeploymentType',
message: 'Which type of deployment do you want ?',
choices: [
{
value: 'local',
name: 'Build and deploy locally',
},
{
value: 'github-action',
name: 'Build and deploy using GitHub Actions',
},
],
default: 0,
},
];
this.prompt(prompts).then(props => {
this.azureSpringCloudDeploymentType = props.azureSpringCloudDeploymentType;
done();
});
},
};
}
get configuring() {
return {
saveConfig() {
if (this.abort) return;
this.config.set({
azureSpringCloudAppName: this.azureSpringCloudAppName,
azureSpringCloudDeploymentType: this.azureSpringCloudDeploymentType,
});
},
};
}
get default() {
return {
insight() {
statistics.sendSubGenEvent('generator', 'azure-spring-cloud');
},
azureSpringCloudAppCreate() {
if (this.abort) return;
const done = this.async();
exec(
`az spring-cloud app show --resource-group ${this.azureSpringCloudResourceGroupName} \
--service ${this.azureSpringCloudServiceName} --name ${this.azureSpringCloudAppName}`,
(err, stdout) => {
if (err) {
this.log(chalk.bold('Application does not exist yet, creating it...'));
exec(
`az spring-cloud app create --resource-group ${this.azureSpringCloudResourceGroupName} \
--service ${this.azureSpringCloudServiceName} --name ${this.azureSpringCloudAppName}`,
(err, stdout) => {
if (err) {
this.abort = true;
this.log.error(`Application creation failed! Here is the error: ${err}`);
} else {
this.log(`${chalk.green(chalk.bold('Success!'))} Your application has been created.`);
}
done();
}
);
} else {
this.log(chalk.bold('Application already exists, using it.'));
done();
}
}
);
},
derivedProperties() {
this.isPackageNameJhipsterTech = this.packageName !== 'tech.jhipster';
this.isAuthenticationTypeJwt = this.authenticationType === JWT;
this.buildToolMaven = this.buildTool === MAVEN;
this.buildToolGradle = this.buildTool === GRADLE;
},
copyAzureSpringCloudFiles() {
if (this.abort) return;
this.log(chalk.bold('\nCreating Azure Spring Cloud deployment files'));
this.template('application-azure.yml.ejs', `${constants.SERVER_MAIN_RES_DIR}/config/application-azure.yml`);
this.template('bootstrap-azure.yml.ejs', `${constants.SERVER_MAIN_RES_DIR}/config/bootstrap-azure.yml`);
if (this.azureSpringCloudDeploymentType === 'github-action') {
this.template('github/workflows/azure-spring-cloud.yml.ejs', '.github/workflows/azure-spring-cloud.yml');
}
},
addAzureSpringCloudMavenProfile() {
if (this.abort) return;
if (this.buildTool === MAVEN) {
this.render('pom-profile.xml.ejs', profile => {
this.addMavenProfile('azure', ` ${profile.toString().trim()}`);
});
}
},
};
}
get end() {
return {
gitHubAction() {
if (this.abort) return;
if (this.azureSpringCloudDeploymentType === 'local') return;
const done = this.async();
try {
this.log('Test if Git is configured on your project...');
fs.lstatSync('.git');
this.log(chalk.bold('\nUsing existing Git repository'));
} catch (e) {
// An exception is thrown if the folder doesn't exist
this.log.error(
`${chalk.red('Git is not set up on your project!')}
You need a GitHub project correctly configured in order to use GitHub Actions.`
);
this.abort = true;
return;
}
const gitAddCmd = 'git add .';
this.log(chalk.bold('\nAdding Azure Spring Cloud files to the Git repository'));
this.log(chalk.cyan(gitAddCmd));
exec(gitAddCmd, (err, stdout, stderr) => {
if (err) {
this.abort = true;
this.log.error(err);
} else {
const line = stderr.toString().trimRight();
if (line.trim().length !== 0) this.log(line);
this.log(chalk.bold('\nCommitting Azure Spring Cloud files'));
const gitCommitCmd = 'git commit -m "Add Azure Spring Cloud files with automated GitHub Action deployment" --allow-empty';
this.log(chalk.cyan(gitCommitCmd));
exec(gitCommitCmd, (err, stdout, stderr) => {
if (err) {
this.abort = true;
this.log.error(err);
} else {
const line = stderr.toString().trimRight();
if (line.trim().length !== 0) this.log(line);
this.log(chalk.bold('\nPushing Azure Spring Cloud files'));
const gitPushCmd = 'git push';
this.log(chalk.cyan(gitPushCmd));
exec(gitPushCmd, (err, stdout, stderr) => {
if (err) {
this.abort = true;
this.log.error(err);
} else {
const line = stderr.toString().trimRight();
if (line.trim().length !== 0) this.log(line);
this.log(chalk.bold(chalk.green('Congratulations, automated deployment with GitHub Action is set up!')));
this.log(
`For the deployment to succeed, you will need to configure a ${chalk.bold('AZURE_CREDENTIALS')} secret in GitHub.
Read the documentation at https://github.com/microsoft/azure-spring-cloud-training/blob/master/11-configure-ci-cd/README.md
for more detailed information.`
);
done();
}
});
}
});
}
});
},
productionBuild() {
if (this.abort) return;
if (this.azureSpringCloudDeploymentType === 'github-action') return;
if (this.azureSpringCloudSkipBuild) return;
const done = this.async();
this.log(chalk.bold('\nBuilding application'));
const child = this.buildApplication(this.buildTool, 'prod,azure', false, err => {
if (err) {
this.abort = true;
this.log.error(err);
}
done();
});
this.buildCmd = child.buildCmd;
child.stdout.on('data', data => {
process.stdout.write(data.toString());
});
},
productionDeploy() {
if (this.abort) return;
if (this.azureSpringCloudDeploymentType === 'github-action') return;
if (this.azureSpringCloudSkipDeploy) return;
const done = this.async();
this.log(chalk.bold('\nDeploying application...'));
let buildDir = 'target';
if (this.buildTool === 'gradle') {
buildDir = 'build/libs';
}
exec(
`az spring-cloud app deploy --resource-group ${this.azureSpringCloudResourceGroupName} \
--service ${this.azureSpringCloudServiceName} --name ${this.azureSpringCloudAppName} \
--jar-path ${buildDir}/*.jar`,
(err, stdout) => {
if (err) {
this.abort = true;
this.log.error(`Deployment failed!\n ${err}`);
} else {
const json = JSON.parse(stdout);
this.log(`${chalk.green(chalk.bold('Success!'))} Your application has been deployed.`);
this.log(`Provisioning state: ${chalk.bold(json.properties.provisioningState)}`);
this.log(`Application status : ${chalk.bold(json.properties.status)}`);
}
done();
}
);
},
};
}
};