generator-pyhipster
Version:
Python (Flask) + Angular/React/Vue in one handy generator
602 lines (517 loc) • 18.3 kB
JavaScript
/**
* Copyright 2013-2022 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.
*/
/* eslint-disable consistent-return */
const chalk = require('chalk');
const _ = require('lodash');
const BaseBlueprintGenerator = require('../generator-base-blueprint');
const {
INITIALIZING_PRIORITY,
PROMPTING_PRIORITY,
CONFIGURING_PRIORITY,
COMPOSING_PRIORITY,
DEFAULT_PRIORITY,
WRITING_PRIORITY,
INSTALL_PRIORITY,
END_PRIORITY,
} = require('../../lib/constants/priorities.cjs').compat;
const cleanup = require('../cleanup');
const prompts = require('./prompts');
const packagejs = require('../../package.json');
const statistics = require('../statistics');
const { appDefaultConfig } = require('../generator-defaults');
const { GENERATOR_APP } = require('../generator-list');
const { GENERATOR_JHIPSTER } = require('../generator-constants');
const { MICROSERVICE } = require('../../jdl/jhipster/application-types');
const { OptionNames } = require('../../jdl/jhipster/application-options');
const { NO: CLIENT_FRAMEWORK_NO } = require('../../jdl/jhipster/client-framework-types');
const { JHI_PREFIX, BASE_NAME, JWT_SECRET_KEY, PACKAGE_NAME, PACKAGE_FOLDER, REMEMBER_ME_KEY } = OptionNames;
const {
GENERATOR_COMMON,
GENERATOR_ENTITIES,
GENERATOR_LANGUAGES,
GENERATOR_CLIENT,
GENERATOR_PAGE,
GENERATOR_SERVER,
GENERATOR_SERVER_FLASK,
} = require('../generator-list');
module.exports = class JHipsterAppGenerator extends BaseBlueprintGenerator {
constructor(args, options, features) {
super(args, options, { unique: 'namespace', ...features });
this.option('defaults', {
desc: 'Execute jhipster with default config',
type: Boolean,
defaults: false,
});
this.option('base-name', {
desc: 'Application base name',
type: String,
});
this.option('application-type', {
desc: 'Application type to generate',
type: String,
});
this.option('client-framework', {
desc: 'Provide client framework for the application',
type: String,
});
// This adds support for a `--skip-client` flag
this.option('skip-client', {
desc: 'Skip the client-side application generation',
type: Boolean,
});
// This adds support for a `--skip-server` flag
this.option('skip-server', {
desc: 'Skip the server-side application generation',
type: Boolean,
});
// This adds support for a `--skip-git` flag
this.option('skip-git', {
desc: 'Skip the git initialization',
type: Boolean,
defaults: false,
});
// This adds support for a `--skip-commit-hook` flag
this.option('skip-commit-hook', {
desc: 'Skip adding husky commit hooks',
type: Boolean,
});
// This adds support for a `--skip-user-management` flag
this.option('skip-user-management', {
desc: 'Skip the user management module during app generation',
type: Boolean,
});
// This adds support for a `--skip-check-length-of-identifier` flag
this.option('skip-check-length-of-identifier', {
desc: 'Skip check the length of the identifier, only for recent Oracle databases that support 30+ characters metadata',
type: Boolean,
});
// This adds support for a `--skip-fake-data` flag
this.option('skip-fake-data', {
desc: 'Skip generation of fake data for development',
type: Boolean,
});
// This adds support for a `--with-entities` flag
this.option('with-entities', {
alias: 'e',
desc: 'Regenerate the existing entities if any',
type: Boolean,
});
// This adds support for a `--skip-checks` flag
this.option('skip-checks', {
desc: 'Check the status of the required tools',
type: Boolean,
});
// This adds support for a `--jhi-prefix` flag
this.option('jhi-prefix', {
desc: 'Add prefix before services, controllers and states name',
type: String,
});
// This adds support for a `--entity-suffix` flag
this.option('entity-suffix', {
desc: 'Add suffix after entities name',
type: String,
});
// This adds support for a `--dto-suffix` flag
this.option('dto-suffix', {
desc: 'Add suffix after dtos name',
type: String,
});
// This adds support for a `--auth` flag
this.option('auth', {
desc: 'Provide authentication type for the application when skipping server side generation',
type: String,
});
// This adds support for a `--db` flag
this.option('db', {
desc: 'Provide DB name for the application when skipping server side generation',
type: String,
});
// This adds support for a `--build` flag
this.option('build', {
desc: 'Provide build tool for the application when skipping server side generation',
type: String,
});
// This adds support for a `--websocket` flag
this.option('websocket', {
desc: 'Provide websocket option for the application when skipping server side generation',
type: String,
});
// This adds support for a `--search-engine` flag
this.option('search-engine', {
desc: 'Provide search engine for the application when skipping server side generation',
type: String,
});
// NOTE: Deprecated!!! Use --blueprints instead
this.option('blueprint', {
desc: 'DEPRECATED: Specify a generator blueprint to use for the sub generators',
type: String,
});
// This adds support for a `--blueprints` flag which can be used to specify one or more blueprints to use for generation
this.option('blueprints', {
desc: 'A comma separated list of one or more generator blueprints to use for the sub generators, e.g. --blueprints kotlin,vuejs',
type: String,
});
// This adds support for a `--experimental` flag which can be used to enable experimental features
this.option('experimental', {
desc: 'Enable experimental features. Please note that these features may be unstable and may undergo breaking changes at any time',
type: Boolean,
});
// This adds support for a `--creation-timestamp` flag which can be used create reproducible builds
this.option('creation-timestamp', {
desc: 'Project creation timestamp (used for reproducible builds)',
type: String,
});
this.option('incremental-changelog', {
desc: 'Creates incremental database changelogs',
type: Boolean,
});
this.option('recreate-initial-changelog', {
desc: 'Recreate the initial database changelog based on the current config',
type: Boolean,
});
this.option('skip-jhipster-dependencies', {
desc: "Don't write jhipster dependencies.",
type: Boolean,
});
this.option('legacy-db-names', {
desc: 'Generate database names with jhipster 6 compatibility.',
type: Boolean,
});
this.option('ignore-errors', {
desc: "Don't fail on prettier errors.",
type: Boolean,
});
this.option('native-language', {
alias: 'n',
desc: 'Set application native language',
type: String,
required: false,
});
this.option('language', {
alias: 'l',
desc: 'Language to be added to application (existing languages are not removed)',
type: Array,
});
this.option('pk-type', {
desc: 'Default primary key type (beta)',
type: String,
});
this.option('reproducible', {
desc: 'Try to reproduce changelog',
type: Boolean,
});
this.option('client-package-manager', {
desc: 'Force an unsupported client package manager',
type: String,
});
this.option('cypress-coverage', {
desc: 'Enable Cypress code coverage report generation',
type: Boolean,
});
this.option('microfrontend', {
desc: 'Force generation of experimental microfrontend support',
type: Boolean,
});
this.option('test-frameworks', {
desc: 'Test frameworks to be generated',
type: Array,
});
this.option('reactive', {
desc: 'Generate a reactive backend',
type: Boolean,
});
this.option('enable-swagger-codegen', {
desc: 'API first development using OpenAPI-generator',
type: Boolean,
});
this.option('cache-provider', {
desc: 'Cache provider',
type: String,
});
this.option('enable-hibernate-cache', {
desc: 'Enable hibernate cache',
type: Boolean,
});
// Just constructing help, stop here
if (this.options.help) {
return;
}
this.loadStoredAppOptions();
this.loadRuntimeOptions();
// Use jhipster defaults
if (this.options.defaults || this.options.withEntities) {
if (!this.jhipsterConfig.baseName) {
this.jhipsterConfig.baseName = this.getDefaultAppName();
}
this.setConfigDefaults(this.getDefaultConfigForApplicationType());
}
this.existingProject = this.jhipsterConfig.baseName !== undefined && this.jhipsterConfig.applicationType !== undefined;
// preserve old jhipsterVersion value for cleanup which occurs after new config is written into disk
this.jhipsterOldVersion = this.jhipsterConfig.jhipsterVersion;
}
async _postConstruct() {
if (!this.fromBlueprint) {
await this.composeWithBlueprints(GENERATOR_APP);
}
}
_initializing() {
return {
validateFromCli() {
this.checkInvocationFromCLI();
},
displayLogo() {
this.printJHipsterLogo();
},
validateBlueprint() {
if (this.jhipsterConfig.blueprints && !this.skipChecks) {
this.jhipsterConfig.blueprints.forEach(blueprint => {
this._checkJHipsterBlueprintVersion(blueprint.name);
this._checkBlueprint(blueprint.name);
});
}
},
validateJava() {
this.checkJava();
},
validatePython() {
this.checkPython();
},
validateNode() {
this.checkNode();
},
validateGit() {
this.checkGit();
},
checkForNewJHVersion() {
if (!this.skipChecks) {
this.checkForNewVersion();
}
},
validate() {
if (this.skipServer && this.skipClient) {
this.error(`You can not pass both ${chalk.yellow('--skip-client')} and ${chalk.yellow('--skip-server')} together`);
}
},
};
}
get [INITIALIZING_PRIORITY]() {
if (this.delegateToBlueprint) {
return;
}
return this._initializing();
}
_prompting() {
return {
askForInsightOptIn: prompts.askForInsightOptIn,
askForApplicationType: prompts.askForApplicationType,
askForModuleName: prompts.askForModuleName,
};
}
get [PROMPTING_PRIORITY]() {
if (this.delegateToBlueprint) return;
return this._prompting();
}
_configuring() {
return {
setup() {
// Update jhipsterVersion.
this.jhipsterConfig.jhipsterVersion = packagejs.version;
this.configOptions.logo = false;
if (this.jhipsterConfig.applicationType === MICROSERVICE) {
this.jhipsterConfig.skipClient =
this.jhipsterConfig.skipClient ||
!this.jhipsterConfig.clientFramework ||
this.jhipsterConfig.clientFramework === CLIENT_FRAMEWORK_NO;
this.jhipsterConfig.withAdminUi = false;
this.jhipsterConfig.skipUserManagement = true;
}
// Set app defaults
this.setConfigDefaults(appDefaultConfig);
},
fixConfig() {
this.jhipsterConfig.jhiPrefix = _.camelCase(this.jhipsterConfig.jhiPrefix);
},
};
}
get [CONFIGURING_PRIORITY]() {
if (this.delegateToBlueprint) return;
return this._configuring();
}
_composing() {
return {
/**
* Composing with others generators, must be executed after `configuring` priority to let others
* generators `configuring` priority to run.
*
* Generators `server`, `client`, `common`, `languages` depends on each other.
* We are composing in the same task so every priority are executed in parallel.
* - compose (app) -> initializing (common) -> initializing (server) -> ...
*
* When composing in different tasks the result would be:
* - composeCommon (app) -> initializing (common) -> prompting (common) -> ... -> composeServer (app) -> initializing (server) -> ...
*/
async compose() {
await this.composeWithJHipster(GENERATOR_COMMON, true);
if (!this.jhipsterConfig.skipServer) {
await this.composeWithJHipster(GENERATOR_SERVER_FLASK, true);
}
if (!this.jhipsterConfig.skipClient) {
await this.composeWithJHipster(GENERATOR_CLIENT, true);
}
if (!this.configOptions.skipI18n) {
await this.composeWithJHipster(
GENERATOR_LANGUAGES,
{
regenerate: true,
skipPrompts: this.options.withEntities || this.existingProject || this.options.defaults,
},
true
);
}
},
askForTestOpts: prompts.askForTestOpts,
askForMoreModules: prompts.askForMoreModules,
/**
* At this point every other generator should already be configured, so, enforce defaults fallback.
*/
saveConfigWithDefaults() {
this.setConfigDefaults();
this._validateAppConfiguration();
},
saveBlueprintConfig() {
const config = {};
this.blueprints && (config.blueprints = this.blueprints);
this.blueprintVersion && (config.blueprintVersion = this.blueprintVersion);
this.config.set(config);
},
async composeEntities() {
if (!this.options.withEntities) return;
await this.composeWithJHipster(GENERATOR_ENTITIES, { skipInstall: true }, true);
},
async composePages() {
if (!this.jhipsterConfig.pages || this.jhipsterConfig.pages.length === 0 || this.configOptions.skipComposePage) return;
this.configOptions.skipComposePage = true;
await Promise.all(
this.jhipsterConfig.pages.map(page => {
return this.composeWithJHipster(page.generator || GENERATOR_PAGE, [page.name], {
skipInstall: true,
page,
});
})
);
},
};
}
get [COMPOSING_PRIORITY]() {
if (this.delegateToBlueprint) return;
return this._composing();
}
_default() {
return {
...super._missingPreDefault(),
insight() {
const yorc = {
..._.omit(this.jhipsterConfig, [JHI_PREFIX, BASE_NAME, JWT_SECRET_KEY, PACKAGE_NAME, PACKAGE_FOLDER, REMEMBER_ME_KEY]),
};
yorc.applicationType = this.jhipsterConfig.applicationType;
statistics.sendYoRc(yorc, this.existingProject, this.jhipsterConfig.jhipsterVersion);
},
};
}
get [DEFAULT_PRIORITY]() {
if (this.delegateToBlueprint) return;
return this._default();
}
_writing() {
return {
cleanup() {
cleanup.cleanupOldFiles(this);
cleanup.upgradeFiles(this);
},
...super._missingPostWriting(),
};
}
get [WRITING_PRIORITY]() {
if (this.delegateToBlueprint) return;
return this._writing();
}
// Public API method used by the getter and also by Blueprints
_install() {
return {
/** Initialize git repository before package manager install for commit hooks */
initGitRepo() {
if (!this.options.skipGit) {
this.initializeGitRepository();
}
},
installPythonModules() {
this.poetryInstall();
}
};
}
get [INSTALL_PRIORITY]() {
if (this.delegateToBlueprint) return;
return this._install();
}
_end() {
return {
/** Initial commit to git repository after package manager install for package-lock.json */
gitCommit() {
if (!this.options.skipGit && this.isGitInstalled()) {
let commitMsg = `Initial version of ${this.jhipsterConfig.baseName} generated by ${GENERATOR_JHIPSTER}@${this.jhipsterConfig.jhipsterVersion}`;
if (this.jhipsterConfig.blueprints && this.jhipsterConfig.blueprints.length > 0) {
const bpInfo = this.jhipsterConfig.blueprints.map(bp => `${bp.name}@${bp.version}`).join(', ');
commitMsg += ` with blueprints: ${bpInfo}`;
}
this.commitFilesToGit(commitMsg, this.async());
}
},
afterRunHook() {
try {
const modules = this.getModuleHooks();
if (modules.length > 0) {
this.log(`\n${chalk.bold.green('Running post run module hooks\n')}`);
// run through all post app creation module hooks
this.callHooks('app', 'post', {
appConfig: this.configOptions,
force: this.options.force,
});
}
} catch (err) {
this.log(`\n${chalk.bold.red('Running post run module hooks failed. No modification done to the generated app.')}`);
this.debug('Error:', err);
}
this.log(
chalk.green(
`\nIf you find PyHipster useful consider sponsoring the project ${chalk.yellow('https://github.com/pyhipster/generator-pyhipster')}`
)
);
},
};
}
get [END_PRIORITY]() {
if (this.delegateToBlueprint) return;
return this._end();
}
_validateAppConfiguration(config = this.jhipsterConfig) {
if (config.entitySuffix === config.dtoSuffix) {
this.error('Entities cannot be generated as the entity suffix and DTO suffix are equals !');
}
}
};