diff --git a/.blueprint/cli/commands.mjs b/.blueprint/cli/commands.mts similarity index 91% rename from .blueprint/cli/commands.mjs rename to .blueprint/cli/commands.mts index 11c9d371cf6b..25b3c9d02974 100644 --- a/.blueprint/cli/commands.mjs +++ b/.blueprint/cli/commands.mts @@ -34,6 +34,10 @@ const defaultCommands = { desc: 'Generate a test sample', blueprint: '@jhipster/jhipster-dev', }, + 'github-build-matrix': { + desc: 'Generate a matrix for GitHub Actions', + blueprint: '@jhipster/jhipster-dev', + }, 'update-vscode': { desc: 'Update generator-jhipster vscode files', blueprint: '@jhipster/jhipster-dev', diff --git a/.blueprint/code-workspace/command.mts b/.blueprint/code-workspace/command.mts index 996cb4ddc257..a7a861ef3135 100644 --- a/.blueprint/code-workspace/command.mts +++ b/.blueprint/code-workspace/command.mts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { type JHipsterCommandDefinition } from '../../generators/base/api.js'; +import { type JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { arguments: {}, diff --git a/.blueprint/code-workspace/generator.mjs b/.blueprint/code-workspace/generator.mts similarity index 100% rename from .blueprint/code-workspace/generator.mjs rename to .blueprint/code-workspace/generator.mts diff --git a/.blueprint/code-workspace/index.mjs b/.blueprint/code-workspace/index.mts similarity index 100% rename from .blueprint/code-workspace/index.mjs rename to .blueprint/code-workspace/index.mts diff --git a/.blueprint/constants.js b/.blueprint/constants.ts similarity index 100% rename from .blueprint/constants.js rename to .blueprint/constants.ts diff --git a/.blueprint/from-issue/command.mts b/.blueprint/from-issue/command.mts index 2d16ff12c404..05339b16bccc 100644 --- a/.blueprint/from-issue/command.mts +++ b/.blueprint/from-issue/command.mts @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../../generators/base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_APP, GENERATOR_WORKSPACES } from '../../generators/generator-list.js'; -import { parseIssue } from '../../testing/github.js'; +import { parseIssue } from '../../lib/testing/github.js'; const command: JHipsterCommandDefinition = { configs: { diff --git a/.blueprint/from-issue/generator.mts b/.blueprint/from-issue/generator.mts index e3e521d42161..a26bf834d205 100644 --- a/.blueprint/from-issue/generator.mts +++ b/.blueprint/from-issue/generator.mts @@ -1,7 +1,7 @@ import { join } from 'node:path'; import BaseGenerator from '../../generators/base/index.js'; -import { getGithubIssue, setGithubTaskOutput, prepareSample } from '../../testing/index.js'; +import { getGithubIssue, setGithubTaskOutput, prepareSample } from '../../lib/testing/index.js'; import { promptSamplesFolder } from '../support.mjs'; import { GENERATOR_APP, GENERATOR_JDL, GENERATOR_WORKSPACES } from '../../generators/generator-list.js'; import { extractDataFromInfo, type InfoData } from '../../generators/info/support/index.js'; diff --git a/.blueprint/from-issue/index.mjs b/.blueprint/from-issue/index.mts similarity index 100% rename from .blueprint/from-issue/index.mjs rename to .blueprint/from-issue/index.mts diff --git a/.blueprint/generate-generator/command.mts b/.blueprint/generate-generator/command.mts index c07b4b050150..a6336ef77428 100644 --- a/.blueprint/generate-generator/command.mts +++ b/.blueprint/generate-generator/command.mts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../../generators/base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { configs: { diff --git a/.blueprint/generate-generator/generator.mjs b/.blueprint/generate-generator/generator.mts similarity index 100% rename from .blueprint/generate-generator/generator.mjs rename to .blueprint/generate-generator/generator.mts index 60328e3f7289..ed0692a3139d 100644 --- a/.blueprint/generate-generator/generator.mjs +++ b/.blueprint/generate-generator/generator.mts @@ -1,5 +1,5 @@ -import BaseGenerator from '../../generators/base/index.js'; import { camelCase, upperFirst } from 'lodash-es'; +import BaseGenerator from '../../generators/base/index.js'; export default class extends BaseGenerator { generatorNamespace; diff --git a/.blueprint/generate-generator/index.mjs b/.blueprint/generate-generator/index.mts similarity index 100% rename from .blueprint/generate-generator/index.mjs rename to .blueprint/generate-generator/index.mts diff --git a/.blueprint/generate-generator/templates/command.ts.ejs b/.blueprint/generate-generator/templates/command.ts.ejs index 2dbdefa750df..2a06cf6e0c5e 100644 --- a/.blueprint/generate-generator/templates/command.ts.ejs +++ b/.blueprint/generate-generator/templates/command.ts.ejs @@ -16,11 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '<%- generatorRelativePath %>base/api.js'; +import type { JHipsterCommandDefinition } from '<%- generatorRelativePath %>../lib/command/types.js'; -const command: JHipsterCommandDefinition = { +const command = { configs: {}, import: [], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/.blueprint/generate-generator/templates/generator.spec.ts.ejs b/.blueprint/generate-generator/templates/generator.spec.ts.ejs index ea65ff227c52..8a6bd47eb943 100644 --- a/.blueprint/generate-generator/templates/generator.spec.ts.ejs +++ b/.blueprint/generate-generator/templates/generator.spec.ts.ejs @@ -21,7 +21,7 @@ import { fileURLToPath } from 'node:url'; import { before, it, describe, expect } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '<%- generatorRelativePath %>../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '<%- generatorRelativePath %>../testing/index.js'; +import { defaultHelpers as helpers, result } from '<%- generatorRelativePath %>../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); diff --git a/.blueprint/generate-sample/command.mts b/.blueprint/generate-sample/command.mts index 1a333b74c161..b1cdba79b3ad 100644 --- a/.blueprint/generate-sample/command.mts +++ b/.blueprint/generate-sample/command.mts @@ -19,7 +19,7 @@ import { join } from 'node:path'; import process from 'node:process'; import { defaultSamplesFolder } from '../constants.js'; -import { JHipsterCommandDefinition } from '../../generators/base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_APP, GENERATOR_WORKSPACES } from '../../generators/generator-list.js'; const command: JHipsterCommandDefinition = { diff --git a/.blueprint/generate-sample/generator.mjs b/.blueprint/generate-sample/generator.mts similarity index 91% rename from .blueprint/generate-sample/generator.mjs rename to .blueprint/generate-sample/generator.mts index 229032d5a42e..3462b4980a3f 100644 --- a/.blueprint/generate-sample/generator.mjs +++ b/.blueprint/generate-sample/generator.mts @@ -2,9 +2,10 @@ import { basename, extname, resolve } from 'path'; import { transform } from '@yeoman/transform'; import BaseGenerator from '../../generators/base/index.js'; import { packageJson } from '../../lib/index.js'; -import { generateSample, entitiesByType } from './support/index.js'; import { promptSamplesFolder } from '../support.mjs'; import { GENERATOR_APP, GENERATOR_INFO, GENERATOR_JDL } from '../../generators/generator-list.js'; +import { entitiesByType, generateSample } from './support/index.js'; +import assert from 'assert'; export default class extends BaseGenerator { sampleName; @@ -64,12 +65,14 @@ export default class extends BaseGenerator { const sample = await generateSample(this.sampleName, { destProjectFolder: this.projectFolder, fork: false, + entity: this.entitiesSample, }); + assert.ok(sample, `Sample ${this.sampleName} not found`); // Cleanup mem-fs files. Reload them from disk. await this.pipeline( { refresh: true, pendingFiles: false }, - transform(() => {}), + transform(() => undefined), ); let generatorOptions = { @@ -101,20 +104,12 @@ export default class extends BaseGenerator { const entitiesFiles = entitiesByType[this.entitiesSample]; if (entitiesFiles) { this.jhipsterConfig.entities = entitiesFiles; - /* + this.log.info(`Copying entities ${this.entitiesSample} (${entitiesFiles})`); this.copyTemplate( entitiesFiles.map(entity => `.jhipster/${entity}.json`), this.projectFolder, { noGlob: true, fromBasePath: this.templatePath('../../../test-integration/samples/') }, ); - */ - entitiesFiles.forEach(entity => - this.copyTemplate( - `../../../test-integration/samples/.jhipster/${entity}.json`, - `${this.projectFolder}/.jhipster/${entity}.json`, - { noGlob: true }, - ), - ); } await this.composeWithJHipster(GENERATOR_APP, { generatorOptions: { destinationRoot: this.projectFolder } }); }, @@ -124,7 +119,7 @@ export default class extends BaseGenerator { generatorOptions: { samplePath: this.sampleName, }, - }); + } as any); } }, async info() { diff --git a/.blueprint/generate-sample/index.mjs b/.blueprint/generate-sample/index.mts similarity index 100% rename from .blueprint/generate-sample/index.mjs rename to .blueprint/generate-sample/index.mts diff --git a/.blueprint/generate-sample/support/copy-entity-samples.js b/.blueprint/generate-sample/support/copy-entity-samples.ts similarity index 100% rename from .blueprint/generate-sample/support/copy-entity-samples.js rename to .blueprint/generate-sample/support/copy-entity-samples.ts diff --git a/.blueprint/generate-sample/support/copy-jdl-entity-samples.js b/.blueprint/generate-sample/support/copy-jdl-entity-samples.ts similarity index 97% rename from .blueprint/generate-sample/support/copy-jdl-entity-samples.js rename to .blueprint/generate-sample/support/copy-jdl-entity-samples.ts index 900cb9c061a4..ebb64bd1801b 100644 --- a/.blueprint/generate-sample/support/copy-jdl-entity-samples.js +++ b/.blueprint/generate-sample/support/copy-jdl-entity-samples.ts @@ -5,7 +5,7 @@ import { jdlEntitiesSamplesFolder } from '../../constants.js'; const isDirectory = dir => { try { return statSync(dir).isDirectory(); - } catch (error) { + } catch { return false; } }; diff --git a/.blueprint/generate-sample/support/generate-sample.js b/.blueprint/generate-sample/support/generate-sample.ts similarity index 93% rename from .blueprint/generate-sample/support/generate-sample.js rename to .blueprint/generate-sample/support/generate-sample.ts index 3bf4f2b3db7a..1a096a624331 100644 --- a/.blueprint/generate-sample/support/generate-sample.js +++ b/.blueprint/generate-sample/support/generate-sample.ts @@ -1,13 +1,13 @@ import { cpSync, existsSync, mkdirSync } from 'fs'; -import { join, resolve } from 'path'; +import { join } from 'path'; import process from 'process'; import { globSync } from 'glob'; import { execa } from 'execa'; +import { dailyBuildsFolder, jdlEntitiesSamplesFolder, jdlSamplesFolder, jhipsterBin, samplesFolder } from '../../constants.js'; import getSamples, { DAILY_PREFIX, isDaily } from './get-workflow-samples.js'; import copyEntitySamples from './copy-entity-samples.js'; import copyJdlEntitySamples from './copy-jdl-entity-samples.js'; -import { dailyBuildsFolder, jdlEntitiesSamplesFolder, jdlSamplesFolder, jhipsterBin, samplesFolder } from '../../constants.js'; const commonCliOptions = ['--skip-jhipster-dependencies', '--skip-checks', '--skip-install', '--no-insight']; @@ -21,7 +21,15 @@ export const generateSample = async ( jdlEntity: passedJdlEntity, jdlSamples: passedJdlSamples, fork = true, - } = {}, + }: { + destProjectFolder: string; + environment?: string; + war?: boolean; + entity?: string; + jdlEntity?: string; + jdlSamples?: string; + fork?: boolean; + }, ) => { if (!sampleName) { throw new Error('Sample name is required'); @@ -34,6 +42,7 @@ export const generateSample = async ( process.chdir(destProjectFolder); if (!sample) { + // eslint-disable-next-line no-console console.log(`Sample ${sampleName} was not found`); } diff --git a/.blueprint/generate-sample/support/get-workflow-samples.js b/.blueprint/generate-sample/support/get-workflow-samples.ts similarity index 90% rename from .blueprint/generate-sample/support/get-workflow-samples.js rename to .blueprint/generate-sample/support/get-workflow-samples.ts index beb06cb79590..9249f1435f35 100644 --- a/.blueprint/generate-sample/support/get-workflow-samples.js +++ b/.blueprint/generate-sample/support/get-workflow-samples.ts @@ -7,7 +7,7 @@ export const DAILY_PREFIX = 'daily-'; export const isDaily = workflow => workflow.startsWith(DAILY_PREFIX); -export const getWorkflowSamples = (workflows = WORKFLOW_NAMES) => +export const getWorkflowSamples = (workflows: string[] = WORKFLOW_NAMES) => Object.fromEntries( workflows.map(workflow => [ workflow, @@ -27,7 +27,7 @@ export const getWorkflowSamples = (workflows = WORKFLOW_NAMES) => ]), ); -export default workflows => +export default (workflows?: string[]) => Object.fromEntries( Object.values(getWorkflowSamples(workflows)) .map(workflowSamples => Object.entries(workflowSamples)) diff --git a/.blueprint/generate-sample/templates/samples/mf-simple.jdl b/.blueprint/generate-sample/templates/samples/mf-simple.jdl new file mode 100644 index 000000000000..dc0f5cb3b1a8 --- /dev/null +++ b/.blueprint/generate-sample/templates/samples/mf-simple.jdl @@ -0,0 +1,58 @@ +/* + * Microservice stack sample to test compilation and base microfrontend functionality. + * + * @example + * jhipster.cjs generate-sample mf-simple.jdl --client-framework vue + */ + +application { + config { + applicationType gateway + baseName gateway + clientFramework angular + creationTimestamp 1617901618886 + databaseType no + jwtSecretKey "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=" + packageName jhipster.tech.gateway + serviceDiscoveryType eureka + testFrameworks [cypress] + microfrontends [notification] + } +} + +application { + config { + applicationType microservice + baseName notification + creationTimestamp 1617901618887 + clientFramework angular + jwtSecretKey "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=" + packageName jhipster.tech.notification + prodDatabaseType postgresql + serverPort 8081 + serviceDiscoveryType eureka + testFrameworks [cypress] + } + entities Notification +} + +@ChangelogDate(20210408164814) +entity Notification { + title String required +} + +deployment { + deploymentType docker-compose, + appsFolders [gateway, notification] + dockerRepositoryName "hipsterslabs" + monitoring no + serviceDiscoveryType eureka +} + +deployment { + deploymentType kubernetes, + appsFolders [gateway, notification] + dockerRepositoryName "hipsterslabs" + monitoring no + serviceDiscoveryType eureka +} diff --git a/.blueprint/github-build-matrix/__snapshots__/generator.spec.ts.snap b/.blueprint/github-build-matrix/__snapshots__/generator.spec.ts.snap new file mode 100644 index 000000000000..bc85bfe41659 --- /dev/null +++ b/.blueprint/github-build-matrix/__snapshots__/generator.spec.ts.snap @@ -0,0 +1,962 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generator - github-build-matrix with angular should match matrix value 1`] = ` +"{ + "include": [ + { + "job-name": "ng-default (n[0]/j[3])", + "sample": "ng-default", + "os": "ubuntu-latest", + "node-version": "[0]", + "java-version": "[3]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "ng-default", + "app-sample": "ng-default", + "entity": "sqlfull", + "sonar-analyse": "true", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-default-additional (n[0]/j[0])", + "sample": "ng-default-additional", + "os": "ubuntu-latest", + "node-version": "[0]", + "java-version": "[0]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "ng-default-additional", + "entity": "none", + "app-sample": "ng-default", + "jdl-entity": "*", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-mysql-es-noi18n-mapsid (n[2]/j[0])", + "sample": "ng-mysql-es-noi18n-mapsid", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[0]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "ng-mysql-es-noi18n-mapsid", + "app-sample": "ng-mysql-es-noi18n-mapsid", + "entity": "sql", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-mongodb-kafka-cucumber (n[2]/j[2])", + "sample": "ng-mongodb-kafka-cucumber", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[2]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "ng-mongodb-kafka-cucumber", + "app-sample": "ng-mongodb-kafka-cucumber", + "entity": "mongodb", + "generatorOptions": { + "defaultEnvironment": "dev" + }, + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-h2mem-ws-nol2 (n[0]/j[2])", + "sample": "ng-h2mem-ws-nol2", + "os": "ubuntu-latest", + "node-version": "[0]", + "java-version": "[2]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "ng-h2mem-ws-nol2", + "app-sample": "ng-h2mem-ws-nol2", + "entity": "sql", + "generatorOptions": { + "defaultEnvironment": "dev" + }, + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-gradle-fr (n[2]/j[3])", + "sample": "ng-gradle-fr", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[3]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "ng-gradle-fr", + "app-sample": "ng-gradle-fr", + "entity": "sql", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-gradle-mariadb-oauth2-infinispan (n[2]/j[3])", + "sample": "ng-gradle-mariadb-oauth2-infinispan", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[3]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "ng-gradle-mariadb-oauth2-infinispan", + "app-sample": "ng-gradle-mariadb-oauth2-infinispan", + "entity": "sql", + "generatorOptions": { + "defaultEnvironment": "dev" + }, + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-gradle-h2disk-ws-nocache (n[2]/j[3])", + "sample": "ng-gradle-h2disk-ws-nocache", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[3]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "ng-gradle-h2disk-ws-nocache", + "app-sample": "ng-gradle-h2disk-ws-nocache", + "entity": "sql", + "generatorOptions": { + "defaultEnvironment": "dev", + "defaultPackaging": "war" + }, + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-webflux-mongodb (n[2]/j[2])", + "sample": "ng-webflux-mongodb", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[2]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "ng-webflux-mongodb", + "app-sample": "webflux-mongodb", + "entity": "mongodb", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-webflux-gradle-mongodb-oauth2 (n[2]/j[2])", + "sample": "ng-webflux-gradle-mongodb-oauth2", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[2]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "ng-webflux-gradle-mongodb-oauth2", + "app-sample": "webflux-mongodb-oauth2", + "entity": "mongodb", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-webflux-psql-default (n[2]/j[3])", + "sample": "ng-webflux-psql-default", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[3]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "ng-webflux-psql-default", + "app-sample": "webflux-psql", + "entity": "sql", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-webflux-psql-additional (n[2]/j[3])", + "sample": "ng-webflux-psql-additional", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[3]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "ng-webflux-psql-additional", + "jdl-samples": "webflux-psql,custom-domain", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ng-webflux-gradle-session-h2mem-es (n[1]/j[1])", + "sample": "ng-webflux-gradle-session-h2mem-es", + "os": "ubuntu-latest", + "node-version": "[1]", + "java-version": "[1]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "ng-webflux-gradle-session-h2mem-es", + "app-sample": "webflux-gradle-session-h2mem-es", + "generatorOptions": { + "defaultEnvironment": "dev" + }, + "entity": "sqllight", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ms-ng-oauth2-mongodb-caffeine (n[1]/j[1])", + "sample": "ms-ng-oauth2-mongodb-caffeine", + "os": "ubuntu-latest", + "node-version": "[1]", + "java-version": "[1]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "ms-ng-oauth2-mongodb-caffeine", + "jdl-samples": "ms-ng-oauth2-mongodb-caffeine", + "generatorOptions": { + "workspaces": true, + "experimental": true, + "monorepository": true + }, + "workspaces": "true", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "mf-ng-eureka-jwt-psql-ehcache (n[0]/j[0])", + "sample": "mf-ng-eureka-jwt-psql-ehcache", + "os": "ubuntu-latest", + "node-version": "[0]", + "java-version": "[0]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "mf-ng-eureka-jwt-psql-ehcache", + "jdl-samples": "mf-ng-eureka-jwt-psql-ehcache", + "generatorOptions": { + "workspaces": true, + "monorepository": true + }, + "workspaces": "true", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ms-mf-ng-consul-oauth2-neo4j (n[0]/j[0])", + "sample": "ms-mf-ng-consul-oauth2-neo4j", + "os": "ubuntu-latest", + "node-version": "[0]", + "java-version": "[0]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "ms-mf-ng-consul-oauth2-neo4j", + "jdl-samples": "ms-mf-ng-consul-oauth2-neo4j", + "generatorOptions": { + "workspaces": true, + "monorepository": true + }, + "workspaces": "true", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + } + ] +}" +`; + +exports[`generator - github-build-matrix with devserver should match matrix value 1`] = ` +"{ + "include": [ + { + "job-name": "ng-default", + "sample": "samples/ng-default", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "args": "--sample-yorc-folder --entities-sample sqllight" + }, + { + "job-name": "react-default", + "sample": "samples/react-default", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "args": "--sample-yorc-folder --entities-sample sqllight" + }, + { + "job-name": "vue-default", + "sample": "samples/vue-default", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "args": "--sample-yorc-folder --entities-sample sqllight" + } + ] +}" +`; + +exports[`generator - github-build-matrix with docker-compose-integration should match matrix value 1`] = ` +"{ + "include": [ + { + "job-name": "cassandra-maven-jwt", + "sample": "cassandra-maven-jwt", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n databaseType cassandra\\n buildTool maven\\n authenticationType jwt\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "cassandra-reactive(true)-gradle-elasticsearch-oauth2-consul-kafka", + "sample": "cassandra-reactive(true)-gradle-elasticsearch-oauth2-consul-kafka", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n databaseType cassandra\\n reactive true\\n buildTool gradle\\n searchEngine elasticsearch\\n authenticationType oauth2\\n serviceDiscoveryType consul\\n messageBroker kafka\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "mongodb-maven-jwt-kafka", + "sample": "mongodb-maven-jwt-kafka", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n databaseType mongodb\\n buildTool maven\\n authenticationType jwt\\n messageBroker kafka\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "mongodb-reactive(true)-gradle-elasticsearch-oauth2-consul", + "sample": "mongodb-reactive(true)-gradle-elasticsearch-oauth2-consul", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n databaseType mongodb\\n reactive true\\n buildTool gradle\\n searchEngine elasticsearch\\n authenticationType oauth2\\n serviceDiscoveryType consul\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "neo4j-maven-jwt-eureka", + "sample": "neo4j-maven-jwt-eureka", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n databaseType neo4j\\n buildTool maven\\n authenticationType jwt\\n serviceDiscoveryType eureka\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "neo4j-reactive(true)-gradle-elasticsearch-oauth2-eureka-kafka", + "sample": "neo4j-reactive(true)-gradle-elasticsearch-oauth2-eureka-kafka", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n databaseType neo4j\\n reactive true\\n buildTool gradle\\n searchEngine elasticsearch\\n authenticationType oauth2\\n serviceDiscoveryType eureka\\n messageBroker kafka\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "postgresql-cacheProvider(no)-maven-jwt-eureka-kafka", + "sample": "postgresql-cacheProvider(no)-maven-jwt-eureka-kafka", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n prodDatabaseType postgresql\\n cacheProvider no\\n buildTool maven\\n authenticationType jwt\\n serviceDiscoveryType eureka\\n messageBroker kafka\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "mysql-memcached-gradle-elasticsearch-oauth2-eureka", + "sample": "mysql-memcached-gradle-elasticsearch-oauth2-eureka", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n prodDatabaseType mysql\\n cacheProvider memcached\\n buildTool gradle\\n searchEngine elasticsearch\\n authenticationType oauth2\\n serviceDiscoveryType eureka\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "mariadb-redis-maven-jwt-consul", + "sample": "mariadb-redis-maven-jwt-consul", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n prodDatabaseType mariadb\\n cacheProvider redis\\n buildTool maven\\n authenticationType jwt\\n serviceDiscoveryType consul\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "postgresql-reactive(true)-gradle-elasticsearch-oauth2-kafka", + "sample": "postgresql-reactive(true)-gradle-elasticsearch-oauth2-kafka", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n prodDatabaseType postgresql\\n reactive true\\n buildTool gradle\\n searchEngine elasticsearch\\n authenticationType oauth2\\n messageBroker kafka\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "mysql-reactive(true)-maven-jwt-consul-kafka", + "sample": "mysql-reactive(true)-maven-jwt-consul-kafka", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n prodDatabaseType mysql\\n reactive true\\n buildTool maven\\n authenticationType jwt\\n serviceDiscoveryType consul\\n messageBroker kafka\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "mariadb-reactive(true)-gradle-elasticsearch-oauth2", + "sample": "mariadb-reactive(true)-gradle-elasticsearch-oauth2", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n prodDatabaseType mariadb\\n reactive true\\n buildTool gradle\\n searchEngine elasticsearch\\n authenticationType oauth2\\n }\\n}", + "samples-group": "docker-compose-integration" + }, + { + "job-name": "h2", + "sample": "h2", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "JAVA-VERSION", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "cmd-e2e": "npm run ci:e2e:dev", + "args": "jdl", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n devDatabaseType h2Disk\\n }\\n}", + "samples-group": "docker-compose-integration" + } + ] +}" +`; + +exports[`generator - github-build-matrix with graalvm should match matrix value 1`] = ` +"{ + "include": [ + { + "job-name": "maven", + "sample": "maven", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "21", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n buildTool maven\\n graalvmSupport true\\n }\\n}", + "samples-group": "graalvm" + }, + { + "job-name": "maven-reactive(true)", + "sample": "maven-reactive(true)", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "21", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n buildTool maven\\n reactive true\\n graalvmSupport true\\n }\\n}", + "samples-group": "graalvm" + }, + { + "job-name": "gradle", + "sample": "gradle", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "21", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n buildTool gradle\\n graalvmSupport true\\n }\\n}", + "samples-group": "graalvm" + }, + { + "job-name": "gradle-reactive(true)", + "sample": "gradle-reactive(true)", + "os": "ubuntu-latest", + "node-version": "NODE-VERSION", + "java-version": "21", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "jdl": "application {\\n config {\\n testFrameworks [cypress]\\n buildTool gradle\\n reactive true\\n graalvmSupport true\\n }\\n}", + "samples-group": "graalvm" + } + ] +}" +`; + +exports[`generator - github-build-matrix with react should match matrix value 1`] = ` +"{ + "include": [ + { + "job-name": "react-default (n[2]/j[2])", + "sample": "react-default", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[2]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "react-default", + "app-sample": "react-default", + "entity": "sqlfull", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "react-maven-h2mem-memcached (n[2]/j[0])", + "sample": "react-maven-h2mem-memcached", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[0]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "react-maven-h2mem-memcached", + "app-sample": "react-maven-h2mem-memcached", + "entity": "sql", + "generatorOptions": { + "defaultEnvironment": "dev" + }, + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "react-gradle-mysql-es-noi18n-mapsid (n[0]/j[3])", + "sample": "react-gradle-mysql-es-noi18n-mapsid", + "os": "ubuntu-latest", + "node-version": "[0]", + "java-version": "[3]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "react-gradle-mysql-es-noi18n-mapsid", + "app-sample": "react-gradle-mysql-es-noi18n-mapsid", + "entity": "sql", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "react-gradle-cassandra-session-redis (n[2]/j[0])", + "sample": "react-gradle-cassandra-session-redis", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[0]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "react-gradle-cassandra-session-redis", + "app-sample": "react-gradle-cassandra-session-redis", + "entity": "cassandra", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ms-react-consul-jwt-cassandra-redis (n[2]/j[1])", + "sample": "ms-react-consul-jwt-cassandra-redis", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[1]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "ms-react-consul-jwt-cassandra-redis", + "jdl-samples": "ms-react-consul-jwt-cassandra-redis", + "generatorOptions": { + "workspaces": true, + "monorepository": true + }, + "workspaces": "true", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ms-mf-react-eureka-oauth2-mariadb-infinispan (n[1]/j[0])", + "sample": "ms-mf-react-eureka-oauth2-mariadb-infinispan", + "os": "ubuntu-latest", + "node-version": "[1]", + "java-version": "[0]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "ms-mf-react-eureka-oauth2-mariadb-infinispan", + "jdl-samples": "ms-mf-react-eureka-oauth2-mariadb-infinispan", + "generatorOptions": { + "workspaces": true, + "monorepository": true + }, + "workspaces": "true", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + } + ] +}" +`; + +exports[`generator - github-build-matrix with vue should match matrix value 1`] = ` +"{ + "include": [ + { + "job-name": "vue-default (n[0]/j[2])", + "sample": "vue-default", + "os": "ubuntu-latest", + "node-version": "[0]", + "java-version": "[2]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "vue-default", + "app-sample": "vue-default", + "entity": "sqlfull", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "vue-default-additional (n[2]/j[2])", + "sample": "vue-default-additional", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[2]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "vue-default-additional", + "app-sample": "vue-default", + "entity": "none", + "jdl-entity": "custom-id", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "vue-noi18n-mysql-ws-oauth2 (n[2]/j[2])", + "sample": "vue-noi18n-mysql-ws-oauth2", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[2]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "vue-noi18n-mysql-ws-oauth2", + "app-sample": "vue-noi18n-ws-oauth2", + "entity": "sqlfull", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "vue-fulli18n-mysql-es (n[2]/j[3])", + "sample": "vue-fulli18n-mysql-es", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[3]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "vue-fulli18n-mysql-es", + "app-sample": "vue-fulli18n-es", + "entity": "sql", + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "vue-gradle-h2mem-ws-session (n[0]/j[0])", + "sample": "vue-gradle-h2mem-ws-session", + "os": "ubuntu-latest", + "node-version": "[0]", + "java-version": "[0]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "vue-gradle-h2mem-ws-session", + "app-sample": "vue-gradle-ws-session", + "entity": "sql", + "generatorOptions": { + "defaultEnvironment": "dev" + }, + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "vue-h2disk-ws-theme (n[2]/j[1])", + "sample": "vue-h2disk-ws-theme", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[1]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "vue-h2disk-ws-theme", + "app-sample": "vue-ws-theme", + "entity": "sql", + "generatorOptions": { + "defaultEnvironment": "dev" + }, + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "vue-session-cassandra-fr (n[0]/j[1])", + "sample": "vue-session-cassandra-fr", + "os": "ubuntu-latest", + "node-version": "[0]", + "java-version": "[1]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "name": "vue-session-cassandra-fr", + "app-sample": "vue-session-cassandra-fr", + "entity": "cassandra", + "generatorOptions": { + "defaultEnvironment": "dev" + }, + "workspaces": "false", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "ms-mf-vue-consul-oauth2-mysql-memcached (n[2]/j[2])", + "sample": "ms-mf-vue-consul-oauth2-mysql-memcached", + "os": "ubuntu-latest", + "node-version": "[2]", + "java-version": "[2]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "false", + "gradle-cache": true, + "name": "ms-mf-vue-consul-oauth2-mysql-memcached", + "jdl-samples": "ms-mf-vue-consul-oauth2-mysql-memcached", + "generatorOptions": { + "workspaces": true, + "monorepository": true + }, + "workspaces": "true", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + }, + { + "job-name": "stack-vue-no-db (n[1]/j[3])", + "sample": "stack-vue-no-db", + "os": "ubuntu-latest", + "node-version": "[1]", + "java-version": "[3]", + "npm-version": "NPM-VERSION", + "default-environment": "prod", + "jwt-secret-key": "ZjY4MTM4YjI5YzMwZjhjYjI2OTNkNTRjMWQ5Y2Q0Y2YwOWNmZTE2NzRmYzU3NTMwM2NjOTE3MTllOTM3MWRkMzcyYTljMjVmNmQ0Y2MxOTUzODc0MDhhMTlkMDIxMzI2YzQzZDM2ZDE3MmQ3NjVkODk3OTVmYzljYTQyZDNmMTQ=", + "skip-backend-tests": "false", + "skip-frontend-tests": "backend tests only", + "gradle-cache": true, + "name": "stack-vue-no-db", + "jdl-samples": "stack-vue-no-db", + "generatorOptions": { + "workspaces": true, + "monorepository": true + }, + "workspaces": "true", + "build-jhipster-bom": true, + "jhipster-bom-branch": "main", + "jhipster-bom-cicd-version": "0.0.0-CICD" + } + ] +}" +`; diff --git a/.blueprint/github-build-matrix/command.ts b/.blueprint/github-build-matrix/command.ts new file mode 100644 index 000000000000..855a1de8ee2f --- /dev/null +++ b/.blueprint/github-build-matrix/command.ts @@ -0,0 +1,24 @@ +import type { JHipsterCommandDefinition } from '../../generators/index.js'; + +export const workflowChoices = ['angular', 'devserver', 'graalvm', 'react', 'docker-compose-integration', 'vue'] as const; +export const eventNameChoices = ['push', 'pull_request', 'daily'] as const; + +export default { + configs: { + workflow: { + description: 'Workflow', + argument: { + type: String, + }, + scope: 'generator', + choices: workflowChoices, + }, + eventName: { + cli: { + type: String, + }, + scope: 'generator', + choices: eventNameChoices, + }, + }, +} as const satisfies JHipsterCommandDefinition; diff --git a/.blueprint/github-build-matrix/generator.spec.ts b/.blueprint/github-build-matrix/generator.spec.ts new file mode 100644 index 000000000000..bf45674d310b --- /dev/null +++ b/.blueprint/github-build-matrix/generator.spec.ts @@ -0,0 +1,31 @@ +import { basename, dirname, join } from 'path'; +import { fileURLToPath } from 'url'; +import { before, describe, expect, it } from 'esmocha'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; +import { shouldSupportFeatures } from '../../test/support/index.js'; +import Generator from './generator.js'; +import { workflowChoices } from './command.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const generator = basename(__dirname); + +describe(`generator - ${generator}`, () => { + shouldSupportFeatures(Generator); + + for (const workflow of workflowChoices) { + describe(`with ${workflow}`, () => { + before(async () => { + await helpers.runJHipster(join(__dirname, 'index.ts'), { useEnvironmentBuilder: true }).withArguments(workflow); + }); + + it('should set workflow value', () => { + expect((runResult.generator as any).workflow).toBe(workflow); + }); + it('should match matrix value', () => { + expect((runResult.generator as any).matrix).toMatchSnapshot(); + }); + }); + } +}); diff --git a/.blueprint/github-build-matrix/generator.ts b/.blueprint/github-build-matrix/generator.ts new file mode 100644 index 000000000000..3275046d3cb8 --- /dev/null +++ b/.blueprint/github-build-matrix/generator.ts @@ -0,0 +1,124 @@ +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import BaseGenerator from '../../generators/base/index.js'; +import type { GitHubMatrix, GitHubMatrixGroup } from '../../lib/testing/index.js'; +import { convertToGitHubMatrix, getGithubOutputFile, getGithubSamplesGroup, setGithubTaskOutput } from '../../lib/testing/index.js'; +import { getPackageRoot } from '../../lib/index.js'; +import { BUILD_JHIPSTER_BOM, JHIPSTER_BOM_BRANCH, JHIPSTER_BOM_CICD_VERSION } from '../../test-integration/integration-test-constants.js'; +import { getGitChanges } from './support/git-changes.js'; +import { devServerMatrix } from './samples/dev-server.js'; +import type { eventNameChoices, workflowChoices } from './command.js'; + +type JHipsterGitHubMatrix = GitHubMatrix & { + name: string; + 'app-sample'?: string; + 'build-jhipster-bom'?: boolean; + 'gradle-cache'?: boolean; + 'jhipster-bom-cicd-version'?: string; + 'jhipster-bom-branch'?: string; + 'sonar-analyse'?: 'true' | 'false'; + workspaces?: 'true' | 'false'; + 'skip-frontend-tests'?: 'true' | 'false'; + 'skip-backend-tests'?: 'true' | 'false'; +}; + +type JHipsterGitHubInputMatrix = JHipsterGitHubMatrix & { + generatorOptions: Record; +}; + +export default class extends BaseGenerator { + workflow!: (typeof workflowChoices)[number]; + eventName?: (typeof eventNameChoices)[number]; + matrix!: string; + + constructor(args, opts, features) { + super(args, opts, { queueCommandTasks: true, ...features, jhipsterBootstrap: false }); + } + + get [BaseGenerator.WRITING]() { + return this.asWritingTaskGroup({ + async buildMatrix() { + // Push events requires a base commit for diff. Diff cannot be checked by @~1 if PR was merged with a rebase. + const useChanges = this.eventName === 'pull_request'; + const changes = await getGitChanges({ allTrue: !useChanges }); + const { base, common, devBlueprint, client, e2e, graalvm, java, workspaces } = changes; + const hasWorkflowChanges = changes[`${this.workflow}Workflow`]; + + let matrix: GitHubMatrixGroup = {}; + let randomEnvironment = false; + if (this.workflow === 'docker-compose-integration') { + const { samples, warnings } = await getGithubSamplesGroup(this.templatePath('../samples/'), this.workflow); + matrix = samples; + if (warnings.length) { + this.log.warn(warnings.join('\n')); + } + } else if (this.workflow === 'graalvm') { + if (hasWorkflowChanges || java || graalvm) { + const { samples, warnings } = await getGithubSamplesGroup(this.templatePath('../samples/'), this.workflow); + matrix = samples; + if (warnings.length) { + this.log.warn(warnings.join('\n')); + } + } + } else if (this.workflow === 'devserver') { + if (devBlueprint || hasWorkflowChanges || client) { + matrix = { ...devServerMatrix.angular, ...devServerMatrix.react, ...devServerMatrix.vue }; + } else { + for (const client of ['angular', 'react', 'vue']) { + if (changes[client]) { + Object.assign(matrix, devServerMatrix[client]); + } + } + } + } else if (['angular', 'react', 'vue'].includes(this.workflow)) { + const hasClientFrameworkChanges = changes[this.workflow]; + const enableAllTests = base || common || hasWorkflowChanges || devBlueprint; + const enableBackendTests = enableAllTests || java; + const enableFrontendTests = enableAllTests || client || hasClientFrameworkChanges; + const enableE2eTests = enableBackendTests || enableFrontendTests || e2e || workspaces; + const enableAnyTest = enableE2eTests; + + randomEnvironment = true; + if (enableAnyTest) { + const content = await readFile(join(getPackageRoot(), `test-integration/workflow-samples/${this.workflow}.json`)); + const parsed: { include: JHipsterGitHubInputMatrix[] } = JSON.parse(content.toString()); + matrix = Object.fromEntries( + parsed.include.map((sample): [string, JHipsterGitHubMatrix] => { + const { 'job-name': jobName = sample.name, 'sonar-analyse': sonarAnalyse, generatorOptions } = sample; + const enableSonar = sonarAnalyse === 'true'; + const workspaces = generatorOptions?.workspaces ? 'true' : 'false'; + if (enableSonar && workspaces === 'true') { + throw new Error('Sonar is not supported with workspaces'); + } + return [ + jobName, + { + // Force tests if sonar is enabled + 'skip-backend-tests': `${!(enableBackendTests || enableSonar)}`, + // Force tests if sonar is enabled + 'skip-frontend-tests': `${!(enableFrontendTests || enableSonar)}`, + 'gradle-cache': generatorOptions?.workspaces || jobName.includes('gradle') ? true : undefined, + ...sample, + sample: jobName, + workspaces, + 'build-jhipster-bom': BUILD_JHIPSTER_BOM, + 'jhipster-bom-branch': BUILD_JHIPSTER_BOM ? JHIPSTER_BOM_BRANCH : undefined, + 'jhipster-bom-cicd-version': BUILD_JHIPSTER_BOM ? JHIPSTER_BOM_CICD_VERSION : undefined, + }, + ]; + }), + ); + } + } + + const { useVersionPlaceholders } = this; + this.matrix = JSON.stringify(convertToGitHubMatrix(matrix, { randomEnvironment, useVersionPlaceholders }), null, 2); + const githubOutputFile = getGithubOutputFile(); + this.log.info('matrix', this.matrix); + if (githubOutputFile) { + setGithubTaskOutput('matrix', this.matrix); + } + }, + }); + } +} diff --git a/.blueprint/github-build-matrix/index.ts b/.blueprint/github-build-matrix/index.ts new file mode 100644 index 000000000000..3eccd6e8659c --- /dev/null +++ b/.blueprint/github-build-matrix/index.ts @@ -0,0 +1,2 @@ +export { default } from './generator.js'; +export { default as command } from './command.js'; diff --git a/.blueprint/github-build-matrix/samples/dev-server.ts b/.blueprint/github-build-matrix/samples/dev-server.ts new file mode 100644 index 000000000000..35f6200db196 --- /dev/null +++ b/.blueprint/github-build-matrix/samples/dev-server.ts @@ -0,0 +1,22 @@ +import type { GitHubMatrixGroup } from '../../../lib/testing/index.js'; + +export const devServerMatrix = { + angular: { + 'ng-default': { + sample: 'samples/ng-default', + args: '--sample-yorc-folder --entities-sample sqllight', + }, + }, + react: { + 'react-default': { + sample: 'samples/react-default', + args: '--sample-yorc-folder --entities-sample sqllight', + }, + }, + vue: { + 'vue-default': { + sample: 'samples/vue-default', + args: '--sample-yorc-folder --entities-sample sqllight', + }, + }, +} satisfies Record; diff --git a/.blueprint/github-build-matrix/samples/docker-compose-integration.ts b/.blueprint/github-build-matrix/samples/docker-compose-integration.ts new file mode 100644 index 000000000000..e21075203ecf --- /dev/null +++ b/.blueprint/github-build-matrix/samples/docker-compose-integration.ts @@ -0,0 +1,45 @@ +import type { GitHubMatrixGroup } from '../../../lib/testing/index.js'; +import { extendMatrix, fromMatrix } from '../../../lib/testing/index.js'; +import { convertOptionsToJDL } from '../support/jdl.js'; + +// Supported containers: https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection +export default Object.fromEntries( + [ + ...Object.entries( + extendMatrix( + { + ...fromMatrix({ + databaseType: ['cassandra', 'mongodb', 'neo4j'], + reactive: [undefined, true], + }), + ...extendMatrix( + fromMatrix({ + prodDatabaseType: ['postgresql', 'mysql', 'mariadb'], + reactive: [undefined], + }), + { cacheProvider: ['no', 'redis', 'memcached'] }, + ), + ...fromMatrix({ + prodDatabaseType: ['postgresql', 'mysql', 'mariadb'], + reactive: [true], + }), + }, + { + buildTool: ['maven', 'gradle'], + searchEngine: [undefined, 'elasticsearch'], + authenticationType: ['jwt', 'oauth2'], + serviceDiscoveryType: [undefined, 'eureka', 'consul'], + messageBroker: [undefined, 'kafka'], + }, + ), + ), + ['h2', { devDatabaseType: 'h2Disk' }], + ].map(([key, value]) => [ + key, + { + 'cmd-e2e': 'npm run ci:e2e:dev', + args: 'jdl', + jdl: convertOptionsToJDL(value), + }, + ]), +) satisfies GitHubMatrixGroup; diff --git a/.blueprint/github-build-matrix/samples/graalvm.ts b/.blueprint/github-build-matrix/samples/graalvm.ts new file mode 100644 index 000000000000..597a4c20f529 --- /dev/null +++ b/.blueprint/github-build-matrix/samples/graalvm.ts @@ -0,0 +1,23 @@ +import type { GitHubMatrixGroup } from '../../../lib/testing/index.js'; +import { extendMatrix, fromMatrix } from '../../../lib/testing/index.js'; +import { convertOptionsToJDL } from '../support/jdl.js'; + +export default Object.fromEntries( + [ + ...Object.entries( + extendMatrix( + fromMatrix({ + buildTool: ['maven', 'gradle'], + reactive: [undefined, true], + }), + {}, + ), + ), + ].map(([key, value]) => [ + key, + { + 'java-version': '21', + jdl: convertOptionsToJDL({ ...value, graalvmSupport: true }), + }, + ]), +) satisfies GitHubMatrixGroup; diff --git a/.blueprint/github-build-matrix/support/cli-args.ts b/.blueprint/github-build-matrix/support/cli-args.ts new file mode 100644 index 000000000000..9acb570da95b --- /dev/null +++ b/.blueprint/github-build-matrix/support/cli-args.ts @@ -0,0 +1,13 @@ +import { kebabCase } from 'lodash-es'; + +export const convertToCliArgs = (opts: Record): string => { + return Object.entries(opts) + .map(([key, value]) => { + key = kebabCase(key); + if (typeof value === 'boolean') { + return `--${value ? '' : 'no-'}${key}`; + } + return `--${key} ${value}`; + }) + .join(' '); +}; diff --git a/.blueprint/github-build-matrix/support/git-changes.ts b/.blueprint/github-build-matrix/support/git-changes.ts new file mode 100644 index 000000000000..768afe62c3b6 --- /dev/null +++ b/.blueprint/github-build-matrix/support/git-changes.ts @@ -0,0 +1,44 @@ +import { fileURLToPath } from 'url'; +import { minimatch } from 'minimatch'; +import { simpleGit } from 'simple-git'; + +export const getGitChanges = async (options: { allTrue?: boolean } = {}) => { + let hasPatternChanges; + if (options.allTrue) { + hasPatternChanges = () => true; + } else { + const git = simpleGit({ baseDir: fileURLToPath(new URL('../../', import.meta.url).href) }); + const summary = await git.diffSummary({ '@~1': null }); + const files = summary.files.map(({ file }) => file); + hasPatternChanges = (pattern: string, ignore?: string) => + files.some(file => minimatch(file, pattern, { dot: true }) && (!ignore || !minimatch(file, ignore, { dot: true }))); + } + + const hasClientWorkflowChanges = (client: 'angular' | 'react' | 'vue') => + hasPatternChanges(`.github/workflows/${client}.yml`) || hasPatternChanges(`test-integration/workflow-samples/${client}.json`); + return { + hasPatternChanges, + angular: hasPatternChanges('generators/angular/**'), + angularWorkflow: hasClientWorkflowChanges('angular'), + base: + hasPatternChanges('lib/**') || + hasPatternChanges('generators/*') || + hasPatternChanges('generators/{base*,bootstrap*,git,jdl,project-name}/**'), + ci: hasPatternChanges('.github/{actions,workflows}/**'), + devBlueprint: hasPatternChanges('.blueprint/**'), + devserverWorkflow: hasPatternChanges('.github/workflows/devserver.yml'), + common: hasPatternChanges('generators/{app,common,docker,languages}/**'), + client: hasPatternChanges('generators/{client,init,javascript}/**'), + e2e: hasPatternChanges('generators/cypress/**'), + java: hasPatternChanges( + 'generators/{cucumber,feign-client,gatling,gradle,java,liquibase,maven,server,spring*}/**', + 'generators/java/generators/graalvm/**', + ), + graalvm: hasPatternChanges('generators/java/generators/graalvm/**'), + react: hasPatternChanges('generators/react/**'), + reactWorkflow: hasClientWorkflowChanges('react'), + workspaces: hasPatternChanges('generators/{docker-compose,kubernetes*,workspaces}/**'), + vue: hasPatternChanges('generators/vue/**'), + vueWorkflow: hasClientWorkflowChanges('vue'), + }; +}; diff --git a/.blueprint/github-build-matrix/support/jdl.ts b/.blueprint/github-build-matrix/support/jdl.ts new file mode 100644 index 000000000000..abe192d47b0d --- /dev/null +++ b/.blueprint/github-build-matrix/support/jdl.ts @@ -0,0 +1,11 @@ +export const convertOptionsToJDL = (opts: Record): string => { + return `application { + config { + testFrameworks [cypress] +${Object.entries(opts) + .filter(([_key, value]) => value !== undefined) + .map(([key, value]) => ` ${key} ${value}`) + .join('\n')} + } +}`; +}; diff --git a/.blueprint/update-vscode/command.mts b/.blueprint/update-vscode/command.mts index 080ad48192af..4b92504f9e2c 100644 --- a/.blueprint/update-vscode/command.mts +++ b/.blueprint/update-vscode/command.mts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { type JHipsterCommandDefinition } from '../../generators/base/api.js'; +import { type JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { arguments: {}, diff --git a/.blueprint/update-vscode/generator.mjs b/.blueprint/update-vscode/generator.mts similarity index 89% rename from .blueprint/update-vscode/generator.mjs rename to .blueprint/update-vscode/generator.mts index 3620f4332d3f..cb6c67ac1249 100644 --- a/.blueprint/update-vscode/generator.mjs +++ b/.blueprint/update-vscode/generator.mts @@ -13,7 +13,7 @@ export default class extends BaseGenerator { async generateVscodeLaunch() { const vscodeLaunch = join(getPackageRoot(), '.vscode/launch.json'); - const baseFile = { + const baseFile: { version: string; inputs: any[]; configurations: any } = { version: '0.2.0', inputs: [], configurations: [ @@ -22,6 +22,7 @@ export default class extends BaseGenerator { request: 'launch', internalConsoleOptions: 'neverOpen', name: 'update vscode launch.json', + // eslint-disable-next-line no-template-curly-in-string program: '${workspaceFolder}/test-integration/scripts/99-update-vscode.js', console: 'integratedTerminal', }, @@ -41,6 +42,7 @@ export default class extends BaseGenerator { request: 'launch', internalConsoleOptions: 'neverOpen', name: `generate sample from ${workflowName} workflow`, + // eslint-disable-next-line no-template-curly-in-string program: '${workspaceFolder}/bin/jhipster.cjs', args: ['generate-sample', `\${input:${workflowName}Sample}`, '--global'], console: 'integratedTerminal', diff --git a/.blueprint/update-vscode/index.mjs b/.blueprint/update-vscode/index.mts similarity index 100% rename from .blueprint/update-vscode/index.mjs rename to .blueprint/update-vscode/index.mts diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index aabe916debee..000000000000 --- a/.eslintignore +++ /dev/null @@ -1,11 +0,0 @@ -.vscode-test -coverage -generators/**/templates -node_modules -node_modules_container -test-integration -docs -test/templates -jdl/bundling -test/fixtures/** -dist diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 920b4c9d8987..000000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "env": { - "node": true, - "es2022": true - }, - "extends": ["plugin:prettier/recommended", "plugin:@typescript-eslint/recommended"], - "parser": "@typescript-eslint/parser", - "plugins": ["mocha", "prettier", "chai-friendly", "@typescript-eslint", "unused-imports", "import"], - "settings": { - "import/core-modules": ["generator-jhipster", "generator-jhipster/support"] - }, - "parserOptions": { - "ecmaVersion": 13 - }, - "overrides": [ - { - "files": ["**/*.{c,m,}{js,ts}"], - "rules": { - "import/extensions": [0, { "pattern": { "{c,m,}{js,ts}": "always" } }] - } - }, - { - "files": ["**/*.spec.{c,m,}{js,ts}", "**/__test-support/*.{c,m,}{js,ts}", "test/**/*.{c,m,}{js,ts}"], - "rules": { - "@typescript-eslint/ban-ts-comment": "off", - "import/first": "off" - } - }, - { - "files": ["**/*.{c,m,}js", "**/*.{c,m,}js"], - "rules": { - "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-this-alias": "off", - "import/no-unresolved": "off" - } - }, - { - "files": ["**/*.{c,m,}ts"], - "rules": { - "import/extensions": "off", - "import/no-unresolved": "off" - } - } - ], - "rules": { - "default-param-last": "off", - "import/no-unresolved": [2, { "ignore": ["^#[\\w\\d/\\-]+$"] }], - "import/prefer-default-export": "off", - "prettier/prettier": "error", - "prefer-regex-literals": "off", - "linebreak-style": 0, - "eol-last": 2, - "quotes": [2, "single", { "avoidEscape": true }], - "semi": [2, "always"], - "eqeqeq": [2, "smart"], - "no-restricted-globals": ["off"], - "no-restricted-exports": "off", - "no-use-before-define": [2, "nofunc"], - "no-confusing-arrow": "off", - "no-multi-str": 2, - "no-promise-executor-return": "off", - "no-irregular-whitespace": 2, - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-unused-vars": "off", - "unused-imports/no-unused-imports": "error", - "unused-imports/no-unused-vars": [ - "error", - { "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" } - ], - "@typescript-eslint/no-explicit-any": "off", - "comma-dangle": "off", - "max-len": "off", - "import/order": "error", - "import/no-duplicates": "error", - "func-names": "off", - "class-methods-use-this": "off", - "no-underscore-dangle": "off", - "no-plusplus": "off", - "no-unused-expressions": 0, - "chai-friendly/no-unused-expressions": [2, { "allowShortCircuit": true, "allowTernary": true }], - "prefer-destructuring": "off", - "no-multi-assign": "off", - "no-param-reassign": "off", - "lines-between-class-members": [2, "always", { "exceptAfterSingleLine": true }], - "import/no-extraneous-dependencies": "off", - "no-await-in-loop": "off", - "no-restricted-syntax": [ - "error", - { - "selector": "ForInStatement", - "message": "for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array." - }, - { - "selector": "LabeledStatement", - "message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand." - }, - { - "selector": "WithStatement", - "message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize." - } - ], - "no-shadow": "off" - } -} diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md index 2d22704bd342..bfdcc632ce6b 100644 --- a/.github/ISSUE_TEMPLATE/BUG_REPORT.md +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md @@ -41,27 +41,20 @@ Which version of JHipster are you using, is it a regression? ##### **JHipster configuration** - - -##### **Entity configuration(s) `entityName.json` files generated in the `.jhipster` directory** - +The information is mandatory for bug reports. This will allow us to use automated tests and genarate the broken sample using `jhipster from-issue` command. ##### **Browsers and Operating System** diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index b7d56f0daf21..d44c134bb739 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -66,7 +66,7 @@ inputs: jhipster-bom-branch: description: 'JHipster BOM branch' required: false - default: auto + default: release jhipster-bom-directory: description: 'JHipster BOM path' required: false diff --git a/.github/actions/sonar/action.yml b/.github/actions/sonar/action.yml new file mode 100644 index 000000000000..682aa809f77c --- /dev/null +++ b/.github/actions/sonar/action.yml @@ -0,0 +1,302 @@ +# +# Copyright 2013-2024 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. +# +name: 'SonarQube PR Analysis' +description: 'A GitHub Action to perform SonarQube analysis on a PR with caching and metrics retrieval.' + +inputs: + sonar-project-key: + description: 'SonarQube project key' + required: true + application-dir: + description: 'Application directory' + required: true + docker-compose-file: + description: 'Path to the Docker Compose file' + required: true + comment-token: + description: 'GitHub token for commenting on the PR' + required: true + +runs: + using: composite + steps: + # Make sure the sonar project folder exists. + - run: mkdir -p ./${{ inputs.sonar-project-key }} + shell: bash + + # Cache the main branch project for future PR analysis + - name: 'Cache project on main branch' + if: github.ref == 'refs/heads/main' + shell: bash + run: | + cp -r ${{ inputs.application-dir }}/. . + rm -rf node_modules \ + package-lock.json \ + target/node \ + target/*.original \ + target/*.jar + working-directory: ${{ inputs.sonar-project-key }} + + - name: 'Store cache (main branch)' + if: github.ref == 'refs/heads/main' + uses: actions/cache/save@v4 + with: + path: ./${{ inputs.sonar-project-key }} + key: application-${{ inputs.sonar-project-key }}-${{ github.sha }} + + # Restore the cache for PR analysis + - name: 'Restore project cache for PR analysis' + if: github.event_name == 'pull_request' + id: restore_cache + uses: actions/cache/restore@v4 + with: + path: ./${{ inputs.sonar-project-key }} + key: application-${{ inputs.sonar-project-key }}-${{ github.event.pull_request.base.sha }} + restore-keys: | + application-${{ inputs.sonar-project-key }}- + + # Start SonarQube server using Docker Compose + - name: 'Start SonarQube server' + if: github.event_name == 'pull_request' + shell: bash + run: | + echo "::group::Starting sonarqube" + docker compose -f ${{ inputs.docker-compose-file }} up --build -d --wait + echo "::endgroup::" + + # Create SonarQube project + - name: 'Create SonarQube project' + if: github.event_name == 'pull_request' + shell: bash + run: | + curl -s -u admin:admin -X POST "http://localhost:9000/api/projects/create?name=${{ inputs.sonar-project-key }}&project=${{ inputs.sonar-project-key }}" || true + + # Run SonarQube analysis on the main branch or add an empty scan + - name: 'Run SonarQube analysis on main branch' + if: github.event_name == 'pull_request' && steps.restore_cache.outputs.cache-matched-key + shell: bash + run: >- + echo "::group::Scanning main branch application" && + ./mvnw --batch-mode initialize org.jacoco:jacoco-maven-plugin:prepare-agent sonar:sonar + -Dsonar.host.url=http://localhost:9000 + -Dsonar.projectKey=${{ inputs.sonar-project-key }} + -Dsonar.login=admin + -Dsonar.password=admin + -Dsonar.branch.name=main && + echo "::endgroup::" + working-directory: ${{ inputs.sonar-project-key }} + + - name: Add an empty scan to sonar main branch + if: github.event_name == 'pull_request' && !steps.restore_cache.outputs.cache-matched-key + shell: bash + run: >- + echo "::group::Scanning empty commit" && + git init && + git commit -m "Initial commit" --allow-empty && + docker run --net=host -v ".:/usr/src" --rm sonarsource/sonar-scanner-cli + -Dsonar.host.url=http://localhost:9000 + -Dsonar.projectKey=${{ inputs.sonar-project-key }} + -Dsonar.login=admin + -Dsonar.password=admin + -Dsonar.branch.name=main && + echo "::endgroup::" + working-directory: ${{ inputs.sonar-project-key }} + + # Prepare the repository for the PR changes + - name: 'Clean repository for PR changes' + if: github.event_name == 'pull_request' + shell: bash + run: find . -mindepth 1 -not -path "./.git*" -delete + working-directory: ${{ inputs.sonar-project-key }} + + - name: 'Apply PR changes to the repository' + if: github.event_name == 'pull_request' + shell: bash + run: | + echo "::group::Creating changes commit" + rm -rf "${{ inputs.application-dir }}/.git" + cp -r ${{ inputs.application-dir }}/. . + + git checkout -b dev + git add -A + git commit -m "Apply changes from PR branch" + echo "::endgroup::" + working-directory: ${{ inputs.sonar-project-key }} + + # Run SonarQube analysis on the PR changes + - name: 'Run SonarQube analysis on PR changes' + if: github.event_name == 'pull_request' + shell: bash + run: >- + echo "::group::Scanning PR application changes" && + ./mvnw --batch-mode initialize org.jacoco:jacoco-maven-plugin:prepare-agent sonar:sonar + -Dsonar.host.url=http://localhost:9000 + -Dsonar.projectKey=${{ inputs.sonar-project-key }} + -Dsonar.login=admin + -Dsonar.password=admin + -Dsonar.pullrequest.key=${{github.event.pull_request.number}} + -Dsonar.pullrequest.branch=dev + -Dsonar.pullrequest.base=main + -Dsonar.scm.revision=$(git rev-parse HEAD) && + echo "::endgroup::" + working-directory: ${{ inputs.sonar-project-key }} + + # Wait for SonarQube tasks to complete + - name: 'Wait for SonarQube tasks to complete' + if: github.event_name == 'pull_request' + shell: bash + run: | + timeout 300s bash -c 'while :; do + response=$(curl -s -u admin:admin "http://localhost:9000/api/ce/component?component=${{ inputs.sonar-project-key }}") + queue_status=$(echo "$response" | jq -r ".queue[]?.status") + current_status=$(echo "$response" | jq -r ".current.status") + + if [[ "$queue_status" == "" && "$current_status" != "IN_PROGRESS" ]]; then + echo "All tasks completed or no tasks pending." + break + fi + + if [[ "$queue_status" == "PENDING" || "$queue_status" == "IN_PROGRESS" || "$current_status" == "IN_PROGRESS" ]]; then + echo "Tasks are still in progress or pending. Waiting..." + sleep 10 + else + echo "All tasks completed." + break + fi + done' || (echo "SonarQube tasks failed to complete in time" && exit 1) + + # Retrieve SonarQube metrics for the PR + - name: 'Retrieve SonarQube metrics' + if: github.event_name == 'pull_request' + id: sonar_metrics + shell: bash + run: | + SONAR_RESPONSE=$(curl -s -u admin:admin \ + "http://localhost:9000/api/measures/component?component=${{ inputs.sonar-project-key }}&pullRequest=${{ github.event.pull_request.number }}&metricKeys=new_bugs,new_vulnerabilities,new_code_smells,new_coverage,new_duplicated_lines_density,new_violations") + echo ":::group::PR SonarQube Analysis" + echo "$SONAR_RESPONSE" + echo "::endgroup::" + + SONAR_RESPONSE_MAIN=$(curl -s -u admin:admin \ + "http://localhost:9000/api/measures/component?component=${{ inputs.sonar-project-key }}&metricKeys=violations") + echo ":::group::SonarQube Analysis" + echo "$SONAR_RESPONSE_MAIN" + echo "::endgroup::" + + export_measure() { + METRIC_NAME=$1 + ENV_VAR_NAME=$2 + METRIC_VALUE=$(echo "$SONAR_RESPONSE" | jq -r ".component.measures[] | select(.metric == \"$METRIC_NAME\") | .period.value") + if [ -z "$METRIC_VALUE" ] || [ "$METRIC_VALUE" == "null" ]; then + METRIC_VALUE="N/A" + fi + echo "$ENV_VAR_NAME=$METRIC_VALUE" >> $GITHUB_ENV + export $ENV_VAR_NAME=$METRIC_VALUE + } + + print_main_metric() { + METRIC_NAME=$1 + METRIC_VALUE=$(echo "$SONAR_RESPONSE_MAIN" | jq -r ".component.measures[] | select(.metric == \"$METRIC_NAME\") | .value") + if [ -z "$METRIC_VALUE" ] || [ "$METRIC_VALUE" == "null" ]; then + METRIC_VALUE="N/A" + fi + echo "${METRIC_VALUE}" + } + + export_measure "new_vulnerabilities" "NEW_VUL" + export_measure "new_code_smells" "NEW_CSM" + export_measure "new_bugs" "NEW_BUG" + export_measure "new_violations" "NEW_VIOLATIONS" + export_measure "violations" "VIOLATIONS" + export_measure "new_coverage" "NEW_COV" + export_measure "new_duplicated_lines_density" "NEW_DUP" + + { + echo "## :bar_chart: SonarQube Analysis for ${{ inputs.sonar-project-key }}" + echo "" + echo "| Metric | Value |" + echo "|-----------------------------|-------------|" + echo "| **Total Violations** | $(print_main_metric "violations") |" + echo "| **New Vulnerabilities** | ${NEW_VUL} |" + echo "| **New Bugs** | ${NEW_BUG} |" + echo "| **New Code smells** | ${NEW_CSM} |" + echo "| **Coverage on New Code** | ${NEW_COV}% |" + echo "| **Duplication on New Code** | ${NEW_DUP}% |" + + if [[ "${NEW_VIOLATIONS}" != "N/A" && "${NEW_VIOLATIONS}" != "0" ]]; then + echo "" + echo "
Unresolved New Issues (click to expand)" + echo "" + ISSUES=$(curl -s -u admin:admin \ + "http://localhost:9000/api/issues/search?componentKeys=${{ inputs.sonar-project-key }}&resolved=false&pullRequest=${{ github.event.pull_request.number }}" | \ + jq -r '.issues[] | "File: \(.component) Line: \(.line)\n [\(.rule)] \(.message)\n"') + echo "$ISSUES" + echo "
" + fi + } > sonar_result.md + + { + echo 'COMMENT_BODY<> "$GITHUB_ENV" + + cat sonar_result.md + + # Find previous SonarQube analysis comment + - name: 'Find existing PR comment with SonarQube results' + if: github.event_name == 'pull_request' && inputs.comment-token && steps.sonar_metrics.outcome == 'success' + id: find_comment + uses: peter-evans/find-comment@v3 + with: + issue-number: ${{ github.event.pull_request.number }} + body-includes: '## :bar_chart: SonarQube Analysis for ${{ inputs.sonar-project-key }}' + token: ${{ inputs.comment-token }} + + # Create or update PR comment with SonarQube results + - name: 'Post SonarQube results as PR comment' + if: github.event_name == 'pull_request' && inputs.comment-token && steps.sonar_metrics.outcome == 'success' + uses: peter-evans/create-or-update-comment@v4 + with: + issue-number: ${{ github.event.pull_request.number }} + body: ${{ env.COMMENT_BODY }} + comment-id: ${{ steps.find_comment.outputs.comment-id }} + edit-mode: replace + token: ${{ inputs.comment-token }} + + # Fail the action if there are unresolved issues + - name: 'Fail PR if unresolved issues are found' + if: >- + github.event_name == 'pull_request' && + steps.sonar_metrics.outcome == 'success' && + env.NEW_VIOLATIONS != 'N/A' && env.NEW_VIOLATIONS != 0 && + !contains(github.event.pull_request.labels.*.name, 'pr: disable-sonar') + shell: bash + run: | + echo "SonarQube PR Analysis failed due to unresolved issues." + exit 1 + + # Stop the SonarQube server + - name: 'Stop SonarQube server' + if: github.event_name == 'pull_request' + shell: bash + run: | + echo "::group::Stopping SonarQube" + docker compose -f ${{ inputs.docker-compose-file }} down + echo "::endgroup::" diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6a033ebc710f..0b8cfb85a8fc 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -36,9 +36,10 @@ updates: - dependency-name: '@types/node' versions: ['>=19'] groups: - typescript-eslint: + eslint: patterns: - - '@typescript-eslint/*' + - '@eslint/*' + - 'eslint' - package-ecosystem: 'npm' directory: '/generators/generate-blueprint/resources/' @@ -83,16 +84,14 @@ updates: - 'ngx-infinite-scroll' - 'typescript' - 'zone.js' - angular-eslint: - patterns: - - '@angular-eslint/*' fortawesome: patterns: - '@fortawesome/fontawesome-svg-core' - '@fortawesome/free-solid-svg-icons' - typescript-eslint: + eslint: patterns: - - '@typescript-eslint/*' + - '@eslint/*' + - 'eslint' - package-ecosystem: 'npm' directory: '/generators/common/resources/' @@ -147,7 +146,8 @@ updates: # Should match generated project node major version. - dependency-name: '@types/node' versions: ['>=19'] - - dependency-name: '@module-federation/utilities' + # https://github.com/jhipster/generator-jhipster/issues/27464#issuecomment-2400505558, https://github.com/twbs/bootstrap/issues/40849 + - dependency-name: 'sass' versions: ['*'] groups: eslint: @@ -181,19 +181,17 @@ updates: # https://github.com/bootstrap-vue/bootstrap-vue/issues/5507 - dependency-name: 'bootstrap' versions: ['>=5'] + # Bootstrap v4 issue https://github.com/jhipster/generator-jhipster/issues/23770, https://github.com/twbs/bootstrap/issues/39028, https://github.com/jhipster/generator-jhipster/issues/27464#issuecomment-2400505558, https://github.com/twbs/bootstrap/issues/40849 + - dependency-name: 'sass' + versions: ['*'] # Should match generated project node major version. - dependency-name: '@types/node' versions: ['>=19'] - - dependency-name: '@module-federation/utilities' - versions: ['*'] groups: - typescript-eslint: - patterns: - - '@typescript-eslint/*' - vue-eslint: + eslint: patterns: - - '@vue/eslint-config-typescript' - - 'eslint-plugin-vue' + - '@eslint/*' + - 'eslint' fortawesome: patterns: - '@fortawesome/fontawesome-svg-core' @@ -209,10 +207,17 @@ updates: - 'theme: dependencies' - 'theme: docker :whale:' - 'skip-changelog' - ignore: - # https://github.com/jhipster/generator-jhipster/issues/25548 - - dependency-name: 'mongo' - versions: ['>=7.0.6'] + + - package-ecosystem: 'docker' + directory: '/test-integration/sonar-pr/' + schedule: + interval: 'daily' + time: '00:30' + open-pull-requests-limit: 5 + labels: + - 'theme: dependencies' + - 'theme: docker :whale:' + - 'skip-changelog' - package-ecosystem: 'maven' directory: '/generators/server/resources/' @@ -258,3 +263,13 @@ updates: - 'theme: github_actions' - 'theme: CI builds' - 'skip-changelog' + + - package-ecosystem: 'gradle' + directory: '/generators/spring-boot/generators/graalvm/resources/' + schedule: + interval: 'daily' + time: '08:30' + open-pull-requests-limit: 5 + labels: + - 'theme: dependencies' + - 'skip-changelog' diff --git a/.github/labeler.yml b/.github/labeler.yml index 72444e7be8b8..bb4d8ac7ebec 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -75,7 +75,10 @@ - changed-files: - any-glob-to-any-file: - generators/common/** + - generators/java/**/* + - generators/liquibase/**/* - generators/server/**/* + - generators/spring-*/**/* 'theme: upgrade': - changed-files: diff --git a/.github/workflows/angular.yml b/.github/workflows/angular.yml index 817642abfca3..b4fcd14f367f 100644 --- a/.github/workflows/angular.yml +++ b/.github/workflows/angular.yml @@ -35,6 +35,8 @@ on: types: [closed, opened, synchronize, reopened] branches: - '*' +env: + FORCE_COLOR: 2 jobs: build-matrix: runs-on: ubuntu-20.04 @@ -51,13 +53,11 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 2 - - name: 'Build matrix' - id: build - uses: ./.github/actions/build-matrix - with: - workflow-samples-file: angular + - run: npm ci --ignore-scripts + - id: build + run: bin/jhipster.cjs github-build-matrix angular --event-name ${{ github.event_name }} applications: - name: ${{ matrix.name }} (n${{ matrix.node }}/j${{ matrix.java }}) + name: ${{ matrix.job-name }} runs-on: ${{ matrix.os || 'ubuntu-20.04' }} needs: build-matrix defaults: @@ -74,12 +74,12 @@ jobs: !contains(github.event.pull_request.title, '[ci skip]') && github.event.action != 'closed' && !contains(github.event.pull_request.labels.*.name, 'pr: skip-ci') && - needs.build-matrix.outputs.workflow-angular == 'true' + fromJson(needs.build-matrix.outputs.matrix).include[0] != null timeout-minutes: 50 strategy: fail-fast: false # Matrix available at https://github.com/jhipster/generator-jhipster/tree/main/test-integration/workflow-samples/ - matrix: ${{fromJson(needs.build-matrix.outputs.matrix)}} + matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} steps: #---------------------------------------------------------------------- # Install all tools and check configuration @@ -91,8 +91,8 @@ jobs: fetch-depth: 2 - uses: jhipster/actions/setup-runner@v0 with: - node-version: ${{ matrix.node }} - java-version: ${{ matrix.java }} + node-version: ${{ matrix.node-version }} + java-version: ${{ matrix.java-version }} npm-version: ${{ matrix.npm-version }} maven-cache: true gradle-cache: ${{ matrix.gradle-cache }} @@ -103,10 +103,11 @@ jobs: - run: npm ci --ignore-scripts working-directory: ${{ github.workspace }}/generator-jhipster - name: 'GENERATION: project' - run: jhipster.cjs generate-sample ${{ matrix.name }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight + run: jhipster.cjs generate-sample ${{ matrix.sample }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight env: JHI_FOLDER_APP: ${{ github.workspace }}/app JHIPSTER_DEPENDENCIES_VERSION: ${{ matrix.jhipster-bom-cicd-version }} + JHI_JWT_SECRET_KEY: ${{ matrix.jwt-secret-key }} - run: jhipster.cjs info #---------------------------------------------------------------------- # Detect changes against base commit @@ -118,11 +119,12 @@ jobs: !contains(github.event.pull_request.labels.*.name, 'pr: disable-compare') with: generator-path: generator-jhipster - cmd: jhipster.cjs generate-sample ${{ matrix.name }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight + cmd: jhipster.cjs generate-sample ${{ matrix.sample }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight env: # generate-sample uses JHI_FOLDER_APP to generate the application. JHI_FOLDER_APP: ${{ github.workspace }}/base/app JHIPSTER_DEPENDENCIES_VERSION: ${{ matrix.jhipster-bom-cicd-version }} + JHI_JWT_SECRET_KEY: ${{ matrix.jwt-secret-key }} #---------------------------------------------------------------------- # Launch tests #---------------------------------------------------------------------- @@ -132,22 +134,25 @@ jobs: jhipster-bom-ref: ${{ matrix.jhipster-bom-branch }} - name: 'TESTS: backend' id: backend - if: steps.compare.outputs.equals != 'true' && matrix.skip-backend-tests != 'true' && needs.build-matrix.outputs.server != 'false' + if: steps.compare.outputs.equals != 'true' && matrix.skip-backend-tests != 'true' run: npm run ci:backend:test continue-on-error: ${{matrix.continue-on-backend-tests-error || false}} timeout-minutes: 15 + # Run npm install for workspaces only, as it is done in packaging for non-workspaces - name: 'PREPARE: npm install' - if: steps.compare.outputs.equals != 'true' && matrix.skip-frontend-tests != 'true' && needs.build-matrix.outputs.client != 'false' - run: ${{ (matrix.workspaces == 'true' && 'npm') || './npmw' }} install + if: steps.compare.outputs.equals != 'true' && matrix.workspaces == 'true' + run: npm install timeout-minutes: 7 - - name: 'TESTS: frontend' - if: steps.compare.outputs.equals != 'true' && matrix.skip-frontend-tests != 'true' && needs.build-matrix.outputs.client != 'false' - run: npm run ci:frontend:test - timeout-minutes: 15 - name: 'TESTS: packaging' + id: packaging if: steps.compare.outputs.equals != 'true' run: npm run ci:e2e:package timeout-minutes: 12 + - name: 'TESTS: frontend' + id: frontend + if: steps.compare.outputs.equals != 'true' && matrix.skip-frontend-tests != 'true' + run: npm run ci:frontend:test + timeout-minutes: 15 - name: 'TESTS: Start docker compose containers for e2e tests' if: steps.compare.outputs.equals != 'true' run: npm run ci:e2e:prepare @@ -157,17 +162,32 @@ jobs: if: steps.compare.outputs.equals != 'true' run: npm run ci:e2e:run --if-present timeout-minutes: 15 + - name: Store the application + uses: actions/upload-artifact@v4 + if: always() && (steps.backend.outcome == 'failure' || steps.e2e.outcome == 'failure' || steps.frontend.outcome == 'failure' || steps.packaging.outcome == 'failure') + with: + name: app-${{ matrix.sample }} + include-hidden-files: true + path: | + ${{ github.workspace }}/app/**/* + !**/app/build/** + !**/app/*/build/** + !**/app/.gradle/** + !**/app/*/.gradle/** + !**/app/target/** + !**/app/*/target/** + !**/node_modules/** - name: 'BACKEND: Store failure logs' uses: actions/upload-artifact@v4 if: always() && steps.backend.outcome == 'failure' with: - name: log-${{ matrix.name }} + name: log-${{ matrix.sample }} path: ${{ github.workspace }}/app/**/test-results/**/*.xml - name: 'E2E: Store failure screenshots' uses: actions/upload-artifact@v4 if: always() && steps.e2e.outcome == 'failure' with: - name: screenshots-${{ matrix.name }} + name: screenshots-${{ matrix.sample }} path: ${{ github.workspace }}/app/**/cypress/screenshots - name: Dump docker logs if: always() @@ -176,13 +196,7 @@ jobs: if: >- github.event_name == 'push' && github.repository == 'jhipster/generator-jhipster' && - matrix.sonar-analyse == 'true' && - steps.compare.outputs.equals != 'true' && - matrix.workspaces != 'true' && - matrix.skip-frontend-tests != 'true' && - needs.build-matrix.outputs.client != 'false' && - matrix.skip-backend-tests != 'true' && - needs.build-matrix.outputs.server != 'false' + matrix.sonar-analyse == 'true' run: | ./mvnw -ntp --batch-mode initialize org.jacoco:jacoco-maven-plugin:prepare-agent sonar:sonar \ -Dsonar.host.url=https://sonarcloud.io \ @@ -191,6 +205,19 @@ jobs: -Dsonar.login=$SONAR_TOKEN env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + - name: 'ANALYSIS: Local SonarQube PR Analysis' + if: >- + matrix.sonar-analyse == 'true' && + !contains(github.event.pull_request.labels.*.name, 'pr: disable-sonar') && + steps.compare.outputs.equals != 'true' + uses: ./generator-jhipster/.github/actions/sonar + with: + sonar-project-key: ${{ matrix.sample }} + application-dir: ${{ github.workspace }}/app + docker-compose-file: ${{ github.workspace }}/generator-jhipster/test-integration/sonar-pr/docker-compose.yml + comment-token: ${{ secrets.PAT_PR_ISSUES_TOKEN }} + check-angular: permissions: contents: none diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 1c7750c8a0f0..f12fd0cbb004 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -31,8 +31,8 @@ jobs: id: dependabot-metadata uses: dependabot/fetch-metadata@v2.2.0 - name: Enable auto-merge for Dependabot PRs - if: steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major' && steps.dependabot-metadata.outputs.dependency-names != 'typescript' - run: gh pr merge --auto --merge "$PR_URL" + if: steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major' + run: gh pr merge --auto --squash "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/copyright-update.yml b/.github/workflows/copyright-update.yml index 5cee1ac1c95e..3657edd49ee8 100644 --- a/.github/workflows/copyright-update.yml +++ b/.github/workflows/copyright-update.yml @@ -47,7 +47,7 @@ jobs: grep -rlZE "Copyright ([0-9]+)-$CURRENT_YEAR" . | xargs -0 sed -i -E "s/Copyright ([0-9]+)-$CURRENT_YEAR/Copyright \1-$NEW_YEAR/g" # Create PR - name: Create Pull Request - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GITHUB_TOKEN }} commit-message: 'Update copyright headers' diff --git a/.github/workflows/devserver.yml b/.github/workflows/devserver.yml index e3d903d98aca..d84d94ce5ea6 100644 --- a/.github/workflows/devserver.yml +++ b/.github/workflows/devserver.yml @@ -22,6 +22,8 @@ concurrency: # Group PRs by head_ref, push to main branch by commit id, and others branch by ref. group: ${{ github.workflow }}-${{ github.head_ref || (github.ref == 'refs/heads/main' && github.sha) || github.ref }} cancel-in-progress: true +env: + FORCE_COLOR: 2 on: push: branches: @@ -31,6 +33,7 @@ on: - '.github/workflows/devserver.yml' - 'generators/angular/**' - 'generators/client/**' + - 'generators/javascript/**' - 'generators/react/**' - 'generators/vue/**' - 'generators/*' @@ -49,23 +52,21 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 2 - - name: 'Build matrix' - id: build - uses: ./.github/actions/build-matrix - with: - workflow-file-prefix: devserver + - run: npm ci --ignore-scripts + - id: build + run: bin/jhipster.cjs github-build-matrix devserver --event-name ${{ github.event_name }} applications: - name: ${{ matrix.app-sample }} + name: ${{ matrix.job-name }} needs: build-matrix - runs-on: ubuntu-20.04 + runs-on: ${{ matrix.os }} defaults: run: working-directory: ${{ github.workspace }}/app timeout-minutes: 40 strategy: fail-fast: false - matrix: ${{fromJson(needs.build-matrix.outputs.matrix)}} - if: needs.build-matrix.outputs.empty-matrix != 'true' + matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} + if: fromJson(needs.build-matrix.outputs.matrix).include[0] != null steps: #---------------------------------------------------------------------- # Install all tools and check configuration @@ -75,44 +76,35 @@ jobs: with: path: generator-jhipster fetch-depth: 2 - - name: 'SETUP: environment' - id: setup - uses: ./generator-jhipster/.github/actions/setup - with: - application-sample: ${{ matrix.setup-application-sample }} - entities-sample: ${{ matrix.setup-entities-sample }} - jdl-entities-sample: ${{ matrix.setup-jdl-entities-sample }} - jdl-sample: ${{ matrix.setup-jdl-sample }} - application-environment: ${{ matrix.setup-application-environment }} - application-packaging: ${{ matrix.setup-application-packaging }} - uses: jhipster/actions/setup-runner@v0 with: - node-version: ${{ steps.setup.outputs.node-version }} - java-version: ${{ steps.setup.outputs.java-version }} + node-version: ${{ matrix.node-version }} + java-version: ${{ matrix.java-version }} + npm-version: ${{ matrix.npm-version }} maven-cache: true + binary-dir: ${{ github.workspace }}/generator-jhipster/bin #---------------------------------------------------------------------- # Install JHipster and generate project+entities #---------------------------------------------------------------------- - - name: 'GENERATION: install JHipster' - run: $JHI_SCRIPTS/10-install-jhipster.sh - - name: 'GENERATION: config' - run: $JHI_SCRIPTS/11-generate-config.sh + - run: npm ci --ignore-scripts + working-directory: ${{ github.workspace }}/generator-jhipster - name: 'GENERATION: project' - run: $JHI_SCRIPTS/12-generate-project.sh ${{ matrix.extra-args }} ${{ matrix.new-extra-args }} - - name: 'GENERATION: jhipster info' - run: $JHI_SCRIPTS/14-jhipster-info.sh + run: jhipster.cjs generate-sample ${{ matrix.sample }} --skip-jhipster-dependencies --skip-install ${{ matrix.args }} + - run: jhipster.cjs info #---------------------------------------------------------------------- # Launch tests #---------------------------------------------------------------------- - name: 'E2E: Run' id: e2e - run: ./npmw run e2e:devserver --if-present + run: | + ./npmw install + ./npmw run e2e:devserver --if-present - name: 'E2E: Store failure screenshots' uses: actions/upload-artifact@v4 if: always() && steps.e2e.outcome == 'failure' with: - name: screenshots-${{ matrix.app-sample }} - path: ${{ steps.setup.outputs.application-path }}/*/cypress/screenshots + name: screenshots-${{ matrix.job-name }} + path: ${{ github.workspace }}/app/*/cypress/screenshots check-dev-server: permissions: contents: none diff --git a/.github/workflows/docker-compose-integration.yml b/.github/workflows/docker-compose-integration.yml new file mode 100644 index 000000000000..1deef2580f66 --- /dev/null +++ b/.github/workflows/docker-compose-integration.yml @@ -0,0 +1,111 @@ +# +# Copyright 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. +# + +name: Testcontainers Integration +concurrency: + # Group PRs by head_ref, push to main branch by commit id, and others branch by ref. + group: ${{ github.workflow }}-${{ github.head_ref || (github.ref == 'refs/heads/main' && github.sha) || github.ref }} + cancel-in-progress: true +on: + pull_request: + types: [closed, opened, synchronize, reopened] + branches: + - '*' +env: + FORCE_COLOR: 2 +jobs: + build-matrix: + runs-on: ubuntu-20.04 + if: >- + contains(github.event.pull_request.labels.*.name, 'pr: docker-compose integration') + outputs: + matrix: ${{ steps.build.outputs.matrix }} + empty-matrix: ${{ steps.build.outputs.empty-matrix }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + - uses: actions/setup-node@v4 + with: + node-version: '20' + - run: npm ci --ignore-scripts + - id: build + run: bin/jhipster.cjs github-build-matrix docker-compose-integration --event-name ${{ github.event_name }} + applications: + name: ${{ matrix.job-name }} + needs: build-matrix + runs-on: ${{ matrix.os }} + defaults: + run: + working-directory: ${{ github.workspace }}/app + timeout-minutes: 40 + strategy: + fail-fast: false + matrix: ${{fromJson(needs.build-matrix.outputs.matrix)}} + steps: + #---------------------------------------------------------------------- + # Install all tools and check configuration + #---------------------------------------------------------------------- + - name: 'SETUP: Checkout generator-jhipster' + uses: actions/checkout@v4 + with: + path: generator-jhipster + fetch-depth: 2 + - uses: jhipster/actions/setup-runner@v0 + with: + node-version: ${{ matrix.node-version }} + java-version: ${{ matrix.java-version }} + npm-version: ${{ matrix.npm-version }} + maven-cache: true + gradle-cache: ${{ matrix.gradle-cache }} + binary-dir: ${{ github.workspace }}/generator-jhipster/bin + - run: npm ci --ignore-scripts + working-directory: ${{ github.workspace }}/generator-jhipster + - uses: jhipster/actions/build-jhipster-bom@v0 + with: + jhipster-bom-ref: main + - name: Generate project + run: jhipster.cjs ${{ matrix.args }} --defaults + env: + JHIPSTER_DEPENDENCIES_VERSION: 0.0.0-CICD + JHI_SKIP_JHIPSTER_DEPENDENCIES: true + JHI_PROFILE: ${{ matrix.default-environment }} + JHI_JDL: ${{ matrix.jdl }} + - run: jhipster.cjs info + - run: ${{ matrix.cmd-e2e }} + id: e2e + - name: Upload cypress screenshots + uses: actions/upload-artifact@v4 + if: always() && steps.e2e.outcome == 'failure' + with: + name: screenshots-${{ matrix.name }} + path: ${{ github.workspace }}app//*/cypress/screenshots + check-workflow: + permissions: + contents: none + runs-on: ubuntu-latest + needs: [applications] + if: always() + steps: + - run: | + echo '${{ toJSON(needs) }}' + if [ 'skipped' == '${{ needs.applications.result }}' ] || [ 'success' == '${{ needs.applications.result }}' ] || [ 'closed' == '${{ github.event.action }}' ]; then + exit 0 + fi + exit 1 diff --git a/.github/workflows/docker-image-publish-github-registry.yml b/.github/workflows/docker-image-publish-github-registry.yml index 2d154be64e8b..946c78428091 100644 --- a/.github/workflows/docker-image-publish-github-registry.yml +++ b/.github/workflows/docker-image-publish-github-registry.yml @@ -28,6 +28,8 @@ on: tags: - 'v*.*.*' +env: + FORCE_COLOR: 1 jobs: build: runs-on: ubuntu-20.04 @@ -40,16 +42,16 @@ jobs: uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v3.1.0 + uses: docker/setup-qemu-action@v3.2.0 with: platforms: arm64 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.4.0 + uses: docker/setup-buildx-action@v3.7.1 - name: Login to GitHub Container Registry if: github.event_name != 'pull_request' - uses: docker/login-action@v3.2.0 + uses: docker/login-action@v3.3.0 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -59,7 +61,7 @@ jobs: env: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} if: ${{env.DOCKERHUB_USERNAME != '' && startsWith(github.ref, 'refs/tags/v')}} - uses: docker/login-action@v3.2.0 + uses: docker/login-action@v3.3.0 id: login-hub with: username: ${{ secrets.DOCKERHUB_USERNAME }} @@ -72,7 +74,7 @@ jobs: images: ghcr.io/${{ github.repository }}${{ (steps.login-hub.outcome == 'success' && ',jhipster/jhipster') || ''}} - name: Build and push Docker image - uses: docker/build-push-action@v6.4.0 + uses: docker/build-push-action@v6.9.0 with: context: . platforms: linux/amd64,linux/arm64 diff --git a/.github/workflows/generator-database-changelog-liquibase.yml b/.github/workflows/generator-database-changelog-liquibase.yml index 6446508b8ea5..2e39df4607b5 100644 --- a/.github/workflows/generator-database-changelog-liquibase.yml +++ b/.github/workflows/generator-database-changelog-liquibase.yml @@ -19,6 +19,8 @@ name: Incremental Changelog on: [workflow_call] +env: + FORCE_COLOR: 2 jobs: check-generator-database-changelog-liquibase: name: ${{ matrix.app-type }} diff --git a/.github/workflows/generator-generate-blueprint.yml b/.github/workflows/generator-generate-blueprint.yml index f3051d763c9a..fa2a6dcdd6db 100644 --- a/.github/workflows/generator-generate-blueprint.yml +++ b/.github/workflows/generator-generate-blueprint.yml @@ -19,6 +19,8 @@ name: Blueprint Generator on: [workflow_call] +env: + FORCE_COLOR: 2 jobs: check-generator-generate-blueprint: runs-on: ubuntu-20.04 diff --git a/.github/workflows/generator-graalvm.yml b/.github/workflows/generator-graalvm.yml new file mode 100644 index 000000000000..1162cc8eb0fe --- /dev/null +++ b/.github/workflows/generator-graalvm.yml @@ -0,0 +1,165 @@ +# +# Copyright 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. +# + +name: Incremental Changelog +on: [workflow_call] +env: + FORCE_COLOR: 2 +jobs: + build-matrix: + runs-on: ubuntu-latest + if: >- + !contains(github.event.head_commit.message, '[ci skip]') && + !contains(github.event.head_commit.message, '[skip ci]') && + !contains(github.event.pull_request.title, '[skip ci]') && + !contains(github.event.pull_request.title, '[ci skip]') && + github.event.action != 'closed' && + (github.event.pull_request.draft == false || !contains(github.event.pull_request.labels.*.name, 'pr: skip-ci')) + outputs: + matrix: ${{ steps.build.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 2 + - uses: actions/setup-node@v4 + with: + node-version: '20' + - run: npm ci --ignore-scripts + - id: build + run: bin/jhipster.cjs github-build-matrix graalvm --event-name ${{ github.event_name }} + applications: + name: ${{ matrix.job-name }} + runs-on: ${{ matrix.os }} + defaults: + run: + working-directory: ${{ github.workspace }}/app + timeout-minutes: 40 + needs: build-matrix + if: fromJson(needs.build-matrix.outputs.matrix).include[0] != null + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} + steps: + #---------------------------------------------------------------------- + # Install all tools and check configuration + #---------------------------------------------------------------------- + - name: 'SETUP: Checkout generator-jhipster' + uses: actions/checkout@v4 + with: + path: generator-jhipster + fetch-depth: 2 + - uses: jhipster/actions/setup-runner@v0 + with: + node-version: ${{ matrix.node-version }} + java-version: ${{ matrix.java-version }} + npm-version: ${{ matrix.npm-version }} + maven-cache: true + gradle-cache: ${{ matrix.gradle-cache }} + binary-dir: ${{ github.workspace }}/generator-jhipster/bin + #---------------------------------------------------------------------- + # Install JHipster and generate project+entities + #---------------------------------------------------------------------- + - run: npm ci --ignore-scripts + working-directory: ${{ github.workspace }}/generator-jhipster + - name: 'GENERATION: project' + run: jhipster.cjs jdl --skip-jhipster-dependencies --skip-install + env: + JHI_FOLDER_APP: ${{ github.workspace }}/app + JHIPSTER_DEPENDENCIES_VERSION: ${{ matrix.jhipster-bom-cicd-version }} + JHI_JWT_SECRET_KEY: ${{ matrix.jwt-secret-key }} + JHI_JDL: ${{ matrix.jdl }} + - run: jhipster.cjs info + #---------------------------------------------------------------------- + # Detect changes against base commit + #---------------------------------------------------------------------- + - uses: jhipster/actions/compare-sample@v0 + id: compare + if: >- + github.event.pull_request && + !contains(github.event.pull_request.labels.*.name, 'pr: disable-compare') + with: + generator-path: generator-jhipster + cmd: jhipster.cjs jdl --skip-jhipster-dependencies --skip-install + env: + # generate-sample uses JHI_FOLDER_APP to generate the application. + JHI_FOLDER_APP: ${{ github.workspace }}/base/app + JHIPSTER_DEPENDENCIES_VERSION: ${{ matrix.jhipster-bom-cicd-version }} + JHI_JWT_SECRET_KEY: ${{ matrix.jwt-secret-key }} + JHI_JDL: ${{ matrix.jdl-base || matrix.jdl }} + #---------------------------------------------------------------------- + # Launch tests + #---------------------------------------------------------------------- + - name: 'SETUP: setup graalvm' + uses: graalvm/setup-graalvm@v1 + with: + java-version: ${{ matrix.java-version }} + distribution: 'graalvm-community' + github-token: ${{ secrets.GITHUB_TOKEN }} + native-image-job-reports: 'true' + - uses: jhipster/actions/build-jhipster-bom@v0 + if: matrix.build-jhipster-bom && steps.compare.outputs.equals != 'true' + with: + jhipster-bom-ref: ${{ matrix.jhipster-bom-branch }} + - run: npm run native-package + if: steps.compare.outputs.equals != 'true' + id: packaging + timeout-minutes: 20 + - run: npm run services:up + if: steps.compare.outputs.equals != 'true' + - run: npm run native-e2e --if-present + id: e2e + if: steps.compare.outputs.equals != 'true' + - name: Store the application + uses: actions/upload-artifact@v4 + if: always() && (steps.e2e.outcome == 'failure' || steps.packaging.outcome == 'failure') + with: + name: app-${{ matrix.sample }} + include-hidden-files: true + path: | + ${{ github.workspace }}/app/**/* + !**/app/build/** + !**/app/*/build/** + !**/app/.gradle/** + !**/app/*/.gradle/** + !**/app/target/** + !**/app/*/target/** + !**/node_modules/** + - name: 'E2E: Store failure screenshots' + uses: actions/upload-artifact@v4 + if: always() && steps.e2e.outcome == 'failure' + with: + name: screenshots-${{ matrix.sample }} + path: ${{ github.workspace }}/app/**/cypress/screenshots + - name: Dump docker logs + if: always() && contains(matrix.os, 'ubuntu') + uses: jwalton/gh-docker-logs@v2 + + check-graalvm: + permissions: + contents: none + runs-on: ubuntu-latest + needs: [applications] + if: always() + steps: + - run: | + echo '${{ toJSON(needs) }}' + if [ 'skipped' == '${{ needs.applications.result }}' ] || [ 'success' == '${{ needs.applications.result }}' ] || [ 'closed' == '${{ github.event.action }}' ]; then + exit 0 + fi + exit 1 diff --git a/.github/workflows/generators.yml b/.github/workflows/generators.yml index 6b554890470f..3956b173f68a 100644 --- a/.github/workflows/generators.yml +++ b/.github/workflows/generators.yml @@ -33,7 +33,8 @@ on: - '*' permissions: contents: read - +env: + FORCE_COLOR: 2 jobs: generate-blueprint: permissions: @@ -43,16 +44,21 @@ jobs: permissions: contents: none uses: ./.github/workflows/generator-database-changelog-liquibase.yml + graalvm: + permissions: + contents: none + uses: ./.github/workflows/generator-graalvm.yml check-generators: permissions: contents: none runs-on: ubuntu-latest - needs: [generate-blueprint, database-changelog-liquibase] + needs: [generate-blueprint, database-changelog-liquibase, graalvm] if: always() steps: - run: | echo '${{ toJSON(needs) }}' if ([ 'skipped' == '${{ needs.generate-blueprint.result }}' ] || [ 'success' == '${{ needs.generate-blueprint.result }}' ]) && \ + ([ 'skipped' == '${{ needs.graalvm.result }}' ] || [ 'success' == '${{ needs.graalvm.result }}' ]) && \ ([ 'skipped' == '${{ needs.database-changelog-liquibase.result }}' ] || [ 'success' == '${{ needs.database-changelog-liquibase.result }}' ]); then exit 0 fi diff --git a/.github/workflows/issue-check.yml b/.github/workflows/issue-check.yml index cac664a235f7..e95380985239 100644 --- a/.github/workflows/issue-check.yml +++ b/.github/workflows/issue-check.yml @@ -29,6 +29,8 @@ on: type: number permissions: contents: read +env: + FORCE_COLOR: 2 jobs: comment: runs-on: ubuntu-latest diff --git a/.github/workflows/lock-maintenance.yml b/.github/workflows/lock-maintenance.yml index 96ea22ab3e44..51cfd851653c 100644 --- a/.github/workflows/lock-maintenance.yml +++ b/.github/workflows/lock-maintenance.yml @@ -47,7 +47,7 @@ jobs: git add . git commit -a -m "Bump transitional dependencies" || true - name: Create Pull Request - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GITHUB_TOKEN }} commit-message: 'Bump transitional dependencies' diff --git a/.github/workflows/react.yml b/.github/workflows/react.yml index 54ffedaeeb56..a2f44239ec66 100644 --- a/.github/workflows/react.yml +++ b/.github/workflows/react.yml @@ -35,6 +35,8 @@ on: types: [closed, opened, synchronize, reopened] branches: - '*' +env: + FORCE_COLOR: 2 jobs: build-matrix: runs-on: ubuntu-20.04 @@ -51,13 +53,11 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 2 - - name: 'Build matrix' - id: build - uses: ./.github/actions/build-matrix - with: - workflow-samples-file: react + - run: npm ci --ignore-scripts + - id: build + run: bin/jhipster.cjs github-build-matrix react --event-name ${{ github.event_name }} applications: - name: ${{ matrix.name }} (n${{ matrix.node }}/j${{ matrix.java }}) + name: ${{ matrix.job-name }} runs-on: ${{ matrix.os || 'ubuntu-20.04' }} needs: build-matrix defaults: @@ -74,12 +74,12 @@ jobs: !contains(github.event.pull_request.title, '[ci skip]') && github.event.action != 'closed' && !contains(github.event.pull_request.labels.*.name, 'pr: skip-ci') && - needs.build-matrix.outputs.workflow-react == 'true' + fromJson(needs.build-matrix.outputs.matrix).include[0] != null timeout-minutes: 50 strategy: fail-fast: false # Matrix available at https://github.com/jhipster/generator-jhipster/tree/main/test-integration/workflow-samples/ - matrix: ${{fromJson(needs.build-matrix.outputs.matrix)}} + matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} steps: #---------------------------------------------------------------------- # Install all tools and check configuration @@ -91,8 +91,8 @@ jobs: fetch-depth: 2 - uses: jhipster/actions/setup-runner@v0 with: - node-version: ${{ matrix.node }} - java-version: ${{ matrix.java }} + node-version: ${{ matrix.node-version }} + java-version: ${{ matrix.java-version }} npm-version: ${{ matrix.npm-version }} maven-cache: true gradle-cache: ${{ matrix.gradle-cache }} @@ -103,26 +103,28 @@ jobs: - run: npm ci --ignore-scripts working-directory: ${{ github.workspace }}/generator-jhipster - name: 'GENERATION: project' - run: jhipster.cjs generate-sample ${{ matrix.name }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight + run: jhipster.cjs generate-sample ${{ matrix.sample }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight env: JHI_FOLDER_APP: ${{ github.workspace }}/app JHIPSTER_DEPENDENCIES_VERSION: ${{ matrix.jhipster-bom-cicd-version }} + JHI_JWT_SECRET_KEY: ${{ matrix.jwt-secret-key }} - run: jhipster.cjs info #---------------------------------------------------------------------- # Detect changes against base commit #---------------------------------------------------------------------- - uses: jhipster/actions/compare-sample@v0 id: compare - with: - generator-path: generator-jhipster - cmd: jhipster.cjs generate-sample ${{ matrix.name }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight if: >- github.event.pull_request && !contains(github.event.pull_request.labels.*.name, 'pr: disable-compare') + with: + generator-path: generator-jhipster + cmd: jhipster.cjs generate-sample ${{ matrix.sample }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight env: # generate-sample uses JHI_FOLDER_APP to generate the application. JHI_FOLDER_APP: ${{ github.workspace }}/base/app JHIPSTER_DEPENDENCIES_VERSION: ${{ matrix.jhipster-bom-cicd-version }} + JHI_JWT_SECRET_KEY: ${{ matrix.jwt-secret-key }} #---------------------------------------------------------------------- # Launch tests #---------------------------------------------------------------------- @@ -132,22 +134,25 @@ jobs: jhipster-bom-ref: ${{ matrix.jhipster-bom-branch }} - name: 'TESTS: backend' id: backend - if: steps.compare.outputs.equals != 'true' && matrix.skip-backend-tests != 'true' && needs.build-matrix.outputs.server != 'false' + if: steps.compare.outputs.equals != 'true' && matrix.skip-backend-tests != 'true' run: npm run ci:backend:test continue-on-error: ${{matrix.continue-on-backend-tests-error || false}} timeout-minutes: 15 + # Run npm install for workspaces only, as it is done in packaging for non-workspaces - name: 'PREPARE: npm install' - if: steps.compare.outputs.equals != 'true' && matrix.skip-frontend-tests != 'true' && needs.build-matrix.outputs.client != 'false' - run: ${{ (matrix.workspaces == 'true' && 'npm') || './npmw' }} install + if: steps.compare.outputs.equals != 'true' && matrix.workspaces == 'true' + run: npm install timeout-minutes: 7 - - name: 'TESTS: frontend' - if: steps.compare.outputs.equals != 'true' && matrix.skip-frontend-tests != 'true' && needs.build-matrix.outputs.client != 'false' - run: npm run ci:frontend:test - timeout-minutes: 15 - name: 'TESTS: packaging' + id: packaging if: steps.compare.outputs.equals != 'true' run: npm run ci:e2e:package timeout-minutes: 12 + - name: 'TESTS: frontend' + id: frontend + if: steps.compare.outputs.equals != 'true' && matrix.skip-frontend-tests != 'true' + run: npm run ci:frontend:test + timeout-minutes: 15 - name: 'TESTS: Start docker compose containers for e2e tests' if: steps.compare.outputs.equals != 'true' run: npm run ci:e2e:prepare @@ -157,17 +162,32 @@ jobs: if: steps.compare.outputs.equals != 'true' run: npm run ci:e2e:run --if-present timeout-minutes: 15 + - name: Store the application + uses: actions/upload-artifact@v4 + if: always() && (steps.backend.outcome == 'failure' || steps.e2e.outcome == 'failure' || steps.frontend.outcome == 'failure' || steps.packaging.outcome == 'failure') + with: + name: app-${{ matrix.sample }} + include-hidden-files: true + path: | + ${{ github.workspace }}/app/**/* + !**/app/build/** + !**/app/*/build/** + !**/app/.gradle/** + !**/app/*/.gradle/** + !**/app/target/** + !**/app/*/target/** + !**/node_modules/** - name: 'BACKEND: Store failure logs' uses: actions/upload-artifact@v4 if: always() && steps.backend.outcome == 'failure' with: - name: log-${{ matrix.name }} + name: log-${{ matrix.sample }} path: ${{ github.workspace }}/app/**/test-results/**/*.xml - name: 'E2E: Store failure screenshots' uses: actions/upload-artifact@v4 if: always() && steps.e2e.outcome == 'failure' with: - name: screenshots-${{ matrix.name }} + name: screenshots-${{ matrix.sample }} path: ${{ github.workspace }}/app/**/cypress/screenshots - name: Dump docker logs if: always() diff --git a/.github/workflows/update-spring-boot-dependencies.yml b/.github/workflows/update-spring-boot-dependencies.yml index 18dfeac5cd2d..6b324054748e 100644 --- a/.github/workflows/update-spring-boot-dependencies.yml +++ b/.github/workflows/update-spring-boot-dependencies.yml @@ -58,7 +58,7 @@ jobs: git add . working-directory: generators/spring-boot/resources - name: Create Pull Request - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GITHUB_TOKEN }} branch: spring-boot/v${{ inputs.springBootVersion }} diff --git a/.github/workflows/vue.yml b/.github/workflows/vue.yml index 2ee0cf26a7ed..c329d1651fd3 100644 --- a/.github/workflows/vue.yml +++ b/.github/workflows/vue.yml @@ -35,6 +35,8 @@ on: types: [closed, opened, synchronize, reopened] branches: - '*' +env: + FORCE_COLOR: 2 jobs: build-matrix: runs-on: ubuntu-20.04 @@ -51,13 +53,11 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 2 - - name: 'Build matrix' - id: build - uses: ./.github/actions/build-matrix - with: - workflow-samples-file: vue + - run: npm ci --ignore-scripts + - id: build + run: bin/jhipster.cjs github-build-matrix vue --event-name ${{ github.event_name }} applications: - name: ${{ matrix.name }} (n${{ matrix.node }}/j${{ matrix.java }}) + name: ${{ matrix.job-name }} runs-on: ${{ matrix.os || 'ubuntu-20.04' }} needs: build-matrix defaults: @@ -74,12 +74,12 @@ jobs: !contains(github.event.pull_request.title, '[ci skip]') && github.event.action != 'closed' && !contains(github.event.pull_request.labels.*.name, 'pr: skip-ci') && - needs.build-matrix.outputs.workflow-vue == 'true' + fromJson(needs.build-matrix.outputs.matrix).include[0] != null timeout-minutes: 50 strategy: fail-fast: false # Matrix available at https://github.com/jhipster/generator-jhipster/tree/main/test-integration/workflow-samples/ - matrix: ${{fromJson(needs.build-matrix.outputs.matrix)}} + matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} steps: #---------------------------------------------------------------------- # Install all tools and check configuration @@ -91,8 +91,8 @@ jobs: fetch-depth: 2 - uses: jhipster/actions/setup-runner@v0 with: - node-version: ${{ matrix.node }} - java-version: ${{ matrix.java }} + node-version: ${{ matrix.node-version }} + java-version: ${{ matrix.java-version }} npm-version: ${{ matrix.npm-version }} maven-cache: true gradle-cache: ${{ matrix.gradle-cache }} @@ -103,10 +103,11 @@ jobs: - run: npm ci --ignore-scripts working-directory: ${{ github.workspace }}/generator-jhipster - name: 'GENERATION: project' - run: jhipster.cjs generate-sample ${{ matrix.name }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight + run: jhipster.cjs generate-sample ${{ matrix.sample }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight env: JHI_FOLDER_APP: ${{ github.workspace }}/app JHIPSTER_DEPENDENCIES_VERSION: ${{ matrix.jhipster-bom-cicd-version }} + JHI_JWT_SECRET_KEY: ${{ matrix.jwt-secret-key }} - run: jhipster.cjs info #---------------------------------------------------------------------- # Detect changes against base commit @@ -118,11 +119,12 @@ jobs: !contains(github.event.pull_request.labels.*.name, 'pr: disable-compare') with: generator-path: generator-jhipster - cmd: jhipster.cjs generate-sample ${{ matrix.name }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight + cmd: jhipster.cjs generate-sample ${{ matrix.sample }} --skip-jhipster-dependencies --skip-checks --skip-install --no-insight env: # generate-sample uses JHI_FOLDER_APP to generate the application. JHI_FOLDER_APP: ${{ github.workspace }}/base/app JHIPSTER_DEPENDENCIES_VERSION: ${{ matrix.jhipster-bom-cicd-version }} + JHI_JWT_SECRET_KEY: ${{ matrix.jwt-secret-key }} #---------------------------------------------------------------------- # Launch tests #---------------------------------------------------------------------- @@ -132,22 +134,25 @@ jobs: jhipster-bom-ref: ${{ matrix.jhipster-bom-branch }} - name: 'TESTS: backend' id: backend - if: steps.compare.outputs.equals != 'true' && matrix.skip-backend-tests != 'true' && needs.build-matrix.outputs.server != 'false' + if: steps.compare.outputs.equals != 'true' && matrix.skip-backend-tests != 'true' run: npm run ci:backend:test continue-on-error: ${{matrix.continue-on-backend-tests-error || false}} timeout-minutes: 15 + # Run npm install for workspaces only, as it is done in packaging for non-workspaces - name: 'PREPARE: npm install' - if: steps.compare.outputs.equals != 'true' && matrix.skip-frontend-tests != 'true' && needs.build-matrix.outputs.client != 'false' - run: ${{ (matrix.workspaces == 'true' && 'npm') || './npmw' }} install + if: steps.compare.outputs.equals != 'true' && matrix.workspaces == 'true' + run: npm install timeout-minutes: 7 - - name: 'TESTS: frontend' - if: steps.compare.outputs.equals != 'true' && matrix.skip-frontend-tests != 'true' && needs.build-matrix.outputs.client != 'false' - run: npm run ci:frontend:test - timeout-minutes: 15 - name: 'TESTS: packaging' + id: packaging if: steps.compare.outputs.equals != 'true' run: npm run ci:e2e:package timeout-minutes: 12 + - name: 'TESTS: frontend' + id: frontend + if: steps.compare.outputs.equals != 'true' && matrix.skip-frontend-tests != 'true' + run: npm run ci:frontend:test + timeout-minutes: 15 - name: 'TESTS: Start docker compose containers for e2e tests' if: steps.compare.outputs.equals != 'true' run: npm run ci:e2e:prepare @@ -157,17 +162,32 @@ jobs: if: steps.compare.outputs.equals != 'true' run: npm run ci:e2e:run --if-present timeout-minutes: 15 + - name: Store the application + uses: actions/upload-artifact@v4 + if: always() && (steps.backend.outcome == 'failure' || steps.e2e.outcome == 'failure' || steps.frontend.outcome == 'failure' || steps.packaging.outcome == 'failure') + with: + name: app-${{ matrix.sample }} + include-hidden-files: true + path: | + ${{ github.workspace }}/app/**/* + !**/app/build/** + !**/app/*/build/** + !**/app/.gradle/** + !**/app/*/.gradle/** + !**/app/target/** + !**/app/*/target/** + !**/node_modules/** - name: 'BACKEND: Store failure logs' uses: actions/upload-artifact@v4 if: always() && steps.backend.outcome == 'failure' with: - name: log-${{ matrix.name }} + name: log-${{ matrix.sample }} path: ${{ github.workspace }}/app/**/test-results/**/*.xml - name: 'E2E: Store failure screenshots' uses: actions/upload-artifact@v4 if: always() && steps.e2e.outcome == 'failure' with: - name: screenshots-${{ matrix.name }} + name: screenshots-${{ matrix.sample }} path: ${{ github.workspace }}/app/**/cypress/screenshots - name: Dump docker logs if: always() diff --git a/.gitignore b/.gitignore index 0b917877cf0f..a67233e2fba0 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,4 @@ build/ nbbuild/ nbdist/ .nb-gradle/ - +generators/**/package-lock.json diff --git a/.mocharc.cjs b/.mocharc.cjs index 3f0b845bbb01..a99e53918548 100644 --- a/.mocharc.cjs +++ b/.mocharc.cjs @@ -2,6 +2,7 @@ const Module = require('module'); const process = require('process'); if (!Module.register) { + // eslint-disable-next-line no-console console.log('JHipster test requires node >=18.19.0 || >= 20.6.0\n'); process.exit(1); } @@ -17,4 +18,5 @@ module.exports = { // `loader` options is passed to forks, but `require` is not. // Use node-option instead (it overrides loader option) parallel: true, + require: ['yeoman-test/mocha-cleanup'], }; diff --git a/.prettierignore b/.prettierignore index baa1ba926cf6..7ba4bb56ef47 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,3 +10,4 @@ jdl/**/.jhipster/** test/fixtures/** dist coverage +BadEntity.json diff --git a/Dockerfile b/Dockerfile index 17a3eb653b87..2eeca6cd6953 100644 --- a/Dockerfile +++ b/Dockerfile @@ -71,4 +71,4 @@ ENV PATH $PATH:/usr/bin WORKDIR "/home/jhipster/app" VOLUME ["/home/jhipster/app"] EXPOSE 8080 9000 3001 -CMD ["tail", "-f", "/home/jhipster/generator-jhipster/generators/server/templates/src/main/resources/banner-no-color.txt"] +CMD ["tail", "-f", "/home/jhipster/generator-jhipster/generators/spring-boot/templates/src/main/resources/banner-no-color.txt"] diff --git a/README.md b/README.md index 566401d59f87..128301bf0fb0 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Greetings, Java Hipster! -Full documentation and information is available on our website at [https://www.jhipster.tech/][jhipster-url] +Full documentation and information is available on our website at [https://www.jhipster.tech][jhipster-url]. Please read our [guidelines](/CONTRIBUTING.md#submitting-an-issue) before submitting an issue. If your issue is a bug, please use the bug template pre-populated [here][issue-template]. For feature requests and queries you can use [this template][feature-template]. If you have found a potential security issue, please read our security policy and contact us privately first: https://github.com/jhipster/generator-jhipster/security/policy @@ -18,9 +18,9 @@ We are honored by any contributions you may have small or large. Please refer to The following Java and Node combinations are tested and verified by GitHub Actions: -| Java | Node | Status | -| -------- | ----- | ------ | -| 17/21/22 | 18/20 | ✅ | +| Java | Node | Status | +| -------- | -------- | ------ | +| 17/21/23 | 18/20/22 | ✅ | ## Sponsors diff --git a/bin/cli.cjs b/bin/cli.cjs deleted file mode 100644 index 3a74d3a170ac..000000000000 --- a/bin/cli.cjs +++ /dev/null @@ -1,6 +0,0 @@ -// Cleanup loaders options, we don't want to pass to child processes. -delete process.env.NODE_OPTIONS; - -process.env.JHIPSTER_DEV_BLUEPRINT = true; - -require('../cli/jhipster.cjs'); diff --git a/bin/jhipster.cjs b/bin/jhipster.cjs index 7967728ea594..6b61635ac3ec 100755 --- a/bin/jhipster.cjs +++ b/bin/jhipster.cjs @@ -2,14 +2,14 @@ // Executable file that runs jhipster sources in JIT mode. // This file should be used for development purposes and should not be distributed in the npm package. // Executable should be written in commonjs https://github.com/nodejs/modules/issues/152. -const { join } = require('path'); +const { Module } = require('module'); +const { pathToFileURL } = require('url'); const [_nodeExec, _exec, ...args] = process.argv; // eslint-disable-next-line no-console console.error('jhipster', ...args); -(async () => { - // eslint-disable-next-line import/no-unresolved - const { default: esbuildx } = await import('@node-loaders/esbuildx'); - await esbuildx(join(__dirname, 'cli.cjs')); -})(); +process.env.JHIPSTER_DEV_BLUEPRINT = true; +Module.register(pathToFileURL(require.resolve('@node-loaders/esbuild/strict')).href); + +require('../cli/jhipster.cjs'); diff --git a/cli/cli-command.d.ts b/cli/cli-command.d.ts index 8e9ef338f808..8bd4864470d6 100644 --- a/cli/cli-command.d.ts +++ b/cli/cli-command.d.ts @@ -1,5 +1,5 @@ import type Environment from 'yeoman-environment'; -import EnvironmentBuilder from './environment-builder.mjs'; +import type EnvironmentBuilder from './environment-builder.mjs'; /** * @param args - positional arguments, a varidic argument is an array at last position. diff --git a/cli/cli-jdl.spec.ts b/cli/cli-jdl.spec.ts new file mode 100644 index 000000000000..8eefeabffb3f --- /dev/null +++ b/cli/cli-jdl.spec.ts @@ -0,0 +1,33 @@ +import { join } from 'path'; +import { execa } from 'execa'; +import { basicHelpers as helpers, runResult } from '../lib/testing/index.js'; +import { getPackageRoot } from '../lib/index.js'; + +const jhipsterCli = join(getPackageRoot(), 'bin/jhipster.cjs'); + +describe('allows customizing JDL definitions', () => { + it('accepts a custom JDL definition', async () => { + await helpers + .prepareTemporaryDir() + .withFiles({ + '.blueprint/app/index.mjs': `export const command = { + configs: { + fooConfig: { + jdl: { + type: 'boolean', + tokenType: 'BOOLEAN', + }, + scope: 'storage', + }, + }, +};`, + }) + .commitFiles(); + await execa(jhipsterCli, ['jdl', '--json-only', '--inline', 'application { config { fooConfig false } }'], { stdio: 'pipe' }); + runResult.assertJsonFileContent('.yo-rc.json', { + 'generator-jhipster': { + fooConfig: false, + }, + }); + }); +}); diff --git a/cli/cli.spec.mts b/cli/cli.spec.mts index e7e94858bae6..75ed978ed3ae 100644 --- a/cli/cli.spec.mts +++ b/cli/cli.spec.mts @@ -8,9 +8,8 @@ import { execaCommandSync } from 'execa'; import type { GeneratorMeta } from '@yeoman/types'; import type FullEnvironment from 'yeoman-environment'; import { coerce } from 'semver'; -import quibble from 'quibble'; -import { defaultHelpers as helpers, createBlueprintFiles } from '../testing/index.js'; +import { defaultHelpers as helpers, createBlueprintFiles } from '../lib/testing/index.js'; import { getCommand as actualGetCommonand } from './utils.mjs'; import { createProgram } from './program.mjs'; @@ -90,23 +89,22 @@ const cliSharedBlueprintFiles = { describe('cli', () => { const __filename = fileURLToPath(import.meta.url); const jhipsterCli = join(dirname(__filename), '..', 'bin', 'jhipster.cjs'); - const logger = { verboseInfo: esmocha.fn(), fatal: esmocha.fn(), debug: esmocha.fn() }; + const logger = { verboseInfo: esmocha.fn(), warn: esmocha.fn(), fatal: esmocha.fn(), debug: esmocha.fn() }; const getCommand = esmocha.fn(); let mockCli; let argv; before(async () => { - await quibble.esm('./utils.mjs', { logger, getCommand, CLI_NAME: 'jhipster', done: () => {} }); + await esmocha.mock('./utils.mjs', { logger, getCommand, CLI_NAME: 'jhipster', done: () => {} } as any); const { buildJHipster } = await import('./program.mjs'); mockCli = async (argv: string[], opts = {}) => { - // @ts-expect-error const program = await buildJHipster({ printLogo: () => {}, ...opts, program: createProgram(), loadCommand: key => opts[`./${key}`] }); return program.parseAsync(argv); }; }); after(() => { - quibble.reset(); + esmocha.reset(); }); beforeEach(async () => { diff --git a/cli/commands.mjs b/cli/commands.mts similarity index 98% rename from cli/commands.mjs rename to cli/commands.mts index cef9b9bd3a7d..2ac329244bd3 100644 --- a/cli/commands.mjs +++ b/cli/commands.mts @@ -17,6 +17,7 @@ * limitations under the License. */ import chalk from 'chalk'; +import { CliCommand } from './types.js'; const removedV8 = chalk.yellow(` @@ -165,6 +166,6 @@ const defaultCommands = { workspaces: { desc: 'Add workspaces configuration', }, -}; +} as const satisfies Record; export default defaultCommands; diff --git a/cli/environment-builder.mjs b/cli/environment-builder.mjs index 333fa64b1dec..dc561cb80131 100644 --- a/cli/environment-builder.mjs +++ b/cli/environment-builder.mjs @@ -17,7 +17,7 @@ * limitations under the License. */ import assert from 'assert'; -import { existsSync, readFileSync } from 'fs'; +import { existsSync } from 'fs'; import path, { dirname, resolve } from 'path'; import { fileURLToPath, pathToFileURL } from 'url'; import chalk from 'chalk'; @@ -26,7 +26,8 @@ import Environment from 'yeoman-environment'; import { QueuedAdapter } from '@yeoman/adapter'; import { createJHipsterLogger, packageNameToNamespace } from '../generators/base/support/index.js'; -import { parseBlueprintInfo, loadBlueprintsFromConfiguration, mergeBlueprints } from '../generators/base/internal/index.js'; +import { loadBlueprintsFromConfiguration, mergeBlueprints, parseBlueprintInfo } from '../generators/base/internal/index.js'; +import { readCurrentPathYoRcFile } from '../lib/utils/yo-rc.js'; import { CLI_NAME, logger } from './utils.mjs'; const __filename = fileURLToPath(import.meta.url); @@ -40,19 +41,14 @@ const defaultLookupOptions = { customizeNamespace: ns => ns?.replaceAll(':generators:', ':'), }; -function loadYoRc(filePath = '.yo-rc.json') { - if (!existsSync(filePath)) { - return undefined; - } - return JSON.parse(readFileSync(filePath, { encoding: 'utf-8' })); -} - const createEnvironment = (options = {}) => { options.adapter = options.adapter ?? new QueuedAdapter({ log: createJHipsterLogger() }); return new Environment({ newErrorHandler: true, ...options }); }; export default class EnvironmentBuilder { + /** @type {Environment} */ + env; devBlueprintPath; localBlueprintPath; localBlueprintExists; @@ -79,7 +75,7 @@ export default class EnvironmentBuilder { * const promise = require('yeoman-test').create('jhipster:app', {}, {createEnv: EnvironmentBuilder.createEnv}).run(); * * @param {...any} args - Arguments passed to Environment.createEnv(). - * @return {EnvironmentBuilder} envBuilder + * @return {Promise} envBuilder */ static async createEnv(...args) { const builder = await EnvironmentBuilder.createDefaultBuilder(...args); @@ -282,7 +278,7 @@ export default class EnvironmentBuilder { /** * Get blueprints commands. * - * @return {Object[]} blueprint commands. + * @return {Record} blueprint commands. */ async getBlueprintCommands() { let blueprintsPackagePath = await this._getBlueprintPackagePaths(); @@ -333,8 +329,8 @@ export default class EnvironmentBuilder { * @returns {Blueprint[]} */ _getBlueprintsFromYoRc() { - const yoRc = loadYoRc(); - if (!yoRc || !yoRc['generator-jhipster']) { + const yoRc = readCurrentPathYoRcFile(); + if (!yoRc?.['generator-jhipster']) { return []; } return loadBlueprintsFromConfiguration(yoRc['generator-jhipster']); @@ -396,7 +392,7 @@ export default class EnvironmentBuilder { * @private * Get blueprints commands. * - * @return {Object[]} commands. + * @return {Record} commands. */ async _getBlueprintCommands(blueprintPackagePaths) { if (!blueprintPackagePaths) { @@ -404,11 +400,11 @@ export default class EnvironmentBuilder { } let result; for (const [blueprint, packagePath] of blueprintPackagePaths) { - /* eslint-disable import/no-dynamic-require */ - /* eslint-disable global-require */ let blueprintCommand; const blueprintCommandFile = `${packagePath}/cli/commands`; - const blueprintCommandExtension = ['.js', '.cjs', '.mjs'].find(extension => existsSync(`${blueprintCommandFile}${extension}`)); + const blueprintCommandExtension = ['.js', '.cjs', '.mjs', '.ts', '.cts', '.mts'].find(extension => + existsSync(`${blueprintCommandFile}${extension}`), + ); if (blueprintCommandExtension) { const blueprintCommandsUrl = pathToFileURL(resolve(`${blueprintCommandFile}${blueprintCommandExtension}`)); try { @@ -418,7 +414,7 @@ export default class EnvironmentBuilder { commandSpec.blueprint = commandSpec.blueprint || blueprint; }); result = { ...result, ...blueprintCommands }; - } catch (e) { + } catch { const msg = `Error parsing custom commands found within blueprint: ${blueprint} at ${blueprintCommandsUrl}`; /* eslint-disable no-console */ console.info(`${chalk.green.bold('INFO!')} ${msg}`); @@ -456,8 +452,6 @@ export default class EnvironmentBuilder { } async function loadSharedOptionsFromFile(sharedOptionsBase, msg, errorMsg) { - /* eslint-disable import/no-dynamic-require */ - /* eslint-disable global-require */ try { const baseExtension = ['.js', '.cjs', '.mjs'].find(extension => existsSync(resolve(`${sharedOptionsBase}${extension}`))); if (baseExtension) { diff --git a/cli/environment-builder.spec.mts b/cli/environment-builder.spec.mts index 3540d81b31b0..b7d701a54e4f 100644 --- a/cli/environment-builder.spec.mts +++ b/cli/environment-builder.spec.mts @@ -22,7 +22,7 @@ import fs from 'fs'; import { expect } from 'chai'; import sinon from 'sinon'; import { before, it, describe, after, expect as jestExpect, beforeEach } from 'esmocha'; -import { defaultHelpers as helpers, createBlueprintFiles } from '../testing/index.js'; +import { defaultHelpers as helpers, createBlueprintFiles } from '../lib/testing/index.js'; import EnvironmentBuilder from './environment-builder.mjs'; diff --git a/cli/jhipster-command.mjs b/cli/jhipster-command.mjs index 980c638e35ca..54976d427fa6 100644 --- a/cli/jhipster-command.mjs +++ b/cli/jhipster-command.mjs @@ -18,11 +18,14 @@ */ import chalk from 'chalk'; -import { Command, Option } from 'commander'; +import { Argument, Command, Option } from 'commander'; import { kebabCase } from 'lodash-es'; -import { convertConfigToOption } from '../lib/internal/index.js'; +import { convertConfigToOption } from '../lib/command/index.js'; export default class JHipsterCommand extends Command { + configs = {}; + blueprintConfigs = {}; + createCommand(name) { return new JHipsterCommand(name); } @@ -150,7 +153,7 @@ export default class JHipsterCommand extends Command { /** * Register options using generator._options structure. * @param {object} options - * @param {string} blueprintOptionDescription - description of the blueprint that adds the option + * @param {string} [blueprintOptionDescription] - description of the blueprint that adds the option * @return {JHipsterCommand} this; */ addGeneratorOptions(options, blueprintOptionDescription) { @@ -164,7 +167,11 @@ export default class JHipsterCommand extends Command { Object.entries(jhipsterArguments ?? {}).forEach(([key, value]) => { let argName = value.type === Array ? `${key}...` : key; argName = value.required ? `<${argName}>` : `[${argName}]`; - this.argument(argName, value.description); + const argument = new Argument(argName, value.description); + if (value.choices) { + argument.choices(value.choices.map(choice => (typeof choice === 'string' ? choice : choice.value))); + } + this.addArgument(argument); }); return this; } @@ -177,12 +184,15 @@ export default class JHipsterCommand extends Command { } addJHipsterConfigs(configs = {}, blueprintOptionDescription) { - Object.entries(configs).forEach(([name, config]) => { - const option = convertConfigToOption(name, config); - if (option) { - this._addGeneratorOption(kebabCase(option.name), option, blueprintOptionDescription); - } - }); + Object.assign(blueprintOptionDescription ? this.blueprintConfigs : this.configs, configs); + Object.entries(configs) + .filter(([_name, config]) => config.cli) + .forEach(([name, config]) => { + const option = convertConfigToOption(name, config); + if (option) { + this._addGeneratorOption(kebabCase(option.name), option, blueprintOptionDescription); + } + }); return this; } @@ -221,6 +231,9 @@ export default class JHipsterCommand extends Command { if (optionDefinition.choices && optionDefinition.choices.length > 0) { option.choices(optionDefinition.choices); } + if (optionDefinition.implies) { + option.implies(optionDefinition.implies); + } return this.addOption(option); } } diff --git a/cli/program.mjs b/cli/program.mts similarity index 72% rename from cli/program.mjs rename to cli/program.mts index a29612a056bc..cf90ecc7efc3 100644 --- a/cli/program.mjs +++ b/cli/program.mts @@ -1,5 +1,3 @@ -/* eslint-disable global-require */ -/* eslint-disable import/no-dynamic-require */ /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -24,17 +22,21 @@ import path, { dirname } from 'path'; import { fileURLToPath } from 'url'; import didYouMean from 'didyoumean'; import chalk from 'chalk'; +import type Environment from 'yeoman-environment'; +import type { BaseEnvironmentOptions, GeneratorMeta } from '@yeoman/types'; import { packageJson } from '../lib/index.js'; import { packageNameToNamespace } from '../generators/base/support/index.js'; -import command from '../generators/base/command.js'; +import baseCommand from '../generators/base/command.js'; import { GENERATOR_APP, GENERATOR_BOOTSTRAP, GENERATOR_JDL } from '../generators/generator-list.js'; -import { extractArgumentsFromConfigs } from '../generators/base/internal/command.js'; +import { extractArgumentsFromConfigs, JHipsterCommandDefinition } from '../lib/command/index.js'; +import { buildJDLApplicationConfig } from '../lib/command/jdl.js'; import logo from './logo.mjs'; import EnvironmentBuilder from './environment-builder.mjs'; import SUB_GENERATORS from './commands.mjs'; import JHipsterCommand from './jhipster-command.mjs'; -import { CLI_NAME, logger, getCommand, done } from './utils.mjs'; +import { CLI_NAME, done, getCommand, logger } from './utils.mjs'; +import type { CliCommand } from './types.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -44,6 +46,33 @@ const JHIPSTER_NS = CLI_NAME; const moreInfo = `\n For more info visit ${chalk.blue('https://www.jhipster.tech')}\n`; +type BuildCommands = { + program: JHipsterCommand; + commands?: Record; + envBuilder?: EnvironmentBuilder; + env: Environment; + loadCommand?: (key: string) => Promise<(...args: any[]) => Promise>; + defaultCommand?: string; + entrypointGenerator?: string; + silent?: boolean; + printLogo?: () => void | Promise; + printBlueprintLogo?: () => void | Promise; + createEnvBuilder: (options?: BaseEnvironmentOptions) => Promise; +}; + +type BuildJHipsterOptions = Partial & { + executableName?: string; + executableVersion?: string; + blueprints?: Record; + lookups?: any[]; + devBlueprintPath?: string; +}; + +type JHipsterModule = { + command?: JHipsterCommandDefinition; + default: any; +}; + export const printJHipsterLogo = () => { // eslint-disable-next-line no-console console.log(); @@ -51,18 +80,29 @@ export const printJHipsterLogo = () => { console.log(logo); }; -const buildAllDependencies = async (generatorNames, { env, blueprintNamespaces }) => { +const buildAllDependencies = async ( + generatorNames: string[], + { env, blueprintNamespaces = [] }: { env: Environment; blueprintNamespaces?: string[] }, +): Promise> => { const allDependencies = {}; - const registerDependency = async ({ namespace, blueprintNamespace }) => { + const registerDependency = async ({ + namespace, + blueprintNamespace, + }: { + namespace: string; + blueprintNamespace?: string; + }): Promise => { const meta = await env.getGeneratorMeta(namespace.includes(':') ? namespace : `${JHIPSTER_NS}:${namespace}`); if (meta) { allDependencies[namespace] = { meta, blueprintNamespace }; + } else if (!blueprintNamespace) { + logger.warn(`Generator ${namespace} not found.`); } - return meta?.importModule(); + return (await meta?.importModule?.()) as JHipsterModule; }; - const lookupDependencyOptions = async ({ namespace, blueprintNamespace }) => { + const lookupDependencyOptions = async ({ namespace, blueprintNamespace }: { namespace: string; blueprintNamespace?: string }) => { const lookupGeneratorAndImports = async ({ namespace, blueprintNamespace }) => { const module = await registerDependency({ namespace, blueprintNamespace }); if (module?.command?.import) { @@ -96,7 +136,11 @@ const buildAllDependencies = async (generatorNames, { env, blueprintNamespaces } return allDependencies; }; -const addCommandGeneratorOptions = async (command, generatorMeta, { root, blueprintOptionDescription, info } = {}) => { +const addCommandGeneratorOptions = async ( + command: JHipsterCommand, + generatorMeta, + { root, blueprintOptionDescription, info }: { root?: boolean; blueprintOptionDescription?: string; info?: string } = {}, +) => { const generatorModule = await generatorMeta.importModule(); if (generatorModule.command) { const { options, configs } = generatorModule.command; @@ -108,7 +152,10 @@ const addCommandGeneratorOptions = async (command, generatorMeta, { root, bluepr } } try { - if (root || !generatorModule.command || generatorModule.command.loadGeneratorOptions) { + if ( + generatorModule.command?.loadGeneratorOptions !== false && + (root || !generatorModule.command || generatorModule.command.loadGeneratorOptions) + ) { const generator = await generatorMeta.instantiateHelp(); // Add basic yeoman generator options command.addGeneratorOptions(generator._options, blueprintOptionDescription); @@ -137,7 +184,10 @@ const addCommandRootGeneratorOptions = async (command, generatorMeta, { usage = } }; -export const createProgram = ({ executableName = CLI_NAME, executableVersion } = {}) => { +export const createProgram = ({ + executableName = CLI_NAME, + executableVersion, +}: { executableName?: string; executableVersion?: string } = {}) => { return ( new JHipsterCommand() .name(executableName) @@ -159,8 +209,9 @@ export const createProgram = ({ executableName = CLI_NAME, executableVersion } = .option('--install-path', 'Show jhipster install path', false) .option('--skip-regenerate', "Don't regenerate identical files", false) .option('--skip-yo-resolve', 'Ignore .yo-resolve files', false) - .addJHipsterOptions(command.options) - .addJHipsterConfigs(command.configs) + .addJHipsterOptions(baseCommand.options) + // @ts-expect-error configs is not defined, but can be added later + .addJHipsterConfigs(baseCommand.configs) ); }; @@ -185,37 +236,47 @@ const rejectExtraArgs = ({ program, command, extraArgs }) => { logger.fatal(message); }; -export const buildCommands = async ({ +export const buildCommands = ({ program, commands = {}, envBuilder, env, - loadCommand, + loadCommand = async key => { + const { default: command } = await import(`./${key}.mjs`); + return command; + }, defaultCommand = GENERATOR_APP, entrypointGenerator, printLogo = printJHipsterLogo, printBlueprintLogo = () => {}, createEnvBuilder, -}) => { + silent, +}: BuildCommands) => { /* create commands */ Object.entries(commands).forEach(([cmdName, opts]) => { const { desc, blueprint, argument, options: commandOptions, alias, help: commandHelp, cliOnly, removed, useOptions = {} } = opts; program .command(cmdName, '', { isDefault: cmdName === defaultCommand, hidden: Boolean(removed) }) .description(desc + (blueprint ? chalk.yellow(` (blueprint: ${blueprint})`) : '')) - .addCommandArguments(argument) + .addCommandArguments(argument!) .addCommandOptions(commandOptions) - .addHelpText('after', commandHelp) - .addAlias(alias) - .excessArgumentsCallback(function (receivedArgs) { + .addHelpText('after', commandHelp!) + .addAlias(alias!) + .excessArgumentsCallback(function (this, receivedArgs) { rejectExtraArgs({ program, command: this, extraArgs: receivedArgs }); }) - .lazyBuildCommand(async function (operands) { + .lazyBuildCommand(async function (this, operands) { logger.debug(`cmd: lazyBuildCommand ${cmdName} ${operands}`); if (removed) { logger.fatal(removed); return; } + + if (!silent) { + await printLogo(); + await printBlueprintLogo(); + } + const command = this; if (cmdName === 'run') { @@ -224,7 +285,7 @@ export const buildCommands = async ({ command.generatorNamespaces = operands.map( namespace => `${namespace.startsWith(JHIPSTER_NS) ? '' : `${JHIPSTER_NS}-`}${namespace}`, ); - await envBuilder.lookupGenerators(command.generatorNamespaces.map(namespace => `generator-${namespace.split(':')[0]}`)); + await envBuilder?.lookupGenerators(command.generatorNamespaces.map(namespace => `generator-${namespace.split(':')[0]}`)); await Promise.all( command.generatorNamespaces.map(async namespace => { const generatorMeta = env.getGeneratorMeta(namespace.includes(':') ? namespace : `${JHIPSTER_NS}:${namespace}`); @@ -256,7 +317,7 @@ export const buildCommands = async ({ } const allDependencies = await buildAllDependencies(boostrapGen, { env, - blueprintNamespaces: envBuilder.getBlueprintsNamespaces(), + blueprintNamespaces: envBuilder?.getBlueprintsNamespaces(), }); for (const [metaName, { meta: generatorMeta, blueprintNamespace }] of Object.entries(allDependencies)) { if (blueprintNamespace) { @@ -278,14 +339,18 @@ export const buildCommands = async ({ const command = everything.pop(); const cmdOptions = everything.pop(); const args = everything; + const commandsConfigs = Object.freeze({ ...command.configs, ...command.blueprintConfigs }); + const jdlDefinition = buildJDLApplicationConfig(commandsConfigs); const options = { ...program.opts(), ...cmdOptions, ...useOptions, commandName: cmdName, entrypointGenerator, - blueprints: envBuilder.getBlueprintsOption(), + blueprints: envBuilder?.getBlueprintsOption(), positionalArguments: args, + jdlDefinition, + commandsConfigs, }; if (options.installPath) { // eslint-disable-next-line no-console @@ -293,9 +358,6 @@ export const buildCommands = async ({ return Promise.resolve(); } - printLogo(); - printBlueprintLogo(); - if (cliOnly) { logger.debug('Executing CLI only script'); const cliOnlyCommand = await loadCommand(cmdName); @@ -306,8 +368,8 @@ export const buildCommands = async ({ if (cmdName === 'run') { return Promise.all(command.generatorNamespaces.map(generator => env.run(generator, options))).then( - results => done(results.find(result => result)), - errors => done(errors.find(error => error)), + results => silent || done(results.find(result => result)), + errors => silent || done(errors.find(error => error)), ); } if (cmdName === 'upgrade') { @@ -315,8 +377,12 @@ export const buildCommands = async ({ options.createEnvBuilder = createEnvBuilder; } const namespace = blueprint ? `${packageNameToNamespace(blueprint)}:${cmdName}` : `${JHIPSTER_NS}:${cmdName}`; - const generatorCommand = getCommand(namespace, args, opts); - return env.run(generatorCommand, options).then(done, done); + const generatorCommand = getCommand(namespace, args); + const promise = env.run(generatorCommand as any, options); + if (silent) { + return promise; + } + return promise.then(done, done); }); }); }; @@ -330,44 +396,35 @@ export const buildJHipster = async ({ createEnvBuilder, envBuilder, commands, - printLogo, - printBlueprintLogo, devBlueprintPath, env, - /* eslint-disable-next-line global-require, import/no-dynamic-require */ - loadCommand = async key => { - const { default: command } = await import(`./${key}.mjs`); - return command; - }, - defaultCommand, - entrypointGenerator, -} = {}) => { - // eslint-disable-next-line chai-friendly/no-unused-expressions + ...buildOptions +}: BuildJHipsterOptions = {}) => { createEnvBuilder = createEnvBuilder ?? (async options => EnvironmentBuilder.create(options).prepare({ blueprints, lookups, devBlueprintPath })); - envBuilder = envBuilder ?? (await createEnvBuilder()); - env = env ?? envBuilder.getEnvironment(); - commands = commands ?? { ...SUB_GENERATORS, ...(await envBuilder.getBlueprintCommands()) }; + if (!env) { + envBuilder = envBuilder ?? (await createEnvBuilder()); + env = env ?? envBuilder.getEnvironment(); + commands = { ...SUB_GENERATORS, ...(await envBuilder.getBlueprintCommands()), ...commands }; + } else { + commands = { ...SUB_GENERATORS, ...commands }; + } - await buildCommands({ + buildCommands({ + ...buildOptions, program, commands, envBuilder, env, - loadCommand, - defaultCommand, - entrypointGenerator, - printLogo, - printBlueprintLogo, createEnvBuilder, }); return program; }; -export const runJHipster = async (args = {}) => { - const { argv = process.argv } = args; - const jhipsterProgram = await buildJHipster(args); +export const runJHipster = async (args: { argv?: string[] } & BuildJHipsterOptions = {}) => { + const { argv = process.argv, ...buildJHipsterOptions } = args; + const jhipsterProgram = await buildJHipster(buildJHipsterOptions); return jhipsterProgram.parseAsync(argv); }; diff --git a/cli/program.spec.mts b/cli/program.spec.mts index b43444feb536..06a835380865 100644 --- a/cli/program.spec.mts +++ b/cli/program.spec.mts @@ -1,9 +1,8 @@ /* eslint-disable no-unused-expressions, no-console */ -import { expect } from 'chai'; -import { describe, it, beforeEach } from 'esmocha'; +import { describe, expect, it, beforeEach } from 'esmocha'; -import { defaultHelpers as helpers } from '../testing/index.js'; +import { defaultHelpers as helpers } from '../lib/testing/index.js'; import { createProgram } from './program.mjs'; describe('cli - program', () => { @@ -12,68 +11,32 @@ describe('cli - program', () => { }); describe('adding a negative option', () => { - it('when executing should not set insight', () => { - return createProgram() - .exitOverride(error => { - throw error; - }) - .parseAsync(['jhipster', 'jhipster']) - .then(command => { - expect(command.opts().insight).to.be.undefined; - }); + it('when executing should not set insight', async () => { + const command = await createProgram().parseAsync(['jhipster', 'jhipster']); + expect(command.opts().insight).toBeUndefined(); }); - it('when executing with --insight should set insight to true', () => { - return createProgram() - .exitOverride(error => { - throw error; - }) - .parseAsync(['jhipster', 'jhipster', '--insight']) - .then(command => { - expect(command.opts().insight).to.be.true; - }); + it('when executing with --insight should set insight to true', async () => { + const command = await createProgram().parseAsync(['jhipster', 'jhipster', '--insight']); + expect(command.opts().insight).toBe(true); }); - it('when executing with --no-insight should set insight to true', () => { - return createProgram() - .exitOverride(error => { - throw error; - }) - .parseAsync(['jhipster', 'jhipster', '--no-insight']) - .then(command => { - expect(command.opts().insight).to.be.false; - }); + it('when executing with --no-insight should set insight to true', async () => { + const command = await createProgram().parseAsync(['jhipster', 'jhipster', '--no-insight']); + expect(command.opts().insight).toBe(false); }); }); describe('adding a option with default value', () => { - it('when executing should not set insight', () => { - return createProgram() - .exitOverride(error => { - throw error; - }) - .parseAsync(['jhipster', 'jhipster']) - .then(command => { - expect(command.opts().skipYoResolve).to.be.false; - }); + it('when executing should not set insight', async () => { + const command = await createProgram().parseAsync(['jhipster', 'jhipster']); + expect(command.opts().skipYoResolve).toBe(false); }); - it('when executing with --skip-yo-resolve should set insight to true', () => { - return createProgram() - .exitOverride(error => { - throw error; - }) - .parseAsync(['jhipster', 'jhipster', '--skip-yo-resolve']) - .then(command => { - expect(command.opts().skipYoResolve).to.be.true; - }); + it('when executing with --skip-yo-resolve should set insight to true', async () => { + const command = await createProgram().parseAsync(['jhipster', 'jhipster', '--skip-yo-resolve']); + expect(command.opts().skipYoResolve).toBe(true); }); - it('when executing with --no-skip-yo-resolve should set insight to false', () => { - return createProgram() - .exitOverride(error => { - throw error; - }) - .parseAsync(['jhipster', 'jhipster', '--no-skip-yo-resolve']) - .then(command => { - expect(command.opts().skipYoResolve).to.be.false; - }); + it('when executing with --no-skip-yo-resolve should set insight to false', async () => { + const command = await createProgram().parseAsync(['jhipster', 'jhipster', '--no-skip-yo-resolve']); + expect(command.opts().skipYoResolve).toBe(false); }); }); }); diff --git a/generators/app/jdl/application-options.ts b/cli/types.d.ts similarity index 77% rename from generators/app/jdl/application-options.ts rename to cli/types.d.ts index 295ff8fab321..a6683979c639 100644 --- a/generators/app/jdl/application-options.ts +++ b/cli/types.d.ts @@ -16,4 +16,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { default } from '../../server/jdl/index.js'; +export type CliCommand = { + desc: string; + blueprint?: string; + argument?: string[]; + options?: any[]; + alias?: string; + help?: string; + cliOnly?: boolean; + removed?: string; + useOptions?: Record; +}; diff --git a/cli/utils.mjs b/cli/utils.mjs index 4805f5d837f4..feea1d91d146 100644 --- a/cli/utils.mjs +++ b/cli/utils.mjs @@ -16,10 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable no-console */ + import chalk from 'chalk'; -import { createJHipsterLogger, CLI_LOGGER } from '../generators/base/support/index.js'; +import { CLI_LOGGER, createJHipsterLogger } from '../lib/utils/logger.js'; export const CLI_NAME = 'jhipster'; export const GENERATOR_NAME = 'generator-jhipster'; @@ -44,31 +44,21 @@ export const getCommand = (cmd, args = []) => { return `${cmd}${cmdArgs ? ` ${cmdArgs}` : ''}`; }; -export const doneFactory = (successMsg, sponsorMsg) => { +export const doneFactory = (options = {}) => { + const { successMsg = SUCCESS_MESSAGE, sponsorMsg = SPONSOR_MESSAGE, logger: log = logger } = options; return errorOrMsg => { if (errorOrMsg instanceof Error) { - logger.error(`ERROR! ${errorOrMsg.message}`); - logger.log(errorOrMsg); + log.error(`ERROR! ${errorOrMsg.message}`); + log.log(errorOrMsg); } else if (errorOrMsg) { - logger.error(`ERROR! ${errorOrMsg}`); + log.error(`ERROR! ${errorOrMsg}`); } else if (successMsg) { - logger.log(''); - logger.log(chalk.green.bold(successMsg)); - logger.log(''); - logger.log(chalk.cyan.bold(sponsorMsg)); + log.log(''); + log.log(chalk.green.bold(successMsg)); + log.log(''); + log.log(chalk.cyan.bold(sponsorMsg)); } }; }; -export const printSuccess = () => { - if (process.exitCode === undefined || process.exitCode === 0) { - logger.log(''); - logger.log(chalk.green.bold(SUCCESS_MESSAGE)); - logger.log(''); - logger.log(chalk.cyan.bold(SPONSOR_MESSAGE)); - } else { - logger.error(`JHipster finished with code ${process.exitCode}`); - } -}; - -export const done = doneFactory(SUCCESS_MESSAGE, SPONSOR_MESSAGE); +export const done = doneFactory(); diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000000..906b9c489982 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,108 @@ +import globals from 'globals'; +import js from '@eslint/js'; +import ts from 'typescript-eslint'; +import prettier from 'eslint-plugin-prettier/recommended'; +import chai from 'eslint-plugin-chai-friendly'; +import imports from 'eslint-plugin-import-x'; +import jhipster from './lib/eslint/index.js'; + +export default ts.config( + { + languageOptions: { + ecmaVersion: 2022, + sourceType: 'module', + globals: { + ...globals.node, + }, + }, + }, + { ignores: ['dist'] }, + js.configs.recommended, + jhipster.base, + { + files: ['**/*.ts'], + extends: [...ts.configs.recommended, ...ts.configs.stylistic], + languageOptions: { + parserOptions: { + project: ['./tsconfig.spec.json'], + }, + }, + rules: { + '@typescript-eslint/consistent-type-imports': 'error', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/ban-ts-comment': ['off', { 'ts-nocheck': true }], + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/prefer-for-of': 'off', + '@typescript-eslint/no-this-alias': 'off', + }, + }, + { + files: ['**/*.spec.ts'], + rules: { + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/no-unused-expressions': 'off', + }, + }, + { + extends: [imports.flatConfigs.recommended, imports.flatConfigs.typescript], + languageOptions: { + // import plugin does not use ecmaVersion and sourceType from languageOptions object + parserOptions: { + ecmaVersion: 2022, + sourceType: 'module', + }, + }, + settings: { + 'import-x/resolver': { + typescript: true, + }, + }, + rules: { + 'import-x/no-named-as-default-member': 'off', + 'import-x/namespace': 'off', + // import-x is not resolving some modules + 'import-x/no-unresolved': ['error', { ignore: ['yeoman-environment', 'yeoman-generator'] }], + }, + }, + { + files: ['bin/**/*', '**/*.spec.ts', 'testing/**/*', 'test/**/*'], + rules: { + 'import-x/no-unresolved': 'off', + }, + }, + { + rules: { + eqeqeq: ['error', 'smart'], + 'no-use-before-define': ['error', 'nofunc'], + 'no-multi-str': 'error', + 'no-irregular-whitespace': 'error', + 'no-console': 'error', + 'no-template-curly-in-string': 'error', + 'no-nested-ternary': 'error', + 'no-restricted-syntax': [ + 'error', + { + selector: 'ForInStatement', + message: + 'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.', + }, + { + selector: 'LabeledStatement', + message: 'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.', + }, + { + selector: 'WithStatement', + message: '`with` is disallowed in strict mode because it makes code impossible to predict and optimize.', + }, + ], + }, + }, + { + ...chai.configs.recommendedFlat, + files: ['jdl/**/*.spec.{js,ts}'], + }, + prettier, +); diff --git a/generators/angular/__snapshots__/generator.spec.ts.snap b/generators/angular/__snapshots__/generator.spec.ts.snap index bd1f351ff540..6ccf39207182 100644 --- a/generators/angular/__snapshots__/generator.spec.ts.snap +++ b/generators/angular/__snapshots__/generator.spec.ts.snap @@ -17,13 +17,10 @@ exports[`generator - angular gateway-jwt-skipUserManagement(true)-withAdminUi(fa ".yo-rc.json": { "stateCleared": "modified", }, - "clientRoot/.eslintignore": { + "clientRoot/angular.json": { "stateCleared": "modified", }, - "clientRoot/.eslintrc.json": { - "stateCleared": "modified", - }, - "clientRoot/angular.json": { + "clientRoot/eslint.config.mjs": { "stateCleared": "modified", }, "clientRoot/jest.conf.js": { @@ -700,13 +697,10 @@ exports[`generator - angular gateway-oauth2-withAdminUi(true)-skipJhipsterDepend ".yo-rc.json": { "stateCleared": "modified", }, - "clientRoot/.eslintignore": { - "stateCleared": "modified", - }, - "clientRoot/.eslintrc.json": { + "clientRoot/angular.json": { "stateCleared": "modified", }, - "clientRoot/angular.json": { + "clientRoot/eslint.config.mjs": { "stateCleared": "modified", }, "clientRoot/jest.conf.js": { @@ -1605,13 +1599,10 @@ exports[`generator - angular microservice-jwt-skipUserManagement(false)-withAdmi ".yo-rc.json": { "stateCleared": "modified", }, - "clientRoot/.eslintignore": { - "stateCleared": "modified", - }, - "clientRoot/.eslintrc.json": { + "clientRoot/angular.json": { "stateCleared": "modified", }, - "clientRoot/angular.json": { + "clientRoot/eslint.config.mjs": { "stateCleared": "modified", }, "clientRoot/jest.conf.js": { @@ -2252,12 +2243,6 @@ exports[`generator - angular microservice-jwt-skipUserManagement(false)-withAdmi exports[`generator - angular microservice-oauth2-withAdminUi(true)-skipJhipsterDependencies(true)-enableTranslation(true)--websocket(false) should match generated files snapshot 1`] = ` { - ".eslintignore": { - "stateCleared": "modified", - }, - ".eslintrc.json": { - "stateCleared": "modified", - }, ".jhipster/EntityWithCustomId.json": { "stateCleared": "modified", }, @@ -2276,6 +2261,9 @@ exports[`generator - angular microservice-oauth2-withAdminUi(true)-skipJhipsterD "angular.json": { "stateCleared": "modified", }, + "eslint.config.mjs": { + "stateCleared": "modified", + }, "jest.conf.js": { "stateCleared": "modified", }, @@ -2923,12 +2911,6 @@ exports[`generator - angular microservice-oauth2-withAdminUi(true)-skipJhipsterD exports[`generator - angular monolith-jwt-skipUserManagement(false)-withAdminUi(true)-skipJhipsterDependencies(true)-enableTranslation(true)--websocket(true) should match generated files snapshot 1`] = ` { - ".eslintignore": { - "stateCleared": "modified", - }, - ".eslintrc.json": { - "stateCleared": "modified", - }, ".jhipster/EntityWithCustomId.json": { "stateCleared": "modified", }, @@ -2947,6 +2929,9 @@ exports[`generator - angular monolith-jwt-skipUserManagement(false)-withAdminUi( "angular.json": { "stateCleared": "modified", }, + "eslint.config.mjs": { + "stateCleared": "modified", + }, "jest.conf.js": { "stateCleared": "modified", }, @@ -3999,12 +3984,6 @@ exports[`generator - angular monolith-jwt-skipUserManagement(false)-withAdminUi( exports[`generator - angular monolith-oauth2-withAdminUi(false)-skipJhipsterDependencies(false)-enableTranslation(false)-websocket(false) should match generated files snapshot 1`] = ` { - ".eslintignore": { - "stateCleared": "modified", - }, - ".eslintrc.json": { - "stateCleared": "modified", - }, ".jhipster/EntityWithCustomId.json": { "stateCleared": "modified", }, @@ -4023,6 +4002,9 @@ exports[`generator - angular monolith-oauth2-withAdminUi(false)-skipJhipsterDepe "angular.json": { "stateCleared": "modified", }, + "eslint.config.mjs": { + "stateCleared": "modified", + }, "jest.conf.js": { "stateCleared": "modified", }, @@ -4655,12 +4637,6 @@ exports[`generator - angular monolith-oauth2-withAdminUi(false)-skipJhipsterDepe exports[`generator - angular monolith-session-skipUserManagement(true)-withAdminUi(false)-skipJhipsterDependencies(false)-enableTranslation(false)-websocket(true) should match generated files snapshot 1`] = ` { - ".eslintignore": { - "stateCleared": "modified", - }, - ".eslintrc.json": { - "stateCleared": "modified", - }, ".jhipster/EntityWithCustomId.json": { "stateCleared": "modified", }, @@ -4679,6 +4655,9 @@ exports[`generator - angular monolith-session-skipUserManagement(true)-withAdmin "angular.json": { "stateCleared": "modified", }, + "eslint.config.mjs": { + "stateCleared": "modified", + }, "jest.conf.js": { "stateCleared": "modified", }, diff --git a/generators/angular/cleanup.ts b/generators/angular/cleanup.ts index 009e3f1fd581..30e1a7a99c80 100644 --- a/generators/angular/cleanup.ts +++ b/generators/angular/cleanup.ts @@ -17,16 +17,15 @@ * limitations under the License. */ -import CoreGenerator from '../base-core/index.js'; +import { asWritingTask } from '../base-application/support/task-type-inference.js'; import { CLIENT_WEBPACK_DIR } from '../generator-constants.js'; -import { GeneratorDefinition } from '../base-application/generator.js'; /** * Removes files that where generated in previous JHipster versions and therefore * need to be removed. */ -// eslint-disable-next-line import/prefer-default-export -export default function cleanupOldFilesTask(this: CoreGenerator, { application }: GeneratorDefinition['writingTaskParam']) { + +export default asWritingTask(function cleanupOldFilesTask(this, { application }) { if (this.isJhipsterVersionLessThan('3.2.0')) { // removeFile and removeFolder methods should be called here for files and folders to cleanup this.removeFile(`${application.clientSrcDir}app/components/form/uib-pager.config.js`); @@ -292,4 +291,4 @@ export default function cleanupOldFilesTask(this: CoreGenerator, { application } this.removeFile(`${application.clientSrcDir}app/entities/user/user.service.ts`); this.removeFile(`${application.clientSrcDir}app/entities/user/user.service.spec.ts`); } -} +}); diff --git a/generators/angular/command.ts b/generators/angular/command.ts index e49e6b411080..235c9748e1c1 100644 --- a/generators/angular/command.ts +++ b/generators/angular/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { options: {}, diff --git a/generators/angular/entity-files-angular.ts b/generators/angular/entity-files-angular.ts index 27c11634b8a7..48ae2dcabd21 100644 --- a/generators/angular/entity-files-angular.ts +++ b/generators/angular/entity-files-angular.ts @@ -16,11 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { GeneratorDefinition } from '../base-application/generator.js'; import { clientApplicationTemplatesBlock } from '../client/support/files.js'; -import CoreGenerator from '../base-core/index.js'; -import { WriteFileSection } from '../base/api.js'; -import { asWritingEntitiesTask } from '../base-application/support/task-type-inference.js'; +import type { WriteFileSection } from '../base/api.js'; +import { asPostWritingEntitiesTask, asWritingEntitiesTask } from '../base-application/support/index.js'; const entityModelFiles = clientApplicationTemplatesBlock({ templates: ['entities/_entityFolder_/_entityFile_.model.ts', 'entities/_entityFolder_/_entityFile_.test-samples.ts'], @@ -95,10 +93,7 @@ export const userManagementFiles: WriteFileSection = { ], }; -export const writeEntitiesFiles = asWritingEntitiesTask(async function ( - this: CoreGenerator, - { control, application, entities }: GeneratorDefinition['writingEntitiesTaskParam'], -) { +export const writeEntitiesFiles = asWritingEntitiesTask(async function ({ control, application, entities }) { for (const entity of (control.filterEntitiesAndPropertiesForClient ?? (entities => entities))(entities)) { if (entity.builtInUser) { await this.writeFiles({ @@ -111,7 +106,7 @@ export const writeEntitiesFiles = asWritingEntitiesTask(async function ( }, }); - if (application.generateUserManagement && application.userManagement.skipClient) { + if (application.generateUserManagement && application.userManagement!.skipClient) { await this.writeFiles({ sections: userManagementFiles, context: { @@ -132,18 +127,15 @@ export const writeEntitiesFiles = asWritingEntitiesTask(async function ( } }); -export async function postWriteEntitiesFiles(this: CoreGenerator, taskParam: GeneratorDefinition['postWritingEntitiesTaskParam']) { - const { control, source, application } = taskParam; +export const postWriteEntitiesFiles = asPostWritingEntitiesTask(async function (this, taskParam) { + const { control, source } = taskParam; const entities = (control.filterEntitiesForClient ?? (entities => entities))(taskParam.entities).filter( entity => !entity.builtInUser && !entity.embedded && !entity.entityClientModelOnly, ); - source.addEntitiesToClient({ application, entities }); -} + source.addEntitiesToClient({ ...taskParam, entities }); +}); -export function cleanupEntitiesFiles( - this: CoreGenerator, - { control, application, entities }: GeneratorDefinition['writingEntitiesTaskParam'], -) { +export const cleanupEntitiesFiles = asWritingEntitiesTask(function ({ control, application, entities }) { for (const entity of (control.filterEntitiesForClient ?? (entities => entities))(entities).filter(entity => !entity.builtIn)) { const { entityFolderName, entityFileName, name: entityName } = entity; if (this.isJhipsterVersionLessThan('5.0.0')) { @@ -189,4 +181,4 @@ export function cleanupEntitiesFiles( this.removeFile(`${application.clientSrcDir}app/entities/${entityFolderName}/route/${entityFileName}-routing.module.ts`); } } -} +}); diff --git a/generators/angular/files-angular.js b/generators/angular/files-angular.ts similarity index 98% rename from generators/angular/files-angular.js rename to generators/angular/files-angular.ts index 838a4d2dfb4d..84edfebacdff 100644 --- a/generators/angular/files-angular.js +++ b/generators/angular/files-angular.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +import { asWritingTask } from '../base-application/support/index.js'; import { clientApplicationTemplatesBlock, clientRootTemplatesBlock, clientSrcTemplatesBlock } from '../client/support/files.js'; export const files = { @@ -28,8 +28,8 @@ export const files = { common: [ clientRootTemplatesBlock({ templates: [ - '.eslintrc.json', 'angular.json', + { sourceFile: 'eslint.config.js.jhi.angular', destinationFile: ctx => `${ctx.eslintConfigFile}.jhi.angular` }, 'ngsw-config.json', 'package.json', 'tsconfig.json', @@ -437,11 +437,11 @@ export const files = { ], }; -export async function writeFiles({ application }) { +export const writeFiles = asWritingTask(async function writeFiles({ application }) { if (!application.clientFrameworkAngular) return; await this.writeFiles({ sections: files, context: application, }); -} +}); diff --git a/generators/angular/generator.spec.ts b/generators/angular/generator.spec.ts index f2e750afd1f9..fbbd9b06fcef 100644 --- a/generators/angular/generator.spec.ts +++ b/generators/angular/generator.spec.ts @@ -1,11 +1,11 @@ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { buildClientSamples, entitiesClientSamples as entities, defaultHelpers as helpers, runResult } from '../../testing/index.js'; -import { shouldSupportFeatures, testBlueprintSupport, checkEnforcements } from '../../test/support/index.js'; -import { clientFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { buildClientSamples, entitiesClientSamples as entities, defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; +import { checkEnforcements, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/index.js'; +import { clientFrameworkTypes } from '../../lib/jhipster/index.js'; import { CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; import { GENERATOR_ANGULAR } from '../generator-list.js'; import Generator from './index.js'; @@ -14,7 +14,6 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorFile = join(__dirname, 'index.ts'); const { ANGULAR: clientFramework } = clientFrameworkTypes; const commonConfig = { clientFramework, nativeLanguage: 'en', languages: ['fr', 'en'] }; @@ -88,7 +87,7 @@ describe(`generator - ${clientFramework}`, () => { describe(name, () => { before(async () => { await helpers - .run(generatorFile) + .runJHipster(generator) .withJHipsterConfig(sampleConfig, entities) .withSharedApplication({ gatewayServicesApiAvailable: sampleConfig.applicationType === 'gateway' }) .withControl({ getWebappTranslation: () => 'translations' }) diff --git a/generators/angular/generator.ts b/generators/angular/generator.ts index e29716bd8075..5e8cd9047611 100644 --- a/generators/angular/generator.ts +++ b/generators/angular/generator.ts @@ -20,32 +20,33 @@ import { camelCase } from 'lodash-es'; import chalk from 'chalk'; import { isFileStateModified } from 'mem-fs-editor/state'; -import BaseApplicationGenerator, { type Entity } from '../base-application/index.js'; +import BaseApplicationGenerator from '../base-application/index.js'; import { GENERATOR_ANGULAR, GENERATOR_CLIENT, GENERATOR_LANGUAGES } from '../generator-list.js'; import { defaultLanguage } from '../languages/support/index.js'; -import { clientFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { clientFrameworkTypes } from '../../lib/jhipster/index.js'; import { + generateTypescriptTestEntity as generateTestEntity, generateEntityClientEnumImports as getClientEnumImportsFormat, getTypescriptKeyType as getTSKeyType, generateTestEntityId as getTestEntityId, generateTestEntityPrimaryKey as getTestEntityPrimaryKey, - generateTypescriptTestEntity as generateTestEntity, } from '../client/support/index.js'; -import type { CommonClientServerApplication } from '../base-application/types.js'; import { createNeedleCallback, mutateData } from '../base/support/index.js'; -import { writeEntitiesFiles, postWriteEntitiesFiles, cleanupEntitiesFiles } from './entity-files-angular.js'; +import { writeEslintClientRootConfigFile } from '../javascript/generators/eslint/support/tasks.js'; +import type { PostWritingEntitiesTaskParam } from '../../lib/types/application/tasks.js'; +import { cleanupEntitiesFiles, postWriteEntitiesFiles, writeEntitiesFiles } from './entity-files-angular.js'; import { writeFiles } from './files-angular.js'; import cleanupOldFilesTask from './cleanup.js'; +import type { addItemToMenu } from './support/index.js'; import { - buildAngularFormPath as angularFormPath, addEntitiesRoute, + addIconImport, + addItemToAdminMenu, + addRoute, addToEntitiesMenu, - translateAngularFilesTransform, + buildAngularFormPath as angularFormPath, isTranslatedAngularFile, - addRoute, - addItemToMenu, - addItemToAdminMenu, - addIconImport, + translateAngularFilesTransform, } from './support/index.js'; const { ANGULAR } = clientFrameworkTypes; @@ -72,6 +73,12 @@ export default class AngularGenerator extends BaseApplicationGenerator { this.fetchFromInstalledJHipster(GENERATOR_ANGULAR, 'resources', 'package.json'), ); }, + applicationDefauts({ applicationDefaults }) { + applicationDefaults({ + __override__: true, + typescriptEslint: true, + }); + }, }); } @@ -81,15 +88,20 @@ export default class AngularGenerator extends BaseApplicationGenerator { get preparing() { return this.asPreparingTaskGroup({ - prepareForTemplates({ application }) { - application.webappEnumerationsDir = `${application.clientSrcDir}app/entities/enumerations/`; - application.angularLocaleId = application.nativeLanguageDefinition.angularLocale ?? defaultLanguage.angularLocale!; + applicationDefauts({ application, applicationDefaults }) { + applicationDefaults({ + __override__: true, + eslintConfigFile: app => `eslint.config.${app.packageJsonType === 'module' ? 'js' : 'mjs'}`, + webappEnumerationsDir: app => `${app.clientSrcDir}app/entities/enumerations/`, + angularLocaleId: app => app.nativeLanguageDefinition.angularLocale ?? defaultLanguage.angularLocale, + }); + + application.addPrettierExtensions?.(['html', 'css', 'scss']); }, addNeedles({ source, application }) { source.addEntitiesToClient = param => { - const { application, entities } = param; - this.addEntitiesToModule({ application, entities }); - this.addEntitiesToMenu({ application, entities }); + this.addEntitiesToModule(param); + this.addEntitiesToMenu(param); }; source.addAdminRoute = (args: Omit[0], 'needle'>) => @@ -129,7 +141,7 @@ export default class AngularGenerator extends BaseApplicationGenerator { { ignoreNonExisting }, createNeedleCallback({ needle: 'jhipster-needle-add-webpack-config', - contentToAdd: `,${args.config}`, + contentToAdd: `${args.config},`, }), ); }; @@ -222,7 +234,13 @@ export default class AngularGenerator extends BaseApplicationGenerator { get writing() { return this.asWritingTaskGroup({ + async cleanup({ control }) { + await control.cleanupFiles({ + '8.6.1': ['.eslintrc.json', '.eslintignore'], + }); + }, cleanupOldFilesTask, + writeEslintClientRootConfigFile, writeFiles, }); } @@ -318,7 +336,7 @@ export default class AngularGenerator extends BaseApplicationGenerator { * } * */ - addVendorSCSSStyle(style, comment) { + addVendorSCSSStyle(style, comment?) { this.needleApi.clientAngular.addVendorSCSSStyle(style, comment); } @@ -374,7 +392,7 @@ export default class AngularGenerator extends BaseApplicationGenerator { this.needleApi.clientAngular.addElementToAdminMenu(routerName, iconName, enableTranslation, translationKeyMenu, jhiPrefix); } - addEntitiesToMenu({ application, entities }: { application: CommonClientServerApplication; entities: Entity[] }) { + addEntitiesToMenu({ application, entities }: Pick) { const filePath = `${application.clientSrcDir}app/layouts/navbar/navbar.component.html`; const ignoreNonExisting = chalk.yellow('Reference to entities not added to menu.'); const editCallback = addToEntitiesMenu({ application, entities }); @@ -382,10 +400,10 @@ export default class AngularGenerator extends BaseApplicationGenerator { this.editFile(filePath, { ignoreNonExisting }, editCallback); } - addEntitiesToModule({ application, entities }: { application: CommonClientServerApplication; entities: Entity[] }) { - const filePath = `${application.clientSrcDir}app/entities/entity.routes.ts`; + addEntitiesToModule(param: Pick) { + const filePath = `${param.application.clientSrcDir}app/entities/entity.routes.ts`; const ignoreNonExisting = chalk.yellow(`Route(s) not added to ${filePath}.`); - const addRouteCallback = addEntitiesRoute({ application, entities }); + const addRouteCallback = addEntitiesRoute(param); this.editFile(filePath, { ignoreNonExisting }, addRouteCallback); } @@ -409,7 +427,7 @@ export default class AngularGenerator extends BaseApplicationGenerator { * } * */ - addMainSCSSStyle(style, comment) { + addMainSCSSStyle(style, comment?) { this.needleApi.clientAngular.addGlobalSCSSStyle(style, comment); } @@ -486,7 +504,7 @@ export default class AngularGenerator extends BaseApplicationGenerator { * @param {string} clientFramework - The name of the client framework * @param {string} translationKeyMenu - i18n key for entry in the menu */ - addElementToMenu(routerName, iconName, enableTranslation, clientFramework, translationKeyMenu = camelCase(routerName)) { + addElementToMenu(routerName, iconName, enableTranslation, _clientFramework?, translationKeyMenu = camelCase(routerName)) { this.needleApi.clientAngular.addElementToMenu(routerName, iconName, enableTranslation, translationKeyMenu); } } diff --git a/generators/angular/needle-api/needle-client-angular.ts b/generators/angular/needle-api/needle-client-angular.ts index 5dc4ed777e66..3c83cd7202c2 100644 --- a/generators/angular/needle-api/needle-client-angular.ts +++ b/generators/angular/needle-api/needle-client-angular.ts @@ -22,17 +22,17 @@ import { startCase } from 'lodash-es'; import needleClientBase from '../../client/needle-api/needle-client.js'; import { LINE_LENGTH } from '../../generator-constants.js'; import { stripMargin, upperFirstCamelCase } from '../../base/support/index.js'; -import { clientFrameworkTypes } from '../../../jdl/jhipster/index.js'; +import { clientFrameworkTypes } from '../../../lib/jhipster/index.js'; import { createNeedleCallback } from '../../base/support/needles.js'; const { ANGULAR } = clientFrameworkTypes; export default class extends needleClientBase { - addGlobalSCSSStyle(style, comment) { + addGlobalSCSSStyle(style, comment?) { const filePath = `${this.clientSrcDir}content/scss/global.scss`; this.addStyle(style, comment, filePath, 'jhipster-needle-scss-add-main'); } - addVendorSCSSStyle(style, comment) { + addVendorSCSSStyle(style, comment?) { const filePath = `${this.clientSrcDir}content/scss/vendor.scss`; super.addStyle(style, comment, filePath, 'jhipster-needle-scss-add-vendor'); } diff --git a/generators/angular/resources/package.json b/generators/angular/resources/package.json index 8ecfd707a92f..4a16fb290170 100644 --- a/generators/angular/resources/package.json +++ b/generators/angular/resources/package.json @@ -1,10 +1,10 @@ { "dependencies": { - "@angular/common": "18.1.1", + "@angular/common": "18.2.9", "@fortawesome/angular-fontawesome": "0.15.0", "@fortawesome/fontawesome-svg-core": "6.6.0", "@fortawesome/free-solid-svg-icons": "6.6.0", - "@ng-bootstrap/ng-bootstrap": "17.0.0", + "@ng-bootstrap/ng-bootstrap": "17.0.1", "@ngx-translate/core": "15.0.0", "@ngx-translate/http-loader": "8.0.0", "@popperjs/core": "2.11.8", @@ -15,39 +15,41 @@ "ngx-infinite-scroll": "18.0.0", "rxjs": "7.8.1", "sockjs-client": "1.6.1", - "tslib": "2.6.3", - "zone.js": "0.14.8" + "tslib": "2.8.0", + "zone.js": "0.14.10" }, "devDependencies": { - "@angular-architects/module-federation": "18.0.4", - "@angular-architects/module-federation-runtime": "18.0.4", + "@angular-architects/module-federation": "18.0.6", + "@angular-architects/module-federation-runtime": "18.0.6", "@angular-builders/custom-webpack": "18.0.0", "@angular-builders/jest": "18.0.0", - "@angular-eslint/eslint-plugin": "18.1.0", - "@angular/cli": "18.1.1", - "@types/jest": "29.5.12", + "@angular/cli": "18.2.10", + "@types/jest": "29.5.14", "@types/node": "20.11.25", "@types/sockjs-client": "1.5.4", - "@typescript-eslint/eslint-plugin": "7.16.1", - "browser-sync": "3.0.2", + "angular-eslint": "18.4.0", + "browser-sync": "3.0.3", "browser-sync-webpack-plugin": "2.3.0", "buffer": "6.0.3", "copy-webpack-plugin": "12.0.2", - "eslint": "8.57.0", + "eslint": "9.13.0", "eslint-config-prettier": "9.1.0", + "eslint-plugin-prettier": "5.2.1", "eslint-webpack-plugin": "4.2.0", "folder-hash": "4.0.4", + "globals": "15.11.0", "jest": "29.7.0", "jest-date-mock": "1.0.10", "jest-junit": "16.0.0", - "jest-preset-angular": "14.1.1", + "jest-preset-angular": "14.2.4", "jest-sonar": "0.2.16", "merge-jsons-webpack-plugin": "2.0.1", - "postcss-rtlcss": "5.3.0", + "postcss-rtlcss": "5.5.0", "rimraf": "5.0.8", - "ts-jest": "29.2.2", - "typescript": "5.4.5", - "webpack": "5.93.0", + "ts-jest": "29.2.5", + "typescript": "5.5.4", + "typescript-eslint": "8.12.2", + "webpack": "5.95.0", "webpack-bundle-analyzer": "4.10.2", "webpack-merge": "6.0.1", "webpack-notifier": "1.15.0" diff --git a/generators/angular/support/needles.ts b/generators/angular/support/needles.ts index 1b7138f4af6f..cf281e2b35fd 100644 --- a/generators/angular/support/needles.ts +++ b/generators/angular/support/needles.ts @@ -16,11 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { Entity } from '../../base-application/index.js'; -import type { BaseApplication, CommonClientServerApplication } from '../../base-application/types.js'; import { createNeedleCallback } from '../../base/support/needles.js'; -import { upperFirstCamelCase } from '../../base/support/string.js'; +import { upperFirstCamelCase } from '../../../lib/utils/string.js'; import { joinCallbacks } from '../../base/support/write-files.js'; +import type { PostWritingEntitiesTaskParam } from '../../../lib/types/application/tasks.js'; export function addRoute({ needle, @@ -55,7 +54,7 @@ export function addRoute({ }); } -export function addEntitiesRoute({ application, entities }: { application: CommonClientServerApplication; entities: Entity[] }) { +export function addEntitiesRoute({ application, entities }: Pick) { const { enableTranslation } = application; return joinCallbacks( ...entities.map(entity => { @@ -127,7 +126,7 @@ export const addIconImport = ({ icon }: { icon: string }) => { }); }; -export function addToEntitiesMenu({ application, entities }: { application: BaseApplication; entities: Entity[] }) { +export function addToEntitiesMenu({ application, entities }: Pick) { const { enableTranslation, jhiPrefix } = application; return joinCallbacks( ...entities.map(entity => { diff --git a/generators/angular/support/path-utils.js b/generators/angular/support/path-utils.ts similarity index 94% rename from generators/angular/support/path-utils.js rename to generators/angular/support/path-utils.ts index 14d9603a81e5..7992e69c8341 100644 --- a/generators/angular/support/path-utils.js +++ b/generators/angular/support/path-utils.ts @@ -25,7 +25,7 @@ * @param {string[]} prefix * @return {string} */ -// eslint-disable-next-line import/prefer-default-export + export const buildAngularFormPath = (reference, prefix = []) => { const formPath = [...prefix, ...reference.path].join("', '"); return `'${formPath}'`; diff --git a/generators/angular/support/translate-angular.spec.ts b/generators/angular/support/translate-angular.spec.ts index 63cdb13d2385..c4b6f0cd0710 100644 --- a/generators/angular/support/translate-angular.spec.ts +++ b/generators/angular/support/translate-angular.spec.ts @@ -17,7 +17,7 @@ * limitations under the License. */ import { inspect } from 'node:util'; -import { it, describe, expect, esmocha, beforeEach } from 'esmocha'; +import { beforeEach, describe, esmocha, expect, it } from 'esmocha'; import { createTranslationReplacer } from './translate-angular.js'; describe('generator - angular - transform', () => { @@ -27,7 +27,7 @@ describe('generator - angular - transform', () => { beforeEach(() => { let value = 0; - const testImpl = (key, data) => `translated-value-${key}-${data ? `${inspect(data)}-` : ''}${value++}`; + const testImpl = (key, data) => (key === 'blank' ? '' : `translated-value-${key}-${data ? `${inspect(data)}-` : ''}${value++}`); replaceAngularTranslations = createTranslationReplacer(esmocha.fn().mockImplementation(testImpl), { jhiPrefix: 'jhi', enableTranslation: false, @@ -189,6 +189,11 @@ translated-value-global.form.currentpassword.title2-0 `); }); + it('should replace __jhiTranslateTag__ with empty translated value', () => { + const body = `__jhiTranslateTag__('blank', { "username": "account()!.login" })`; + expect(replaceAngularTranslations(body, extension)).toMatchInlineSnapshot(`""`); + }); + it('should replace __jhiTranslateTag__ with translation attribute and value', () => { const body = ` __jhiTranslateTag__('global.form.currentpassword.title1', { "username": "account()!.login" }) diff --git a/generators/angular/support/translate-angular.ts b/generators/angular/support/translate-angular.ts index adafd666db95..54dfb1eb75d9 100644 --- a/generators/angular/support/translate-angular.ts +++ b/generators/angular/support/translate-angular.ts @@ -37,10 +37,6 @@ const TRANSLATE_REGEX = [JHI_TRANSLATE_REGEX, TRANSLATE_VALUES_REGEX].join('|'); export type ReplacerOptions = { jhiPrefix: string; enableTranslation: boolean }; -function getTranslationValue(getWebappTranslation, key, data?) { - return getWebappTranslation(key, data) || undefined; -} - /** * Replace translation key with translation values * @@ -69,7 +65,7 @@ function replaceTranslationKeysWithText( // match is now the next match, in array form and our key is at index 1, index 1 is replace target. const key = match[keyIndex]; const target = match[replacementIndex]; - let translation = getTranslationValue(getWebappTranslation, key); + let translation = getWebappTranslation(key); if (escape) { translation = escape(translation, match); } @@ -134,7 +130,7 @@ const tagTranslation = ( const translatedValueInterpolate = parsedInterpolate ? Object.fromEntries(Object.entries(parsedInterpolate).map(([key, value]) => [key, `{{ ${value} }}`])) : undefined; - const translatedValue = escapeHtmlTranslationValue(getTranslationValue(getWebappTranslation, key, translatedValueInterpolate)); + const translatedValue = escapeHtmlTranslationValue(getWebappTranslation(key, translatedValueInterpolate)); if (enableTranslation) { const translateValuesAttr = parsedInterpolate @@ -160,7 +156,7 @@ const validationTagTranslation = ( if (!parsedInterpolate || Object.keys(parsedInterpolate).length === 0) { throw new Error(`No interpolation values found for translation key ${key}, use __jhiTranslateTag__ instead.`); } - const translatedValue = escapeHtmlTranslationValue(getTranslationValue(getWebappTranslation, key, parsedInterpolate)); + const translatedValue = escapeHtmlTranslationValue(getWebappTranslation(key, parsedInterpolate)); if (enableTranslation) { const translateValuesAttr = parsedInterpolate @@ -189,7 +185,7 @@ const tagPipeTranslation = ( const translatedValueInterpolate = Object.fromEntries( Object.entries(parsedInterpolate).map(([key, value]) => [key, getWebappTranslation(value)]), ); - const translatedValue = escapeHtmlTranslationValue(getTranslationValue(getWebappTranslation, key, translatedValueInterpolate)); + const translatedValue = escapeHtmlTranslationValue(getWebappTranslation(key, translatedValueInterpolate)); if (enableTranslation) { const translateValuesAttr = ` [translateValues]="{ ${Object.entries(parsedInterpolate) .map(([key, value]) => `${key}: ('${value}' | translate)`) @@ -213,7 +209,7 @@ const tagEnumTranslation = ( throw new Error(`Value is required for TagEnum ${key}.`); } const { value, fallback } = parsedInterpolate; - const translatedValue = `{{ ${JSON.stringify(getTranslationValue(getWebappTranslation, key))}[${value}]${fallback ? ` || ${fallback}` : ''} }}`; + const translatedValue = `{{ ${JSON.stringify(getWebappTranslation(key))}[${value}]${fallback ? ` || ${fallback}` : ''} }}`; if (enableTranslation) { return ` [${jhiPrefix}Translate]="'${key}.' + (${parsedInterpolate?.value})"${prefix}${translatedValue}${suffix}`; } @@ -234,7 +230,7 @@ const pipeTranslation = ( return `${prefix}{{ '${key}' | translate }}${suffix}`; } - return `${prefix}${escapeHtmlTranslationValue(getTranslationValue(getWebappTranslation, key))}${suffix}`; + return `${prefix}${escapeHtmlTranslationValue(getWebappTranslation(key))}${suffix}`; }; /** @@ -245,7 +241,7 @@ const valueTranslation = ( _replacerOptions: ReplacerOptions, { filePath, key, prefix, suffix }: JHITranslateConverterOptions, ) => { - let translationValue = getTranslationValue(getWebappTranslation, key); + let translationValue = getWebappTranslation(key); const fileExtension = extname(filePath); if (fileExtension === '.html') { translationValue = escapeHtmlTranslationValue(translationValue); @@ -272,7 +268,7 @@ const pipeEnumTranslation = ( return `${prefix}{{ '${key}.' + ${value} | translate }}${suffix}`; } - const translatedValue = `{{ ${JSON.stringify(getTranslationValue(getWebappTranslation, key))}[${value}]${fallback ? ` ?? ${fallback}` : ''} }}`; + const translatedValue = `{{ ${JSON.stringify(getWebappTranslation(key))}[${value}]${fallback ? ` ?? ${fallback}` : ''} }}`; return `${prefix}${translatedValue}${suffix}`; }; @@ -314,7 +310,7 @@ export const createTranslationReplacer = (getWebappTranslation, opts: ReplacerOp ); } return function replaceAngularTranslations(content, filePath) { - if (/\.html$/.test(filePath)) { + if (filePath.endsWith('.html')) { if (!enableTranslation) { content = content.replace(new RegExp(TRANSLATE_REGEX, 'g'), ''); content = replacePlaceholders(getWebappTranslation, content); @@ -332,7 +328,7 @@ export const createTranslationReplacer = (getWebappTranslation, opts: ReplacerOp if (/(:?route|module)\.ts$/.test(filePath)) { content = replacePageTitles(getWebappTranslation, content); } - if (/error\.route\.ts$/.test(filePath)) { + if (filePath.endsWith('error.route.ts')) { content = replaceErrorMessage(getWebappTranslation, content); } } diff --git a/generators/angular/templates/.eslintrc.json.ejs b/generators/angular/templates/.eslintrc.json.ejs deleted file mode 100644 index 26c41af20842..000000000000 --- a/generators/angular/templates/.eslintrc.json.ejs +++ /dev/null @@ -1,123 +0,0 @@ -<%# - Copyright 2013-2024 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. --%> -{ - "parser": "@typescript-eslint/parser", - "plugins": ["@angular-eslint/eslint-plugin", "@typescript-eslint"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking", - "plugin:@angular-eslint/recommended", - "prettier", - "eslint-config-prettier" - ], - "env": { - "browser": true, - "es6": true, - "commonjs": true - }, - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module", - "project": [ - "./tsconfig.app.json", -<%_ if (cypressTests) { _%> - "./<%= this.relativeDir(clientRootDir, cypressDir) %>tsconfig.json", -<%_ } _%> - "./tsconfig.spec.json" - ] - }, - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "<%= jhiPrefixDashed %>", - "style": "kebab-case" - } - ], - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "<%= jhiPrefix %>", - "style": "camelCase" - } - ], - "@angular-eslint/relative-url-prefix": "error", - "@typescript-eslint/ban-types": [ - "error", - { - "extendDefaults": true, - "types": { - "{}": false - } - } - ], - "@typescript-eslint/explicit-function-return-type": ["error", { "allowExpressions": true }], - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/member-ordering": [ - "error", - { - "default": [ - "public-static-field", - "protected-static-field", - "private-static-field", - "public-instance-field", - "protected-instance-field", - "private-instance-field", - "constructor", - "public-static-method", - "protected-static-method", - "private-static-method", - "public-instance-method", - "protected-instance-method", - "private-instance-method" - ] - } - ], - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-floating-promises": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-shadow": ["error"], - "@typescript-eslint/no-unnecessary-condition": "error", - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/prefer-nullish-coalescing": "error", - "@typescript-eslint/prefer-optional-chain": "error", - "@typescript-eslint/unbound-method": "off", - "arrow-body-style": "error", - "curly": "error", - "eqeqeq": ["error", "always", { "null": "ignore" }], - "guard-for-in": "error", - "no-bitwise": "error", - "no-caller": "error", - "no-console": ["error", { "allow": ["warn", "error"] }], - "no-eval": "error", - "no-labels": "error", - "no-new": "error", - "no-new-wrappers": "error", - "object-shorthand": ["error", "always", { "avoidExplicitReturnArrows": true }], - "radix": "error", - "spaced-comment": ["warn", "always"] - } -} diff --git a/generators/angular/templates/eslint.config.js.jhi.angular.ejs b/generators/angular/templates/eslint.config.js.jhi.angular.ejs new file mode 100644 index 000000000000..a8040493294f --- /dev/null +++ b/generators/angular/templates/eslint.config.js.jhi.angular.ejs @@ -0,0 +1,141 @@ +<%# + Copyright 2013-2024 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. +-%> +<&_ if (fragment.importsSection) { -&> +import eslint from '@eslint/js'; +// For a detailed explanation, visit: https://github.com/angular-eslint/angular-eslint/blob/main/docs/CONFIGURING_FLAT_CONFIG.md +import angular from 'angular-eslint'; +<&_ } -&> +<&_ if (fragment.configSection) { -&> + { ignores: ['<%- this.relativeDir(clientRootDir, clientDistDir) %>', '<%- temporaryDir %>'] }, + eslint.configs.recommended, + { + files: ['**/*.{js,cjs,mjs}'], + rules: { + 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + }, + }, + { + files: ['<%- this.relativeDir(clientRootDir, clientSrcDir) %>**/*.ts'], + extends: [...tseslint.configs.strictTypeChecked, ...tseslint.configs.stylistic, ...angular.configs.tsRecommended], + languageOptions: { + globals: { + ...globals.browser, + }, + parserOptions: { + project: ['./tsconfig.app.json', './tsconfig.spec.json'], + }, + }, + processor: { + // https://github.com/angular-eslint/angular-eslint/issues/1917 + meta:{ + name:'extract-inline-html', + }, + ...angular.processInlineTemplates, + }, + rules: { + '@angular-eslint/component-selector': [ + 'error', + { + type: 'element', + prefix: '<%= jhiPrefixDashed %>', + style: 'kebab-case', + }, + ], + '@angular-eslint/directive-selector': [ + 'error', + { + type: 'attribute', + prefix: '<%= jhiPrefix %>', + style: 'camelCase', + }, + ], + '@angular-eslint/relative-url-prefix': 'error', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/explicit-function-return-type': ['error', { allowExpressions: true }], + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/member-ordering': [ + 'error', + { + default: [ + 'public-static-field', + 'protected-static-field', + 'private-static-field', + 'public-instance-field', + 'protected-instance-field', + 'private-instance-field', + 'constructor', + 'public-static-method', + 'protected-static-method', + 'private-static-method', + 'public-instance-method', + 'protected-instance-method', + 'private-instance-method', + ], + }, + ], + '@typescript-eslint/no-confusing-void-expression': 'off', + '@typescript-eslint/no-empty-object-type': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-extraneous-class': 'off', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-shadow': ['error'], + '@typescript-eslint/no-unnecessary-condition': 'error', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/prefer-nullish-coalescing': 'error', + '@typescript-eslint/prefer-optional-chain': 'error', + '@typescript-eslint/restrict-template-expressions': ['error', { allowNumber: true }], + '@typescript-eslint/unbound-method': 'off', + 'arrow-body-style': 'error', + curly: 'error', + eqeqeq: ['error', 'always', { null: 'ignore' }], + 'guard-for-in': 'error', + 'no-bitwise': 'error', + 'no-caller': 'error', + 'no-console': ['error', { allow: ['warn', 'error'] }], + 'no-eval': 'error', + 'no-labels': 'error', + 'no-new': 'error', + 'no-new-wrappers': 'error', + 'object-shorthand': ['error', 'always', { avoidExplicitReturnArrows: true }], + radix: 'error', + 'spaced-comment': ['warn', 'always'], + }, + }, + { + files: ['<%- this.relativeDir(clientRootDir, clientSrcDir) %>**/*.spec.ts'], + rules: { + '@typescript-eslint/no-empty-function': 'off', + }, + }, + { + files: ['**/*.html'], + extends: [...angular.configs.templateRecommended, ...angular.configs.templateAccessibility], + rules: {}, + }, + { + // Html templates requires some work + ignores: ['**/*.html'], + extends: [prettier], + }, +<&_ } -&> diff --git a/generators/angular/templates/jest.conf.js.ejs b/generators/angular/templates/jest.conf.js.ejs index dbf7131d4797..4b876b35e520 100644 --- a/generators/angular/templates/jest.conf.js.ejs +++ b/generators/angular/templates/jest.conf.js.ejs @@ -16,9 +16,11 @@ See the License for the specific language governing permissions and limitations under the License. -%> -const { pathsToModuleNameMapper } = require('ts-jest') +const { pathsToModuleNameMapper } = require('ts-jest'); -const { compilerOptions: { paths = {}, baseUrl = './' } } = require('./tsconfig.json'); +const { + compilerOptions: { paths = {}, baseUrl = './' }, +} = require('./tsconfig.json'); const environment = require('./webpack/environment'); module.exports = { diff --git a/generators/angular/templates/package.json.ejs b/generators/angular/templates/package.json.ejs index 1af61a7c84a2..e18b8ae8aa3c 100644 --- a/generators/angular/templates/package.json.ejs +++ b/generators/angular/templates/package.json.ejs @@ -77,18 +77,18 @@ "@angular-builders/custom-webpack": "<%= nodeDependencies['@angular-builders/custom-webpack'] %>", "@angular-builders/jest": "<%= nodeDependencies['@angular-builders/jest'] %>", "@angular-devkit/build-angular": "<%= nodeDependencies['@angular/cli'] %>", - "@angular-eslint/eslint-plugin": "<%= nodeDependencies['@angular-eslint/eslint-plugin'] %>", "@types/jest": "<%= nodeDependencies['@types/jest'] %>", "@types/node": "<%= nodeDependencies['@types/node'] %>", - "@typescript-eslint/eslint-plugin": "<%= nodeDependencies['@typescript-eslint/eslint-plugin'] %>", - "@typescript-eslint/parser": "<%= nodeDependencies['@typescript-eslint/eslint-plugin'] %>", + "angular-eslint": "<%= nodeDependencies['angular-eslint'] %>", "browser-sync": "<%= nodeDependencies['browser-sync'] %>", "browser-sync-webpack-plugin": "<%= nodeDependencies['browser-sync-webpack-plugin'] %>", "buffer": "<%= nodeDependencies['buffer'] %>", "copy-webpack-plugin": "<%= nodeDependencies['copy-webpack-plugin'] %>", "eslint": "<%= nodeDependencies['eslint'] %>", "eslint-config-prettier": "<%= nodeDependencies['eslint-config-prettier'] %>", + "eslint-plugin-prettier": "<%= nodeDependencies['eslint-plugin-prettier'] %>", "eslint-webpack-plugin": "<%= nodeDependencies['eslint-webpack-plugin'] %>", + "globals": "<%= nodeDependencies.globals %>", "jest": "<%= nodeDependencies['jest'] %>", "jest-environment-jsdom": "<%= nodeDependencies['jest'] %>", "jest-preset-angular": "<%= nodeDependencies['jest-preset-angular'] %>", @@ -102,6 +102,7 @@ "swagger-ui-dist": "<%= nodeDependencies['swagger-ui-dist'] %>", "ts-jest": "<%= nodeDependencies['ts-jest'] %>", "typescript": "<%= nodeDependencies['typescript'] %>", + "typescript-eslint": "<%= nodeDependencies['typescript-eslint'] %>", "webpack-bundle-analyzer": "<%= nodeDependencies['webpack-bundle-analyzer'] %>", "webpack-merge": "<%= nodeDependencies['webpack-merge'] %>", "webpack-notifier": "<%= nodeDependencies['webpack-notifier'] %>" @@ -119,7 +120,7 @@ "scripts": { "prettier:check": "prettier --check \"{,src/**/,webpack/,.blueprint/**/}*.{<%= prettierExtensions %>}\"", "prettier:format": "prettier --write \"{,src/**/,webpack/,.blueprint/**/}*.{<%= prettierExtensions %>}\"", - "lint": "eslint . --ext .js,.ts", + "lint": "eslint .", "lint:fix": "<%= clientPackageManager %> run lint -- --fix", "cleanup": "rimraf <%= this.relativeDir(clientRootDir, temporaryDir) %>", "clean-www": "rimraf <%= this.relativeDir(clientRootDir, clientDistDir) %>", diff --git a/generators/angular/templates/src/main/webapp/app/account/activate/activate.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/activate/activate.component.ts.ejs index 940a2eb36307..3fdf0c69db91 100644 --- a/generators/angular/templates/src/main/webapp/app/account/activate/activate.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/activate/activate.component.ts.ejs @@ -33,8 +33,8 @@ export default class ActivateComponent implements OnInit { error = signal(false); success = signal(false); - private activateService = inject(ActivateService); - private route = inject(ActivatedRoute); + private readonly activateService = inject(ActivateService); + private readonly route = inject(ActivatedRoute); ngOnInit(): void { this.route.queryParams.pipe(mergeMap(params => this.activateService.get(params.key))).subscribe({ diff --git a/generators/angular/templates/src/main/webapp/app/account/activate/activate.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/activate/activate.service.ts.ejs index 12af78026d4b..34213a695a04 100644 --- a/generators/angular/templates/src/main/webapp/app/account/activate/activate.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/activate/activate.service.ts.ejs @@ -24,8 +24,8 @@ import { ApplicationConfigService } from 'app/core/config/application-config.ser @Injectable({ providedIn: 'root' }) export class ActivateService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); get(key: string): Observable<{}> { return this.http.get(this.applicationConfigService.getEndpointFor('api/activate'), { diff --git a/generators/angular/templates/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts.ejs index 43c7976e31dd..b85850db15f1 100644 --- a/generators/angular/templates/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts.ejs @@ -50,13 +50,13 @@ export default class PasswordResetFinishComponent implements OnInit, AfterViewIn }), }); - private passwordResetFinishService = inject(PasswordResetFinishService); - private route = inject(ActivatedRoute); + private readonly passwordResetFinishService = inject(PasswordResetFinishService); + private readonly route = inject(ActivatedRoute); ngOnInit(): void { this.route.queryParams.subscribe(params => { - if (params['key']) { - this.key.set(params['key']); + if (params.key) { + this.key.set(params.key); } this.initialized.set(true); }); diff --git a/generators/angular/templates/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts.ejs index 7404aac89fc6..f0a59fc06965 100644 --- a/generators/angular/templates/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts.ejs @@ -24,8 +24,8 @@ import { ApplicationConfigService } from 'app/core/config/application-config.ser @Injectable({ providedIn: 'root' }) export class PasswordResetFinishService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); save(key: string, newPassword: string): Observable<{}> { return this.http.post(this.applicationConfigService.getEndpointFor('api/account/reset-password/finish'), { key, newPassword }); diff --git a/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html.ejs b/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html.ejs index ee41816b73a2..a6aea5853791 100644 --- a/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html.ejs @@ -23,62 +23,54 @@ <<%= jhiPrefixDashed %>-alert-error>-alert-error> - @if (!success()) { -
- __jhiTranslateTag__('reset.request.messages.info') -
-
-
- - + @if (!success()) { +
+ __jhiTranslateTag__('reset.request.messages.info') +
+ +
+ + - @let emailRef = resetRequestForm.get('email')!; - @if (emailRef.invalid && - (emailRef.dirty || emailRef.touched)) { -
- @if (emailRef?.errors?.required) { - __jhiTranslateTag__('global.messages.validate.email.required') - } - @if (emailRef?.errors?.email) { - __jhiTranslateTag__('global.messages.validate.email.invalid') - } + @let emailRef = resetRequestForm.get('email')!; + @if (emailRef.invalid && (emailRef.dirty || emailRef.touched)) { +
+ @if (emailRef?.errors?.required) { + __jhiTranslateTag__('global.messages.validate.email.required') + } + @if (emailRef?.errors?.email) { + __jhiTranslateTag__('global.messages.validate.email.invalid') + } - @if (emailRef?.errors?.minlength) { - __jhiTranslateTag__('global.messages.validate.email.minlength') - } + @if (emailRef?.errors?.minlength) { + __jhiTranslateTag__('global.messages.validate.email.minlength') + } - @if (emailRef?.errors?.maxlength) { - __jhiTranslateTag__('global.messages.validate.email.maxlength') - } + @if (emailRef?.errors?.maxlength) { + __jhiTranslateTag__('global.messages.validate.email.maxlength') + } +
+ }
- } + + + } @else { +
+ __jhiTranslateTag__('reset.request.messages.success')
- - - } @else { -
- __jhiTranslateTag__('reset.request.messages.success') -
- } + }
diff --git a/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts.ejs index 42320626db7e..6d6fb2f07787 100644 --- a/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts.ejs @@ -34,8 +34,8 @@ export default class PasswordResetInitComponent implements AfterViewInit { success = signal(false); resetRequestForm; - private passwordResetInitService = inject(PasswordResetInitService); - private fb = inject(FormBuilder); + private readonly passwordResetInitService = inject(PasswordResetInitService); + private readonly fb = inject(FormBuilder); constructor() { this.resetRequestForm = this.fb.group({ diff --git a/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts.ejs index a5fec6989405..f833a1b45e9c 100644 --- a/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts.ejs @@ -24,8 +24,8 @@ import { ApplicationConfigService } from 'app/core/config/application-config.ser @Injectable({ providedIn: 'root' }) export class PasswordResetInitService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); save(mail: string): Observable<{}> { return this.http.post(this.applicationConfigService.getEndpointFor('api/account/reset-password/init'), mail); diff --git a/generators/angular/templates/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.ts.ejs index 91db00f57b40..ebf1c1417c1e 100644 --- a/generators/angular/templates/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.ts.ejs @@ -30,8 +30,8 @@ import SharedModule from 'app/shared/shared.module'; export default class PasswordStrengthBarComponent { colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0']; - private renderer = inject(Renderer2); - private elementRef = inject(ElementRef); + private readonly renderer = inject(Renderer2); + private readonly elementRef = inject(ElementRef); measureStrength(p: string): number { let force = 0; @@ -42,7 +42,7 @@ export default class PasswordStrengthBarComponent { const symbols = regex.test(p); const flags = [lowerLetters, upperLetters, numbers, symbols]; - const passedMatches = flags.filter((isMatchedFlag: boolean) => isMatchedFlag === true).length; + const passedMatches = flags.filter((isMatchedFlag: boolean) => isMatchedFlag).length; force += 2 * p.length + (p.length >= 10 ? 1 : 0); force += passedMatches * 10; diff --git a/generators/angular/templates/src/main/webapp/app/account/password/password.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/password/password.component.ts.ejs index 12a35dc8e1b1..a8f18b40805b 100644 --- a/generators/angular/templates/src/main/webapp/app/account/password/password.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/password/password.component.ts.ejs @@ -49,8 +49,8 @@ export default class PasswordComponent implements OnInit { }), }); - private passwordService = inject(PasswordService); - private accountService = inject(AccountService); + private readonly passwordService = inject(PasswordService); + private readonly accountService = inject(AccountService); ngOnInit(): void { this.account$ = this.accountService.identity(); diff --git a/generators/angular/templates/src/main/webapp/app/account/password/password.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/password/password.service.ts.ejs index ad2617dc9a4a..a8d01af00777 100644 --- a/generators/angular/templates/src/main/webapp/app/account/password/password.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/password/password.service.ts.ejs @@ -24,8 +24,8 @@ import { ApplicationConfigService } from 'app/core/config/application-config.ser @Injectable({ providedIn: 'root' }) export class PasswordService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); save(newPassword: string, currentPassword: string): Observable<{}> { return this.http.post(this.applicationConfigService.getEndpointFor('api/account/change-password'), { currentPassword, newPassword }); diff --git a/generators/angular/templates/src/main/webapp/app/account/register/register.component.html.ejs b/generators/angular/templates/src/main/webapp/app/account/register/register.component.html.ejs index baa6309464b8..1c4861e337d4 100644 --- a/generators/angular/templates/src/main/webapp/app/account/register/register.component.html.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/register/register.component.html.ejs @@ -21,25 +21,25 @@

__jhiTranslateTag__('register.title')

- @if (success()) { -
__jhiTranslateTag__('register.messages.success')
- } + @if (success()) { +
__jhiTranslateTag__('register.messages.success')
+ } - @if (error()) { -
__jhiTranslateTag__('register.messages.error.fail')
- } + @if (error()) { +
__jhiTranslateTag__('register.messages.error.fail')
+ } - @if (errorUserExists()) { -
__jhiTranslateTag__('register.messages.error.userexists')
- } + @if (errorUserExists()) { +
__jhiTranslateTag__('register.messages.error.userexists')
+ } - @if (errorEmailExists()) { -
__jhiTranslateTag__('register.messages.error.emailexists')
- } + @if (errorEmailExists()) { +
__jhiTranslateTag__('register.messages.error.emailexists')
+ } - @if (doNotMatch()) { -
__jhiTranslateTag__('global.messages.error.dontmatch')
- } + @if (doNotMatch()) { +
__jhiTranslateTag__('global.messages.error.dontmatch')
+ }
@@ -205,7 +205,8 @@
__jhiTranslateTag__('global.messages.info.authenticated.prefix') - __jhiTranslateTag__('global.messages.info.authenticated.link')__jhiTranslateTag__('global.messages.info.authenticated.suffix') + __jhiTranslateTag__('global.messages.info.authenticated.link')__jhiTranslateTag__('global.messages.info.authenticated.suffix')
diff --git a/generators/angular/templates/src/main/webapp/app/account/register/register.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/register/register.component.ts.ejs index 7449b7b31140..ecb5dc7ab9dc 100644 --- a/generators/angular/templates/src/main/webapp/app/account/register/register.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/register/register.component.ts.ejs @@ -68,8 +68,8 @@ export default class RegisterComponent implements AfterViewInit { }), }); - <%_ if (enableTranslation) { _%>private translateService = inject(TranslateService);<%_ } _%> - private registerService = inject(RegisterService); + <%_ if (enableTranslation) { _%>private readonly translateService = inject(TranslateService);<%_ } _%> + private readonly registerService = inject(RegisterService); ngAfterViewInit(): void { this.login().nativeElement.focus(); diff --git a/generators/angular/templates/src/main/webapp/app/account/register/register.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/register/register.service.ts.ejs index a5d4d28f8c8e..ff8c226860e2 100644 --- a/generators/angular/templates/src/main/webapp/app/account/register/register.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/register/register.service.ts.ejs @@ -25,8 +25,8 @@ import { Registration } from './register.model'; @Injectable({ providedIn: 'root' }) export class RegisterService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); save(registration: Registration): Observable<{}> { return this.http.post(this.applicationConfigService.getEndpointFor('api/register'), registration); diff --git a/generators/angular/templates/src/main/webapp/app/account/sessions/sessions.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/sessions/sessions.component.ts.ejs index 21cfd6ecd9ad..a564f81d9b47 100644 --- a/generators/angular/templates/src/main/webapp/app/account/sessions/sessions.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/sessions/sessions.component.ts.ejs @@ -36,8 +36,8 @@ export default class SessionsComponent implements OnInit { success = false; sessions: Session[] = []; - private sessionsService = inject(SessionsService); - private accountService = inject(AccountService); + private readonly sessionsService = inject(SessionsService); + private readonly accountService = inject(AccountService); ngOnInit(): void { this.sessionsService.findAll().subscribe(sessions => (this.sessions = sessions)); @@ -49,12 +49,12 @@ export default class SessionsComponent implements OnInit { this.error = false; this.success = false; - this.sessionsService.delete(encodeURIComponent(series)).subscribe( - () => { + this.sessionsService.delete(encodeURIComponent(series)).subscribe({ + next: () => { this.success = true; this.sessionsService.findAll().subscribe(sessions => (this.sessions = sessions)); }, - () => (this.error = true), - ); + error: () => (this.error = true), + }); } } diff --git a/generators/angular/templates/src/main/webapp/app/account/sessions/sessions.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/sessions/sessions.service.ts.ejs index e1f9d047c768..536dfe670d66 100644 --- a/generators/angular/templates/src/main/webapp/app/account/sessions/sessions.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/sessions/sessions.service.ts.ejs @@ -25,8 +25,8 @@ import { Session } from './session.model'; @Injectable({ providedIn: 'root' }) export class SessionsService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); private resourceUrl = this.applicationConfigService.getEndpointFor('api/account/sessions'); diff --git a/generators/angular/templates/src/main/webapp/app/account/settings/settings.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/account/settings/settings.component.ts.ejs index c318b34720b0..aa781f3294e4 100644 --- a/generators/angular/templates/src/main/webapp/app/account/settings/settings.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/account/settings/settings.component.ts.ejs @@ -64,9 +64,9 @@ export default class SettingsComponent implements OnInit { login: new FormControl(initialAccount.login, { nonNullable: true }), }); - private accountService = inject(AccountService); + private readonly accountService = inject(AccountService); <%_ if (enableTranslation) { _%> - private translateService = inject(TranslateService); + private readonly translateService = inject(TranslateService); <%_ } _%> ngOnInit(): void { diff --git a/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.component.ts.ejs index 18c168590acf..f3e571d294f7 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.component.ts.ejs @@ -49,8 +49,8 @@ export default class ConfigurationComponent implements OnInit { return data; }); - private sortService = inject(SortService); - private configurationService = inject(ConfigurationService); + private readonly sortService = inject(SortService); + private readonly configurationService = inject(ConfigurationService); ngOnInit(): void { this.configurationService.getBeans().subscribe(beans => { diff --git a/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.model.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.model.ts.ejs index e88181838a45..1adc30dc05b3 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.model.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.model.ts.ejs @@ -20,18 +20,14 @@ export interface ConfigProps { contexts: Contexts; } -export interface Contexts { - [key: string]: Context; -} +export type Contexts = Record; export interface Context { beans: Beans; parentId?: any; } -export interface Beans { - [key: string]: Bean; -} +export type Beans = Record; export interface Bean { prefix: string; @@ -48,9 +44,7 @@ export interface PropertySource { properties: Properties; } -export interface Properties { - [key: string]: Property; -} +export type Properties = Record; export interface Property { value: string; diff --git a/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.service.ts.ejs index f8e4f8bf2c10..73e55f6163b3 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/configuration/configuration.service.ts.ejs @@ -26,8 +26,8 @@ import { Bean, Beans, ConfigProps, Env, PropertySource } from './configuration.m @Injectable({ providedIn: 'root' }) export class ConfigurationService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); getBeans(): Observable { return this.http.get(this.applicationConfigService.getEndpointFor('management/configprops')).pipe( diff --git a/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway-route.model.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway-route.model.ts.ejs index 98f5d366a8b7..1925a7622aa9 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway-route.model.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway-route.model.ts.ejs @@ -20,6 +20,6 @@ export class GatewayRoute { constructor( public path: string, public serviceId: string, - public serviceInstances: any[] + public serviceInstances: any[], ) {} } diff --git a/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway-routes.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway-routes.service.ts.ejs index 7af87ff2cbf8..801a9b01b41f 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway-routes.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway-routes.service.ts.ejs @@ -25,8 +25,8 @@ import { GatewayRoute } from './gateway-route.model'; @Injectable() export class GatewayRoutesService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); findAll(): Observable { return this.http.get(this.applicationConfigService.getEndpointFor('api/gateway/routes')); diff --git a/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway.component.html.ejs b/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway.component.html.ejs index 4c917369824b..b18a1e17d36a 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway.component.html.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway.component.html.ejs @@ -20,7 +20,7 @@

__jhiTranslateTag__('gateway.title') -

@@ -37,46 +37,50 @@ - @for (route of gatewayRoutes; track route.path) { - - {{ route.path }} - {{ route.serviceId }} - - @if (route.serviceInstances.length === 0) { -
__jhiTranslateTag__('gateway.routes.error')
- } - -
- @if (route) { - - @for (instance of route.serviceInstances; track instance.uri) { - - - - - + @for (route of gatewayRoutes; track route.path) { + + + +
{{ instance.uri }} - @if (instance.instanceInfo) { -
{{ instance.instanceInfo.status }}
- } @else { -
?
- } -
- @for (entry of (instance.metadata | keyvalue ); track entry.key) { - - - {{ entry.key }} - {{ entry.value }} - - - } -
{{ route.path }}{{ route.serviceId }} + @if (route.serviceInstances.length === 0) { +
__jhiTranslateTag__('gateway.routes.error')
} -
- } -
- - - } + +
+ @if (route) { + + @for (instance of route.serviceInstances; track instance.uri) { + + + + + + } +
+ {{ instance.uri }} + + @if (instance.instanceInfo) { +
+ {{ instance.instanceInfo.status }} +
+ } @else { +
?
+ } +
+ @for (entry of instance.metadata | keyvalue; track entry.key) { + + + {{ entry.key }} + {{ entry.value }} + + + } +
+ } +
+ + + } diff --git a/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway.component.ts.ejs index 8f7f61f28801..2c06992b192d 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/gateway/gateway.component.ts.ejs @@ -33,7 +33,7 @@ export default class GatewayComponent implements OnInit { gatewayRoutes: GatewayRoute[] = []; updatingRoutes = false; - private gatewayRoutesService = inject(GatewayRoutesService); + private readonly gatewayRoutesService = inject(GatewayRoutesService); ngOnInit(): void { this.refresh(); @@ -52,7 +52,7 @@ export default class GatewayComponent implements OnInit { ) { serviceInstance.instanceInfo = { status: 'UP' }; } else { - serviceInstance.instanceInfo = { status: 'DOWN'} ; + serviceInstance.instanceInfo = { status: 'DOWN' }; } } return serviceInstance as object; diff --git a/generators/angular/templates/src/main/webapp/app/admin/health/health.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/health/health.component.ts.ejs index a7ae65495f83..cfc437b53d5c 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/health/health.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/health/health.component.ts.ejs @@ -34,8 +34,8 @@ import HealthModalComponent from './modal/health-modal.component'; export default class HealthComponent implements OnInit { health?: Health; - private modalService = inject(NgbModal); - private healthService = inject(HealthService); + private readonly modalService = inject(NgbModal); + private readonly healthService = inject(HealthService); ngOnInit(): void { this.refresh(); diff --git a/generators/angular/templates/src/main/webapp/app/admin/health/health.model.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/health/health.model.ts.ejs index d26c7acde3a6..ffe11c0bac53 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/health/health.model.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/health/health.model.ts.ejs @@ -56,12 +56,10 @@ export type HealthKey = export interface Health { status: HealthStatus; - components: { - [key in HealthKey]?: HealthDetails; - }; + components?: Partial>; } export interface HealthDetails { status: HealthStatus; - details?: { [key: string]: unknown }; + details?: Record; } diff --git a/generators/angular/templates/src/main/webapp/app/admin/health/health.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/health/health.service.ts.ejs index ceeba50c50f8..77ffa7557e54 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/health/health.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/health/health.service.ts.ejs @@ -25,8 +25,8 @@ import { Health } from './health.model'; @Injectable({ providedIn: 'root' }) export class HealthService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); checkHealth(): Observable { return this.http.get(this.applicationConfigService.getEndpointFor('management/health')); diff --git a/generators/angular/templates/src/main/webapp/app/admin/health/modal/health-modal.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/health/modal/health-modal.component.ts.ejs index 31c6c58d17db..56593369cc11 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/health/modal/health-modal.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/health/modal/health-modal.component.ts.ejs @@ -31,7 +31,7 @@ import { HealthKey, HealthDetails } from '../health.model'; export default class HealthModalComponent { health?: { key: HealthKey; value: HealthDetails }; - private activeModal = inject(NgbActiveModal); + private readonly activeModal = inject(NgbActiveModal); readableValue(value: any): string { if (this.health?.key === 'diskSpace') { diff --git a/generators/angular/templates/src/main/webapp/app/admin/logs/log.model.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/logs/log.model.ts.ejs index 873b5db2982e..533390efd4b8 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/logs/log.model.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/logs/log.model.ts.ejs @@ -25,7 +25,7 @@ export interface Logger { export interface LoggersResponse { levels: Level[]; - loggers: { [key: string]: Logger }; + loggers: Record; } export class Log { diff --git a/generators/angular/templates/src/main/webapp/app/admin/logs/logs.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/logs/logs.component.ts.ejs index 28c555051817..cb0dc1d89a96 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/logs/logs.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/logs/logs.component.ts.ejs @@ -60,9 +60,9 @@ export default class LogsComponent implements OnInit { selectedService: string | undefined = undefined; <%_ } _%> - private logsService = inject(LogsService); - private sortService = inject(SortService); - <%= applicationTypeGateway && gatewayServicesApiAvailable ? 'private gatewayRoutesService = inject(GatewayRoutesService);' : '' %> + private readonly logsService = inject(LogsService); + private readonly sortService = inject(SortService); + <%= applicationTypeGateway && gatewayServicesApiAvailable ? 'private readonly gatewayRoutesService = inject(GatewayRoutesService);' : '' %> ngOnInit(): void { this.findAndExtractLoggers(); diff --git a/generators/angular/templates/src/main/webapp/app/admin/logs/logs.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/logs/logs.service.ts.ejs index 5e729ed055ce..21c5ae944245 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/logs/logs.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/logs/logs.service.ts.ejs @@ -25,8 +25,8 @@ import { LoggersResponse, Level } from './log.model'; @Injectable({ providedIn: 'root' }) export class LogsService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); changeLevel(name: string, configuredLevel: Level<%= applicationTypeGateway && gatewayServicesApiAvailable ? ', service?: string' : '' %>): Observable<{}> { return this.http.post(this.applicationConfigService.getEndpointFor(`management/loggers/${name}`<%= applicationTypeGateway && gatewayServicesApiAvailable ? ', service' : '' %>), { configuredLevel }); diff --git a/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.ts.ejs index 5209cf859e66..ddb7d233c8e3 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.ts.ejs @@ -31,7 +31,7 @@ export class JvmMemoryComponent { /** * object containing all jvm memory metrics */ - jvmMemoryMetrics = input<{ [key: string]: JvmMetrics }>(); + jvmMemoryMetrics = input>(); /** * boolean field saying if the metrics are in the process of being updated diff --git a/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.ts.ejs index d88412c0859d..f9d78f8378bc 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.ts.ejs @@ -33,7 +33,7 @@ export class MetricsCacheComponent { /** * object containing all cache related metrics */ - cacheMetrics = input<{ [key: string]: CacheMetrics }>(); + cacheMetrics = input>(); /** * boolean field saying if the metrics are in the process of being updated diff --git a/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts.ejs index 0da6b695223f..abb06dc537f9 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts.ejs @@ -39,7 +39,7 @@ export class MetricsModalThreadsComponent implements OnInit { threadDumpTimedWaiting = 0; threadDumpWaiting = 0; - private activeModal = inject(NgbActiveModal); + private readonly activeModal = inject(NgbActiveModal); ngOnInit(): void { this.threads?.forEach(thread => { diff --git a/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.html.ejs b/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.html.ejs index 3d039d966410..c6d004af980c 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.html.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.html.ejs @@ -27,20 +27,21 @@

__jhiTranslateTag__('metrics.jvm.title')

-@if (metrics() && !updatingMetrics()) { +@let metricsRef = metrics(); +@if (metricsRef && !updatingMetrics()) {
- <<%= jhiPrefixDashed %>-jvm-memory class="col-md-4" [updating]="updatingMetrics()" [jvmMemoryMetrics]="metrics()?.jvm">-jvm-memory> + <<%= jhiPrefixDashed %>-jvm-memory class="col-md-4" [updating]="updatingMetrics()" [jvmMemoryMetrics]="metricsRef.jvm">-jvm-memory> <<%= jhiPrefixDashed %>-jvm-threads class="col-md-4" [threads]="threads()">-jvm-threads> - <<%= jhiPrefixDashed %>-metrics-system class="col-md-4" [updating]="updatingMetrics()" [systemMetrics]="metrics()?.processMetrics">-metrics-system> + <<%= jhiPrefixDashed %>-metrics-system class="col-md-4" [updating]="updatingMetrics()" [systemMetrics]="metricsRef.processMetrics">-metrics-system>
} -@if (metrics() && metricsKeyExists('garbageCollector')) { +@if (metricsRef?.garbageCollector; as metricsRefGarbageCollector) { <<%= jhiPrefixDashed %>-metrics-garbagecollector [updating]="updatingMetrics()" - [garbageCollectorMetrics]="metrics()?.garbageCollector" + [garbageCollectorMetrics]="metricsRefGarbageCollector" >-metrics-garbagecollector> } @@ -48,31 +49,31 @@
__jhiTranslateTag__('metrics.updating')
} -@if (metrics() && metricsKeyExists('http.server.requests')) { +@if (metricsRef?.['http.server.requests']; as metricsRefHttpServerRequests) { <<%= jhiPrefixDashed %>-metrics-request [updating]="updatingMetrics()" - [requestMetrics]="metrics()?.['http.server.requests']" + [requestMetrics]="metricsRefHttpServerRequests" >-metrics-request> } -@if (metrics() && metricsKeyExists('services')) { +@if (metricsRef?.services; as metricsRefServices) { <<%= jhiPrefixDashed %>-metrics-endpoints-requests [updating]="updatingMetrics()" - [endpointsRequestsMetrics]="metrics()?.services" + [endpointsRequestsMetrics]="metricsRefServices" >-metrics-endpoints-requests> } -@if (metrics() && metricsKeyExists('cache')) { +@if (metricsRef?.cache; as metricsRefCache) { <<%= jhiPrefixDashed %>-metrics-cache [updating]="updatingMetrics()" - [cacheMetrics]="metrics()?.cache" + [cacheMetrics]="metricsRefCache" >-metrics-cache> } -@if (metrics() && metricsKeyExistsAndObjectNotEmpty('databases')) { +@if (metricsRef && metricsKeyExistsAndObjectNotEmpty('databases')) { <<%= jhiPrefixDashed %>-metrics-datasource [updating]="updatingMetrics()" - [datasourceMetrics]="metrics()?.databases" + [datasourceMetrics]="metricsRef.databases" >-metrics-datasource> } diff --git a/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.spec.ts.ejs index b7fa0c5120e6..5ad3cb78b836 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.spec.ts.ejs @@ -80,52 +80,6 @@ describe('MetricsComponent', () => { }); }); - describe('metricsKeyExists', () => { - it('should check that metrics key exists', () => { - // GIVEN - comp.metrics.set({ - garbageCollector: { - 'PS Scavenge': { - collectionCount: 0, - collectionTime: 0, - }, - 'PS MarkSweep': { - collectionCount: 0, - collectionTime: 0, - }, - }, - } as unknown as Metrics); - - // WHEN - const garbageCollectorKeyExists = comp.metricsKeyExists('garbageCollector'); - - // THEN - expect(garbageCollectorKeyExists).toBeTruthy(); - }); - - it('should check that metrics key does not exist', () => { - // GIVEN - comp.metrics.set({ - garbageCollector: { - 'PS Scavenge': { - collectionCount: 0, - collectionTime: 0, - }, - 'PS MarkSweep': { - collectionCount: 0, - collectionTime: 0, - }, - }, - } as unknown as Metrics); - - // WHEN - const databasesCollectorKeyExists = comp.metricsKeyExists('databases'); - - // THEN - expect(databasesCollectorKeyExists).toBeFalsy(); - }); - }); - describe('metricsKeyExistsAndObjectNotEmpty', () => { it('should check that metrics key exists and is not empty', () => { // GIVEN diff --git a/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.ts.ejs index 6be36132f99a..2b46008897bd 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.component.ts.ejs @@ -55,8 +55,8 @@ export default class MetricsComponent implements OnInit { threads = signal(undefined); updatingMetrics = signal(true); - private metricsService = inject(MetricsService); - private changeDetector = inject(ChangeDetectorRef); + private readonly metricsService = inject(MetricsService); + private readonly changeDetector = inject(ChangeDetectorRef); ngOnInit(): void { this.refresh(); @@ -72,10 +72,6 @@ export default class MetricsComponent implements OnInit { }); } - metricsKeyExists(key: keyof Metrics): boolean { - return Boolean(this.metrics()?.[key]); - } - metricsKeyExistsAndObjectNotEmpty(key: keyof Metrics): boolean { return Boolean(this.metrics()?.[key] && JSON.stringify(this.metrics()?.[key]) !== '{}'); } diff --git a/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.model.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.model.ts.ejs index bfba0712d3c8..d9ccac40916a 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.model.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.model.ts.ejs @@ -17,10 +17,10 @@ limitations under the License. -%> export interface Metrics { - jvm: { [key: string]: JvmMetrics }; + jvm: Record; databases: Databases; 'http.server.requests': HttpServerRequests; - cache: { [key: string]: CacheMetrics }; + cache: Record; garbageCollector: GarbageCollector; services: Services; processMetrics: ProcessMetrics; @@ -65,7 +65,7 @@ export interface HttpServerRequests { all: { count: number; }; - percode: { [key: string]: MaxMeanCount }; + percode: Record; } export interface MaxMeanCount { @@ -92,11 +92,7 @@ export interface GarbageCollector { classesUnloaded: number; } -export interface Services { - [key: string]: { - [key in HttpMethod]?: MaxMeanCount; - }; -} +export type Services = Record>; export enum HttpMethod { Post = 'POST', diff --git a/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.service.ts.ejs index 5d9197c28500..80e1ffe74b03 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/metrics/metrics.service.ts.ejs @@ -25,8 +25,8 @@ import { Metrics, ThreadDump } from './metrics.model'; @Injectable({ providedIn: 'root' }) export class MetricsService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); getMetrics(): Observable { return this.http.get(this.applicationConfigService.getEndpointFor('management/jhimetrics')); diff --git a/generators/angular/templates/src/main/webapp/app/admin/tracker/tracker.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/tracker/tracker.component.ts.ejs index 7698b388eee2..63f6c42fe9a2 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/tracker/tracker.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/tracker/tracker.component.ts.ejs @@ -33,7 +33,7 @@ export default class TrackerComponent implements OnInit, OnDestroy { activities: TrackerActivity[] = []; subscription?: Subscription; - private trackerService = inject(TrackerService); + private readonly trackerService = inject(TrackerService); showActivity(activity: TrackerActivity): void { let existingActivity = false; diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.ts.ejs index 3a4ad5686492..05ff1a100ca3 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.ts.ejs @@ -33,8 +33,8 @@ import { UserManagementService } from '../service/user-management.service'; export default class UserManagementDeleteDialogComponent { user?: User; - private userService = inject(UserManagementService); - private activeModal = inject(NgbActiveModal); + private readonly userService = inject(UserManagementService); + private readonly activeModal = inject(NgbActiveModal); cancel(): void { this.activeModal.dismiss(); diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts.ejs index a982f7b06e82..d38cefed6d44 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts.ejs @@ -38,7 +38,7 @@ describe('User Management Detail Component', () => { [ { path: '**', - component: UserManagementDetailComponent, + loadComponent: () => import('./user-management-detail.component'), resolve: { user: () => of({ id: <%- tsKeyId %>, diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.html.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.html.ejs index dbf9fa1ebc32..9fd6111bcc06 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.html.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.html.ejs @@ -71,7 +71,7 @@ - @for (user of users(); track trackIdentity) { + @for (user of users(); track trackIdentity(user)) { {{ user.id }} diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts.ejs index c85e5b206975..8863770d6d44 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts.ejs @@ -76,8 +76,8 @@ describe('User Management Component', () => { new HttpResponse({ body: [new User(<%- tsKeyId %>)], headers, - }) - ) + }), + ), ); // WHEN diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.ts.ejs index 1dda325bcbc2..9092829a518c 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/list/user-management.component.ts.ejs @@ -63,13 +63,13 @@ export default class UserManagementComponent implements OnInit { sortState = sortStateSignal({}); <%_ } _%> - private userService = inject(UserManagementService); + private readonly userService = inject(UserManagementService); <%_ if (!databaseTypeCassandra) { _%> - private activatedRoute = inject(ActivatedRoute); - private router = inject(Router); - private sortService = inject(SortService); + private readonly activatedRoute = inject(ActivatedRoute); + private readonly router = inject(Router); + private readonly sortService = inject(SortService); <%_ } _%> - private modalService = inject(NgbModal); + private readonly modalService = inject(NgbModal); ngOnInit(): void { <%_ if (databaseTypeCassandra) { _%> @@ -83,7 +83,7 @@ export default class UserManagementComponent implements OnInit { this.userService.update({ ...user, activated: isActivated }).subscribe(() => this.loadAll()); } - trackIdentity(_index: number, item: User): <%= this.getTypescriptKeyType(user.primaryKey.type) %> { + trackIdentity(item: User): <%= this.getTypescriptKeyType(user.primaryKey.type) %> { return item.id!; } @@ -130,7 +130,7 @@ export default class UserManagementComponent implements OnInit { combineLatest([this.activatedRoute.data, this.activatedRoute.queryParamMap]).subscribe(([data, params]) => { const page = params.get('page'); this.page = +(page ?? 1); - this.sortState.set(this.sortService.parseSortParam(params.get(SORT) ?? data['defaultSort'])); + this.sortState.set(this.sortService.parseSortParam(params.get(SORT) ?? data.defaultSort)); this.loadAll(); }); } @@ -138,7 +138,7 @@ export default class UserManagementComponent implements OnInit { private onSuccess(users: User[] | null<% if (!databaseTypeCassandra) { %>, headers: HttpHeaders<% } %>): void { <%_ if (!databaseTypeCassandra) { _%> - this.totalItems.set(Number(headers.get('X-Total-Count'))); + this.totalItems.set(Number(headers.get('X-Total-Count'))); <%_ } _%> this.users.set(users); } diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/service/user-management.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/service/user-management.service.ts.ejs index 5157587dac86..28a4dc9f880b 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/service/user-management.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/service/user-management.service.ts.ejs @@ -30,10 +30,10 @@ import { Authority } from 'app/config/authority.constants'; @Injectable({ providedIn: 'root' }) export class UserManagementService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); - private resourceUrl = this.applicationConfigService.getEndpointFor('api/admin/users'); + private readonly resourceUrl = this.applicationConfigService.getEndpointFor('api/admin/users'); <%_ if (generateUserManagement) { _%> create(user: IUser): Observable { @@ -62,7 +62,7 @@ export class UserManagementService { authorities(): Observable { <%_ if (generateBuiltInAuthorityEntity) { _%> return this.http - .get>(this.applicationConfigService.getEndpointFor('api/authorities')) + .get<{ name: string }[]>(this.applicationConfigService.getEndpointFor('api/authorities')) .pipe(map(authorities => authorities.map(a => a.name))); <%_ } else { _%> return of([Authority.ADMIN, Authority.USER]); diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/update/user-management-update.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/update/user-management-update.component.ts.ejs index bb52560fcc71..fcc98a1a78e2 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/update/user-management-update.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/update/user-management-update.component.ts.ejs @@ -73,8 +73,8 @@ export default class UserManagementUpdateComponent implements OnInit { authorities: new FormControl(userTemplate.authorities, { nonNullable: true }), }); - private userService = inject(UserManagementService); - private route = inject(ActivatedRoute); + private readonly userService = inject(UserManagementService); + private readonly route = inject(ActivatedRoute); ngOnInit(): void { this.route.data.subscribe(({ user }) => { diff --git a/generators/angular/templates/src/main/webapp/app/admin/user-management/user-management.route.ts.ejs b/generators/angular/templates/src/main/webapp/app/admin/user-management/user-management.route.ts.ejs index 12e0e2055e72..dc3a30b84bc9 100644 --- a/generators/angular/templates/src/main/webapp/app/admin/user-management/user-management.route.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/admin/user-management/user-management.route.ts.ejs @@ -22,9 +22,6 @@ import { of } from 'rxjs'; import { IUser } from './user-management.model'; import { UserManagementService } from './service/user-management.service'; -import UserManagementComponent from './list/user-management.component'; -import UserManagementDetailComponent from './detail/user-management-detail.component'; -import UserManagementUpdateComponent from './update/user-management-update.component'; export const userManagementResolve: ResolveFn = (route: ActivatedRouteSnapshot) => { const login = route.paramMap.get('login'); @@ -37,28 +34,28 @@ export const userManagementResolve: ResolveFn = (route: ActivatedR const userManagementRoute: Routes = [ { path: '', - component: UserManagementComponent, + loadComponent: () => import('./list/user-management.component'), data: { defaultSort: 'id,asc', }, }, { path: ':login/view', - component: UserManagementDetailComponent, + loadComponent: () => import('./detail/user-management-detail.component'), resolve: { user: userManagementResolve, }, }, { path: 'new', - component: UserManagementUpdateComponent, + loadComponent: () => import('./update/user-management-update.component'), resolve: { user: userManagementResolve, }, }, { path: ':login/edit', - component: UserManagementUpdateComponent, + loadComponent: () => import('./update/user-management-update.component'), resolve: { user: userManagementResolve, }, diff --git a/generators/angular/templates/src/main/webapp/app/app.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/app.component.ts.ejs index 9d70fb56c1e6..fd500c2519df 100644 --- a/generators/angular/templates/src/main/webapp/app/app.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/app.component.ts.ejs @@ -22,10 +22,7 @@ import dayjs from 'dayjs/esm'; import { FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { NgbDatepickerConfig } from '@ng-bootstrap/ng-bootstrap'; import { provideRouter } from '@angular/router'; -import { registerLocaleData } from '@angular/common'; import locale from '@angular/common/locales/<%= angularLocaleId %>'; -import { FaIconLibrary } from '@fortawesome/angular-fontawesome'; -import dayjs from 'dayjs/esm'; import appRoutes from './app.routes'; // jhipster-needle-angular-add-module-import JHipster will add new module here @@ -49,12 +46,12 @@ import { TrackerService } from './core/tracker/tracker.service'; ], }) export default class AppComponent { - private applicationConfigService = inject(ApplicationConfigService); - private iconLibrary = inject(FaIconLibrary); + private readonly applicationConfigService = inject(ApplicationConfigService); + private readonly iconLibrary = inject(FaIconLibrary); <%_ if (communicationSpringWebsocket) { _%> - private trackerService = inject(TrackerService); + private readonly trackerService = inject(TrackerService); <%_ } _%> - private dpConfig = inject(NgbDatepickerConfig); + private readonly dpConfig = inject(NgbDatepickerConfig); constructor() { <%_ if (communicationSpringWebsocket) { _%> diff --git a/generators/angular/templates/src/main/webapp/app/app.config.ts.ejs b/generators/angular/templates/src/main/webapp/app/app.config.ts.ejs index c818ec74cf74..3c6895468ac4 100644 --- a/generators/angular/templates/src/main/webapp/app/app.config.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/app.config.ts.ejs @@ -36,7 +36,7 @@ import routes from './app.routes'; import { NgbDateDayjsAdapter } from './config/datepicker-adapter'; import { AppPageTitleStrategy } from './app-page-title-strategy'; -const routerFeatures: Array = [ +const routerFeatures: RouterFeatures[] = [ withComponentInputBinding(), withNavigationErrorHandler((e: NavigationError) => { const router = inject(Router); diff --git a/generators/angular/templates/src/main/webapp/app/app.routes.ts.ejs b/generators/angular/templates/src/main/webapp/app/app.routes.ts.ejs index ecf4e5d999b7..f793bf6fafc6 100644 --- a/generators/angular/templates/src/main/webapp/app/app.routes.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/app.routes.ts.ejs @@ -22,11 +22,6 @@ import { Routes } from '@angular/router'; import { errorRoute } from './layouts/error/error.route'; import { Authority } from 'app/config/authority.constants'; -import HomeComponent from './home/home.component'; -import NavbarComponent from './layouts/navbar/navbar.component'; -<%_ if (!authenticationTypeOauth2) { _%> -import LoginComponent from './login/login.component'; -<%_ } _%> <%_ if (applicationTypeGateway && microfrontend) { _%> import { loadEntityRoutes } from './core/microfrontend'; <%_ } _%> @@ -36,12 +31,12 @@ import { UserRouteAccessService } from 'app/core/auth/user-route-access.service' const routes: Routes = [ { path: '', - component: HomeComponent, + loadComponent: () => import('./home/home.component'), title: 'home.title', }, { path: '', - component: NavbarComponent, + loadComponent: () => import('./layouts/navbar/navbar.component'), outlet: 'navbar', }, <%_ if (!applicationTypeMicroservice) { _%> @@ -63,7 +58,7 @@ const routes: Routes = [ <%_ if (!authenticationTypeOauth2) { _%> { path: 'login', - component: LoginComponent, + loadComponent: () => import('./login/login.component'), title: 'login.title', }, <%_ } _%> diff --git a/generators/angular/templates/src/main/webapp/app/config/translation.config.ts.ejs b/generators/angular/templates/src/main/webapp/app/config/translation.config.ts.ejs index 5213fcfda27e..7f763c383a22 100644 --- a/generators/angular/templates/src/main/webapp/app/config/translation.config.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/config/translation.config.ts.ejs @@ -24,7 +24,7 @@ export const translationNotFoundMessage = 'translation-not-found'; export class MissingTranslationHandlerImpl implements MissingTranslationHandler { handle(params: MissingTranslationHandlerParams): string { - const key = params.key; + const { key } = params; return `${translationNotFoundMessage}[${key}]`; } } diff --git a/generators/angular/templates/src/main/webapp/app/core/auth/account.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/auth/account.service.ts.ejs index c7d7133410e9..bcf841ac3941 100644 --- a/generators/angular/templates/src/main/webapp/app/core/auth/account.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/auth/account.service.ts.ejs @@ -31,17 +31,17 @@ import { ApplicationConfigService } from '../config/application-config.service'; @Injectable({ providedIn: 'root' }) export class AccountService { - private userIdentity = signal(null); - private authenticationState = new ReplaySubject(1); + private readonly userIdentity = signal(null); + private readonly authenticationState = new ReplaySubject(1); private accountCache$?: Observable | null; <%_ if (enableTranslation) { _%> - private translateService = inject(TranslateService); + private readonly translateService = inject(TranslateService); <%_ } _%> - private http = inject(HttpClient); - private stateStorageService = inject(StateStorageService); - private router = inject(Router); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly stateStorageService = inject(StateStorageService); + private readonly router = inject(Router); + private readonly applicationConfigService = inject(ApplicationConfigService); <%_ if (generateUserManagement) { _%> save(account: Account): Observable<{}> { diff --git a/generators/angular/templates/src/main/webapp/app/core/auth/auth-jwt.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/auth/auth-jwt.service.ts.ejs index b504852322d7..701ae258af69 100644 --- a/generators/angular/templates/src/main/webapp/app/core/auth/auth-jwt.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/auth/auth-jwt.service.ts.ejs @@ -31,9 +31,9 @@ type JwtToken = { @Injectable({ providedIn: 'root' }) export class AuthServerProvider { - private http = inject(HttpClient); - private stateStorageService = inject(StateStorageService); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly stateStorageService = inject(StateStorageService); + private readonly applicationConfigService = inject(ApplicationConfigService); getToken(): string { return this.stateStorageService.getAuthenticationToken() ?? ''; diff --git a/generators/angular/templates/src/main/webapp/app/core/auth/auth-session.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/auth/auth-session.service.ts.ejs index 4b0416f7118c..6570adcc48ed 100644 --- a/generators/angular/templates/src/main/webapp/app/core/auth/auth-session.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/auth/auth-session.service.ts.ejs @@ -32,8 +32,8 @@ import { Login } from 'app/login/login.model'; @Injectable({ providedIn: 'root' }) export class AuthServerProvider { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); <%_ if (!authenticationTypeOauth2) { _%> diff --git a/generators/angular/templates/src/main/webapp/app/core/auth/csrf.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/auth/csrf.service.ts.ejs index 7cc9a7442274..cf9dc20e3834 100644 --- a/generators/angular/templates/src/main/webapp/app/core/auth/csrf.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/auth/csrf.service.ts.ejs @@ -21,7 +21,7 @@ import { CookieService } from 'ngx-cookie-service'; @Injectable({ providedIn: 'root' }) export class CSRFService { - private cookieService = inject(CookieService); + private readonly cookieService = inject(CookieService); getCSRF(name = 'XSRF-TOKEN'): string { return this.cookieService.get(name); diff --git a/generators/angular/templates/src/main/webapp/app/core/auth/state-storage.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/auth/state-storage.service.ts.ejs index 8291c6d35dc8..2f7919065b1f 100644 --- a/generators/angular/templates/src/main/webapp/app/core/auth/state-storage.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/auth/state-storage.service.ts.ejs @@ -20,10 +20,10 @@ import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class StateStorageService { - private previousUrlKey = 'previousUrl'; - private authenticationKey = '<%= jhiPrefixDashed %>-authenticationToken'; + private readonly previousUrlKey = 'previousUrl'; + private readonly authenticationKey = '<%= jhiPrefixDashed %>-authenticationToken'; <%_ if (enableTranslation) { _%> - private localeKey = 'locale'; + private readonly localeKey = 'locale'; <%_ } _%> storeUrl(url: string): void { diff --git a/generators/angular/templates/src/main/webapp/app/core/auth/user-route-access.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/auth/user-route-access.service.ts.ejs index d487ee8d7471..41c659a96da5 100644 --- a/generators/angular/templates/src/main/webapp/app/core/auth/user-route-access.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/auth/user-route-access.service.ts.ejs @@ -36,7 +36,7 @@ export const UserRouteAccessService: CanActivateFn = (next: ActivatedRouteSnapsh return accountService.identity().pipe( map(account => { if (account) { - const authorities = next.data['authorities']; + const { authorities } = next.data; if (!authorities || authorities.length === 0 || accountService.hasAnyAuthority(authorities)) { return true; @@ -56,6 +56,6 @@ export const UserRouteAccessService: CanActivateFn = (next: ActivatedRouteSnapsh loginService.login(); <%_ } _%> return false; - }) + }), ); }; diff --git a/generators/angular/templates/src/main/webapp/app/core/interceptor/auth-expired.interceptor.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/interceptor/auth-expired.interceptor.ts.ejs index 61d70040ac5f..7de3add2f2d9 100644 --- a/generators/angular/templates/src/main/webapp/app/core/interceptor/auth-expired.interceptor.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/interceptor/auth-expired.interceptor.ts.ejs @@ -51,7 +51,7 @@ export class AuthExpiredInterceptor implements HttpInterceptor { <%_ } _%> } }, - }) + }), ); } } diff --git a/generators/angular/templates/src/main/webapp/app/core/interceptor/error-handler.interceptor.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/interceptor/error-handler.interceptor.ts.ejs index 6e1a22a90cf7..447b5b1d0068 100644 --- a/generators/angular/templates/src/main/webapp/app/core/interceptor/error-handler.interceptor.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/interceptor/error-handler.interceptor.ts.ejs @@ -35,7 +35,7 @@ export class ErrorHandlerInterceptor implements HttpInterceptor { this.eventManager.broadcast(new EventWithContent('<%= frontendAppName %>.httpError', err)); } }, - }) + }), ); } } diff --git a/generators/angular/templates/src/main/webapp/app/core/interceptor/notification.interceptor.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/interceptor/notification.interceptor.ts.ejs index 538c17e17e0e..e7720ff6c520 100644 --- a/generators/angular/templates/src/main/webapp/app/core/interceptor/notification.interceptor.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/interceptor/notification.interceptor.ts.ejs @@ -25,7 +25,7 @@ import { AlertService } from 'app/core/util/alert.service'; @Injectable() export class NotificationInterceptor implements HttpInterceptor { - private alertService = inject(AlertService); + private readonly alertService = inject(AlertService); intercept(request: HttpRequest, next: HttpHandler): Observable> { return next.handle(request).pipe( @@ -58,7 +58,7 @@ export class NotificationInterceptor implements HttpInterceptor { }); } } - }) + }), ); } } diff --git a/generators/angular/templates/src/main/webapp/app/core/tracker/tracker.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/tracker/tracker.service.ts.ejs index f346824ad05b..c7cc088f2dee 100644 --- a/generators/angular/templates/src/main/webapp/app/core/tracker/tracker.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/tracker/tracker.service.ts.ejs @@ -43,14 +43,14 @@ export class TrackerService { private rxStomp?: RxStomp; private routerSubscription: Subscription | null = null; - private router = inject(Router); - private accountService = inject(AccountService); + private readonly router = inject(Router); + private readonly accountService = inject(AccountService); <%_ if (authenticationTypeSession) { _%> - private csrfService = inject(CSRFService); + private readonly csrfService = inject(CSRFService); <%_ } else if (authenticationTypeJwt) { _%> - private authServerProvider = inject(AuthServerProvider); + private readonly authServerProvider = inject(AuthServerProvider); <%_ } _%> - private location = inject(Location); + private readonly location = inject(Location); setup(): void { this.rxStomp = new RxStomp(); diff --git a/generators/angular/templates/src/main/webapp/app/core/util/alert.service.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/util/alert.service.spec.ts.ejs index dc41f189c243..974453e12a09 100644 --- a/generators/angular/templates/src/main/webapp/app/core/util/alert.service.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/util/alert.service.spec.ts.ejs @@ -236,7 +236,7 @@ describe('Alert service test', () => { type: 'success', message: 'Hello Jhipster', position: 'bottom left', - } as Alert) + } as Alert), ); })); @@ -245,7 +245,7 @@ describe('Alert service test', () => { expect.objectContaining({ type: 'danger', message: 'Hello Jhipster', - } as Alert) + } as Alert), ); })); @@ -254,7 +254,7 @@ describe('Alert service test', () => { expect.objectContaining({ type: 'warning', message: 'Hello Jhipster', - } as Alert) + } as Alert), ); })); @@ -263,7 +263,7 @@ describe('Alert service test', () => { expect.objectContaining({ type: 'info', message: 'Hello Jhipster', - } as Alert) + } as Alert), ); })); diff --git a/generators/angular/templates/src/main/webapp/app/core/util/alert.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/util/alert.service.ts.ejs index 3496bb4363bd..5d71a40e91ae 100644 --- a/generators/angular/templates/src/main/webapp/app/core/util/alert.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/util/alert.service.ts.ejs @@ -27,12 +27,12 @@ import { translationNotFoundMessage } from 'app/config/translation.config'; export type AlertType = 'success' | 'danger' | 'warning' | 'info'; export interface Alert { - id?: number; + id: number; type: AlertType; message?: string; <%_ if (enableTranslation) { _%> translationKey?: string; - translationParams?: { [key: string]: unknown }; + translationParams?: Record; <%_ } _%> timeout?: number; toast?: boolean; @@ -52,9 +52,9 @@ export class AlertService { private alertId = 0; private alerts: Alert[] = []; - private sanitizer = inject(DomSanitizer); + private readonly sanitizer = inject(DomSanitizer); <%_ if (enableTranslation) { _%> - private translateService = inject(TranslateService); + private readonly translateService = inject(TranslateService); <%_ } _%> clear(): void { @@ -75,8 +75,8 @@ export class AlertService { * Else adding `alert` to `extAlerts`. * @returns Added alert */ - addAlert(alert: Alert, extAlerts?: Alert[]): Alert { - alert.id = this.alertId++; + addAlert(alertToAdd: Omit, extAlerts?: Alert[]): Alert { + const alert: Alert = { ...alertToAdd, id: this.alertId++ }; <%_ if (enableTranslation) { _%> if (alert.translationKey) { @@ -94,13 +94,13 @@ export class AlertService { alert.timeout = alert.timeout ?? this.timeout; alert.toast = alert.toast ?? this.toast; alert.position = alert.position ?? this.position; - alert.close = (alertsArray: Alert[]) => this.closeAlert(alert.id!, alertsArray); + alert.close = (alertsArray: Alert[]) => this.closeAlert(alert.id, alertsArray); (extAlerts ?? this.alerts).push(alert); if (alert.timeout > 0) { setTimeout(() => { - this.closeAlert(alert.id!, extAlerts ?? this.alerts); + this.closeAlert(alert.id, extAlerts ?? this.alerts); }, alert.timeout); } diff --git a/generators/angular/templates/src/main/webapp/app/core/util/data-util.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/util/data-util.service.ts.ejs index c44e12ba5594..a901917c92bf 100644 --- a/generators/angular/templates/src/main/webapp/app/core/util/data-util.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/util/data-util.service.ts.ejs @@ -89,7 +89,7 @@ export class DataUtils { }; observer.error(error); } else { - const fieldContentType: string = field + 'ContentType'; + const fieldContentType = `${field}ContentType`; this.toBase64(file, (base64Data: string) => { editForm.patchValue({ [field]: base64Data, @@ -143,6 +143,6 @@ export class DataUtils { } private formatAsBytes(size: number): string { - return size.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ') + ' bytes'; // NOSONAR + return `${size.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ')} bytes`; // NOSONAR } } diff --git a/generators/angular/templates/src/main/webapp/app/core/util/operators.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/util/operators.ts.ejs index e6095754fff9..ffc2eb8ffbac 100644 --- a/generators/angular/templates/src/main/webapp/app/core/util/operators.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/util/operators.ts.ejs @@ -20,7 +20,7 @@ * Function used to workaround https://github.com/microsoft/TypeScript/issues/16069 * es2019 alternative `const filteredArr = myArr.flatMap((x) => x ? x : []);` */ -export function isPresent(t: T | undefined | null | void): t is T { +export function isPresent(t: T | undefined | null): t is T { return t !== undefined && t !== null; } diff --git a/generators/angular/templates/src/main/webapp/app/core/util/parse-links.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/core/util/parse-links.service.ts.ejs index 74ee8f6784ff..92c410e4a181 100644 --- a/generators/angular/templates/src/main/webapp/app/core/util/parse-links.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/core/util/parse-links.service.ts.ejs @@ -28,7 +28,7 @@ export class ParseLinks { /** * Method to parse the links */ - parseAll(header: string): { [key: string]: { [key: string]: string | undefined } | undefined } { + parseAll(header: string): Record | undefined> { if (header.length === 0) { throw new Error('input must not be of zero length'); } @@ -46,7 +46,7 @@ export class ParseLinks { } const url: string = section[0].replace(/<(.*)>/, '$1').trim(); // NOSONAR - const queryString: { [key: string]: string } = {}; + const queryString: Record = {}; url.replace(/([^?=&]+)(=([^&]*))?/g, (_$0: string, $1: string | undefined, _$2: string | undefined, $3: string | undefined) => { if ($1 !== undefined && $3 !== undefined) { @@ -64,9 +64,9 @@ export class ParseLinks { /** * Method to parse the links */ - parse(header: string): { [key: string]: number } { + parse(header: string): Record { const sections = this.parseAll(header); - const links: { [key: string]: number } = {}; + const links: Record = {}; for (const [name, queryParams] of Object.entries(sections)) { if (queryParams?.page !== undefined) { links[name] = parseInt(queryParams.page, 10); diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.routes.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.routes.ts.ejs index 237a135ca29b..23dae3119711 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.routes.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.routes.ts.ejs @@ -19,18 +19,13 @@ import { Routes } from '@angular/router'; import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; -import { <%= entityAngularName %>Component } from './list/<%= entityFileName %>.component'; -import { <%= entityAngularName %>DetailComponent } from './detail/<%= entityFileName %>-detail.component'; -<%_ if (!readOnly) { _%> -import { <%= entityAngularName %>UpdateComponent } from './update/<%= entityFileName %>-update.component'; -<%_ } _%> import <%= entityAngularName %>Resolve from './route/<%= entityFileName %>-routing-resolve.service'; import { ASC } from 'app/config/navigation.constants'; const <%= entityInstance %>Route: Routes = [ { path: '', - component: <%= entityAngularName %>Component, + loadComponent: () => import('./list/<%= entityFileName %>.component').then(m => m.<%= entityAngularName %>Component), data: { <%_ if (primaryKey.typeLong && primaryKey.autoGenerate) { _%> defaultSort: '<%- primaryKey.name %>,' + ASC, @@ -39,11 +34,11 @@ const <%= entityInstance %>Route: Routes = [ authorities: [<%- entityAngularReadAuthorities %>], <%_ } _%> }, - canActivate: [UserRouteAccessService] + canActivate: [UserRouteAccessService], }, { path: ':<%= primaryKey.name %>/view', - component: <%= entityAngularName %>DetailComponent, + loadComponent: () => import('./detail/<%= entityFileName %>-detail.component').then(m => m.<%= entityAngularName %>DetailComponent), resolve: { <%= entityInstance %>: <%= entityAngularName %>Resolve }, @@ -57,7 +52,7 @@ const <%= entityInstance %>Route: Routes = [ <%_ if (!readOnly) { _%> { path: 'new', - component: <%= entityAngularName %>UpdateComponent, + loadComponent: () => import('./update/<%= entityFileName %>-update.component').then(m => m.<%= entityAngularName %>UpdateComponent), resolve: { <%= entityInstance %>: <%= entityAngularName %>Resolve }, @@ -72,7 +67,7 @@ const <%= entityInstance %>Route: Routes = [ <%_ if (!readOnly && updatableEntity) { _%> { path: ':<%= primaryKey.name %>/edit', - component: <%= entityAngularName %>UpdateComponent, + loadComponent: () => import('./update/<%= entityFileName %>-update.component').then(m => m.<%= entityAngularName %>UpdateComponent), resolve: { <%= entityInstance %>: <%= entityAngularName %>Resolve }, diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/detail/_entityFile_-detail.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/detail/_entityFile_-detail.component.spec.ts.ejs index fc4265f60883..c595a3049e79 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/detail/_entityFile_-detail.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/detail/_entityFile_-detail.component.spec.ts.ejs @@ -46,7 +46,7 @@ describe('<%= entityAngularName %> Management Detail Component', () => { [ { path: '**', - component: <%= entityAngularName %>DetailComponent, + loadComponent: () => import('./<%= entityFileName %>-detail.component').then(m => m.<%= entityAngularName %>DetailComponent), resolve: { <%= entityInstance %>: () => of(<%- testEntity %>) }, }, ], diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.html.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.html.ejs index 109a5182ff7f..5e92d78a701b 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.html.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.html.ejs @@ -103,7 +103,7 @@ infinite-scroll (scrolled)="loadNextPage()" [infiniteScrollDisabled]="!hasMorePage()" [infiniteScrollDistance]="0"<% } %>> - @for (<%= entityInstance %> of <%= entityInstancePlural %>; track track<%= primaryKey.nameCapitalized %>) { + @for (<%= entityInstance %> of <%= entityInstancePlural %>; track track<%= primaryKey.nameCapitalized %>(<%= entityInstance %>)) { <%_ const routerLink = ` [routerLink]="['/${ entityPage }', ${entityInstance}.${primaryKey.name}, 'view']"`; diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.spec.ts.ejs index 5095e818f588..d1095c54ac79 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.spec.ts.ejs @@ -138,7 +138,7 @@ describe('<%= entityAngularName %> Management Component', () => { it('Should forward to <%= entityInstance %>Service', () => { const entity = <%- this.generateTestEntityPrimaryKey(primaryKey, 0) %>; jest.spyOn(service, 'get<%= entityAngularName %>Identifier'); - const <%= primaryKey.name %> = comp.track<%= primaryKey.nameCapitalized %>(0, entity); + const <%= primaryKey.name %> = comp.track<%= primaryKey.nameCapitalized %>(entity); expect(service.get<%= entityAngularName %>Identifier).toHaveBeenCalledWith(entity); expect(<%= primaryKey.name %>).toBe(entity.<%= primaryKey.name %>); }); diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.ts.ejs index 181dff2d5f9d..145d25635372 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/list/_entityFile_.component.ts.ejs @@ -132,15 +132,15 @@ export class <%= componentName %> implements OnInit { <%- include('pagination-template'); -%> <%_ } else if (paginationInfiniteScroll) { _%> itemsPerPage = ITEMS_PER_PAGE; - links: WritableSignal<{ [key: string]: undefined | { [key: string]: string | undefined } }> = signal({}); + links: WritableSignal>> = signal({}); hasMorePage = computed(() => !!this.links().next); isFirstFetch = computed(() => Object.keys(this.links()).length === 0); <%_ } _%> - public router = inject(Router); - protected <%= entityInstance %>Service = inject(<%= entityAngularName %>Service); - protected activatedRoute = inject(ActivatedRoute); - protected sortService = inject(SortService); + public readonly router = inject(Router); + protected readonly <%= entityInstance %>Service = inject(<%= entityAngularName %>Service); + protected readonly activatedRoute = inject(ActivatedRoute); + protected readonly sortService = inject(SortService); <%_ if (paginationInfiniteScroll) { _%> protected parseLinks = inject(ParseLinks); <%_ } _%> @@ -153,7 +153,7 @@ export class <%= componentName %> implements OnInit { protected ngZone = inject(NgZone); <%_ if (primaryKey) { _%> - track<%= primaryKey.nameCapitalized %> = (_index: number, item: I<%= entityAngularName %>): <%= primaryKey.tsType %> => this.<%= entityInstance %>Service.get<%= entityAngularName %>Identifier(item); + track<%= primaryKey.nameCapitalized %> = (item: I<%= entityAngularName %>): <%= primaryKey.tsType %> => this.<%= entityInstance %>Service.get<%= entityAngularName %>Identifier(item); <%_ } _%> ngOnInit(): void { @@ -302,7 +302,7 @@ export class <%= componentName %> implements OnInit { if (data) { for (const d of data) { <%_ if (primaryKey) { _%> - if (<%= entityInstancePlural %>New.map(op => op.<%= primaryKey.name %>).indexOf(d.<%= primaryKey.name %>) === -1) { + if (<%= entityInstancePlural %>New.some(op => op.<%= primaryKey.name %> === d.<%= primaryKey.name %>)) { <%_ } _%> <%= entityInstancePlural %>New.push(d); <%_ if (primaryKey) { _%> diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/route/_entityFile_-routing-resolve.service.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/route/_entityFile_-routing-resolve.service.spec.ts.ejs index 71f1bfee62c8..3539949394ed 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/route/_entityFile_-routing-resolve.service.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/route/_entityFile_-routing-resolve.service.spec.ts.ejs @@ -91,7 +91,7 @@ describe('<%= entityAngularName %> routing resolve service', () => { }); // THEN - expect(service.find).not.toBeCalled(); + expect(service.find).not.toHaveBeenCalled(); expect(result<%= entityAngularName %>).toEqual(null); }); diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.ts.ejs index da5d45ff66f2..139e798e50d7 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/service/_entityFile_.service.ts.ejs @@ -84,8 +84,8 @@ export type EntityArrayResponseType = HttpResponse[]>; @Injectable({ providedIn: 'root' }) export class <%= entityAngularName %>Service { - protected http = inject(HttpClient); - protected applicationConfigService = inject(ApplicationConfigService); + protected readonly http = inject(HttpClient); + protected readonly applicationConfigService = inject(ApplicationConfigService); protected resourceUrl = this.applicationConfigService.getEndpointFor('api/<%= entityApiUrl %>'<% if ((applicationTypeGateway || applicationTypeMicroservice) && locals.microserviceName) { %>, '<%= microserviceName.toLowerCase() %>'<% } %>); <%_ if (searchEngineAny) { _%> diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs index 42251e49704d..f67cbff56ef9 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs @@ -45,7 +45,7 @@ _%> <% if (field.autoGenerate) { %>@if (editForm.controls.<%= field.fieldName %>.value !== null) {<% } %> - @let <%= fieldName %>Ref = editForm.get('<%= fieldName %>')!; + <% if (field.fieldTypeBinary && !field.blobContentTypeText || field.fieldValidate) { %>@let <%= fieldName %>Ref = editForm.get('<%= fieldName %>')!;<% } %>
<%_ if (field.fieldIsEnum) { _%> diff --git a/generators/angular/templates/src/main/webapp/app/home/home.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/home/home.component.ts.ejs index 505dd237ada6..63b06ccf137e 100644 --- a/generators/angular/templates/src/main/webapp/app/home/home.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/home/home.component.ts.ejs @@ -49,11 +49,11 @@ export default class HomeComponent implements OnInit<% if (!authenticationTypeOa private readonly destroy$ = new Subject(); <%_ } _%> - private accountService = inject(AccountService); + private readonly accountService = inject(AccountService); <%_ if (!authenticationTypeOauth2) { _%> - private router = inject(Router); + private readonly router = inject(Router); <%_ } else { _%> - private loginService = inject(LoginService); + private readonly loginService = inject(LoginService); <%_ } _%> ngOnInit(): void { diff --git a/generators/angular/templates/src/main/webapp/app/layouts/error/error.route.ts.ejs b/generators/angular/templates/src/main/webapp/app/layouts/error/error.route.ts.ejs index ae57e9e0c8db..ac86180daa76 100644 --- a/generators/angular/templates/src/main/webapp/app/layouts/error/error.route.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/layouts/error/error.route.ts.ejs @@ -18,17 +18,15 @@ -%> import { Routes } from '@angular/router'; -import ErrorComponent from './error.component'; - export const errorRoute: Routes = [ { path: 'error', - component: ErrorComponent, + loadComponent: () => import('./error.component'), title: 'error.title', }, { path: 'accessdenied', - component: ErrorComponent, + loadComponent: () => import('./error.component'), data: { errorMessage: 'error.http.403', }, @@ -36,7 +34,7 @@ export const errorRoute: Routes = [ }, { path: '404', - component: ErrorComponent, + loadComponent: () => import('./error.component'), data: { errorMessage: 'error.http.404', }, diff --git a/generators/angular/templates/src/main/webapp/app/layouts/main/main.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/layouts/main/main.component.spec.ts.ejs index 320ef3b7a8a7..a11d9ac0a17f 100644 --- a/generators/angular/templates/src/main/webapp/app/layouts/main/main.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/layouts/main/main.component.spec.ts.ejs @@ -179,7 +179,7 @@ describe('MainComponent', () => { translateService.onLangChange.emit(langChangeEvent); // THEN - expect(document.title).toBe(defaultPageTitle + ' translated'); + expect(document.title).toBe(`${defaultPageTitle} translated`); }); it('should set page title to root route pageTitle if there is no child routes', fakeAsync(() => { @@ -192,7 +192,7 @@ describe('MainComponent', () => { tick(); // THEN - expect(document.title).toBe(parentRoutePageTitle + ' translated'); + expect(document.title).toBe(`${parentRoutePageTitle} translated`); // GIVEN document.title = 'other title'; @@ -201,7 +201,7 @@ describe('MainComponent', () => { translateService.onLangChange.emit(langChangeEvent); // THEN - expect(document.title).toBe(parentRoutePageTitle + ' translated'); + expect(document.title).toBe(`${parentRoutePageTitle} translated`); })); it('should set page title to child route pageTitle if child routes exist and pageTitle is set for child route', fakeAsync(() => { @@ -219,7 +219,7 @@ describe('MainComponent', () => { tick(); // THEN - expect(document.title).toBe(childRoutePageTitle + ' translated'); + expect(document.title).toBe(`${childRoutePageTitle} translated`); // GIVEN document.title = 'other title'; @@ -228,7 +228,7 @@ describe('MainComponent', () => { translateService.onLangChange.emit(langChangeEvent); // THEN - expect(document.title).toBe(childRoutePageTitle + ' translated'); + expect(document.title).toBe(`${childRoutePageTitle} translated`); })); it('should set page title to parent route pageTitle if child routes exists but pageTitle is not set for child route data', fakeAsync(() => { @@ -246,7 +246,7 @@ describe('MainComponent', () => { tick(); // THEN - expect(document.title).toBe(parentRoutePageTitle + ' translated'); + expect(document.title).toBe(`${parentRoutePageTitle} translated`); // GIVEN document.title = 'other title'; @@ -255,7 +255,7 @@ describe('MainComponent', () => { translateService.onLangChange.emit(langChangeEvent); // THEN - expect(document.title).toBe(parentRoutePageTitle + ' translated'); + expect(document.title).toBe(`${parentRoutePageTitle} translated`); })); }); <%_ } _%> @@ -295,6 +295,5 @@ describe('MainComponent', () => { <%_ } _%> }); -@Component({template: ''}) -export class BlankComponent { -} +@Component({ template: '' }) +export class BlankComponent {} diff --git a/generators/angular/templates/src/main/webapp/app/layouts/main/main.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/layouts/main/main.component.ts.ejs index efbc28b6aa6f..42c90c88a2df 100644 --- a/generators/angular/templates/src/main/webapp/app/layouts/main/main.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/layouts/main/main.component.ts.ejs @@ -40,25 +40,25 @@ import PageRibbonComponent from '../profiles/page-ribbon.component'; }) export default class MainComponent implements OnInit { <%_ if (enableTranslation) { _%> - private renderer: Renderer2; + private readonly renderer: Renderer2; <%_ } _%> - private router = inject(Router); - private appPageTitleStrategy = inject(AppPageTitleStrategy); - private accountService = inject(AccountService); + private readonly router = inject(Router); + private readonly appPageTitleStrategy = inject(AppPageTitleStrategy); + private readonly accountService = inject(AccountService); <%_ if (enableI18nRTL) { _%> - private findLanguageFromKeyPipe = inject(FindLanguageFromKeyPipe); + private readonly findLanguageFromKeyPipe = inject(FindLanguageFromKeyPipe); <%_ } _%> <%_ if (enableTranslation) { _%> - private translateService = inject(TranslateService); - private rootRenderer = inject(RendererFactory2); + private readonly translateService = inject(TranslateService); + private readonly rootRenderer = inject(RendererFactory2); <%_ } _%> +<%_ if (enableTranslation) { _%> constructor() { -<%_ if (enableTranslation) { _%> this.renderer = this.rootRenderer.createRenderer(document.querySelector('html'), null); -<%_ } _%> } +<%_ } _%> ngOnInit(): void { // try to log in automatically diff --git a/generators/angular/templates/src/main/webapp/app/layouts/navbar/navbar.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/layouts/navbar/navbar.component.ts.ejs index c512ce976865..8e3173409cc0 100644 --- a/generators/angular/templates/src/main/webapp/app/layouts/navbar/navbar.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/layouts/navbar/navbar.component.ts.ejs @@ -70,19 +70,19 @@ export default class NavbarComponent implements OnInit { <%_ } _%> <%_ } _%> - private loginService = inject(LoginService); + private readonly loginService = inject(LoginService); <%_ if (enableTranslation) { _%> - private translateService = inject(TranslateService); - private stateStorageService = inject(StateStorageService); + private readonly translateService = inject(TranslateService); + private readonly stateStorageService = inject(StateStorageService); <%_ if (applicationTypeGateway && microfrontend) { _%> - private injector = inject(Injector); + private readonly injector = inject(Injector); <%_ } _%> <%_ } _%> <%_ if (applicationTypeGateway && microfrontend) { _%> - private accountService = inject(AccountService); + private readonly accountService = inject(AccountService); <%_ } _%> - private profileService = inject(ProfileService); - private router = inject(Router); + private readonly profileService = inject(ProfileService); + private readonly router = inject(Router); constructor() { if (VERSION) { @@ -150,7 +150,7 @@ export default class NavbarComponent implements OnInit { } <%_ } _%> }, - error => { + (error: unknown) => { // eslint-disable-next-line no-console console.log('Error loading <%= remote.lowercaseBaseName %> entities', error); } diff --git a/generators/angular/templates/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts.ejs index e1b5bfc69aaa..20c7c7715bbd 100644 --- a/generators/angular/templates/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts.ejs @@ -39,7 +39,7 @@ import { ProfileService } from './profile.service'; export default class PageRibbonComponent implements OnInit { ribbonEnv$?: Observable; - private profileService = inject(ProfileService); + private readonly profileService = inject(ProfileService); ngOnInit(): void { this.ribbonEnv$ = this.profileService.getProfileInfo().pipe(map(profileInfo => profileInfo.ribbonEnv)); diff --git a/generators/angular/templates/src/main/webapp/app/layouts/profiles/profile.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/layouts/profiles/profile.service.ts.ejs index ced901fc55d3..38e578133df0 100644 --- a/generators/angular/templates/src/main/webapp/app/layouts/profiles/profile.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/layouts/profiles/profile.service.ts.ejs @@ -26,10 +26,10 @@ import { ProfileInfo, InfoResponse } from './profile-info.model'; @Injectable({ providedIn: 'root' }) export class ProfileService { - private http = inject(HttpClient); - private applicationConfigService = inject(ApplicationConfigService); + private readonly http = inject(HttpClient); + private readonly applicationConfigService = inject(ApplicationConfigService); - private infoUrl = this.applicationConfigService.getEndpointFor('management/info'); + private readonly infoUrl = this.applicationConfigService.getEndpointFor('management/info'); private profileInfo$?: Observable; getProfileInfo(): Observable { diff --git a/generators/angular/templates/src/main/webapp/app/login/login.component.html.ejs b/generators/angular/templates/src/main/webapp/app/login/login.component.html.ejs index 9e7885ee4aa9..95594c59332d 100644 --- a/generators/angular/templates/src/main/webapp/app/login/login.component.html.ejs +++ b/generators/angular/templates/src/main/webapp/app/login/login.component.html.ejs @@ -62,7 +62,9 @@ <%_ if (generateUserManagement) { _%>
diff --git a/generators/angular/templates/src/main/webapp/app/login/login.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/login/login.component.ts.ejs index c0b05205bfbf..dc9440a4e517 100644 --- a/generators/angular/templates/src/main/webapp/app/login/login.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/login/login.component.ts.ejs @@ -41,9 +41,9 @@ export default class LoginComponent implements OnInit, AfterViewInit { rememberMe: new FormControl(false, { nonNullable: true, validators: [Validators.required] }), }); - private accountService = inject(AccountService); - private loginService = inject(LoginService); - private router = inject(Router); + private readonly accountService = inject(AccountService); + private readonly loginService = inject(LoginService); + private readonly router = inject(Router); ngOnInit(): void { // if already authenticated then navigate to home page diff --git a/generators/angular/templates/src/main/webapp/app/login/login.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/login/login.service.ts.ejs index fc639e2db976..ad94be0a867a 100644 --- a/generators/angular/templates/src/main/webapp/app/login/login.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/login/login.service.ts.ejs @@ -44,14 +44,14 @@ import { Login } from './login.model'; @Injectable({ providedIn: 'root' }) export class LoginService { <%_ if (authenticationTypeSession) { _%> - private applicationConfigService = inject(ApplicationConfigService); + private readonly applicationConfigService = inject(ApplicationConfigService); <%_ } _%> <%_ if (authenticationTypeOauth2) { _%> - private location = inject(Location); + private readonly location = inject(Location); <%_ } else { _%> - private accountService = inject(AccountService); + private readonly accountService = inject(AccountService); <%_ } _%> - private authServerProvider = inject(AuthServerProvider); + private readonly authServerProvider = inject(AuthServerProvider); <%_ if (authenticationTypeOauth2) { _%> login(): void { diff --git a/generators/angular/templates/src/main/webapp/app/shared/alert/alert-error.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/alert/alert-error.component.ts.ejs index 3625db8db419..184336c98444 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/alert/alert-error.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/alert/alert-error.component.ts.ejs @@ -40,10 +40,10 @@ export class AlertErrorComponent implements OnDestroy { errorListener: Subscription; httpErrorListener: Subscription; - private alertService = inject(AlertService); - private eventManager = inject(EventManager); + private readonly alertService = inject(AlertService); + private readonly eventManager = inject(EventManager); <% if (enableTranslation) { %> - private translateService = inject(TranslateService); + private readonly translateService = inject(TranslateService); <% } %> constructor() { @@ -57,7 +57,7 @@ export class AlertErrorComponent implements OnDestroy { }); } - setClasses(alert: Alert): { [key: string]: boolean } { + setClasses(alert: Alert): Record { const classes = { 'jhi-toast': Boolean(alert.toast) }; if (alert.position) { return { ...classes, [alert.position]: true }; @@ -74,7 +74,7 @@ export class AlertErrorComponent implements OnDestroy { alert.close?.(this.alerts()); } - private addErrorAlert(message?: string<% if (enableTranslation) { %>, translationKey?: string, translationParams?: { [key: string]: unknown }<% } %>): void { + private addErrorAlert(message?: string<% if (enableTranslation) { %>, translationKey?: string, translationParams?: Record<% } %>): void { this.alertService.addAlert({ type: 'danger', message<% if (enableTranslation) { %>, translationKey, translationParams<% } %> }, this.alerts()); } @@ -138,7 +138,7 @@ export class AlertErrorComponent implements OnDestroy { } private handleFieldsError(httpErrorResponse: HttpErrorResponse): void { - const fieldErrors = httpErrorResponse.error.fieldErrors; + const { fieldErrors } = httpErrorResponse.error; for (const fieldError of fieldErrors) { if (['Min', 'Max', 'DecimalMin', 'DecimalMax'].includes(fieldError.message)) { fieldError.message = 'Size'; diff --git a/generators/angular/templates/src/main/webapp/app/shared/alert/alert-error.model.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/alert/alert-error.model.ts.ejs index 1ee73d99eb50..18e1415dc287 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/alert/alert-error.model.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/alert/alert-error.model.ts.ejs @@ -21,7 +21,7 @@ export class AlertError { public message: string, <%_ if (enableTranslation) { _%> public key?: string, - public params?: { [key: string]: unknown } + public params?: Record <%_ } _%> ) {} } diff --git a/generators/angular/templates/src/main/webapp/app/shared/alert/alert.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/alert/alert.component.ts.ejs index 910bb025ef6d..fec3ec80da53 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/alert/alert.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/alert/alert.component.ts.ejs @@ -31,13 +31,13 @@ import { AlertService, Alert } from 'app/core/util/alert.service'; export class AlertComponent implements OnInit, OnDestroy { alerts = signal([]); - private alertService = inject(AlertService); + private readonly alertService = inject(AlertService); ngOnInit(): void { this.alerts.set(this.alertService.get()); } - setClasses(alert: Alert): { [key: string]: boolean } { + setClasses(alert: Alert): Record { const classes = { 'jhi-toast': Boolean(alert.toast) }; if (alert.position) { return { ...classes, [alert.position]: true }; diff --git a/generators/angular/templates/src/main/webapp/app/shared/auth/has-any-authority.directive.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/auth/has-any-authority.directive.ts.ejs index 268eb3cb8067..a8cab5b40c13 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/auth/has-any-authority.directive.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/auth/has-any-authority.directive.ts.ejs @@ -38,8 +38,8 @@ import { AccountService } from 'app/core/auth/account.service'; export default class HasAnyAuthorityDirective { public authorities = input([], { alias: '<%= jhiPrefix %>HasAnyAuthority' }); - private templateRef = inject(TemplateRef); - private viewContainerRef = inject(ViewContainerRef); + private readonly templateRef = inject(TemplateRef); + private readonly viewContainerRef = inject(ViewContainerRef); constructor() { const accountService = inject(AccountService); diff --git a/generators/angular/templates/src/main/webapp/app/shared/filter/filter.model.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/filter/filter.model.spec.ts.ejs index 41212ee76e8a..22648d3f22c3 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/filter/filter.model.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/filter/filter.model.spec.ts.ejs @@ -81,7 +81,7 @@ describe('FilterModel Tests', () => { filters.clear(); - expect(filters.filterChanges.next).not.toBeCalled(); + expect(filters.filterChanges.next).not.toHaveBeenCalled(); expect(filters.filterOptions).toMatchObject([]); }); it('removes empty filters and emits next element', () => { @@ -128,7 +128,7 @@ describe('FilterModel Tests', () => { const result = filters.addFilter('foo', 'existingFoo1', 'existingFoo2'); expect(result).toBe(false); - expect(filters.filterChanges.next).not.toBeCalled(); + expect(filters.filterChanges.next).not.toHaveBeenCalled(); expect(filters.filterOptions).toMatchObject([{ name: 'foo', values: ['existingFoo1', 'existingFoo2'] }]); }); }); @@ -151,7 +151,7 @@ describe('FilterModel Tests', () => { const result = filters.removeFilter('foo', 'nonExisting1'); expect(result).toBe(false); - expect(filters.filterChanges.next).not.toBeCalled(); + expect(filters.filterChanges.next).not.toHaveBeenCalled(); expect(filters.filterOptions).toMatchObject([{ name: 'foo', values: ['existingFoo1', 'existingFoo2'] }]); }); it("doesn't remove a non existing FilterOptions returns false", () => { @@ -161,7 +161,7 @@ describe('FilterModel Tests', () => { const result = filters.removeFilter('nonExisting', 'nonExisting1'); expect(result).toBe(false); - expect(filters.filterChanges.next).not.toBeCalled(); + expect(filters.filterChanges.next).not.toHaveBeenCalled(); expect(filters.filterOptions).toMatchObject([{ name: 'foo', values: ['existingFoo1', 'existingFoo2'] }]); }); }); diff --git a/generators/angular/templates/src/main/webapp/app/shared/filter/filter.model.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/filter/filter.model.ts.ejs index 794a0c096724..91477220cbcb 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/filter/filter.model.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/filter/filter.model.ts.ejs @@ -26,7 +26,7 @@ export class FilterOption implements IFilterOption { } nameAsQueryParam(): string { - return 'filter[' + this.name + ']'; + return `filter[${this.name}]`; } isSet(): boolean { @@ -67,7 +67,7 @@ export class FilterOption implements IFilterOption { } export class FilterOptions implements IFilterOptions { - readonly filterChanges: Subject = new Subject(); + readonly filterChanges = new Subject(); private _filterOptions: FilterOption[]; constructor(filterOptions: FilterOption[] = []) { @@ -146,8 +146,7 @@ export class FilterOptions implements IFilterOptions { } protected getFilterOptionByName(name: string, add: true): FilterOption; - protected getFilterOptionByName(name: string, add: false): FilterOption | null; - protected getFilterOptionByName(name: string): FilterOption | null; + protected getFilterOptionByName(name: string, add?: false): FilterOption | null; protected getFilterOptionByName(name: string, add = false): FilterOption | null { const addOption = (option: FilterOption): FilterOption => { this._filterOptions.push(option); diff --git a/generators/angular/templates/src/main/webapp/app/shared/language/find-language-from-key.pipe.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/language/find-language-from-key.pipe.ts.ejs index f5889aaa620e..df041844366c 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/language/find-language-from-key.pipe.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/language/find-language-from-key.pipe.ts.ejs @@ -23,7 +23,7 @@ import { Pipe, PipeTransform } from '@angular/core'; name: 'findLanguageFromKey', }) export default class FindLanguageFromKeyPipe implements PipeTransform { - private readonly languages: { [key: string]: { name: string; rtl?: boolean } } = { + private readonly languages: Record = { // jhipster-needle-i18n-language-key-pipe - JHipster will add/remove languages in this object }; diff --git a/generators/angular/templates/src/main/webapp/app/shared/language/translate.directive.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/language/translate.directive.ts.ejs index 1929b205b604..8e48420d3fb4 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/language/translate.directive.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/language/translate.directive.ts.ejs @@ -32,12 +32,12 @@ import { translationNotFoundMessage } from 'app/config/translation.config'; }) export default class TranslateDirective implements OnChanges, OnInit, OnDestroy { @Input() <%= jhiPrefix %>Translate!: string; - @Input() translateValues?: { [key: string]: unknown }; + @Input() translateValues?: Record; private readonly directiveDestroyed = new Subject(); - private el = inject(ElementRef); - private translateService = inject(TranslateService); + private readonly el = inject(ElementRef); + private readonly translateService = inject(TranslateService); ngOnInit(): void { this.translateService.onLangChange.pipe(takeUntil(this.directiveDestroyed)).subscribe(() => { diff --git a/generators/angular/templates/src/main/webapp/app/shared/language/translation.module.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/language/translation.module.ts.ejs index 31f0f57cf558..62d29619b44e 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/language/translation.module.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/language/translation.module.ts.ejs @@ -33,8 +33,8 @@ function lazyTranslatePartialLoader(http: HttpClient): TranslateLoader { TranslateModule.forChild({ loader: { provide: TranslateLoader, - useFactory: (lazyTranslatePartialLoader), - deps: [HttpClient] + useFactory: lazyTranslatePartialLoader, + deps: [HttpClient], }, isolate: false, extend: true, @@ -42,12 +42,12 @@ function lazyTranslatePartialLoader(http: HttpClient): TranslateLoader { ], }) export class LazyTranslationModule { - private translateService = inject(TranslateService); - private translateLoader = inject(TranslateLoader); - private stateStorageService = inject(StateStorageService); + private readonly translateService = inject(TranslateService); + private readonly translateLoader = inject(TranslateLoader); + private readonly stateStorageService = inject(StateStorageService); constructor() { - const currentLang = this.translateService.store.currentLang; + const { currentLang } = this.translateService.store; this.translateLoader.getTranslation(currentLang).subscribe(translation => { this.translateService.setTranslation(currentLang, translation); }); diff --git a/generators/angular/templates/src/main/webapp/app/shared/sort/sort-by.directive.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/sort/sort-by.directive.ts.ejs index a314d3d81c52..b99583fdccec 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/sort/sort-by.directive.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/sort/sort-by.directive.ts.ejs @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. -%> -import { Directive, Host, HostListener, Input, contentChild, effect } from '@angular/core'; +import { Directive, HostListener, Input, contentChild, effect, inject } from '@angular/core'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { faSort, faSortDown, faSortUp, IconDefinition } from '@fortawesome/free-solid-svg-icons'; @@ -35,7 +35,9 @@ export class SortByDirective { protected sortAscIcon = faSortUp; protected sortDescIcon = faSortDown; - constructor(@Host() private sort: SortDirective) { + private readonly sort = inject(SortDirective, { host: true }); + + constructor() { effect(() => { if (this.iconComponent()) { let icon: IconDefinition = this.sortIcon; diff --git a/generators/angular/templates/src/main/webapp/app/shared/sort/sort.service.ts.ejs b/generators/angular/templates/src/main/webapp/app/shared/sort/sort.service.ts.ejs index 4f23e7b2eb36..88d0756a8995 100644 --- a/generators/angular/templates/src/main/webapp/app/shared/sort/sort.service.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/shared/sort/sort.service.ts.ejs @@ -21,7 +21,7 @@ import { SortState } from './sort-state'; @Injectable({ providedIn: 'root' }) export class SortService { - private collator = new Intl.Collator(undefined, { + private readonly collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base', }); diff --git a/generators/angular/templates/src/main/webapp/bootstrap.ts.ejs b/generators/angular/templates/src/main/webapp/bootstrap.ts.ejs index e0ad4c857ef8..ca38b57dba3a 100644 --- a/generators/angular/templates/src/main/webapp/bootstrap.ts.ejs +++ b/generators/angular/templates/src/main/webapp/bootstrap.ts.ejs @@ -31,4 +31,4 @@ if (!DEBUG_INFO_ENABLED) { bootstrapApplication(AppComponent, appConfig) // eslint-disable-next-line no-console .then(() => console.log('Application started')) - .catch(err => console.error(err)); + .catch((err: unknown) => console.error(err)); diff --git a/generators/angular/templates/src/main/webapp/main.ts.ejs b/generators/angular/templates/src/main/webapp/main.ts.ejs index 9f14222e4993..596014f3fbd1 100644 --- a/generators/angular/templates/src/main/webapp/main.ts.ejs +++ b/generators/angular/templates/src/main/webapp/main.ts.ejs @@ -16,4 +16,4 @@ See the License for the specific language governing permissions and limitations under the License. -%> -import('./bootstrap').catch(err => console.error(err)); +import('./bootstrap').catch((err: unknown) => console.error(err)); diff --git a/generators/angular/templates/webpack/environment.js.ejs b/generators/angular/templates/webpack/environment.js.ejs index d02117767c3e..6536851cb965 100644 --- a/generators/angular/templates/webpack/environment.js.ejs +++ b/generators/angular/templates/webpack/environment.js.ejs @@ -1,6 +1,6 @@ module.exports = { I18N_HASH: 'generated_hash', SERVER_API_URL: '', - __VERSION__: process.env.hasOwnProperty('APP_VERSION') ? process.env.APP_VERSION : 'DEV', + __VERSION__: process.env.APP_VERSION || 'DEV', __DEBUG_INFO_ENABLED__: false, }; diff --git a/generators/angular/templates/webpack/webpack.custom.js.ejs b/generators/angular/templates/webpack/webpack.custom.js.ejs index a8051fa7f65a..a6f471ac8449 100644 --- a/generators/angular/templates/webpack/webpack.custom.js.ejs +++ b/generators/angular/templates/webpack/webpack.custom.js.ejs @@ -27,7 +27,7 @@ const postcssRTLCSS = require('postcss-rtlcss'); <%_ } _%> <%_ } _%> const BrowserSyncPlugin = require('browser-sync-webpack-plugin'); -const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; +const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const WebpackNotifierPlugin = require('webpack-notifier'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const ESLintPlugin = require('eslint-webpack-plugin'); @@ -48,16 +48,13 @@ module.exports = async (config, options, targetOptions) => { if (config.mode === 'development') { config.plugins.push( new ESLintPlugin({ - baseConfig: { - parserOptions: { - project: ['../tsconfig.app.json'], - }, - }, + configType: 'flat', + extensions: ['ts', 'js', 'html'], }), new WebpackNotifierPlugin({ title: '<%= humanizedBaseName %>', contentImage: path.join(__dirname, 'logo-jhipster.png'), - }) + }), ); } @@ -81,12 +78,12 @@ module.exports = async (config, options, targetOptions) => { changeOrigin: false, //pass the Host header to the backend unchanged https://github.com/Browsersync/browser-sync/issues/430 }, proxyReq: [ - function(proxyReq) { + function (proxyReq) { // URI that will be retrieved by the ForwardedHeaderFilter on the server side proxyReq.setHeader('X-Forwarded-Host', 'localhost:9000'); proxyReq.setHeader('X-Forwarded-Proto', 'https'); - } - ] + }, + ], }, socket: { clients: { @@ -182,7 +179,7 @@ module.exports = async (config, options, targetOptions) => { ); config = merge( - config + config, // jhipster-needle-add-webpack-config - JHipster will add custom config ); diff --git a/generators/angular/templates/webpack/webpack.microfrontend.js.ejs b/generators/angular/templates/webpack/webpack.microfrontend.js.ejs index 58dbf512ecf7..6e552d9d5702 100644 --- a/generators/angular/templates/webpack/webpack.microfrontend.js.ejs +++ b/generators/angular/templates/webpack/webpack.microfrontend.js.ejs @@ -22,7 +22,6 @@ const packageJson = require('../package.json'); const apiVersion = '0.0.1'; const sharedDefaults = { singleton: true, strictVersion: true, requiredVersion: apiVersion }; -const shareAllDefaults = { ...sharedDefaults, requiredVersion: 'auto' } const shareMappings = (...mappings) => Object.fromEntries(mappings.map(map => [map, { ...sharedDefaults, version: apiVersion }])); const shareDependencies = ({ skipList = [] } = {}) => @@ -39,6 +38,7 @@ sharedDependencies = { 'rxjs/operators': sharedDependencies.rxjs, }; +// eslint-disable-next-line no-unused-vars module.exports = (config, options, targetOptions) => { return withModuleFederationPlugin({ name: '<%= lowercaseBaseName %>', diff --git a/generators/app/__snapshots__/generator.spec.ts.snap b/generators/app/__snapshots__/generator.spec.ts.snap index f97a4a996e3f..d73e17534a1b 100644 --- a/generators/app/__snapshots__/generator.spec.ts.snap +++ b/generators/app/__snapshots__/generator.spec.ts.snap @@ -24,20 +24,18 @@ Options: --force-install Fail on install dependencies error (default: false) --ask-answered Show prompts for already configured options (default: false) --base-name Application base name - --skip-jhipster-dependencies Don't write jhipster dependencies to package.json. + --skip-jhipster-dependencies Don't write jhipster dependencies to package.json. (env: JHI_SKIP_JHIPSTER_DEPENDENCIES) --creation-timestamp Project creation timestamp (used for reproducible builds) --jdl-store JDL store - --skip-commit-hook Skip adding husky commit hooks - --prettier-tab-width Default tab width for prettier + --prettier-tab-width Default tab width for prettier (default: 2) --monorepository Use monorepository + --skip-commit-hook Skip adding husky commit hooks --db Provide DB name for the application when skipping server side generation - --incremental-changelog Creates incremental database changelogs --skip-user-management Skip the user management module during app generation --recreate-initial-changelog Recreate the initial database changelog based on the current config --cache-provider Cache provider --enable-swagger-codegen API first development using OpenAPI-generator --enable-hibernate-cache Enable hibernate cache - --message-broker message broker --search-engine Provide search engine for the application when skipping server side generation --skip-check-length-of-identifier Skip check the length of the identifier, only for recent Oracle databases that support 30+ characters metadata --skip-db-changelog Skip the generation of database migrations @@ -49,13 +47,17 @@ Options: --reactive Generate a reactive backend --service-discovery-type Service discovery type (choices: "consul", "eureka", "no") --auth Provide authentication type for the application when skipping server side generation (choices: "jwt", "oauth2", "session") - --feign-client Generate a feign client + --feign-client Generate a feign client (default: false) --sync-user-with-idp Allow relationships with User for oauth2 applications + --message-broker message broker (choices: "kafka", "pulsar", "no") + --database-migration Database migration (choices: "liquibase") + --graalvm-support Experimental GraalVM Native support --with-generated-flag Add a GeneratedByJHipster annotation to all generated java classes and interfaces --package-name The package name for the generated application - --build Provide build tool for the application when skipping server side generation (choices: "maven", "gradle") - --enable-gradle-enterprise Enable Gradle Enterprise integration + --build Provide build tool for the application when skipping server side generation (default: maven) (choices: "maven", "gradle") + --enable-gradle-enterprise Enable Gradle Enterprise integration (default: false) --gradle-enterprise-host Gradle Enterprise Host + --incremental-changelog Creates incremental database changelogs --dev-database-type Development database --client-framework Provide client framework for the application (choices: "angular", "react", "vue", "no") --microfrontend Enable microfrontend support @@ -63,6 +65,8 @@ Options: --with-admin-ui Generate administrative user interface --client-root-dir Client root --skip-git Skip git repository initialization + --force-git Force commit to git repository + --commit-msg Commit changes (implies forceGit) --cypress-coverage Enable Cypress code coverage report generation --cypress-audit Enable cypress-audit/lighthouse report generation --enable-translation Enable translation @@ -172,6 +176,7 @@ exports[`generator - app jdlStore with incremental changelog application and ent "contents": "application { config { baseName jhipster + incrementalChangelog true skipClient true skipServer true } @@ -197,11 +202,8 @@ exports[`generator - app with default config should match snapshot 1`] = ` "DOCUMENTATION_URL": "https://www.jhipster.tech", "JAVA_COMPATIBLE_VERSIONS": [ "17", - "18", - "19", - "20", "21", - "22", + "23", ], "JAVA_VERSION": "JAVA_VERSION", "LOGIN_REGEX": "^(?>[a-zA-Z0-9!$&*+=?^_\`{|}~.-]+@[a-zA-Z0-9-]+(?:\\\\.[a-zA-Z0-9-]+)*)|(?>[_.@A-Za-z0-9-]+)$", @@ -213,6 +215,8 @@ exports[`generator - app with default config should match snapshot 1`] = ` "SERVER_TEST_SRC_DIR": "src/test/java/", "TEST_DIR": "src/test/", "VUE": "vue", + "addOpenapiGeneratorPlugin": undefined, + "addPrettierExtensions": [Function], "addSpringMilestoneRepository": false, "angularLocaleId": "en", "anyEntityHasRelationshipWithUser": false, @@ -222,6 +226,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "applicationTypeMicroservice": false, "applicationTypeMonolith": true, "authenticationType": "jwt", + "authenticationTypeAny": true, "authenticationTypeJwt": true, "authenticationTypeOauth2": false, "authenticationTypeSession": false, @@ -233,6 +238,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "baseName": "jhipster", "blueprints": [], "buildTool": "maven", + "buildToolAny": true, "buildToolGradle": false, "buildToolMaven": true, "buildToolUnknown": false, @@ -247,10 +253,17 @@ exports[`generator - app with default config should match snapshot 1`] = ` "cacheProviderRedis": false, "camelizedBaseName": "jhipster", "capitalizedBaseName": "Jhipster", + "caret": undefined, + "cjsExtension": ".cjs", + "clientBundler": "webpack", + "clientBundlerAny": true, + "clientBundlerVite": false, + "clientBundlerWebpack": true, "clientDistDir": "target/classes/static/", "clientFramework": "angular", "clientFrameworkAngular": true, "clientFrameworkAny": true, + "clientFrameworkBuiltIn": true, "clientFrameworkNo": false, "clientFrameworkReact": false, "clientFrameworkVue": false, @@ -273,6 +286,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "cypressTests": false, "dasherizedBaseName": "jhipster", "databaseMigration": undefined, + "databaseMigrationAny": undefined, "databaseMigrationLiquibase": true, "databaseType": "sql", "databaseTypeAny": true, @@ -283,10 +297,16 @@ exports[`generator - app with default config should match snapshot 1`] = ` "databaseTypeNo": false, "databaseTypeSql": true, "defaultEnvironment": "prod", + "defaultEnvironmentAny": true, + "defaultEnvironmentDev": false, + "defaultEnvironmentProd": true, "defaultPackaging": "jar", + "defaultPackagingAny": true, + "defaultPackagingJar": true, + "defaultPackagingWar": false, "devDatabaseExtraOptions": "", "devDatabaseName": "jhipster", - "devDatabasePassword": "", + "devDatabasePassword": "password", "devDatabaseType": "postgresql", "devDatabaseTypeH2Any": false, "devDatabaseTypeH2Disk": false, @@ -450,9 +470,9 @@ exports[`generator - app with default config should match snapshot 1`] = ` "com.mycompany.myapp", ], "entitySuffix": "", + "eslintConfigFile": "eslint.config.mjs", "fakerSeed": undefined, - "feignClient": undefined, - "fromInit": undefined, + "feignClient": false, "frontendAppName": "jhipsterApp", "gatewayRoutes": undefined, "gatewayServerPort": undefined, @@ -464,6 +484,9 @@ exports[`generator - app with default config should match snapshot 1`] = ` "generateInMemoryUserCredentials": false, "generateSpringAuditor": true, "generateUserManagement": true, + "githubRepository": undefined, + "githubWorkflows": undefined, + "graalvmSupport": undefined, "gradleEnterpriseHost": undefined, "hipster": "jhipster_family_member_3", "hipsterBugTrackerLink": "https://github.com/jhipster/generator-jhipster/issues?state=open", @@ -484,11 +507,8 @@ exports[`generator - app with default config should match snapshot 1`] = ` "incrementalChangelog": undefined, "javaCompatibleVersions": [ "17", - "18", - "19", - "20", "21", - "22", + "23", ], "javaDependencies": { "archunit-junit5": "'ARCHUNIT-JUNIT-5-VERSION'", @@ -497,6 +517,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "checksum-maven-plugin": "'CHECKSUM-MAVEN-PLUGIN-VERSION'", "common-custom-user-data-gradle-plugin": "'COMMON-CUSTOM-USER-DATA-GRADLE-PLUGIN-VERSION'", "commons-beanutils": "'COMMONS-BEANUTILS-VERSION'", + "couchmove": "'COUCHMOVE-VERSION'", "cucumber-bom": "'CUCUMBER-BOM-VERSION'", "feign-reactor-bom": "'FEIGN-REACTOR-BOM-VERSION'", "frontend-maven-plugin": "'FRONTEND-MAVEN-PLUGIN-VERSION'", @@ -516,6 +537,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "jacoco-maven-plugin": "'JACOCO-MAVEN-PLUGIN-VERSION'", "jhipster-dependabot": "'JHIPSTER-DEPENDABOT-VERSION'", "jib-maven-plugin": "'JIB-MAVEN-PLUGIN-VERSION'", + "jib-spring-boot-extension-maven": "'JIB-SPRING-BOOT-EXTENSION-MAVEN-VERSION'", "lifecycle-mapping": "'LIFECYCLE-MAPPING-VERSION'", "lz4-java": "'LZ-4-JAVA-VERSION'", "mapstruct": "'MAPSTRUCT-VERSION'", @@ -582,6 +604,8 @@ exports[`generator - app with default config should match snapshot 1`] = ` ], "liquibaseAddH2Properties": false, "liquibaseDefaultSchemaName": "", + "listOrFlux": "List", + "listOrFluxClassPath": "java.util.List", "lowercaseBaseName": "jhipster", "mainClass": "JhipsterApp", "mainJavaDir": "src/main/java/", @@ -590,11 +614,12 @@ exports[`generator - app with default config should match snapshot 1`] = ` "messageBroker": "no", "messageBrokerAny": false, "messageBrokerKafka": false, + "messageBrokerNo": true, "messageBrokerPulsar": false, "microfrontend": false, "microfrontends": undefined, + "mjsExtension": ".mjs", "monorepository": undefined, - "monorepositoryRoot": undefined, "nativeLanguage": "en", "nativeLanguageDefinition": { "angularLocale": "en", @@ -611,7 +636,6 @@ exports[`generator - app with default config should match snapshot 1`] = ` "@angular-architects/module-federation-runtime": "ANGULAR_ARCHITECTS_MODULE_FEDERATION_RUNTIME_VERSION", "@angular-builders/custom-webpack": "ANGULAR_BUILDERS_CUSTOM_WEBPACK_VERSION", "@angular-builders/jest": "ANGULAR_BUILDERS_JEST_VERSION", - "@angular-eslint/eslint-plugin": "ANGULAR_ESLINT_ESLINT_PLUGIN_VERSION", "@angular/cli": "ANGULAR_CLI_VERSION", "@angular/common": "ANGULAR_COMMON_VERSION", "@cypress/code-coverage": "CYPRESS_CODE_COVERAGE_VERSION", @@ -626,7 +650,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "@types/jest": "TYPES_JEST_VERSION", "@types/node": "TYPES_NODE_VERSION", "@types/sockjs-client": "TYPES_SOCKJS_CLIENT_VERSION", - "@typescript-eslint/eslint-plugin": "TYPESCRIPT_ESLINT_ESLINT_PLUGIN_VERSION", + "angular-eslint": "ANGULAR_ESLINT_VERSION", "babel-loader": "BABEL_LOADER_VERSION", "babel-plugin-istanbul": "BABEL_PLUGIN_ISTANBUL_VERSION", "bootstrap": "BOOTSTRAP_VERSION", @@ -642,8 +666,10 @@ exports[`generator - app with default config should match snapshot 1`] = ` "eslint": "ESLINT_VERSION", "eslint-config-prettier": "ESLINT_CONFIG_PRETTIER_VERSION", "eslint-plugin-cypress": "ESLINT_PLUGIN_CYPRESS_VERSION", + "eslint-plugin-prettier": "ESLINT_PLUGIN_PRETTIER_VERSION", "eslint-webpack-plugin": "ESLINT_WEBPACK_PLUGIN_VERSION", "folder-hash": "FOLDER_HASH_VERSION", + "globals": "GLOBALS_VERSION", "husky": "HUSKY_VERSION", "jest": "JEST_VERSION", "jest-date-mock": "JEST_DATE_MOCK_VERSION", @@ -668,6 +694,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "ts-jest": "TS_JEST_VERSION", "tslib": "TSLIB_VERSION", "typescript": "TYPESCRIPT_VERSION", + "typescript-eslint": "TYPESCRIPT_ESLINT_VERSION", "wait-on": "WAIT_ON_VERSION", "webpack": "WEBPACK_VERSION", "webpack-bundle-analyzer": "WEBPACK_BUNDLE_ANALYZER_VERSION", @@ -677,6 +704,9 @@ exports[`generator - app with default config should match snapshot 1`] = ` }, "nodePackageManager": "npm", "nodeVersion": "NODE_VERSION", + "optionalOrMono": "Optional", + "optionalOrMonoClassPath": "java.util.Optional", + "optionalOrMonoOfNullable": "Optional.ofNullable", "packageFolder": "com/mycompany/myapp/", "packageInfoJavadocs": [ { @@ -716,10 +746,16 @@ exports[`generator - app with default config should match snapshot 1`] = ` "packageName": "com.mycompany.myapp.web.rest.vm", }, ], + "packageJsonNodeEngine": undefined, + "packageJsonScripts": {}, + "packageJsonType": "commonjs", + "packageJsonTypeAny": true, + "packageJsonTypeCommonjs": true, + "packageJsonTypeModule": false, "packageName": "com.mycompany.myapp", "pages": [], - "prettierConfigFile": ".prettierrc", - "prettierExtensions": "md,json,yml,html,cjs,mjs,js,ts,tsx,css,scss,java", + "prettierExtensions": "md,json,yml,js,cjs,mjs,ts,cts,mts,java,html,css,scss", + "prettierFolders": ",**/", "prettierJava": undefined, "prettierTabWidth": 2, "prodDatabaseDriver": { @@ -731,11 +767,17 @@ exports[`generator - app with default config should match snapshot 1`] = ` "artifactId": "r2dbc-postgresql", "groupId": "org.postgresql", }, + "testContainer": { + "artifactId": "postgresql", + "groupId": "org.testcontainers", + "scope": "test", + }, }, "prodDatabaseExtraOptions": "", "prodDatabaseName": "jhipster", - "prodDatabasePassword": "", + "prodDatabasePassword": "password", "prodDatabaseType": "postgresql", + "prodDatabaseTypeAny": true, "prodDatabaseTypeMariadb": false, "prodDatabaseTypeMssql": false, "prodDatabaseTypeMysql": false, @@ -753,6 +795,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "reactorBlockOptional": "", "rememberMeKey": undefined, "requiresDeleteAllUsers": false, + "routes": undefined, "searchEngine": "no", "searchEngineAny": false, "searchEngineCouchbase": false, @@ -762,7 +805,12 @@ exports[`generator - app with default config should match snapshot 1`] = ` "serviceDiscoveryAny": false, "serviceDiscoveryConsul": false, "serviceDiscoveryEureka": false, + "serviceDiscoveryNo": true, "serviceDiscoveryType": "no", + "serviceDiscoveryTypeAny": undefined, + "serviceDiscoveryTypeConsul": undefined, + "serviceDiscoveryTypeEureka": undefined, + "serviceDiscoveryTypeNo": undefined, "skipCheckLengthOfIdentifier": false, "skipClient": undefined, "skipCommitHook": undefined, @@ -770,7 +818,6 @@ exports[`generator - app with default config should match snapshot 1`] = ` "skipJhipsterDependencies": undefined, "skipServer": undefined, "skipUserManagement": false, - "sortMavenPom": undefined, "springBootDependencies": Any, "srcMainDir": "src/main/", "srcMainJava": "src/main/java/", @@ -786,6 +833,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "testJavaDir": "src/test/java/", "testJavaPackageDir": "src/test/java/com/mycompany/myapp/", "testResourceDir": "src/test/resources/", + "typescriptEslint": true, "upperFirstCamelCaseBaseName": "Jhipster", "useNpmWrapper": true, "user": Any, @@ -794,6 +842,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "webappLoginRegExp": "^[a-zA-Z0-9!$&*+=?^_\`{|}~.-]+@[a-zA-Z0-9-]+(?:\\\\.[a-zA-Z0-9-]+)*$|^[_.@A-Za-z0-9-]+$", "websocket": "no", "withAdminUi": true, + "wrapMono": [Function], } `; @@ -805,11 +854,8 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "DOCUMENTATION_URL": "https://www.jhipster.tech", "JAVA_COMPATIBLE_VERSIONS": [ "17", - "18", - "19", - "20", "21", - "22", + "23", ], "JAVA_VERSION": "JAVA_VERSION", "LOGIN_REGEX": "^(?>[a-zA-Z0-9!$&*+=?^_\`{|}~.-]+@[a-zA-Z0-9-]+(?:\\\\.[a-zA-Z0-9-]+)*)|(?>[_.@A-Za-z0-9-]+)$", @@ -821,6 +867,8 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "SERVER_TEST_SRC_DIR": "src/test/java/", "TEST_DIR": "src/test/", "VUE": "vue", + "addOpenapiGeneratorPlugin": undefined, + "addPrettierExtensions": [Function], "addSpringMilestoneRepository": false, "angularLocaleId": "en", "anyEntityHasRelationshipWithUser": false, @@ -830,6 +878,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "applicationTypeMicroservice": false, "applicationTypeMonolith": false, "authenticationType": "jwt", + "authenticationTypeAny": true, "authenticationTypeJwt": true, "authenticationTypeOauth2": false, "authenticationTypeSession": false, @@ -841,6 +890,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "baseName": "jhipster", "blueprints": [], "buildTool": "maven", + "buildToolAny": true, "buildToolGradle": false, "buildToolMaven": true, "buildToolUnknown": false, @@ -855,10 +905,17 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "cacheProviderRedis": false, "camelizedBaseName": "jhipster", "capitalizedBaseName": "Jhipster", + "caret": undefined, + "cjsExtension": ".cjs", + "clientBundler": "webpack", + "clientBundlerAny": true, + "clientBundlerVite": false, + "clientBundlerWebpack": true, "clientDistDir": "target/classes/static/", "clientFramework": "angular", "clientFrameworkAngular": true, "clientFrameworkAny": true, + "clientFrameworkBuiltIn": true, "clientFrameworkNo": false, "clientFrameworkReact": false, "clientFrameworkVue": false, @@ -881,6 +938,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "cypressTests": false, "dasherizedBaseName": "jhipster", "databaseMigration": undefined, + "databaseMigrationAny": undefined, "databaseMigrationLiquibase": true, "databaseType": "sql", "databaseTypeAny": true, @@ -891,10 +949,16 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "databaseTypeNo": false, "databaseTypeSql": true, "defaultEnvironment": "prod", + "defaultEnvironmentAny": true, + "defaultEnvironmentDev": false, + "defaultEnvironmentProd": true, "defaultPackaging": "jar", + "defaultPackagingAny": true, + "defaultPackagingJar": true, + "defaultPackagingWar": false, "devDatabaseExtraOptions": "", "devDatabaseName": "jhipster", - "devDatabasePassword": "", + "devDatabasePassword": "password", "devDatabaseType": "postgresql", "devDatabaseTypeH2Any": false, "devDatabaseTypeH2Disk": false, @@ -1060,9 +1124,9 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "com.mycompany.myapp", ], "entitySuffix": "", + "eslintConfigFile": "eslint.config.mjs", "fakerSeed": undefined, - "feignClient": undefined, - "fromInit": undefined, + "feignClient": false, "frontendAppName": "jhipsterApp", "gatewayRoutes": [], "gatewayServerPort": undefined, @@ -1074,6 +1138,9 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "generateInMemoryUserCredentials": false, "generateSpringAuditor": true, "generateUserManagement": true, + "githubRepository": undefined, + "githubWorkflows": undefined, + "graalvmSupport": undefined, "gradleEnterpriseHost": undefined, "hipster": "jhipster_family_member_3", "hipsterBugTrackerLink": "https://github.com/jhipster/generator-jhipster/issues?state=open", @@ -1094,11 +1161,8 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "incrementalChangelog": undefined, "javaCompatibleVersions": [ "17", - "18", - "19", - "20", "21", - "22", + "23", ], "javaDependencies": { "archunit-junit5": "'ARCHUNIT-JUNIT-5-VERSION'", @@ -1107,6 +1171,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "checksum-maven-plugin": "'CHECKSUM-MAVEN-PLUGIN-VERSION'", "common-custom-user-data-gradle-plugin": "'COMMON-CUSTOM-USER-DATA-GRADLE-PLUGIN-VERSION'", "commons-beanutils": "'COMMONS-BEANUTILS-VERSION'", + "couchmove": "'COUCHMOVE-VERSION'", "cucumber-bom": "'CUCUMBER-BOM-VERSION'", "feign-reactor-bom": "'FEIGN-REACTOR-BOM-VERSION'", "frontend-maven-plugin": "'FRONTEND-MAVEN-PLUGIN-VERSION'", @@ -1124,6 +1189,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "jacoco-maven-plugin": "'JACOCO-MAVEN-PLUGIN-VERSION'", "jhipster-dependabot": "'JHIPSTER-DEPENDABOT-VERSION'", "jib-maven-plugin": "'JIB-MAVEN-PLUGIN-VERSION'", + "jib-spring-boot-extension-maven": "'JIB-SPRING-BOOT-EXTENSION-MAVEN-VERSION'", "lifecycle-mapping": "'LIFECYCLE-MAPPING-VERSION'", "lz4-java": "'LZ-4-JAVA-VERSION'", "mapstruct": "'MAPSTRUCT-VERSION'", @@ -1186,6 +1252,8 @@ exports[`generator - app with gateway should match snapshot 1`] = ` ], "liquibaseAddH2Properties": false, "liquibaseDefaultSchemaName": "", + "listOrFlux": "Flux", + "listOrFluxClassPath": "reactor.core.publisher.Flux", "lowercaseBaseName": "jhipster", "mainClass": "JhipsterApp", "mainJavaDir": "src/main/java/", @@ -1194,11 +1262,12 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "messageBroker": "no", "messageBrokerAny": false, "messageBrokerKafka": false, + "messageBrokerNo": true, "messageBrokerPulsar": false, "microfrontend": undefined, "microfrontends": undefined, + "mjsExtension": ".mjs", "monorepository": undefined, - "monorepositoryRoot": undefined, "nativeLanguage": "en", "nativeLanguageDefinition": { "angularLocale": "en", @@ -1215,7 +1284,6 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "@angular-architects/module-federation-runtime": "ANGULAR_ARCHITECTS_MODULE_FEDERATION_RUNTIME_VERSION", "@angular-builders/custom-webpack": "ANGULAR_BUILDERS_CUSTOM_WEBPACK_VERSION", "@angular-builders/jest": "ANGULAR_BUILDERS_JEST_VERSION", - "@angular-eslint/eslint-plugin": "ANGULAR_ESLINT_ESLINT_PLUGIN_VERSION", "@angular/cli": "ANGULAR_CLI_VERSION", "@angular/common": "ANGULAR_COMMON_VERSION", "@cypress/code-coverage": "CYPRESS_CODE_COVERAGE_VERSION", @@ -1230,7 +1298,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "@types/jest": "TYPES_JEST_VERSION", "@types/node": "TYPES_NODE_VERSION", "@types/sockjs-client": "TYPES_SOCKJS_CLIENT_VERSION", - "@typescript-eslint/eslint-plugin": "TYPESCRIPT_ESLINT_ESLINT_PLUGIN_VERSION", + "angular-eslint": "ANGULAR_ESLINT_VERSION", "babel-loader": "BABEL_LOADER_VERSION", "babel-plugin-istanbul": "BABEL_PLUGIN_ISTANBUL_VERSION", "bootstrap": "BOOTSTRAP_VERSION", @@ -1246,8 +1314,10 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "eslint": "ESLINT_VERSION", "eslint-config-prettier": "ESLINT_CONFIG_PRETTIER_VERSION", "eslint-plugin-cypress": "ESLINT_PLUGIN_CYPRESS_VERSION", + "eslint-plugin-prettier": "ESLINT_PLUGIN_PRETTIER_VERSION", "eslint-webpack-plugin": "ESLINT_WEBPACK_PLUGIN_VERSION", "folder-hash": "FOLDER_HASH_VERSION", + "globals": "GLOBALS_VERSION", "husky": "HUSKY_VERSION", "jest": "JEST_VERSION", "jest-date-mock": "JEST_DATE_MOCK_VERSION", @@ -1272,6 +1342,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "ts-jest": "TS_JEST_VERSION", "tslib": "TSLIB_VERSION", "typescript": "TYPESCRIPT_VERSION", + "typescript-eslint": "TYPESCRIPT_ESLINT_VERSION", "wait-on": "WAIT_ON_VERSION", "webpack": "WEBPACK_VERSION", "webpack-bundle-analyzer": "WEBPACK_BUNDLE_ANALYZER_VERSION", @@ -1281,6 +1352,9 @@ exports[`generator - app with gateway should match snapshot 1`] = ` }, "nodePackageManager": "npm", "nodeVersion": "NODE_VERSION", + "optionalOrMono": "Mono", + "optionalOrMonoClassPath": "reactor.core.publisher.Mono", + "optionalOrMonoOfNullable": "Mono.justOrEmpty", "packageFolder": "com/mycompany/myapp/", "packageInfoJavadocs": [ { @@ -1320,10 +1394,16 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "packageName": "com.mycompany.myapp.web.rest.vm", }, ], + "packageJsonNodeEngine": undefined, + "packageJsonScripts": {}, + "packageJsonType": "commonjs", + "packageJsonTypeAny": true, + "packageJsonTypeCommonjs": true, + "packageJsonTypeModule": false, "packageName": "com.mycompany.myapp", "pages": [], - "prettierConfigFile": ".prettierrc", - "prettierExtensions": "md,json,yml,html,cjs,mjs,js,ts,tsx,css,scss,java", + "prettierExtensions": "md,json,yml,js,cjs,mjs,ts,cts,mts,java,html,css,scss", + "prettierFolders": ",**/", "prettierJava": undefined, "prettierTabWidth": 2, "prodDatabaseDriver": { @@ -1335,11 +1415,17 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "artifactId": "r2dbc-postgresql", "groupId": "org.postgresql", }, + "testContainer": { + "artifactId": "postgresql", + "groupId": "org.testcontainers", + "scope": "test", + }, }, "prodDatabaseExtraOptions": "", "prodDatabaseName": "jhipster", - "prodDatabasePassword": "", + "prodDatabasePassword": "password", "prodDatabaseType": "postgresql", + "prodDatabaseTypeAny": true, "prodDatabaseTypeMariadb": false, "prodDatabaseTypeMssql": false, "prodDatabaseTypeMysql": false, @@ -1368,7 +1454,12 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "serviceDiscoveryAny": true, "serviceDiscoveryConsul": true, "serviceDiscoveryEureka": false, + "serviceDiscoveryNo": false, "serviceDiscoveryType": "consul", + "serviceDiscoveryTypeAny": undefined, + "serviceDiscoveryTypeConsul": undefined, + "serviceDiscoveryTypeEureka": undefined, + "serviceDiscoveryTypeNo": undefined, "skipCheckLengthOfIdentifier": false, "skipClient": undefined, "skipCommitHook": undefined, @@ -1376,7 +1467,6 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "skipJhipsterDependencies": undefined, "skipServer": undefined, "skipUserManagement": false, - "sortMavenPom": undefined, "springBootDependencies": Any, "srcMainDir": "src/main/", "srcMainJava": "src/main/java/", @@ -1392,6 +1482,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "testJavaDir": "src/test/java/", "testJavaPackageDir": "src/test/java/com/mycompany/myapp/", "testResourceDir": "src/test/resources/", + "typescriptEslint": true, "upperFirstCamelCaseBaseName": "Jhipster", "useNpmWrapper": true, "user": Any, @@ -1400,6 +1491,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "webappLoginRegExp": "^[a-zA-Z0-9!$&*+=?^_\`{|}~.-]+@[a-zA-Z0-9-]+(?:\\\\.[a-zA-Z0-9-]+)*$|^[_.@A-Za-z0-9-]+$", "websocket": "no", "withAdminUi": true, + "wrapMono": [Function], } `; @@ -1411,11 +1503,8 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "DOCUMENTATION_URL": "https://www.jhipster.tech", "JAVA_COMPATIBLE_VERSIONS": [ "17", - "18", - "19", - "20", "21", - "22", + "23", ], "JAVA_VERSION": "JAVA_VERSION", "LOGIN_REGEX": "^(?>[a-zA-Z0-9!$&*+=?^_\`{|}~.-]+@[a-zA-Z0-9-]+(?:\\\\.[a-zA-Z0-9-]+)*)|(?>[_.@A-Za-z0-9-]+)$", @@ -1427,6 +1516,8 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "SERVER_TEST_SRC_DIR": "src/test/java/", "TEST_DIR": "src/test/", "VUE": "vue", + "addOpenapiGeneratorPlugin": undefined, + "addPrettierExtensions": [Function], "addSpringMilestoneRepository": false, "anyEntityHasRelationshipWithUser": false, "applicationType": "microservice", @@ -1435,6 +1526,7 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "applicationTypeMicroservice": true, "applicationTypeMonolith": false, "authenticationType": "jwt", + "authenticationTypeAny": true, "authenticationTypeJwt": true, "authenticationTypeOauth2": false, "authenticationTypeSession": false, @@ -1445,6 +1537,7 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "baseName": "jhipster", "blueprints": [], "buildTool": "maven", + "buildToolAny": true, "buildToolGradle": false, "buildToolMaven": true, "buildToolUnknown": false, @@ -1459,10 +1552,17 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "cacheProviderRedis": false, "camelizedBaseName": "jhipster", "capitalizedBaseName": "Jhipster", + "caret": undefined, + "cjsExtension": ".cjs", + "clientBundler": undefined, + "clientBundlerAny": true, + "clientBundlerVite": false, + "clientBundlerWebpack": false, "clientDistDir": "target/classes/static/", "clientFramework": "no", "clientFrameworkAngular": false, "clientFrameworkAny": false, + "clientFrameworkBuiltIn": false, "clientFrameworkNo": true, "clientFrameworkReact": false, "clientFrameworkVue": false, @@ -1485,6 +1585,7 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "cypressTests": false, "dasherizedBaseName": "jhipster", "databaseMigration": undefined, + "databaseMigrationAny": undefined, "databaseMigrationLiquibase": true, "databaseType": "sql", "databaseTypeAny": true, @@ -1495,10 +1596,16 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "databaseTypeNo": false, "databaseTypeSql": true, "defaultEnvironment": "prod", + "defaultEnvironmentAny": true, + "defaultEnvironmentDev": false, + "defaultEnvironmentProd": true, "defaultPackaging": "jar", + "defaultPackagingAny": true, + "defaultPackagingJar": true, + "defaultPackagingWar": false, "devDatabaseExtraOptions": "", "devDatabaseName": "jhipster", - "devDatabasePassword": "", + "devDatabasePassword": "password", "devDatabaseType": "postgresql", "devDatabaseTypeH2Any": false, "devDatabaseTypeH2Disk": false, @@ -1666,8 +1773,7 @@ exports[`generator - app with microservice should match snapshot 1`] = ` ], "entitySuffix": "", "fakerSeed": undefined, - "feignClient": undefined, - "fromInit": undefined, + "feignClient": false, "frontendAppName": "jhipsterApp", "gatewayRoutes": undefined, "gatewayServerPort": undefined, @@ -1679,6 +1785,9 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "generateInMemoryUserCredentials": false, "generateSpringAuditor": true, "generateUserManagement": false, + "githubRepository": undefined, + "githubWorkflows": undefined, + "graalvmSupport": undefined, "gradleEnterpriseHost": undefined, "hipster": "jhipster_family_member_3", "hipsterBugTrackerLink": "https://github.com/jhipster/generator-jhipster/issues?state=open", @@ -1699,11 +1808,8 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "incrementalChangelog": undefined, "javaCompatibleVersions": [ "17", - "18", - "19", - "20", "21", - "22", + "23", ], "javaDependencies": { "archunit-junit5": "'ARCHUNIT-JUNIT-5-VERSION'", @@ -1712,6 +1818,7 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "checksum-maven-plugin": "'CHECKSUM-MAVEN-PLUGIN-VERSION'", "common-custom-user-data-gradle-plugin": "'COMMON-CUSTOM-USER-DATA-GRADLE-PLUGIN-VERSION'", "commons-beanutils": "'COMMONS-BEANUTILS-VERSION'", + "couchmove": "'COUCHMOVE-VERSION'", "cucumber-bom": "'CUCUMBER-BOM-VERSION'", "feign-reactor-bom": "'FEIGN-REACTOR-BOM-VERSION'", "frontend-maven-plugin": "'FRONTEND-MAVEN-PLUGIN-VERSION'", @@ -1731,6 +1838,7 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "jacoco-maven-plugin": "'JACOCO-MAVEN-PLUGIN-VERSION'", "jhipster-dependabot": "'JHIPSTER-DEPENDABOT-VERSION'", "jib-maven-plugin": "'JIB-MAVEN-PLUGIN-VERSION'", + "jib-spring-boot-extension-maven": "'JIB-SPRING-BOOT-EXTENSION-MAVEN-VERSION'", "lifecycle-mapping": "'LIFECYCLE-MAPPING-VERSION'", "lz4-java": "'LZ-4-JAVA-VERSION'", "mapstruct": "'MAPSTRUCT-VERSION'", @@ -1797,6 +1905,8 @@ exports[`generator - app with microservice should match snapshot 1`] = ` ], "liquibaseAddH2Properties": false, "liquibaseDefaultSchemaName": "", + "listOrFlux": "List", + "listOrFluxClassPath": "java.util.List", "lowercaseBaseName": "jhipster", "mainClass": "JhipsterApp", "mainJavaDir": "src/main/java/", @@ -1805,11 +1915,12 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "messageBroker": "no", "messageBrokerAny": false, "messageBrokerKafka": false, + "messageBrokerNo": true, "messageBrokerPulsar": false, "microfrontend": false, "microfrontends": undefined, + "mjsExtension": ".mjs", "monorepository": undefined, - "monorepositoryRoot": undefined, "nativeLanguage": "en", "nativeLanguageDefinition": { "angularLocale": "en", @@ -1823,6 +1934,8 @@ exports[`generator - app with microservice should match snapshot 1`] = ` }, "nodeDependencies": { "concurrently": "CONCURRENTLY_VERSION", + "eslint-config-prettier": "ESLINT_CONFIG_PRETTIER_VERSION", + "eslint-plugin-prettier": "ESLINT_PLUGIN_PRETTIER_VERSION", "husky": "HUSKY_VERSION", "lint-staged": "LINT_STAGED_VERSION", "npm": "NPM_VERSION", @@ -1833,6 +1946,9 @@ exports[`generator - app with microservice should match snapshot 1`] = ` }, "nodePackageManager": "npm", "nodeVersion": "NODE_VERSION", + "optionalOrMono": "Optional", + "optionalOrMonoClassPath": "java.util.Optional", + "optionalOrMonoOfNullable": "Optional.ofNullable", "packageFolder": "com/mycompany/myapp/", "packageInfoJavadocs": [ { @@ -1872,10 +1988,16 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "packageName": "com.mycompany.myapp.web.rest.vm", }, ], + "packageJsonNodeEngine": undefined, + "packageJsonScripts": {}, + "packageJsonType": "commonjs", + "packageJsonTypeAny": true, + "packageJsonTypeCommonjs": true, + "packageJsonTypeModule": false, "packageName": "com.mycompany.myapp", "pages": [], - "prettierConfigFile": ".prettierrc", - "prettierExtensions": "md,json,yml,html,java", + "prettierExtensions": "md,json,yml,js,cjs,mjs,ts,cts,mts,java", + "prettierFolders": ",**/", "prettierJava": undefined, "prettierTabWidth": 2, "prodDatabaseDriver": { @@ -1887,11 +2009,17 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "artifactId": "r2dbc-postgresql", "groupId": "org.postgresql", }, + "testContainer": { + "artifactId": "postgresql", + "groupId": "org.testcontainers", + "scope": "test", + }, }, "prodDatabaseExtraOptions": "", "prodDatabaseName": "jhipster", - "prodDatabasePassword": "", + "prodDatabasePassword": "password", "prodDatabaseType": "postgresql", + "prodDatabaseTypeAny": true, "prodDatabaseTypeMariadb": false, "prodDatabaseTypeMssql": false, "prodDatabaseTypeMysql": false, @@ -1909,6 +2037,7 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "reactorBlockOptional": "", "rememberMeKey": undefined, "requiresDeleteAllUsers": false, + "routes": undefined, "searchEngine": "no", "searchEngineAny": false, "searchEngineCouchbase": false, @@ -1918,7 +2047,12 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "serviceDiscoveryAny": true, "serviceDiscoveryConsul": true, "serviceDiscoveryEureka": false, + "serviceDiscoveryNo": false, "serviceDiscoveryType": "consul", + "serviceDiscoveryTypeAny": undefined, + "serviceDiscoveryTypeConsul": undefined, + "serviceDiscoveryTypeEureka": undefined, + "serviceDiscoveryTypeNo": undefined, "skipCheckLengthOfIdentifier": false, "skipClient": true, "skipCommitHook": undefined, @@ -1926,7 +2060,6 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "skipJhipsterDependencies": undefined, "skipServer": undefined, "skipUserManagement": true, - "sortMavenPom": undefined, "springBootDependencies": Any, "srcMainDir": "src/main/", "srcMainJava": "src/main/java/", @@ -1946,5 +2079,6 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "useNpmWrapper": false, "websocket": "no", "withAdminUi": false, + "wrapMono": [Function], } `; diff --git a/generators/app/cleanup.js b/generators/app/cleanup.ts similarity index 87% rename from generators/app/cleanup.js rename to generators/app/cleanup.ts index 907bcb6f359c..823691e0de93 100644 --- a/generators/app/cleanup.js +++ b/generators/app/cleanup.ts @@ -17,13 +17,15 @@ * limitations under the License. */ +import { asWritingTask } from '../base-application/support/index.js'; + /** * Removes files that where generated in previous JHipster versions and therefore * need to be removed. */ -export default function cleanupOldFilesTask() { +export default asWritingTask(function cleanupOldFilesTask() { if (this.isJhipsterVersionLessThan('6.1.0')) { this.config.delete('blueprint'); this.config.delete('blueprintVersion'); } -} +}); diff --git a/generators/app/command.ts b/generators/app/command.ts index 9f5b59098e25..74b52225caa5 100644 --- a/generators/app/command.ts +++ b/generators/app/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_BOOTSTRAP, GENERATOR_BOOTSTRAP_APPLICATION_BASE, @@ -28,11 +28,12 @@ import { GENERATOR_SERVER, } from '../generator-list.js'; -const command: JHipsterCommandDefinition = { +const command = { options: { defaults: { description: 'Execute jhipster with default config', type: Boolean, + scope: 'none', }, skipClient: { description: 'Skip the client-side application generation', @@ -62,15 +63,18 @@ const command: JHipsterCommandDefinition = { blueprint: { description: 'DEPRECATED: Specify a generator blueprint to use for the sub generators', type: Array, + scope: 'none', }, blueprints: { description: 'A comma separated list of one or more generator blueprints to use for the sub generators, e.g. --blueprints kotlin,vuejs', type: String, + scope: 'none', }, ignoreErrors: { description: "Don't fail on prettier errors.", type: Boolean, + scope: 'none', }, pkType: { description: 'Default primary key type (beta)', @@ -85,6 +89,7 @@ const command: JHipsterCommandDefinition = { testFrameworks: { description: 'Test frameworks to be generated', type: Array, + scope: 'none', }, }, import: [ @@ -97,6 +102,6 @@ const command: JHipsterCommandDefinition = { GENERATOR_CYPRESS, GENERATOR_LANGUAGES, ], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/app/composing.spec.ts b/generators/app/composing.spec.ts index 2ea92899a5d5..058a6e68bd47 100644 --- a/generators/app/composing.spec.ts +++ b/generators/app/composing.spec.ts @@ -1,7 +1,6 @@ -import assert from 'assert'; -import { before, it, describe } from 'esmocha'; +import { before, describe, it } from 'esmocha'; -import { defaultHelpers as helpers } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { GENERATOR_APP } from '../generator-list.js'; const allMockedComposedGenerators = [ @@ -19,48 +18,39 @@ const allMockedComposedGenerators = [ describe('generator - app - composing', () => { describe('when mocking all generators', () => { describe('with default options', () => { - let runResult; before(async () => { - runResult = await helpers.runJHipster(GENERATOR_APP).withJHipsterConfig().withMockedGenerators(allMockedComposedGenerators); + await helpers.runJHipster(GENERATOR_APP).withJHipsterConfig().withMockedGenerators(allMockedComposedGenerators); }); it('should compose with bootstrap generator', () => { - assert(runResult.mockedGenerators['jhipster:bootstrap'].called); + runResult.assertGeneratorComposed('jhipster:bootstrap'); }); it('should compose with common generator', () => { - const CommonGenerator = runResult.mockedGenerators['jhipster:common']; - assert(CommonGenerator.calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:common'); }); it('should compose with server generator', () => { - const ServerGenerator = runResult.mockedGenerators['jhipster:server']; - assert(ServerGenerator.calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:server'); }); it('should compose with client generator', () => { - const ClientGenerator = runResult.mockedGenerators['jhipster:client']; - assert(ClientGenerator.calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:client'); }); it('should not compose with languages generator', () => { - const LanguagesGenerator = runResult.mockedGenerators['jhipster:languages']; - assert.equal(LanguagesGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:languages'); }); it('should not compose with entities generator', () => { - const MockedGenerator = runResult.mockedGenerators['jhipster:entities']; - assert.equal(MockedGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:entities'); }); it('should not compose with entity generator', () => { - const MockedGenerator = runResult.mockedGenerators['jhipster:entity']; - assert.equal(MockedGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:entity'); }); it('should not compose with database-changelog generator', () => { - const MockedGenerator = runResult.mockedGenerators['jhipster:database-changelog']; - assert.equal(MockedGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:database-changelog'); }); }); describe('with --skip-client', () => { - let runResult; before(async () => { - runResult = await helpers + await helpers .runJHipster(GENERATOR_APP) .withJHipsterConfig({ skipClient: true, @@ -69,43 +59,34 @@ describe('generator - app - composing', () => { }); it('should compose with bootstrap generator', () => { - const BootstrapGenerator = runResult.mockedGenerators['jhipster:bootstrap']; - assert(BootstrapGenerator.called); + runResult.assertGeneratorComposed('jhipster:bootstrap'); }); it('should compose with common generator', () => { - const CommonGenerator = runResult.mockedGenerators['jhipster:common']; - assert(CommonGenerator.calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:common'); }); it('should compose with server generator', () => { - const ServerGenerator = runResult.mockedGenerators['jhipster:server']; - assert(ServerGenerator.calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:server'); }); it('should not compose with client generator', () => { - const ClientGenerator = runResult.mockedGenerators['jhipster:client']; - assert.equal(ClientGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:client'); }); it('should not compose with languages generator', () => { - const LanguagesGenerator = runResult.mockedGenerators['jhipster:languages']; - assert.equal(LanguagesGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:languages'); }); it('should not compose with entities generator', () => { - const MockedGenerator = runResult.mockedGenerators['jhipster:entities']; - assert.equal(MockedGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:entities'); }); it('should not compose with entity generator', () => { - const MockedGenerator = runResult.mockedGenerators['jhipster:entity']; - assert.equal(MockedGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:entity'); }); it('should not compose with database-changelog generator', () => { - const MockedGenerator = runResult.mockedGenerators['jhipster:database-changelog']; - assert.equal(MockedGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:database-changelog'); }); }); describe('with --skip-server', () => { - let runResult; before(async () => { - runResult = await helpers + await helpers .runJHipster(GENERATOR_APP) .withJHipsterConfig({ skipServer: true, @@ -114,31 +95,25 @@ describe('generator - app - composing', () => { }); it('should compose with bootstrap generator', () => { - assert(runResult.mockedGenerators['jhipster:bootstrap'].called); + runResult.assertGeneratorComposed('jhipster:bootstrap'); }); it('should compose with common generator', () => { - const CommonGenerator = runResult.mockedGenerators['jhipster:common']; - assert(CommonGenerator.calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:common'); }); it('should not compose with server generator', () => { - const ServerGenerator = runResult.mockedGenerators['jhipster:server']; - assert(ServerGenerator.callCount === 0); + runResult.assertGeneratorNotComposed('jhipster:server'); }); it('should compose with client generator', () => { - const ClientGenerator = runResult.mockedGenerators['jhipster:client']; - assert(ClientGenerator.calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:client'); }); it('should not compose with entities generator', () => { - const EntityGenerator = runResult.mockedGenerators['jhipster:entities']; - assert.equal(EntityGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:entities'); }); it('should not compose with entity generator', () => { - const MockedGenerator = runResult.mockedGenerators['jhipster:entity']; - assert.equal(MockedGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:entity'); }); it('should not compose with database-changelog generator', () => { - const MockedGenerator = runResult.mockedGenerators['jhipster:database-changelog']; - assert.equal(MockedGenerator.callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:database-changelog'); }); }); }); diff --git a/generators/app/generator.spec.ts b/generators/app/generator.spec.ts index 01f254405c0f..4ed0224074e5 100644 --- a/generators/app/generator.spec.ts +++ b/generators/app/generator.spec.ts @@ -16,20 +16,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { getCommandHelpOutput, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { defaultHelpers as helpers, runResult } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorPath = join(__dirname, 'index.js'); describe(`generator - ${generator}`, () => { it('generator-list constant matches folder name', async () => { @@ -44,9 +43,8 @@ describe(`generator - ${generator}`, () => { describe('blueprint support', () => testBlueprintSupport(generator)); describe('with', () => { describe('default config', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath).withJHipsterConfig().withSkipWritingPriorities().withMockedSource(); + await helpers.runJHipster(generator).withJHipsterConfig().withSkipWritingPriorities().withMockedSource(); }); it('should match snapshot', () => { @@ -61,10 +59,9 @@ describe(`generator - ${generator}`, () => { }); describe('gateway', () => { - let runResult; before(async () => { - runResult = await helpers - .run(generatorPath) + await helpers + .runJHipster(generator) .withJHipsterConfig({ applicationType: 'gateway', }) @@ -84,10 +81,9 @@ describe(`generator - ${generator}`, () => { }); describe('microservice', () => { - let runResult; before(async () => { - runResult = await helpers - .run(generatorPath) + await helpers + .runJHipster(generator) .withJHipsterConfig({ applicationType: 'microservice', }) @@ -108,7 +104,7 @@ describe(`generator - ${generator}`, () => { describe('with application', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({ jdlStore: 'app.jdl', skipServer: true, @@ -125,7 +121,7 @@ describe(`generator - ${generator}`, () => { describe('with application and entities', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig( { jdlStore: 'app.jdl', @@ -146,7 +142,7 @@ describe(`generator - ${generator}`, () => { describe('with incremental changelog application and entities', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig( { jdlStore: 'app.jdl', @@ -168,7 +164,7 @@ describe(`generator - ${generator}`, () => { describe('questions', () => { describe('without answers', () => { before(async () => { - await helpers.run(generatorPath).withSkipWritingPriorities(); + await helpers.runJHipster(generator).withSkipWritingPriorities(); }); it('should match order', () => { @@ -202,7 +198,7 @@ describe(`generator - ${generator}`, () => { describe('with gateway, gradle and no cacheProvider', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withAnswers({ applicationType: 'gateway', buildTool: 'gradle', cacheProvider: 'no' }) .withSkipWritingPriorities(); }); @@ -221,8 +217,6 @@ describe(`generator - ${generator}`, () => { "databaseType", "prodDatabaseType", "devDatabaseType", - "cacheProvider", - "enableHibernateCache", "serverSideOptions", "enableGradleEnterprise", "clientFramework", @@ -241,7 +235,7 @@ describe(`generator - ${generator}`, () => { describe('with microservice', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withAnswers({ applicationType: 'microservice', databaseType: 'mongodb' }) .withSkipWritingPriorities(); }); diff --git a/generators/app/generator.js b/generators/app/generator.ts similarity index 95% rename from generators/app/generator.js rename to generators/app/generator.ts index c8dfe83e5c80..2ddd2fd5072d 100644 --- a/generators/app/generator.js +++ b/generators/app/generator.ts @@ -16,16 +16,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return, import/no-named-as-default-member */ + import chalk from 'chalk'; import { camelCase } from 'lodash-es'; import BaseApplicationGenerator from '../base-application/index.js'; -import { GENERATOR_COMMON, GENERATOR_CLIENT, GENERATOR_SERVER } from '../generator-list.js'; +import { GENERATOR_CLIENT, GENERATOR_COMMON, GENERATOR_SERVER } from '../generator-list.js'; import { getDefaultAppName } from '../project-name/support/index.js'; import { packageJson } from '../../lib/index.js'; -import { applicationTypes } from '../../jdl/jhipster/index.js'; +import { applicationTypes } from '../../lib/jhipster/index.js'; import cleanupOldFilesTask from './cleanup.js'; import { checkNode, loadStoredAppOptions } from './support/index.js'; diff --git a/generators/app/support/check-node.js b/generators/app/support/check-node.ts similarity index 100% rename from generators/app/support/check-node.js rename to generators/app/support/check-node.ts diff --git a/generators/app/support/config.ts b/generators/app/support/config.ts index a5a6b3e973ec..df7346769c41 100644 --- a/generators/app/support/config.ts +++ b/generators/app/support/config.ts @@ -1,6 +1,6 @@ import { camelCase, kebabCase, startCase, upperFirst } from 'lodash-es'; import { NODE_VERSION } from '../../generator-constants.js'; -import { applicationTypes, authenticationTypes, databaseTypes, testFrameworkTypes } from '../../../jdl/index.js'; +import { applicationTypes, authenticationTypes, databaseTypes, testFrameworkTypes } from '../../../lib/jhipster/index.js'; import { getHipster, mutateData, pickFields, upperFirstCamelCase } from '../../base/support/index.js'; import { getDBTypeFromDBValue } from '../../server/support/index.js'; import detectLanguage from '../../languages/support/detect-language.js'; diff --git a/generators/base-application/application-options.d.ts b/generators/base-application/application-options.d.ts index b6c9d1b1def1..9e54edd0479b 100644 --- a/generators/base-application/application-options.d.ts +++ b/generators/base-application/application-options.d.ts @@ -1,4 +1,4 @@ -import type { UnionToIntersection, StringKeyOf } from 'type-fest'; +import type { StringKeyOf, UnionToIntersection } from 'type-fest'; // Values<{ a: string, b: number }> = string | number type Values = T[keyof T]; diff --git a/generators/base-application/generator.spec.ts b/generators/base-application/generator.spec.ts index a55b214f5c7d..2cb958003cef 100644 --- a/generators/base-application/generator.spec.ts +++ b/generators/base-application/generator.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable max-classes-per-file */ /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -19,11 +18,11 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect, esmocha } from 'esmocha'; +import { before, describe, esmocha, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import EnvironmentBuilder from '../../cli/environment-builder.mjs'; -import { defaultHelpers as helpers } from '../../testing/index.js'; +import { defaultHelpers as helpers } from '../../lib/testing/index.js'; import { shouldSupportFeatures } from '../../test/support/tests.js'; import Generator from './index.js'; @@ -158,27 +157,30 @@ describe(`generator - ${generator}`, () => { } before(async () => { - await helpers.run(CustomGenerator).withJHipsterConfig({}, [ - { - name: 'One', - fields: [{ fieldName: 'id', fieldType: 'Long' }], - relationships: [{ relationshipName: 'two', otherEntityName: 'Two', relationshipType: 'many-to-one' }], - }, - { - name: 'Two', - fields: [ - { fieldName: 'id', fieldType: 'Long' }, - { fieldName: 'name', fieldType: 'String' }, - ], - relationships: [ - { relationshipName: 'one', otherEntityName: 'One', relationshipType: 'many-to-one' }, - { relationshipName: 'three', otherEntityName: 'Three', relationshipType: 'many-to-one' }, - ], - }, - { - name: 'Three', - }, - ]); + await helpers + .run(CustomGenerator as any) + .withJHipsterGenerators({ useDefaultMocks: true }) + .withJHipsterConfig({}, [ + { + name: 'One', + fields: [{ fieldName: 'id', fieldType: 'Long' }], + relationships: [{ relationshipName: 'two', otherEntityName: 'Two', relationshipType: 'many-to-one' }], + }, + { + name: 'Two', + fields: [ + { fieldName: 'id', fieldType: 'Long' }, + { fieldName: 'name', fieldType: 'String' }, + ], + relationships: [ + { relationshipName: 'one', otherEntityName: 'One', relationshipType: 'many-to-one' }, + { relationshipName: 'three', otherEntityName: 'Three', relationshipType: 'many-to-one' }, + ], + }, + { + name: 'Three', + }, + ]); }); it('should call priorities with correct arguments', async () => { @@ -397,7 +399,8 @@ describe(`generator - ${generator}`, () => { before(async () => { await helpers - .run(CustomGenerator) + .run(CustomGenerator as any) + .withJHipsterGenerators({ useDefaultMocks: true }) .withJHipsterConfig({}, [ { name: 'One', diff --git a/generators/base-application/generator.ts b/generators/base-application/generator.ts index bff8e7fa4dcf..c0993e17a330 100644 --- a/generators/base-application/generator.ts +++ b/generators/base-application/generator.ts @@ -21,21 +21,21 @@ import type { ComposeOptions, Storage } from 'yeoman-generator'; import BaseGenerator from '../base/index.js'; import { JHIPSTER_CONFIG_DIR } from '../generator-constants.js'; -import { GenericTaskGroup, GenericSourceTypeDefinition } from '../base/tasks.js'; -import { SpringBootSourceType } from '../server/types.js'; -import { ClientSourceType } from '../client/types.js'; -import { I18nApplication } from '../languages/types.js'; -import { JHipsterGeneratorFeatures, JHipsterGeneratorOptions } from '../base/api.js'; -import { mutateData } from '../base/support/config.js'; +import type { JHipsterGeneratorFeatures, JHipsterGeneratorOptions } from '../base/api.js'; +import { mutateData } from '../../lib/utils/object.js'; import { GENERATOR_BOOTSTRAP_APPLICATION, GENERATOR_BOOTSTRAP_APPLICATION_BASE, GENERATOR_BOOTSTRAP_APPLICATION_CLIENT, GENERATOR_BOOTSTRAP_APPLICATION_SERVER, } from '../generator-list.js'; +import type { TaskTypes as DefaultTaskTypes } from '../../lib/types/application/tasks.js'; +import type { ApplicationType } from '../../lib/types/application/application.js'; +import type { Entity } from '../../lib/types/application/entity.js'; +import type { GenericTaskGroup } from '../../lib/types/base/tasks.js'; +import type { ApplicationConfiguration } from '../../lib/types/application/yo-rc.js'; +import type SharedData from '../base/shared-data.js'; import { getEntitiesFromDir } from './support/index.js'; -import type { BaseApplication, CommonClientServerApplication } from './types.js'; -import type { BaseApplicationGeneratorDefinition, GenericApplicationDefinition } from './tasks.js'; import { CUSTOM_PRIORITIES, PRIORITY_NAMES, QUEUES } from './priorities.js'; const { @@ -71,24 +71,14 @@ const { const asPriority = BaseGenerator.asPriority; -export type BaseApplicationSource = Record any> & SpringBootSourceType & ClientSourceType & I18nApplication; - -export type JHipsterApplication = BaseApplication & Partial; - -export type GeneratorDefinition = BaseApplicationGeneratorDefinition< - GenericApplicationDefinition & GenericSourceTypeDefinition ->; - /** * This is the base class for a generator that generates entities. */ export default class BaseApplicationGenerator< - Definition extends BaseApplicationGeneratorDefinition<{ - applicationType: any; - entityType: any; - sourceType: any; - }> = GeneratorDefinition, -> extends BaseGenerator { + E extends Entity = Entity, + A extends ApplicationType = ApplicationType, + TaskTypes extends DefaultTaskTypes = DefaultTaskTypes, +> extends BaseGenerator { static CONFIGURING_EACH_ENTITY = asPriority(CONFIGURING_EACH_ENTITY); static LOADING_ENTITIES = asPriority(LOADING_ENTITIES); @@ -105,6 +95,9 @@ export default class BaseApplicationGenerator< static POST_WRITING_ENTITIES = asPriority(POST_WRITING_ENTITIES); + declare jhipsterConfig: ApplicationConfiguration & Record; + declare sharedData: SharedData; + constructor(args: string | string[], options: JHipsterGeneratorOptions, features: JHipsterGeneratorFeatures) { super(args, options, features); @@ -194,16 +187,16 @@ export default class BaseApplicationGenerator< /** * get sorted list of entities according to changelog date (i.e. the order in which they were added) */ - getExistingEntities(): { name: string; definition: Record }[] { + getExistingEntities(): { name: string; definition: E }[] { function isBefore(e1, e2) { return (e1.definition.annotations?.changelogDate ?? 0) - (e2.definition.annotations?.changelogDate ?? 0); } const configDir = this.getEntitiesConfigPath(); - const entities: { name: string; definition: Record }[] = []; + const entities: { name: string; definition: E }[] = []; for (const entityName of [...new Set(((this.jhipsterConfig.entities as string[]) || []).concat(getEntitiesFromDir(configDir)))]) { - const definition = this.getEntityConfig(entityName)?.getAll(); + const definition: E = this.getEntityConfig(entityName)?.getAll() as unknown as E; if (definition) { entities.push({ name: entityName, definition }); } @@ -218,118 +211,118 @@ export default class BaseApplicationGenerator< * * Configuring each entity should configure entities. */ - get configuringEachEntity(): GenericTaskGroup { - return this.asConfiguringEachEntityTaskGroup({}); + get configuringEachEntity() { + return {}; } - get preparingEachEntity(): GenericTaskGroup { - return this.asPreparingEachEntityTaskGroup({}); + get preparingEachEntity() { + return {}; } /** * Priority API stub for blueprints. */ - get preparingEachEntityField(): GenericTaskGroup { - return this.asPreparingEachEntityFieldTaskGroup({}); + get preparingEachEntityField() { + return {}; } /** * Priority API stub for blueprints. */ - get preparingEachEntityRelationship(): GenericTaskGroup { - return this.asPreparingEachEntityRelationshipTaskGroup({}); + get preparingEachEntityRelationship() { + return {}; } /** * Priority API stub for blueprints. */ - get postPreparingEachEntity(): GenericTaskGroup { - return this.asPostPreparingEachEntityTaskGroup({}); + get postPreparingEachEntity() { + return {}; } /** * Priority API stub for blueprints. */ - get writingEntities(): GenericTaskGroup { - return this.asWritingEntitiesTaskGroup({}); + get writingEntities() { + return {}; } /** * Priority API stub for blueprints. */ - get postWritingEntities(): GenericTaskGroup { - return this.asPostWritingEntitiesTaskGroup({}); + get postWritingEntities() { + return {}; } /** * Utility method to get typed objects for autocomplete. */ - asConfiguringEachEntityTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asConfiguringEachEntityTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } /** * Utility method to get typed objects for autocomplete. */ - asLoadingEntitiesTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asLoadingEntitiesTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } /** * Utility method to get typed objects for autocomplete. */ - asPreparingEachEntityTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asPreparingEachEntityTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } /** * Utility method to get typed objects for autocomplete. */ - asPreparingEachEntityFieldTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asPreparingEachEntityFieldTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } /** * Utility method to get typed objects for autocomplete. */ - asPreparingEachEntityRelationshipTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asPreparingEachEntityRelationshipTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } /** * Utility method to get typed objects for autocomplete. */ - asPostPreparingEachEntityTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asPostPreparingEachEntityTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } /** * Utility method to get typed objects for autocomplete. */ - asWritingEntitiesTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asWritingEntitiesTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } /** * Utility method to get typed objects for autocomplete. */ - asPostWritingEntitiesTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asPostWritingEntitiesTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -459,7 +452,6 @@ export default class BaseApplicationGenerator< } const entitiesToLoad = [...new Set([...builtInEntities, ...this.getExistingEntityNames()])]; return entitiesToLoad.map(entityName => { - // eslint-disable-next-line @typescript-eslint/no-this-alias const generator = this; if (!this.sharedData.hasEntity(entityName)) { this.sharedData.setEntity(entityName, { name: entityName }); diff --git a/generators/base-application/index.ts b/generators/base-application/index.ts index 82dbddeb9ffa..c040c6bcb452 100644 --- a/generators/base-application/index.ts +++ b/generators/base-application/index.ts @@ -21,4 +21,4 @@ * Register generator-base at yeoman-environment */ export { default } from './generator.js'; -export type { BaseEntity, Entity, Field, Relationship } from './types/index.js'; +export type { Entity, Field, Relationship } from '../../lib/types/application/index.js'; diff --git a/generators/base-application/priorities.js b/generators/base-application/priorities.ts similarity index 97% rename from generators/base-application/priorities.js rename to generators/base-application/priorities.ts index fdee8c346827..14e5bc7a7c4e 100644 --- a/generators/base-application/priorities.js +++ b/generators/base-application/priorities.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { QUEUE_PREFIX, PRIORITY_NAMES as PRIORITY_NAMES_BASE, QUEUES as QUEUES_BASE } from '../base/priorities.js'; +import { PRIORITY_NAMES as PRIORITY_NAMES_BASE, QUEUES as QUEUES_BASE, QUEUE_PREFIX } from '../base/priorities.js'; const { DEFAULT, TRANSFORM, MULTISTEP_TRANSFORM } = PRIORITY_NAMES_BASE; diff --git a/generators/base-application/support/debug.ts b/generators/base-application/support/debug.ts index bad7eaad8087..16d04ae6826d 100644 --- a/generators/base-application/support/debug.ts +++ b/generators/base-application/support/debug.ts @@ -17,7 +17,6 @@ * limitations under the License. */ -// eslint-disable-next-line import/prefer-default-export export const stringifyApplicationData = data => JSON.stringify( data, diff --git a/generators/base-application/support/doc.ts b/generators/base-application/support/doc.ts index 64fe466f172f..edc17e7ecef6 100644 --- a/generators/base-application/support/doc.ts +++ b/generators/base-application/support/doc.ts @@ -30,7 +30,7 @@ const isSimpleText = (previousLine, text) => { /** * Format As Liquibase Remarks */ -// eslint-disable-next-line import/prefer-default-export + export const formatDocAsSingleLine = (text: string): string => { let [description, ...rows] = text.split('\n'); // discard blank rows diff --git a/generators/base-application/support/entities.ts b/generators/base-application/support/entities.ts index 3e44c74f8f04..1e1463d088c3 100644 --- a/generators/base-application/support/entities.ts +++ b/generators/base-application/support/entities.ts @@ -17,9 +17,8 @@ * limitations under the License. */ import { existsSync, opendirSync } from 'fs'; -import { extname, basename } from 'path'; +import { basename, extname } from 'path'; -// eslint-disable-next-line import/prefer-default-export export function getEntitiesFromDir(configDir: string): string[] { if (!existsSync(configDir)) { return []; diff --git a/generators/base-application/support/entity.ts b/generators/base-application/support/entity.ts index 554a051d5ebb..7564e325834f 100644 --- a/generators/base-application/support/entity.ts +++ b/generators/base-application/support/entity.ts @@ -18,8 +18,7 @@ */ import { upperFirst } from 'lodash-es'; -import { JSONEntity } from '../../../jdl/converters/types.js'; +import type { Entity } from '../../../lib/types/application/entity.js'; -// eslint-disable-next-line import/prefer-default-export -export const findEntityInEntities = (entityName: string, entities: JSONEntity[]) => +export const findEntityInEntities = (entityName: string, entities: Entity[]): Entity | undefined => entities.find(entity => upperFirst(entity.name) === upperFirst(entityName)); diff --git a/generators/base-application/support/enum.spec.ts b/generators/base-application/support/enum.spec.ts index cf0ea0186785..a69fb2facb35 100644 --- a/generators/base-application/support/enum.spec.ts +++ b/generators/base-application/support/enum.spec.ts @@ -1,5 +1,5 @@ import assert from 'assert'; -import { before, it, describe } from 'esmocha'; +import { before, describe, it } from 'esmocha'; import { getEnumInfo } from './enum.js'; describe('base-application - support - enum', () => { diff --git a/generators/base-application/support/enum.js b/generators/base-application/support/enum.ts similarity index 85% rename from generators/base-application/support/enum.js rename to generators/base-application/support/enum.ts index a23b92ba8404..75cfd68cfd74 100644 --- a/generators/base-application/support/enum.js +++ b/generators/base-application/support/enum.ts @@ -47,7 +47,7 @@ const getEnums = (enums, customValuesState, comments) => { return enums.map(enumValue => ({ name: enumValue, value: enumValue, - comment: comments && comments[enumValue] && formatDocAsJavaDoc(comments[enumValue], 4), + comment: comments?.[enumValue] && formatDocAsJavaDoc(comments[enumValue], 4), })); } return enums.map(enumValue => { @@ -55,15 +55,15 @@ const getEnums = (enums, customValuesState, comments) => { return { name: enumValue.trim(), value: enumValue.trim(), - comment: comments && comments[enumValue] && formatDocAsJavaDoc(comments[enumValue], 4), + comment: comments?.[enumValue] && formatDocAsJavaDoc(comments[enumValue], 4), }; } - // eslint-disable-next-line no-unused-vars + const matched = /\s*(.+?)\s*\((.+?)\)/.exec(enumValue); return { - name: matched[1], - value: matched[2], - comment: comments && comments[matched[1]] && formatDocAsJavaDoc(comments[matched[1]], 4), + name: matched![1], + value: matched![2], + comment: comments?.[matched![1]] && formatDocAsJavaDoc(comments[matched![1]], 4), }; }); }; @@ -83,8 +83,8 @@ const extractEnumEntries = field => { * @param {String} [clientRootFolder] - the client's root folder * @return {Object} the enum info. */ -// eslint-disable-next-line import/prefer-default-export -export const getEnumInfo = (field, clientRootFolder) => { + +export const getEnumInfo = (field, clientRootFolder?) => { field.enumInstance = extractEnumInstance(field); // TODO remove side effect const enums = extractEnumEntries(field); const customValuesState = getCustomValuesState(enums); diff --git a/generators/base-application/support/field-utils.js b/generators/base-application/support/field-utils.ts similarity index 92% rename from generators/base-application/support/field-utils.js rename to generators/base-application/support/field-utils.ts index a11a323a444e..aced4dcc6aa9 100644 --- a/generators/base-application/support/field-utils.js +++ b/generators/base-application/support/field-utils.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { fieldTypes } from '../../../jdl/jhipster/index.js'; +import { fieldTypes } from '../../../lib/jhipster/index.js'; const { CommonDBTypes, RelationalOnlyDBTypes } = fieldTypes; const { BYTES, BYTE_BUFFER } = RelationalOnlyDBTypes; @@ -39,7 +39,6 @@ const { BLOB, } = CommonDBTypes; -// eslint-disable-next-line import/prefer-default-export export function fieldIsEnum(fieldType) { return ![ STRING, diff --git a/generators/base-application/support/prepare-entity.spec.ts b/generators/base-application/support/prepare-entity.spec.ts index 349a0468ffc1..f7d632fecebf 100644 --- a/generators/base-application/support/prepare-entity.spec.ts +++ b/generators/base-application/support/prepare-entity.spec.ts @@ -17,12 +17,12 @@ * limitations under the License. */ -import { it, describe, beforeEach } from 'esmocha'; +import { beforeEach, describe, it } from 'esmocha'; import { expect } from 'chai'; import { formatDateForChangelog } from '../../base/support/index.js'; import BaseGenerator from '../../base/index.js'; -import { getConfigWithDefaults } from '../../../jdl/jhipster/index.js'; -import { prepareEntityPrimaryKeyForTemplates, entityDefaultConfig } from './prepare-entity.js'; +import { getConfigWithDefaults } from '../../../lib/jhipster/index.js'; +import { entityDefaultConfig, prepareEntityPrimaryKeyForTemplates } from './prepare-entity.js'; describe('generator - base-application - support - prepareEntity', () => { const defaultGenerator = { jhipsterConfig: getConfigWithDefaults() }; @@ -31,7 +31,6 @@ describe('generator - base-application - support - prepareEntity', () => { describe('prepareEntityPrimaryKeyForTemplates', () => { describe('with field with id name', () => { describe('without @Id', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any let entity: any = { ...entityDefaultConfig, name: 'Entity', diff --git a/generators/base-application/support/prepare-entity.ts b/generators/base-application/support/prepare-entity.ts index a8f347c66234..2029fb2610a5 100644 --- a/generators/base-application/support/prepare-entity.ts +++ b/generators/base-application/support/prepare-entity.ts @@ -16,30 +16,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { camelCase, kebabCase, startCase, upperFirst, sortedUniq, intersection, lowerFirst, uniq } from 'lodash-es'; +import { camelCase, intersection, kebabCase, lowerFirst, sortedUniq, startCase, uniq, upperFirst } from 'lodash-es'; import pluralize from 'pluralize'; import type BaseGenerator from '../../base-core/index.js'; import { getDatabaseTypeData, hibernateSnakeCase } from '../../server/support/index.js'; import { createFaker, + getMicroserviceAppName, + mutateData, parseChangelog, stringHashCode, upperFirstCamelCase, - getMicroserviceAppName, - mutateData, } from '../../base/support/index.js'; -import { getTypescriptKeyType, getEntityParentPathAddition } from '../../client/support/index.js'; -import { - applicationTypes, - binaryOptions, - databaseTypes, - entityOptions, - fieldTypes, - searchEngineTypes, -} from '../../../jdl/jhipster/index.js'; - -import { Entity } from '../types/index.js'; +import { getEntityParentPathAddition, getTypescriptKeyType } from '../../client/support/index.js'; +import { applicationTypes, databaseTypes, entityOptions, fieldTypes, searchEngineTypes } from '../../../lib/jhipster/index.js'; +import { binaryOptions } from '../../../lib/jdl/core/built-in-options/index.js'; + +import type { Entity } from '../../../lib/types/application/index.js'; import type CoreGenerator from '../../base-core/generator.js'; import { fieldIsEnum } from './field-utils.js'; import { fieldToReference } from './prepare-field.js'; @@ -149,7 +143,11 @@ export default function prepareEntity(entityWithConfig, generator, application) mutateData(entityWithConfig, entityDefaultConfig, BASE_TEMPLATE_DATA); if (entityWithConfig.changelogDate) { - entityWithConfig.changelogDateForRecent = parseChangelog(String(entityWithConfig.changelogDate)); + try { + entityWithConfig.changelogDateForRecent = parseChangelog(String(entityWithConfig.changelogDate)); + } catch (error: unknown) { + throw new Error(`Error parsing changelog date for entity ${entityName}: ${(error as Error).message}`, { cause: error }); + } } entityWithConfig.entityAngularJSSuffix = entityWithConfig.angularJSSuffix; @@ -281,9 +279,9 @@ export default function prepareEntity(entityWithConfig, generator, application) export function derivedPrimaryKeyProperties(primaryKey) { mutateData(primaryKey, { - hasUUID: primaryKey.fields && primaryKey.fields.some(field => field.fieldType === UUID), - hasLong: primaryKey.fields && primaryKey.fields.some(field => field.fieldType === LONG), - hasInteger: primaryKey.fields && primaryKey.fields.some(field => field.fieldType === INTEGER), + hasUUID: primaryKey.fields?.some(field => field.fieldType === UUID), + hasLong: primaryKey.fields?.some(field => field.fieldType === LONG), + hasInteger: primaryKey.fields?.some(field => field.fieldType === INTEGER), typeUUID: primaryKey.type === UUID, typeString: primaryKey.type === STRING, typeLong: primaryKey.type === LONG, @@ -610,7 +608,7 @@ function preparePostEntityCommonDerivedPropertiesNotTyped(entity: any) { entity.relationships.some(relationship => !relationship.id && relationship.persistableRelationship); entity.allReferences - .filter(reference => reference.relationship && reference.relationship.relatedField) + .filter(reference => reference.relationship?.relatedField) .forEach(reference => { reference.relatedReference = reference.relationship.relatedField.reference; }); diff --git a/generators/base-application/support/prepare-field.spec.ts b/generators/base-application/support/prepare-field.spec.ts index 5d7cdad65e51..7864113b8d1b 100644 --- a/generators/base-application/support/prepare-field.spec.ts +++ b/generators/base-application/support/prepare-field.spec.ts @@ -17,11 +17,11 @@ * limitations under the License. */ -import { it, describe, beforeEach } from 'esmocha'; +import { beforeEach, describe, it } from 'esmocha'; import { expect } from 'chai'; import { formatDateForChangelog } from '../../base/support/index.js'; import BaseGenerator from '../../base/index.js'; -import { getConfigWithDefaults } from '../../../jdl/jhipster/index.js'; +import { getConfigWithDefaults } from '../../../lib/jhipster/index.js'; import prepareFieldForTemplates, { getEnumValuesWithCustomValues } from './prepare-field.js'; import prepareEntityForTemplates, { loadRequiredConfigIntoEntity } from './prepare-entity.js'; @@ -39,7 +39,6 @@ describe('generator - base-application - support - prepareField', () => { describe('prepareFieldForTemplates', () => { describe('when called', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any let field: any = { fieldName: 'name', fieldType: 'String' }; beforeEach(() => { field = prepareFieldForTemplates(defaultEntity, field, defaultGenerator); @@ -58,7 +57,6 @@ describe('generator - base-application - support - prepareField', () => { }); }); describe('with dto == mapstruct and @MapstructExpression', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any let field: any = { fieldName: 'name', fieldType: 'String', mapstructExpression: 'java()' }; beforeEach(() => { field = prepareFieldForTemplates({ ...defaultEntity, dto: 'mapstruct' }, field, defaultGenerator); @@ -73,6 +71,7 @@ describe('generator - base-application - support - prepareField', () => { describe('getEnumValuesWithCustomValues', () => { describe('when not passing anything', () => { it('should fail', () => { + // @ts-expect-error testing invalid arguments expect(() => getEnumValuesWithCustomValues()).to.throw(/^Enumeration values must be passed to get the formatted values\.$/); }); }); diff --git a/generators/base-application/support/prepare-field.js b/generators/base-application/support/prepare-field.ts similarity index 78% rename from generators/base-application/support/prepare-field.js rename to generators/base-application/support/prepare-field.ts index 7faa94b5de42..e27ab5f3d53e 100644 --- a/generators/base-application/support/prepare-field.js +++ b/generators/base-application/support/prepare-field.ts @@ -16,12 +16,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { snakeCase, startCase, upperFirst, defaults, kebabCase } from 'lodash-es'; -import { fieldTypes, validations } from '../../../jdl/jhipster/index.js'; +import { defaults, kebabCase, snakeCase, startCase, upperFirst } from 'lodash-es'; +import { fieldTypes, validations } from '../../../lib/jhipster/index.js'; import { getTypescriptType, prepareField as prepareClientFieldForTemplates } from '../../client/support/index.js'; import { prepareField as prepareServerFieldForTemplates } from '../../server/support/index.js'; -import { mutateData } from '../../base/support/config.js'; -import { fieldIsEnum } from './field-utils.js'; +import { mutateData } from '../../../lib/utils/object.js'; +import type CoreGenerator from '../../base-core/generator.js'; +import type { Field } from '../../../lib/types/application/field.js'; +import type { Entity } from '../../../lib/types/application/entity.js'; +import { fieldTypeValues, isFieldEnumType } from '../../../lib/application/field-types.js'; +import type { FakerWithRandexp } from '../../base/support/faker.js'; import { prepareProperty } from './prepare-property.js'; const { BlobTypes, CommonDBTypes, RelationalOnlyDBTypes } = fieldTypes; @@ -103,16 +107,25 @@ const fakeStringTemplateForFieldName = columnName => { * @param {string} type csv, cypress, json-serializable, ts * @returns fake value */ -function generateFakeDataForField(field, faker, changelogDate, type = 'csv') { +function generateFakeDataForField(this: CoreGenerator, field: Field, faker: FakerWithRandexp, changelogDate, type = 'csv') { let data; + for (const prop of ['fieldValidateRulesMax', 'fieldValidateRulesMin', 'fieldValidateRulesMaxlength', 'fieldValidateRulesMinlength']) { + if (prop in field) { + try { + field[prop] = parseInt(field[prop], 10); + } catch { + throw new Error(`Error parsing ${prop} for field ${field.fieldName}`); + } + } + } + if (field.fakerTemplate) { - data = faker.faker(field.fakerTemplate); - } else if (field.fieldValidate && field.fieldValidateRules.includes('pattern')) { - const re = field.createRandexp(); - if (!re) { + data = faker.helpers.fake(field.fakerTemplate); + } else if (field.fieldValidate && field.fieldValidateRules?.includes('pattern')) { + const generated = field.generateFakeDataFromPattern!(); + if (!generated) { return undefined; } - const generated = re.gen(); if (type === 'csv' || type === 'cypress') { data = generated.replace(/"/g, ''); } else { @@ -123,7 +136,7 @@ function generateFakeDataForField(field, faker, changelogDate, type = 'csv') { data = undefined; } } else if (field.fieldIsEnum) { - if (field.fieldValues.length !== 0) { + if (field.enumValues && field.enumValues.length > 0) { const enumValues = field.enumValues; data = enumValues[faker.number.int(enumValues.length - 1)].name; } else { @@ -136,14 +149,14 @@ function generateFakeDataForField(field, faker, changelogDate, type = 'csv') { // eslint-disable-next-line no-template-curly-in-string } else if ([FLOAT, '${floatType}', DOUBLE, BIG_DECIMAL].includes(field.fieldType)) { data = faker.number.float({ - max: field.fieldValidateRulesMax ? parseInt(field.fieldValidateRulesMax, 10) : 32767, - min: field.fieldValidateRulesMin ? parseInt(field.fieldValidateRulesMin, 10) : 0, + max: field.fieldValidateRulesMax ?? 32767, + min: field.fieldValidateRulesMin ?? 0, multipleOf: 0.01, }); } else if ([INTEGER, LONG, DURATION].includes(field.fieldType)) { data = faker.number.int({ - max: field.fieldValidateRulesMax ? parseInt(field.fieldValidateRulesMax, 10) : 32767, - min: field.fieldValidateRulesMin ? parseInt(field.fieldValidateRulesMin, 10) : 0, + max: field.fieldValidateRulesMax ?? 32767, + min: field.fieldValidateRulesMin ?? 0, }); } else if ([INSTANT, ZONED_DATE_TIME, LOCAL_DATE].includes(field.fieldType)) { // Iso: YYYY-MM-DDTHH:mm:ss.sssZ @@ -163,12 +176,12 @@ function generateFakeDataForField(field, faker, changelogDate, type = 'csv') { data = data.substr(0, data.length - 3); } } - } else if (field.fieldType === BYTES && field.fieldTypeBlobContent !== TEXT) { + } else if (field.fieldTypeBinary && field.fieldTypeBlobContent !== TEXT) { data = '../fake-data/blob/hipster.png'; - } else if (field.fieldType === BYTES && field.fieldTypeBlobContent === TEXT) { + } else if (field.fieldTypeBinary && field.fieldTypeBlobContent === TEXT) { data = '../fake-data/blob/hipster.txt'; } else if (field.fieldType === STRING) { - data = field.id ? faker.string.uuid() : faker.helpers.fake(fakeStringTemplateForFieldName(field.columnName)); + data = field.id ? faker.string.uuid() : faker.helpers.fake(fakeStringTemplateForFieldName(field.columnName!)); } else if (field.fieldType === UUID) { data = faker.string.uuid(); } else if (field.fieldType === BOOLEAN) { @@ -182,17 +195,17 @@ function generateFakeDataForField(field, faker, changelogDate, type = 'csv') { } // Validation rules - if (data !== undefined && field.fieldValidate === true) { + if (data !== undefined && field.fieldValidate === true && field.fieldValidateRules) { + const { fieldValidateRulesMinlength = 0, fieldValidateRulesMaxlength } = field; // manage String max length - if (field.fieldValidateRules.includes(MAXLENGTH)) { + if (field.fieldValidateRules.includes(MAXLENGTH) && fieldValidateRulesMaxlength !== undefined) { const maxlength = field.fieldValidateRulesMaxlength; data = data.substring(0, maxlength); } // manage String min length - if (field.fieldValidateRules.includes(MINLENGTH)) { - const minlength = field.fieldValidateRulesMinlength; - data = data.length > minlength ? data : data + 'X'.repeat(minlength - data.length); + if (field.fieldValidateRules.includes(MINLENGTH) && fieldValidateRulesMinlength !== undefined) { + data = data.length > fieldValidateRulesMinlength ? data : data + 'X'.repeat(fieldValidateRulesMinlength - data.length); } // test if generated data is still compatible with the regexp as we potentially modify it with min/maxLength @@ -204,7 +217,7 @@ function generateFakeDataForField(field, faker, changelogDate, type = 'csv') { // eslint-disable-next-line no-template-curly-in-string if (type === 'ts' && ![BOOLEAN, INTEGER, LONG, FLOAT, '${floatType}', DOUBLE, BIG_DECIMAL].includes(field.fieldType)) { data = `'${typeof data === 'string' ? data.replace(/\\/g, '\\\\').replace(/'/g, "\\'") : data}'`; - } else if (type === 'csv' && field.fieldValidate && field.fieldValidateRules.includes(PATTERN)) { + } else if (type === 'csv' && field.fieldValidate && field.fieldValidateRules?.includes(PATTERN)) { data = `"${typeof data === 'string' ? data.replace(/"/g, '\\"') : data}"`; } } @@ -263,11 +276,11 @@ export default function prepareField(entityWithConfig, field, generator) { prepareServerFieldForTemplates(entityWithConfig, field, generator); } - prepareClientFieldForTemplates(entityWithConfig, field, generator); + prepareClientFieldForTemplates(entityWithConfig, field); return field; } -function prepareCommonFieldForTemplates(entityWithConfig, field, generator) { +function prepareCommonFieldForTemplates(entityWithConfig: Entity, field: Field, generator) { mutateData(field, { __override__: false, path: [field.fieldName], @@ -287,10 +300,14 @@ function prepareCommonFieldForTemplates(entityWithConfig, field, generator) { }); const fieldType = field.fieldType; - field.fieldIsEnum = !field.id && fieldIsEnum(fieldType); - if (field.fieldIsEnum) { + const fieldIsEnum = isFieldEnumType(field); + field.fieldIsEnum = fieldIsEnum; + if (fieldIsEnum) { + if (fieldTypeValues.includes(fieldType)) { + throw new Error(`Field type '${fieldType}' is a reserved keyword and can't be used as an enum name.`); + } field.enumFileName = kebabCase(field.fieldType); - field.enumValues = getEnumValuesWithCustomValues(field.fieldValues); + field.enumValues = getEnumValuesWithCustomValues(field.fieldValues!); } field.fieldWithContentType = (fieldType === BYTES || fieldType === BYTE_BUFFER) && field.fieldTypeBlobContent !== TEXT; @@ -300,24 +317,38 @@ function prepareCommonFieldForTemplates(entityWithConfig, field, generator) { field.fieldValidate = Array.isArray(field.fieldValidateRules) && field.fieldValidateRules.length >= 1; defaults(field, { - nullable: !(field.fieldValidate === true && field.fieldValidateRules.includes(REQUIRED)), + nullable: !(field.fieldValidate === true && field.fieldValidateRules!.includes(REQUIRED)), }); - field.unique = field.fieldValidate === true && field.fieldValidateRules.includes(UNIQUE); - if (field.fieldValidate === true && field.fieldValidateRules.includes(MAXLENGTH)) { + field.unique = field.fieldValidate === true && field.fieldValidateRules!.includes(UNIQUE); + if (field.fieldValidate === true && field.fieldValidateRules!.includes(MAXLENGTH)) { field.maxlength = field.fieldValidateRulesMaxlength || 255; } const faker = entityWithConfig.faker; + field.generateFakeDataFromPattern = () => { + // check if regex is valid. If not, issue warning and we skip fake data generation. + try { + new RegExp(field.fieldValidateRulesPattern!); + } catch { + generator.log.warn(`${field.fieldName} pattern is not valid: ${field.fieldValidateRulesPattern}. Skipping generating fake data. `); + return undefined; + } + const re = faker.createRandexp(field.fieldValidateRulesPattern!); + if (!re) { + generator.log.warn(`Error creating generator for pattern ${field.fieldValidateRulesPattern}`); + } + return re?.gen(); + }; + field.createRandexp = () => { // check if regex is valid. If not, issue warning and we skip fake data generation. try { - // eslint-disable-next-line no-new - new RegExp(field.fieldValidateRulesPattern); - } catch (e) { + new RegExp(field.fieldValidateRulesPattern!); + } catch { generator.log.warn(`${field.fieldName} pattern is not valid: ${field.fieldValidateRulesPattern}. Skipping generating fake data. `); return undefined; } - const re = faker.createRandexp(field.fieldValidateRulesPattern); + const re = faker.createRandexp(field.fieldValidateRulesPattern!); if (!re) { generator.log.warn(`Error creating generator for pattern ${field.fieldValidateRulesPattern}`); } @@ -329,9 +360,9 @@ function prepareCommonFieldForTemplates(entityWithConfig, field, generator) { field.generateFakeData = (type = 'csv') => { let data = generateFakeDataForField.call(generator, field, faker, entityWithConfig.changelogDateForRecent, type); // manage uniqueness - if ((field.fieldValidate === true && field.fieldValidateRules.includes(UNIQUE)) || field.id) { + if ((field.fieldValidate === true && field.fieldValidateRules!.includes(UNIQUE)) || field.id) { let i = 0; - while (field.uniqueValue.indexOf(data) !== -1) { + while (field.uniqueValue!.indexOf(data) !== -1) { if (i++ === 5) { data = undefined; break; @@ -341,7 +372,7 @@ function prepareCommonFieldForTemplates(entityWithConfig, field, generator) { if (data === undefined) { generator.log.warn(`Error generating a unique value field ${field.fieldName} and type ${field.fieldType}`); } else { - field.uniqueValue.push(data); + field.uniqueValue!.push(data); } } if (data === undefined) { @@ -361,7 +392,7 @@ function prepareCommonFieldForTemplates(entityWithConfig, field, generator) { * @param {String} [enumValues] - an enum's values. * @return {Array} the formatted enum's values. */ -export function getEnumValuesWithCustomValues(enumValues) { +export function getEnumValuesWithCustomValues(enumValues: string): { name: string; value: string }[] { if (!enumValues || enumValues === '') { throw new Error('Enumeration values must be passed to get the formatted values.'); } @@ -371,8 +402,8 @@ export function getEnumValuesWithCustomValues(enumValues) { } const matched = /\s*(.+?)\s*\((.+?)\)/.exec(enumValue); return { - name: matched[1], - value: matched[2], + name: matched![1], + value: matched![2], }; }); } diff --git a/generators/base-application/support/prepare-property.ts b/generators/base-application/support/prepare-property.ts index 70c1e21e531d..bd156f3b5135 100644 --- a/generators/base-application/support/prepare-property.ts +++ b/generators/base-application/support/prepare-property.ts @@ -17,9 +17,11 @@ * limitations under the License. */ import { snakeCase, upperFirst } from 'lodash-es'; -import { mutateData } from '../../base/support/config.js'; +import { mutateData } from '../../../lib/utils/object.js'; +import type { Field } from '../../../lib/types/application/field.js'; +import type { Relationship } from '../../../lib/types/application/relationship.js'; -export const prepareProperty = (property: any) => { +export const prepareProperty = (property: Field | Relationship) => { mutateData(property, { __override__: false, propertyNameCapitalized: ({ propertyName }) => upperFirst(propertyName), diff --git a/generators/base-application/support/prepare-relationship.js b/generators/base-application/support/prepare-relationship.ts similarity index 93% rename from generators/base-application/support/prepare-relationship.js rename to generators/base-application/support/prepare-relationship.ts index 71c454b8f50a..6f1df4534f25 100644 --- a/generators/base-application/support/prepare-relationship.js +++ b/generators/base-application/support/prepare-relationship.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -19,11 +20,14 @@ import { lowerFirst, startCase, upperFirst } from 'lodash-es'; import pluralize from 'pluralize'; -import { databaseTypes, entityOptions, validations, checkAndReturnRelationshipOnValue } from '../../../jdl/jhipster/index.js'; +import { checkAndReturnRelationshipOnValue, databaseTypes, entityOptions, validations } from '../../../lib/jhipster/index.js'; import { getJoinTableName, hibernateSnakeCase } from '../../server/support/index.js'; -import { mutateData } from '../../base/support/config.js'; -import { stringifyApplicationData } from './debug.js'; +import { mutateData } from '../../../lib/utils/object.js'; +import type CoreGenerator from '../../base-core/generator.js'; +import type { Relationship } from '../../../lib/types/application/relationship.js'; +import type { Entity } from '../../../lib/types/application/entity.js'; import { prepareProperty } from './prepare-property.js'; +import { stringifyApplicationData } from './debug.js'; const { NEO4J, NO: DATABASE_NO } = databaseTypes; const { MapperTypes } = entityOptions; @@ -33,12 +37,17 @@ const { const { MAPSTRUCT } = MapperTypes; -function _defineOnUpdateAndOnDelete(relationship, generator) { +function _defineOnUpdateAndOnDelete(relationship: Relationship, generator: CoreGenerator) { relationship.onDelete = checkAndReturnRelationshipOnValue(relationship.options?.onDelete, generator); relationship.onUpdate = checkAndReturnRelationshipOnValue(relationship.options?.onUpdate, generator); } -export default function prepareRelationship(entityWithConfig, relationship, generator, ignoreMissingRequiredRelationship) { +export default function prepareRelationship( + entityWithConfig: Entity, + relationship: Relationship>, + generator: CoreGenerator, + ignoreMissingRequiredRelationship = false, +) { const entityName = entityWithConfig.name; const { otherEntityName, relationshipSide, relationshipType, relationshipName } = relationship; @@ -228,7 +237,7 @@ export default function prepareRelationship(entityWithConfig, relationship, gene relationship.otherEntityPath = relationship.otherEntityFolderName; } - if (relationship.relationshipValidateRules && relationship.relationshipValidateRules.includes(REQUIRED)) { + if (relationship.relationshipValidateRules?.includes(REQUIRED)) { if (entityName.toLowerCase() === relationship.otherEntityName.toLowerCase()) { generator.log.warn(`Error at entity ${entityName}: required relationships to the same entity are not supported.`); } else { diff --git a/generators/base-application/support/relationship.ts b/generators/base-application/support/relationship.ts index 5185384204ae..cb2806d048a6 100644 --- a/generators/base-application/support/relationship.ts +++ b/generators/base-application/support/relationship.ts @@ -17,20 +17,17 @@ * limitations under the License. */ -import { upperFirst, lowerFirst } from 'lodash-es'; +import { lowerFirst, upperFirst } from 'lodash-es'; -import { JSONRelationship, JSONEntity } from '../../../jdl/converters/types.js'; -import { ValidationResult } from '../../base/api.js'; -import { stringifyApplicationData } from './debug.js'; +import type { ValidationResult } from '../../base/api.js'; +import type { Entity } from '../../../lib/types/application/entity.js'; +import type { Relationship } from '../../../lib/types/application/relationship.js'; import { findEntityInEntities } from './entity.js'; +import { stringifyApplicationData } from './debug.js'; export const otherRelationshipType = relationshipType => relationshipType.split('-').reverse().join('-'); -export const findOtherRelationshipInRelationships = ( - entityName: string, - relationship: JSONRelationship, - inRelationships: JSONRelationship[], -) => { +export const findOtherRelationshipInRelationships = (entityName: string, relationship: Relationship, inRelationships: Relationship[]) => { return inRelationships.find(otherRelationship => { if (upperFirst(otherRelationship.otherEntityName) !== entityName) { return false; @@ -47,7 +44,7 @@ export const findOtherRelationshipInRelationships = ( }); }; -export const loadEntitiesAnnotations = (entities: JSONEntity[]) => { +export const loadEntitiesAnnotations = (entities: Entity[]) => { for (const entity of entities) { // Load field annotations for (const field of entity.fields ?? []) { @@ -65,7 +62,7 @@ export const loadEntitiesAnnotations = (entities: JSONEntity[]) => { } }; -export const loadEntitiesOtherSide = (entities: JSONEntity[], { application }: { application?: any } = {}): ValidationResult => { +export const loadEntitiesOtherSide = (entities: Entity[], { application }: { application?: any } = {}): ValidationResult => { const result: { warning: string[] } = { warning: [] }; for (const entity of entities) { for (const relationship of entity.relationships ?? []) { @@ -76,7 +73,7 @@ export const loadEntitiesOtherSide = (entities: JSONEntity[], { application }: { if (!application || application.authenticationTypeOauth2) { errors.push("oauth2 applications with database and '--sync-user-with-idp' option"); } - if (!application || !application.authenticationTypeOauth2) { + if (!application?.authenticationTypeOauth2) { errors.push('jwt and session authentication types in monolith or gateway applications with database'); } throw new Error(`Error at entity ${entity.name}: relationships with built-in User entity is supported in ${errors}.`); @@ -89,7 +86,7 @@ export const loadEntitiesOtherSide = (entities: JSONEntity[], { application }: { relationship.otherEntity = otherEntity; const otherRelationship = findOtherRelationshipInRelationships(entity.name, relationship, otherEntity.relationships ?? []); if (otherRelationship) { - relationship.otherRelationship = otherRelationship; + relationship.otherRelationship = otherRelationship as Relationship; otherRelationship.otherEntityRelationshipName = otherRelationship.otherEntityRelationshipName ?? relationship.relationshipName; relationship.otherEntityRelationshipName = relationship.otherEntityRelationshipName ?? otherRelationship.relationshipName; if ( @@ -115,17 +112,17 @@ export const loadEntitiesOtherSide = (entities: JSONEntity[], { application }: { return result; }; -export const addOtherRelationship = (entity: JSONEntity, otherEntity: JSONEntity, relationship: JSONRelationship) => { +export const addOtherRelationship = (entity: Entity, otherEntity: Entity, relationship: Relationship): Relationship => { relationship.otherEntityRelationshipName = relationship.otherEntityRelationshipName ?? lowerFirst(entity.name); - const otherRelationship: JSONRelationship = { - otherEntity: entity, + const otherRelationship = { otherEntityName: lowerFirst(entity.name), - ownerSide: !relationship.ownerSide, otherEntityRelationshipName: relationship.relationshipName, relationshipName: relationship.otherEntityRelationshipName as string, relationshipType: otherRelationshipType(relationship.relationshipType), + otherEntity: entity, + ownerSide: !relationship.ownerSide, otherRelationship: relationship, - }; + } as any; otherEntity.relationships = otherEntity.relationships ?? []; otherEntity.relationships.push(otherRelationship); return otherRelationship; diff --git a/generators/base-application/support/task-type-inference.ts b/generators/base-application/support/task-type-inference.ts index 04347b06b386..83bcbfd2f9d9 100644 --- a/generators/base-application/support/task-type-inference.ts +++ b/generators/base-application/support/task-type-inference.ts @@ -14,100 +14,124 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import CoreGenerator from '../../base-core/generator.js'; -import { WriteFileSection, WriteFileBlock } from '../../base/api.js'; -import { GeneratorDefinition } from '../generator.js'; +import type { ApplicationType } from '../../../lib/types/application/application.js'; +import type { TaskTypes } from '../../../lib/types/application/tasks.js'; +import type CoreGenerator from '../../base-core/generator.js'; +import type { WriteFileBlock, WriteFileSection } from '../../base/api.js'; +import type { Entity } from '../../../lib/types/application/entity.js'; -export function asWriteFilesSection( - section: WriteFileSection, -) { +export function asWriteFilesSection>(section: WriteFileSection) { return section; } -export function asWriteFilesBlock( - section: WriteFileBlock, -) { +export function asWriteFilesBlock>(section: WriteFileBlock) { return section; } -export function asInitializingTask(task: (this: CoreGenerator, params: GeneratorDefinition['initializingTaskParam']) => void) { +export function asInitializingTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['InitializingTaskParam']) => void, +) { return task; } -export function asPromptingTask(task: (this: CoreGenerator, params: GeneratorDefinition['promptingTaskParam']) => void) { +export function asPromptingTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['PromptingTaskParam']) => void, +) { return task; } -export function asConfiguringTask(task: (this: CoreGenerator, params: GeneratorDefinition['configuringTaskParam']) => void) { +export function asConfiguringTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['ConfiguringTaskParam']) => void, +) { return task; } -export function asComposingTask(task: (this: CoreGenerator, params: GeneratorDefinition['composingTaskParam']) => void) { +export function asComposingTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['ComposingTaskParam']) => void, +) { return task; } -export function asLoadingTask(task: (this: CoreGenerator, params: GeneratorDefinition['loadingTaskParam']) => void) { +export function asLoadingTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['LoadingTaskParam']) => void, +) { return task; } -export function asPreparingTask(task: (this: CoreGenerator, params: GeneratorDefinition['preparingTaskParam']) => void) { +export function asPreparingTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['PreparingTaskParam']) => void, +) { return task; } -export function asPostPreparingTask(task: (this: CoreGenerator, params: GeneratorDefinition['postPreparingTaskParam']) => void) { +export function asPostPreparingTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['PostPreparingTaskParam']) => void, +) { return task; } -export function asPreparingEachEntityTask( - task: (this: CoreGenerator, params: GeneratorDefinition['preparingEachEntityTaskParam']) => void, +export function asPreparingEachEntityTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['PreparingEachEntityTaskParam']) => void, ) { return task; } -export function asPreparingEachEntityFieldTask( - task: (this: CoreGenerator, params: GeneratorDefinition['preparingEachEntityFieldTaskParam']) => void, +export function asPreparingEachEntityFieldTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['PreparingEachEntityFieldTaskParam']) => void, ) { return task; } -export function asPreparingEachEntityRelationshipTask( - task: (this: CoreGenerator, params: GeneratorDefinition['preparingEachEntityRelationshipTaskParam']) => void, +export function asPreparingEachEntityRelationshipTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['PreparingEachEntityRelationshipTaskParam']) => void, ) { return task; } -export function asPostPreparingEachEntityTask( - task: (this: CoreGenerator, params: GeneratorDefinition['postPreparingEachEntityTaskParam']) => void, +export function asPostPreparingEachEntityTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['PostPreparingEachEntityTaskParam']) => void, ) { return task; } -export function asDefaultTask(task: (this: CoreGenerator, params: GeneratorDefinition['defaultTaskParam']) => void) { +export function asDefaultTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['DefaultTaskParam']) => void, +) { return task; } -export function asWritingTask(task: (this: CoreGenerator, params: GeneratorDefinition['writingTaskParam']) => void) { +export function asWritingTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['WritingTaskParam']) => void, +) { return task; } -export function asWritingEntitiesTask(task: (this: CoreGenerator, params: GeneratorDefinition['writingEntitiesTaskParam']) => void) { +export function asWritingEntitiesTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['WritingEntitiesTaskParam']) => void, +) { return task; } -export function asPostWritingTask(task: (this: CoreGenerator, params: GeneratorDefinition['postWritingTaskParam']) => void) { +export function asPostWritingTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['PostWritingTaskParam']) => void, +) { return task; } -export function asPostWritingEntitiesTask( - task: (this: CoreGenerator, params: GeneratorDefinition['postWritingEntitiesTaskParam']) => void, +export function asPostWritingEntitiesTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['PostWritingEntitiesTaskParam']) => void, ) { return task; } -export function asInstallTask(task: (this: CoreGenerator, params: GeneratorDefinition['installTaskParam']) => void) { +export function asInstallTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['InstallTaskParam']) => void, +) { return task; } -export function asEndTask(task: (this: CoreGenerator, params: GeneratorDefinition['endTaskParam']) => void) { +export function asEndTask, const G extends CoreGenerator = CoreGenerator>( + task: (this: G, params: TaskTypes['EndTaskParam']) => void, +) { return task; } diff --git a/generators/base-application/support/update-application-entities-transform.ts b/generators/base-application/support/update-application-entities-transform.ts index 370477009e43..83e2c824ea05 100644 --- a/generators/base-application/support/update-application-entities-transform.ts +++ b/generators/base-application/support/update-application-entities-transform.ts @@ -47,10 +47,10 @@ export const updateApplicationEntitiesTransform = ({ yoRcFile.contents = Buffer.from(JSON.stringify(contents, null, 2)); yoRcFileInMemory = yoRcFile; } else if (throwOnMissingConfig) { - throw new Error(`File ${yoRcFile!.path} is not a valid JHipster configuration file`); + throw new Error(`File ${yoRcFile.path} is not a valid JHipster configuration file`); } } else if (throwOnMissingConfig) { - throw new Error(`File ${yoRcFile!.path} has no contents`); + throw new Error(`File ${yoRcFile.path} has no contents`); } } if (yoRcFileInMemory) { diff --git a/generators/base-application/tasks.d.ts b/generators/base-application/tasks.d.ts deleted file mode 100644 index 4cbbea7d6752..000000000000 --- a/generators/base-application/tasks.d.ts +++ /dev/null @@ -1,123 +0,0 @@ -import type { Storage } from 'yeoman-generator'; -import { ControlTaskParam, BaseGeneratorDefinition, SourceTaskParam, GenericSourceTypeDefinition } from '../base/tasks.js'; -import { ClientSourceType } from '../client/types.js'; -import { BaseChangelog } from '../base-entity-changes/types.js'; -import { CommonClientServerApplication } from './types.js'; -import { Entity, Field, Relationship } from './types/index.js'; - -export type GenericApplicationDefinition = { - applicationType: ApplicationType; - entityType: Entity; -}; - -type ConfiguringEachEntityTaskParam = { - entityName: string; - /** Entity storage */ - entityStorage: Storage; - /** Proxy object for the entitystorage */ - entityConfig: Record; -}; - -type LoadingEntitiesTaskParam = { - entitiesToLoad: { - entityName: string; - /** Entity storage */ - entityStorage: Storage; - /** Proxy object for the entitystorage */ - entityConfig: Record; - /** Initial entity object */ - entityBootstrap: Record; - }[]; -}; - -type ApplicationTaskParam = { - application: Definition['applicationType'] & { user: Definition['entityType'] }; -}; - -type ApplicationDefaultsTaskParam = { - /** - * Parameter properties accepts: - * - functions: receives the application and the return value is set at the application property. - * - non functions: application property will receive the property in case current value is undefined. - * - * Applies each object in order. - * - * @example - * // application = { prop: 'foo-bar', prop2: 'foo2' } - * applicationDefaults( - * application, - * { prop: 'foo', prop2: ({ prop }) => prop + 2 }, - * { prop: ({ prop }) => prop + '-bar', prop2: 'won\'t override' }, - * ); - */ - applicationDefaults: (...defaults: Record[]) => void; -}; - -export type EntitiesTaskParam = { - entities: Definition['entityType'][]; -}; - -type EachEntityTaskParam = { - entity: Definition['entityType']; - entityName: string; - description: string; -}; - -type PreparingEachEntityFieldTaskParam = - EachEntityTaskParam & { - field: Field; - fieldName: string; - }; - -type PreparingEachEntityRelationshipTaskParam = - EachEntityTaskParam & { - relationship: Relationship; - relationshipName: string; - }; - -type ClientSource = { - addEntitiesToClient?: (param: ControlTaskParam & { source: ExtendsSelf } & EntitiesTaskParam) => any; -}; - -export type BaseApplicationGeneratorDefinition< - Definition extends { applicationType: any; entityType: any; sourceType: any } = GenericApplicationDefinition & - GenericSourceTypeDefinition any>>, -> = BaseGeneratorDefinition & - // Add application to existing priorities - Record<'loadingTaskParam' | 'preparingTaskParam', ApplicationTaskParam & ApplicationDefaultsTaskParam> & - Record< - | 'postPreparingTaskParam' - | 'defaultTaskParam' - | 'postWritingTaskParam' - | 'preConflictsTaskParam' - | 'installTaskParam' - | 'postInstallTaskParam' - | 'endTaskParam', - ApplicationTaskParam - > & - Record<'writingTaskParam', ApplicationTaskParam & { configChanges?: Record }> & - // Add entities to existing priorities - Record<'defaultTaskParam', EntitiesTaskParam & { entityChanges?: BaseChangelog[] }> & - // Add application and control to new priorities - Record< - | 'configuringEachEntityTaskParam' - | 'loadingEntitiesTaskParam' - | 'preparingEachEntityTaskParam' - | 'preparingEachEntityFieldTaskParam' - | 'preparingEachEntityRelationshipTaskParam' - | 'postPreparingEachEntityTaskParam' - | 'writingEntitiesTaskParam' - | 'postWritingEntitiesTaskParam', - ControlTaskParam & ApplicationTaskParam - > & { - // Add additional types to each priority - applicationType: Definition['applicationType']; - configuringEachEntityTaskParam: ConfiguringEachEntityTaskParam; - loadingEntitiesTaskParam: LoadingEntitiesTaskParam; - preparingEachEntityTaskParam: EachEntityTaskParam; - preparingEachEntityFieldTaskParam: PreparingEachEntityFieldTaskParam; - preparingEachEntityRelationshipTaskParam: PreparingEachEntityRelationshipTaskParam; - postPreparingEachEntityTaskParam: EachEntityTaskParam; - writingEntitiesTaskParam: EntitiesTaskParam & { entityChanges?: BaseChangelog[] }; - postWritingEntitiesTaskParam: SourceTaskParam & EntitiesTaskParam & { entityChanges?: BaseChangelog[] }; - }; diff --git a/generators/base-application/types.d.ts b/generators/base-application/types.d.ts index b2ed95ece4e9..e0749fabd968 100644 --- a/generators/base-application/types.d.ts +++ b/generators/base-application/types.d.ts @@ -1,7 +1,10 @@ -import { ClientApplication } from '../client/types.js'; -import { I18nApplication } from '../languages/types.js'; -import { SpringBootApplication } from '../server/types.js'; -import { DeterministicOptionWithDerivedProperties, OptionWithDerivedProperties } from './application-options.js'; +/* eslint-disable @typescript-eslint/consistent-type-imports */ +import type { ExportApplicationPropertiesFromCommand } from '../../lib/command/types.js'; +import type CoreGenerator from '../base-core/generator.ts'; +import type { ClientApplication } from '../client/types.js'; +import type { I18nApplication } from '../languages/types.js'; +import type { SpringBootApplication } from '../server/types.js'; +import type { OptionWithDerivedProperties } from './application-options.js'; export type BaseApplication = { jhipsterVersion: string; @@ -35,15 +38,17 @@ export type BaseApplication = { monorepository?: boolean; /** Customize templates sourceFile and destinationFile */ - customizeTemplatePaths: Array< - (file: { + customizeTemplatePaths: (( + this: CoreGenerator, + file: { namespace: string; sourceFile: string; resolvedSourceFile: string; destinationFile: string; templatesRoots: string[]; - }) => undefined | { sourceFile: string; resolvedSourceFile: string; destinationFile: string; templatesRoots: string[] } - >; + }, + context: any, + ) => undefined | { sourceFile: string; resolvedSourceFile: string; destinationFile: string; templatesRoots: string[] })[]; } & I18nApplication; /* ApplicationType Start */ @@ -56,15 +61,23 @@ type GatewayApplication = MicroservicesArchitectureApplication & { microfrontends: string[]; }; +/* +Deterministic option causes types to be too complex type ApplicationType = DeterministicOptionWithDerivedProperties< 'applicationType', ['monolith', 'gateway', 'microservice'], [Record, GatewayApplication, MicroservicesArchitectureApplication] >; +*/ +type ApplicationProperties = OptionWithDerivedProperties<'applicationType', ['monolith', 'gateway', 'microservice']> & + GatewayApplication & + MicroservicesArchitectureApplication; /* ApplicationType End */ /* AuthenticationType Start */ +/* +Deterministic option causes types to be too complex type UserManagement = | { skipUserManagement: true; @@ -81,8 +94,17 @@ type UserManagement = generateBuiltInAuthorityEntity: boolean; authority: any; }; - -type JwtApplication = UserManagement & { + */ +type UserManagement = { + skipUserManagement: boolean; + generateUserManagement: boolean; + generateBuiltInUserEntity?: boolean; + generateBuiltInAuthorityEntity: boolean; + user: Entity; + userManagement: Entity; + authority: Entity; +}; +type JwtApplication = { jwtSecretKey: string; }; @@ -94,15 +116,23 @@ type Oauth2Application = { generateUserManagement: false; }; -type SessionApplication = UserManagement & { +type SessionApplication = { rememberMeKey: string; }; +/* +Deterministic option causes types to be too complex type AuthenticationType = DeterministicOptionWithDerivedProperties< 'authenticationType', ['jwt', 'oauth2', 'session'], [JwtApplication, Oauth2Application, SessionApplication] >; +*/ +type AuthenticationProperties = OptionWithDerivedProperties<'authenticationType', ['jwt', 'oauth2', 'session']> & + UserManagement & + JwtApplication & + Oauth2Application & + SessionApplication; /* AuthenticationType End */ @@ -110,12 +140,14 @@ type QuirksApplication = { cypressBootstrapEntities?: boolean; }; -export type CommonClientServerApplication = BaseApplication & +export type CommonClientServerApplication = BaseApplication & QuirksApplication & - AuthenticationType & + AuthenticationProperties & SpringBootApplication & ClientApplication & - ApplicationType & { + ExportApplicationPropertiesFromCommand & + ExportApplicationPropertiesFromCommand & + ApplicationProperties & { clientRootDir: string; clientSrcDir: string; clientTestDir?: string; diff --git a/generators/base-application/types/entity.d.ts b/generators/base-application/types/entity.d.ts deleted file mode 100644 index 326c5beaf181..000000000000 --- a/generators/base-application/types/entity.d.ts +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright 2013-2024 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. - */ - -import { SpringEntity } from '../../server/types.js'; -import Field from './field.js'; -import Relationship from './relationship.js'; - -export type BaseEntity = { - name: string; - changelogDate?: string; - dto?: string; - - primaryKey?: Record; - fields?: Field[]; - relationships?: Relationship[]; - - readOnly?: boolean; - embedded?: boolean; - skipClient?: boolean; - skipServer?: boolean; -}; - -type AngularEntity = { - entityAngularAuthorities?: string; - entityAngularReadAuthorities?: string; -}; - -type Entity = Required & - SpringEntity & - AngularEntity & { - builtIn?: boolean; - builtInUser?: boolean; - builtInAuthority?: boolean; - microserviceName?: string; - adminEntity?: boolean; - entityAuthority?: string; - entityReadAuthority?: string; - hasCyclicRequiredRelationship?: boolean; - - entityNameCapitalized: string; - entityClass: string; - entityInstance: string; - entityTableName: string; - entityNamePlural: string; - - dtoClass?: string; - dtoInstance?: string; - - persistClass: string; - persistInstance: string; - restClass: string; - restInstance: string; - - entityNamePluralizedAndSpinalCased: string; - entityClassPlural: string; - entityInstancePlural: string; - - entityI18nVariant: string; - entityClassHumanized: string; - entityClassPluralHumanized: string; - - entityFileName: string; - entityFolderName: string; - entityModelFileName: string; - entityParentPathAddition: string; - entityPluralFileName: string; - entityServiceFileName: string; - - /** Generate only the model at client side for relationships. */ - entityClientModelOnly?: boolean; - entityAngularName: string; - entityAngularNamePlural: string; - entityReactName: string; - - entityApiUrl: string; - entityStateName: string; - entityUrl: string; - - entityTranslationKey: string; - entityTranslationKeyMenu: string; - - i18nKeyPrefix: string; - i18nAlertHeaderPrefix: string; - - entityApi: string; - entityPage: string; - - anyFieldIsBigDecimal: boolean; - /** - * Any file is of type Bytes or ByteBuffer - */ - anyFieldIsBlobDerived: boolean; - /** - * Any field is of type ZonedDateTime, Instant or LocalDate - */ - anyFieldIsDateDerived: boolean; - anyFieldIsDuration: boolean; - anyFieldIsInstant: boolean; - anyFieldIsLocalDate: boolean; - /** - * Any field is of type ZonedDateTime or Instant - */ - anyFieldIsTimeDerived: boolean; - anyFieldIsUUID: boolean; - anyFieldIsZonedDateTime: boolean; - - anyFieldHasDocumentation: boolean; - anyFieldHasImageContentType: boolean; - anyFieldHasTextContentType: boolean; - /** - * Any field has image or any contentType - */ - anyFieldHasFileBasedContentType: boolean; - - dtoMapstruct: boolean; - }; - -export default Entity; diff --git a/generators/base-core/generator-core.spec.ts b/generators/base-core/generator-core.spec.ts index 2a24645c47a7..d22a746f6b7c 100644 --- a/generators/base-core/generator-core.spec.ts +++ b/generators/base-core/generator-core.spec.ts @@ -1,8 +1,7 @@ -/* eslint-disable no-unused-expressions */ -import { it, describe, expect as jestExpect, beforeEach } from 'esmocha'; -import { basicHelpers as helpers } from '../../testing/index.js'; +import { beforeEach, describe, it, expect as jestExpect } from 'esmocha'; +import { defaultHelpers as helpers } from '../../lib/testing/index.js'; -import { createJHipsterLogger } from '../base/support/logger.js'; +import { createJHipsterLogger } from '../base/support/index.js'; import Base from './index.js'; const BaseGenerator: any = Base.prototype; @@ -19,7 +18,7 @@ describe('generator - base-core', () => { let Dummy; beforeEach(async () => { await helpers.prepareTemporaryDir(); - Dummy = helpers.createDummyGenerator(Base); + Dummy = helpers.createDummyGenerator(Base as any); }); it('no argument', async () => { @@ -78,7 +77,8 @@ describe('generator - base-core', () => { }, }); jestExpect(base.first).toBe('bar'); - jestExpect(base.jdlFiles).toMatchObject(['foo']); + jestExpect(base.jdlFiles).toHaveLength(1); + jestExpect(base.jdlFiles[0]).toMatch('foo'); }); it('vararg arguments using positionalArguments', async () => { const base = new Dummy({ positionalArguments: ['bar', ['foo']], sharedData: {}, env: await helpers.createTestEnv() }); @@ -91,7 +91,8 @@ describe('generator - base-core', () => { }, }); jestExpect(base.first).toBe('bar'); - jestExpect(base.jdlFiles).toMatchObject(['foo']); + jestExpect(base.jdlFiles).toHaveLength(1); + jestExpect(base.jdlFiles[0]).toBe('foo'); }); }); }); diff --git a/generators/base-core/generator.ts b/generators/base-core/generator.ts index b329a9b80111..f450912d6a85 100644 --- a/generators/base-core/generator.ts +++ b/generators/base-core/generator.ts @@ -16,17 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, join as joinPath, dirname, relative, isAbsolute, join, extname } from 'path'; +import { basename, dirname, extname, isAbsolute, join, join as joinPath, relative } from 'path'; import { relative as posixRelative } from 'path/posix'; import { createHash } from 'crypto'; import { fileURLToPath } from 'url'; -import { statSync, rmSync, existsSync, readFileSync } from 'fs'; +import { existsSync, readFileSync, rmSync, statSync } from 'fs'; import assert from 'assert'; import { requireNamespace } from '@yeoman/namespace'; -import { GeneratorMeta } from '@yeoman/types'; +import type { GeneratorMeta } from '@yeoman/types'; import chalk from 'chalk'; import { parse as parseYaml, stringify as stringifyYaml } from 'yaml'; -import { kebabCase, snakeCase, merge, get, set, defaults, mergeWith } from 'lodash-es'; +import { defaults, get, kebabCase, merge, mergeWith, set, snakeCase } from 'lodash-es'; import { simpleGit } from 'simple-git'; import type { CopyOptions } from 'mem-fs-editor'; import type { Data as TemplateData, Options as TemplateOptions } from 'ejs'; @@ -36,38 +36,38 @@ import type Environment from 'yeoman-environment'; import latestVersion from 'latest-version'; import SharedData from '../base/shared-data.js'; import { CUSTOM_PRIORITIES, PRIORITY_NAMES, PRIORITY_PREFIX, QUEUES } from '../base/priorities.js'; -import { - createJHipster7Context, - formatDateForChangelog, - joinCallbacks, - Logger, - removeFieldsWithNullishValues, -} from '../base/support/index.js'; +import type { Logger } from '../base/support/index.js'; +import { createJHipster7Context, formatDateForChangelog, joinCallbacks, removeFieldsWithNullishValues } from '../base/support/index.js'; import type { - JHipsterGeneratorOptions, - JHipsterGeneratorFeatures, + CascatedEditFileCallback, EditFileCallback, EditFileOptions, - CascatedEditFileCallback, - JHipsterOptions, + JHipsterGeneratorFeatures, + JHipsterGeneratorOptions, ValidationResult, WriteFileOptions, - JHipsterArguments, - JHipsterConfigs, - JHipsterCommandDefinition, } from '../base/api.js'; +import { + type JHipsterArguments, + type JHipsterCommandDefinition, + type JHipsterConfigs, + type JHipsterOptions, + convertConfigToOption, +} from '../../lib/command/index.js'; import { packageJson } from '../../lib/index.js'; -import { CommonClientServerApplication, type BaseApplication } from '../base-application/types.js'; +import type { BaseApplication } from '../base-application/types.js'; import { GENERATOR_BOOTSTRAP } from '../generator-list.js'; import NeedleApi from '../needle-api.js'; import command from '../base/command.js'; import { GENERATOR_JHIPSTER, YO_RC_FILE } from '../generator-constants.js'; -import { convertConfigToOption, loadConfig } from '../../lib/internal/index.js'; +import { loadConfig } from '../../lib/internal/index.js'; import { getGradleLibsVersionsProperties } from '../gradle/support/dependabot-gradle.js'; import { dockerPlaceholderGenerator } from '../docker/utils.js'; -import { getConfigWithDefaults } from '../../jdl/index.js'; -import { extractArgumentsFromConfigs } from '../base/internal/command.js'; +import { getConfigWithDefaults } from '../../lib/jhipster/index.js'; +import { extractArgumentsFromConfigs } from '../../lib/command/index.js'; +import type BaseApplicationGenerator from '../base-application/generator.js'; +import type { ApplicationConfiguration } from '../../lib/types/application/yo-rc.js'; const { INITIALIZING, @@ -132,6 +132,7 @@ export default class CoreGenerator extends YeomanGenerator; useVersionPlaceholders?: boolean; skipChecks?: boolean; ignoreNeedlesError?: boolean; @@ -141,7 +142,7 @@ export default class CoreGenerator extends YeomanGenerator; + readonly sharedData!: SharedData; readonly logger: Logger; jhipsterConfig!: Record; /** @@ -195,7 +196,7 @@ export default class CoreGenerator extends YeomanGenerator> { const configWithDefaults = getConfigWithDefaults(removeFieldsWithNullishValues(this.config.getAll())); defaults(configWithDefaults, { skipFakeData: false, @@ -254,7 +259,7 @@ export default class CoreGenerator extends YeomanGenerator def?.prompt) .map(([name, def]) => { - const promptSpec = typeof def.prompt === 'function' ? def.prompt(this as any, def) : { ...def.prompt }; + let promptSpec = typeof def.prompt === 'function' ? def.prompt(this as any, def) : { ...def.prompt }; let storage: any; if ((def.scope ?? 'storage') === 'storage') { storage = this.config; if (promptSpec.default === undefined) { - promptSpec.default = () => (this as any).jhipsterConfigWithDefaults?.[name]; + promptSpec = { ...promptSpec, default: () => (this as any).jhipsterConfigWithDefaults?.[name] }; } } else if (def.scope === 'blueprint') { storage = this.blueprintStorage; @@ -612,6 +623,11 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`); getPath: path => get(this, path), setPath: (path, value) => set(this, path, value), }; + } else if (def.scope === 'context') { + storage = { + getPath: path => get(this.context, path), + setPath: (path, value) => set(this.context!, path, value), + }; } return { name, @@ -631,7 +647,7 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`); */ dateFormatForLiquibase(reproducible?: boolean) { const control = this.sharedData.getControl(); - reproducible = reproducible ?? control.reproducible; + reproducible = reproducible ?? Boolean(control.reproducible); // Use started counter or use stored creationTimestamp if creationTimestamp option is passed const creationTimestamp = this.options.creationTimestamp ? this.config.get('creationTimestamp') : undefined; let now = new Date(); @@ -644,8 +660,8 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`); now = control.reproducibleLiquibaseTimestamp; } else { // Create a new counter - const newCreationTimestamp = creationTimestamp ?? this.config.get('creationTimestamp'); - now = newCreationTimestamp ? new Date(newCreationTimestamp as any) : now; + const newCreationTimestamp: string = (creationTimestamp as string) ?? this.config.get('creationTimestamp'); + now = newCreationTimestamp ? new Date(newCreationTimestamp) : now; now.setMilliseconds(0); } now.setMinutes(now.getMinutes() + 1); @@ -679,7 +695,7 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`); let existingGenerator: string; try { existingGenerator = this._jhipsterGenerator ?? requireNamespace(this.options.namespace).generator; - } catch (error) { + } catch { if (this.options.namespace) { const split = this.options.namespace.split(':', 2); existingGenerator = split.length === 1 ? split[0] : split[1]; @@ -697,22 +713,15 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`); * Compose with a jhipster generator using default jhipster config. * @return {object} the composed generator */ - async composeWithJHipster(generator: string, options?: ComposeOptions) { - assert(typeof generator === 'string', 'generator should to be a string'); + async composeWithJHipster(gen: G, options?: ComposeOptions) { + assert(typeof gen === 'string', 'generator should to be a string'); + let generator: string = gen; if (!isAbsolute(generator)) { const namespace = generator.includes(':') ? generator : `jhipster:${generator}`; if (await this.env.get(namespace)) { generator = namespace; } else { - // Keep test compatibility were jhipster lookup does not run. - const found = ['/index.js', '/index.cjs', '/index.mjs', '/index.ts', '/index.cts', '/index.mts'].find(extension => { - const pathToLook = join(__dirname, `../${generator}${extension}`); - return existsSync(pathToLook) ? pathToLook : undefined; - }); - if (!found) { - throw new Error(`Generator ${generator} was not found`); - } - generator = join(__dirname, `../${generator}${found}`); + throw new Error(`Generator ${generator} was not found`); } } @@ -730,7 +739,7 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`); /** * Compose with a jhipster generator using default jhipster config, but queue it immediately. */ - async dependsOnJHipster(generator: string, options?: ComposeOptions) { + async dependsOnJHipster(generator: string, options?: ComposeOptions) { return this.composeWithJHipster(generator, { ...options, schedule: false, @@ -771,7 +780,7 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`); this.log.info(`Removing legacy folder ${relativePath}`); rmSync(destinationFolder, { recursive: true }); } - } catch (error) { + } catch { this.log.log(`Could not remove folder ${destinationFolder}`); } } @@ -797,7 +806,7 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`); */ writeFile(source: string, destination: string, data: TemplateData = this, options?: TemplateOptions, copyOptions: CopyOptions = {}) { // Convert to any because ejs types doesn't support string[] https://github.com/DefinitelyTyped/DefinitelyTyped/pull/63315 - // eslint-disable-next-line @typescript-eslint/no-explicit-any + const root: any = this.jhipsterTemplatesFolders ?? this.templatePath(); try { return this.renderTemplate(source, destination, data, { root, ...options }, { noGlob: true, ...copyOptions }); @@ -809,7 +818,7 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`); /** * write the given files using provided options. */ - async writeFiles(options: WriteFileOptions): Promise { + async writeFiles(options: WriteFileOptions): Promise { const paramCount = Object.keys(options).filter(key => ['sections', 'blocks', 'templates'].includes(key)).length; assert(paramCount > 0, 'One of sections, blocks or templates is required'); assert(paramCount === 1, 'Only one of sections, blocks or templates must be provided'); @@ -847,23 +856,26 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`); } const normalizeEjs = file => file.replace('.ejs', ''); - const resolveCallback = (val, fallback?) => { - if (val === undefined) { + const resolveCallback = (maybeCallback, fallback?) => { + if (maybeCallback === undefined) { if (typeof fallback === 'function') { return resolveCallback(fallback); } return fallback; } - if (typeof val === 'boolean' || typeof val === 'string') { - return val; + if (typeof maybeCallback === 'boolean' || typeof maybeCallback === 'string') { + return maybeCallback; } - if (typeof val === 'function') { - return val.call(this, templateData) || false; + if (typeof maybeCallback === 'function') { + return (maybeCallback as any).call(this, templateData) || false; } - throw new Error(`Type not supported ${val}`); + throw new Error(`Type not supported ${maybeCallback}`); }; - const renderTemplate = async ({ sourceFile, destinationFile, options, noEjs, transform, binary }) => { + const renderTemplate = async ({ condition, sourceFile, destinationFile, options, noEjs, transform, binary }) => { + if (condition !== undefined && !resolveCallback(condition, true)) { + return undefined; + } const extension = extname(sourceFile); const isBinary = binary || ['.png', '.jpg', '.gif', '.svg', '.ico'].includes(extension); const appendEjs = noEjs === undefined ? !isBinary && extension !== '.ejs' : !noEjs; @@ -897,17 +909,13 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; } } sourceFileFrom = existingTemplates.shift(); - - if (sourceFileFrom === undefined) { - throw new Error(`Template file ${sourceFile} was not found at ${rootTemplatesAbsolutePath}`); - } } else if (typeof rootTemplatesAbsolutePath === 'string') { sourceFileFrom = this.templatePath(rootTemplatesAbsolutePath, sourceFile); } else { sourceFileFrom = this.templatePath(sourceFile); } - const file = customizeTemplatePath({ sourceFile, resolvedSourceFile: sourceFileFrom, destinationFile: targetFile }); + const file = customizeTemplatePath.call(this, { sourceFile, resolvedSourceFile: sourceFileFrom, destinationFile: targetFile }); if (!file) { return undefined; } @@ -916,13 +924,17 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; let templatesRoots: string[] = [].concat(rootTemplatesAbsolutePath); for (const contextCustomizeTemplatePath of contextCustomizeTemplatePaths) { - const file = contextCustomizeTemplatePath({ - namespace: this.options.namespace, - sourceFile, - resolvedSourceFile: sourceFileFrom, - destinationFile: targetFile, - templatesRoots, - }); + const file = contextCustomizeTemplatePath.call( + this, + { + namespace: this.options.namespace, + sourceFile, + resolvedSourceFile: sourceFileFrom, + destinationFile: targetFile, + templatesRoots, + }, + context, + ); if (!file) { return undefined; } @@ -931,6 +943,10 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; templatesRoots = file.templatesRoots; } + if (sourceFileFrom === undefined) { + throw new Error(`Template file ${sourceFile} was not found at ${rootTemplatesAbsolutePath}`); + } + try { if (!appendEjs && extname(sourceFileFrom) !== '.ejs') { await (this as any).copyTemplateAsync(sourceFileFrom, targetFile); @@ -969,7 +985,7 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; } catch (error) { throw new Error(`Error rendering template ${sourceFileFrom} to ${targetFile}: ${error}`, { cause: error }); } - if (!isBinary && transform && transform.length) { + if (!isBinary && transform?.length) { this.editFile(targetFile, ...transform); } return targetFile; @@ -1049,7 +1065,7 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; return { sourceFile, destinationFile, noEjs, transform: derivedTransform }; } - const { options, file, renameTo, transform: fileTransform = [], binary } = fileSpec; + const { condition, options, file, renameTo, transform: fileTransform = [], binary } = fileSpec; let { sourceFile, destinationFile } = fileSpec; if (typeof fileTransform === 'boolean') { @@ -1070,7 +1086,7 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; } const override = resolveCallback(fileSpec.override); - if (override !== undefined && !override && (this as any).fs.exists(destinationFile)) { + if (override !== undefined && !override && (this as any).fs.exists(destinationFile.replace(/\.jhi$/, ''))) { this.log.debug(`skipping file ${destinationFile}`); return undefined; } @@ -1084,6 +1100,7 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; } return { + condition, sourceFile, destinationFile, options, @@ -1104,7 +1121,7 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; }); } - const files = await Promise.all(parsedTemplates.map(template => renderTemplate(template))); + const files = await Promise.all(parsedTemplates.map(template => renderTemplate(template)).filter(Boolean)); this.log.debug(`Time taken to write files: ${new Date().getMilliseconds() - startTime}ms`); return files.filter(file => file); } @@ -1147,20 +1164,20 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; let originalContent; try { originalContent = this.readDestination(filePath); - } catch (_error) { + } catch { // null return should be treated like an error. } if (!originalContent) { const { ignoreNonExisting, create } = actualOptions; const errorMessage = typeof ignoreNonExisting === 'string' ? ` ${ignoreNonExisting}.` : ''; - if (ignoreNonExisting || (!create && this.ignoreNeedlesError)) { - this.log(`${chalk.yellow('\nUnable to find ')}${filePath}.${chalk.yellow(errorMessage)}\n`); - // return a noop. - const noop = () => noop; - return noop; - } if (!create || transformCallbacks.length === 0) { + if (ignoreNonExisting || this.ignoreNeedlesError) { + this.log(`${chalk.yellow('\nUnable to find ')}${filePath}.${chalk.yellow(errorMessage)}\n`); + // return a noop. + const noop = () => noop; + return noop; + } throw new Error(`Unable to find ${filePath}. ${errorMessage}`); } // allow to edit non existing files @@ -1261,6 +1278,8 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; * @param javaDependencies * @param gradleCatalog Gradle catalog file path, true for generator-jhipster's generator catalog of falsy for blueprint catalog */ + loadJavaDependenciesFromGradleCatalog(javaDependencies: Record, gradleCatalogFile?: string): void; + loadJavaDependenciesFromGradleCatalog(javaDependencies: Record, mainGenerator: boolean): void; loadJavaDependenciesFromGradleCatalog(javaDependencies: Record, gradleCatalog?: string | boolean): void { if (typeof gradleCatalog !== 'string') { const tomlFile = '../resources/gradle/libs.versions.toml'; @@ -1269,7 +1288,7 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; const gradleLibsVersions = this.readTemplate(gradleCatalog)?.toString(); if (gradleLibsVersions) { - Object.assign(javaDependencies, this.prepareDependencies(getGradleLibsVersionsProperties(gradleLibsVersions!), 'java')); + Object.assign(javaDependencies, this.prepareDependencies(getGradleLibsVersionsProperties(gradleLibsVersions), 'java')); } } @@ -1277,7 +1296,7 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; destination: Record, packageJsonFile: string = this.templatePath('../resources/package.json'), ): void { - const { devDependencies, dependencies } = this.fs.readJSON(packageJsonFile, {}) as any; + const { devDependencies, dependencies } = this.fs.readJSON(packageJsonFile, {}); this.loadNodeDependencies(destination, { ...devDependencies, ...dependencies }); } @@ -1355,8 +1374,8 @@ templates: ${JSON.stringify(existingTemplates, null, 2)}`; /** * Create a simple-git instance using current destinationPath as baseDir. */ - createGit() { - return simpleGit({ baseDir: this.destinationPath() }).env({ + createGit(options?: Parameters[0]) { + return simpleGit({ baseDir: this.destinationPath(), ...options }).env({ ...process.env, LANG: 'en', }); diff --git a/generators/base-entity-changes/generator.ts b/generators/base-entity-changes/generator.ts index 1795e6c37e2f..aae56c854189 100644 --- a/generators/base-entity-changes/generator.ts +++ b/generators/base-entity-changes/generator.ts @@ -22,6 +22,9 @@ import { PRIORITY_NAMES } from '../base-application/priorities.js'; import { loadEntitiesAnnotations, loadEntitiesOtherSide } from '../base-application/support/index.js'; import { relationshipEquals, relationshipNeedsForeignKeyRecreationOnly } from '../liquibase/support/index.js'; import { addEntitiesOtherRelationships } from '../server/support/index.js'; +import type { TaskTypes as ApplicationTaskTypes } from '../../lib/types/application/tasks.js'; +import type { ApplicationType } from '../../lib/types/application/application.js'; +import type { Entity } from '../../lib/types/application/entity.js'; import type { BaseChangelog } from './types.js'; const { DEFAULT, WRITING_ENTITIES, POST_WRITING_ENTITIES } = PRIORITY_NAMES; @@ -41,10 +44,19 @@ const baseChangelog: () => Omit = ApplicationTaskTypes & { + DefaultTaskParam: { entityChanges?: BaseChangelog[] }; + WritingEntitiesTaskParam: { entityChanges?: BaseChangelog[] }; + PostWritingEntitiesTaskParam: { entityChanges?: BaseChangelog[] }; +}; + /** * This is the base class for a generator for every generator. */ -export default abstract class GeneratorBaseEntityChanges extends GeneratorBaseApplication { +export default abstract class GeneratorBaseEntityChanges< + E extends Entity = Entity, + A extends ApplicationType = ApplicationType, +> extends GeneratorBaseApplication> { recreateInitialChangelog!: boolean; private entityChanges!: any[]; diff --git a/generators/base-workspaces/command.ts b/generators/base-workspaces/command.ts index 9a52554793a2..9ef8f931de58 100644 --- a/generators/base-workspaces/command.ts +++ b/generators/base-workspaces/command.ts @@ -1,4 +1,4 @@ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { options: {}, diff --git a/generators/base-workspaces/generator.ts b/generators/base-workspaces/generator.ts index d47d39e20cfe..40b4839cc5cf 100644 --- a/generators/base-workspaces/generator.ts +++ b/generators/base-workspaces/generator.ts @@ -25,8 +25,11 @@ import BaseGenerator from '../base/index.js'; import { YO_RC_FILE } from '../generator-constants.js'; import { GENERATOR_BOOTSTRAP_APPLICATION } from '../generator-list.js'; import { normalizePathEnd } from '../base/support/path.js'; +import type { TaskTypes } from '../../lib/types/base/tasks.js'; +import type { Entity } from '../../lib/types/application/entity.js'; +import type { ApplicationType } from '../../lib/types/application/application.js'; +import { CUSTOM_PRIORITIES, PRIORITY_NAMES } from './priorities.js'; import command from './command.js'; -import { PRIORITY_NAMES, CUSTOM_PRIORITIES } from './priorities.js'; const { PROMPTING_WORKSPACES, @@ -41,10 +44,22 @@ const { END, } = PRIORITY_NAMES; +type WorkspacesTypes = ApplicationType> = TaskTypes & { + LoadingTaskParam: TaskTypes['LoadingTaskParam'] & { applications: A[] }; + PreparingTaskParam: TaskTypes['PreparingTaskParam'] & { applications: A[] }; + PostPreparingTaskParam: TaskTypes['PostPreparingTaskParam'] & { applications: A[] }; + DefaultTaskParam: TaskTypes['DefaultTaskParam'] & { applications: A[] }; + WritingTaskParam: TaskTypes['WritingTaskParam'] & { applications: A[] }; + PostWritingTaskParam: TaskTypes['PostWritingTaskParam'] & { applications: A[] }; + InstallTaskParam: TaskTypes['InstallTaskParam'] & { applications: A[] }; + PostInstallTaskParam: TaskTypes['PostInstallTaskParam'] & { applications: A[] }; + EndTaskParam: TaskTypes['EndTaskParam'] & { applications: A[] }; +}; + /** * This is the base class for a generator that generates entities. */ -export default abstract class BaseWorkspacesGenerator extends BaseGenerator { +export default abstract class BaseWorkspacesGenerator extends BaseGenerator { static PROMPTING_WORKSPACES = BaseGenerator.asPriority(PROMPTING_WORKSPACES); static CONFIGURING_WORKSPACES = BaseGenerator.asPriority(CONFIGURING_WORKSPACES); @@ -66,7 +81,8 @@ export default abstract class BaseWorkspacesGenerator extends BaseGenerator { } } - protected loadWorkspacesConfig({ context = this } = {}) { + protected loadWorkspacesConfig(opts?) { + const { context = this } = opts ?? {}; context.appsFolders = this.jhipsterConfig.appsFolders; context.directoryPath = this.jhipsterConfig.directoryPath ?? './'; } diff --git a/generators/base-workspaces/internal/deployments.ts b/generators/base-workspaces/internal/deployments.ts index 4c02235d0b19..7f573bac1e74 100644 --- a/generators/base-workspaces/internal/deployments.ts +++ b/generators/base-workspaces/internal/deployments.ts @@ -17,8 +17,8 @@ * limitations under the License. */ import { defaults } from 'lodash-es'; -import { applicationOptions, deploymentOptions } from '../../../jdl/index.js'; -import { loadDerivedPlatformConfig, loadPlatformConfig, loadDerivedServerAndPlatformProperties } from '../../server/support/index.js'; +import { applicationOptions, deploymentOptions } from '../../../lib/jhipster/index.js'; +import { loadDerivedPlatformConfig, loadDerivedServerAndPlatformProperties, loadPlatformConfig } from '../../server/support/index.js'; import type { GeneratorBaseCore } from '../../index.js'; const { OptionNames } = applicationOptions; diff --git a/generators/base-workspaces/internal/docker-base.js b/generators/base-workspaces/internal/docker-base.ts similarity index 87% rename from generators/base-workspaces/internal/docker-base.js rename to generators/base-workspaces/internal/docker-base.ts index ca76c933e356..18c3d12be4f6 100644 --- a/generators/base-workspaces/internal/docker-base.js +++ b/generators/base-workspaces/internal/docker-base.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -20,11 +21,13 @@ import { existsSync } from 'fs'; import chalk from 'chalk'; import { convertSecretToBase64, createBase64Secret, removeFieldsWithNullishValues } from '../../base/support/index.js'; -import { applicationTypes, buildToolTypes, getConfigWithDefaults } from '../../../jdl/jhipster/index.js'; +import { applicationTypes, buildToolTypes, getConfigWithDefaults } from '../../../lib/jhipster/index.js'; import { GENERATOR_JHIPSTER } from '../../generator-constants.js'; import { loadDeploymentConfig } from '../../base-workspaces/internal/index.js'; import { loadDerivedAppConfig } from '../../app/support/index.js'; import { loadDerivedPlatformConfig, loadDerivedServerConfig } from '../../server/support/index.js'; +import { loadCommandConfigsIntoApplication } from '../../../lib/command/load.js'; +import { lookupCommandsConfigs } from '../../../lib/command/lookup-commands-configs.js'; const { MAVEN } = buildToolTypes; const { MONOLITH, MICROSERVICE, GATEWAY } = applicationTypes; @@ -61,9 +64,7 @@ export function checkImages() { * Generate Jwt Secret */ export function generateJwtSecret() { - if (this.jwtSecretKey === undefined) { - this.jwtSecretKey = this.jhipsterConfig.jwtSecretKey = createBase64Secret(this.options.reproducibleTests); - } + this.jwtSecretKey = this.jhipsterConfig.jwtSecretKey = this.jwtSecretKey ?? createBase64Secret(this.options.reproducibleTests); } /** @@ -80,7 +81,7 @@ export function configureImageNames() { /** * Load config from this.appFolders */ -export function loadConfigs() { +export async function loadConfigs() { this.appConfigs = []; this.gatewayNb = 0; this.monolithicNb = 0; @@ -91,7 +92,7 @@ export function loadConfigs() { // Loading configs this.log.debug(`Apps folders: ${this.appsFolders}`); - this.appsFolders.forEach((appFolder, index) => { + for (const [index, appFolder] of this.appsFolders.entries()) { const path = this.destinationPath(`${this.directoryPath + appFolder}`); this.log.debug(chalk.red.bold(`App folder ${path}`)); if (this.fs.exists(`${path}/.yo-rc.json`)) { @@ -99,6 +100,12 @@ export function loadConfigs() { config.composePort = serverPort + index; this.log.debug(chalk.red.bold(`${config.baseName} has compose port ${config.composePort} and appIndex ${config.applicationIndex}`)); + loadCommandConfigsIntoApplication({ + source: config, + application: config, + commandsConfigs: this.options.commandsConfigs ?? (await lookupCommandsConfigs()), + }); + loadDerivedAppConfig({ application: config }); loadDerivedPlatformConfig({ application: config }); loadDerivedServerConfig({ application: config }); @@ -117,7 +124,7 @@ export function loadConfigs() { } else { throw new Error(`Application '${appFolder}' is not found in the path '${this.directoryPath}'`); } - }); + } } export function setClusteredApps() { @@ -128,7 +135,7 @@ export function setClusteredApps() { } } -export function loadFromYoRc() { +export async function loadFromYoRc() { loadDeploymentConfig.call(this); this.useKafka = false; @@ -136,7 +143,7 @@ export function loadFromYoRc() { this.useMemcached = false; this.useRedis = false; - loadConfigs.call(this); + await loadConfigs.call(this); if (this.microserviceNb > 0 || this.gatewayNb > 0) { this.deploymentApplicationType = MICROSERVICE; } else { diff --git a/generators/base-workspaces/internal/docker-prompts.js b/generators/base-workspaces/internal/docker-prompts.ts similarity index 98% rename from generators/base-workspaces/internal/docker-prompts.js rename to generators/base-workspaces/internal/docker-prompts.ts index 9b2e31f48966..fc8d1aa8321c 100644 --- a/generators/base-workspaces/internal/docker-prompts.js +++ b/generators/base-workspaces/internal/docker-prompts.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -20,7 +21,7 @@ import { readFileSync, readdirSync, statSync } from 'node:fs'; import { join } from 'node:path'; import chalk from 'chalk'; -import { applicationTypes, monitoringTypes, serviceDiscoveryTypes } from '../../../jdl/jhipster/index.js'; +import { applicationTypes, monitoringTypes, serviceDiscoveryTypes } from '../../../lib/jhipster/index.js'; import { convertSecretToBase64 } from '../../base/support/index.js'; import { loadConfigs } from './docker-base.js'; @@ -181,7 +182,7 @@ async function askForApps() { const props = await this.prompt(prompts); this.appsFolders = this.jhipsterConfig.appsFolders = props.chosenApps; - loadConfigs.call(this); + await loadConfigs.call(this); } /** @@ -388,7 +389,7 @@ export function getAppFolders(directory, deploymentApplicationType) { deploymentApplicationType === (fileData['generator-jhipster'].applicationType ?? MONOLITH) || (deploymentApplicationType === MICROSERVICE && fileData['generator-jhipster'].applicationType === GATEWAY)) ) { - appsFolders.push(file.match(/([^/]*)\/*$/)[1]); + appsFolders.push(/([^/]*)\/*$/.exec(file)[1]); } } catch (err) { this.log.error(chalk.red(`${yoRcFile}: this .yo-rc.json can't be read`)); diff --git a/generators/base-workspaces/priorities.ts b/generators/base-workspaces/priorities.ts index 3bc19e2559a4..19f6302e1644 100644 --- a/generators/base-workspaces/priorities.ts +++ b/generators/base-workspaces/priorities.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { QUEUE_PREFIX, PRIORITY_NAMES as PRIORITY_NAMES_BASE, QUEUES as QUEUES_BASE } from '../base/priorities.js'; +import { PRIORITY_NAMES as PRIORITY_NAMES_BASE, QUEUES as QUEUES_BASE, QUEUE_PREFIX } from '../base/priorities.js'; const { DEFAULT } = PRIORITY_NAMES_BASE; diff --git a/generators/base/api.d.ts b/generators/base/api.d.ts index 3c164ea41c24..9572d228a1da 100644 --- a/generators/base/api.d.ts +++ b/generators/base/api.d.ts @@ -1,72 +1,68 @@ -import type { BaseOptions, BaseFeatures, ArgumentSpec, CliOptionSpec } from 'yeoman-generator'; -import type { RequireAtLeastOne, SetOptional } from 'type-fest'; +import type { BaseFeatures, BaseOptions } from 'yeoman-generator'; import type CoreGenerator from '../base-core/index.js'; +import type { ApplicationType } from '../../lib/types/application/application.js'; +import type { Entity } from '../../lib/types/application/entity.js'; +import type { ApplicationOptions } from '../../lib/types/application/options.js'; +import type { JDLApplicationConfig } from '../../lib/jdl/core/types/parsing.js'; +import type { JHipsterConfigs } from '../../lib/command/types.js'; export type ApplicationWithConfig = { - config: { - [key: string]: string | boolean | number | string[]; - }; + config: Record; entities: Record; }; -export type JHipsterGeneratorOptions = BaseOptions & { - /* cli options */ - commandName: string; - positionalArguments?: unknown[]; - - /* yeoman options */ - skipYoResolve?: boolean; - sharedData: any; - force?: boolean; - - /* base options */ - applicationId?: string; - applicationWithConfig?: ApplicationWithConfig; - /** - * @deprecated - */ - applicationWithEntities?: any; - creationTimestamp?: string; - ignoreErrors?: boolean; - ignoreNeedlesError?: boolean; - reproducible?: boolean; - reproducibleTests?: boolean; - skipPriorities?: string[]; - skipWriting?: boolean; - entities?: string[]; - disableBlueprints?: boolean; - - /* Init based application */ - fromInit?: boolean; - - /* blueprint options */ - blueprints?: string; - blueprint?: any; - jhipsterContext?: any; - composeWithLocalBlueprint?: boolean; - - /* generate-blueprint options */ - localBlueprint?: boolean; - - /* jdl generator options */ - jdlFile?: string; - - /* application options */ - baseName?: string; - db?: string; - applicationType?: string; - skipUserManagement?: boolean; - skipDbChangelog?: boolean; - recreateInitialChangelog?: boolean; - - /* workspaces options */ - generateApplications?: boolean; - generateWorkspaces?: boolean; - generateWith?: string; - monorepository?: boolean; - workspaces?: boolean; - workspacesFolders?: string[]; -}; +export type JHipsterGeneratorOptions = BaseOptions & + ApplicationOptions & { + /* cli options */ + commandName: string; + programName: string; + positionalArguments?: unknown[]; + createEnvBuilder?: any; + /** @experimental */ + jdlDefinition?: JDLApplicationConfig; + /** @experimental */ + commandsConfigs?: JHipsterConfigs; + + /* yeoman options */ + skipYoResolve?: boolean; + sharedData: any; + force?: boolean; + + /* base options */ + applicationId?: string; + applicationWithConfig?: ApplicationWithConfig; + /** + * @deprecated + */ + applicationWithEntities?: any; + reproducibleTests?: boolean; + skipPriorities?: string[]; + skipWriting?: boolean; + entities?: string[]; + + jhipsterContext?: any; + composeWithLocalBlueprint?: boolean; + + /** boostrap options */ + applyDefaults?: (data: data) => data; + + /* generate-blueprint options */ + localBlueprint?: boolean; + + /* jdl generator options */ + jdlFile?: string; + + /* application options */ + db?: string; + + /* workspaces options */ + generateApplications?: boolean; + generateWorkspaces?: boolean; + generateWith?: string; + monorepository?: boolean; + workspaces?: boolean; + workspacesFolders?: string[]; + }; export type JHipsterGeneratorFeatures = BaseFeatures & { priorityArgs?: boolean; @@ -115,7 +111,8 @@ export type JHipsterGeneratorFeatures = BaseFeatures & { queueCommandTasks?: boolean; }; -// eslint-disable-next-line no-use-before-define +export type NeedleCallback = (content: string) => string; + export type EditFileCallback = (this: Generator, content: string, filePath: string) => string; export type EditFileOptions = { create?: boolean; ignoreNonExisting?: boolean | string; assertModified?: boolean }; @@ -124,16 +121,19 @@ export type CascatedEditFileCallback = ( ...callbacks: EditFileCallback[] ) => CascatedEditFileCallback; -export type WriteFileTemplate = +type DataCallback, Generator = CoreGenerator> = Type | ((this: Generator, data: DataType) => Type); + +export type WriteFileTemplate, Generator = CoreGenerator> = | string | ((this: Generator, data: DataType, filePath: string) => string) | { + condition?: DataCallback; /** source file */ - sourceFile?: string | ((this: Generator, data: DataType) => string); + sourceFile?: DataCallback; /** destination file */ - destinationFile?: string | ((this: Generator, destinationFile: DataType) => string); + destinationFile?: DataCallback; /** @deprecated, use sourceFile instead */ - file?: string | ((this: Generator, data: DataType) => string); + file?: DataCallback; /** @deprecated, use destinationFile instead */ renameTo?: string | ((this: Generator, data: DataType, filePath: string) => string); /** transforms (files processing) to be applied */ @@ -142,10 +142,10 @@ export type WriteFileTemplate = binary?: boolean; /** ejs options. Refer to https://ejs.co/#docs */ options?: Record; - override?: boolean | ((this: Generator, data: DataType) => boolean); + override?: DataCallback; }; -export type WriteFileBlock = { +export type WriteFileBlock, Generator = CoreGenerator> = { /** relative path were sources are placed */ from?: ((this: Generator, data: DataType) => string) | string; /** relative path were the files should be written, fallbacks to from/path */ @@ -157,16 +157,19 @@ export type WriteFileBlock = { condition?: (this: Generator, data: DataType) => boolean | undefined; /** transforms (files processing) to be applied */ transform?: boolean | (() => string)[]; - templates: WriteFileTemplate[]; + templates: WriteFileTemplate[]; }; -export type WriteFileSection = Record[]>; +export type WriteFileSection, Generator = CoreGenerator> = Record< + string, + WriteFileBlock[] +>; -export type WriteFileOptions = { +export type WriteFileOptions, Generator = CoreGenerator> = { /** transforms (files processing) to be applied */ transform?: EditFileCallback[]; /** context to be used as template data */ - context?: DataType; + context?: any; /** config passed to render methods */ renderOptions?: Record; /** @@ -183,93 +186,21 @@ export type WriteFileOptions = { }) => undefined | { sourceFile: string; resolvedSourceFile: string; destinationFile: string }; } & ( | { - sections: WriteFileSection; + sections: WriteFileSection; } | { /** templates to be written */ - templates: WriteFileTemplate; + templates: WriteFileTemplate[]; } | { /** blocks to be written */ - blocks: WriteFileBlock[]; + blocks: WriteFileBlock[]; } ); -export type JHispterChoices = string[] | { value: string; name: string }[]; - -export type JHipsterOption = SetOptional & { - name?: string; - scope?: 'storage' | 'blueprint' | 'control' | 'generator'; - env?: string; - choices?: JHispterChoices; -}; - export type ValidationResult = { debug?: unknown; info?: string | string[]; warning?: string | string[]; error?: string | string[]; }; - -export type PromptSpec = { - type: 'input' | 'list' | 'confirm' | 'checkbox'; - message: string | ((any) => string); - when?: boolean | ((any) => boolean); - default?: any | ((any) => any); - filter?: any | ((any) => any); - transformer?: any | ((any) => any); - validate?: any | ((any) => any); -}; - -export type JHipsterArgumentConfig = SetOptional & { scope?: 'storage' | 'blueprint' | 'generator' }; - -export type ConfigSpec = { - description?: string; - choices?: JHispterChoices; - - cli?: SetOptional & { env?: string }; - argument?: JHipsterArgumentConfig; - prompt?: PromptSpec | ((gen: CoreGenerator & { jhipsterConfigWithDefaults: Record }, config: ConfigSpec) => PromptSpec); - scope?: 'storage' | 'blueprint' | 'generator'; - /** - * The callback receives the generator as input for 'generator' scope. - * The callback receives jhipsterConfigWithDefaults as input for 'storage' (default) scope. - * The callback receives blueprintStorage contents as input for 'blueprint' scope. - */ - default?: string | boolean | number | string[] | ((this: CoreGenerator | void, ctx: any) => string | boolean | number | string[]); - /** - * Configure the generator according to the selected configuration. - */ - configure?: (gen: CoreGenerator) => void; -}; - -export type JHipsterArguments = Record; - -export type JHipsterOptions = Record; - -export type JHipsterConfigs = Record>; - -export type JHipsterCommandDefinition = { - arguments?: JHipsterArguments; - options?: JHipsterOptions; - configs?: JHipsterConfigs; - /** - * Import options from a generator. - * @example ['server', 'jhipster-blueprint:server'] - */ - import?: string[]; - /** - * @experimental - * Compose with generator. - * @example ['server', 'jhipster-blueprint:server'] - */ - compose?: string[]; - /** - * Override options from the generator been blueprinted. - */ - override?: boolean; - /** - * Load old options definition (yeoman's `this.options()`) from the generator. - */ - loadGeneratorOptions?: boolean; -}; diff --git a/generators/base/blueprints.spec.ts b/generators/base/blueprints.spec.ts index 80df047469c3..102cc81fc1a7 100644 --- a/generators/base/blueprints.spec.ts +++ b/generators/base/blueprints.spec.ts @@ -1,20 +1,17 @@ -/* eslint-disable max-classes-per-file */ -import { before, it, describe, expect, esmocha } from 'esmocha'; -import { RunResult } from 'yeoman-test'; -import { toHaveBeenCalledAfter } from 'jest-extended'; +import type { Mock } from 'node:test'; +import { mock } from 'node:test'; +import { before, describe, expect, it } from 'esmocha'; -import { basicHelpers as helpers } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { packageJson } from '../../lib/index.js'; import BaseGenerator from './index.js'; -expect.extend({ toHaveBeenCalledAfter }); const jhipsterVersion = packageJson.version; describe('generator - base - with blueprint', () => { describe('generate application with a version-compatible blueprint', () => { - let runResult: RunResult; before(async () => { - runResult = await helpers + await helpers .runTestBlueprintGenerator() .withFakeTestBlueprint('generator-jhipster-myblueprint', { packageJson: { @@ -27,12 +24,12 @@ describe('generator - base - with blueprint', () => { .withJHipsterConfig() .withOptions({ skipChecks: false, - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }); }); it('creates expected default files for server and angular', () => { - expect(runResult.mockedGenerators['jhipster-myblueprint:test-blueprint'].called); + runResult.assertGeneratorComposed('jhipster-myblueprint:test-blueprint'); }); it('blueprint version is saved in .yo-rc.json', () => { @@ -59,7 +56,7 @@ describe('generator - base - with blueprint', () => { .withJHipsterConfig() .withOptions({ skipChecks: false, - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }), ).rejects.toThrow(/targets JHipster v1.1.1 and is not compatible with this JHipster version/)); }); @@ -79,14 +76,13 @@ describe('generator - base - with blueprint', () => { .withJHipsterConfig() .withOptions({ skipChecks: false, - blueprint: 'myblueprint', + blueprint: ['myblueprint'], })); }); describe('generate application with a peer version-compatible blueprint', () => { - let runResult: RunResult; before(async () => { - runResult = await helpers + await helpers .runTestBlueprintGenerator() .withFakeTestBlueprint('generator-jhipster-myblueprint', { packageJson: { @@ -97,7 +93,7 @@ describe('generator - base - with blueprint', () => { }) .withOptions({ skipChecks: false, - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }); }); @@ -124,15 +120,14 @@ describe('generator - base - with blueprint', () => { .withJHipsterConfig() .withOptions({ skipChecks: false, - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }), ).rejects.toThrow(/targets JHipster v1.1.1 and is not compatible with this JHipster version/)); }); describe('generate application with a engines compatible blueprint', () => { - let runResult: RunResult; before(async () => { - runResult = await helpers + await helpers .runTestBlueprintGenerator() .withFakeTestBlueprint('generator-jhipster-myblueprint', { packageJson: { @@ -149,7 +144,7 @@ describe('generator - base - with blueprint', () => { }) .withOptions({ skipChecks: false, - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }); }); @@ -182,7 +177,7 @@ describe('generator - base - with blueprint', () => { .withJHipsterConfig() .withOptions({ skipChecks: false, - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }), ).rejects.toThrow(/targets JHipster v1.1.1 and is not compatible with this JHipster version/)); }); @@ -190,9 +185,8 @@ describe('generator - base - with blueprint', () => { describe('generator - base - with scoped blueprint', () => { describe('generate monolith application with scoped blueprint', () => { - let runResult: RunResult; before(async () => { - runResult = await helpers + await helpers .runTestBlueprintGenerator() .withFakeTestBlueprint('@jhipster/generator-jhipster-scoped-blueprint') .withMockedGenerators(['@jhipster/jhipster-scoped-blueprint:test-blueprint']) @@ -203,7 +197,7 @@ describe('generator - base - with scoped blueprint', () => { }); it('should compose with blueprint', () => { - expect(runResult.mockedGenerators['@jhipster/jhipster-scoped-blueprint:test-blueprint'].called).toBe(true); + runResult.assertGeneratorComposed('@jhipster/jhipster-scoped-blueprint:test-blueprint'); }); it('blueprint version is saved in .yo-rc.json', () => { @@ -216,9 +210,8 @@ describe('generator - base - with scoped blueprint', () => { describe('generator - base - with blueprints disabled', () => { describe('should not compose with blueprint', () => { - let runResult: RunResult; before(async () => { - runResult = await helpers + await helpers .runTestBlueprintGenerator() .withFakeTestBlueprint('@jhipster/generator-jhipster-scoped-blueprint') .withMockedGenerators(['@jhipster/jhipster-scoped-blueprint:test-blueprint']) @@ -230,7 +223,7 @@ describe('generator - base - with blueprints disabled', () => { }); it('should compose with blueprint', () => { - expect(runResult.mockedGenerators['@jhipster/jhipster-scoped-blueprint:test-blueprint'].called).toBeFalsy; + runResult.assertGeneratorNotComposed('@jhipster/jhipster-scoped-blueprint:test-blueprint'); }); }); }); @@ -248,7 +241,7 @@ describe('generator - base - with blueprint with constructor error', () => { await expect( helpers .runTestBlueprintGenerator() - .withGenerators([[BlueprintBlueprintedGenerator, 'jhipster-throwing-constructor:test-blueprint']]) + .withGenerators([[BlueprintBlueprintedGenerator, { namespace: 'jhipster-throwing-constructor:test-blueprint' }]]) .withJHipsterConfig() .withOptions({ blueprints: 'generator-jhipster-throwing-constructor', @@ -260,10 +253,8 @@ describe('generator - base - with blueprint with constructor error', () => { describe('generator - base - with multiple blueprints', () => { describe('generate monolith application with scoped blueprint', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers + await helpers .runTestBlueprintGenerator() .withMockedGenerators(['jhipster-blueprint1:test-blueprint', 'jhipster-blueprint2:test-blueprint']) .withJHipsterConfig() @@ -272,8 +263,8 @@ describe('generator - base - with multiple blueprints', () => { }); }); it('should compose with blueprints once', () => { - expect(runResult.mockedGenerators['jhipster-blueprint1:test-blueprint'].calledOnce); - expect(runResult.mockedGenerators['jhipster-blueprint2:test-blueprint'].calledOnce); + runResult.assertGeneratorComposedOnce('jhipster-blueprint1:test-blueprint'); + runResult.assertGeneratorComposedOnce('jhipster-blueprint2:test-blueprint'); }); }); }); @@ -299,10 +290,9 @@ describe('generator - base - local blueprint', () => { `; describe('generates application', () => { - let runResult; before(async () => { - runResult = await helpers - .run(BLUEPRINT_NS) + await helpers + .runJHipster(BLUEPRINT_NS, { useEnvironmentBuilder: true }) .withFiles({ '.blueprint/app/index.mjs': BLUEPRINT_CONTENTS }) .commitFiles() .withJHipsterConfig(); @@ -344,10 +334,11 @@ describe('generator - base-blueprint', () => { 'end', ]; - const createPrioritiesFakes = (): Record => { - const mockedPriorities: Record = {}; + const createPrioritiesFakes = (): Record number>> => { + const mockedPriorities: Record number>> = {}; + let callOrder = 0; priorities.forEach(priority => { - mockedPriorities[priority] = esmocha.fn(); + mockedPriorities[priority] = mock.fn(() => callOrder++); }); return mockedPriorities; }; @@ -494,29 +485,29 @@ describe('generator - base-blueprint', () => { describe('priorities', () => { describe('when every priority has been implemented', () => { - let mockedPriorities: Record; + let mockedPriorities: Record number>>; let mockBlueprintSubGen; before(() => { mockedPriorities = createPrioritiesFakes(); mockBlueprintSubGen = createAllBlueprint(mockedPriorities); - return helpers.run(mockBlueprintSubGen); + return helpers.run(mockBlueprintSubGen).withJHipsterGenerators({ useDefaultMocks: true }); }); priorities.forEach((priority, idx) => { it(`should execute ${priority} once`, () => { - expect(mockedPriorities[priority]).toBeCalledTimes(1); + expect(mockedPriorities[priority].mock.callCount()).toBe(1); }); if (idx > 0) { const priorityBefore = priorities[idx - 1]; it(`should execute ${priority} after ${priorityBefore} `, () => { - expect(mockedPriorities[priority]).toHaveBeenCalledAfter(mockedPriorities[priorityBefore]); + expect(mockedPriorities[priority].mock.calls[0].result).toBeGreaterThan(mockedPriorities[priorityBefore].mock.calls[0].result!); }); } }); }); describe('when custom priorities are missing and the blueprint is sbs', () => { - let mockedPriorities; + let mockedPriorities: Record number>>; let mockBlueprintSubGen; before(() => { mockedPriorities = createPrioritiesFakes(); @@ -554,17 +545,17 @@ describe('generator - base-blueprint', () => { return super.end; } }; - return helpers.create(mockBlueprintSubGen).run(); + return helpers.run(mockBlueprintSubGen).withJHipsterGenerators({ useDefaultMocks: true }); }); priorities.forEach(priority => { if (['composing', 'loading', 'preparing', 'postWriting'].includes(priority)) { it(`should not execute ${priority}`, () => { - expect(mockedPriorities[priority]).not.toBeCalled(); + expect(mockedPriorities[priority].mock.callCount()).toBe(0); }); } else { it(`should execute ${priority} once`, () => { - expect(mockedPriorities[priority]).toBeCalledTimes(1); + expect(mockedPriorities[priority].mock.callCount()).toBe(1); }); } }); diff --git a/generators/base/command.ts b/generators/base/command.ts index 5a604768e54b..f33d6722fac0 100644 --- a/generators/base/command.ts +++ b/generators/base/command.ts @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/types.js'; -const command: JHipsterCommandDefinition = { +const command = { options: { useVersionPlaceholders: { description: 'replace mutable versions with placeholders', @@ -41,6 +41,7 @@ const command: JHipsterCommandDefinition = { disableBlueprints: { description: 'Disable blueprints support', type: Boolean, + scope: 'generator', }, debugEnabled: { name: 'debug', @@ -57,6 +58,7 @@ const command: JHipsterCommandDefinition = { skipPrompts: { description: 'Skip prompts', type: Boolean, + scope: 'generator', }, ignoreNeedlesError: { description: 'Ignore needles failures', @@ -65,6 +67,6 @@ const command: JHipsterCommandDefinition = { scope: 'generator', }, }, -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/base/generator.spec.ts b/generators/base/generator.spec.ts index a17308665791..7000e5416695 100644 --- a/generators/base/generator.spec.ts +++ b/generators/base/generator.spec.ts @@ -18,11 +18,11 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect, esmocha } from 'esmocha'; +import { before, describe, esmocha, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import EnvironmentBuilder from '../../cli/environment-builder.mjs'; -import { defaultHelpers as helpers } from '../../testing/index.js'; +import { defaultHelpers as helpers } from '../../lib/testing/index.js'; import { getCommandHelpOutput, shouldSupportFeatures } from '../../test/support/tests.js'; import BaseGenerator from './index.js'; @@ -81,9 +81,12 @@ describe(`generator - ${generator}`, () => { } before(async () => { - await helpers.run(CustomGenerator).withOptions({ - skipPriorities: ['prompting', 'writing', 'postWriting'], - }); + await helpers + .run(CustomGenerator as any) + .withJHipsterGenerators({ useDefaultMocks: true }) + .withOptions({ + skipPriorities: ['prompting', 'writing', 'postWriting'], + }); }); it('should skip priorities', async () => { diff --git a/generators/base/generator.ts b/generators/base/generator.ts index 2a6e591161ec..b87e9ce8d854 100644 --- a/generators/base/generator.ts +++ b/generators/base/generator.ts @@ -22,22 +22,21 @@ import chalk from 'chalk'; import semver from 'semver'; import type { ComposeOptions } from 'yeoman-generator'; +import { union } from 'lodash-es'; import { packageJson } from '../../lib/index.js'; import CoreGenerator from '../base-core/index.js'; import { loadStoredAppOptions } from '../app/support/index.js'; +import type { TaskTypes as BaseTaskTypes, GenericTaskGroup } from '../../lib/types/base/tasks.js'; import { packageNameToNamespace } from './support/index.js'; -import { mergeBlueprints, parseBluePrints, loadBlueprintsFromConfiguration, normalizeBlueprintName } from './internal/index.js'; +import { loadBlueprintsFromConfiguration, mergeBlueprints, normalizeBlueprintName, parseBluePrints } from './internal/index.js'; import { PRIORITY_NAMES } from './priorities.js'; -import { BaseGeneratorDefinition, GenericTaskGroup } from './tasks.js'; import type { JHipsterGeneratorFeatures, JHipsterGeneratorOptions } from './api.js'; import { LOCAL_BLUEPRINT_PACKAGE_NAMESPACE } from './support/constants.js'; /** * Base class that contains blueprints support. */ -export default class JHipsterBaseBlueprintGenerator< - Definition extends BaseGeneratorDefinition = BaseGeneratorDefinition, -> extends CoreGenerator { +export default class JHipsterBaseBlueprintGenerator extends CoreGenerator { fromBlueprint!: boolean; sbsBlueprint?: boolean; delegateToBlueprint?: boolean; @@ -100,12 +99,19 @@ export default class JHipsterBaseBlueprintGenerator< return this.delegateToBlueprint ? ({} as TaskGroupType) : tasksGetter(); } + /** + * Utility method to get typed objects for autocomplete. + */ + asAnyTaskGroup(taskGroup: GenericTaskGroup): GenericTaskGroup { + return taskGroup; + } + /** * Priority API stub for blueprints. * * Initializing priority is used to show logo and tasks related to preparing for prompts, like loading constants. */ - get initializing(): GenericTaskGroup { + get initializing() { return this.asInitializingTaskGroup(this._initializing()); } @@ -120,9 +126,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asInitializingTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asInitializingTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -131,8 +137,8 @@ export default class JHipsterBaseBlueprintGenerator< * * Prompting priority is used to prompt users for configuration values. */ - get prompting(): GenericTaskGroup { - return this.asPromptingTaskGroup(this._prompting()); + get prompting() { + return this._prompting(); } /** @@ -146,9 +152,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asPromptingTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asPromptingTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -157,8 +163,8 @@ export default class JHipsterBaseBlueprintGenerator< * * Configuring priority is used to customize and validate the configuration. */ - get configuring(): GenericTaskGroup { - return this.asConfiguringTaskGroup(this._configuring()); + get configuring() { + return this._configuring(); } /** @@ -172,9 +178,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asConfiguringTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asConfiguringTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -183,8 +189,8 @@ export default class JHipsterBaseBlueprintGenerator< * * Composing should be used to compose with others generators. */ - get composing(): GenericTaskGroup { - return this.asComposingTaskGroup(this._composing()); + get composing() { + return this._composing(); } /** @@ -198,9 +204,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asComposingTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asComposingTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -209,16 +215,16 @@ export default class JHipsterBaseBlueprintGenerator< * * ComposingComponent priority should be used to handle component configuration order. */ - get composingComponent(): GenericTaskGroup { + get composingComponent(): any { return {}; } /** * Utility method to get typed objects for autocomplete. */ - asComposingComponentTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asComposingComponentTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -228,7 +234,7 @@ export default class JHipsterBaseBlueprintGenerator< * Loading should be used to load application configuration from jhipster configuration. * Before this priority the configuration should be considered dirty, while each generator configures itself at configuring priority, another generator composed at composing priority can still change it. */ - get loading(): GenericTaskGroup { + get loading(): any { return this.asLoadingTaskGroup(this._loading()); } @@ -243,9 +249,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asLoadingTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asLoadingTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -254,8 +260,8 @@ export default class JHipsterBaseBlueprintGenerator< * * Preparing should be used to generate derived properties. */ - get preparing(): GenericTaskGroup { - return this.asPreparingTaskGroup(this._preparing()); + get preparing() { + return this._preparing(); } /** @@ -269,9 +275,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asPreparingTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asPreparingTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -280,16 +286,16 @@ export default class JHipsterBaseBlueprintGenerator< * * Preparing should be used to generate derived properties. */ - get postPreparing(): GenericTaskGroup { - return this.asPreparingTaskGroup({}); + get postPreparing() { + return {}; } /** * Utility method to get typed objects for autocomplete. */ - asPostPreparingTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asPostPreparingTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -298,8 +304,8 @@ export default class JHipsterBaseBlueprintGenerator< * * Default priority should used as misc customizations. */ - get default(): GenericTaskGroup { - return this.asDefaultTaskGroup(this._default()); + get default() { + return this._default(); } /** @@ -313,9 +319,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asDefaultTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asDefaultTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -324,8 +330,8 @@ export default class JHipsterBaseBlueprintGenerator< * * Writing priority should used to write files. */ - get writing(): GenericTaskGroup { - return this.asWritingTaskGroup(this._writing()); + get writing() { + return this._writing(); } /** @@ -339,9 +345,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asWritingTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asWritingTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -350,8 +356,8 @@ export default class JHipsterBaseBlueprintGenerator< * * PostWriting priority should used to customize files. */ - get postWriting(): GenericTaskGroup { - return this.asPostWritingTaskGroup(this._postWriting()); + get postWriting() { + return this._postWriting(); } /** @@ -365,9 +371,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asPostWritingTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asPostWritingTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -376,8 +382,8 @@ export default class JHipsterBaseBlueprintGenerator< * * Install priority should used to prepare the project. */ - get install(): GenericTaskGroup { - return this.asInstallTaskGroup(this._install()); + get install() { + return this._install(); } /** @@ -391,9 +397,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asInstallTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asInstallTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -402,8 +408,8 @@ export default class JHipsterBaseBlueprintGenerator< * * PostWriting priority should used to customize files. */ - get postInstall(): GenericTaskGroup { - return this.asPostInstallTaskGroup(this._postInstall()); + get postInstall() { + return this._postInstall(); } /** @@ -417,9 +423,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asPostInstallTaskGroup( - taskGroup: GenericTaskGroup, - ): GenericTaskGroup { + asPostInstallTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -428,8 +434,8 @@ export default class JHipsterBaseBlueprintGenerator< * * End priority should used to say good bye and print instructions. */ - get end(): GenericTaskGroup { - return this.asEndTaskGroup(this._end()); + get end() { + return this._end(); } /** @@ -443,7 +449,9 @@ export default class JHipsterBaseBlueprintGenerator< /** * Utility method to get typed objects for autocomplete. */ - asEndTaskGroup(taskGroup: GenericTaskGroup): GenericTaskGroup { + asEndTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { return taskGroup; } @@ -454,7 +462,7 @@ export default class JHipsterBaseBlueprintGenerator< protected async composeWithBlueprints(subGen?: string, options?: ComposeOptions) { if (subGen === undefined) { const { namespace } = this.options; - if (!namespace || !namespace.startsWith('jhipster:')) { + if (!namespace?.startsWith('jhipster:')) { throw new Error(`Generator is not blueprintable ${namespace}`); } subGen = namespace.substring('jhipster:'.length); @@ -539,12 +547,13 @@ export default class JHipsterBaseBlueprintGenerator< private async _configureBlueprints() { let argvBlueprints = this.options.blueprints || ''; // check for old single blueprint declaration - const blueprint = this.options.blueprint; + let { blueprint } = this.options; if (blueprint) { - this.log.warn('--blueprint option is deprecated. Please use --blueprints instead'); - if (!argvBlueprints.split(',').includes(blueprint)) { - argvBlueprints = `${blueprint},${argvBlueprints}`; + if (typeof blueprint === 'string') { + blueprint = [blueprint]; } + this.log.warn('--blueprint option is deprecated. Please use --blueprints instead'); + argvBlueprints = union(blueprint, argvBlueprints.split(',')).join(','); } const blueprints = mergeBlueprints(parseBluePrints(argvBlueprints), loadBlueprintsFromConfiguration(this.config)); @@ -653,7 +662,7 @@ export default class JHipsterBaseBlueprintGenerator< */ private _findBlueprintVersion(blueprintPkgName) { const blueprintPackageJson = this._findBlueprintPackageJson(blueprintPkgName); - if (!blueprintPackageJson || !blueprintPackageJson.version) { + if (!blueprintPackageJson?.version) { this.log.warn(`Could not retrieve version of blueprint '${blueprintPkgName}'`); return undefined; } diff --git a/generators/base/internal/blueprint.spec.ts b/generators/base/internal/blueprint.spec.ts index 44705ca8f09b..1cbc5330e8b5 100644 --- a/generators/base/internal/blueprint.spec.ts +++ b/generators/base/internal/blueprint.spec.ts @@ -1,5 +1,5 @@ import assert from 'assert'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { mergeBlueprints, normalizeBlueprintName, parseBluePrints, removeBlueprintDuplicates } from './blueprint.js'; describe('generator - base - internal - blueprint', () => { diff --git a/generators/base/internal/blueprint.js b/generators/base/internal/blueprint.ts similarity index 95% rename from generators/base/internal/blueprint.js rename to generators/base/internal/blueprint.ts index ba6197023e59..c92993030f64 100644 --- a/generators/base/internal/blueprint.js +++ b/generators/base/internal/blueprint.ts @@ -26,7 +26,7 @@ import { requireNamespace } from '@yeoman/namespace'; */ export function loadBlueprintsFromConfiguration(config) { // handle both config based on yeoman's Storage object, and direct configuration loaded from .yo-rc.json - const configuration = config && config.getAll && typeof config.getAll === 'function' ? config.getAll() || {} : config; + const configuration = config?.getAll && typeof config.getAll === 'function' ? config.getAll() || {} : config; // load blueprints from config file const blueprints = configuration.blueprints || []; @@ -45,7 +45,7 @@ export function loadBlueprintsFromConfiguration(config) { * no processing is performed and it is returned as is. * @returns {Array} an array that contains the info for each blueprint */ -export function parseBluePrints(blueprints) { +export function parseBluePrints(blueprints?: string | { name: string; version: string }[]) { if (Array.isArray(blueprints)) { return blueprints; } @@ -133,8 +133,8 @@ export function normalizeBlueprintName(blueprint) { } return ns.with({ unscoped: `generator-jhipster-${ns.unscoped}` }).toString(); // eslint-disable-next-line no-empty - } catch (e) {} - if (blueprint && blueprint.startsWith('@')) { + } catch {} + if (blueprint?.startsWith('@')) { return blueprint; } if (blueprint && !blueprint.startsWith('generator-jhipster')) { diff --git a/generators/base/internal/command.ts b/generators/base/internal/command.ts deleted file mode 100644 index 3b90542ce4ce..000000000000 --- a/generators/base/internal/command.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { JHipsterArguments, JHipsterConfigs } from '../api.js'; - -export const extractArgumentsFromConfigs = (configs: JHipsterConfigs | undefined): JHipsterArguments => { - if (!configs) return {}; - return Object.fromEntries( - Object.entries(configs) - .filter(([_name, def]) => def.argument) - .map(([name, def]) => [ - name, - { - description: def.description, - ...def.argument, - }, - ]), - ) as JHipsterArguments; -}; diff --git a/generators/base/internal/index.ts b/generators/base/internal/index.ts index 511ad83a3062..4b28488a64d4 100644 --- a/generators/base/internal/index.ts +++ b/generators/base/internal/index.ts @@ -17,4 +17,3 @@ * limitations under the License. */ export * from './blueprint.js'; -export * from './command.js'; diff --git a/generators/base/priorities.js b/generators/base/priorities.ts similarity index 100% rename from generators/base/priorities.js rename to generators/base/priorities.ts diff --git a/generators/base/shared-data.ts b/generators/base/shared-data.ts index dc5db5bcf564..76c8b1781692 100644 --- a/generators/base/shared-data.ts +++ b/generators/base/shared-data.ts @@ -21,7 +21,8 @@ import { rm } from 'fs/promises'; import { isAbsolute, join, relative } from 'path'; import { lt as semverLessThan } from 'semver'; import { defaults } from 'lodash-es'; -import { MemFsEditor, create } from 'mem-fs-editor'; +import type { MemFsEditor } from 'mem-fs-editor'; +import { create } from 'mem-fs-editor'; import { type BaseApplication } from '../base-application/types.js'; import { GENERATOR_JHIPSTER } from '../generator-constants.js'; import { type Control } from './types.js'; @@ -65,7 +66,7 @@ export default class SharedData string | undefined> = []; + let customizeRemoveFiles: ((file: string) => string | undefined)[] = []; const removeFiles = async (assertions: { removedInVersion?: string } | string, ...files: string[]) => { if (typeof assertions === 'string') { files = [assertions, ...files]; @@ -103,7 +104,8 @@ export default class SharedData>) => { + cleanupFiles: async (cleanup: Record) => { + if (!jhipsterOldVersion) return; await Promise.all( Object.entries(cleanup).map(async ([version, files]) => { const stringFiles: string[] = []; diff --git a/generators/base/support/basename.spec.ts b/generators/base/support/basename.spec.ts index 610ce5d2eaa0..573a994ca3be 100644 --- a/generators/base/support/basename.spec.ts +++ b/generators/base/support/basename.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { getFrontendAppName } from './basename.js'; describe('generator > base', () => { diff --git a/generators/base/support/basename.ts b/generators/base/support/basename.ts index f738f38ecea4..d265edd0b6be 100644 --- a/generators/base/support/basename.ts +++ b/generators/base/support/basename.ts @@ -5,7 +5,7 @@ import { camelCase } from 'lodash-es'; */ export const getFrontendAppName = ({ baseName }: { baseName: string }) => { const name = camelCase(baseName) + (baseName.endsWith('App') ? '' : 'App'); - return name.match(/^\d/) ? 'App' : name; + return /^\d/.exec(name) ? 'App' : name; }; export const getMicroserviceAppName = ({ microserviceName }: { microserviceName: string }) => { diff --git a/generators/base/support/configuration-helpers/options.js b/generators/base/support/configuration-helpers/options.ts similarity index 93% rename from generators/base/support/configuration-helpers/options.js rename to generators/base/support/configuration-helpers/options.ts index e6917f1e0677..63576135cbf7 100644 --- a/generators/base/support/configuration-helpers/options.js +++ b/generators/base/support/configuration-helpers/options.ts @@ -21,5 +21,4 @@ const isReproducible = generator => { return generator.options.reproducible; }; -// eslint-disable-next-line import/prefer-default-export export { isReproducible }; diff --git a/generators/base/support/contents.spec.ts b/generators/base/support/contents.spec.ts index 566cd67b188d..4d6ef9e13d69 100644 --- a/generators/base/support/contents.spec.ts +++ b/generators/base/support/contents.spec.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { normalizeLineEndings, stripMargin } from './contents.js'; describe('generator - base - support - contents', () => { diff --git a/generators/base/support/contents.ts b/generators/base/support/contents.ts index 01dc16db2a8c..063e2d25481b 100644 --- a/generators/base/support/contents.ts +++ b/generators/base/support/contents.ts @@ -23,7 +23,7 @@ * @param lineEnding * @returns normalized line ending string */ -// eslint-disable-next-line import/prefer-default-export + export function normalizeLineEndings(str: string, lineEnding: string): string { return str.replace(/\r\n|\r|\n/g, lineEnding); } @@ -35,7 +35,7 @@ export function normalizeLineEndings(str: string, lineEnding: string): string { * * @param {string} content - the string to process */ -// eslint-disable-next-line import/prefer-default-export + export const stripMargin = content => { return content.replace(/^[ ]*\|/gm, ''); }; diff --git a/generators/base/support/faker.ts b/generators/base/support/faker.ts index 33b49ce7cae4..c438d438b602 100644 --- a/generators/base/support/faker.ts +++ b/generators/base/support/faker.ts @@ -1,4 +1,3 @@ -/* eslint-disable max-classes-per-file */ /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -39,7 +38,7 @@ class RandexpWithFaker extends Randexp { } } -class FakerWithRandexp extends Faker { +export class FakerWithRandexp extends Faker { createRandexp(regexp: string | RegExp, flags?: string) { return new RandexpWithFaker(regexp, flags, this); } @@ -50,7 +49,7 @@ class FakerWithRandexp extends Faker { * @param nativeLanguage - native language * @returns Faker instance */ -// eslint-disable-next-line import/prefer-default-export + export async function createFaker(nativeLanguage = 'en') { nativeLanguage = languageToJavaLanguage(nativeLanguage); let locale; @@ -58,11 +57,10 @@ export async function createFaker(nativeLanguage = 'en') { // We need a Faker instance for each entity, to build additional fake instances, use the locale from the exported localized faker instance. // See https://github.com/faker-js/faker/pull/642 try { - // eslint-disable-next-line import/no-dynamic-require, quotes locale = (await import(`@faker-js/faker`))[nativeLanguage]; - } catch (error) { + } catch { // Faker not implemented for the native language, fallback to en. - // eslint-disable-next-line import/no-unresolved, import/no-dynamic-require + locale = (await import('@faker-js/faker')).en; } diff --git a/generators/base/support/hipster.ts b/generators/base/support/hipster.ts index 72c27452ec69..f3799ab58afc 100644 --- a/generators/base/support/hipster.ts +++ b/generators/base/support/hipster.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { stringHashCode } from './string.js'; +import { stringHashCode } from '../../../lib/utils/string.js'; /** * get a hipster based on the applications name. diff --git a/generators/base/support/index.ts b/generators/base/support/index.ts index 8776111c8956..7dd80722a854 100644 --- a/generators/base/support/index.ts +++ b/generators/base/support/index.ts @@ -18,17 +18,17 @@ */ export * from './basename.js'; export * from './configuration-helpers/options.js'; -export * from './config.js'; +export * from '../../../lib/utils/object.js'; export * from './contents.js'; export * from './faker.js'; export { default as getHipster } from './hipster.js'; -export { default as createJHipster7Context } from './jhipster7-context.js'; -export * from './logger.js'; +export * from './jhipster7-context.js'; +export * from '../../../lib/utils/logger.js'; export * from './namespace.js'; export * from './needles.js'; export * from './path.js'; export { default as httpsGet } from './remote.js'; export * from './secret.js'; -export * from './string.js'; +export * from '../../../lib/utils/string.js'; export * from './timestamp.js'; export * from './write-files.js'; diff --git a/generators/base/support/jhipster7-context.js b/generators/base/support/jhipster7-context.ts similarity index 84% rename from generators/base/support/jhipster7-context.js rename to generators/base/support/jhipster7-context.ts index 14ba76ec7b56..4d19376ad963 100644 --- a/generators/base/support/jhipster7-context.js +++ b/generators/base/support/jhipster7-context.ts @@ -2,7 +2,7 @@ import chalk from 'chalk'; import { camelCase } from 'lodash-es'; -import { isReservedTableName } from '../../../jdl/jhipster/reserved-keywords.js'; +import { isReservedTableName } from '../../../lib/jhipster/reserved-keywords.js'; import { getJavaValueGeneratorForType, getJoinTableName, @@ -12,12 +12,35 @@ import { } from '../../server/support/index.js'; import { getDBCExtraOption } from '../../spring-data-relational/support/database-data.js'; import { getJdbcUrl, getR2dbcUrl } from '../../spring-data-relational/support/database-url.js'; -import { fieldTypes } from '../../../jdl/index.js'; -import { upperFirstCamelCase } from './string.js'; +import { fieldTypes } from '../../../lib/jhipster/index.js'; +import { upperFirstCamelCase } from '../../../lib/utils/string.js'; const { BYTES, BYTE_BUFFER } = fieldTypes.RelationalOnlyDBTypes; -const deprecatedProperties = { +export const jhipster7deprecatedProperties = { + devDatabaseType: { + behaviorOnlyReason: 'v8: devDatabaseType is only used in jhipster:spring-data-relational generator', + get: ({ data }) => { + if (data.devDatabaseType !== undefined) return data.devDatabaseType; + const fallbackValue = data.prodDatabaseType ?? data.databaseType; + + console.log( + `JHipster v8 behavior change(devDatabaseType is only used in jhipster:spring-data-relational generator): devDatabaseType is not set, using fallback: ${fallbackValue}`, + ); + return fallbackValue; + }, + }, + prodDatabaseType: { + behaviorOnlyReason: 'v8: prodDatabaseType is only used in jhipster:spring-data-relational generator', + get: ({ data }) => { + if (data.prodDatabaseType !== undefined) return data.prodDatabaseType; + + console.log( + `JHipster v8 behavior change(prodDatabaseType is only used in jhipster:spring-data-relational generator): devDatabaseType is not set, using fallback: ${data.databaseType}`, + ); + return data.databaseType; + }, + }, GRADLE_VERSION: { replacement: 'gradleVersion', get: ({ data }) => data.gradleVersion, @@ -212,6 +235,7 @@ const deprecatedProperties = { get: () => (...args) => + // @ts-expect-error getJoinTableName(...args).value, }, getJavaValueGeneratorForType: { @@ -248,7 +272,7 @@ const deprecatedProperties = { data.prettierExtensions, }, _generateSqlSafeName: { - replacement: 'relationshipSqlSafeName', + replacement: 'relationshipSqlSafeName property', get: () => name => (isReservedTableName(name, 'sql') ? `e_${name}` : name), }, isFilterableType: { @@ -260,7 +284,7 @@ const deprecatedProperties = { get: () => getSpecificationBuildForType, }, getColumnName: { - replacement: 'entityTableName || relationship.columnName', + replacement: 'entityTableName || relationship.columnName property', get: () => hibernateSnakeCase, }, isUsingBuiltInUser: { @@ -299,13 +323,15 @@ const getPropertBuilder = const { generator, data } = context; const value = prop in data ? data[prop] : undefined; - if (prop in deprecatedProperties) { - const { replacement, get } = deprecatedProperties[prop]; + if (prop in jhipster7deprecatedProperties) { + const { replacement, get, behaviorOnlyReason } = jhipster7deprecatedProperties[prop]; const fallBackValue = get(context); const valueDesc = prop in data ? `Value: ${value}, ` : ''; - log( - `Template data ${chalk.yellow(String(prop))} was removed and should be replaced with ${chalk.yellow(replacement)}. ${valueDesc}FallbackValue: ${fallBackValue}`, - ); + if (!behaviorOnlyReason) { + log( + `Template data ${chalk.yellow(String(prop))} was removed and should be replaced with ${chalk.yellow(replacement)}. ${valueDesc}FallbackValue: ${fallBackValue}`, + ); + } return value ?? fallBackValue; } if (prop?.startsWith?.('DOCKER_')) { @@ -333,7 +359,7 @@ const getPropertBuilder = return undefined; }; -const createHandler = ({ log } = {}) => { +const createHandler = ({ log }: { log: (msg: string) => void } = { log: msg => console.log(msg) }) => { const getProperty = getPropertBuilder({ log }); return { ...Object.fromEntries( @@ -378,6 +404,6 @@ const createHandler = ({ log } = {}) => { }; }; -export default function createJHipster7Context(generator, data, options) { +export function createJHipster7Context(generator, data, options: { log: (msg: string) => void }) { return new Proxy({ generator, data }, createHandler(options)); } diff --git a/generators/base/support/namespace.ts b/generators/base/support/namespace.ts index 94017a229cf5..bbbf537a0455 100644 --- a/generators/base/support/namespace.ts +++ b/generators/base/support/namespace.ts @@ -21,7 +21,7 @@ * @param {string} packageName - name of the blueprint's package name * @returns {string} namespace of the blueprint */ -// eslint-disable-next-line import/prefer-default-export + export function packageNameToNamespace(packageName) { return packageName.replace('generator-', ''); } diff --git a/generators/base/support/needles.spec.ts b/generators/base/support/needles.spec.ts index 0261ad78dbc4..40ec8d20809f 100644 --- a/generators/base/support/needles.spec.ts +++ b/generators/base/support/needles.spec.ts @@ -16,8 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { it, describe, expect, esmocha, beforeEach } from 'esmocha'; -import { checkContentIn, insertContentBeforeNeedle, createNeedleCallback, createBaseNeedle } from './needles.js'; +import test from 'node:test'; +import { beforeEach, describe, esmocha, expect, it } from 'esmocha'; +import { createJHipsterLogger } from '../../../lib/utils/logger.js'; +import { checkContentIn, createBaseNeedle, createNeedleCallback, insertContentBeforeNeedle } from './needles.js'; describe('needles - support', () => { describe('checkContentIn', () => { @@ -218,37 +220,38 @@ ${needlePrefix} jhipster-needle-a-needle" }); it('returned function should throw on missing content', () => { - expect(() => createNeedleCallback({ contentToAdd, needle }).call({ log() {} })).toThrow(/content is required/); + const needleCallback = createNeedleCallback({ contentToAdd, needle }); + // @ts-expect-error invalid params + expect(() => needleCallback.call({ log() {} })).toThrow(/content is required/); }); it('returned function should throw on missing needle', () => { - expect(() => createNeedleCallback({ contentToAdd, needle }).call({ log() {} }, 'no needle')).toThrow( - /Missing required jhipster-needle/, - ); + const log = test.mock.fn(createJHipsterLogger()); + const needleCallback = createNeedleCallback({ contentToAdd, needle }); + // @ts-expect-error invalid params + expect(() => needleCallback.call({ log } as any, 'no needle')).toThrow(/Missing required jhipster-needle/); }); it('returned function should not throw on optional missing needle', () => { const content = 'no needle'; - const log = () => {}; - log.warn = () => {}; - expect(createNeedleCallback({ contentToAdd, needle, optional: true }).call({ log }, content, 'file')).toBe(content); + const log = test.mock.fn(createJHipsterLogger()); + const needleCallback = createNeedleCallback({ contentToAdd, needle, optional: true }); + expect(needleCallback.call({ log } as any, content, 'file')).toBe(content); }); it('returned function should add contentToAdd', () => { - expect(createNeedleCallback({ contentToAdd, needle }).call({ log() {} }, `\\\\ jhipster-needle-${needle}`, 'file')) - .toMatchInlineSnapshot(` + const log = test.mock.fn(createJHipsterLogger()); + const needleCallback = createNeedleCallback({ contentToAdd, needle }); + expect(needleCallback.call({ log } as any, `\\\\ jhipster-needle-${needle}`, 'file')).toMatchInlineSnapshot(` "content to add \\\\ jhipster-needle-a-needle" `); }); it('returned function should add contentToAdd array', () => { - expect( - createNeedleCallback({ contentToAdd: [contentToAdd, `${contentToAdd}2`], needle }).call( - { log() {} }, - `\\\\ jhipster-needle-${needle}`, - ), - ).toMatchInlineSnapshot(` + const log = test.mock.fn(createJHipsterLogger()); + const needleCallback = createNeedleCallback({ contentToAdd: [contentToAdd, `${contentToAdd}2`], needle }); + expect(needleCallback.call({ log } as any, `\\\\ jhipster-needle-${needle}`, 'any-file')).toMatchInlineSnapshot(` "content to add content to add2 \\\\ jhipster-needle-a-needle" @@ -276,7 +279,6 @@ content to add2 }); it('should throw with options and empty needles', () => { - // @ts-expect-error expect(() => createBaseNeedle({ optional: true }, {})).toThrow(/At least 1 needle is required/); }); @@ -286,12 +288,13 @@ content to add2 it('should throw with filePath without generator', () => { const filePath = 'file.foo'; + // @ts-expect-error invalid params expect(() => createBaseNeedle({ filePath }, needles)).toThrow(/when passing filePath, the generator is required/); }); it('should execute editFile if generator and filePath is passed', () => { const filePath = 'file.foo'; - createBaseNeedle.call(generator, { filePath }, needles); + createBaseNeedle.call(generator as any, { filePath }, needles); expect(generator.editFile).toBeCalledTimes(1); expect(generator.editFile.mock.lastCall[0]).toBe(filePath); expect(typeof generator.editFile.mock.lastCall[1]).toBe('function'); diff --git a/generators/base/support/needles.ts b/generators/base/support/needles.ts index f577357a5534..0d874903c21a 100644 --- a/generators/base/support/needles.ts +++ b/generators/base/support/needles.ts @@ -18,8 +18,8 @@ */ import assert from 'assert'; import { escapeRegExp, kebabCase } from 'lodash-es'; -import CoreGenerator from '../../base-core/index.js'; -import { CascatedEditFileCallback, EditFileCallback } from '../api.js'; +import type CoreGenerator from '../../base-core/index.js'; +import type { CascatedEditFileCallback, EditFileCallback, NeedleCallback } from '../api.js'; import { joinCallbacks } from './write-files.js'; export type NeedleInsertion = { @@ -210,7 +210,7 @@ export const createNeedleCallback = , + needles: Record, +): NeedleCallback; +export function createBaseNeedle(needles: Record): NeedleCallback; +export function createBaseNeedle( + this: Generator, + options: Omit & { filePath: string }, + needles: Record, +): CascatedEditFileCallback; export function createBaseNeedle( this: Generator | void, - options: NeedleFileInsertion | Record, + options: Omit | Record, needles?: Record, ): EditFileCallback | CascatedEditFileCallback { const actualNeedles = needles === undefined ? (options as Record) : needles; const actualOptions: Partial | undefined = needles === undefined ? {} : (options as NeedleFileInsertion); assert(actualNeedles, 'needles is required'); - const { filePath, optional = false, ignoreWhitespaces = true } = actualOptions; - let { needlesPrefix } = actualOptions; - needlesPrefix = needlesPrefix ? `${needlesPrefix}-` : ''; + const { needlesPrefix, filePath, ...needleOptions } = actualOptions; + needleOptions.optional = needleOptions.optional ?? false; + needleOptions.ignoreWhitespaces = needleOptions.ignoreWhitespaces ?? true; const callbacks = Object.entries(actualNeedles) .filter(([_key, contentToAdd]) => contentToAdd) .map(([key, contentToAdd]) => - createNeedleCallback({ needle: `${needlesPrefix}${kebabCase(key)}`, contentToAdd, optional, ignoreWhitespaces }), + createNeedleCallback({ ...needleOptions, needle: `${needlesPrefix ? `${needlesPrefix}-` : ''}${kebabCase(key)}`, contentToAdd }), ); assert(callbacks.length > 0, 'At least 1 needle is required'); diff --git a/generators/base/support/path.ts b/generators/base/support/path.ts index d72a6ac2de5a..4a32a59c9d5b 100644 --- a/generators/base/support/path.ts +++ b/generators/base/support/path.ts @@ -16,5 +16,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// eslint-disable-next-line import/prefer-default-export + export const normalizePathEnd = (directory: string): string => (directory.endsWith('/') ? directory : `${directory}/`); diff --git a/generators/base/support/remote.js b/generators/base/support/remote.ts similarity index 100% rename from generators/base/support/remote.js rename to generators/base/support/remote.ts diff --git a/generators/base/support/secret.ts b/generators/base/support/secret.ts index eaa1dc78ac2d..b748fa9fb5bb 100644 --- a/generators/base/support/secret.ts +++ b/generators/base/support/secret.ts @@ -52,3 +52,10 @@ export function createBase64Secret(len?: number | boolean, reproducible = false) } return Buffer.from(createSecret(len)).toString('base64'); } + +/** + * Create a strong secret from a timestamp and a base name + */ +export function createSafeSecret(timestamp: number, baseName: string) { + return Buffer.from(`${timestamp}-${baseName}`).toString('base64'); +} diff --git a/generators/base/support/timestamp.spec.ts b/generators/base/support/timestamp.spec.ts index 50bba295239c..9e2d79821625 100644 --- a/generators/base/support/timestamp.spec.ts +++ b/generators/base/support/timestamp.spec.ts @@ -16,20 +16,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { parseChangelog } from './timestamp.js'; describe('generator - base - support - timestamp', () => { describe('::parseChangelog', () => { describe('when not passing parameters', () => { it('throws', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any expect(() => parseChangelog(undefined as any)).toThrow(/^changelogDate is required\.$/); }); }); describe('when passing a number', () => { it('throws', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // @ts-expect-error invalid argument expect(() => parseChangelog(123)).toThrow(/^changelogDate 123 must be a string\.$/); }); }); diff --git a/generators/base/support/timestamp.ts b/generators/base/support/timestamp.ts index 88987aba77c1..c69e1701d384 100644 --- a/generators/base/support/timestamp.ts +++ b/generators/base/support/timestamp.ts @@ -65,11 +65,16 @@ export function parseChangelog(changelogDate: string): Date { if (changelogDate.length !== 14) { throw new Error(`changelogDate ${changelogDate} is not a valid changelogDate.`); } - const formattedDate = `${changelogDate.substring(0, 4)}-${changelogDate.substring(4, 6)}-${changelogDate.substring( - 6, - 8, - )}T${changelogDate.substring(8, 10)}:${changelogDate.substring(10, 12)}:${changelogDate.substring(12, 14)}+00:00`; - return new Date(Date.parse(formattedDate)); + const zeroFallback = (val: string, fallback: string) => (/^0+$/.test(val) ? fallback : val); + const year = zeroFallback(changelogDate.substring(0, 4), '2024'); + const month = zeroFallback(changelogDate.substring(4, 6), '01'); + const day = zeroFallback(changelogDate.substring(6, 8), '01'); + const formattedDate = `${year}-${month}-${day}T${changelogDate.substring(8, 10)}:${changelogDate.substring(10, 12)}:${changelogDate.substring(12, 14)}+00:00`; + const parsedTimestamp = Date.parse(formattedDate); + if (isNaN(parsedTimestamp)) { + throw new Error(`changelogDate ${changelogDate} is not a valid date.`); + } + return new Date(parsedTimestamp); } /** diff --git a/generators/base/support/write-files.spec.ts b/generators/base/support/write-files.spec.ts index 415fa2036c73..74dab1748990 100644 --- a/generators/base/support/write-files.spec.ts +++ b/generators/base/support/write-files.spec.ts @@ -16,8 +16,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { it, describe, expect, esmocha } from 'esmocha'; -import { EditFileCallback } from '../api.js'; +import { describe, esmocha, expect, it } from 'esmocha'; +import type { EditFileCallback } from '../api.js'; import { joinCallbacks } from './write-files.js'; describe('generator - base - support - writeFiles', () => { @@ -32,7 +32,7 @@ describe('generator - base - support - writeFiles', () => { it('with a callback, should return the callback return', () => { const mock = esmocha.fn().mockReturnValue('return1'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any + const callback = joinCallbacks(mock as EditFileCallback); expect(callback('original', 'file')).toBe('return1'); @@ -44,7 +44,7 @@ describe('generator - base - support - writeFiles', () => { it('with two callbacks, should forward last callback and return the last callback return', () => { const mock1 = esmocha.fn().mockReturnValue('return1'); const mock2 = esmocha.fn().mockReturnValue('return2'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any + const callback = joinCallbacks(mock1 as EditFileCallback, mock2 as EditFileCallback); expect(callback('original', 'file')).toBe('return2'); diff --git a/generators/base/support/write-files.ts b/generators/base/support/write-files.ts index eb6c95edf5de..f1ba9e41c6c0 100644 --- a/generators/base/support/write-files.ts +++ b/generators/base/support/write-files.ts @@ -27,10 +27,10 @@ const isWin32 = platform() === 'win32'; * TODO move to utils when converted to typescripts * Converts multiples EditFileCallback callbacks into one. */ -// eslint-disable-next-line import/prefer-default-export + export function joinCallbacks(...callbacks: EditFileCallback[]): EditFileCallback { return function (this: Generator, content: string, filePath: string) { - if (isWin32 && content.match(/\r\n/)) { + if (isWin32 && /\r\n/.exec(content)) { const removeSlashRSlashN: EditFileCallback = ct => normalizeLineEndings(ct, '\n'); const addSlashRSlashN: EditFileCallback = ct => normalizeLineEndings(ct, '\r\n'); callbacks = [removeSlashRSlashN, ...callbacks, addSlashRSlashN]; diff --git a/generators/base/tasks.d.ts b/generators/base/tasks.d.ts deleted file mode 100644 index 268b3c5989eb..000000000000 --- a/generators/base/tasks.d.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { Control } from './types.js'; - -export type ControlTaskParam = { - control: Control & Record; -}; - -export type GenericSourceTypeDefinition = { sourceType: SourceType }; - -export type SourceTaskParam = { - source: Definition['sourceType']; -}; - -export type GenericTask = (this: ThisType, arg1: Arg1Type) => unknown; - -export type GenericTaskGroup = Record>; - -export type BaseGeneratorDefinition = Record< - | 'initializingTaskParam' - | 'promptingTaskParam' - | 'configuringTaskParam' - | 'composingTaskParam' - | 'loadingTaskParam' - | 'defaultTaskParam' - | 'writingTaskParam' - | 'postWritingTaskParam' - | 'preConflictsTaskParam' - | 'installTaskParam' - | 'postInstallTaskParam' - | 'endTaskParam', - ControlTaskParam -> & - Record<'preparingTaskParam' | 'postPreparingTaskParam' | 'postWritingTaskParam', SourceTaskParam>; diff --git a/generators/base/types-export.d.ts b/generators/base/types-export.d.ts index 62af8093edf4..e6af63578b66 100644 --- a/generators/base/types-export.d.ts +++ b/generators/base/types-export.d.ts @@ -1,4 +1,4 @@ -import Generator from './index.js'; +import type Generator from './index.js'; // Remove generics support export type BaseGenerator = Generator; diff --git a/generators/base/types.d.ts b/generators/base/types.d.ts index 2986feb6bb66..e4ce9a51f3c0 100644 --- a/generators/base/types.d.ts +++ b/generators/base/types.d.ts @@ -1,11 +1,14 @@ -import type { Entity } from '../base-application/index.ts'; +import type { Entity } from '../base-application/index.js'; +import type { ExportControlPropertiesFromCommand } from '../../lib/command/index.js'; +import type command from './command.ts'; -export type Control = { +type BaseApplicationControlProperties = ExportControlPropertiesFromCommand; + +export type Control = BaseApplicationControlProperties & { existingProject: boolean; ignoreNeedlesError: boolean; jhipsterOldVersion: string | null; useVersionPlaceholders?: boolean; - reproducible?: boolean; /** * Configure blueprints once per application. */ @@ -13,12 +16,13 @@ export type Control = { reproducibleLiquibaseTimestamp?: Date; filterEntitiesForClient?: (entity: Entity[]) => Entity[]; filterEntitiesAndPropertiesForClient?: (entity: Entity[]) => Entity[]; - customizeRemoveFiles: Array<(file: string) => string | undefined>; + customizeRemoveFiles: ((file: string) => string | undefined)[]; removeFiles: (options: { removedInVersion: string } | string, ...files: string[]) => Promise; /** * Cleanup files conditionally based on version and condition. * @example * cleanupFiles({ '6.0.0': ['file1', 'file2', [application.shouldRemove, 'file3']] }) */ - cleanupFiles: (cleanup: Record>) => Promise; + cleanupFiles: (cleanup: Record) => Promise; + getWebappTranslation?: (s: string, data?: Record) => string; }; diff --git a/generators/bootstrap-application-base/command.ts b/generators/bootstrap-application-base/command.ts index ff2b1aa357bf..3733cecbe1e7 100644 --- a/generators/bootstrap-application-base/command.ts +++ b/generators/bootstrap-application-base/command.ts @@ -16,10 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { parseCreationTimestamp } from '../base/support/timestamp.js'; -const command: JHipsterCommandDefinition = { +const command = { options: { baseName: { description: 'Application base name', @@ -29,6 +29,7 @@ const command: JHipsterCommandDefinition = { skipJhipsterDependencies: { description: "Don't write jhipster dependencies to package.json.", type: Boolean, + env: 'JHI_SKIP_JHIPSTER_DEPENDENCIES', scope: 'storage', }, creationTimestamp: { @@ -46,6 +47,6 @@ const command: JHipsterCommandDefinition = { scope: 'storage', }, }, -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/bootstrap-application-base/generator.spec.ts b/generators/bootstrap-application-base/generator.spec.ts index b64a95292eb8..ab5b4e95f9c1 100644 --- a/generators/bootstrap-application-base/generator.spec.ts +++ b/generators/bootstrap-application-base/generator.spec.ts @@ -16,20 +16,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect, beforeEach } from 'esmocha'; +import { before, beforeEach, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { defaultHelpers as helpers, runResult } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { shouldSupportFeatures } from '../../test/support/tests.js'; -import { parseChangelog } from '../base/support/timestamp.ts'; +import { parseChangelog } from '../base/support/timestamp.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const generatorPath = join(__dirname, 'index.ts'); const generator = basename(__dirname); describe(`generator - ${generator}`, () => { @@ -43,9 +42,8 @@ describe(`generator - ${generator}`, () => { describe('with', () => { describe('default config', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath).withJHipsterConfig(); + await helpers.runJHipster(generator).withJHipsterConfig(); }); it('should succeed', () => { @@ -71,7 +69,7 @@ describe(`generator - ${generator}`, () => { describe('when there is no configured lastLiquibaseTimestamp', () => { let firstChangelogDate; before(async () => { - await helpers.run(generatorPath).withJHipsterConfig(); + await helpers.runJHipster(generator).withJHipsterConfig(); firstChangelogDate = runResult.generator.dateFormatForLiquibase(); }); it('should return a valid changelog date', () => { @@ -85,7 +83,7 @@ describe(`generator - ${generator}`, () => { let firstChangelogDate; before(async () => { const lastLiquibaseTimestamp = new Date(2000, 1, 1); - await helpers.run(generatorPath).withJHipsterConfig({ lastLiquibaseTimestamp: lastLiquibaseTimestamp.getTime() }); + await helpers.runJHipster(generator).withJHipsterConfig({ lastLiquibaseTimestamp: lastLiquibaseTimestamp.getTime() }); firstChangelogDate = runResult.generator.dateFormatForLiquibase(); }); it('should return a valid changelog date', () => { @@ -104,8 +102,8 @@ describe(`generator - ${generator}`, () => { beforeEach(async () => { const lastLiquibaseTimestamp = new Date(Date.parse('2030-01-01')); await helpers - .run(generatorPath) - .withJHipsterConfig({ lastLiquibaseTimestamp: lastLiquibaseTimestamp.getTime(), creationTimestamp: null }) + .runJHipster(generator) + .withJHipsterConfig({ lastLiquibaseTimestamp: lastLiquibaseTimestamp.getTime(), creationTimestamp: undefined }) .withOptions({ reproducible: false }); firstChangelogDate = runResult.generator.dateFormatForLiquibase(); secondChangelogDate = runResult.generator.dateFormatForLiquibase(); @@ -128,7 +126,7 @@ describe(`generator - ${generator}`, () => { let firstChangelogDate; let secondChangelogDate; before(async () => { - await helpers.run(generatorPath).withJHipsterConfig(); + await helpers.runJHipster(generator).withJHipsterConfig(); firstChangelogDate = runResult.generator.dateFormatForLiquibase(false); secondChangelogDate = runResult.generator.dateFormatForLiquibase(false); }); @@ -148,7 +146,7 @@ describe(`generator - ${generator}`, () => { let secondChangelogDate; before(async () => { - await helpers.run(generatorPath).withJHipsterConfig().withOptions({ creationTimestamp: '2000-01-01' }); + await helpers.runJHipster(generator).withJHipsterConfig().withOptions({ creationTimestamp: '2000-01-01' }); firstChangelogDate = runResult.generator.dateFormatForLiquibase(); secondChangelogDate = runResult.generator.dateFormatForLiquibase(); @@ -169,7 +167,7 @@ describe(`generator - ${generator}`, () => { }); describe('with a future creationTimestamp option', () => { it('should throw', async () => { - await expect(helpers.run(generatorPath).withJHipsterConfig().withOptions({ creationTimestamp: '2030-01-01' })).rejects.toThrow( + await expect(helpers.runJHipster(generator).withJHipsterConfig().withOptions({ creationTimestamp: '2030-01-01' })).rejects.toThrow( /^Creation timestamp should not be in the future: 2030-01-01\.$/, ); }); diff --git a/generators/bootstrap-application-base/generator.ts b/generators/bootstrap-application-base/generator.ts index 6cd88471e850..35f3ec66c46f 100644 --- a/generators/bootstrap-application-base/generator.ts +++ b/generators/bootstrap-application-base/generator.ts @@ -28,16 +28,21 @@ import { addFakerToEntity, loadEntitiesAnnotations, loadEntitiesOtherSide, - stringifyApplicationData, prepareEntity as prepareEntityForTemplates, prepareField as prepareFieldForTemplates, prepareRelationship, + stringifyApplicationData, } from '../base-application/support/index.js'; import { JAVA_DOCKER_DIR } from '../generator-constants.js'; import { GENERATOR_BOOTSTRAP, GENERATOR_COMMON, GENERATOR_PROJECT_NAME } from '../generator-list.js'; import { packageJson } from '../../lib/index.js'; import { loadLanguagesConfig } from '../languages/support/index.js'; import { loadAppConfig, loadDerivedAppConfig, loadStoredAppOptions } from '../app/support/index.js'; +import { lookupCommandsConfigs } from '../../lib/command/lookup-commands-configs.js'; +import { loadCommandConfigsIntoApplication, loadCommandConfigsKeysIntoTemplatesContext } from '../../lib/command/load.js'; +import { getConfigWithDefaults } from '../../lib/jhipster/default-application-options.js'; +import { removeFieldsWithNullishValues } from '../base/support/index.js'; +import { convertFieldBlobType, getBlobContentType, isFieldBinaryType, isFieldBlobType } from '../../lib/application/field-types.js'; import { createAuthorityEntity, createUserEntity, createUserManagementEntity } from './utils.js'; import { exportJDLTransform, importJDLTransform } from './support/index.js'; @@ -78,9 +83,13 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { const destinationPath = this.destinationPath(); const jdlStorePath = this.destinationPath(this.jhipsterConfig.jdlStore); + const { jdlDefinition } = this.options; - this.features.commitTransformFactory = () => exportJDLTransform({ destinationPath, jdlStorePath }); - await this.pipeline({ refresh: true, pendingFiles: false }, importJDLTransform({ destinationPath, jdlStorePath })); + this.features.commitTransformFactory = () => exportJDLTransform({ destinationPath, jdlStorePath, jdlDefinition: jdlDefinition! }); + await this.pipeline( + { refresh: true, pendingFiles: false }, + importJDLTransform({ destinationPath, jdlStorePath, jdlDefinition: jdlDefinition! }), + ); } }, }); @@ -117,6 +126,7 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { applicationDefaults({ backendType: this.jhipsterConfig.backendType ?? 'Java', syncUserWithIdp: this.jhipsterConfig.syncUserWithIdp, + packageJsonScripts: {}, }); }, loadNodeDependencies({ application }) { @@ -140,6 +150,17 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { get preparing() { return this.asPreparingTaskGroup({ + /** + * Avoid having undefined keys in the application object when redering ejs templates + */ + async loadApplicationKeys({ application }) { + const { applyDefaults = getConfigWithDefaults, commandsConfigs = await lookupCommandsConfigs() } = this.options; + loadCommandConfigsIntoApplication({ + source: applyDefaults(removeFieldsWithNullishValues(this.config.getAll())), + application, + commandsConfigs, + }); + }, prepareApplication({ application, applicationDefaults }) { loadDerivedAppConfig({ application }); @@ -165,6 +186,7 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { backendTypeSpringBoot: ({ backendType }) => backendType === 'Java', backendTypeJavaAny: ({ backendTypeSpringBoot }) => backendTypeSpringBoot, + clientFrameworkBuiltIn: ({ clientFramework }) => ['angular', 'vue', 'react'].includes(clientFramework), }); }, userRelationship({ applicationDefaults }) { @@ -207,6 +229,11 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { configureEntity({ entityStorage, entityConfig }) { entityStorage.defaults({ fields: [], relationships: [], annotations: {} }); + for (const field of entityConfig.fields!.filter(field => field.fieldType === 'byte[]')) { + convertFieldBlobType(field); + entityStorage.save(); + } + if (entityConfig.changelogDate) { entityConfig.annotations.changelogDate = entityConfig.changelogDate; delete entityConfig.changelogDate; @@ -219,7 +246,7 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { configureRelationships({ entityName, entityStorage, entityConfig }) { // Validate entity json relationship content - entityConfig.relationships.forEach((relationship: any) => { + entityConfig.relationships!.forEach(relationship => { const { otherEntityName, relationshipType } = relationship; assert( @@ -233,7 +260,9 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { if (!relationship.relationshipSide) { // Try to create relationshipSide based on best bet. + // @ts-ignore deprecated property if (relationship.ownerSide !== undefined) { + // @ts-ignore deprecated property relationship.relationshipSide = relationship.ownerSide ? 'left' : 'right'; } else { // Missing ownerSide (one-to-many/many-to-one relationships) depends on the otherSide existence. @@ -275,7 +304,7 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { } const customUserData: any = customUser?.entityStorage.getAll() ?? {}; - Object.assign(bootstrap!, createUserEntity.call(this, { ...customUserData, ...customUserData.annotations }, application)); + Object.assign(bootstrap, createUserEntity.call(this, { ...customUserData, ...customUserData.annotations }, application)); application.user = bootstrap; } }, @@ -290,7 +319,7 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { const customUserManagementData: any = customUserManagement?.entityStorage.getAll() ?? {}; Object.assign( - bootstrap!, + bootstrap, createUserManagementEntity.call(this, { ...customUserManagementData, ...customUserManagementData.annotations }, application), ); application.userManagement = bootstrap; @@ -307,10 +336,7 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { } const customEntityData: any = customEntity?.entityStorage.getAll() ?? {}; - Object.assign( - bootstrap!, - createAuthorityEntity.call(this, { ...customEntityData, ...customEntityData.annotations }, application), - ); + Object.assign(bootstrap, createAuthorityEntity.call(this, { ...customEntityData, ...customEntityData.annotations }, application)); application.authority = bootstrap; } }, @@ -329,6 +355,19 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { this.validateResult(loadEntitiesOtherSide(entities, { application })); for (const entity of entities) { + for (const field of entity.fields) { + if (isFieldBinaryType(field)) { + if (isFieldBlobType(field)) { + field.fieldTypeBlobContent ??= getBlobContentType(field.fieldType); + } + if (application.databaseTypeCassandra || entity.databaseType === 'cassandra') { + // @ts-expect-error set another type + field.fieldType = 'ByteBuffer'; + } else if (isFieldBlobType(field)) { + field.fieldType = 'byte[]' as any; + } + } + } for (const relationship of entity.relationships) { if (relationship.ownerSide === undefined) { // ownerSide backward compatibility @@ -385,6 +424,9 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { get postPreparingEachEntity() { return this.asPostPreparingEachEntityTaskGroup({ + hasRequiredRelationship({ entity }) { + entity.anyRelationshipIsRequired = entity.relationships.some(rel => rel.relationshipRequired || rel.id); + }, checkForCircularRelationships({ entity }) { const detectCyclicRequiredRelationship = (entity, relatedEntities) => { if (relatedEntities.has(entity)) return true; @@ -404,6 +446,23 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { get default() { return this.asDefaultTaskGroup({ + /** + * Avoid having undefined keys in the application object when redering ejs templates + */ + async loadApplicationKeys({ application }) { + if (this.options.commandsConfigs) { + // Load keys passed from cli + loadCommandConfigsKeysIntoTemplatesContext({ + templatesContext: application, + commandsConfigs: this.options.commandsConfigs, + }); + } + // Load keys from main generators + loadCommandConfigsKeysIntoTemplatesContext({ + templatesContext: application, + commandsConfigs: await lookupCommandsConfigs(), + }); + }, task({ application }) { const packageJsonFiles = [this.destinationPath('package.json')]; if (application.clientRootDir) { diff --git a/generators/bootstrap-application-base/support/export-jdl-transform.ts b/generators/bootstrap-application-base/support/export-jdl-transform.ts index a1a03f72f0be..2aeff0bc50f9 100644 --- a/generators/bootstrap-application-base/support/export-jdl-transform.ts +++ b/generators/bootstrap-application-base/support/export-jdl-transform.ts @@ -5,25 +5,29 @@ import type { MemFsEditorFile } from 'mem-fs-editor'; import { Minimatch } from 'minimatch'; import { setModifiedFileState } from 'mem-fs-editor/state'; import { GENERATOR_JHIPSTER } from '../../generator-constants.js'; -import { getJDLObjectFromSingleApplication } from '../../../jdl/converters/json-to-jdl-converter.js'; -import { JSONEntity } from '../../../jdl/converters/types.js'; +import { getJDLObjectFromSingleApplication } from '../../../lib/jdl/converters/json-to-jdl-converter.js'; +import { createRuntime } from '../../../lib/jdl/core/runtime.js'; +import type { JDLApplicationConfig } from '../../../lib/jdl/core/types/parsing.js'; +import type { Entity } from '../../../lib/types/base/entity.js'; export const exportJDLTransform = ({ destinationPath, jdlStorePath, throwOnMissingConfig = true, keepEntitiesConfig, + jdlDefinition, }: { destinationPath: string; jdlStorePath: string; throwOnMissingConfig?: boolean; keepEntitiesConfig?: boolean; + jdlDefinition: JDLApplicationConfig; }) => Duplex.from(async function* (files: AsyncGenerator) { const yoRcFilePath = join(destinationPath, '.yo-rc.json'); const entitiesMatcher = new Minimatch(`${destinationPath}/.jhipster/*.json`); const entitiesFiles: MemFsEditorFile[] = []; - const entitiesMap: Map = new Map(); + const entitiesMap = new Map(); let yoRcFileInMemory: MemFsEditorFile | undefined; let jdlStoreFileInMemory: MemFsEditorFile | undefined; @@ -52,6 +56,8 @@ export const exportJDLTransform = ({ const jdlObject = getJDLObjectFromSingleApplication( { ...contents, [GENERATOR_JHIPSTER]: { ...rest, incrementalChangelog } }, entitiesMap, + undefined, + createRuntime(jdlDefinition), ); const jdlContents = jdlObject.toString(); diff --git a/generators/bootstrap-application-base/support/import-jdl-transform.ts b/generators/bootstrap-application-base/support/import-jdl-transform.ts index 1a93b475934d..0aeb46ded5dc 100644 --- a/generators/bootstrap-application-base/support/import-jdl-transform.ts +++ b/generators/bootstrap-application-base/support/import-jdl-transform.ts @@ -5,15 +5,24 @@ import type { MemFsEditorFile } from 'mem-fs-editor'; import { Minimatch } from 'minimatch'; import { upperFirst } from 'lodash-es'; import { GENERATOR_JHIPSTER } from '../../generator-constants.js'; -import { createImporterFromContent } from '../../../jdl/jdl-importer.js'; -import { mergeYoRcContent } from '../../../jdl/index.js'; +import { createImporterFromContent } from '../../../lib/jdl/jdl-importer.js'; +import { mergeYoRcContent } from '../../../lib/utils/yo-rc.js'; +import type { JDLApplicationConfig } from '../../../lib/jdl/core/types/parsing.js'; -export const importJDLTransform = ({ destinationPath, jdlStorePath }: { destinationPath: string; jdlStorePath: string }) => +export const importJDLTransform = ({ + destinationPath, + jdlStorePath, + jdlDefinition, +}: { + destinationPath: string; + jdlStorePath: string; + jdlDefinition: JDLApplicationConfig; +}) => Duplex.from(async function* (files: AsyncGenerator) { const yoRcFilePath = join(destinationPath, '.yo-rc.json'); const entitiesFolder = join(destinationPath, '.jhipster'); const entitiesMatcher = new Minimatch(`${entitiesFolder}/*.json`); - const entityFields: Array = []; + const entityFields: MemFsEditorFile[] = []; let jdlStoreFileInMemory: MemFsEditorFile | undefined; let yoRcFileInMemory: MemFsEditorFile | undefined; @@ -44,7 +53,7 @@ export const importJDLTransform = ({ destinationPath, jdlStorePath }: { destinat if (entityFields.length > 0) { throw new Error('Entities configuration files are not supported by jdlStore'); } - const importer = createImporterFromContent(jdlStoreContents.toString()); + const importer = createImporterFromContent(jdlStoreContents.toString(), undefined, jdlDefinition); const importState = importer.import(); const applicationWithEntities = Object.values(importState.exportedApplicationsWithEntities); if (applicationWithEntities.length !== 1) { diff --git a/generators/bootstrap-application-base/utils.js b/generators/bootstrap-application-base/utils.ts similarity index 88% rename from generators/bootstrap-application-base/utils.js rename to generators/bootstrap-application-base/utils.ts index 51c0287b4a90..d51122ebace1 100644 --- a/generators/bootstrap-application-base/utils.js +++ b/generators/bootstrap-application-base/utils.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -17,11 +18,13 @@ * limitations under the License. */ import { defaults } from 'lodash-es'; -import { Validations, authenticationTypes, databaseTypes, fieldTypes } from '../../jdl/jhipster/index.js'; +import { Validations, authenticationTypes, databaseTypes, fieldTypes } from '../../lib/jhipster/index.js'; import { loadRequiredConfigIntoEntity } from '../base-application/support/index.js'; -import { PaginationTypes } from '../../jdl/jhipster/entity-options.js'; +import { PaginationTypes } from '../../lib/jhipster/entity-options.js'; import { LOGIN_REGEX, LOGIN_REGEX_JS } from '../generator-constants.js'; import { getDatabaseTypeData } from '../server/support/database.js'; +import type BaseApplicationGenerator from '../base-application/generator.js'; +import { formatDateForChangelog } from '../base/support/timestamp.js'; const { CASSANDRA } = databaseTypes; const { OAUTH2 } = authenticationTypes; @@ -70,24 +73,24 @@ export const auditableEntityFields = () => [ const authorityEntityName = 'Authority'; -// eslint-disable-next-line import/prefer-default-export -export function createUserEntity(customUserData = {}, application) { +export function createUserEntity(this: BaseApplicationGenerator, customUserData = {}, application) { const userEntityDefinition = this.getEntityConfig('User')?.getAll(); if (userEntityDefinition) { if (userEntityDefinition.relationships && userEntityDefinition.relationships.length > 0) { this.log.warn('Relationships on the User entity side will be disregarded'); } - if (userEntityDefinition.fields && userEntityDefinition.fields.some(field => field.fieldName !== 'id')) { + if (userEntityDefinition.fields?.some(field => field.fieldName !== 'id')) { this.log.warn('Fields on the User entity side (other than id) will be disregarded'); } } + const creationTimestamp = new Date(this.jhipsterConfig.creationTimestamp ?? Date.now()); const cassandraOrNoDatabase = application.databaseTypeNo || application.databaseTypeCassandra; // Create entity definition for built-in entity to make easier to deal with relationships. const user = { name: 'User', builtIn: true, - changelogDate: '00000000000100', + changelogDate: formatDateForChangelog(creationTimestamp), entityTableName: `${application.jhiTablePrefix}_user`, relationships: [], fields: userEntityDefinition ? userEntityDefinition.fields || [] : [], @@ -191,7 +194,7 @@ export function createUserEntity(customUserData = {}, application) { return user; } -export function createUserManagementEntity(customUserManagementData = {}, application) { +export function createUserManagementEntity(this: BaseApplicationGenerator, customUserManagementData = {}, application) { const user = createUserEntity.call(this, {}, application); for (const field of user.fields) { // Login is used as the id field in rest api. @@ -205,12 +208,14 @@ export function createUserManagementEntity(customUserManagementData = {}, applic } } + const creationTimestamp = new Date(this.jhipsterConfig.creationTimestamp ?? Date.now()); + creationTimestamp.setMinutes(creationTimestamp.getMinutes() + 1); const userManagement = { ...user, name: 'UserManagement', skipClient: true, skipServer: true, - changelogDate: '00000000000150', + changelogDate: formatDateForChangelog(creationTimestamp), clientRootFolder: 'admin', entityAngularName: 'UserManagement', entityApiUrl: 'admin/users', @@ -236,24 +241,26 @@ export function createUserManagementEntity(customUserManagementData = {}, applic return userManagement; } -export function createAuthorityEntity(customAuthorityData = {}, application) { +export function createAuthorityEntity(this: BaseApplicationGenerator, customAuthorityData = {}, application) { const entityDefinition = this.getEntityConfig(authorityEntityName)?.getAll(); if (entityDefinition) { if (entityDefinition.relationships && entityDefinition.relationships.length > 0) { this.log.warn(`Relationships on the ${authorityEntityName} entity side will be disregarded`); } - if (entityDefinition.fields && entityDefinition.fields.some(field => field.fieldName !== 'name')) { + if (entityDefinition.fields?.some(field => field.fieldName !== 'name')) { this.log.warn(`Fields on the ${authorityEntityName} entity side (other than name) will be disregarded`); } } + const creationTimestamp = new Date(this.jhipsterConfig.creationTimestamp ?? Date.now()); + creationTimestamp.setMinutes(creationTimestamp.getMinutes() + 2); // Create entity definition for built-in entity to make easier to deal with relationships. const authorityEntity = { name: authorityEntityName, entitySuffix: '', clientRootFolder: 'admin', builtIn: true, - changelogDate: '00000000000200', + changelogDate: formatDateForChangelog(creationTimestamp), adminEntity: true, entityTableName: `${application.jhiTablePrefix}_authority`, relationships: [], diff --git a/generators/bootstrap-application-client/generator.spec.ts b/generators/bootstrap-application-client/generator.spec.ts index 2e519225e9bc..76d04df070be 100644 --- a/generators/bootstrap-application-client/generator.spec.ts +++ b/generators/bootstrap-application-client/generator.spec.ts @@ -16,19 +16,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { defaultHelpers as helpers } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { shouldSupportFeatures } from '../../test/support/tests.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const generatorPath = join(__dirname, 'index.ts'); const generator = basename(__dirname); describe(`generator - ${generator}`, () => { @@ -42,9 +41,8 @@ describe(`generator - ${generator}`, () => { describe('with', () => { describe('default config', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath).withJHipsterConfig(); + await helpers.runJHipster(generator).withJHipsterConfig(); }); it('should succeed', () => { diff --git a/generators/bootstrap-application-client/generator.ts b/generators/bootstrap-application-client/generator.ts index 4f71d030177e..80d4fed32a1f 100644 --- a/generators/bootstrap-application-client/generator.ts +++ b/generators/bootstrap-application-client/generator.ts @@ -17,11 +17,11 @@ * limitations under the License. */ import { + filterEntitiesAndPropertiesForClient, + filterEntitiesForClient, loadClientConfig, loadDerivedClientConfig, preparePostEntityClientDerivedProperties, - filterEntitiesAndPropertiesForClient, - filterEntitiesForClient, } from '../client/support/index.js'; import BaseApplicationGenerator from '../base-application/index.js'; import { loadStoredAppOptions } from '../app/support/index.js'; diff --git a/generators/bootstrap-application-server/generator.spec.ts b/generators/bootstrap-application-server/generator.spec.ts index 2e519225e9bc..76d04df070be 100644 --- a/generators/bootstrap-application-server/generator.spec.ts +++ b/generators/bootstrap-application-server/generator.spec.ts @@ -16,19 +16,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { defaultHelpers as helpers } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { shouldSupportFeatures } from '../../test/support/tests.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const generatorPath = join(__dirname, 'index.ts'); const generator = basename(__dirname); describe(`generator - ${generator}`, () => { @@ -42,9 +41,8 @@ describe(`generator - ${generator}`, () => { describe('with', () => { describe('default config', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath).withJHipsterConfig(); + await helpers.runJHipster(generator).withJHipsterConfig(); }); it('should succeed', () => { diff --git a/generators/bootstrap-application-server/generator.ts b/generators/bootstrap-application-server/generator.ts index 1d525fbb5c24..a88983313060 100644 --- a/generators/bootstrap-application-server/generator.ts +++ b/generators/bootstrap-application-server/generator.ts @@ -30,12 +30,12 @@ import { } from '../generator-constants.js'; import { loadRequiredConfigIntoEntity, prepareEntityPrimaryKeyForTemplates } from '../base-application/support/index.js'; import { - loadRequiredConfigDerivedProperties, - prepareEntity as prepareEntityServerForTemplates, addEntitiesOtherRelationships, hibernateSnakeCase, - loadServerConfig, loadDerivedServerConfig, + loadRequiredConfigDerivedProperties, + loadServerConfig, + prepareEntity as prepareEntityServerForTemplates, prepareRelationship, } from '../server/support/index.js'; import { getGradleLibsVersionsProperties } from '../gradle/support/index.js'; @@ -214,7 +214,7 @@ export default class BoostrapApplicationServer extends BaseApplicationGenerator return; } // derivedPrimary uses '@MapsId', which requires for each relationship id field to have corresponding field in the model - const derivedFields = entity.primaryKey.derivedFields; + const derivedFields = primaryKey.derivedFields; entity.fields.unshift(...derivedFields); }, }); diff --git a/generators/bootstrap-application/generator.spec.ts b/generators/bootstrap-application/generator.spec.ts index 3b09bd3c66d0..2b941a85c630 100644 --- a/generators/bootstrap-application/generator.spec.ts +++ b/generators/bootstrap-application/generator.spec.ts @@ -16,13 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { defaultHelpers as helpers, result as runResult } from '../../testing/index.js'; -import { fieldTypes } from '../../jdl/jhipster/index.js'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; +import { fieldTypes } from '../../lib/jhipster/index.js'; import { shouldSupportFeatures } from '../../test/support/tests.js'; import Generator from './index.js'; @@ -33,7 +33,6 @@ const { const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const generatorPath = join(__dirname, 'index.ts'); const generator = basename(__dirname); const expectedField = () => ({ @@ -87,7 +86,7 @@ describe(`generator - ${generator}`, () => { describe('with', () => { describe('default config', () => { before(async () => { - await helpers.run(generatorPath).withJHipsterConfig({}, [ + await helpers.runJHipster(generator).withJHipsterConfig({}, [ { name: 'EntityA', changelogDate: '20220129025419', @@ -189,6 +188,7 @@ describe(`generator - ${generator}`, () => { "anyFieldIsUUID": true, "anyFieldIsZonedDateTime": false, "anyPropertyHasValidation": true, + "anyRelationshipIsRequired": false, "applicationType": "monolith", "auditableEntity": true, "authenticationType": "jwt", @@ -323,6 +323,7 @@ describe(`generator - ${generator}`, () => { "fieldValidationUnique": false, "fieldWithContentType": false, "generateFakeData": Any, + "generateFakeDataFromPattern": [Function], "id": true, "javaFieldType": "UUID", "javaValueGenerator": "UUID.randomUUID()", @@ -417,6 +418,7 @@ describe(`generator - ${generator}`, () => { "fieldValidationUnique": true, "fieldWithContentType": false, "generateFakeData": Any, + "generateFakeDataFromPattern": [Function], "javaFieldType": "String", "javaValueGenerator": "UUID.randomUUID().toString()", "javaValueSample1": ""login1"", @@ -503,6 +505,7 @@ describe(`generator - ${generator}`, () => { "fieldValidationUnique": false, "fieldWithContentType": false, "generateFakeData": Any, + "generateFakeDataFromPattern": [Function], "javaFieldType": "String", "javaValueGenerator": "UUID.randomUUID().toString()", "javaValueSample1": ""firstName1"", @@ -588,6 +591,7 @@ describe(`generator - ${generator}`, () => { "fieldValidationUnique": false, "fieldWithContentType": false, "generateFakeData": Any, + "generateFakeDataFromPattern": [Function], "javaFieldType": "String", "javaValueGenerator": "UUID.randomUUID().toString()", "javaValueSample1": ""lastName1"", @@ -677,6 +681,7 @@ describe(`generator - ${generator}`, () => { "fieldValidationUnique": true, "fieldWithContentType": false, "generateFakeData": Any, + "generateFakeDataFromPattern": [Function], "javaFieldType": "String", "javaValueGenerator": "UUID.randomUUID().toString()", "javaValueSample1": ""email1"", @@ -763,6 +768,7 @@ describe(`generator - ${generator}`, () => { "fieldValidationUnique": false, "fieldWithContentType": false, "generateFakeData": Any, + "generateFakeDataFromPattern": [Function], "javaFieldType": "String", "javaValueGenerator": "UUID.randomUUID().toString()", "javaValueSample1": ""imageUrl1"", @@ -845,6 +851,7 @@ describe(`generator - ${generator}`, () => { "fieldValidationUnique": false, "fieldWithContentType": false, "generateFakeData": Any, + "generateFakeDataFromPattern": [Function], "javaFieldType": "Boolean", "liquibaseDefaultValueAttributeName": undefined, "liquibaseDefaultValueAttributeValue": undefined, @@ -926,6 +933,7 @@ describe(`generator - ${generator}`, () => { "fieldValidationUnique": false, "fieldWithContentType": false, "generateFakeData": Any, + "generateFakeDataFromPattern": [Function], "javaFieldType": "String", "javaValueGenerator": "UUID.randomUUID().toString()", "javaValueSample1": ""langKey1"", @@ -1089,6 +1097,7 @@ describe(`generator - ${generator}`, () => { "anyFieldIsUUID": true, "anyFieldIsZonedDateTime": false, "anyPropertyHasValidation": false, + "anyRelationshipIsRequired": false, "applicationType": "monolith", "authenticationType": "jwt", "baseName": "jhipster", @@ -1212,6 +1221,7 @@ describe(`generator - ${generator}`, () => { "fieldValidationUnique": false, "fieldWithContentType": false, "generateFakeData": Any, + "generateFakeDataFromPattern": [Function], "id": true, "javaFieldType": "UUID", "javaValueGenerator": "UUID.randomUUID()", @@ -1355,9 +1365,8 @@ describe(`generator - ${generator}`, () => { }); describe('skipUserManagement', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath).withJHipsterConfig( + await helpers.runJHipster(generator).withJHipsterConfig( { skipUserManagement: true, }, @@ -1432,6 +1441,7 @@ describe(`generator - ${generator}`, () => { "anyFieldIsUUID": true, "anyFieldIsZonedDateTime": false, "anyPropertyHasValidation": false, + "anyRelationshipIsRequired": false, "applicationType": "monolith", "authenticationType": "jwt", "baseName": "jhipster", @@ -1555,6 +1565,7 @@ describe(`generator - ${generator}`, () => { "fieldValidationUnique": false, "fieldWithContentType": false, "generateFakeData": Any, + "generateFakeDataFromPattern": [Function], "id": true, "javaFieldType": "UUID", "javaValueGenerator": "UUID.randomUUID()", diff --git a/generators/bootstrap-application/generator.ts b/generators/bootstrap-application/generator.ts index a4d7be482dc4..b4b408170119 100644 --- a/generators/bootstrap-application/generator.ts +++ b/generators/bootstrap-application/generator.ts @@ -19,12 +19,12 @@ import assert from 'assert'; import BaseApplicationGenerator from '../base-application/index.js'; -import { validations } from '../../jdl/jhipster/index.js'; +import { validations } from '../../lib/jhipster/index.js'; import { - stringifyApplicationData, derivedPrimaryKeyProperties, preparePostEntitiesCommonDerivedProperties, preparePostEntityCommonDerivedProperties, + stringifyApplicationData, } from '../base-application/support/index.js'; import { preparePostEntityServerDerivedProperties } from '../server/support/index.js'; @@ -69,12 +69,6 @@ export default class BootstrapApplicationGenerator extends BaseApplicationGenera gatewayServicesApiAvailable: undefined, }); - applicationDefaults({ - useNpmWrapper: application => application.clientFrameworkAny && application.backendTypeJavaAny, - documentationArchiveUrl: ({ jhipsterVersion }) => - `${JHIPSTER_DOCUMENTATION_URL}${JHIPSTER_DOCUMENTATION_ARCHIVE_PATH}v${jhipsterVersion}`, - }); - let prettierExtensions = 'md,json,yml,html'; if (application.clientFrameworkAny) { prettierExtensions = `${prettierExtensions},cjs,mjs,js,ts,tsx,css,scss`; @@ -85,7 +79,14 @@ export default class BootstrapApplicationGenerator extends BaseApplicationGenera if (!application.skipServer) { prettierExtensions = `${prettierExtensions},java`; } - application.prettierExtensions = prettierExtensions; + + applicationDefaults({ + // TODO remove prettierExtensions, moved to prettier generator + prettierExtensions, + useNpmWrapper: application => application.clientFrameworkAny && application.backendTypeJavaAny, + documentationArchiveUrl: ({ jhipsterVersion }) => + `${JHIPSTER_DOCUMENTATION_URL}${JHIPSTER_DOCUMENTATION_ARCHIVE_PATH}v${jhipsterVersion}`, + }); }, }); } @@ -101,7 +102,7 @@ export default class BootstrapApplicationGenerator extends BaseApplicationGenera entityConfig.name = entityName; } - entityConfig.fields.forEach((field: any) => { + entityConfig.fields!.forEach((field: any) => { const { fieldName, fieldType, fieldValidateRules } = field; assert(fieldName, `fieldName is missing in .jhipster/${entityName}.json for field ${stringifyApplicationData(field)}`); diff --git a/generators/bootstrap-workspaces/command.ts b/generators/bootstrap-workspaces/command.ts index 6bd85df69142..71166bc5242b 100644 --- a/generators/bootstrap-workspaces/command.ts +++ b/generators/bootstrap-workspaces/command.ts @@ -1,14 +1,16 @@ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; -const command: JHipsterCommandDefinition = { - options: { +const command = { + configs: { customWorkspacesConfig: { - type: Boolean, + cli: { + type: Boolean, + hide: true, + }, description: 'Use custom configuration', scope: 'generator', - hide: true, }, }, -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/bootstrap-workspaces/generator.ts b/generators/bootstrap-workspaces/generator.ts index 6c0d5463d202..6b1a4cce47a6 100644 --- a/generators/bootstrap-workspaces/generator.ts +++ b/generators/bootstrap-workspaces/generator.ts @@ -18,8 +18,6 @@ */ import BaseWorkspacesGenerator from '../base-workspaces/index.js'; -import command from './command.js'; - export default class DockerComposeGenerator extends BaseWorkspacesGenerator { sharedWorkspaces!: any; customWorkspacesConfig?: boolean; @@ -27,7 +25,6 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { async beforeQueue() { this.sharedWorkspaces = this.getSharedApplication().sharedWorkspaces; this.sharedWorkspaces.existingWorkspaces = this.sharedWorkspaces.existingWorkspaces ?? Boolean(this.jhipsterConfig.appsFolders); - this.parseJHipsterOptions(command.options); if (!this.fromBlueprint) { await this.composeWithBlueprints(); diff --git a/generators/bootstrap-workspaces/index.ts b/generators/bootstrap-workspaces/index.ts index 58ac334eafae..2d8013d19f51 100644 --- a/generators/bootstrap-workspaces/index.ts +++ b/generators/bootstrap-workspaces/index.ts @@ -16,4 +16,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +export { default as command } from './command.js'; export { default } from './generator.js'; diff --git a/generators/bootstrap/command.ts b/generators/bootstrap/command.ts index 72aa8ad92b76..82da8abeafb0 100644 --- a/generators/bootstrap/command.ts +++ b/generators/bootstrap/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { options: { @@ -26,7 +26,13 @@ const command: JHipsterCommandDefinition = { scope: 'storage', }, skipPrettier: { - description: 'Skip prettier', + description: 'Skip prettier transformation', + type: Boolean, + hide: true, + scope: 'generator', + }, + skipEslint: { + description: 'Skip ESlint transformation', type: Boolean, hide: true, scope: 'generator', @@ -37,6 +43,12 @@ const command: JHipsterCommandDefinition = { hide: true, scope: 'generator', }, + skipForks: { + description: 'Dont use forks', + type: Boolean, + hide: true, + scope: 'generator', + }, }, }; diff --git a/generators/bootstrap/generator.spec.ts b/generators/bootstrap/generator.spec.ts index b25895cf89f4..d90bf385002d 100644 --- a/generators/bootstrap/generator.spec.ts +++ b/generators/bootstrap/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures } from '../../test/support/tests.js'; diff --git a/generators/bootstrap/generator.ts b/generators/bootstrap/generator.ts index 4e553da74d9a..d2f113f86130 100644 --- a/generators/bootstrap/generator.ts +++ b/generators/bootstrap/generator.ts @@ -17,28 +17,28 @@ * limitations under the License. */ import { Duplex } from 'stream'; -import { forceYoFiles, createConflicterTransform, createYoResolveTransform } from '@yeoman/conflicter'; +import { createConflicterTransform, createYoResolveTransform, forceYoFiles } from '@yeoman/conflicter'; import type { MemFsEditorFile } from 'mem-fs-editor'; -import { isFileStateModified, isFilePending } from 'mem-fs-editor/state'; +import { isFilePending, isFileStateModified } from 'mem-fs-editor/state'; import { createCommitTransform } from 'mem-fs-editor/transform'; -import prettier from 'prettier'; +import type { Options as PrettierOptions } from 'prettier'; import type { FileTransform, PipelineOptions } from 'mem-fs'; import BaseGenerator from '../base/index.js'; import { PRETTIER_EXTENSIONS } from '../generator-constants.js'; import { GENERATOR_UPGRADE } from '../generator-list.js'; import { PRIORITY_NAMES, QUEUES } from '../base-application/priorities.js'; -import type { BaseGeneratorDefinition, GenericTaskGroup } from '../base/tasks.js'; import { loadStoredAppOptions } from '../app/support/index.js'; +import type { GenericTaskGroup, TaskParamWithControl } from '../../lib/types/base/tasks.js'; import { - createMultiStepTransform, - createPrettierTransform, - createForceWriteConfigFilesTransform, autoCrlfTransform, - isPrettierConfigFilePath, - createSortConfigFilesTransform, createESLintTransform, + createForceWriteConfigFilesTransform, + createMultiStepTransform, + createPrettierTransform, createRemoveUnusedImportsTransform, + createSortConfigFilesTransform, + isPrettierConfigFilePath, } from './support/index.js'; const { MULTISTEP_TRANSFORM, PRE_CONFLICTS } = PRIORITY_NAMES; @@ -54,8 +54,10 @@ export default class BootstrapGenerator extends BaseGenerator { upgradeCommand?: boolean; skipPrettier?: boolean; + skipEslint?: boolean; + skipForks?: boolean; prettierExtensions: string[] = PRETTIER_EXTENSIONS.split(','); - prettierOptions: prettier.Options = { plugins: [] }; + prettierOptions: PrettierOptions = { plugins: [] }; refreshOnCommit = false; constructor(args: any, options: any, features: any) { @@ -107,7 +109,7 @@ export default class BootstrapGenerator extends BaseGenerator { return this.multistepTransform; } - get preConflicts(): GenericTaskGroup { + get preConflicts(): GenericTaskGroup { return { queueCommitPrettierConfig() { this.queueCommitPrettierConfig(); @@ -192,30 +194,35 @@ export default class BootstrapGenerator extends BaseGenerator { */ async commitSharedFs( { log, ...options }: PipelineOptions & { log?: string } = {}, - ...transforms: Array> + ...transforms: FileTransform[] ) { - const skipYoResolveTransforms: Array> = []; + const skipYoResolveTransforms: FileTransform[] = []; if (!this.options.skipYoResolve) { skipYoResolveTransforms.push(createYoResolveTransform()); } - const prettierTransforms: Array> = []; + const prettierTransforms: FileTransform[] = []; if (!this.skipPrettier) { const ignoreErrors = this.options.ignoreErrors || this.upgradeCommand; + if (!this.skipEslint) { + prettierTransforms.push( + createESLintTransform.call(this, { ignoreErrors }), + createRemoveUnusedImportsTransform.call(this, { ignoreErrors }), + ); + } prettierTransforms.push( - createESLintTransform.call(this, { ignoreErrors, extensions: 'ts,js,cjs,mjs' }), - createRemoveUnusedImportsTransform.call(this, { ignoreErrors }), await createPrettierTransform.call(this, { ignoreErrors, prettierPackageJson: true, prettierJava: !this.jhipsterConfig.skipServer, extensions: this.prettierExtensions.join(','), prettierOptions: this.prettierOptions, + skipForks: this.skipForks, }), ); } - const autoCrlfTransforms: Array> = []; + const autoCrlfTransforms: FileTransform[] = []; if (this.jhipsterConfig.autoCrlf) { autoCrlfTransforms.push(await autoCrlfTransform({ baseDir: this.destinationPath() })); } diff --git a/generators/bootstrap/support/auto-crlf-transform.spec.ts b/generators/bootstrap/support/auto-crlf-transform.spec.ts index 776cb4968133..da765171e6e8 100644 --- a/generators/bootstrap/support/auto-crlf-transform.spec.ts +++ b/generators/bootstrap/support/auto-crlf-transform.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe, expect } from 'esmocha'; -import { defaultHelpers as helpers } from '../../../testing/index.js'; +import { before, describe, expect, it } from 'esmocha'; +import { defaultHelpers as helpers } from '../../../lib/testing/index.js'; import { detectCrLf } from './auto-crlf-transform.js'; describe('generator - bootstrap - utils', () => { diff --git a/generators/bootstrap/support/eslint-transform.spec.ts b/generators/bootstrap/support/eslint-transform.spec.ts index 4f8b199bb6d5..a5b3131968ce 100644 --- a/generators/bootstrap/support/eslint-transform.spec.ts +++ b/generators/bootstrap/support/eslint-transform.spec.ts @@ -1,6 +1,6 @@ import { Readable } from 'stream'; import { pipeline } from 'stream/promises'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { transform } from 'p-transform'; import { setModifiedFileState } from 'mem-fs-editor/state'; @@ -13,6 +13,7 @@ describe('generator - bootstrap - eslint', () => { path: 'foo.ts', contents: Buffer.from(` import { Foo } from 'bar'; +// eslint-disable-next-line no-console export const foo = 'bar'; `), }; @@ -23,6 +24,7 @@ export const foo = 'bar'; transform(() => undefined), ); expect(file.contents.toString()).toBe(` +// eslint-disable-next-line no-console export const foo = 'bar'; `); }); diff --git a/generators/bootstrap/support/eslint-transform.ts b/generators/bootstrap/support/eslint-transform.ts index e785bbe30034..ed22891e1bb9 100644 --- a/generators/bootstrap/support/eslint-transform.ts +++ b/generators/bootstrap/support/eslint-transform.ts @@ -21,23 +21,34 @@ import { isFileStateModified } from 'mem-fs-editor/state'; import { Minimatch } from 'minimatch'; import { Piscina } from 'piscina'; -import BaseGenerator from '../../base-core/index.js'; -import { getPackageRoot } from '../../../lib/index.js'; -import { JS_PRETTIER_EXTENSIONS } from '../../generator-constants.js'; +import type BaseGenerator from '../../base-core/index.js'; import { addLineNumbers } from '../internal/transform-utils.js'; -// eslint-disable-next-line import/prefer-default-export +type PoolOptions = Exclude[0], undefined>; +type ESLintWorkerOptions = { cwd?: string; extensions: string; recreateEslint?: boolean }; + +export class ESLintPool extends Piscina { + constructor(options?: PoolOptions) { + super({ + maxThreads: 1, + filename: new URL('./eslint-worker.js', import.meta.url).href, + ...options, + }); + } + + apply(data: ESLintWorkerOptions & { filePath: string; fileContents: string }): Promise<{ result: string; error: string }> { + return this.run(data); + } +} + export const createESLintTransform = function ( this: BaseGenerator | void, - transformOptions: { ignoreErrors?: boolean; extensions?: string } = {}, + transformOptions: { ignoreErrors?: boolean; poolOptions?: PoolOptions } & Partial = {}, ) { - const { extensions = JS_PRETTIER_EXTENSIONS, ignoreErrors } = transformOptions; + const { extensions = 'js,cjs,mjs,ts,cts,mts,jsx,tsx', ignoreErrors, cwd, poolOptions, recreateEslint } = transformOptions; const minimatch = new Minimatch(`**/*.{${extensions}}`, { dot: true }); - const pool = new Piscina({ - maxThreads: 1, - filename: new URL('./eslint-worker.js', import.meta.url).href, - }); + const pool = new ESLintPool(poolOptions); return passthrough( async file => { @@ -45,10 +56,12 @@ export const createESLintTransform = function ( return; } const fileContents = file.contents.toString(); - const { result, error } = await pool.run({ - resolvePluginsRelativeTo: getPackageRoot(), + const { result, error } = await pool.apply({ + cwd, filePath: file.path, fileContents, + extensions, + recreateEslint, }); if (result) { file.contents = Buffer.from(result); @@ -62,8 +75,8 @@ export const createESLintTransform = function ( this?.log?.warn?.(errorMessage); } }, - () => { - pool.destroy(); + async () => { + await pool.destroy(); }, ); }; diff --git a/generators/bootstrap/support/eslint-worker.js b/generators/bootstrap/support/eslint-worker.js index 59107a7a7c65..06b86fc0ce80 100644 --- a/generators/bootstrap/support/eslint-worker.js +++ b/generators/bootstrap/support/eslint-worker.js @@ -1,32 +1,24 @@ import eslint from 'eslint'; +import ts from 'typescript-eslint'; -import { baseRules } from '../../../lib/eslint/base.js'; +import jhipster from '../../../lib/eslint/index.js'; let eslintInstance; -/* Flat config based eslint -Blocked by https://github.com/import-js/eslint-plugin-import/issues/2556 -import eslint from 'eslint/use-at-your-own-risk'; -const { languageOptions, plugins: tseslintPlugins } = tseslint.configs.base; -new eslint.FlatESLint({ fix: true, overrideConfigFile: true, cwd, plugins, baseConfig: { languageOptions, rules } }); -*/ - -export default async ({ resolvePluginsRelativeTo, filePath, fileContents }) => { - if (!eslintInstance) { +export default async ({ cwd, filePath, fileContents, extensions, config, additionalConfig = [], recreateEslint }) => { + if (recreateEslint || !eslintInstance) { eslintInstance = new eslint.ESLint({ fix: true, - // Disable destination configs. We should apply plugins and rules which jhipster depends on. - useEslintrc: false, - resolvePluginsRelativeTo, - overrideConfig: { - plugins: ['unused-imports', 'import'], - extends: ['plugin:@typescript-eslint/base'], - parserOptions: { - sourceType: 'module', - ecmaVersion: 'latest', - }, - rules: baseRules, - }, + overrideConfigFile: true, + allowInlineConfig: false, + cache: false, + cwd, + baseConfig: ts.config( + { files: [`**/*.{${extensions}}`] }, + ts.configs.base, + ...additionalConfig, + config ? JSON.parse(config) : jhipster.base, + ), }); } diff --git a/generators/bootstrap/support/force-write-config-files-transform.ts b/generators/bootstrap/support/force-write-config-files-transform.ts index e8623784878c..0bc5e28ccf1e 100644 --- a/generators/bootstrap/support/force-write-config-files-transform.ts +++ b/generators/bootstrap/support/force-write-config-files-transform.ts @@ -17,7 +17,7 @@ * limitations under the License. */ import { transformFileField } from '@yeoman/transform'; -import { ConflicterFile } from '@yeoman/conflicter'; +import type { ConflicterFile } from '@yeoman/conflicter'; const createForceWriteConfigFilesTransform = () => transformFileField<'conflicter', ConflicterFile>('conflicter', 'force', { pattern: '**/.jhipster/*.json' }); diff --git a/generators/bootstrap/support/java-unused-imports-transform.ts b/generators/bootstrap/support/java-unused-imports-transform.ts index 4a11750c2fa9..b7c1352e34cf 100644 --- a/generators/bootstrap/support/java-unused-imports-transform.ts +++ b/generators/bootstrap/support/java-unused-imports-transform.ts @@ -1,13 +1,12 @@ import { extname } from 'path'; import { passthrough } from 'p-transform'; import { isFileStateModified } from 'mem-fs-editor/state'; -import { VinylMemFsEditorFile } from 'mem-fs-editor'; +import type { VinylMemFsEditorFile } from 'mem-fs-editor'; import { Piscina } from 'piscina'; import type CoreGenerator from '../../base-core/index.js'; import { addLineNumbers } from '../internal/transform-utils.js'; -// eslint-disable-next-line import/prefer-default-export export const createRemoveUnusedImportsTransform = function ( this: CoreGenerator, options: { @@ -45,8 +44,8 @@ export const createRemoveUnusedImportsTransform = function ( } } }, - () => { - pool.destroy(); + async () => { + await pool.destroy(); }, ); }; diff --git a/generators/bootstrap/support/multi-step-transform/index.ts b/generators/bootstrap/support/multi-step-transform/index.ts index 49407e65b2bd..830d77710b0b 100644 --- a/generators/bootstrap/support/multi-step-transform/index.ts +++ b/generators/bootstrap/support/multi-step-transform/index.ts @@ -19,12 +19,11 @@ import { type DuplexWithDebug, transform } from 'p-transform'; import type { MemFsEditorFile } from 'mem-fs-editor'; import TemplateFileFs from './template-file-fs.js'; -import TemplateFile from './template-file.js'; +import type TemplateFile from './template-file.js'; -// eslint-disable-next-line import/prefer-default-export export const createMultiStepTransform = () => { const templateFileFs = new TemplateFileFs({}); - const templateFiles: Array = []; + const templateFiles: TemplateFile[] = []; const duplex: DuplexWithDebug & { templateFileFs: TemplateFileFs } = transform( (file: MemFsEditorFile) => { diff --git a/generators/bootstrap/support/multi-step-transform/template-data.js b/generators/bootstrap/support/multi-step-transform/template-data.ts similarity index 85% rename from generators/bootstrap/support/multi-step-transform/template-data.js rename to generators/bootstrap/support/multi-step-transform/template-data.ts index e5f995d03262..1d0cc78764d6 100644 --- a/generators/bootstrap/support/multi-step-transform/template-data.js +++ b/generators/bootstrap/support/multi-step-transform/template-data.ts @@ -1,4 +1,10 @@ export default class TemplateData { + private _templateFile: any; + private _defaultData: { fragment?: any; section?: string }; + private _sections: any; + private _defaultFragment: any; + private last: any; + constructor(templateFile, defaultData = {}) { this._templateFile = templateFile; this._defaultData = defaultData; @@ -31,7 +37,7 @@ export default class TemplateData { /** * Render fragments using default join and suffix. */ - render(fragmentData = {}, suffix = '\n') { + render(fragmentData: { join?: string; section?: string } = {}, suffix = '\n') { const { join = '\n' } = fragmentData; const renderedFragments = this.renderFragments(fragmentData).filter(fragment => fragment); const section = fragmentData.section || this._defaultData.section; @@ -49,7 +55,7 @@ export default class TemplateData { /** * Proxy to renderFragments for templates. */ - renderFragments(fragmentData = {}) { + renderFragments(fragmentData: { fragment?: any; section?: string } = {}) { const fragment = { ...this._defaultData.fragment, ...fragmentData.fragment }; if (this._defaultData.section && fragmentData.section) { // Disable section passed by the parent. diff --git a/generators/bootstrap/support/multi-step-transform/template-file-fs.ts b/generators/bootstrap/support/multi-step-transform/template-file-fs.ts index 39e9809dbade..fff7f22b5e17 100644 --- a/generators/bootstrap/support/multi-step-transform/template-file-fs.ts +++ b/generators/bootstrap/support/multi-step-transform/template-file-fs.ts @@ -25,7 +25,7 @@ import TemplateFile from './template-file.js'; export default class TemplateFileFs { fragmentFiles: Record; - rootFiles: Array = []; + rootFiles: MemFsEditorFile[] = []; extension: string; delimiter: string; @@ -55,7 +55,7 @@ export default class TemplateFileFs { if (templateFile.rootTemplate) { templateFile.file = file; } else { - this.get(templateFile.parentPath).addFragment(templateFile); + this.get(templateFile.parentPath!).addFragment(templateFile); } return templateFile; } diff --git a/generators/bootstrap/support/multi-step-transform/template-file.js b/generators/bootstrap/support/multi-step-transform/template-file.ts similarity index 81% rename from generators/bootstrap/support/multi-step-transform/template-file.js rename to generators/bootstrap/support/multi-step-transform/template-file.ts index d2272fb02ff6..d12964cf0c46 100644 --- a/generators/bootstrap/support/multi-step-transform/template-file.js +++ b/generators/bootstrap/support/multi-step-transform/template-file.ts @@ -7,6 +7,19 @@ import TemplateData from './template-data.js'; export default class TemplateFile { file; + rootTemplate: boolean; + basePath?: string; + parentPath?: string; + filePath?: string; + + private depth: number; + private _filename: any; + private _extension: any; + private _compiled: ejs.TemplateFunction; + // eslint-disable-next-line no-use-before-define + private _fragments: TemplateFile[]; + private _fragmentName: string; + private _debug: { enabled: boolean } & ((msg: string) => void); constructor(filename, extension) { this._filename = filename; @@ -43,7 +56,7 @@ export default class TemplateFile { } try { - this._compiled = ejs.compile(contents, options); + this._compiled = ejs.compile(contents, { ...options, async: false }) as unknown as ejs.TemplateFunction; } catch (error) { throw new Error(`Error compiling ${this._filename}, with contents:\n${contents}`, { cause: error }); } @@ -59,7 +72,7 @@ export default class TemplateFile { return this._fragments.map(templateFile => templateFile.render(data)); } - render(data = {}) { + render(data: any = {}) { const fragments = new TemplateData(this, data); try { const rendered = this._compiled({ diff --git a/generators/bootstrap/support/prettier-support.ts b/generators/bootstrap/support/prettier-support.ts index 98802d081550..3ff4947130bd 100644 --- a/generators/bootstrap/support/prettier-support.ts +++ b/generators/bootstrap/support/prettier-support.ts @@ -20,7 +20,7 @@ import { passthrough } from 'p-transform'; import { isFileStateModified } from 'mem-fs-editor/state'; import { Minimatch } from 'minimatch'; import { Piscina } from 'piscina'; -import type prettier from 'prettier'; +import type { Options as PrettierOptions } from 'prettier'; import type { MemFsEditorFile, VinylMemFsEditorFile } from 'mem-fs-editor'; import type CoreGenerator from '../../base-core/index.js'; @@ -28,26 +28,46 @@ const minimatch = new Minimatch('**/{.prettierrc**,.prettierignore}'); export const isPrettierConfigFilePath = (filePath: string) => minimatch.match(filePath); export const isPrettierConfigFile = (file: MemFsEditorFile) => isPrettierConfigFilePath(file.path); +type PrettierWorkerOptions = { + prettierPackageJson?: boolean; + prettierJava?: boolean; + prettierProperties?: boolean; + prettierOptions?: PrettierOptions; +}; + +export class PrettierPool extends Piscina { + constructor(options = {}) { + super({ + maxThreads: 1, + filename: new URL('./prettier-worker.js', import.meta.url).href, + ...options, + }); + } + + apply( + data: PrettierWorkerOptions & { relativeFilePath: string; filePath: string; fileContents: string }, + ): Promise<{ result?: string; errorMessage?: string }> { + return this.run(data); + } +} + export const createPrettierTransform = async function ( this: CoreGenerator, - options: { - ignoreErrors?: boolean; - extensions?: string; - prettierPackageJson?: boolean; - prettierJava?: boolean; - prettierProperties?: boolean; - prettierOptions?: prettier.Options; - } = {}, + options: PrettierWorkerOptions & { ignoreErrors?: boolean; extensions?: string; skipForks?: boolean } = {}, ) { - const pool = new Piscina({ - maxThreads: 1, - filename: new URL('./prettier-worker.js', import.meta.url).href, - }); - - const { ignoreErrors = false, extensions = '*', prettierPackageJson, prettierJava, prettierProperties, prettierOptions } = options; + const { ignoreErrors = false, extensions = '*', skipForks, ...workerOptions } = options; const globExpression = extensions.includes(',') ? `**/*.{${extensions}}` : `**/*.${extensions}`; const minimatch = new Minimatch(globExpression, { dot: true }); + let applyPrettier; + const pool = skipForks ? undefined : new PrettierPool(); + if (skipForks) { + const { default: applyPrettierWorker } = await import('./prettier-worker.js'); + applyPrettier = applyPrettierWorker; + } else { + applyPrettier = data => pool!.apply(data); + } + return passthrough( async (file: VinylMemFsEditorFile) => { if (!minimatch.match(file.path) || !isFileStateModified(file)) { @@ -56,15 +76,11 @@ export const createPrettierTransform = async function ( if (!file.contents) { throw new Error(`File content doesn't exist for ${file.relative}`); } - const { result, errorMessage } = await pool.run({ + const { result, errorMessage } = await applyPrettier({ relativeFilePath: file.relative, filePath: file.path, fileContents: file.contents.toString('utf8'), - prettierOptions, - prettierPackageJson, - prettierJava, - prettierProperties, - ignoreErrors, + ...workerOptions, }); if (result) { file.contents = Buffer.from(result); @@ -76,8 +92,8 @@ export const createPrettierTransform = async function ( this?.log?.warn?.(errorMessage); } }, - () => { - pool.destroy(); + async () => { + await pool?.destroy(); }, ); }; diff --git a/generators/bootstrap/support/prettier-worker.js b/generators/bootstrap/support/prettier-worker.js index f1f250dbfd86..4ddafb94a9a4 100644 --- a/generators/bootstrap/support/prettier-worker.js +++ b/generators/bootstrap/support/prettier-worker.js @@ -1,4 +1,4 @@ -import prettier from 'prettier'; +import { format, resolveConfig } from 'prettier'; import prettierPluginJava from 'prettier-plugin-java'; import prettierPluginProperties from 'prettier-plugin-properties'; import prettierPluginPackagejson from 'prettier-plugin-packagejson'; @@ -14,7 +14,7 @@ export default async ({ prettierProperties, }) => { try { - const resolvedDestinationFileOptions = await prettier.resolveConfig(relativeFilePath); + const resolvedDestinationFileOptions = await resolveConfig(relativeFilePath); const fileOptions = { // Config from disk ...resolvedDestinationFileOptions, @@ -32,7 +32,7 @@ export default async ({ if (prettierProperties) { fileOptions.plugins.push(prettierPluginProperties); } - return { result: await prettier.format(fileContents, fileOptions) }; + return { result: await format(fileContents, fileOptions) }; } catch (error) { let errorMessage; if (fileContents) { diff --git a/generators/bootstrap/support/sort-config-files-transform.ts b/generators/bootstrap/support/sort-config-files-transform.ts index a92774969eae..337c03e0e7f6 100644 --- a/generators/bootstrap/support/sort-config-files-transform.ts +++ b/generators/bootstrap/support/sort-config-files-transform.ts @@ -16,10 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import File from 'vinyl'; +import type File from 'vinyl'; import sortKeys from 'sort-keys'; import { transformContents } from '@yeoman/transform'; -import { MemFsEditorFile } from 'mem-fs-editor'; +import type { MemFsEditorFile } from 'mem-fs-editor'; const sortJsonFileContent = (contents: Exclude) => { return Buffer.from(`${JSON.stringify(sortKeys(JSON.parse(contents.toString('utf8')), { deep: true }), null, 2)}\n`); diff --git a/generators/ci-cd/__snapshots__/ci-cd.spec.ts.snap b/generators/ci-cd/__snapshots__/ci-cd.spec.ts.snap index 87569b094a33..5ab973ad0a7d 100644 --- a/generators/ci-cd/__snapshots__/ci-cd.spec.ts.snap +++ b/generators/ci-cd/__snapshots__/ci-cd.spec.ts.snap @@ -9,7 +9,9 @@ exports[`generator - CI-CD Azure Pipelines tests Azure Pipelines: Gradle Angular "buildTool": "gradle", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -17,98 +19,98 @@ exports[`generator - CI-CD Azure Pipelines tests Azure Pipelines: Gradle Angular }, "azure-pipelines.yml": { "contents": "jobs: - - job: Test - pool: - vmImage: "ubuntu-20.04" - variables: - NODE_VERSION: NODE_VERSION - SPRING_OUTPUT_ANSI_ENABLED: NEVER - SPRING_JPA_SHOW_SQL: false - JHI_DISABLE_WEBPACK_LOGS: true - NG_CLI_ANALYTICS: "false" - JHI_E2E_HEADLESS: true - - steps: - #---------------------------------------------------------------------- - # Install all tools and check configuration - #---------------------------------------------------------------------- - - task: NodeTool@0 - inputs: - versionSpec: $(NODE_VERSION) - displayName: "TOOLS: install Node.js" - - task: Bash@3 - inputs: - targetType: "inline" - script: | - wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - sudo apt install ./google-chrome-stable_current_amd64.deb - displayName: "TOOLS: install Chrome" - #---------------------------------------------------------------------- - # Tests - #---------------------------------------------------------------------- - - task: Npm@1 - inputs: - command: "install" - displayName: "INSTALL: launch npm install" - - script: chmod +x gradlew - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:backend:test" - displayName: "TESTS: backend" - - task: PublishTestResults@2 - inputs: - testResultsFormat: "JUnit" - testResultsFiles: "**/TEST-*.xml" - searchFolder: "$(Build.SourcesDirectory)/build/test-results" - condition: succeededOrFailed() - displayName: "TESTS: publish test results" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:frontend:test" - displayName: "TESTS: frontend" - - task: PublishTestResults@2 - inputs: - testResultsFormat: "JUnit" - testResultsFiles: "$(Build.SourcesDirectory)/build/test-results/TESTS-results-jest.xml" - condition: succeededOrFailed() - displayName: "TESTS: publish test results" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run java:jar:prod" - displayName: "TESTS: packaging" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:package" - displayName: "E2E: Package" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:prepare" - displayName: "E2E: Prepare" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:run" - displayName: "E2E: Run" - env: - CYPRESS_ENABLE_RECORD: false - CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID) - CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) - - task: PublishPipelineArtifact@1 - inputs: - artifactName: "cypress-screenshots" - targetPath: "$(Build.SourcesDirectory)/build/cypress/screenshots" - condition: failed() - displayName: "E2E: Publish Cypress Screenshots" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:teardown" - displayName: "E2E: Teardown" +- job: Test + pool: + vmImage: 'ubuntu-20.04' + variables: + NODE_VERSION: NODE_VERSION + SPRING_OUTPUT_ANSI_ENABLED: NEVER + SPRING_JPA_SHOW_SQL: false + JHI_DISABLE_WEBPACK_LOGS: true + NG_CLI_ANALYTICS: "false" + JHI_E2E_HEADLESS: true + + steps: + #---------------------------------------------------------------------- + # Install all tools and check configuration + #---------------------------------------------------------------------- + - task: NodeTool@0 + inputs: + versionSpec: $(NODE_VERSION) + displayName: 'TOOLS: install Node.js' + - task: Bash@3 + inputs: + targetType: 'inline' + script: | + wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb + sudo apt install ./google-chrome-stable_current_amd64.deb + displayName: 'TOOLS: install Chrome' + #---------------------------------------------------------------------- + # Tests + #---------------------------------------------------------------------- + - task: Npm@1 + inputs: + command: 'install' + displayName: 'INSTALL: launch npm install' + - script: chmod +x gradlew + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:backend:test' + displayName: 'TESTS: backend' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TEST-*.xml' + searchFolder: '$(Build.SourcesDirectory)/build/test-results' + condition: succeededOrFailed() + displayName: 'TESTS: publish test results' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:frontend:test' + displayName: 'TESTS: frontend' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '$(Build.SourcesDirectory)/build/test-results/TESTS-results-jest.xml' + condition: succeededOrFailed() + displayName: 'TESTS: publish test results' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run java:jar:prod' + displayName: 'TESTS: packaging' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:package' + displayName: 'E2E: Package' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:prepare' + displayName: 'E2E: Prepare' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:run' + displayName: 'E2E: Run' + env: + CYPRESS_ENABLE_RECORD: false + CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID) + CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) + - task: PublishPipelineArtifact@1 + inputs: + artifactName: 'cypress-screenshots' + targetPath: '$(Build.SourcesDirectory)/build/cypress/screenshots' + condition: failed() + displayName: 'E2E: Publish Cypress Screenshots' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:teardown' + displayName: 'E2E: Teardown' ", "stateCleared": "modified", }, @@ -124,7 +126,9 @@ exports[`generator - CI-CD Azure Pipelines tests Azure Pipelines: Gradle Angular "buildTool": "gradle", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -132,110 +136,110 @@ exports[`generator - CI-CD Azure Pipelines tests Azure Pipelines: Gradle Angular }, "azure-pipelines.yml": { "contents": "jobs: - - job: Test - pool: - vmImage: "ubuntu-20.04" - variables: - NODE_VERSION: NODE_VERSION - SPRING_OUTPUT_ANSI_ENABLED: NEVER - SPRING_JPA_SHOW_SQL: false - JHI_DISABLE_WEBPACK_LOGS: true - NG_CLI_ANALYTICS: "false" - JHI_E2E_HEADLESS: true - - steps: - #---------------------------------------------------------------------- - # Install all tools and check configuration - #---------------------------------------------------------------------- - - task: NodeTool@0 - inputs: - versionSpec: $(NODE_VERSION) - displayName: "TOOLS: install Node.js" - - task: Bash@3 - inputs: - targetType: "inline" - script: | - wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - sudo apt install ./google-chrome-stable_current_amd64.deb - displayName: "TOOLS: install Chrome" - #---------------------------------------------------------------------- - # Tests - #---------------------------------------------------------------------- - - task: Npm@1 - inputs: - command: "install" - displayName: "INSTALL: launch npm install" - - script: | - curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') - chmod +x snyk - displayName: "INSTALL: Snyk CLI" - - script: ./snyk test --all-projects || true - displayName: "CHECK: Snyk test" - env: - SNYK_TOKEN: $(SNYK_TOKEN) - - script: ./snyk monitor --all-projects - displayName: "CHECK: Snyk monitor" - env: - SNYK_TOKEN: $(SNYK_TOKEN) - - script: chmod +x gradlew - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:backend:test" - displayName: "TESTS: backend" - - task: PublishTestResults@2 - inputs: - testResultsFormat: "JUnit" - testResultsFiles: "**/TEST-*.xml" - searchFolder: "$(Build.SourcesDirectory)/build/test-results" - condition: succeededOrFailed() - displayName: "TESTS: publish test results" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:frontend:test" - displayName: "TESTS: frontend" - - task: PublishTestResults@2 - inputs: - testResultsFormat: "JUnit" - testResultsFiles: "$(Build.SourcesDirectory)/build/test-results/TESTS-results-jest.xml" - condition: succeededOrFailed() - displayName: "TESTS: publish test results" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run java:jar:prod" - displayName: "TESTS: packaging" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:package" - displayName: "E2E: Package" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:prepare" - displayName: "E2E: Prepare" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:run" - displayName: "E2E: Run" - env: - CYPRESS_ENABLE_RECORD: false - CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID) - CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) - - task: PublishPipelineArtifact@1 - inputs: - artifactName: "cypress-screenshots" - targetPath: "$(Build.SourcesDirectory)/build/cypress/screenshots" - condition: failed() - displayName: "E2E: Publish Cypress Screenshots" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:teardown" - displayName: "E2E: Teardown" +- job: Test + pool: + vmImage: 'ubuntu-20.04' + variables: + NODE_VERSION: NODE_VERSION + SPRING_OUTPUT_ANSI_ENABLED: NEVER + SPRING_JPA_SHOW_SQL: false + JHI_DISABLE_WEBPACK_LOGS: true + NG_CLI_ANALYTICS: "false" + JHI_E2E_HEADLESS: true + + steps: + #---------------------------------------------------------------------- + # Install all tools and check configuration + #---------------------------------------------------------------------- + - task: NodeTool@0 + inputs: + versionSpec: $(NODE_VERSION) + displayName: 'TOOLS: install Node.js' + - task: Bash@3 + inputs: + targetType: 'inline' + script: | + wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb + sudo apt install ./google-chrome-stable_current_amd64.deb + displayName: 'TOOLS: install Chrome' + #---------------------------------------------------------------------- + # Tests + #---------------------------------------------------------------------- + - task: Npm@1 + inputs: + command: 'install' + displayName: 'INSTALL: launch npm install' + - script: | + curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') + chmod +x snyk + displayName: 'INSTALL: Snyk CLI' + - script: ./snyk test --all-projects || true + displayName: 'CHECK: Snyk test' + env: + SNYK_TOKEN: $(SNYK_TOKEN) + - script: ./snyk monitor --all-projects + displayName: 'CHECK: Snyk monitor' + env: + SNYK_TOKEN: $(SNYK_TOKEN) + - script: chmod +x gradlew + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:backend:test' + displayName: 'TESTS: backend' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TEST-*.xml' + searchFolder: '$(Build.SourcesDirectory)/build/test-results' + condition: succeededOrFailed() + displayName: 'TESTS: publish test results' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:frontend:test' + displayName: 'TESTS: frontend' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '$(Build.SourcesDirectory)/build/test-results/TESTS-results-jest.xml' + condition: succeededOrFailed() + displayName: 'TESTS: publish test results' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run java:jar:prod' + displayName: 'TESTS: packaging' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:package' + displayName: 'E2E: Package' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:prepare' + displayName: 'E2E: Prepare' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:run' + displayName: 'E2E: Run' + env: + CYPRESS_ENABLE_RECORD: false + CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID) + CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) + - task: PublishPipelineArtifact@1 + inputs: + artifactName: 'cypress-screenshots' + targetPath: '$(Build.SourcesDirectory)/build/cypress/screenshots' + condition: failed() + displayName: 'E2E: Publish Cypress Screenshots' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:teardown' + displayName: 'E2E: Teardown' ", "stateCleared": "modified", }, @@ -251,7 +255,9 @@ exports[`generator - CI-CD Azure Pipelines tests Azure Pipelines: Maven Angular "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -259,98 +265,98 @@ exports[`generator - CI-CD Azure Pipelines tests Azure Pipelines: Maven Angular }, "azure-pipelines.yml": { "contents": "jobs: - - job: Test - pool: - vmImage: "ubuntu-20.04" - variables: - NODE_VERSION: NODE_VERSION - SPRING_OUTPUT_ANSI_ENABLED: NEVER - SPRING_JPA_SHOW_SQL: false - JHI_DISABLE_WEBPACK_LOGS: true - NG_CLI_ANALYTICS: "false" - JHI_E2E_HEADLESS: true - - steps: - #---------------------------------------------------------------------- - # Install all tools and check configuration - #---------------------------------------------------------------------- - - task: NodeTool@0 - inputs: - versionSpec: $(NODE_VERSION) - displayName: "TOOLS: install Node.js" - - task: Bash@3 - inputs: - targetType: "inline" - script: | - wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - sudo apt install ./google-chrome-stable_current_amd64.deb - displayName: "TOOLS: install Chrome" - #---------------------------------------------------------------------- - # Tests - #---------------------------------------------------------------------- - - task: Npm@1 - inputs: - command: "install" - displayName: "INSTALL: launch npm install" - - script: chmod +x mvnw - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:backend:test" - displayName: "TESTS: backend" - - task: PublishTestResults@2 - inputs: - testResultsFormat: "JUnit" - testResultsFiles: "**/TEST-*.xml" - searchFolder: "$(Build.SourcesDirectory)/target/test-results" - condition: succeededOrFailed() - displayName: "TESTS: publish test results" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:frontend:test" - displayName: "TESTS: frontend" - - task: PublishTestResults@2 - inputs: - testResultsFormat: "JUnit" - testResultsFiles: "$(Build.SourcesDirectory)/target/test-results/TESTS-results-jest.xml" - condition: succeededOrFailed() - displayName: "TESTS: publish test results" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run java:jar:prod" - displayName: "TESTS: packaging" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:package" - displayName: "E2E: Package" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:prepare" - displayName: "E2E: Prepare" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:run" - displayName: "E2E: Run" - env: - CYPRESS_ENABLE_RECORD: true - CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID) - CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) - - task: PublishPipelineArtifact@1 - inputs: - artifactName: "cypress-screenshots" - targetPath: "$(Build.SourcesDirectory)/target/cypress/screenshots" - condition: failed() - displayName: "E2E: Publish Cypress Screenshots" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:teardown" - displayName: "E2E: Teardown" +- job: Test + pool: + vmImage: 'ubuntu-20.04' + variables: + NODE_VERSION: NODE_VERSION + SPRING_OUTPUT_ANSI_ENABLED: NEVER + SPRING_JPA_SHOW_SQL: false + JHI_DISABLE_WEBPACK_LOGS: true + NG_CLI_ANALYTICS: "false" + JHI_E2E_HEADLESS: true + + steps: + #---------------------------------------------------------------------- + # Install all tools and check configuration + #---------------------------------------------------------------------- + - task: NodeTool@0 + inputs: + versionSpec: $(NODE_VERSION) + displayName: 'TOOLS: install Node.js' + - task: Bash@3 + inputs: + targetType: 'inline' + script: | + wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb + sudo apt install ./google-chrome-stable_current_amd64.deb + displayName: 'TOOLS: install Chrome' + #---------------------------------------------------------------------- + # Tests + #---------------------------------------------------------------------- + - task: Npm@1 + inputs: + command: 'install' + displayName: 'INSTALL: launch npm install' + - script: chmod +x mvnw + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:backend:test' + displayName: 'TESTS: backend' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TEST-*.xml' + searchFolder: '$(Build.SourcesDirectory)/target/test-results' + condition: succeededOrFailed() + displayName: 'TESTS: publish test results' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:frontend:test' + displayName: 'TESTS: frontend' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '$(Build.SourcesDirectory)/target/test-results/TESTS-results-jest.xml' + condition: succeededOrFailed() + displayName: 'TESTS: publish test results' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run java:jar:prod' + displayName: 'TESTS: packaging' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:package' + displayName: 'E2E: Package' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:prepare' + displayName: 'E2E: Prepare' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:run' + displayName: 'E2E: Run' + env: + CYPRESS_ENABLE_RECORD: true + CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID) + CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) + - task: PublishPipelineArtifact@1 + inputs: + artifactName: 'cypress-screenshots' + targetPath: '$(Build.SourcesDirectory)/target/cypress/screenshots' + condition: failed() + displayName: 'E2E: Publish Cypress Screenshots' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:teardown' + displayName: 'E2E: Teardown' ", "stateCleared": "modified", }, @@ -366,7 +372,9 @@ exports[`generator - CI-CD Azure Pipelines tests Azure Pipelines: Maven Angular "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -374,110 +382,110 @@ exports[`generator - CI-CD Azure Pipelines tests Azure Pipelines: Maven Angular }, "azure-pipelines.yml": { "contents": "jobs: - - job: Test - pool: - vmImage: "ubuntu-20.04" - variables: - NODE_VERSION: NODE_VERSION - SPRING_OUTPUT_ANSI_ENABLED: NEVER - SPRING_JPA_SHOW_SQL: false - JHI_DISABLE_WEBPACK_LOGS: true - NG_CLI_ANALYTICS: "false" - JHI_E2E_HEADLESS: true - - steps: - #---------------------------------------------------------------------- - # Install all tools and check configuration - #---------------------------------------------------------------------- - - task: NodeTool@0 - inputs: - versionSpec: $(NODE_VERSION) - displayName: "TOOLS: install Node.js" - - task: Bash@3 - inputs: - targetType: "inline" - script: | - wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - sudo apt install ./google-chrome-stable_current_amd64.deb - displayName: "TOOLS: install Chrome" - #---------------------------------------------------------------------- - # Tests - #---------------------------------------------------------------------- - - task: Npm@1 - inputs: - command: "install" - displayName: "INSTALL: launch npm install" - - script: | - curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') - chmod +x snyk - displayName: "INSTALL: Snyk CLI" - - script: ./snyk test --all-projects || true - displayName: "CHECK: Snyk test" - env: - SNYK_TOKEN: $(SNYK_TOKEN) - - script: ./snyk monitor --all-projects - displayName: "CHECK: Snyk monitor" - env: - SNYK_TOKEN: $(SNYK_TOKEN) - - script: chmod +x mvnw - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:backend:test" - displayName: "TESTS: backend" - - task: PublishTestResults@2 - inputs: - testResultsFormat: "JUnit" - testResultsFiles: "**/TEST-*.xml" - searchFolder: "$(Build.SourcesDirectory)/target/test-results" - condition: succeededOrFailed() - displayName: "TESTS: publish test results" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:frontend:test" - displayName: "TESTS: frontend" - - task: PublishTestResults@2 - inputs: - testResultsFormat: "JUnit" - testResultsFiles: "$(Build.SourcesDirectory)/target/test-results/TESTS-results-jest.xml" - condition: succeededOrFailed() - displayName: "TESTS: publish test results" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run java:jar:prod" - displayName: "TESTS: packaging" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:package" - displayName: "E2E: Package" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:prepare" - displayName: "E2E: Prepare" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:run" - displayName: "E2E: Run" - env: - CYPRESS_ENABLE_RECORD: false - CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID) - CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) - - task: PublishPipelineArtifact@1 - inputs: - artifactName: "cypress-screenshots" - targetPath: "$(Build.SourcesDirectory)/target/cypress/screenshots" - condition: failed() - displayName: "E2E: Publish Cypress Screenshots" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:teardown" - displayName: "E2E: Teardown" +- job: Test + pool: + vmImage: 'ubuntu-20.04' + variables: + NODE_VERSION: NODE_VERSION + SPRING_OUTPUT_ANSI_ENABLED: NEVER + SPRING_JPA_SHOW_SQL: false + JHI_DISABLE_WEBPACK_LOGS: true + NG_CLI_ANALYTICS: "false" + JHI_E2E_HEADLESS: true + + steps: + #---------------------------------------------------------------------- + # Install all tools and check configuration + #---------------------------------------------------------------------- + - task: NodeTool@0 + inputs: + versionSpec: $(NODE_VERSION) + displayName: 'TOOLS: install Node.js' + - task: Bash@3 + inputs: + targetType: 'inline' + script: | + wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb + sudo apt install ./google-chrome-stable_current_amd64.deb + displayName: 'TOOLS: install Chrome' + #---------------------------------------------------------------------- + # Tests + #---------------------------------------------------------------------- + - task: Npm@1 + inputs: + command: 'install' + displayName: 'INSTALL: launch npm install' + - script: | + curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') + chmod +x snyk + displayName: 'INSTALL: Snyk CLI' + - script: ./snyk test --all-projects || true + displayName: 'CHECK: Snyk test' + env: + SNYK_TOKEN: $(SNYK_TOKEN) + - script: ./snyk monitor --all-projects + displayName: 'CHECK: Snyk monitor' + env: + SNYK_TOKEN: $(SNYK_TOKEN) + - script: chmod +x mvnw + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:backend:test' + displayName: 'TESTS: backend' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TEST-*.xml' + searchFolder: '$(Build.SourcesDirectory)/target/test-results' + condition: succeededOrFailed() + displayName: 'TESTS: publish test results' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:frontend:test' + displayName: 'TESTS: frontend' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '$(Build.SourcesDirectory)/target/test-results/TESTS-results-jest.xml' + condition: succeededOrFailed() + displayName: 'TESTS: publish test results' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run java:jar:prod' + displayName: 'TESTS: packaging' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:package' + displayName: 'E2E: Package' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:prepare' + displayName: 'E2E: Prepare' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:run' + displayName: 'E2E: Run' + env: + CYPRESS_ENABLE_RECORD: false + CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID) + CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) + - task: PublishPipelineArtifact@1 + inputs: + artifactName: 'cypress-screenshots' + targetPath: '$(Build.SourcesDirectory)/target/cypress/screenshots' + condition: failed() + displayName: 'E2E: Publish Cypress Screenshots' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:teardown' + displayName: 'E2E: Teardown' ", "stateCleared": "modified", }, @@ -493,7 +501,9 @@ exports[`generator - CI-CD Azure Pipelines tests Azure Pipelines: autoconfigure "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -501,98 +511,98 @@ exports[`generator - CI-CD Azure Pipelines tests Azure Pipelines: autoconfigure }, "azure-pipelines.yml": { "contents": "jobs: - - job: Test - pool: - vmImage: "ubuntu-20.04" - variables: - NODE_VERSION: NODE_VERSION - SPRING_OUTPUT_ANSI_ENABLED: NEVER - SPRING_JPA_SHOW_SQL: false - JHI_DISABLE_WEBPACK_LOGS: true - NG_CLI_ANALYTICS: "false" - JHI_E2E_HEADLESS: true - - steps: - #---------------------------------------------------------------------- - # Install all tools and check configuration - #---------------------------------------------------------------------- - - task: NodeTool@0 - inputs: - versionSpec: $(NODE_VERSION) - displayName: "TOOLS: install Node.js" - - task: Bash@3 - inputs: - targetType: "inline" - script: | - wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - sudo apt install ./google-chrome-stable_current_amd64.deb - displayName: "TOOLS: install Chrome" - #---------------------------------------------------------------------- - # Tests - #---------------------------------------------------------------------- - - task: Npm@1 - inputs: - command: "install" - displayName: "INSTALL: launch npm install" - - script: chmod +x mvnw - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:backend:test" - displayName: "TESTS: backend" - - task: PublishTestResults@2 - inputs: - testResultsFormat: "JUnit" - testResultsFiles: "**/TEST-*.xml" - searchFolder: "$(Build.SourcesDirectory)/target/test-results" - condition: succeededOrFailed() - displayName: "TESTS: publish test results" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:frontend:test" - displayName: "TESTS: frontend" - - task: PublishTestResults@2 - inputs: - testResultsFormat: "JUnit" - testResultsFiles: "$(Build.SourcesDirectory)/target/test-results/TESTS-results-jest.xml" - condition: succeededOrFailed() - displayName: "TESTS: publish test results" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run java:jar:prod" - displayName: "TESTS: packaging" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:package" - displayName: "E2E: Package" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:prepare" - displayName: "E2E: Prepare" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:run" - displayName: "E2E: Run" - env: - CYPRESS_ENABLE_RECORD: false - CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID) - CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) - - task: PublishPipelineArtifact@1 - inputs: - artifactName: "cypress-screenshots" - targetPath: "$(Build.SourcesDirectory)/target/cypress/screenshots" - condition: failed() - displayName: "E2E: Publish Cypress Screenshots" - - task: Npm@1 - inputs: - command: "custom" - customCommand: " run ci:e2e:teardown" - displayName: "E2E: Teardown" +- job: Test + pool: + vmImage: 'ubuntu-20.04' + variables: + NODE_VERSION: NODE_VERSION + SPRING_OUTPUT_ANSI_ENABLED: NEVER + SPRING_JPA_SHOW_SQL: false + JHI_DISABLE_WEBPACK_LOGS: true + NG_CLI_ANALYTICS: "false" + JHI_E2E_HEADLESS: true + + steps: + #---------------------------------------------------------------------- + # Install all tools and check configuration + #---------------------------------------------------------------------- + - task: NodeTool@0 + inputs: + versionSpec: $(NODE_VERSION) + displayName: 'TOOLS: install Node.js' + - task: Bash@3 + inputs: + targetType: 'inline' + script: | + wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb + sudo apt install ./google-chrome-stable_current_amd64.deb + displayName: 'TOOLS: install Chrome' + #---------------------------------------------------------------------- + # Tests + #---------------------------------------------------------------------- + - task: Npm@1 + inputs: + command: 'install' + displayName: 'INSTALL: launch npm install' + - script: chmod +x mvnw + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:backend:test' + displayName: 'TESTS: backend' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TEST-*.xml' + searchFolder: '$(Build.SourcesDirectory)/target/test-results' + condition: succeededOrFailed() + displayName: 'TESTS: publish test results' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:frontend:test' + displayName: 'TESTS: frontend' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '$(Build.SourcesDirectory)/target/test-results/TESTS-results-jest.xml' + condition: succeededOrFailed() + displayName: 'TESTS: publish test results' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run java:jar:prod' + displayName: 'TESTS: packaging' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:package' + displayName: 'E2E: Package' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:prepare' + displayName: 'E2E: Prepare' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:run' + displayName: 'E2E: Run' + env: + CYPRESS_ENABLE_RECORD: false + CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID) + CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) + - task: PublishPipelineArtifact@1 + inputs: + artifactName: 'cypress-screenshots' + targetPath: '$(Build.SourcesDirectory)/target/cypress/screenshots' + condition: failed() + displayName: 'E2E: Publish Cypress Screenshots' + - task: Npm@1 + inputs: + command: 'custom' + customCommand: ' run ci:e2e:teardown' + displayName: 'E2E: Teardown' ", "stateCleared": "modified", }, @@ -604,60 +614,60 @@ exports[`generator - CI-CD Circle CI test Circle CI: Gradle Angular NPM should m ".circleci/config.yml": { "contents": "version: 2.1 jobs: - build: - machine: - image: ubuntu-2004:current - resource_class: large - steps: - - checkout - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "build.gradle" }}-{{ checksum "package-lock.json" }} - # Perform a Partial Cache Restore (https://circleci.com/docs/2.0/caching/#restoring-cache) - - v1-dependencies- - - run: - name: Print Java Version - command: "java -version" - - run: - name: Print Node Version - command: "node -v" - - run: - name: Print NPM Version - command: "npm -v" - - run: - name: Install Node Modules - command: "npm install" - - save_cache: - paths: - - node - - node_modules - - ~/.gradle - key: v1-dependencies-{{ checksum "build.gradle" }}-{{ checksum "package-lock.json" }} - - - run: - name: Give Executable Power - command: "chmod +x gradlew" - - run: - name: Backend tests - command: npm run ci:backend:test - - run: - name: Run Front End Tests - command: npm run ci:frontend:test - # - run: - # name: 'E2E: Package' - # command: npm run ci:e2e:package - # - run: - # name: 'E2E: Prepare' - # command: npm run ci:e2e:prepare - # - run: - # name: 'E2E: Run' - # command: npm run ci:e2e:run - # environment: - # CYPRESS_ENABLE_RECORD: false - # - run: - # name: 'E2E: Teardown' - # command: npm run ci:e2e:teardown + build: + machine: + image: ubuntu-2004:current + resource_class: large + steps: + - checkout + # Download and cache dependencies + - restore_cache: + keys: + - v1-dependencies-{{ checksum "build.gradle" }}-{{ checksum "package-lock.json" }} + # Perform a Partial Cache Restore (https://circleci.com/docs/2.0/caching/#restoring-cache) + - v1-dependencies- + - run: + name: Print Java Version + command: 'java -version' + - run: + name: Print Node Version + command: 'node -v' + - run: + name: Print NPM Version + command: 'npm -v' + - run: + name: Install Node Modules + command: 'npm install' + - save_cache: + paths: + - node + - node_modules + - ~/.gradle + key: v1-dependencies-{{ checksum "build.gradle" }}-{{ checksum "package-lock.json" }} + + - run: + name: Give Executable Power + command: 'chmod +x gradlew' + - run: + name: Backend tests + command: npm run ci:backend:test + - run: + name: Run Front End Tests + command: npm run ci:frontend:test + # - run: + # name: 'E2E: Package' + # command: npm run ci:e2e:package + # - run: + # name: 'E2E: Prepare' + # command: npm run ci:e2e:prepare + # - run: + # name: 'E2E: Run' + # command: npm run ci:e2e:run + # environment: + # CYPRESS_ENABLE_RECORD: false + # - run: + # name: 'E2E: Teardown' + # command: npm run ci:e2e:teardown ", "stateCleared": "modified", }, @@ -668,7 +678,9 @@ jobs: "buildTool": "gradle", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -682,71 +694,71 @@ exports[`generator - CI-CD Circle CI test Circle CI: Gradle with Snyk should mat ".circleci/config.yml": { "contents": "version: 2.1 jobs: - build: - machine: - image: ubuntu-2004:current - resource_class: large - steps: - - checkout - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "build.gradle" }}-{{ checksum "package-lock.json" }} - # Perform a Partial Cache Restore (https://circleci.com/docs/2.0/caching/#restoring-cache) - - v1-dependencies- - - run: - name: Print Java Version - command: "java -version" - - run: - name: Print Node Version - command: "node -v" - - run: - name: Print NPM Version - command: "npm -v" - - run: - name: Install Node Modules - command: "npm install" - - run: - name: Install Snyk CLI - command: | - curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') - chmod +x snyk - - run: - name: Snyk test - command: "./snyk test --all-projects || true" - - run: - name: Snyk monitor - command: "./snyk monitor --all-projects" - - save_cache: - paths: - - node - - node_modules - - ~/.gradle - key: v1-dependencies-{{ checksum "build.gradle" }}-{{ checksum "package-lock.json" }} - - - run: - name: Give Executable Power - command: "chmod +x gradlew" - - run: - name: Backend tests - command: npm run ci:backend:test - - run: - name: Run Front End Tests - command: npm run ci:frontend:test - # - run: - # name: 'E2E: Package' - # command: npm run ci:e2e:package - # - run: - # name: 'E2E: Prepare' - # command: npm run ci:e2e:prepare - # - run: - # name: 'E2E: Run' - # command: npm run ci:e2e:run - # environment: - # CYPRESS_ENABLE_RECORD: false - # - run: - # name: 'E2E: Teardown' - # command: npm run ci:e2e:teardown + build: + machine: + image: ubuntu-2004:current + resource_class: large + steps: + - checkout + # Download and cache dependencies + - restore_cache: + keys: + - v1-dependencies-{{ checksum "build.gradle" }}-{{ checksum "package-lock.json" }} + # Perform a Partial Cache Restore (https://circleci.com/docs/2.0/caching/#restoring-cache) + - v1-dependencies- + - run: + name: Print Java Version + command: 'java -version' + - run: + name: Print Node Version + command: 'node -v' + - run: + name: Print NPM Version + command: 'npm -v' + - run: + name: Install Node Modules + command: 'npm install' + - run: + name: Install Snyk CLI + command: | + curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') + chmod +x snyk + - run: + name: Snyk test + command: './snyk test --all-projects || true' + - run: + name: Snyk monitor + command: './snyk monitor --all-projects' + - save_cache: + paths: + - node + - node_modules + - ~/.gradle + key: v1-dependencies-{{ checksum "build.gradle" }}-{{ checksum "package-lock.json" }} + + - run: + name: Give Executable Power + command: 'chmod +x gradlew' + - run: + name: Backend tests + command: npm run ci:backend:test + - run: + name: Run Front End Tests + command: npm run ci:frontend:test + # - run: + # name: 'E2E: Package' + # command: npm run ci:e2e:package + # - run: + # name: 'E2E: Prepare' + # command: npm run ci:e2e:prepare + # - run: + # name: 'E2E: Run' + # command: npm run ci:e2e:run + # environment: + # CYPRESS_ENABLE_RECORD: false + # - run: + # name: 'E2E: Teardown' + # command: npm run ci:e2e:teardown ", "stateCleared": "modified", }, @@ -757,7 +769,9 @@ jobs: "buildTool": "gradle", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -771,60 +785,60 @@ exports[`generator - CI-CD Circle CI test Circle CI: Maven Angular NPM should ma ".circleci/config.yml": { "contents": "version: 2.1 jobs: - build: - machine: - image: ubuntu-2004:current - resource_class: large - steps: - - checkout - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "pom.xml" }}-{{ checksum "package-lock.json" }} - # Perform a Partial Cache Restore (https://circleci.com/docs/2.0/caching/#restoring-cache) - - v1-dependencies- - - run: - name: Print Java Version - command: "java -version" - - run: - name: Print Node Version - command: "node -v" - - run: - name: Print NPM Version - command: "npm -v" - - run: - name: Install Node Modules - command: "npm install" - - save_cache: - paths: - - node - - node_modules - - ~/.m2 - key: v1-dependencies-{{ checksum "pom.xml" }}-{{ checksum "package-lock.json" }} - - - run: - name: Give Executable Power - command: "chmod +x mvnw" - - run: - name: Backend tests - command: npm run ci:backend:test - - run: - name: Run Front End Tests - command: npm run ci:frontend:test - # - run: - # name: 'E2E: Package' - # command: npm run ci:e2e:package - # - run: - # name: 'E2E: Prepare' - # command: npm run ci:e2e:prepare - # - run: - # name: 'E2E: Run' - # command: npm run ci:e2e:run - # environment: - # CYPRESS_ENABLE_RECORD: true - # - run: - # name: 'E2E: Teardown' - # command: npm run ci:e2e:teardown + build: + machine: + image: ubuntu-2004:current + resource_class: large + steps: + - checkout + # Download and cache dependencies + - restore_cache: + keys: + - v1-dependencies-{{ checksum "pom.xml" }}-{{ checksum "package-lock.json" }} + # Perform a Partial Cache Restore (https://circleci.com/docs/2.0/caching/#restoring-cache) + - v1-dependencies- + - run: + name: Print Java Version + command: 'java -version' + - run: + name: Print Node Version + command: 'node -v' + - run: + name: Print NPM Version + command: 'npm -v' + - run: + name: Install Node Modules + command: 'npm install' + - save_cache: + paths: + - node + - node_modules + - ~/.m2 + key: v1-dependencies-{{ checksum "pom.xml" }}-{{ checksum "package-lock.json" }} + + - run: + name: Give Executable Power + command: 'chmod +x mvnw' + - run: + name: Backend tests + command: npm run ci:backend:test + - run: + name: Run Front End Tests + command: npm run ci:frontend:test + # - run: + # name: 'E2E: Package' + # command: npm run ci:e2e:package + # - run: + # name: 'E2E: Prepare' + # command: npm run ci:e2e:prepare + # - run: + # name: 'E2E: Run' + # command: npm run ci:e2e:run + # environment: + # CYPRESS_ENABLE_RECORD: true + # - run: + # name: 'E2E: Teardown' + # command: npm run ci:e2e:teardown ", "stateCleared": "modified", }, @@ -835,7 +849,9 @@ jobs: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -849,71 +865,71 @@ exports[`generator - CI-CD Circle CI test Circle CI: Maven with Snyk should matc ".circleci/config.yml": { "contents": "version: 2.1 jobs: - build: - machine: - image: ubuntu-2004:current - resource_class: large - steps: - - checkout - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "pom.xml" }}-{{ checksum "package-lock.json" }} - # Perform a Partial Cache Restore (https://circleci.com/docs/2.0/caching/#restoring-cache) - - v1-dependencies- - - run: - name: Print Java Version - command: "java -version" - - run: - name: Print Node Version - command: "node -v" - - run: - name: Print NPM Version - command: "npm -v" - - run: - name: Install Node Modules - command: "npm install" - - run: - name: Install Snyk CLI - command: | - curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') - chmod +x snyk - - run: - name: Snyk test - command: "./snyk test --all-projects || true" - - run: - name: Snyk monitor - command: "./snyk monitor --all-projects" - - save_cache: - paths: - - node - - node_modules - - ~/.m2 - key: v1-dependencies-{{ checksum "pom.xml" }}-{{ checksum "package-lock.json" }} - - - run: - name: Give Executable Power - command: "chmod +x mvnw" - - run: - name: Backend tests - command: npm run ci:backend:test - - run: - name: Run Front End Tests - command: npm run ci:frontend:test - # - run: - # name: 'E2E: Package' - # command: npm run ci:e2e:package - # - run: - # name: 'E2E: Prepare' - # command: npm run ci:e2e:prepare - # - run: - # name: 'E2E: Run' - # command: npm run ci:e2e:run - # environment: - # CYPRESS_ENABLE_RECORD: false - # - run: - # name: 'E2E: Teardown' - # command: npm run ci:e2e:teardown + build: + machine: + image: ubuntu-2004:current + resource_class: large + steps: + - checkout + # Download and cache dependencies + - restore_cache: + keys: + - v1-dependencies-{{ checksum "pom.xml" }}-{{ checksum "package-lock.json" }} + # Perform a Partial Cache Restore (https://circleci.com/docs/2.0/caching/#restoring-cache) + - v1-dependencies- + - run: + name: Print Java Version + command: 'java -version' + - run: + name: Print Node Version + command: 'node -v' + - run: + name: Print NPM Version + command: 'npm -v' + - run: + name: Install Node Modules + command: 'npm install' + - run: + name: Install Snyk CLI + command: | + curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') + chmod +x snyk + - run: + name: Snyk test + command: './snyk test --all-projects || true' + - run: + name: Snyk monitor + command: './snyk monitor --all-projects' + - save_cache: + paths: + - node + - node_modules + - ~/.m2 + key: v1-dependencies-{{ checksum "pom.xml" }}-{{ checksum "package-lock.json" }} + + - run: + name: Give Executable Power + command: 'chmod +x mvnw' + - run: + name: Backend tests + command: npm run ci:backend:test + - run: + name: Run Front End Tests + command: npm run ci:frontend:test + # - run: + # name: 'E2E: Package' + # command: npm run ci:e2e:package + # - run: + # name: 'E2E: Prepare' + # command: npm run ci:e2e:prepare + # - run: + # name: 'E2E: Run' + # command: npm run ci:e2e:run + # environment: + # CYPRESS_ENABLE_RECORD: false + # - run: + # name: 'E2E: Teardown' + # command: npm run ci:e2e:teardown ", "stateCleared": "modified", }, @@ -924,7 +940,9 @@ jobs: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -939,54 +957,54 @@ exports[`generator - CI-CD GitHub Actions tests GitHub Actions: Gradle Angular N "contents": "name: Application CI on: [push, pull_request] jobs: - validation: - name: "Gradle Wrapper Validation" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v1 - pipeline: - name: sampleMysql pipeline - runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.pull_request.title, '[skip ci]') && !contains(github.event.pull_request.title, '[ci skip]')" - timeout-minutes: 40 - env: - NODE_VERSION: NODE_VERSION - SPRING_OUTPUT_ANSI_ENABLED: DETECT - SPRING_JPA_SHOW_SQL: false - JHI_DISABLE_WEBPACK_LOGS: true - NG_CLI_ANALYTICS: false - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: NODE_VERSION - - uses: actions/setup-java@v4 - with: - distribution: "temurin" - java-version: JAVA_VERSION - - name: Install Node.js packages - run: npm install - - name: Run backend test - run: | - chmod +x gradlew - npm run ci:backend:test - - name: Run frontend test - run: npm run ci:frontend:test - - name: Package application - run: npm run java:jar:prod - - name: "E2E: Package" - run: npm run ci:e2e:package - - name: "E2E: Prepare" - run: npm run ci:e2e:prepare - - name: "E2E: Run" - run: npm run ci:e2e:run + validation: + name: "Gradle Wrapper Validation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: gradle/wrapper-validation-action@v1 + pipeline: + name: sampleMysql pipeline + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.pull_request.title, '[skip ci]') && !contains(github.event.pull_request.title, '[ci skip]')" + timeout-minutes: 40 env: - CYPRESS_ENABLE_RECORD: false - CYPRESS_PROJECT_ID: \${{ secrets.CYPRESS_PROJECT_ID }} - CYPRESS_RECORD_KEY: \${{ secrets.CYPRESS_RECORD_KEY }} - - name: "E2E: Teardown" - run: npm run ci:e2e:teardown + NODE_VERSION: NODE_VERSION + SPRING_OUTPUT_ANSI_ENABLED: DETECT + SPRING_JPA_SHOW_SQL: false + JHI_DISABLE_WEBPACK_LOGS: true + NG_CLI_ANALYTICS: false + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: NODE_VERSION + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: JAVA_VERSION + - name: Install Node.js packages + run: npm install + - name: Run backend test + run: | + chmod +x gradlew + npm run ci:backend:test + - name: Run frontend test + run: npm run ci:frontend:test + - name: Package application + run: npm run java:jar:prod + - name: 'E2E: Package' + run: npm run ci:e2e:package + - name: 'E2E: Prepare' + run: npm run ci:e2e:prepare + - name: 'E2E: Run' + run: npm run ci:e2e:run + env: + CYPRESS_ENABLE_RECORD: false + CYPRESS_PROJECT_ID: \${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_RECORD_KEY: \${{ secrets.CYPRESS_RECORD_KEY }} + - name: 'E2E: Teardown' + run: npm run ci:e2e:teardown ", "stateCleared": "modified", }, @@ -997,7 +1015,9 @@ jobs: "buildTool": "gradle", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -1012,94 +1032,94 @@ exports[`generator - CI-CD GitHub Actions tests GitHub Actions: Gradle Angular N "contents": "name: Application CI on: [push, pull_request] jobs: - validation: - name: "Gradle Wrapper Validation" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v1 - pipeline: - name: sampleMysql pipeline - runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.pull_request.title, '[skip ci]') && !contains(github.event.pull_request.title, '[ci skip]')" - timeout-minutes: 40 - env: - NODE_VERSION: NODE_VERSION - SPRING_OUTPUT_ANSI_ENABLED: DETECT - SPRING_JPA_SHOW_SQL: false - JHI_DISABLE_WEBPACK_LOGS: true - NG_CLI_ANALYTICS: false - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: NODE_VERSION - - uses: actions/setup-java@v4 - with: - distribution: "temurin" - java-version: JAVA_VERSION - - name: Install Node.js packages - run: npm install - - name: Install Snyk CLI - run: | - curl --compressed https://static.snyk.io/cli/latest/snyk-linux -o snyk - chmod +x snyk - - name: Snyk test - continue-on-error: true - run: ./snyk test --all-projects - env: - SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }} - - name: Snyk monitor - continue-on-error: true - run: ./snyk monitor --all-projects + validation: + name: "Gradle Wrapper Validation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: gradle/wrapper-validation-action@v1 + pipeline: + name: sampleMysql pipeline + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.pull_request.title, '[skip ci]') && !contains(github.event.pull_request.title, '[ci skip]')" + timeout-minutes: 40 env: - SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }} - - name: Run backend test - run: | - chmod +x gradlew - npm run ci:backend:test - - name: Run frontend test - run: npm run ci:frontend:test - - name: Analyze code with SonarQube - env: - GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }} - run: | - if [ ! -z "$SONAR_TOKEN" ]; then - ./gradlew sonarqube --no-daemon -Dsonar.host.url=http://sonar.com:9000 - else - echo No SONAR_TOKEN, skipping... - fi - - name: Package application - run: npm run java:jar:prod - - name: Deploy to Heroku - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - env: - HEROKU_API_KEY: \${{ secrets.HEROKU_API_KEY }} - run: | - if [ ! -z "$HEROKU_API_KEY" ]; then - ./gradlew deployHeroku --no-daemon - else - echo No HEROKU_API_KEY, skipping... - fi - - name: Build and publish docker image - if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) - run: | - GIT_TAG=:\${GITHUB_REF#refs/tags/} - DOCKER_TAG=\${GIT_TAG#:refs/heads/main} - ./gradlew jib -Djib.to.image=jhipster-publish-docker\${DOCKER_TAG} -Djib.to.auth.username="\${{ secrets.DOCKER_USERNAME }}" -Djib.to.auth.password="\${{ secrets.DOCKER_PASSWORD }}" -Pprod - - name: "E2E: Package" - run: npm run ci:e2e:package - - name: "E2E: Prepare" - run: npm run ci:e2e:prepare - - name: "E2E: Run" - run: npm run ci:e2e:run - env: - CYPRESS_ENABLE_RECORD: false - CYPRESS_PROJECT_ID: \${{ secrets.CYPRESS_PROJECT_ID }} - CYPRESS_RECORD_KEY: \${{ secrets.CYPRESS_RECORD_KEY }} - - name: "E2E: Teardown" - run: npm run ci:e2e:teardown + NODE_VERSION: NODE_VERSION + SPRING_OUTPUT_ANSI_ENABLED: DETECT + SPRING_JPA_SHOW_SQL: false + JHI_DISABLE_WEBPACK_LOGS: true + NG_CLI_ANALYTICS: false + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: NODE_VERSION + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: JAVA_VERSION + - name: Install Node.js packages + run: npm install + - name: Install Snyk CLI + run: | + curl --compressed https://static.snyk.io/cli/latest/snyk-linux -o snyk + chmod +x snyk + - name: Snyk test + continue-on-error: true + run: ./snyk test --all-projects + env: + SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }} + - name: Snyk monitor + continue-on-error: true + run: ./snyk monitor --all-projects + env: + SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }} + - name: Run backend test + run: | + chmod +x gradlew + npm run ci:backend:test + - name: Run frontend test + run: npm run ci:frontend:test + - name: Analyze code with SonarQube + env: + GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }} + run: | + if [ ! -z "$SONAR_TOKEN" ]; then + ./gradlew sonarqube --no-daemon -Dsonar.host.url=http://sonar.com:9000 + else + echo No SONAR_TOKEN, skipping... + fi + - name: Package application + run: npm run java:jar:prod + - name: Deploy to Heroku + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + env: + HEROKU_API_KEY: \${{ secrets.HEROKU_API_KEY }} + run: | + if [ ! -z "$HEROKU_API_KEY" ]; then + ./gradlew deployHeroku --no-daemon + else + echo No HEROKU_API_KEY, skipping... + fi + - name: Build and publish docker image + if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) + run: | + GIT_TAG=:\${GITHUB_REF#refs/tags/} + DOCKER_TAG=\${GIT_TAG#:refs/heads/main} + ./gradlew jib -Djib.to.image=jhipster-publish-docker\${DOCKER_TAG} -Djib.to.auth.username="\${{ secrets.DOCKER_USERNAME }}" -Djib.to.auth.password="\${{ secrets.DOCKER_PASSWORD }}" -Pprod + - name: 'E2E: Package' + run: npm run ci:e2e:package + - name: 'E2E: Prepare' + run: npm run ci:e2e:prepare + - name: 'E2E: Run' + run: npm run ci:e2e:run + env: + CYPRESS_ENABLE_RECORD: false + CYPRESS_PROJECT_ID: \${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_RECORD_KEY: \${{ secrets.CYPRESS_RECORD_KEY }} + - name: 'E2E: Teardown' + run: npm run ci:e2e:teardown ", "stateCleared": "modified", }, @@ -1110,7 +1130,9 @@ jobs: "buildTool": "gradle", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -1124,29 +1146,29 @@ services: ports: - 5000:5000 #environment: - # uncomment to enable basic auth - #- REGISTRY_AUTH=htpasswd - #- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd - #- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm - - # uncomment to enable tls with a certificate - #- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt - #- REGISTRY_HTTP_TLS_KEY=/certs/domain.key - - # uncomment to enable tls with letsencrypt - #- REGISTRY_HTTP_TLS_LETSENCRYPT_CACHEFILE=/path/to/cache-file - #- REGISTRY_HTTP_TLS_LETSENCRYPT_EMAIL=mail@example.com + # uncomment to enable basic auth + #- REGISTRY_AUTH=htpasswd + #- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd + #- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm + + # uncomment to enable tls with a certificate + #- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt + #- REGISTRY_HTTP_TLS_KEY=/certs/domain.key + + # uncomment to enable tls with letsencrypt + #- REGISTRY_HTTP_TLS_LETSENCRYPT_CACHEFILE=/path/to/cache-file + #- REGISTRY_HTTP_TLS_LETSENCRYPT_EMAIL=mail@example.com #volumes: - # uncomment to enable basic auth - # you will need to generate a \`htpasswd\` file using : - # docker run --entrypoint htpasswd registry:2 -Bbn admin admin > ~/volumes/registry/htpasswd - #- ~/volumes/registry/htpasswd:/auth/htpasswd:ro + # uncomment to enable basic auth + # you will need to generate a \`htpasswd\` file using : + # docker run --entrypoint htpasswd registry:2 -Bbn admin admin > ~/volumes/registry/htpasswd + #- ~/volumes/registry/htpasswd:/auth/htpasswd:ro - # uncomment to enable tls - #- ~/volumes/registry/certs:/certs + # uncomment to enable tls + #- ~/volumes/registry/certs:/certs - # uncomment to persist data to a volume - #- ~/volumes/registry/data:/var/lib/registry + # uncomment to persist data to a volume + #- ~/volumes/registry/data:/var/lib/registry registry-ui: image: konradkleine/docker-registry-frontend:v2 environment: @@ -1155,6 +1177,7 @@ services: #- ENV_DOCKER_REGISTRY_USE_SSL=1 ports: - 5080:80 + ", "stateCleared": "modified", }, @@ -1167,48 +1190,48 @@ exports[`generator - CI-CD GitHub Actions tests GitHub Actions: Maven Angular NP "contents": "name: Application CI on: [push, pull_request] jobs: - pipeline: - name: sampleMysql pipeline - runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.pull_request.title, '[skip ci]') && !contains(github.event.pull_request.title, '[ci skip]')" - timeout-minutes: 40 - env: - NODE_VERSION: NODE_VERSION - SPRING_OUTPUT_ANSI_ENABLED: DETECT - SPRING_JPA_SHOW_SQL: false - JHI_DISABLE_WEBPACK_LOGS: true - NG_CLI_ANALYTICS: false - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: NODE_VERSION - - uses: actions/setup-java@v4 - with: - distribution: "temurin" - java-version: JAVA_VERSION - - name: Install Node.js packages - run: npm install - - name: Run backend test - run: | - chmod +x mvnw - npm run ci:backend:test - - name: Run frontend test - run: npm run ci:frontend:test - - name: Package application - run: npm run java:jar:prod - - name: "E2E: Package" - run: npm run ci:e2e:package - - name: "E2E: Prepare" - run: npm run ci:e2e:prepare - - name: "E2E: Run" - run: npm run ci:e2e:run + pipeline: + name: sampleMysql pipeline + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.pull_request.title, '[skip ci]') && !contains(github.event.pull_request.title, '[ci skip]')" + timeout-minutes: 40 env: - CYPRESS_ENABLE_RECORD: false - CYPRESS_PROJECT_ID: \${{ secrets.CYPRESS_PROJECT_ID }} - CYPRESS_RECORD_KEY: \${{ secrets.CYPRESS_RECORD_KEY }} - - name: "E2E: Teardown" - run: npm run ci:e2e:teardown + NODE_VERSION: NODE_VERSION + SPRING_OUTPUT_ANSI_ENABLED: DETECT + SPRING_JPA_SHOW_SQL: false + JHI_DISABLE_WEBPACK_LOGS: true + NG_CLI_ANALYTICS: false + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: NODE_VERSION + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: JAVA_VERSION + - name: Install Node.js packages + run: npm install + - name: Run backend test + run: | + chmod +x mvnw + npm run ci:backend:test + - name: Run frontend test + run: npm run ci:frontend:test + - name: Package application + run: npm run java:jar:prod + - name: 'E2E: Package' + run: npm run ci:e2e:package + - name: 'E2E: Prepare' + run: npm run ci:e2e:prepare + - name: 'E2E: Run' + run: npm run ci:e2e:run + env: + CYPRESS_ENABLE_RECORD: false + CYPRESS_PROJECT_ID: \${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_RECORD_KEY: \${{ secrets.CYPRESS_RECORD_KEY }} + - name: 'E2E: Teardown' + run: npm run ci:e2e:teardown ", "stateCleared": "modified", }, @@ -1219,7 +1242,9 @@ jobs: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -1234,88 +1259,88 @@ exports[`generator - CI-CD GitHub Actions tests GitHub Actions: Maven Angular NP "contents": "name: Application CI on: [push, pull_request] jobs: - pipeline: - name: sampleMysql pipeline - runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.pull_request.title, '[skip ci]') && !contains(github.event.pull_request.title, '[ci skip]')" - timeout-minutes: 40 - env: - NODE_VERSION: NODE_VERSION - SPRING_OUTPUT_ANSI_ENABLED: DETECT - SPRING_JPA_SHOW_SQL: false - JHI_DISABLE_WEBPACK_LOGS: true - NG_CLI_ANALYTICS: false - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: NODE_VERSION - - uses: actions/setup-java@v4 - with: - distribution: "temurin" - java-version: JAVA_VERSION - - name: Install Node.js packages - run: npm install - - name: Install Snyk CLI - run: | - curl --compressed https://static.snyk.io/cli/latest/snyk-linux -o snyk - chmod +x snyk - - name: Snyk test - continue-on-error: true - run: ./snyk test --all-projects + pipeline: + name: sampleMysql pipeline + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.pull_request.title, '[skip ci]') && !contains(github.event.pull_request.title, '[ci skip]')" + timeout-minutes: 40 env: - SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }} - - name: Snyk monitor - continue-on-error: true - run: ./snyk monitor --all-projects - env: - SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }} - - name: Run backend test - run: | - chmod +x mvnw - npm run ci:backend:test - - name: Run frontend test - run: npm run ci:frontend:test - - name: Analyze code with SonarQube - env: - GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }} - run: | - if [ ! -z "$SONAR_TOKEN" ]; then - ./mvnw -ntp initialize sonar:sonar -Dsonar.host.url=http://sonar.com:9000 - else - echo No SONAR_TOKEN, skipping... - fi - - name: Package application - run: npm run java:jar:prod - - name: Deploy to Heroku - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - env: - HEROKU_API_KEY: \${{ secrets.HEROKU_API_KEY }} - run: | - if [ ! -z "$HEROKU_API_KEY" ]; then - ./mvnw -ntp com.heroku.sdk:heroku-maven-plugin:3.0.7:deploy -DskipTests -Pprod -Dheroku.buildpacks=heroku/jvm -Dheroku.appName=sample-mysql - else - echo No HEROKU_API_KEY, skipping... - fi - - name: Build and publish docker image - if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) - run: | - GIT_TAG=:\${GITHUB_REF#refs/tags/} - DOCKER_TAG=\${GIT_TAG#:refs/heads/main} - ./mvnw -ntp jib:build -Djib.to.image=jhipster-publish-docker\${DOCKER_TAG} -Djib.to.auth.username="\${{ secrets.DOCKER_USERNAME }}" -Djib.to.auth.password="\${{ secrets.DOCKER_PASSWORD }}" -Pprod - - name: "E2E: Package" - run: npm run ci:e2e:package - - name: "E2E: Prepare" - run: npm run ci:e2e:prepare - - name: "E2E: Run" - run: npm run ci:e2e:run - env: - CYPRESS_ENABLE_RECORD: true - CYPRESS_PROJECT_ID: \${{ secrets.CYPRESS_PROJECT_ID }} - CYPRESS_RECORD_KEY: \${{ secrets.CYPRESS_RECORD_KEY }} - - name: "E2E: Teardown" - run: npm run ci:e2e:teardown + NODE_VERSION: NODE_VERSION + SPRING_OUTPUT_ANSI_ENABLED: DETECT + SPRING_JPA_SHOW_SQL: false + JHI_DISABLE_WEBPACK_LOGS: true + NG_CLI_ANALYTICS: false + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: NODE_VERSION + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: JAVA_VERSION + - name: Install Node.js packages + run: npm install + - name: Install Snyk CLI + run: | + curl --compressed https://static.snyk.io/cli/latest/snyk-linux -o snyk + chmod +x snyk + - name: Snyk test + continue-on-error: true + run: ./snyk test --all-projects + env: + SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }} + - name: Snyk monitor + continue-on-error: true + run: ./snyk monitor --all-projects + env: + SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }} + - name: Run backend test + run: | + chmod +x mvnw + npm run ci:backend:test + - name: Run frontend test + run: npm run ci:frontend:test + - name: Analyze code with SonarQube + env: + GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }} + run: | + if [ ! -z "$SONAR_TOKEN" ]; then + ./mvnw -ntp initialize sonar:sonar -Dsonar.host.url=http://sonar.com:9000 + else + echo No SONAR_TOKEN, skipping... + fi + - name: Package application + run: npm run java:jar:prod + - name: Deploy to Heroku + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + env: + HEROKU_API_KEY: \${{ secrets.HEROKU_API_KEY }} + run: | + if [ ! -z "$HEROKU_API_KEY" ]; then + ./mvnw -ntp com.heroku.sdk:heroku-maven-plugin:3.0.7:deploy -DskipTests -Pprod -Dheroku.buildpacks=heroku/jvm -Dheroku.appName=sample-mysql + else + echo No HEROKU_API_KEY, skipping... + fi + - name: Build and publish docker image + if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) + run: | + GIT_TAG=:\${GITHUB_REF#refs/tags/} + DOCKER_TAG=\${GIT_TAG#:refs/heads/main} + ./mvnw -ntp jib:build -Djib.to.image=jhipster-publish-docker\${DOCKER_TAG} -Djib.to.auth.username="\${{ secrets.DOCKER_USERNAME }}" -Djib.to.auth.password="\${{ secrets.DOCKER_PASSWORD }}" -Pprod + - name: 'E2E: Package' + run: npm run ci:e2e:package + - name: 'E2E: Prepare' + run: npm run ci:e2e:prepare + - name: 'E2E: Run' + run: npm run ci:e2e:run + env: + CYPRESS_ENABLE_RECORD: true + CYPRESS_PROJECT_ID: \${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_RECORD_KEY: \${{ secrets.CYPRESS_RECORD_KEY }} + - name: 'E2E: Teardown' + run: npm run ci:e2e:teardown ", "stateCleared": "modified", }, @@ -1326,7 +1351,9 @@ jobs: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -1359,29 +1386,29 @@ services: ports: - 5000:5000 #environment: - # uncomment to enable basic auth - #- REGISTRY_AUTH=htpasswd - #- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd - #- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm - - # uncomment to enable tls with a certificate - #- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt - #- REGISTRY_HTTP_TLS_KEY=/certs/domain.key - - # uncomment to enable tls with letsencrypt - #- REGISTRY_HTTP_TLS_LETSENCRYPT_CACHEFILE=/path/to/cache-file - #- REGISTRY_HTTP_TLS_LETSENCRYPT_EMAIL=mail@example.com + # uncomment to enable basic auth + #- REGISTRY_AUTH=htpasswd + #- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd + #- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm + + # uncomment to enable tls with a certificate + #- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt + #- REGISTRY_HTTP_TLS_KEY=/certs/domain.key + + # uncomment to enable tls with letsencrypt + #- REGISTRY_HTTP_TLS_LETSENCRYPT_CACHEFILE=/path/to/cache-file + #- REGISTRY_HTTP_TLS_LETSENCRYPT_EMAIL=mail@example.com #volumes: - # uncomment to enable basic auth - # you will need to generate a \`htpasswd\` file using : - # docker run --entrypoint htpasswd registry:2 -Bbn admin admin > ~/volumes/registry/htpasswd - #- ~/volumes/registry/htpasswd:/auth/htpasswd:ro + # uncomment to enable basic auth + # you will need to generate a \`htpasswd\` file using : + # docker run --entrypoint htpasswd registry:2 -Bbn admin admin > ~/volumes/registry/htpasswd + #- ~/volumes/registry/htpasswd:/auth/htpasswd:ro - # uncomment to enable tls - #- ~/volumes/registry/certs:/certs + # uncomment to enable tls + #- ~/volumes/registry/certs:/certs - # uncomment to persist data to a volume - #- ~/volumes/registry/data:/var/lib/registry + # uncomment to persist data to a volume + #- ~/volumes/registry/data:/var/lib/registry registry-ui: image: konradkleine/docker-registry-frontend:v2 environment: @@ -1390,6 +1417,7 @@ services: #- ENV_DOCKER_REGISTRY_USE_SSL=1 ports: - 5080:80 + ", "stateCleared": "modified", }, @@ -1402,48 +1430,48 @@ exports[`generator - CI-CD GitHub Actions tests GitHub Actions: autoconfigure sh "contents": "name: Application CI on: [push, pull_request] jobs: - pipeline: - name: sampleMysql pipeline - runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.pull_request.title, '[skip ci]') && !contains(github.event.pull_request.title, '[ci skip]')" - timeout-minutes: 40 - env: - NODE_VERSION: NODE_VERSION - SPRING_OUTPUT_ANSI_ENABLED: DETECT - SPRING_JPA_SHOW_SQL: false - JHI_DISABLE_WEBPACK_LOGS: true - NG_CLI_ANALYTICS: false - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: NODE_VERSION - - uses: actions/setup-java@v4 - with: - distribution: "temurin" - java-version: JAVA_VERSION - - name: Install Node.js packages - run: npm install - - name: Run backend test - run: | - chmod +x mvnw - npm run ci:backend:test - - name: Run frontend test - run: npm run ci:frontend:test - - name: Package application - run: npm run java:jar:prod - - name: "E2E: Package" - run: npm run ci:e2e:package - - name: "E2E: Prepare" - run: npm run ci:e2e:prepare - - name: "E2E: Run" - run: npm run ci:e2e:run + pipeline: + name: sampleMysql pipeline + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.pull_request.title, '[skip ci]') && !contains(github.event.pull_request.title, '[ci skip]')" + timeout-minutes: 40 env: - CYPRESS_ENABLE_RECORD: false - CYPRESS_PROJECT_ID: \${{ secrets.CYPRESS_PROJECT_ID }} - CYPRESS_RECORD_KEY: \${{ secrets.CYPRESS_RECORD_KEY }} - - name: "E2E: Teardown" - run: npm run ci:e2e:teardown + NODE_VERSION: NODE_VERSION + SPRING_OUTPUT_ANSI_ENABLED: DETECT + SPRING_JPA_SHOW_SQL: false + JHI_DISABLE_WEBPACK_LOGS: true + NG_CLI_ANALYTICS: false + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: NODE_VERSION + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: JAVA_VERSION + - name: Install Node.js packages + run: npm install + - name: Run backend test + run: | + chmod +x mvnw + npm run ci:backend:test + - name: Run frontend test + run: npm run ci:frontend:test + - name: Package application + run: npm run java:jar:prod + - name: 'E2E: Package' + run: npm run ci:e2e:package + - name: 'E2E: Prepare' + run: npm run ci:e2e:prepare + - name: 'E2E: Run' + run: npm run ci:e2e:run + env: + CYPRESS_ENABLE_RECORD: false + CYPRESS_PROJECT_ID: \${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_RECORD_KEY: \${{ secrets.CYPRESS_RECORD_KEY }} + - name: 'E2E: Teardown' + run: npm run ci:e2e:teardown ", "stateCleared": "modified", }, @@ -1454,7 +1482,9 @@ jobs: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -1466,82 +1496,86 @@ jobs: exports[`generator - CI-CD GitLab CI tests GitLab CI: Gradle Angular NPM should match files snapshot 1`] = ` { ".gitlab-ci.yml": { - "contents": "cache: - key: "$CI_COMMIT_REF_NAME" - paths: - - .gradle/ + "contents": " +cache: + key: "$CI_COMMIT_REF_NAME" + paths: + - .gradle/ stages: - - check - - build - - test - - analyze - - package - - release - - deploy + - check + - build + - test + - analyze + - package + - release + - deploy before_script: - - export NG_CLI_ANALYTICS="false" - - export GRADLE_USER_HOME=\`pwd\`/.gradle - - ./gradlew npm_install -PnodeInstall --no-daemon + - export NG_CLI_ANALYTICS="false" + - export GRADLE_USER_HOME=\`pwd\`/.gradle + - ./gradlew npm_install -PnodeInstall --no-daemon nohttp: - stage: check - script: - - ./gradlew checkstyleNohttp --no-daemon + stage: check + script: + - ./gradlew checkstyleNohttp --no-daemon gradle-compile: - stage: build - script: - - ./gradlew compileJava -x check -PnodeInstall --no-daemon - artifacts: - paths: - - build/classes/ - - build/generated/ - expire_in: 1 day + stage: build + script: + - ./gradlew compileJava -x check -PnodeInstall --no-daemon + artifacts: + paths: + - build/classes/ + - build/generated/ + expire_in: 1 day gradle-test: - stage: test - script: - - ./gradlew test -PnodeInstall --no-daemon - artifacts: - reports: - junit: build/test-results/test/TEST-*.xml - paths: - - build/test-results/ - - build/jacoco/ - expire_in: 1 day + stage: test + script: + - ./gradlew test -PnodeInstall --no-daemon + artifacts: + reports: + junit: build/test-results/test/TEST-*.xml + paths: + - build/test-results/ + - build/jacoco/ + expire_in: 1 day gradle-integration-test: - stage: test - script: - - ./gradlew integrationTest -PnodeInstall --no-daemon - artifacts: - reports: - junit: build/test-results/integrationTest/TEST-*.xml - paths: - - build/test-results/ - - build/jacoco/ - expire_in: 1 day + + stage: test + script: + - ./gradlew integrationTest -PnodeInstall --no-daemon + artifacts: + reports: + junit: build/test-results/integrationTest/TEST-*.xml + paths: + - build/test-results/ + - build/jacoco/ + expire_in: 1 day frontend-test: - stage: test - script: - - ./gradlew npm_run_test -PnodeInstall --no-daemon - artifacts: - reports: - junit: build/test-results/TESTS-results-jest.xml - paths: - - build/test-results/ - - build/jacoco/ - expire_in: 1 day + stage: test + script: + - ./gradlew npm_run_test -PnodeInstall --no-daemon + artifacts: + reports: + junit: build/test-results/TESTS-results-jest.xml + paths: + - build/test-results/ + - build/jacoco/ + expire_in: 1 day + gradle-package: - stage: package - script: - - ./gradlew bootJar -Pprod -PnodeInstall -x check --no-daemon - artifacts: - paths: - - build/libs/*.jar - - build/classes - expire_in: 1 day + stage: package + script: + - ./gradlew bootJar -Pprod -PnodeInstall -x check --no-daemon + artifacts: + paths: + - build/libs/*.jar + - build/classes + expire_in: 1 day + # Uncomment the following line to use gitlabs container registry. You need to adapt the REGISTRY_URL in case you are not using gitlab.com #docker-push: # stage: release @@ -1563,7 +1597,9 @@ gradle-package: "buildTool": "gradle", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -1578,99 +1614,99 @@ exports[`generator - CI-CD GitLab CI tests GitLab CI: Maven Angular NPM inside D "contents": "image: jhipster/jhipster:vJHIPSTER_VERSION cache: - key: "$CI_COMMIT_REF_NAME" - paths: - - .maven/ + key: "$CI_COMMIT_REF_NAME" + paths: + - .maven/ stages: - - check - - build - - test - - analyze - - package - - release - - deploy + - check + - build + - test + - analyze + - package + - release + - deploy before_script: - - export NG_CLI_ANALYTICS="false" - - export MAVEN_USER_HOME=\`pwd\`/.maven + - export NG_CLI_ANALYTICS="false" + - export MAVEN_USER_HOME=\`pwd\`/.maven nohttp: - stage: check - script: - - ./mvnw -ntp checkstyle:check -Dmaven.repo.local=$MAVEN_USER_HOME + stage: check + script: + - ./mvnw -ntp checkstyle:check -Dmaven.repo.local=$MAVEN_USER_HOME dependency-scanning: - stage: check - script: - - curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') - - chmod +x snyk - - ./snyk test --all-projects - - ./snyk monitor --all-projects - allow_failure: true + stage: check + script: + - curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') + - chmod +x snyk + - ./snyk test --all-projects + - ./snyk monitor --all-projects + allow_failure: true maven-compile: - stage: build - script: - - ./mvnw -ntp compile -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - paths: - - target/classes/ - - target/generated-sources/ - expire_in: 1 day + stage: build + script: + - ./mvnw -ntp compile -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/classes/ + - target/generated-sources/ + expire_in: 1 day maven-test: - services: - - docker:dind + services: + - docker:dind - variables: - # Instruct Testcontainers to use the daemon of DinD. - DOCKER_HOST: "tcp://docker:2375" - # Improve performance with overlayfs. - DOCKER_DRIVER: overlay2 - - stage: test - script: - - ./mvnw -ntp verify -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - reports: - junit: - - target/surefire-reports/TEST-*.xml - - target/failsafe-reports/TEST-*.xml - paths: - - target/surefire-reports - - target/failsafe-reports - - target/site - expire_in: 1 day + variables: + # Instruct Testcontainers to use the daemon of DinD. + DOCKER_HOST: 'tcp://docker:2375' + # Improve performance with overlayfs. + DOCKER_DRIVER: overlay2 + + stage: test + script: + - ./mvnw -ntp verify -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + reports: + junit: + - target/surefire-reports/TEST-*.xml + - target/failsafe-reports/TEST-*.xml + paths: + - target/surefire-reports + - target/failsafe-reports + - target/site + expire_in: 1 day frontend-test: - stage: test - script: - - npm install - - npm test - artifacts: - reports: - junit: target/test-results/TESTS-results-jest.xml - paths: - - target/test-results - - target/jacoco - expire_in: 1 day + stage: test + script: + - npm install + - npm test + artifacts: + reports: + junit: target/test-results/TESTS-results-jest.xml + paths: + - target/test-results + - target/jacoco + expire_in: 1 day sonar-analyze: - stage: analyze - dependencies: - - maven-test - - frontend-test - script: - - ./mvnw -ntp org.jacoco:jacoco-maven-plugin:prepare-agent initialize sonar:sonar -Dsonar.host.url=http://localhost:9000 -Dsonar.login=$SONAR_TOKEN -Dmaven.repo.local=$MAVEN_USER_HOME - allow_failure: true + stage: analyze + dependencies: + - maven-test + - frontend-test + script: + - ./mvnw -ntp org.jacoco:jacoco-maven-plugin:prepare-agent initialize sonar:sonar -Dsonar.host.url=http://localhost:9000 -Dsonar.login=$SONAR_TOKEN -Dmaven.repo.local=$MAVEN_USER_HOME + allow_failure: true maven-package: - stage: package - script: - - ./mvnw -ntp verify deploy -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - paths: - - target/*.jar - - target/classes - expire_in: 1 day + stage: package + script: + - ./mvnw -ntp verify deploy -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/*.jar + - target/classes + expire_in: 1 day # Uncomment the following line to use gitlabs container registry. You need to adapt the REGISTRY_URL in case you are not using gitlab.com #docker-push: @@ -1684,12 +1720,12 @@ maven-package: # - ./mvnw -ntp jib:build -Pprod -Djib.to.image=$IMAGE_TAG -Djib.to.auth.username=gitlab-ci-token -Djib.to.auth.password=$CI_BUILD_TOKEN -Dmaven.repo.local=$MAVEN_USER_HOME deploy-to-production: - stage: deploy - script: - - ./mvnw -ntp com.heroku.sdk:heroku-maven-plugin:3.0.7:deploy -DskipTests -Pprod -Dheroku.buildpacks=heroku/jvm -Dheroku.appName=sample-mysql -Dmaven.repo.local=$MAVEN_USER_HOME - environment: - name: production - when: manual + stage: deploy + script: + - ./mvnw -ntp com.heroku.sdk:heroku-maven-plugin:3.0.7:deploy -DskipTests -Pprod -Dheroku.buildpacks=heroku/jvm -Dheroku.appName=sample-mysql -Dmaven.repo.local=$MAVEN_USER_HOME + environment: + name: production + when: manual ", "stateCleared": "modified", }, @@ -1700,7 +1736,9 @@ deploy-to-production: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -1731,75 +1769,78 @@ deploy-to-production: exports[`generator - CI-CD GitLab CI tests GitLab CI: Maven Angular NPM should match files snapshot 1`] = ` { ".gitlab-ci.yml": { - "contents": "cache: - key: "$CI_COMMIT_REF_NAME" - paths: - - .maven/ + "contents": " +cache: + key: "$CI_COMMIT_REF_NAME" + paths: + - .maven/ stages: - - check - - build - - test - - analyze - - package - - release - - deploy + - check + - build + - test + - analyze + - package + - release + - deploy before_script: - - export NG_CLI_ANALYTICS="false" - - export MAVEN_USER_HOME=\`pwd\`/.maven - - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:install-node-and-npm@install-node-and-npm -Dmaven.repo.local=$MAVEN_USER_HOME - - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:npm -Dmaven.repo.local=$MAVEN_USER_HOME + - export NG_CLI_ANALYTICS="false" + - export MAVEN_USER_HOME=\`pwd\`/.maven + - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:install-node-and-npm@install-node-and-npm -Dmaven.repo.local=$MAVEN_USER_HOME + - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:npm -Dmaven.repo.local=$MAVEN_USER_HOME nohttp: - stage: check - script: - - ./mvnw -ntp checkstyle:check -Dmaven.repo.local=$MAVEN_USER_HOME + stage: check + script: + - ./mvnw -ntp checkstyle:check -Dmaven.repo.local=$MAVEN_USER_HOME maven-compile: - stage: build - script: - - ./mvnw -ntp compile -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - paths: - - target/classes/ - - target/generated-sources/ - expire_in: 1 day + stage: build + script: + - ./mvnw -ntp compile -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/classes/ + - target/generated-sources/ + expire_in: 1 day maven-test: - stage: test - script: - - ./mvnw -ntp verify -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - reports: - junit: - - target/surefire-reports/TEST-*.xml - - target/failsafe-reports/TEST-*.xml - paths: - - target/surefire-reports - - target/failsafe-reports - - target/site - expire_in: 1 day + + stage: test + script: + - ./mvnw -ntp verify -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + reports: + junit: + - target/surefire-reports/TEST-*.xml + - target/failsafe-reports/TEST-*.xml + paths: + - target/surefire-reports + - target/failsafe-reports + - target/site + expire_in: 1 day frontend-test: - stage: test - script: - - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:npm -Dfrontend.npm.arguments='run test' -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - reports: - junit: target/test-results/TESTS-results-jest.xml - paths: - - target/test-results - - target/jacoco - expire_in: 1 day + stage: test + script: + - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:npm -Dfrontend.npm.arguments='run test' -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + reports: + junit: target/test-results/TESTS-results-jest.xml + paths: + - target/test-results + - target/jacoco + expire_in: 1 day maven-package: - stage: package - script: - - ./mvnw -ntp verify -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - paths: - - target/*.jar - - target/classes - expire_in: 1 day + stage: package + script: + - ./mvnw -ntp verify -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/*.jar + - target/classes + expire_in: 1 day + # Uncomment the following line to use gitlabs container registry. You need to adapt the REGISTRY_URL in case you are not using gitlab.com #docker-push: # stage: release @@ -1821,7 +1862,9 @@ maven-package: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -1833,92 +1876,94 @@ maven-package: exports[`generator - CI-CD GitLab CI tests GitLab CI: Maven Angular NPM with full options should match files snapshot 1`] = ` { ".gitlab-ci.yml": { - "contents": "cache: - key: "$CI_COMMIT_REF_NAME" - paths: - - .maven/ + "contents": " +cache: + key: "$CI_COMMIT_REF_NAME" + paths: + - .maven/ stages: - - check - - build - - test - - analyze - - package - - release - - deploy + - check + - build + - test + - analyze + - package + - release + - deploy before_script: - - export NG_CLI_ANALYTICS="false" - - export MAVEN_USER_HOME=\`pwd\`/.maven - - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:install-node-and-npm@install-node-and-npm -Dmaven.repo.local=$MAVEN_USER_HOME - - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:npm -Dmaven.repo.local=$MAVEN_USER_HOME + - export NG_CLI_ANALYTICS="false" + - export MAVEN_USER_HOME=\`pwd\`/.maven + - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:install-node-and-npm@install-node-and-npm -Dmaven.repo.local=$MAVEN_USER_HOME + - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:npm -Dmaven.repo.local=$MAVEN_USER_HOME nohttp: - stage: check - script: - - ./mvnw -ntp checkstyle:check -Dmaven.repo.local=$MAVEN_USER_HOME + stage: check + script: + - ./mvnw -ntp checkstyle:check -Dmaven.repo.local=$MAVEN_USER_HOME dependency-scanning: - stage: check - script: - - curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') - - chmod +x snyk - - ./snyk test --all-projects - - ./snyk monitor --all-projects - allow_failure: true + stage: check + script: + - curl -Lo ./snyk $(curl -s https://api.github.com/repos/snyk/snyk/releases/latest | grep "browser_download_url.*snyk-linux" | cut -d ':' -f 2,3 | tr -d \\" | tr -d ' ') + - chmod +x snyk + - ./snyk test --all-projects + - ./snyk monitor --all-projects + allow_failure: true maven-compile: - stage: build - script: - - ./mvnw -ntp compile -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - paths: - - target/classes/ - - target/generated-sources/ - expire_in: 1 day + stage: build + script: + - ./mvnw -ntp compile -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/classes/ + - target/generated-sources/ + expire_in: 1 day maven-test: - stage: test - script: - - ./mvnw -ntp verify -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - reports: - junit: - - target/surefire-reports/TEST-*.xml - - target/failsafe-reports/TEST-*.xml - paths: - - target/surefire-reports - - target/failsafe-reports - - target/site - expire_in: 1 day + + stage: test + script: + - ./mvnw -ntp verify -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + reports: + junit: + - target/surefire-reports/TEST-*.xml + - target/failsafe-reports/TEST-*.xml + paths: + - target/surefire-reports + - target/failsafe-reports + - target/site + expire_in: 1 day frontend-test: - stage: test - script: - - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:npm -Dfrontend.npm.arguments='run test' -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - reports: - junit: target/test-results/TESTS-results-jest.xml - paths: - - target/test-results - - target/jacoco - expire_in: 1 day + stage: test + script: + - ./mvnw -ntp com.github.eirslett:frontend-maven-plugin:npm -Dfrontend.npm.arguments='run test' -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + reports: + junit: target/test-results/TESTS-results-jest.xml + paths: + - target/test-results + - target/jacoco + expire_in: 1 day sonar-analyze: - stage: analyze - dependencies: - - maven-test - - frontend-test - script: - - ./mvnw -ntp org.jacoco:jacoco-maven-plugin:prepare-agent initialize sonar:sonar -Dsonar.host.url=http://localhost:9000 -Dsonar.login=$SONAR_TOKEN -Dmaven.repo.local=$MAVEN_USER_HOME - allow_failure: true + stage: analyze + dependencies: + - maven-test + - frontend-test + script: + - ./mvnw -ntp org.jacoco:jacoco-maven-plugin:prepare-agent initialize sonar:sonar -Dsonar.host.url=http://localhost:9000 -Dsonar.login=$SONAR_TOKEN -Dmaven.repo.local=$MAVEN_USER_HOME + allow_failure: true maven-package: - stage: package - script: - - ./mvnw -ntp verify deploy -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - paths: - - target/*.jar - - target/classes - expire_in: 1 day + stage: package + script: + - ./mvnw -ntp verify deploy -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/*.jar + - target/classes + expire_in: 1 day # Uncomment the following line to use gitlabs container registry. You need to adapt the REGISTRY_URL in case you are not using gitlab.com #docker-push: @@ -1932,12 +1977,12 @@ maven-package: # - ./mvnw -ntp jib:build -Pprod -Djib.to.image=$IMAGE_TAG -Djib.to.auth.username=gitlab-ci-token -Djib.to.auth.password=$CI_BUILD_TOKEN -Dmaven.repo.local=$MAVEN_USER_HOME deploy-to-production: - stage: deploy - script: - - ./mvnw -ntp com.heroku.sdk:heroku-maven-plugin:3.0.7:deploy -DskipTests -Pprod -Dheroku.buildpacks=heroku/jvm -Dheroku.appName=sample-mysql -Dmaven.repo.local=$MAVEN_USER_HOME - environment: - name: production - when: manual + stage: deploy + script: + - ./mvnw -ntp com.heroku.sdk:heroku-maven-plugin:3.0.7:deploy -DskipTests -Pprod -Dheroku.buildpacks=heroku/jvm -Dheroku.appName=sample-mysql -Dmaven.repo.local=$MAVEN_USER_HOME + environment: + name: production + when: manual ", "stateCleared": "modified", }, @@ -1948,7 +1993,9 @@ deploy-to-production: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -1982,82 +2029,83 @@ exports[`generator - CI-CD GitLab CI tests GitLab CI: Maven Angular Yarn inside "contents": "image: jhipster/jhipster:vJHIPSTER_VERSION cache: - key: "$CI_COMMIT_REF_NAME" - paths: - - .maven/ + key: "$CI_COMMIT_REF_NAME" + paths: + - .maven/ stages: - - check - - build - - test - - analyze - - package - - release - - deploy + - check + - build + - test + - analyze + - package + - release + - deploy before_script: - - export NG_CLI_ANALYTICS="false" - - export MAVEN_USER_HOME=\`pwd\`/.maven + - export NG_CLI_ANALYTICS="false" + - export MAVEN_USER_HOME=\`pwd\`/.maven nohttp: - stage: check - script: - - ./mvnw -ntp checkstyle:check -Dmaven.repo.local=$MAVEN_USER_HOME + stage: check + script: + - ./mvnw -ntp checkstyle:check -Dmaven.repo.local=$MAVEN_USER_HOME maven-compile: - stage: build - script: - - ./mvnw -ntp compile -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - paths: - - target/classes/ - - target/generated-sources/ - expire_in: 1 day + stage: build + script: + - ./mvnw -ntp compile -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/classes/ + - target/generated-sources/ + expire_in: 1 day maven-test: - services: - - docker:dind + services: + - docker:dind - variables: - # Instruct Testcontainers to use the daemon of DinD. - DOCKER_HOST: "tcp://docker:2375" - # Improve performance with overlayfs. - DOCKER_DRIVER: overlay2 - - stage: test - script: - - ./mvnw -ntp verify -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - reports: - junit: - - target/surefire-reports/TEST-*.xml - - target/failsafe-reports/TEST-*.xml - paths: - - target/surefire-reports - - target/failsafe-reports - - target/site - expire_in: 1 day + variables: + # Instruct Testcontainers to use the daemon of DinD. + DOCKER_HOST: 'tcp://docker:2375' + # Improve performance with overlayfs. + DOCKER_DRIVER: overlay2 + + stage: test + script: + - ./mvnw -ntp verify -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + reports: + junit: + - target/surefire-reports/TEST-*.xml + - target/failsafe-reports/TEST-*.xml + paths: + - target/surefire-reports + - target/failsafe-reports + - target/site + expire_in: 1 day frontend-test: - stage: test - script: - - npm install - - npm test - artifacts: - reports: - junit: target/test-results/TESTS-results-jest.xml - paths: - - target/test-results - - target/jacoco - expire_in: 1 day + stage: test + script: + - npm install + - npm test + artifacts: + reports: + junit: target/test-results/TESTS-results-jest.xml + paths: + - target/test-results + - target/jacoco + expire_in: 1 day maven-package: - stage: package - script: - - ./mvnw -ntp verify -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - paths: - - target/*.jar - - target/classes - expire_in: 1 day + stage: package + script: + - ./mvnw -ntp verify -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/*.jar + - target/classes + expire_in: 1 day + # Uncomment the following line to use gitlabs container registry. You need to adapt the REGISTRY_URL in case you are not using gitlab.com #docker-push: # stage: release @@ -2079,7 +2127,9 @@ maven-package: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -2094,70 +2144,70 @@ exports[`generator - CI-CD GitLab CI tests GitLab CI: npm skip server should mat "contents": "image: jhipster/jhipster:vJHIPSTER_VERSION before_script: - - export NG_CLI_ANALYTICS="false" - - export MAVEN_USER_HOME=\`pwd\`/.maven + - export NG_CLI_ANALYTICS="false" + - export MAVEN_USER_HOME=\`pwd\`/.maven nohttp: - stage: check - script: - - ./mvnw -ntp checkstyle:check -Dmaven.repo.local=$MAVEN_USER_HOME + stage: check + script: + - ./mvnw -ntp checkstyle:check -Dmaven.repo.local=$MAVEN_USER_HOME maven-compile: - stage: build - script: - - ./mvnw -ntp compile -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - paths: - - target/classes/ - - target/generated-sources/ - expire_in: 1 day + stage: build + script: + - ./mvnw -ntp compile -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/classes/ + - target/generated-sources/ + expire_in: 1 day maven-test: - services: - - docker:dind + services: + - docker:dind - variables: - # Instruct Testcontainers to use the daemon of DinD. - DOCKER_HOST: "tcp://docker:2375" - # Improve performance with overlayfs. - DOCKER_DRIVER: overlay2 - - stage: test - script: - - ./mvnw -ntp verify -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - reports: - junit: - - target/surefire-reports/TEST-*.xml - - target/failsafe-reports/TEST-*.xml - paths: - - target/surefire-reports - - target/failsafe-reports - - target/site - expire_in: 1 day + variables: + # Instruct Testcontainers to use the daemon of DinD. + DOCKER_HOST: 'tcp://docker:2375' + # Improve performance with overlayfs. + DOCKER_DRIVER: overlay2 + + stage: test + script: + - ./mvnw -ntp verify -P-webapp -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + reports: + junit: + - target/surefire-reports/TEST-*.xml + - target/failsafe-reports/TEST-*.xml + paths: + - target/surefire-reports + - target/failsafe-reports + - target/site + expire_in: 1 day frontend-test: - stage: test - script: - - npm install - - npm test - artifacts: - reports: - junit: target/test-results/TESTS-results-jest.xml - paths: - - target/test-results - - target/jacoco - expire_in: 1 day + stage: test + script: + - npm install + - npm test + artifacts: + reports: + junit: target/test-results/TESTS-results-jest.xml + paths: + - target/test-results + - target/jacoco + expire_in: 1 day maven-package: - stage: package - script: - - ./mvnw -ntp verify -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME - artifacts: - paths: - - target/*.jar - - target/classes - expire_in: 1 day + stage: package + script: + - ./mvnw -ntp verify -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/*.jar + - target/classes + expire_in: 1 day # Uncomment the following line to use gitlabs container registry. You need to adapt the REGISTRY_URL in case you are not using gitlab.com #docker-push: @@ -2171,40 +2221,40 @@ maven-package: # - ./mvnw -ntp jib:build -Pprod -Djib.to.image=$IMAGE_TAG -Djib.to.auth.username=gitlab-ci-token -Djib.to.auth.password=$CI_BUILD_TOKEN -Dmaven.repo.local=$MAVEN_USER_HOME cache: - paths: - - node_modules/ + paths: + - node_modules/ stages: - - build - - test - - packaging + - build + - test + - packaging webapp-build: - stage: build - script: - - npm install - - npm run webapp:build - artifacts: - paths: - - build/ + stage: build + script: + - npm install + - npm run webapp:build + artifacts: + paths: + - build/ webapp-test: - stage: test - dependencies: - - webapp-build - script: - - npm run webapp:test - artifacts: - reports: - junit: build/test-results/TESTS-results-jest.xml - paths: - - build/test-results - expire_in: 1 day + stage: test + dependencies: + - webapp-build + script: + - npm run webapp:test + artifacts: + reports: + junit: build/test-results/TESTS-results-jest.xml + paths: + - build/test-results + expire_in: 1 day webapp-prod: - stage: packaging - script: - - npm run webapp:prod - # - add cmd to zip the app folder build/resources/main/static - artifacts: - paths: - - build/ + stage: packaging + script: + - npm run webapp:prod + # - add cmd to zip the app folder build/resources/main/static + artifacts: + paths: + - build/ ", "stateCleared": "modified", }, @@ -2233,7 +2283,9 @@ exports[`generator - CI-CD Jenkins tests Jenkins: Gradle Angular NPM should matc "buildTool": "gradle", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -2301,11 +2353,11 @@ node { # uncomment for docker in docker #privileged: true #volumes: - # enable persistent volume (warning: make sure that the local jenkins_home folder is created) - #- ~/volumes/jenkins_home:/var/jenkins_home - # mount docker sock and binary for docker in docker (only works on linux) - #- /var/run/docker.sock:/var/run/docker.sock - #- /usr/bin/docker:/usr/bin/docker + # enable persistent volume (warning: make sure that the local jenkins_home folder is created) + #- ~/volumes/jenkins_home:/var/jenkins_home + # mount docker sock and binary for docker in docker (only works on linux) + #- /var/run/docker.sock:/var/run/docker.sock + #- /usr/bin/docker:/usr/bin/docker ", "stateCleared": "modified", }, @@ -2415,7 +2467,9 @@ exports[`generator - CI-CD Jenkins tests Jenkins: Maven Angular NPM inside Docke "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -2530,29 +2584,29 @@ services: ports: - 5000:5000 #environment: - # uncomment to enable basic auth - #- REGISTRY_AUTH=htpasswd - #- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd - #- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm - - # uncomment to enable tls with a certificate - #- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt - #- REGISTRY_HTTP_TLS_KEY=/certs/domain.key - - # uncomment to enable tls with letsencrypt - #- REGISTRY_HTTP_TLS_LETSENCRYPT_CACHEFILE=/path/to/cache-file - #- REGISTRY_HTTP_TLS_LETSENCRYPT_EMAIL=mail@example.com + # uncomment to enable basic auth + #- REGISTRY_AUTH=htpasswd + #- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd + #- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm + + # uncomment to enable tls with a certificate + #- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt + #- REGISTRY_HTTP_TLS_KEY=/certs/domain.key + + # uncomment to enable tls with letsencrypt + #- REGISTRY_HTTP_TLS_LETSENCRYPT_CACHEFILE=/path/to/cache-file + #- REGISTRY_HTTP_TLS_LETSENCRYPT_EMAIL=mail@example.com #volumes: - # uncomment to enable basic auth - # you will need to generate a \`htpasswd\` file using : - # docker run --entrypoint htpasswd registry:2 -Bbn admin admin > ~/volumes/registry/htpasswd - #- ~/volumes/registry/htpasswd:/auth/htpasswd:ro + # uncomment to enable basic auth + # you will need to generate a \`htpasswd\` file using : + # docker run --entrypoint htpasswd registry:2 -Bbn admin admin > ~/volumes/registry/htpasswd + #- ~/volumes/registry/htpasswd:/auth/htpasswd:ro - # uncomment to enable tls - #- ~/volumes/registry/certs:/certs + # uncomment to enable tls + #- ~/volumes/registry/certs:/certs - # uncomment to persist data to a volume - #- ~/volumes/registry/data:/var/lib/registry + # uncomment to persist data to a volume + #- ~/volumes/registry/data:/var/lib/registry registry-ui: image: konradkleine/docker-registry-frontend:v2 environment: @@ -2561,6 +2615,7 @@ services: #- ENV_DOCKER_REGISTRY_USE_SSL=1 ports: - 5080:80 + ", "stateCleared": "modified", }, @@ -2574,11 +2629,11 @@ services: # uncomment for docker in docker #privileged: true #volumes: - # enable persistent volume (warning: make sure that the local jenkins_home folder is created) - #- ~/volumes/jenkins_home:/var/jenkins_home - # mount docker sock and binary for docker in docker (only works on linux) - #- /var/run/docker.sock:/var/run/docker.sock - #- /usr/bin/docker:/usr/bin/docker + # enable persistent volume (warning: make sure that the local jenkins_home folder is created) + #- ~/volumes/jenkins_home:/var/jenkins_home + # mount docker sock and binary for docker in docker (only works on linux) + #- /var/run/docker.sock:/var/run/docker.sock + #- /usr/bin/docker:/usr/bin/docker ", "stateCleared": "modified", }, @@ -2688,7 +2743,9 @@ exports[`generator - CI-CD Jenkins tests Jenkins: Maven Angular NPM should match "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -2759,11 +2816,11 @@ node { # uncomment for docker in docker #privileged: true #volumes: - # enable persistent volume (warning: make sure that the local jenkins_home folder is created) - #- ~/volumes/jenkins_home:/var/jenkins_home - # mount docker sock and binary for docker in docker (only works on linux) - #- /var/run/docker.sock:/var/run/docker.sock - #- /usr/bin/docker:/usr/bin/docker + # enable persistent volume (warning: make sure that the local jenkins_home folder is created) + #- ~/volumes/jenkins_home:/var/jenkins_home + # mount docker sock and binary for docker in docker (only works on linux) + #- /var/run/docker.sock:/var/run/docker.sock + #- /usr/bin/docker:/usr/bin/docker ", "stateCleared": "modified", }, @@ -2873,7 +2930,9 @@ exports[`generator - CI-CD Jenkins tests Jenkins: Maven Angular NPM with full op "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -2985,29 +3044,29 @@ services: ports: - 5000:5000 #environment: - # uncomment to enable basic auth - #- REGISTRY_AUTH=htpasswd - #- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd - #- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm - - # uncomment to enable tls with a certificate - #- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt - #- REGISTRY_HTTP_TLS_KEY=/certs/domain.key - - # uncomment to enable tls with letsencrypt - #- REGISTRY_HTTP_TLS_LETSENCRYPT_CACHEFILE=/path/to/cache-file - #- REGISTRY_HTTP_TLS_LETSENCRYPT_EMAIL=mail@example.com + # uncomment to enable basic auth + #- REGISTRY_AUTH=htpasswd + #- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd + #- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm + + # uncomment to enable tls with a certificate + #- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt + #- REGISTRY_HTTP_TLS_KEY=/certs/domain.key + + # uncomment to enable tls with letsencrypt + #- REGISTRY_HTTP_TLS_LETSENCRYPT_CACHEFILE=/path/to/cache-file + #- REGISTRY_HTTP_TLS_LETSENCRYPT_EMAIL=mail@example.com #volumes: - # uncomment to enable basic auth - # you will need to generate a \`htpasswd\` file using : - # docker run --entrypoint htpasswd registry:2 -Bbn admin admin > ~/volumes/registry/htpasswd - #- ~/volumes/registry/htpasswd:/auth/htpasswd:ro + # uncomment to enable basic auth + # you will need to generate a \`htpasswd\` file using : + # docker run --entrypoint htpasswd registry:2 -Bbn admin admin > ~/volumes/registry/htpasswd + #- ~/volumes/registry/htpasswd:/auth/htpasswd:ro - # uncomment to enable tls - #- ~/volumes/registry/certs:/certs + # uncomment to enable tls + #- ~/volumes/registry/certs:/certs - # uncomment to persist data to a volume - #- ~/volumes/registry/data:/var/lib/registry + # uncomment to persist data to a volume + #- ~/volumes/registry/data:/var/lib/registry registry-ui: image: konradkleine/docker-registry-frontend:v2 environment: @@ -3016,6 +3075,7 @@ services: #- ENV_DOCKER_REGISTRY_USE_SSL=1 ports: - 5080:80 + ", "stateCleared": "modified", }, @@ -3029,11 +3089,11 @@ services: # uncomment for docker in docker #privileged: true #volumes: - # enable persistent volume (warning: make sure that the local jenkins_home folder is created) - #- ~/volumes/jenkins_home:/var/jenkins_home - # mount docker sock and binary for docker in docker (only works on linux) - #- /var/run/docker.sock:/var/run/docker.sock - #- /usr/bin/docker:/usr/bin/docker + # enable persistent volume (warning: make sure that the local jenkins_home folder is created) + #- ~/volumes/jenkins_home:/var/jenkins_home + # mount docker sock and binary for docker in docker (only works on linux) + #- /var/run/docker.sock:/var/run/docker.sock + #- /usr/bin/docker:/usr/bin/docker ", "stateCleared": "modified", }, @@ -3185,9 +3245,9 @@ script: notifications: webhooks: - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: false # default: false + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: false # default: false ", "stateCleared": "modified", }, @@ -3198,7 +3258,9 @@ notifications: "buildTool": "gradle", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -3259,9 +3321,9 @@ script: notifications: webhooks: - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: false # default: false + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: false # default: false ", "stateCleared": "modified", }, @@ -3272,7 +3334,9 @@ notifications: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", @@ -3339,9 +3403,9 @@ script: notifications: webhooks: - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: false # default: false + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: false # default: false ", "stateCleared": "modified", }, @@ -3352,7 +3416,9 @@ notifications: "buildTool": "maven", "creationTimestamp": 1577836800000, "entities": [], - "testFrameworks": ["cypress"] + "testFrameworks": [ + "cypress" + ] } } ", diff --git a/generators/ci-cd/ci-cd.spec.ts b/generators/ci-cd/ci-cd.spec.ts index e3fa7454ce36..6a4bf2390bde 100644 --- a/generators/ci-cd/ci-cd.spec.ts +++ b/generators/ci-cd/ci-cd.spec.ts @@ -1,6 +1,6 @@ -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { GENERATOR_CI_CD } from '../generator-list.js'; -import { dryRunHelpers as helpers } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; const expectedFiles = { travis: ['.travis.yml'], @@ -31,17 +31,15 @@ describe('generator - CI-CD', () => { //-------------------------------------------------- describe('Jenkins tests', () => { describe('Jenkins: Maven Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withAnswers({ ciCd: ['jenkins'], insideDocker: false, ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -57,17 +55,15 @@ describe('generator - CI-CD', () => { }); }); describe('Jenkins: Gradle Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(gradleSample) .withAnswers({ ciCd: ['jenkins'], insideDocker: false, ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -83,10 +79,9 @@ describe('generator - CI-CD', () => { }); }); describe('Jenkins: Maven Angular NPM with full options', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withFiles({ 'pom.xml': pomFile }) .withAnswers({ @@ -98,8 +93,7 @@ describe('generator - CI-CD', () => { artifactoryReleasesId: 'releases', artifactoryReleasesUrl: 'http://artifactory:8081/artifactory/libs-release', sonarName: 'sonarName', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -118,10 +112,9 @@ describe('generator - CI-CD', () => { }); }); describe('Jenkins: Maven Angular NPM inside Docker', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withFiles({ 'pom.xml': pomFile }) .withAnswers({ @@ -133,8 +126,7 @@ describe('generator - CI-CD', () => { artifactoryReleasesId: 'releases', artifactoryReleasesUrl: 'http://artifactory:8081/artifactory/libs-release', sonarName: 'sonarName', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -157,17 +149,15 @@ describe('generator - CI-CD', () => { //-------------------------------------------------- describe('GitLab CI tests', () => { describe('GitLab CI: Maven Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withAnswers({ ciCd: ['gitlab'], insideDocker: false, ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -183,16 +173,14 @@ describe('generator - CI-CD', () => { }); }); describe('GitLab CI: Gradle Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(gradleSample) .withAnswers({ ciCd: ['gitlab'], ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -208,17 +196,15 @@ describe('generator - CI-CD', () => { }); }); describe('GitLab CI: npm skip server', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(skipServerSample) .withAnswers({ ciCd: ['gitlab'], insideDocker: true, ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -231,10 +217,9 @@ describe('generator - CI-CD', () => { }); }); describe('GitLab CI: Maven Angular NPM with full options', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withFiles({ 'pom.xml': pomFile }) .withAnswers({ @@ -246,8 +231,7 @@ describe('generator - CI-CD', () => { artifactoryReleasesId: 'releases', artifactoryReleasesUrl: 'http://artifactory:8081/artifactory/libs-release', sonarUrl: 'http://localhost:9000', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -266,10 +250,9 @@ describe('generator - CI-CD', () => { }); }); describe('GitLab CI: Maven Angular NPM inside Docker', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withFiles({ 'pom.xml': pomFile }) .withAnswers({ @@ -281,8 +264,7 @@ describe('generator - CI-CD', () => { artifactoryReleasesId: 'releases', artifactoryReleasesUrl: 'http://artifactory:8081/artifactory/libs-release', sonarUrl: 'http://localhost:9000', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -301,16 +283,10 @@ describe('generator - CI-CD', () => { }); }); describe('GitLab CI: Maven Angular Yarn inside Docker Autoconfigure', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) - .withJHipsterConfig(mavenSample) - .withArguments(['gitlab']) - .withAnswers({ - insideDocker: true, - }) - .run(); + await helpers.runJHipster(GENERATOR_CI_CD).withJHipsterConfig(mavenSample).withArguments(['gitlab']).withAnswers({ + insideDocker: true, + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -332,16 +308,14 @@ describe('generator - CI-CD', () => { //-------------------------------------------------- describe('Travis CI tests', () => { describe('Travis CI: Maven Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withAnswers({ ciCd: ['travis'], ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -355,16 +329,14 @@ describe('generator - CI-CD', () => { }); }); describe('Travis CI: Gradle Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(gradleSample) .withAnswers({ ciCd: ['travis'], ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -382,10 +354,9 @@ describe('generator - CI-CD', () => { }); }); describe('Travis CI: Maven Angular NPM with full options', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withFiles({ 'pom.xml': pomFile }) .withAnswers({ @@ -396,8 +367,7 @@ describe('generator - CI-CD', () => { artifactoryReleasesId: 'releases', artifactoryReleasesUrl: 'http://artifactory:8081/artifactory/libs-release', sonarUrl: 'http://localhost:9000', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -425,16 +395,14 @@ describe('generator - CI-CD', () => { //-------------------------------------------------- describe('Azure Pipelines tests', () => { describe('Azure Pipelines: Maven Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withAnswers({ ciCd: ['azure'], ciCdIntegrations: ['cypressDashboard'], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -450,16 +418,14 @@ describe('generator - CI-CD', () => { }); }); describe('Azure Pipelines: Gradle Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(gradleSample) .withAnswers({ ciCd: ['azure'], ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -473,16 +439,14 @@ describe('generator - CI-CD', () => { }); }); describe('Azure Pipelines: Maven Angular NPM with Snyk', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withAnswers({ ciCd: ['azure'], ciCdIntegrations: ['snyk'], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -495,16 +459,14 @@ describe('generator - CI-CD', () => { }); }); describe('Azure Pipelines: Gradle Angular NPM with Snyk', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(gradleSample) .withAnswers({ ciCd: ['azure'], ciCdIntegrations: ['snyk'], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -517,9 +479,8 @@ describe('generator - CI-CD', () => { }); }); describe('Azure Pipelines: autoconfigure', () => { - let runResult; before(async () => { - runResult = await helpers.createJHipster(GENERATOR_CI_CD).withJHipsterConfig(mavenSample).withArguments(['azure']).run(); + await helpers.runJHipster(GENERATOR_CI_CD).withJHipsterConfig(mavenSample).withArguments(['azure']); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -535,16 +496,14 @@ describe('generator - CI-CD', () => { //-------------------------------------------------- describe('GitHub Actions tests', () => { describe('GitHub Actions: Maven Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withAnswers({ ciCd: ['github'], ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -554,16 +513,14 @@ describe('generator - CI-CD', () => { }); }); describe('GitHub Actions: Gradle Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(gradleSample) .withAnswers({ ciCd: ['github'], ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -573,10 +530,9 @@ describe('generator - CI-CD', () => { }); }); describe('GitHub Actions: Maven Angular NPM with full options', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withFiles({ 'pom.xml': pomFile }) .withAnswers({ @@ -588,8 +544,7 @@ describe('generator - CI-CD', () => { artifactoryReleasesId: 'releases', artifactoryReleasesUrl: 'http://artifactory:8081/artifactory/libs-release', sonarUrl: 'http://sonar.com:9000', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -614,18 +569,16 @@ describe('generator - CI-CD', () => { }); }); describe('GitHub Actions: Gradle Angular NPM with full options', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(gradleSample) .withAnswers({ ciCd: ['github'], ciCdIntegrations: ['sonar', 'publishDocker', 'heroku', 'snyk'], dockerImage: 'jhipster-publish-docker', sonarUrl: 'http://sonar.com:9000', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -647,9 +600,8 @@ describe('generator - CI-CD', () => { }); }); describe('GitHub Actions: autoconfigure', () => { - let runResult; before(async () => { - runResult = await helpers.createJHipster(GENERATOR_CI_CD).withJHipsterConfig(mavenSample).withArguments(['github']).run(); + await helpers.runJHipster(GENERATOR_CI_CD).withJHipsterConfig(mavenSample).withArguments(['github']); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -665,16 +617,14 @@ describe('generator - CI-CD', () => { //-------------------------------------------------- describe('Circle CI test', () => { describe('Circle CI: Maven Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withAnswers({ ciCd: ['circle'], ciCdIntegrations: ['cypressDashboard'], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -691,16 +641,14 @@ describe('generator - CI-CD', () => { }); }); describe('Circle CI: Gradle Angular NPM', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(gradleSample) .withAnswers({ ciCd: ['circle'], ciCdIntegrations: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -717,16 +665,14 @@ describe('generator - CI-CD', () => { }); }); describe('Circle CI: Maven with Snyk', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(mavenSample) .withAnswers({ ciCd: ['circle'], ciCdIntegrations: ['snyk'], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -739,16 +685,14 @@ describe('generator - CI-CD', () => { }); }); describe('Circle CI: Gradle with Snyk', () => { - let runResult; before(async () => { - runResult = await helpers - .createJHipster(GENERATOR_CI_CD) + await helpers + .runJHipster(GENERATOR_CI_CD) .withJHipsterConfig(gradleSample) .withAnswers({ ciCd: ['circle'], ciCdIntegrations: ['snyk'], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); diff --git a/generators/ci-cd/command.ts b/generators/ci-cd/command.ts index e8d94b563e34..dba7ccce0f6b 100644 --- a/generators/ci-cd/command.ts +++ b/generators/ci-cd/command.ts @@ -17,8 +17,8 @@ * limitations under the License. */ import chalk from 'chalk'; -import { kebabCase, intersection } from 'lodash-es'; -import type { JHipsterCommandDefinition } from '../base/api.js'; +import { intersection, kebabCase } from 'lodash-es'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; const includesValue = (prop, values) => answers => answers[prop] && intersection(answers[prop], values).length > 0; @@ -41,7 +41,7 @@ const command: JHipsterCommandDefinition = { { name: 'Travis CI', value: 'travis' }, { name: 'CircleCI', value: 'circle' }, ], - scope: 'generator', + scope: 'context', }, ciCdIntegrations: { prompt: { @@ -73,7 +73,7 @@ const command: JHipsterCommandDefinition = { value: 'cypressDashboard', }, ], - scope: 'generator', + scope: 'context', }, insideDocker: { prompt: { @@ -82,7 +82,7 @@ const command: JHipsterCommandDefinition = { message: 'Would you like to perform the build in a Docker container ?', default: false, }, - scope: 'generator', + scope: 'context', }, sendBuildToGitlab: { prompt: { @@ -91,7 +91,7 @@ const command: JHipsterCommandDefinition = { message: 'Would you like to send build status to GitLab ?', default: false, }, - scope: 'generator', + scope: 'context', }, artifactorySnapshotsId: { prompt: { @@ -100,7 +100,7 @@ const command: JHipsterCommandDefinition = { message: `${chalk.yellow('*Artifactory*')}: what is the ID of distributionManagement for snapshots ?`, }, default: 'snapshots', - scope: 'generator', + scope: 'context', }, artifactorySnapshotsUrl: { prompt: { @@ -109,7 +109,7 @@ const command: JHipsterCommandDefinition = { message: `${chalk.yellow('*Artifactory*')}: what is the URL of distributionManagement for snapshots ?`, }, default: 'http://artifactory:8081/artifactory/libs-snapshot', - scope: 'generator', + scope: 'context', }, artifactoryReleasesId: { prompt: { @@ -118,7 +118,7 @@ const command: JHipsterCommandDefinition = { message: `${chalk.yellow('*Artifactory*')}: what is the ID of distributionManagement for releases ?`, }, default: 'releases', - scope: 'generator', + scope: 'context', }, artifactoryReleasesUrl: { prompt: { @@ -127,7 +127,7 @@ const command: JHipsterCommandDefinition = { message: `${chalk.yellow('*Artifactory*')}: what is the URL of distributionManagement for releases ?`, }, default: 'http://artifactory:8081/artifactory/libs-release', - scope: 'generator', + scope: 'context', }, sonarName: { prompt: { @@ -136,7 +136,7 @@ const command: JHipsterCommandDefinition = { message: `${chalk.yellow('*Sonar*')}: what is the name of the Sonar server ?`, }, default: 'sonar', - scope: 'generator', + scope: 'context', }, sonarUrl: { prompt: { @@ -147,7 +147,7 @@ const command: JHipsterCommandDefinition = { message: `${chalk.yellow('*Sonar*')}: what is the URL of the Sonar server ?`, }, default: 'https://sonarcloud.io', - scope: 'generator', + scope: 'context', }, sonarOrga: { prompt: { @@ -157,7 +157,7 @@ const command: JHipsterCommandDefinition = { type: 'input', message: `${chalk.yellow('*Sonar*')}: what is the Organization of the Sonar server ?`, }, - scope: 'generator', + scope: 'context', }, dockerImage: { prompt: ({ jhipsterConfigWithDefaults: config }) => ({ @@ -166,7 +166,7 @@ const command: JHipsterCommandDefinition = { message: `${chalk.yellow('*Docker*')}: what is the name of the image ?`, default: () => `jhipster/${config.dasherizedBaseName}`, }), - scope: 'generator', + scope: 'context', }, herokuAppName: { prompt: { @@ -174,8 +174,10 @@ const command: JHipsterCommandDefinition = { type: 'input', message: `${chalk.yellow('*Heroku*')}: name of your Heroku Application ?`, }, - scope: 'generator', - default: gen => kebabCase(gen.jhipsterConfigWithDefaults.baseName), + scope: 'context', + default() { + return kebabCase(this.jhipsterConfigWithDefaults.baseName); + }, }, }, }; diff --git a/generators/ci-cd/generator.spec.ts b/generators/ci-cd/generator.spec.ts new file mode 100644 index 000000000000..52ead2bc7763 --- /dev/null +++ b/generators/ci-cd/generator.spec.ts @@ -0,0 +1,106 @@ +/** + * Copyright 2013-2024 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. + */ +import { basename, dirname } from 'path'; +import { fileURLToPath } from 'url'; +import { describe, expect, it } from 'esmocha'; +import { snakeCase } from 'lodash-es'; + +import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/helpers.js'; +import Generator from './index.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const generator = basename(__dirname); + +describe(`generator - ${generator}`, () => { + it('generator-list constant matches folder name', async () => { + await expect((await import('../generator-list.js'))[`GENERATOR_${snakeCase(generator).toUpperCase()}`]).toBe(generator); + }); + shouldSupportFeatures(Generator); + describe('blueprint support', () => testBlueprintSupport(generator)); + + describe('cli', () => { + describe('without ciCd values', () => { + before(async () => { + await helpers.runCli('ci-cd').withJHipsterConfig().withSkipWritingPriorities(); + }); + + it('should match prompts order', () => { + expect(runResult.askedQuestions.map(({ name }) => name)).toMatchInlineSnapshot(` +[ + "ciCd", + "ciCdIntegrations", +] +`); + }); + }); + + describe('with invalid ciCd value', () => { + it('should exit with error', async () => { + await expect( + helpers.runCli('ci-cd foo').withJHipsterConfig().withSkipWritingPriorities(), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"error: command-argument value 'foo' is invalid for argument 'ciCd'. Allowed choices are github, jenkins, gitlab, azure, travis, circle."`, + ); + }); + }); + + describe('with multiples values', () => { + before(async () => { + await helpers.runCli('ci-cd github jenkins gitlab azure').withJHipsterConfig().withSkipWritingPriorities(); + }); + + it('should populate context', () => { + expect(runResult.generator.context!.ciCd).toEqual(['github', 'jenkins', 'gitlab', 'azure']); + }); + }); + + describe('with github', () => { + before(async () => { + await helpers.runCli('ci-cd github').withJHipsterConfig().withSkipWritingPriorities(); + }); + + it('should not ask ciCd question', () => { + expect(runResult.askedQuestions.map(({ name }) => name)).toMatchInlineSnapshot(` +[ + "ciCdIntegrations", +] +`); + }); + }); + + describe('with jenkins', () => { + before(async () => { + await helpers.runCli('ci-cd jenkins').withJHipsterConfig().withSkipWritingPriorities(); + }); + + it('should not ask ciCd question', () => { + expect(runResult.askedQuestions.map(({ name }) => name)).toMatchInlineSnapshot(` +[ + "ciCdIntegrations", + "insideDocker", + "sendBuildToGitlab", +] +`); + }); + }); + }); +}); diff --git a/generators/ci-cd/generator.js b/generators/ci-cd/generator.ts similarity index 77% rename from generators/ci-cd/generator.js rename to generators/ci-cd/generator.ts index b726a9ea7d13..944e38fd21ab 100644 --- a/generators/ci-cd/generator.js +++ b/generators/ci-cd/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,11 +17,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return */ + import chalk from 'chalk'; import BaseApplicationGenerator from '../base-application/index.js'; -import { clientFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { clientFrameworkTypes } from '../../lib/jhipster/index.js'; import { createPomStorage } from '../maven/support/pom-store.js'; import { loadConfig, loadDerivedConfig } from '../../lib/internal/config-def.js'; import command from './command.js'; @@ -29,6 +30,7 @@ const { REACT } = clientFrameworkTypes; export default class CiCdGenerator extends BaseApplicationGenerator { insideDocker; + context = {}; async beforeQueue() { if (!this.fromBlueprint) { @@ -55,11 +57,11 @@ export default class CiCdGenerator extends BaseApplicationGenerator { // Public API method used by the getter and also by Blueprints get loading() { - return { - loadSharedConfig({ application }) { - loadConfig.call(this, command.configs, { application }); + return this.asLoadingTaskGroup({ + loadSharedConfig() { + loadConfig.call(this, command.configs, { application: this.context }); }, - }; + }); } get [BaseApplicationGenerator.LOADING]() { @@ -68,19 +70,19 @@ export default class CiCdGenerator extends BaseApplicationGenerator { get preparing() { return this.asPreparingTaskGroup({ - setTemplateConstants({ application }) { - loadDerivedConfig(command.configs, { application }); + setTemplateConstants() { + loadDerivedConfig(command.configs, { application: this.context }); - if (application.ciCdIntegrations === undefined) { - application.ciCdIntegrations = []; + if (this.context.ciCdIntegrations === undefined) { + this.context.ciCdIntegrations = []; } - application.gitLabIndent = application.sendBuildToGitlab ? ' ' : ''; - application.indent = application.insideDocker ? ' ' : ''; - application.indent += application.gitLabIndent; - if (application.clientFramework === REACT) { - application.frontTestCommand = 'test-ci'; + this.context.gitLabIndent = this.context.sendBuildToGitlab ? ' ' : ''; + this.context.indent = this.context.insideDocker ? ' ' : ''; + this.context.indent += this.context.gitLabIndent; + if (this.context.clientFramework === REACT) { + this.context.frontTestCommand = 'test-ci'; } else { - application.frontTestCommand = 'test'; + this.context.frontTestCommand = 'test'; } }, }); @@ -90,6 +92,18 @@ export default class CiCdGenerator extends BaseApplicationGenerator { return this.delegateTasksToBlueprint(() => this.preparing); } + get default() { + return this.asDefaultTaskGroup({ + loadContext({ application }) { + Object.assign(application, this.context); + }, + }); + } + + get [BaseApplicationGenerator.DEFAULT]() { + return this.delegateTasksToBlueprint(() => this.default); + } + // Public API method used by the getter and also by Blueprints get writing() { return this.asWritingTaskGroup({ @@ -105,11 +119,11 @@ export default class CiCdGenerator extends BaseApplicationGenerator { }, { sourceFile: 'jenkins/jenkins.yml', - destinationFile: `${application.dockerServicesDir}jenkins.yml`, + destinationFile: ctx => `${ctx.dockerServicesDir}jenkins.yml`, }, { sourceFile: 'jenkins/idea.gdsl', - destinationFile: `${application.srcMainResources}idea.gdsl`, + destinationFile: ctx => `${ctx.srcMainResources}idea.gdsl`, }, ], }, @@ -137,7 +151,7 @@ export default class CiCdGenerator extends BaseApplicationGenerator { context: application, }); - if (application.ciCdIntegrations.includes('publishDocker')) { + if (application.ciCdIntegrations?.includes('publishDocker')) { this.writeFile('docker-registry.yml.ejs', `${application.dockerServicesDir}docker-registry.yml`); } }, @@ -152,7 +166,7 @@ export default class CiCdGenerator extends BaseApplicationGenerator { get postWriting() { return this.asPostWritingTaskGroup({ postWriting({ application }) { - if (application.ciCdIntegrations.includes('deploy')) { + if (application.ciCdIntegrations?.includes('deploy')) { if (application.buildToolMaven) { createPomStorage(this, { sortFile: false }).addDistributionManagement({ releasesId: application.artifactoryReleasesId, diff --git a/generators/client/command.ts b/generators/client/command.ts index f095f386a282..e64ec89440f2 100644 --- a/generators/client/command.ts +++ b/generators/client/command.ts @@ -18,9 +18,13 @@ */ import chalk from 'chalk'; import { intersection } from 'lodash-es'; -import { testFrameworkTypes } from '../../jdl/jhipster/index.js'; -import { JHipsterCommandDefinition } from '../base/api.js'; -import { APPLICATION_TYPE_GATEWAY, APPLICATION_TYPE_MICROSERVICE, clientFrameworkTypes } from '../../jdl/index.js'; +import { + APPLICATION_TYPE_GATEWAY, + APPLICATION_TYPE_MICROSERVICE, + clientFrameworkTypes, + testFrameworkTypes, +} from '../../lib/jhipster/index.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_COMMON } from '../generator-list.js'; const { CYPRESS } = testFrameworkTypes; @@ -36,7 +40,7 @@ const promptValueToMicrofrontends = answer => .map(baseName => ({ baseName })) : []; -const command: JHipsterCommandDefinition = { +const command = { options: {}, configs: { clientFramework: { @@ -57,6 +61,29 @@ const command: JHipsterCommandDefinition = { { value: VUE, name: 'Vue' }, { value: CLIENT_FRAMEWORK_NO, name: 'No client' }, ], + scope: 'storage', + }, + clientTheme: { + cli: { + type: String, + hide: true, + }, + scope: 'storage', + }, + clientThemeVariant: { + cli: { + type: String, + hide: true, + }, + scope: 'storage', + }, + clientBundler: { + cli: { + type: String, + hide: true, + }, + choices: ['webpack', 'vite'], + scope: 'storage', }, microfrontend: { description: 'Enable microfrontend support', @@ -71,11 +98,12 @@ const command: JHipsterCommandDefinition = { message: `Do you want to enable ${chalk.yellow('*microfrontends*')}?`, default: false, }), + scope: 'storage', }, microfrontends: { description: 'Microfrontends to load', cli: { - type: String, + type: (val: string) => promptValueToMicrofrontends(val), }, prompt: ({ jhipsterConfigWithDefaults: config }) => ({ when: answers => { @@ -95,9 +123,14 @@ const command: JHipsterCommandDefinition = { filter: promptValueToMicrofrontends, transformer: microfrontendsToPromptValue, }), + scope: 'storage', }, clientTestFrameworks: { description: 'Client test frameworks', + cli: { + type: Array, + hide: true, + }, prompt: ({ jhipsterConfigWithDefaults: config }) => ({ when: answers => [ANGULAR, REACT, VUE].includes(answers.clientFramework ?? config.clientFramework), type: 'checkbox', @@ -105,6 +138,7 @@ const command: JHipsterCommandDefinition = { default: () => intersection([CYPRESS], config.testFrameworks), }), choices: [{ name: 'Cypress', value: CYPRESS }], + scope: 'storage', }, withAdminUi: { description: 'Generate administrative user interface', @@ -116,15 +150,17 @@ const command: JHipsterCommandDefinition = { when: answers => [ANGULAR, REACT, VUE].includes(answers.clientFramework ?? config.clientFramework), message: 'Do you want to generate the admin UI?', }), + scope: 'storage', }, clientRootDir: { description: 'Client root', cli: { type: String, }, + scope: 'storage', }, }, import: [GENERATOR_COMMON], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/client/entity-files.js b/generators/client/entity-files.ts similarity index 91% rename from generators/client/entity-files.js rename to generators/client/entity-files.ts index 9f5090d4803b..2c414dba2005 100644 --- a/generators/client/entity-files.js +++ b/generators/client/entity-files.ts @@ -18,8 +18,9 @@ */ import { CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; import { getEnumInfo } from '../base-application/support/index.js'; +import type CoreGenerator from '../base-core/generator.js'; -export async function addEnumerationFiles({ application, entity }) { +export async function addEnumerationFiles(this: CoreGenerator, { application, entity }) { for (const field of entity.fields) { if (field.fieldIsEnum === true) { const { enumFileName } = field; diff --git a/generators/client/files-common.js b/generators/client/files-common.ts similarity index 86% rename from generators/client/files-common.js rename to generators/client/files-common.ts index c11c3840d31d..f27e23e2d8db 100644 --- a/generators/client/files-common.js +++ b/generators/client/files-common.ts @@ -16,22 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { clientFrameworkTypes } from '../../jdl/index.js'; +import { asWritingTask } from '../base-application/support/task-type-inference.js'; import { clientRootTemplatesBlock, clientSrcTemplatesBlock } from './support/files.js'; -const { ANGULAR, REACT, VUE } = clientFrameworkTypes; - export const files = { common: [ { templates: ['README.md.jhi.client', '.prettierignore.jhi.client'], }, clientRootTemplatesBlock({ - condition: ctx => !ctx.clientFrameworkReact, - templates: ['.eslintignore'], - }), - clientRootTemplatesBlock({ - condition: generator => generator.microfrontend && (generator.clientFrameworkVue || generator.clientFrameworkReact), + condition: generator => + generator.microfrontend && generator.clientBundlerWebpack && (generator.clientFrameworkVue || generator.clientFrameworkReact), templates: ['webpack/webpack.microfrontend.js.jhi'], }), { @@ -81,8 +76,8 @@ export const files = { ], }; -export async function writeFiles({ application }) { - if (![ANGULAR, REACT, VUE].includes(application.clientFramework)) { +export const writeFiles = asWritingTask(async function writeFiles({ application }) { + if (!application.clientFrameworkBuiltIn) { return; } @@ -90,4 +85,4 @@ export async function writeFiles({ application }) { sections: files, context: application, }); -} +}); diff --git a/generators/client/generator-needles.spec.ts b/generators/client/generator-needles.spec.ts index d611620abb2c..7841de1d2dd5 100644 --- a/generators/client/generator-needles.spec.ts +++ b/generators/client/generator-needles.spec.ts @@ -1,12 +1,11 @@ -import { before, it, describe } from 'esmocha'; -import { basicHelpers as helpers, result as runResult, getGenerator } from '../../testing/index.js'; +import { before, describe, it } from 'esmocha'; +import { dryRunHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import { CLIENT_WEBPACK_DIR } from '../generator-constants.js'; -import { clientFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { clientFrameworkTypes } from '../../lib/jhipster/index.js'; import ClientGenerator from './index.js'; const { ANGULAR, REACT } = clientFrameworkTypes; -// eslint-disable-next-line @typescript-eslint/no-explicit-any const mockBlueprintSubGen: any = class extends ClientGenerator { constructor(args, opts, features) { super(args, opts, { ...features, sbsBlueprint: true }); @@ -15,7 +14,7 @@ const mockBlueprintSubGen: any = class extends ClientGenerator { get [ClientGenerator.POST_WRITING]() { return this.asPostWritingTaskGroup({ webpackPhase({ source }) { - source!.addWebpackConfig!({ config: '{devServer:{}}' }); + source.addWebpackConfig!({ config: '{devServer:{}}' }); }, }); } @@ -24,9 +23,9 @@ const mockBlueprintSubGen: any = class extends ClientGenerator { describe('needle API Webpack: JHipster client generator with blueprint', () => { function generateAppWithClientFramework(clientFramework) { return helpers - .create(getGenerator('client')) + .runJHipster('client') .withOptions({ - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }) .withJHipsterConfig({ buildTool: 'maven', @@ -39,8 +38,7 @@ describe('needle API Webpack: JHipster client generator with blueprint', () => { nativeLanguage: 'en', languages: ['en', 'fr'], }) - .withGenerators([[mockBlueprintSubGen, { namespace: 'jhipster-myblueprint:client' }]]) - .run(); + .withGenerators([[mockBlueprintSubGen, { namespace: 'jhipster-myblueprint:client' }]]); } describe('Angular clientFramework', () => { diff --git a/generators/client/generator.spec.ts b/generators/client/generator.spec.ts index 2855902ac727..a6ae9c0ad8f7 100644 --- a/generators/client/generator.spec.ts +++ b/generators/client/generator.spec.ts @@ -16,14 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import assert from 'assert'; import { snakeCase } from 'lodash-es'; -import { before, it, describe, expect } from 'esmocha'; -import { shouldSupportFeatures, testBlueprintSupport, checkEnforcements } from '../../test/support/index.js'; -import { defaultHelpers as helpers, result } from '../../testing/index.js'; -import { testFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { before, describe, expect, it } from 'esmocha'; +import { checkEnforcements, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/index.js'; +import { defaultHelpers as helpers, result, runResult } from '../../lib/testing/index.js'; +import { testFrameworkTypes } from '../../lib/jhipster/index.js'; import { GENERATOR_CLIENT } from '../generator-list.js'; import Generator from './index.js'; @@ -33,7 +32,6 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorFile = join(__dirname, 'index.js'); describe(`generator - ${generator}`, () => { it('generator-list constant matches folder name', async () => { @@ -47,11 +45,10 @@ describe(`generator - ${generator}`, () => { const mockedComposedGenerators = ['jhipster:common', 'jhipster:languages', 'jhipster:cypress']; describe('with translation disabled', () => { - let runResult; const options = { enableTranslation: false }; before(async () => { - runResult = await helpers - .run(generatorFile) + await helpers + .runJHipster(generator) .withControl({ getWebappTranslation: () => 'translations' }) .withJHipsterConfig(options) .withSkipWritingPriorities() @@ -59,19 +56,18 @@ describe(`generator - ${generator}`, () => { }); it('should compose with jhipster:common', () => { - assert(runResult.mockedGenerators['jhipster:common'].calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:common'); }); it('should compose with jhipster:languages', () => { - assert.equal(runResult.mockedGenerators['jhipster:languages'].callCount, 1); + runResult.assertGeneratorComposedOnce('jhipster:languages'); }); }); describe('with translation enabled', () => { - let runResult; const options = { enableTranslation: true }; before(async () => { - runResult = await helpers - .run(generatorFile) + await helpers + .runJHipster(generator) .withControl({ getWebappTranslation: () => 'translations' }) .withJHipsterConfig(options) .withSkipWritingPriorities() @@ -79,19 +75,18 @@ describe(`generator - ${generator}`, () => { }); it('should compose with jhipster:common', () => { - assert(runResult.mockedGenerators['jhipster:common'].calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:common'); }); it('should compose with jhipster:languages', () => { - assert.equal(runResult.mockedGenerators['jhipster:languages'].callCount, 1); + runResult.assertGeneratorComposedOnce('jhipster:languages'); }); }); describe('without cypress', () => { - let runResult; const options = { testFrameworks: [] }; before(async () => { - runResult = await helpers - .run(generatorFile) + await helpers + .runJHipster(generator) .withControl({ getWebappTranslation: () => 'translations' }) .withJHipsterConfig(options) .withSkipWritingPriorities() @@ -99,22 +94,21 @@ describe(`generator - ${generator}`, () => { }); it('should compose with jhipster:common', () => { - assert(runResult.mockedGenerators['jhipster:common'].calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:common'); }); it('should compose with jhipster:languages', () => { - assert(runResult.mockedGenerators['jhipster:languages'].calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:languages'); }); it('should not compose with jhipster:cypress', () => { - assert.equal(runResult.mockedGenerators['jhipster:cypress'].callCount, 0); + runResult.assertGeneratorNotComposed('jhipster:cypress'); }); }); describe('with cypress', () => { - let runResult; const options = { testFrameworks: [CYPRESS] }; before(async () => { - runResult = await helpers - .run(generatorFile) + await helpers + .runJHipster(generator) .withControl({ getWebappTranslation: () => 'translations' }) .withJHipsterConfig(options) .withSkipWritingPriorities() @@ -122,13 +116,13 @@ describe(`generator - ${generator}`, () => { }); it('should compose with jhipster:common', () => { - assert(runResult.mockedGenerators['jhipster:common'].calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:common'); }); it('should compose with jhipster:languages', () => { - assert(runResult.mockedGenerators['jhipster:languages'].calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:languages'); }); it('should compose with jhipster:cypress', () => { - assert(runResult.mockedGenerators['jhipster:cypress'].calledOnce); + runResult.assertGeneratorComposedOnce('jhipster:cypress'); }); }); }); @@ -142,33 +136,32 @@ describe(`generator - ${generator}`, () => { 'jhipster:react', 'jhipster:vue', ]; - const options = { applicationType: 'microservice' }; before(async () => { await helpers - .run(generatorFile) + .runJHipster(generator) .withControl({ getWebappTranslation: () => 'translations' }) - .withJHipsterConfig(options) + .withJHipsterConfig({ applicationType: 'microservice' }) .withSkipWritingPriorities() .withMockedGenerators(mockedComposedGenerators); }); it('should compose with jhipster:common', () => { - assert(result.mockedGenerators['jhipster:common'].calledOnce); + result.assertGeneratorComposedOnce('jhipster:common'); }); it('should compose with jhipster:languages', () => { - assert(result.mockedGenerators['jhipster:languages'].notCalled); + result.assertGeneratorNotComposed('jhipster:languages'); }); it('should compose with jhipster:cypress', () => { - assert(result.mockedGenerators['jhipster:cypress'].notCalled); + result.assertGeneratorNotComposed('jhipster:cypress'); }); it('should compose with jhipster:angular', () => { - assert(result.mockedGenerators['jhipster:angular'].notCalled); + result.assertGeneratorNotComposed('jhipster:angular'); }); it('should compose with jhipster:react', () => { - assert(result.mockedGenerators['jhipster:react'].notCalled); + result.assertGeneratorNotComposed('jhipster:react'); }); it('should compose with jhipster:vue', () => { - assert(result.mockedGenerators['jhipster:vue'].notCalled); + result.assertGeneratorNotComposed('jhipster:vue'); }); }); }); diff --git a/generators/client/generator.js b/generators/client/generator.ts similarity index 89% rename from generators/client/generator.js rename to generators/client/generator.ts index b368ce829759..87dec9e9c4b9 100644 --- a/generators/client/generator.js +++ b/generators/client/generator.ts @@ -20,16 +20,16 @@ import BaseApplicationGenerator from '../base-application/index.js'; import { LOGIN_REGEX_JS } from '../generator-constants.js'; -import { GENERATOR_CYPRESS, GENERATOR_COMMON, GENERATOR_CLIENT } from '../generator-list.js'; +import { GENERATOR_CLIENT, GENERATOR_COMMON, GENERATOR_CYPRESS } from '../generator-list.js'; -import { testFrameworkTypes, clientFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { clientFrameworkTypes, testFrameworkTypes } from '../../lib/jhipster/index.js'; import { createNeedleCallback } from '../base/support/index.js'; import { loadStoredAppOptions } from '../app/support/index.js'; import { addEnumerationFiles } from './entity-files.js'; import { writeFiles as writeCommonFiles } from './files-common.js'; import { askForClientTheme, askForClientThemeVariant } from './prompts.js'; -const { ANGULAR, VUE, REACT, NO: CLIENT_FRAMEWORK_NO } = clientFrameworkTypes; +const { ANGULAR, NO: CLIENT_FRAMEWORK_NO } = clientFrameworkTypes; const { CYPRESS } = testFrameworkTypes; export default class JHipsterClientGenerator extends BaseApplicationGenerator { @@ -76,6 +76,7 @@ export default class JHipsterClientGenerator extends BaseApplicationGenerator { } }, upgradeAngular() { + // @ts-ignore deprecated value if (this.jhipsterConfig.clientFramework === 'angularX') { this.jhipsterConfig.clientFramework = ANGULAR; } @@ -107,8 +108,8 @@ export default class JHipsterClientGenerator extends BaseApplicationGenerator { return this.asComposingTaskGroup({ async composing() { const { clientFramework, testFrameworks } = this.jhipsterConfigWithDefaults; - if ([ANGULAR, VUE, REACT].includes(clientFramework)) { - await this.composeWithJHipster(clientFramework); + if (['angular', 'react', 'vue'].includes(clientFramework!)) { + await this.composeWithJHipster(clientFramework!); } if (Array.isArray(testFrameworks) && testFrameworks.includes(CYPRESS)) { await this.composeWithJHipster(GENERATOR_CYPRESS); @@ -125,7 +126,7 @@ export default class JHipsterClientGenerator extends BaseApplicationGenerator { return this.asLoadingTaskGroup({ loadSharedConfig({ application }) { // TODO v8 rename to nodePackageManager; - application.clientPackageManager = 'npm'; + (application as any).clientPackageManager = 'npm'; }, loadPackageJson({ application }) { @@ -156,7 +157,7 @@ export default class JHipsterClientGenerator extends BaseApplicationGenerator { }, addExternalResource({ application, source }) { - if (![ANGULAR, VUE, REACT].includes(application.clientFramework)) { + if (!application.clientFrameworkBuiltIn) { return; } source.addExternalResourceToRoot = ({ resource, comment }) => @@ -206,7 +207,7 @@ export default class JHipsterClientGenerator extends BaseApplicationGenerator { get writingEntities() { return this.asWritingEntitiesTaskGroup({ async writeEnumerationFiles({ control, application, entities }) { - if (!application.webappEnumerationsDir || ![ANGULAR, VUE, REACT].includes(application.clientFramework)) { + if (!application.webappEnumerationsDir || !application.clientFrameworkBuiltIn) { return; } for (const entity of (control.filterEntitiesAndPropertiesForClient ?? (entities => entities))(entities)) { @@ -223,10 +224,10 @@ export default class JHipsterClientGenerator extends BaseApplicationGenerator { get postWriting() { return this.asPostWritingTaskGroup({ packageJsonScripts({ application }) { - if (![ANGULAR, VUE, REACT].includes(application.clientFramework)) { + if (!application.clientFrameworkBuiltIn) { return; } - const packageJsonStorage = this.createStorage(this.destinationPath(application.clientRootDir, 'package.json')); + const packageJsonStorage = this.createStorage(this.destinationPath(application.clientRootDir!, 'package.json')); const scriptsStorage = packageJsonStorage.createStorage('scripts'); const devDependencies = packageJsonStorage.createStorage('devDependencies'); @@ -242,16 +243,16 @@ export default class JHipsterClientGenerator extends BaseApplicationGenerator { }, microfrontend({ application, source }) { - if (!application.microfrontend || ![ANGULAR, VUE, REACT].includes(application.clientFramework)) { + if (!application.microfrontend || !application.clientFrameworkBuiltIn || !application.clientBundlerWebpack) { return; } if (application.clientFrameworkAngular) { const conditional = application.applicationTypeMicroservice ? "targetOptions.target === 'serve' ? {} : " : ''; - source.addWebpackConfig({ + source.addWebpackConfig!({ config: `${conditional}require('./webpack.microfrontend')(config, options, targetOptions)`, }); } else if (application.clientFrameworkVue || application.clientFrameworkReact) { - source.addWebpackConfig({ config: "require('./webpack.microfrontend')({ serve: options.env.WEBPACK_SERVE })" }); + source.addWebpackConfig!({ config: "require('./webpack.microfrontend')({ serve: options.env.WEBPACK_SERVE })" }); } else { throw new Error(`Client framework ${application.clientFramework} doesn't support microfrontends`); } diff --git a/generators/client/generators/common/command.ts b/generators/client/generators/common/command.ts index 7d3ac0741f15..4afecbf25013 100644 --- a/generators/client/generators/common/command.ts +++ b/generators/client/generators/common/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; const command: JHipsterCommandDefinition = { configs: {}, diff --git a/generators/client/generators/common/generator.spec.ts b/generators/client/generators/common/generator.spec.ts index 56dfe4af5064..b88a3325f9e3 100644 --- a/generators/client/generators/common/generator.spec.ts +++ b/generators/client/generators/common/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -47,7 +47,12 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot('[]'); + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` +[ + "jhipster:bootstrap", + "jhipster:project-name", +] +`); }); }); }); diff --git a/generators/client/generators/common/templates/src/main/webapp/app/shared/jhipster/headers.ts.ejs b/generators/client/generators/common/templates/src/main/webapp/app/shared/jhipster/headers.ts.ejs index 046d6ce4d691..e79957332cf7 100644 --- a/generators/client/generators/common/templates/src/main/webapp/app/shared/jhipster/headers.ts.ejs +++ b/generators/client/generators/common/templates/src/main/webapp/app/shared/jhipster/headers.ts.ejs @@ -36,7 +36,7 @@ const headerToString = (headerValue: any): string => { throw new Error('Header value is not a string'); } return headerValue; -} +}; const decodeHeaderValue = (headerValue: string): string => decodeURIComponent(headerValue.replace(/\+/g, ' ')); diff --git a/generators/client/generators/common/templates/src/main/webapp/app/shared/jhipster/problem-details.ts.ejs b/generators/client/generators/common/templates/src/main/webapp/app/shared/jhipster/problem-details.ts.ejs index 89953b4c6d1a..6341e9a2cd75 100644 --- a/generators/client/generators/common/templates/src/main/webapp/app/shared/jhipster/problem-details.ts.ejs +++ b/generators/client/generators/common/templates/src/main/webapp/app/shared/jhipster/problem-details.ts.ejs @@ -31,7 +31,7 @@ export type ProblemDetails = { detail: string; /** A URI reference that identifies the specific occurrence of the problem */ instance: string; -} +}; export const ProblemWithMessageType = 'https://www.jhipster.tech/problem/problem-with-message'; diff --git a/generators/client/index.ts b/generators/client/index.ts index f402370e7808..8044359653d7 100644 --- a/generators/client/index.ts +++ b/generators/client/index.ts @@ -16,12 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { GeneratorDefinition } from '../base-application/generator.js'; - export { default } from './generator.js'; export { default as command } from './command.js'; export { files as commonFiles } from './files-common.js'; - -export type SourceType = { - addEntitiesToClient: (arg1: GeneratorDefinition['postWritingEntitiesTaskParam']) => void; -}; diff --git a/generators/client/needle-api/needle-client-vue.ts b/generators/client/needle-api/needle-client-vue.ts index 723bb73d146d..b05c9c9afe66 100644 --- a/generators/client/needle-api/needle-client-vue.ts +++ b/generators/client/needle-api/needle-client-vue.ts @@ -57,7 +57,7 @@ export default class extends needleClientBase { ); } - addEntityToRouterImport(entityName: string, fileName: string, folderName: string, readOnly: string) { + addEntityToRouterImport(entityName: string, fileName: string, folderName: string, readOnly?: string) { const ignoreNonExisting = this.generator.sharedData.getControl().ignoreNeedlesError && `${chalk.yellow('Reference to entity ') + entityName} ${chalk.yellow('not added to router entities import.\n')}`; @@ -97,7 +97,7 @@ export default class extends needleClientBase { ); } - addEntityToRouter(entityInstance: string, entityName: string, entityFileName: string, readOnly: boolean) { + addEntityToRouter(entityInstance: string, entityName: string, entityFileName: string, readOnly?: boolean) { const ignoreNonExisting = this.generator.sharedData.getControl().ignoreNeedlesError && `${chalk.yellow('Reference to entity ') + entityName} ${chalk.yellow('not added to router entities.\n')}`; diff --git a/generators/client/needle-api/needle-client.ts b/generators/client/needle-api/needle-client.ts index 3a21525c9ae6..189053ab3a17 100644 --- a/generators/client/needle-api/needle-client.ts +++ b/generators/client/needle-api/needle-client.ts @@ -19,7 +19,7 @@ import needleBase from '../../needle-base.js'; export default class extends needleBase { - addStyle(style: string, comment: string, filePath: string, needle: string) { + addStyle(style: string, comment: string | undefined, filePath: string, needle: string) { const content = this._mergeStyleAndComment(style, comment); this.addBlockContentToFile( @@ -28,7 +28,7 @@ export default class extends needleBase { ); } - _mergeStyleAndComment(style: string, comment: string) { + _mergeStyleAndComment(style: string, comment?: string) { let styleBlock = ''; if (comment) { diff --git a/generators/client/needle-client.spec.ts b/generators/client/needle-client.spec.ts index a5cb07295786..8263dcb58867 100644 --- a/generators/client/needle-client.spec.ts +++ b/generators/client/needle-client.spec.ts @@ -1,9 +1,8 @@ -import { before, it, describe } from 'esmocha'; +import { before, describe, it } from 'esmocha'; import ClientGenerator from '../../generators/client/index.js'; import { CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; -import { dryRunHelpers as helpers, result as runResult, getGenerator } from '../../testing/index.js'; +import { dryRunHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any const mockBlueprintSubGen: any = class extends ClientGenerator { constructor(args, opts, features) { super(args, opts, features); @@ -19,7 +18,7 @@ const mockBlueprintSubGen: any = class extends ClientGenerator { return this.asPostWritingTaskGroup({ // @ts-ignore async additionalResource({ source }) { - source!.addExternalResourceToRoot!({ + source.addExternalResourceToRoot!({ resource: '', comment: 'Comment added by JHipster API', }); @@ -31,12 +30,12 @@ const mockBlueprintSubGen: any = class extends ClientGenerator { describe('needle API Client: JHipster client generator with blueprint', () => { before(async () => { await helpers - .run(getGenerator('client')) + .runJHipster('client') .withJHipsterConfig({ skipServer: true, }) .withOptions({ - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }) .withGenerators([[mockBlueprintSubGen, { namespace: 'jhipster-myblueprint:client' }]]); }); diff --git a/generators/client/prompts.spec.ts b/generators/client/prompts.spec.ts index 613a908d7e15..6e7554335e6a 100644 --- a/generators/client/prompts.spec.ts +++ b/generators/client/prompts.spec.ts @@ -1,14 +1,14 @@ -import { before, it, describe } from 'esmocha'; -import { defaultHelpers as helpers } from '../../testing/index.js'; +import { before, describe, it } from 'esmocha'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { applicationTypes, - databaseTypes, - cacheTypes, authenticationTypes, - testFrameworkTypes, - clientFrameworkTypes, buildToolTypes, -} from '../../jdl/jhipster/index.js'; + cacheTypes, + clientFrameworkTypes, + databaseTypes, + testFrameworkTypes, +} from '../../lib/jhipster/index.js'; import { GENERATOR_APP } from '../generator-list.js'; const { MONOLITH } = applicationTypes; @@ -24,9 +24,8 @@ const mockedComposedGenerators = ['jhipster:common', 'jhipster:server', 'jhipste describe('generator - client - prompts', () => { describe('clientTestFrameworks prompt', () => { describe('with cypress value', () => { - let runResult; before(async () => { - runResult = await helpers + await helpers .runJHipster(GENERATOR_APP) .withControl({ getWebappTranslation: () => 'translations' }) .withAnswers({ diff --git a/generators/client/prompts.js b/generators/client/prompts.ts similarity index 77% rename from generators/client/prompts.js rename to generators/client/prompts.ts index 61a78684220e..ec8e7bf5aeca 100644 --- a/generators/client/prompts.js +++ b/generators/client/prompts.ts @@ -16,22 +16,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { asPromptingTask } from '../base-application/support/task-type-inference.js'; import { httpsGet } from '../base/support/index.js'; -export async function askForClientTheme({ control }) { +type Choice = { value: string; name: string }; + +export const askForClientTheme = asPromptingTask(async function askForClientTheme({ control }) { if (control.existingProject && !this.options.askAnswered) return; const config = this.jhipsterConfigWithDefaults; + const { clientFramework } = config; + await this.prompt( { type: 'list', name: 'clientTheme', - when: () => ['angular', 'react', 'vue'].includes(config.clientFramework), + when: () => ['angular', 'react', 'vue'].includes(clientFramework!), message: 'Would you like to use a Bootswatch theme (https://bootswatch.com/)?', choices: async () => { - const bootswatchChoices = await retrieveOnlineBootswatchThemes(this).catch(errorMessage => { + const bootswatchChoices = await retrieveOnlineBootswatchThemes({ clientFramework }).catch(errorMessage => { this.log.warn(errorMessage); - return retrieveLocalBootswatchThemes(); + return retrieveLocalBootswatchThemes({ clientFramework }); }); return [ { @@ -45,9 +50,9 @@ export async function askForClientTheme({ control }) { }, this.config, ); -} +}); -export async function askForClientThemeVariant({ control }) { +export const askForClientThemeVariant = asPromptingTask(async function askForClientThemeVariant({ control }) { if (control.existingProject && !this.options.askAnswered) return; if ((this.jhipsterConfig.clientTheme ?? 'none') === 'none') { return; @@ -69,17 +74,17 @@ export async function askForClientThemeVariant({ control }) { }, this.config, ); -} +}); -async function retrieveOnlineBootswatchThemes(generator) { - return _retrieveBootswatchThemes(generator, true); +async function retrieveOnlineBootswatchThemes({ clientFramework }): Promise { + return _retrieveBootswatchThemes({ clientFramework, useApi: true }); } -async function retrieveLocalBootswatchThemes(generator) { - return _retrieveBootswatchThemes(generator, false); +async function retrieveLocalBootswatchThemes({ clientFramework }): Promise { + return _retrieveBootswatchThemes({ clientFramework, useApi: false }); } -async function _retrieveBootswatchThemes(generator, useApi) { +async function _retrieveBootswatchThemes({ clientFramework, useApi }): Promise { const errorMessage = 'Could not fetch bootswatch themes from API. Using default ones.'; if (!useApi) { return [ @@ -113,7 +118,7 @@ async function _retrieveBootswatchThemes(generator, useApi) { return new Promise((resolve, reject) => { httpsGet( - 'https://bootswatch.com/api/5.json', + `https://bootswatch.com/api/${clientFramework === 'vue' ? '4' : '5'}.json`, body => { try { @@ -125,7 +130,7 @@ async function _retrieveBootswatchThemes(generator, useApi) { })); resolve(bootswatchChoices); - } catch (err) { + } catch { reject(errorMessage); } }, diff --git a/generators/client/resources/package.json b/generators/client/resources/package.json index 881a135b0b70..473ae467f80a 100644 --- a/generators/client/resources/package.json +++ b/generators/client/resources/package.json @@ -1,16 +1,16 @@ { "dependencies": { - "dayjs": "1.11.11" + "dayjs": "1.11.13" }, "devDependencies": { - "@cypress/code-coverage": "3.12.42", - "babel-loader": "9.1.3", + "@cypress/code-coverage": "3.13.5", + "babel-loader": "9.2.1", "babel-plugin-istanbul": "7.0.0", - "cypress": "13.13.1", + "cypress": "13.15.1", "cypress-audit": "1.1.0", - "eslint-plugin-cypress": "3.3.0", - "lighthouse": "12.1.0", - "nyc": "17.0.0", + "eslint-plugin-cypress": "4.0.0", + "lighthouse": "12.2.1", + "nyc": "17.1.0", "swagger-ui-dist": "5.17.14" } } diff --git a/generators/client/support/config.ts b/generators/client/support/config.ts index f219cd2c8fe3..e4009a135c0d 100644 --- a/generators/client/support/config.ts +++ b/generators/client/support/config.ts @@ -5,34 +5,34 @@ import { CLIENT_MAIN_SRC_DIR, CLIENT_TEST_SRC_DIR } from '../../generator-consta * Load client configs into application. */ export const loadClientConfig = ({ config, application }: { config: any; application: any }) => { - (application as any).clientPackageManager = config.clientPackageManager; + application.clientPackageManager = config.clientPackageManager; application.clientFramework = config.clientFramework; - (application as any).clientTheme = config.clientTheme; - (application as any).clientThemeVariant = config.clientThemeVariant; - (application as any).devServerPort = config.devServerPort; + application.clientTheme = config.clientTheme; + application.clientThemeVariant = config.clientThemeVariant; + application.devServerPort = config.devServerPort; - (application as any).clientRootDir = config.clientRootDir ?? ''; - (application as any).clientSrcDir = config.clientSrcDir ?? `${application.clientRootDir}${CLIENT_MAIN_SRC_DIR}`; - (application as any).clientTestDir = config.clientTestDir ?? `${application.clientRootDir}${CLIENT_TEST_SRC_DIR}`; + application.clientRootDir = config.clientRootDir ?? ''; + application.clientSrcDir = config.clientSrcDir ?? `${application.clientRootDir}${CLIENT_MAIN_SRC_DIR}`; + application.clientTestDir = config.clientTestDir ?? `${application.clientRootDir}${CLIENT_TEST_SRC_DIR}`; }; /** * Load client derived properties. */ export const loadDerivedClientConfig = ({ application }: { application: any }) => { - if ((application as any).microfrontend === undefined) { - if ((application as any).applicationTypeMicroservice) { - (application as any).microfrontend = application.clientFrameworkAny; - } else if ((application as any).applicationTypeGateway) { - (application as any).microfrontend = (application as any).microfrontends && (application as any).microfrontends.length > 0; + if (application.microfrontend === undefined) { + if (application.applicationTypeMicroservice) { + application.microfrontend = application.clientFrameworkAny; + } else if (application.applicationTypeGateway) { + application.microfrontend = application.microfrontends && application.microfrontends.length > 0; } } - (application as any).clientThemeNone = (application as any).clientTheme === 'none'; - (application as any).clientThemePrimary = (application as any).clientThemeVariant === 'primary'; - (application as any).clientThemeLight = (application as any).clientThemeVariant === 'light'; - (application as any).clientThemeDark = (application as any).clientThemeVariant === 'dark'; + application.clientThemeNone = application.clientTheme === 'none'; + application.clientThemePrimary = application.clientThemeVariant === 'primary'; + application.clientThemeLight = application.clientThemeVariant === 'light'; + application.clientThemeDark = application.clientThemeVariant === 'dark'; - if ((application as any).baseName) { - (application as any).frontendAppName = getFrontendAppName({ baseName: (application as any).baseName }); + if (application.baseName) { + application.frontendAppName = getFrontendAppName({ baseName: application.baseName }); } }; diff --git a/generators/client/support/entity-definition.js b/generators/client/support/entity-definition.ts similarity index 95% rename from generators/client/support/entity-definition.js rename to generators/client/support/entity-definition.ts index b5f7e14dfa37..2ed424ac0976 100644 --- a/generators/client/support/entity-definition.js +++ b/generators/client/support/entity-definition.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -17,7 +18,7 @@ * limitations under the License. */ -import { fieldTypes, validations, clientFrameworkTypes } from '../../../jdl/jhipster/index.js'; +import { clientFrameworkTypes, fieldTypes, validations } from '../../../lib/jhipster/index.js'; import getTypescriptKeyType from './types-utils.js'; import { filterRelevantRelationships } from './template-utils.js'; @@ -66,7 +67,7 @@ const generateEntityClientFields = ( dto, customDateType = 'dayjs.Dayjs', embedded = false, - clientFramework = ANGULAR, + clientFramework: string = ANGULAR, ) => { const variablesWithTypes = []; if (!embedded && primaryKey) { @@ -105,7 +106,7 @@ const generateEntityClientFields = ( relevantRelationships.forEach(relationship => { let fieldType; let fieldName; - const nullable = !relationship.relationshipValidateRules || !relationship.relationshipValidateRules.includes(REQUIRED); + const nullable = !relationship.relationshipValidateRules?.includes(REQUIRED); const relationshipType = relationship.relationshipType; if (relationshipType === 'one-to-many' || relationshipType === 'many-to-many') { fieldType = `I${relationship.otherEntityAngularName}[]`; diff --git a/generators/client/support/files.ts b/generators/client/support/files.ts index cb3c535d2056..aa3e7a69b164 100644 --- a/generators/client/support/files.ts +++ b/generators/client/support/files.ts @@ -1,7 +1,6 @@ import type { WriteFileBlock } from '../../base/api.js'; import type CoreGenerator from '../../base-core/index.js'; import { CLIENT_MAIN_SRC_DIR, CLIENT_TEST_SRC_DIR } from '../../generator-constants.js'; -import type { CommonClientServerApplication } from '../../base-application/types.js'; export const replaceEntityFilePath = (data: any, filepath: string) => filepath @@ -11,7 +10,7 @@ export const replaceEntityFilePath = (data: any, filepath: string) => const CLIENT_TEMPLATES_SRC_DIR = CLIENT_MAIN_SRC_DIR; -type RelativeWriteFileBlock = WriteFileBlock> & { +type RelativeWriteFileBlock = WriteFileBlock & { relativePath?: string; }; diff --git a/generators/client/support/prepare-entity.js b/generators/client/support/prepare-entity.ts similarity index 100% rename from generators/client/support/prepare-entity.js rename to generators/client/support/prepare-entity.ts diff --git a/generators/client/support/prepare-field.js b/generators/client/support/prepare-field.ts similarity index 100% rename from generators/client/support/prepare-field.js rename to generators/client/support/prepare-field.ts diff --git a/generators/client/support/template-utils.spec.js b/generators/client/support/template-utils.spec.ts similarity index 95% rename from generators/client/support/template-utils.spec.js rename to generators/client/support/template-utils.spec.ts index 4cb69f2b2e5e..097f2f6fdd28 100644 --- a/generators/client/support/template-utils.spec.js +++ b/generators/client/support/template-utils.spec.ts @@ -1,7 +1,7 @@ import path from 'path'; import { expect } from 'chai'; -import { it, describe } from 'esmocha'; -import { entityOptions } from '../../../jdl/jhipster/index.js'; +import { describe, it } from 'esmocha'; +import { entityOptions } from '../../../lib/jhipster/index.js'; import { generateEntityClientImports, generateTestEntityId, getEntityParentPathAddition } from './template-utils.js'; @@ -74,7 +74,7 @@ describe('generator - client - support - template-utils', () => { describe('generateTestEntityId', () => { describe('when called with int', () => { it('return 123', () => { - expect(generateTestEntityId('int')).to.equal(123); + expect(generateTestEntityId('Integer')).to.equal(123); }); }); describe('when called with String', () => { @@ -102,6 +102,7 @@ describe('generator - client - support - template-utils', () => { }); describe('when passing undefined', () => { it('returns an empty string', () => { + // @ts-expect-error testing invalid argument expect(getEntityParentPathAddition()).to.equal(''); }); }); diff --git a/generators/client/support/template-utils.js b/generators/client/support/template-utils.ts similarity index 93% rename from generators/client/support/template-utils.js rename to generators/client/support/template-utils.ts index 825c1f878cab..ad30cd519080 100644 --- a/generators/client/support/template-utils.js +++ b/generators/client/support/template-utils.ts @@ -18,7 +18,9 @@ */ import path from 'path'; -import { fieldTypes, clientFrameworkTypes } from '../../../jdl/jhipster/index.js'; +import { clientFrameworkTypes, fieldTypes } from '../../../lib/jhipster/index.js'; +import type { PrimaryKey } from '../../../lib/types/application/entity.js'; +import type { FieldType } from '../../../lib/application/field-types.js'; import { getEntryIfTypeOrTypeAttribute } from './types-utils.js'; const { STRING: TYPE_STRING, UUID: TYPE_UUID } = fieldTypes.CommonDBTypes; @@ -43,7 +45,7 @@ export const filterRelevantRelationships = relationships => { * @param {string} clientFramework the client framework, 'angular', 'vue' or 'react'. * @returns typeImports: Map */ -export const generateEntityClientImports = (relationships, dto, clientFramework) => { +export const generateEntityClientImports = (relationships, dto?, clientFramework?) => { const typeImports = new Map(); const relevantRelationships = filterRelevantRelationships(relationships); @@ -99,7 +101,7 @@ export const generateEntityClientEnumImports = (fields, clientFramework) => { * @param {boolean} [wrapped=true] - wrapped values for required types. */ -export const generateTestEntityId = (primaryKey, index = 0, wrapped = true) => { +export const generateTestEntityId = (primaryKey: FieldType | PrimaryKey, index: string | number = 0, wrapped = true) => { primaryKey = getEntryIfTypeOrTypeAttribute(primaryKey); let value; if (primaryKey === TYPE_STRING) { @@ -109,7 +111,7 @@ export const generateTestEntityId = (primaryKey, index = 0, wrapped = true) => { } else { value = index === 0 ? 123 : 456; } - if (wrapped && [TYPE_UUID, TYPE_STRING].includes(primaryKey)) { + if (wrapped && [TYPE_UUID, TYPE_STRING].includes(primaryKey as any)) { return `'${value}'`; } return value; diff --git a/generators/client/support/types-utils.spec.js b/generators/client/support/types-utils.spec.ts similarity index 89% rename from generators/client/support/types-utils.spec.js rename to generators/client/support/types-utils.spec.ts index 4b7affef8c92..49f904ac8f76 100644 --- a/generators/client/support/types-utils.spec.js +++ b/generators/client/support/types-utils.spec.ts @@ -1,5 +1,5 @@ -import { it, describe, expect } from 'esmocha'; -import { fieldTypes } from '../../../jdl/jhipster/index.js'; +import { describe, expect, it } from 'esmocha'; +import { fieldTypes } from '../../../lib/jhipster/index.js'; import { getTypescriptType } from './types-utils.js'; diff --git a/generators/client/support/types-utils.js b/generators/client/support/types-utils.ts similarity index 85% rename from generators/client/support/types-utils.js rename to generators/client/support/types-utils.ts index 4b292fe59141..05afc331bf97 100644 --- a/generators/client/support/types-utils.js +++ b/generators/client/support/types-utils.ts @@ -16,7 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { fieldTypes } from '../../../jdl/jhipster/index.js'; +import type { FieldType } from '../../../lib/application/field-types.js'; +import { fieldTypes } from '../../../lib/jhipster/index.js'; +import type { PrimaryKey } from '../../../lib/types/application/entity.js'; import { fieldIsEnum } from '../../base-application/support/index.js'; const { @@ -36,7 +38,7 @@ const { * @param key * @returns {*} */ -export const getEntryIfTypeOrTypeAttribute = key => { +export const getEntryIfTypeOrTypeAttribute = (key: FieldType | PrimaryKey): FieldType => { if (typeof key === 'object') { return key.type; } @@ -49,7 +51,7 @@ export const getEntryIfTypeOrTypeAttribute = key => { * @param {string | object} primaryKey - primary key definition * @returns {string} primary key type in Typescript */ -const getTypescriptKeyType = primaryKey => { +const getTypescriptKeyType = (primaryKey: FieldType | PrimaryKey) => { if ([TYPE_INTEGER, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, TYPE_BIG_DECIMAL].includes(getEntryIfTypeOrTypeAttribute(primaryKey))) { return 'number'; } diff --git a/generators/client/support/update-languages.ts b/generators/client/support/update-languages.ts index 0a8b89de2a57..da6539d84444 100644 --- a/generators/client/support/update-languages.ts +++ b/generators/client/support/update-languages.ts @@ -16,10 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { CommonClientServerApplication } from '../../base-application/types.js'; -import BaseGenerator from '../../base/index.js'; +import type { CommonClientServerApplication } from '../../base-application/types.js'; +import type BaseGenerator from '../../base/index.js'; -export type UpdateClientLanguagesTaskParam = { application: CommonClientServerApplication & { enableTranslation: true }; control?: any }; +export type UpdateClientLanguagesTaskParam = { + application: CommonClientServerApplication & { enableTranslation: true }; + control?: any; +}; /** * Update DayJS Locales. @@ -28,7 +31,7 @@ export type UpdateClientLanguagesTaskParam = { application: CommonClientServerAp * @param configurationFile * @param commonjs */ -// eslint-disable-next-line import/prefer-default-export + export function updateLanguagesInDayjsConfigurationTask( this: BaseGenerator, { application, control = {} }: UpdateClientLanguagesTaskParam, diff --git a/generators/client/templates/.eslintignore.ejs b/generators/client/templates/.eslintignore.ejs deleted file mode 100644 index d4baca84c272..000000000000 --- a/generators/client/templates/.eslintignore.ejs +++ /dev/null @@ -1,32 +0,0 @@ -<%# - Copyright 2013-2024 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. --%> -node_modules/ -<%- dockerServicesDir %> -<%_ if (!clientFrameworkVue) { _%> -jest.conf.js -<%_ } _%> -<%_ if (!clientFrameworkVue || microfrontend) { _%> -webpack/ -<%_ } _%> -<%- temporaryDir %> -coverage/ -<%_ if (clientFrameworkReact) { _%> -postcss.config.js -<%_ } _%> -<%- this.relativeDir(clientRootDir, clientDistDir) %> diff --git a/generators/client/templates/src/main/webapp/index.html.ejs b/generators/client/templates/src/main/webapp/index.html.ejs index 3cff205f77a9..9aa99012747f 100644 --- a/generators/client/templates/src/main/webapp/index.html.ejs +++ b/generators/client/templates/src/main/webapp/index.html.ejs @@ -39,7 +39,8 @@ <%_ if (clientFrameworkAngular) { _%> @@ -49,8 +50,16 @@ <%_ } _%>
-
-
+
+
+
+
+
+
+
+
+
+
@@ -76,15 +85,22 @@

If you have a question on how to use JHipster

- Go to Stack Overflow with the "jhipster" tag. + Go to Stack Overflow with the + "jhipster" tag.

If you have a bug or a feature request

- First read our contributing guidelines. + First read our + contributing guidelines.

- Then, fill a ticket on our bug tracker, we'll be happy to resolve your issue! + Then, fill a ticket on our + bug tracker, we'll be happy to resolve your issue!

If you want to chat with contributors and other users

diff --git a/generators/client/templates/src/main/webapp/swagger-ui/index.html.ejs b/generators/client/templates/src/main/webapp/swagger-ui/index.html.ejs index 50ba45a35514..b6e6fcaad7bc 100644 --- a/generators/client/templates/src/main/webapp/swagger-ui/index.html.ejs +++ b/generators/client/templates/src/main/webapp/swagger-ui/index.html.ejs @@ -173,10 +173,7 @@ req.headers['Authorization'] = getBearerToken(); <%_ } _%> // Remove the sample Swagger UI request body if present - if ( - req.method === 'GET' && - req.body === '{"additionalProp1":"string","additionalProp2":"string","additionalProp3":"string"}' - ) { + if (req.method === 'GET' && req.body === '{"additionalProp1":"string","additionalProp2":"string","additionalProp3":"string"}') { req.body = undefined; } return req; diff --git a/generators/client/templates/webpack/webpack.microfrontend.js.jhi.ejs b/generators/client/templates/webpack/webpack.microfrontend.js.jhi.ejs index 409867e8adbe..ec5af9442fa6 100644 --- a/generators/client/templates/webpack/webpack.microfrontend.js.jhi.ejs +++ b/generators/client/templates/webpack/webpack.microfrontend.js.jhi.ejs @@ -26,8 +26,9 @@ }); _&> -const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); +const { ModuleFederationPlugin } = require('@module-federation/enhanced/webpack'); <&- fragments.importsSection() &> +<%_ if (!clientFrameworkVue) { _%> const packageJson = require('../package.json'); // Microfrontend api, should match across gateway and microservices. const apiVersion = '0.0.1'; @@ -41,6 +42,7 @@ const shareDependencies = ({ skipList = [] } = {}) => .filter(([dependency]) => !skipList.includes(dependency)) .map(([dependency, version]) => [dependency, { ...sharedDefaults, version, requiredVersion: version }]), ); +<%_ } _%> module.exports = () => { return { @@ -51,18 +53,27 @@ module.exports = () => { }, <&- fragments.configSection() &> plugins: [ - new ModuleFederationPlugin({ -<%_ if (applicationTypeMicroservice) { _%> + new ModuleFederationPlugin( +<%_ if (clientFrameworkVue) { _%> + require('../module-federation.config.cjs'), +<%_ } else { -%> + { + <%_ if (applicationTypeMicroservice) { _%> name: '<%= lowercaseBaseName %>', filename: 'remoteEntry.js', -<%_ } _%> + <%_ } _%> shareScope: 'default', + dts: false, + manifest: false, <&- fragments.moduleFederationSection() &> - }), + } +<%_ } -%> + ), <&- fragments.pluginsSection() &> ], output: { publicPath: 'auto', + scriptType: 'text/javascript', }, }; }; diff --git a/generators/client/types.d.ts b/generators/client/types.d.ts index 338518f7a6fe..35cf78e2b8f8 100644 --- a/generators/client/types.d.ts +++ b/generators/client/types.d.ts @@ -1,20 +1,20 @@ import type { addIconImport, addItemToMenu, addRoute } from '../angular/support/needles.js'; import type { AngularApplication } from '../angular/types.js'; -import type { OptionWithDerivedProperties } from '../base-application/application-options.js'; +import type { ExportApplicationPropertiesFromCommand } from '../../lib/command/index.js'; import type { CypressApplication } from '../cypress/types.js'; import type { JavaScriptApplication, JavaScriptSourceType } from '../javascript/types.js'; +import type { PostWritingEntitiesTaskParam } from '../../lib/types/application/tasks.js'; +import type Command from './command.ts'; -type ClientFrameworkType = ['no', 'angular', 'react', 'vue', 'svelte']; +type ApplicationClientProperties = ExportApplicationPropertiesFromCommand; -type ClientFrameworkApplication = OptionWithDerivedProperties<'clientFramework', ClientFrameworkType>; - -export type ClientApplication = ClientFrameworkApplication & +export type ClientApplication = ApplicationClientProperties & JavaScriptApplication & AngularApplication & CypressApplication & { - withAdminUi: boolean; webappLoginRegExp: string; webappEnumerationsDir?: string; + clientFrameworkBuiltIn?: boolean; }; export type ClientResources = { @@ -27,7 +27,9 @@ export type ClientResources = { */ comment?: string; }; + export type ClientSourceType = JavaScriptSourceType & { + addEntitiesToClient: (arg1: Pick) => void; /** * Add external resources to root file(index.html). */ diff --git a/generators/common/__snapshots__/generator.spec.js.snap b/generators/common/__snapshots__/generator.spec.ts.snap similarity index 82% rename from generators/common/__snapshots__/generator.spec.js.snap rename to generators/common/__snapshots__/generator.spec.ts.snap index fbf37e6dcf7f..3df1e24246db 100644 --- a/generators/common/__snapshots__/generator.spec.js.snap +++ b/generators/common/__snapshots__/generator.spec.ts.snap @@ -19,9 +19,6 @@ insert_final_newline = true # Change these settings to your own preference indent_style = space -indent_size = 4 - -[*.{ts,tsx,js,jsx,json,css,scss,yml,html,vue}] indent_size = 2 [*.md] @@ -30,17 +27,13 @@ trim_trailing_whitespace = false "stateCleared": "modified", }, ".husky/pre-commit": { - "contents": "#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - - -"$(dirname "$0")/../npmw" exec --no-install lint-staged + "contents": "lint-staged ", "stateCleared": "modified", }, ".lintstagedrc.cjs": { "contents": "module.exports = { - '{,**/}*.{md,json,yml,html,cjs,mjs,js,ts,tsx,css,scss,java}': ['prettier --write'], + '{,**/}*.{md,json,yml,js,cjs,mjs,ts,cts,mts}': ['prettier --write'], }; ", "stateCleared": "modified", @@ -111,20 +104,26 @@ This application was generated using JHipster JHIPSTER_VERSION, you can find doc }, "package.json": { "contents": "{ - "config": { - "default_environment": "prod" - }, + "private": true, + "dependencies": {}, "devDependencies": { "generator-jhipster": "JHIPSTER_VERSION", - "husky": "HUSKY_VERSION", - "lint-staged": "LINT_STAGED_VERSION", "prettier": "PRETTIER_VERSION", "prettier-plugin-packagejson": "PRETTIER_PLUGIN_PACKAGEJSON_VERSION", - "prettier-plugin-java": "PRETTIER_PLUGIN_JAVA_VERSION" + "husky": "HUSKY_VERSION", + "lint-staged": "LINT_STAGED_VERSION" }, + "engines": {}, "scripts": { "prepare": "husky" - } + }, + "config": { + "default_environment": "prod" + }, + "name": "jhipster", + "version": "0.0.0", + "description": "Description for JHipster", + "license": "UNLICENSED" } ", "stateCleared": "modified", @@ -152,8 +151,13 @@ sonar.exclusions = src/main/webapp/content/**/*.*, src/main/webapp/i18n/*.js, \\ target/classes/static/**/*.* sonar.issue.ignore.multicriteria = \\ - S1192,S125,S3437,S4502,S4684,S5145,UndocumentedApi + S6437,S1192,S125,S3437,S4502,S4684,S5145,S7027-domain,S7027-dto,UndocumentedAp\\ + i +# Rule https://rules.sonarsource.com/java/RSPEC-6437 is ignored, hardcoded +# passwords are provided for development purposes +sonar.issue.ignore.multicriteria.S6437.resourceKey = src/main/resources/config/* +sonar.issue.ignore.multicriteria.S6437.ruleKey = java:S6437 # Rule https://rules.sonarsource.com/java/RSPEC-3437 is ignored, as a # JPA-managed field cannot be transient sonar.issue.ignore.multicriteria.S3437.resourceKey = src/main/java/**/* @@ -168,6 +172,14 @@ sonar.issue.ignore.multicriteria.S4684.ruleKey = java:S4684 # Rule https://rules.sonarsource.com/java/RSPEC-5145 log filter is applied sonar.issue.ignore.multicriteria.S5145.resourceKey = src/main/java/**/* sonar.issue.ignore.multicriteria.S5145.ruleKey = javasecurity:S5145 +# Rule https://rules.sonarsource.com/java/RSPEC-7027 is ignored for entities +sonar.issue.ignore.multicriteria.S7027-domain.resourceKey = \\ + src/main/java/com/mycompany/myapp/domain/**/* +sonar.issue.ignore.multicriteria.S7027-domain.ruleKey = javaarchitecture:S7027 +# Rule https://rules.sonarsource.com/java/RSPEC-7027 is ignored for dtos +sonar.issue.ignore.multicriteria.S7027-dto.resourceKey = \\ + src/main/java/com/mycompany/myapp/service/dto/**/* +sonar.issue.ignore.multicriteria.S7027-dto.ruleKey = javaarchitecture:S7027 # Rule https://rules.sonarsource.com/java/RSPEC-1176 is ignored, as we want to # follow "clean code" guidelines and classes, methods and arguments names # should be self-explanatory diff --git a/generators/common/command.ts b/generators/common/command.ts index ad3ac009f69a..6512b4637461 100644 --- a/generators/common/command.ts +++ b/generators/common/command.ts @@ -16,17 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_BOOTSTRAP_APPLICATION_BASE } from '../generator-list.js'; const command: JHipsterCommandDefinition = { - options: { - skipCommitHook: { - description: 'Skip adding husky commit hooks', - type: Boolean, - scope: 'storage', - }, - }, configs: { defaultEnvironment: { description: 'Default environment for the application', @@ -40,7 +33,7 @@ const command: JHipsterCommandDefinition = { scope: 'storage', }, }, - import: [GENERATOR_BOOTSTRAP_APPLICATION_BASE, 'jhipster:javascript:prettier'], + import: [GENERATOR_BOOTSTRAP_APPLICATION_BASE, 'jhipster:javascript:prettier', 'jhipster:javascript:husky'], }; export default command; diff --git a/generators/common/files.js b/generators/common/files.ts similarity index 85% rename from generators/common/files.js rename to generators/common/files.ts index 860040a65100..57bbe95cc482 100644 --- a/generators/common/files.js +++ b/generators/common/files.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -24,7 +25,7 @@ export const commonFiles = { global: [ { - templates: ['README.md.jhi', '.editorconfig'], + templates: ['README.md.jhi', '.editorconfig.jhi'], }, ], sonar: [ @@ -32,12 +33,6 @@ export const commonFiles = { templates: ['sonar-project.properties'], }, ], - commitHooks: [ - { - condition: generator => !generator.skipCommitHook, - templates: ['.lintstagedrc.cjs', '.husky/pre-commit'], - }, - ], }; export function writeFiles() { diff --git a/generators/common/generator.spec.js b/generators/common/generator.spec.ts similarity index 83% rename from generators/common/generator.spec.js rename to generators/common/generator.spec.ts index 46d459222184..703951531ee9 100644 --- a/generators/common/generator.spec.js +++ b/generators/common/generator.spec.ts @@ -16,13 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { defaultHelpers as helpers, basicHelpers, runResult } from '../../testing/index.js'; -import { shouldSupportFeatures, testBlueprintSupport, checkEnforcements } from '../../test/support/index.js'; +import { basicHelpers, defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; +import { checkEnforcements, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/index.js'; import { GENERATOR_COMMON } from '../generator-list.js'; import Generator from './index.js'; @@ -30,7 +30,6 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorFile = join(__dirname, 'index.js'); const mockedGenerators = ['jhipster:git']; @@ -45,7 +44,7 @@ describe(`generator - ${generator}`, () => { describe('with', () => { describe('default config', () => { before(async () => { - await helpers.run(generatorFile).withJHipsterConfig().withMockedGenerators(mockedGenerators); + await helpers.runJHipster(generator).withJHipsterConfig().withMockedGenerators(mockedGenerators); }); it('should succeed', () => { @@ -59,7 +58,7 @@ describe(`generator - ${generator}`, () => { describe('Custom prettier', () => { before(async () => { await basicHelpers - .run(generatorFile) + .runJHipster(generator) .withJHipsterConfig({ prettierTabWidth: 10, }) diff --git a/generators/common/generator.js b/generators/common/generator.ts similarity index 88% rename from generators/common/generator.js rename to generators/common/generator.ts index 8733e4100cba..6bda63fd4519 100644 --- a/generators/common/generator.js +++ b/generators/common/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,18 +17,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return */ + import { isFileStateModified } from 'mem-fs-editor/state'; import BaseApplicationGenerator from '../base-application/index.js'; import { + JHIPSTER_DOCUMENTATION_ARCHIVE_PATH, + JHIPSTER_DOCUMENTATION_URL, MAIN_DIR, - TEST_DIR, SERVER_MAIN_RES_DIR, - JHIPSTER_DOCUMENTATION_URL, - JHIPSTER_DOCUMENTATION_ARCHIVE_PATH, + TEST_DIR, } from '../generator-constants.js'; -import { clientFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { clientFrameworkTypes } from '../../lib/jhipster/index.js'; import { GENERATOR_COMMON, GENERATOR_GIT } from '../generator-list.js'; import { createPrettierTransform } from '../bootstrap/support/prettier-support.js'; import { loadStoredAppOptions } from '../app/support/index.js'; @@ -79,6 +80,9 @@ export default class CommonGenerator extends BaseApplicationGenerator { return this.asComposingTaskGroup({ async composing() { await this.composeWithJHipster('jhipster:javascript:prettier'); + if (!this.jhipsterConfig.skipCommitHook) { + await this.composeWithJHipster('jhipster:javascript:husky'); + } }, }); } @@ -192,8 +196,8 @@ export default class CommonGenerator extends BaseApplicationGenerator { // Public API method used by the getter and also by Blueprints get writing() { return this.asWritingTaskGroup({ - cleanup({ application, control }) { - control.cleanupFiles({ + async cleanup({ application, control }) { + await control.cleanupFiles({ '7.1.1': [[!application.skipCommitHook, '.huskyrc']], '7.6.1': [[application.skipClient, 'npmw', 'npmw.cmd']], '8.0.0-rc.2': [[!application.skipCommitHook, '.lintstagedrc.js']], @@ -225,27 +229,6 @@ export default class CommonGenerator extends BaseApplicationGenerator { }, }); }, - addCommitHookDependencies({ application }) { - if (application.skipCommitHook) return; - this.packageJson.merge({ - scripts: { - prepare: 'husky', - }, - devDependencies: { - husky: application.nodeDependencies.husky, - 'lint-staged': application.nodeDependencies['lint-staged'], - prettier: application.nodeDependencies.prettier, - 'prettier-plugin-packagejson': application.nodeDependencies['prettier-plugin-packagejson'], - }, - }); - if (application.backendTypeJavaAny) { - this.packageJson.merge({ - devDependencies: { - 'prettier-plugin-java': application.nodeDependencies['prettier-plugin-java'], - }, - }); - } - }, }); } diff --git a/generators/common/index.ts b/generators/common/index.ts index c555f998dedd..5560397a490b 100644 --- a/generators/common/index.ts +++ b/generators/common/index.ts @@ -16,21 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BaseApplicationGeneratorDefinition } from '../base-application/tasks.js'; -import { type Entity } from '../base-application/index.js'; -import { ClientServerApplication } from './types.js'; - export { default } from './generator.js'; export { default as command } from './command.js'; export { commonFiles as files } from './files.js'; - -// TODO move to ./generator.mts -type ApplicationDefinition = { - applicationType: ClientServerApplication; - entityType: Entity; - sourceType: Record any>; -}; - -// TODO move to ./generator.mts -export type GeneratorDefinition = - BaseApplicationGeneratorDefinition; diff --git a/generators/common/resources/package.json b/generators/common/resources/package.json index e5d4bff5d8a2..959d0cf304cf 100644 --- a/generators/common/resources/package.json +++ b/generators/common/resources/package.json @@ -1,9 +1,7 @@ { "devDependencies": { - "concurrently": "8.2.2", - "husky": "9.0.11", - "lint-staged": "15.2.7", - "npm": "10.8.2", - "wait-on": "7.2.0" + "concurrently": "9.0.1", + "npm": "10.9.0", + "wait-on": "8.0.1" } } diff --git a/generators/common/templates/.editorconfig.ejs b/generators/common/templates/.editorconfig.jhi.ejs similarity index 83% rename from generators/common/templates/.editorconfig.ejs rename to generators/common/templates/.editorconfig.jhi.ejs index c2fa6a2d9fab..352e2df72e42 100644 --- a/generators/common/templates/.editorconfig.ejs +++ b/generators/common/templates/.editorconfig.jhi.ejs @@ -14,10 +14,9 @@ insert_final_newline = true # Change these settings to your own preference indent_style = space -indent_size = 4 - -[*.{ts,tsx,js,jsx,json,css,scss,yml,html,vue}] -indent_size = 2 +indent_size = <%= prettierTabWidth %> [*.md] trim_trailing_whitespace = false + +<&- fragments.render({ join: '\n\n' }) &> diff --git a/generators/common/templates/.husky/pre-commit.ejs b/generators/common/templates/.husky/pre-commit.ejs deleted file mode 100755 index 96421e83b237..000000000000 --- a/generators/common/templates/.husky/pre-commit.ejs +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - - -<%_ if (useNpmWrapper) { _%> -"$(dirname "$0")/../npmw" exec --no-install lint-staged -<%_ } else { _%> -npx --no-install lint-staged -<%_ } _%> diff --git a/generators/common/templates/.lintstagedrc.cjs.ejs b/generators/common/templates/.lintstagedrc.cjs.ejs deleted file mode 100644 index d87d1d08e925..000000000000 --- a/generators/common/templates/.lintstagedrc.cjs.ejs +++ /dev/null @@ -1,21 +0,0 @@ -<%# - Copyright 2013-2024 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. --%> -module.exports = { - '{,**/}*.{<%= prettierExtensions %>}': ['prettier --write'], -}; diff --git a/generators/common/templates/sonar-project.properties.ejs b/generators/common/templates/sonar-project.properties.ejs index dc2a531618f4..8fa2d6e2de06 100644 --- a/generators/common/templates/sonar-project.properties.ejs +++ b/generators/common/templates/sonar-project.properties.ejs @@ -40,6 +40,9 @@ sonar.exclusions=<%= clientSrcDir %>content/**/*.*, <%= clientSrcDir %>i18n/*.js <%_ if (!skipServer) { _%> sonar.issue.ignore.multicriteria=\ +<%_ if (backendTypeSpringBoot) { _%> + S6437,\ +<%_ } _%> <%_ if (cacheProviderAny) { _%> S1192,\ <%_ } _%> @@ -53,29 +56,40 @@ sonar.issue.ignore.multicriteria=\ <%_ if (authenticationTypeJwt) { _%> S4502,\ <%_ } _%> - S4684,S5145,UndocumentedApi + S4684,S5145,S7027-domain,S7027-dto,UndocumentedApi - <%_ if (gatlingTests) { _%> +<%_ if (backendTypeSpringBoot) { _%> +# Rule https://rules.sonarsource.com/java/RSPEC-6437 is ignored, hardcoded passwords are provided for development purposes +sonar.issue.ignore.multicriteria.S6437.resourceKey=<%= srcMainResources %>config/* +sonar.issue.ignore.multicriteria.S6437.ruleKey=java:S6437 +<%_ } _%> +<%_ if (gatlingTests) { _%> # Rule https://rules.sonarsource.com/java/RSPEC-2187 is ignored, gatling tests are not supported by sonar -sonar.issue.ignore.multicriteria.S2187.resourceKey=<%= TEST_DIR %>java/gatling/**/* +sonar.issue.ignore.multicriteria.S2187.resourceKey= <%- srcTestJava %>gatling/**/* sonar.issue.ignore.multicriteria.S2187.ruleKey=java:S2187 - <%_ } _%> +<%_ } _%> # Rule https://rules.sonarsource.com/java/RSPEC-3437 is ignored, as a JPA-managed field cannot be transient -sonar.issue.ignore.multicriteria.S3437.resourceKey=<%= MAIN_DIR %>java/**/* +sonar.issue.ignore.multicriteria.S3437.resourceKey= <%- srcMainJava %>**/* sonar.issue.ignore.multicriteria.S3437.ruleKey=squid:S3437 - <%_ if (authenticationTypeJwt) { _%> +<%_ if (authenticationTypeJwt) { _%> # Rule https://rules.sonarsource.com/java/RSPEC-4502 is ignored, as for JWT tokens we are not subject to CSRF attack -sonar.issue.ignore.multicriteria.S4502.resourceKey=<%= MAIN_DIR %>java/**/* +sonar.issue.ignore.multicriteria.S4502.resourceKey= <%- srcMainJava %>**/* sonar.issue.ignore.multicriteria.S4502.ruleKey=java:S4502 - <%_ } _%> +<%_ } _%> # Rule https://rules.sonarsource.com/java/RSPEC-4684 -sonar.issue.ignore.multicriteria.S4684.resourceKey=<%= MAIN_DIR %>java/**/* +sonar.issue.ignore.multicriteria.S4684.resourceKey= <%- srcMainJava %>**/* sonar.issue.ignore.multicriteria.S4684.ruleKey=java:S4684 # Rule https://rules.sonarsource.com/java/RSPEC-5145 log filter is applied -sonar.issue.ignore.multicriteria.S5145.resourceKey=<%= MAIN_DIR %>java/**/* +sonar.issue.ignore.multicriteria.S5145.resourceKey= <%- srcMainJava %>**/* sonar.issue.ignore.multicriteria.S5145.ruleKey=javasecurity:S5145 +# Rule https://rules.sonarsource.com/java/RSPEC-7027 is ignored for entities +sonar.issue.ignore.multicriteria.S7027-domain.resourceKey = <%- srcMainJava %><%- packageFolder %>domain/**/* +sonar.issue.ignore.multicriteria.S7027-domain.ruleKey = javaarchitecture:S7027 +# Rule https://rules.sonarsource.com/java/RSPEC-7027 is ignored for dtos +sonar.issue.ignore.multicriteria.S7027-dto.resourceKey = <%- srcMainJava %><%- packageFolder %>service/dto/**/* +sonar.issue.ignore.multicriteria.S7027-dto.ruleKey = javaarchitecture:S7027 # Rule https://rules.sonarsource.com/java/RSPEC-1176 is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names should be self-explanatory -sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey=<%= MAIN_DIR %>java/**/* +sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey= <%- srcMainJava %>**/* sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey=squid:UndocumentedApi <%_ } _%> <%_ if (cacheProviderAny) { _%> diff --git a/generators/cucumber/files.ts b/generators/cucumber/files.ts index 3dee663fabbc..539dac3bb3b3 100644 --- a/generators/cucumber/files.ts +++ b/generators/cucumber/files.ts @@ -17,12 +17,11 @@ * limitations under the License. */ import { moveToJavaPackageTestDir } from '../server/support/index.js'; -import { SERVER_TEST_SRC_DIR, SERVER_TEST_RES_DIR, GRADLE_BUILD_SRC_MAIN_DIR } from '../generator-constants.js'; -import { WriteFileSection } from '../base/api.js'; -import { CommonClientServerApplication } from '../base-application/types.js'; -import Generator from './generator.js'; +import { GRADLE_BUILD_SRC_MAIN_DIR, SERVER_TEST_RES_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; +import type { WriteFileSection } from '../base/api.js'; +import type Generator from './generator.js'; -const cucumberFiles: WriteFileSection = { +const cucumberFiles: WriteFileSection = { cucumberFiles: [ { path: `${SERVER_TEST_SRC_DIR}_package_/`, diff --git a/generators/cucumber/generator.spec.ts b/generators/cucumber/generator.spec.ts index ea55093f8c63..8ec5f8ac062d 100644 --- a/generators/cucumber/generator.spec.ts +++ b/generators/cucumber/generator.spec.ts @@ -1,10 +1,10 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../lib/testing/index.js'; import { GENERATOR_CUCUMBER } from '../generator-list.js'; import Generator from './index.js'; diff --git a/generators/cucumber/generator.ts b/generators/cucumber/generator.ts index 17c98294b538..bc874558722c 100644 --- a/generators/cucumber/generator.ts +++ b/generators/cucumber/generator.ts @@ -46,32 +46,30 @@ export default class CucumberGenerator extends BaseApplicationGenerator { return this.asPostWritingTaskGroup({ addDependencies({ application, source }) { const { javaDependencies, gradleBuildSrc } = application; - source.addJavaDependencies?.( - [ - { - groupId: 'io.cucumber', - artifactId: 'cucumber-bom', - version: javaDependencies!['cucumber-bom'], - type: 'pom', - scope: 'import', - }, - { groupId: 'io.cucumber', artifactId: 'cucumber-junit-platform-engine', scope: 'test' }, - { groupId: 'io.cucumber', artifactId: 'cucumber-java', scope: 'test' }, - { groupId: 'io.cucumber', artifactId: 'cucumber-spring', scope: 'test' }, - { groupId: 'org.junit.platform', artifactId: 'junit-platform-console', scope: 'test' }, - { groupId: 'org.testng', artifactId: 'testng', scope: 'test', version: javaDependencies!.testng }, - ], + source.addJavaDefinitions?.( { gradleFile: `${gradleBuildSrc}src/main/groovy/jhipster.cucumber-conventions.gradle` }, - ); - - if (application.buildToolMaven) { - source.addMavenDefinition?.({ - plugins: [{ groupId: 'org.apache.maven.plugins', artifactId: 'maven-antrun-plugin' }], - pluginManagement: [ + { + dependencies: [ { - groupId: 'org.apache.maven.plugins', - artifactId: 'maven-antrun-plugin', - additionalContent: ` + groupId: 'io.cucumber', + artifactId: 'cucumber-bom', + version: javaDependencies!['cucumber-bom'], + type: 'pom', + scope: 'import', + }, + { groupId: 'io.cucumber', artifactId: 'cucumber-junit-platform-engine', scope: 'test' }, + { groupId: 'io.cucumber', artifactId: 'cucumber-java', scope: 'test' }, + { groupId: 'io.cucumber', artifactId: 'cucumber-spring', scope: 'test' }, + { groupId: 'org.junit.platform', artifactId: 'junit-platform-console', scope: 'test' }, + { groupId: 'org.testng', artifactId: 'testng', scope: 'test', version: javaDependencies!.testng }, + ], + mavenDefinition: { + plugins: [{ groupId: 'org.apache.maven.plugins', artifactId: 'maven-antrun-plugin' }], + pluginManagement: [ + { + groupId: 'org.apache.maven.plugins', + artifactId: 'maven-antrun-plugin', + additionalContent: ` @@ -105,10 +103,11 @@ export default class CucumberGenerator extends BaseApplicationGenerator { `, - }, - ], - }); - } + }, + ], + }, + }, + ); if (application.buildToolGradle) { source.addGradlePlugin?.({ id: 'jhipster.cucumber-conventions' }); diff --git a/generators/cypress/__snapshots__/generator.spec.ts.snap b/generators/cypress/__snapshots__/generator.spec.ts.snap index f19b4e1082c0..28ab8d8541a8 100644 --- a/generators/cypress/__snapshots__/generator.spec.ts.snap +++ b/generators/cypress/__snapshots__/generator.spec.ts.snap @@ -14,10 +14,10 @@ exports[`generator - cypress jwt-cypressAudit(false)-angular-withAdminUi(false)- "clientRoot/package.json": { "stateCleared": "modified", }, - "clientRoot/src/test/javascript/cypress/.eslintrc.json": { + "clientRoot/src/test/javascript/cypress/e2e/account/login-page.cy.ts": { "stateCleared": "modified", }, - "clientRoot/src/test/javascript/cypress/e2e/account/login-page.cy.ts": { + "clientRoot/src/test/javascript/cypress/e2e/account/logout.cy.ts": { "stateCleared": "modified", }, "clientRoot/src/test/javascript/cypress/e2e/account/password-page.cy.ts": { @@ -88,10 +88,10 @@ exports[`generator - cypress jwt-cypressAudit(true)-vue-withAdminUi(true)-cypres "clientRoot/package.json": { "stateCleared": "modified", }, - "clientRoot/src/test/javascript/cypress/.eslintrc.json": { + "clientRoot/src/test/javascript/cypress/e2e/account/login-page.cy.ts": { "stateCleared": "modified", }, - "clientRoot/src/test/javascript/cypress/e2e/account/login-page.cy.ts": { + "clientRoot/src/test/javascript/cypress/e2e/account/logout.cy.ts": { "stateCleared": "modified", }, "clientRoot/src/test/javascript/cypress/e2e/account/password-page.cy.ts": { @@ -162,7 +162,7 @@ exports[`generator - cypress oauth2-cypressAudit(false)-angular-withAdminUi(fals "package.json": { "stateCleared": "modified", }, - "src/test/javascript/cypress/.eslintrc.json": { + "src/test/javascript/cypress/e2e/account/logout.cy.ts": { "stateCleared": "modified", }, "src/test/javascript/cypress/e2e/administration/administration.cy.ts": { @@ -218,7 +218,7 @@ exports[`generator - cypress oauth2-cypressAudit(true)-vue-withAdminUi(true)-cyp "package.json": { "stateCleared": "modified", }, - "src/test/javascript/cypress/.eslintrc.json": { + "src/test/javascript/cypress/e2e/account/logout.cy.ts": { "stateCleared": "modified", }, "src/test/javascript/cypress/e2e/administration/administration.cy.ts": { @@ -348,10 +348,10 @@ exports[`generator - cypress session-cypressAudit(false)-angular-withAdminUi(fal "package.json": { "stateCleared": "modified", }, - "src/test/javascript/cypress/.eslintrc.json": { + "src/test/javascript/cypress/e2e/account/login-page.cy.ts": { "stateCleared": "modified", }, - "src/test/javascript/cypress/e2e/account/login-page.cy.ts": { + "src/test/javascript/cypress/e2e/account/logout.cy.ts": { "stateCleared": "modified", }, "src/test/javascript/cypress/e2e/account/password-page.cy.ts": { @@ -422,10 +422,10 @@ exports[`generator - cypress session-cypressAudit(true)-vue-withAdminUi(true)-cy "package.json": { "stateCleared": "modified", }, - "src/test/javascript/cypress/.eslintrc.json": { + "src/test/javascript/cypress/e2e/account/login-page.cy.ts": { "stateCleared": "modified", }, - "src/test/javascript/cypress/e2e/account/login-page.cy.ts": { + "src/test/javascript/cypress/e2e/account/logout.cy.ts": { "stateCleared": "modified", }, "src/test/javascript/cypress/e2e/account/password-page.cy.ts": { diff --git a/generators/cypress/command.ts b/generators/cypress/command.ts index 5f659e5d44e2..1786a5693d29 100644 --- a/generators/cypress/command.ts +++ b/generators/cypress/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { options: { diff --git a/generators/cypress/files.ts b/generators/cypress/files.ts index efaa182ef783..4d8cb3b056b7 100644 --- a/generators/cypress/files.ts +++ b/generators/cypress/files.ts @@ -19,15 +19,11 @@ import { CLIENT_TEST_SRC_DIR } from '../generator-constants.js'; import type { WriteFileSection } from '../base/api.js'; -import { type Entity } from '../base-application/index.js'; -import type { CommonClientServerApplication } from '../base-application/types.js'; import { clientRootTemplatesBlock } from '../client/support/index.js'; -import type { CypressApplication } from './types.js'; -import type CypressGenerator from './generator.js'; const CYPRESS_TEMPLATE_SOURCE_DIR = `${CLIENT_TEST_SRC_DIR}cypress/`; -export const cypressFiles: WriteFileSection = { +export const cypressFiles: WriteFileSection = { common: [ { templates: ['README.md.jhi.cypress'], @@ -45,7 +41,6 @@ export const cypressFiles: WriteFileSection `${ctx.cypressDir}${file}`, templates: [ - '.eslintrc.json', 'fixtures/integration-test.png', 'plugins/index.ts', 'e2e/administration/administration.cy.ts', @@ -57,6 +52,12 @@ export const cypressFiles: WriteFileSection !generator.applicationTypeMicroservice, + path: CYPRESS_TEMPLATE_SOURCE_DIR, + renameTo: (ctx, file) => `${ctx.cypressDir}${file}`, + templates: ['e2e/account/logout.cy.ts'], + }, { condition: generator => !generator.authenticationTypeOauth2, path: CYPRESS_TEMPLATE_SOURCE_DIR, @@ -104,7 +105,7 @@ export const cypressFiles: WriteFileSection = { +export const cypressEntityFiles: WriteFileSection = { testsCypress: [ { path: CYPRESS_TEMPLATE_SOURCE_DIR, diff --git a/generators/cypress/generator.spec.ts b/generators/cypress/generator.spec.ts index 1e3eeb21c774..222e15093654 100644 --- a/generators/cypress/generator.spec.ts +++ b/generators/cypress/generator.spec.ts @@ -16,13 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import path, { basename, dirname } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, after, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { clientFrameworkTypes, testFrameworkTypes } from '../../jdl/jhipster/index.js'; -import { fromMatrix, extendMatrix, AuthenticationTypeMatrix, defaultHelpers as helpers } from '../../testing/index.js'; -import { shouldSupportFeatures, testBlueprintSupport, checkEnforcements } from '../../test/support/index.js'; +import { clientFrameworkTypes, testFrameworkTypes } from '../../lib/jhipster/index.js'; +import { AuthenticationTypeMatrix, extendMatrix, fromMatrix, defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; +import { checkEnforcements, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/index.js'; import { GENERATOR_CYPRESS } from '../generator-list.js'; import Generator from './generator.js'; @@ -34,8 +34,6 @@ const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorPath = path.join(__dirname, 'index.ts'); - const e2eMatrix = extendMatrix( fromMatrix({ ...AuthenticationTypeMatrix, @@ -79,14 +77,10 @@ describe(`generator - ${generator}`, () => { Object.entries(e2eSamples).forEach(([name, sampleConfig]) => { describe(name, () => { - let runResult; - before(async () => { - runResult = await helpers.run(generatorPath).withJHipsterConfig(sampleConfig, entities); + await helpers.runJHipster(generator).withJHipsterConfig(sampleConfig, entities); }); - after(() => runResult.cleanup()); - it('should match generated files snapshot', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); }); @@ -103,7 +97,7 @@ describe(`generator - ${generator}`, () => { const adminUiRoutingTitle = generateAdminUi ? 'should generate admin routing' : 'should not generate admin routing'; it(adminUiRoutingTitle, () => { const assertion = (...args) => - generateAdminUi ? runResult.assertFileContent(...args) : runResult.assertNoFileContent(...args); + generateAdminUi ? (runResult.assertFileContent as any)(...args) : (runResult.assertNoFileContent as any)(...args); assertion( `${clientRootDir}src/test/javascript/cypress/e2e/administration/administration.cy.ts`, diff --git a/generators/cypress/generator.ts b/generators/cypress/generator.ts index 11f5b32e071c..e12cbbef710f 100644 --- a/generators/cypress/generator.ts +++ b/generators/cypress/generator.ts @@ -17,13 +17,13 @@ * limitations under the License. */ -import { stringHashCode, createFaker } from '../base/support/index.js'; +import { createFaker, stringHashCode } from '../base/support/index.js'; import BaseApplicationGenerator from '../base-application/index.js'; -import { clientFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { clientFrameworkTypes } from '../../lib/jhipster/index.js'; import { CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; import { generateTestEntity as entityWithFakeValues } from '../client/support/index.js'; -import { cypressFiles, cypressEntityFiles } from './files.js'; +import { cypressEntityFiles, cypressFiles } from './files.js'; const { ANGULAR } = clientFrameworkTypes; @@ -110,7 +110,7 @@ export default class CypressGenerator extends BaseApplicationGenerator { get writing() { return this.asWritingTaskGroup({ - cleanup({ application: { authenticationTypeOauth2, generateUserManagement, cypressDir } }) { + async cleanup({ control, application: { authenticationTypeOauth2, generateUserManagement, cypressDir } }) { if (this.isJhipsterVersionLessThan('7.0.0-beta.1')) { this.removeFile(`${cypressDir}support/keycloak-oauth2.ts`); this.removeFile(`${cypressDir}fixtures/users/user.json`); @@ -131,6 +131,8 @@ export default class CypressGenerator extends BaseApplicationGenerator { this.removeFile(`${cypressDir}integration/account/reset-password-page.spec.ts`); } } + + await control.cleanupFiles({ '8.6.1': [`${cypressDir}.eslintrc.json`] }); }, async writeFiles({ application }) { const faker = await createFaker(); @@ -213,9 +215,7 @@ export default class CypressGenerator extends BaseApplicationGenerator { scripts: { 'cypress:audits': 'cypress open --e2e --config-file cypress-audits.config.js', 'e2e:cypress:audits:headless': 'npm run e2e:cypress -- --config-file cypress-audits.config.js', - 'e2e:cypress:audits': - // eslint-disable-next-line no-template-curly-in-string - 'cypress run --e2e --browser chrome --config-file cypress-audits.config.js', + 'e2e:cypress:audits': 'cypress run --e2e --browser chrome --config-file cypress-audits.config.js', }, }); }, diff --git a/generators/cypress/index.ts b/generators/cypress/index.ts index f3ccaf492f17..082d5730094c 100644 --- a/generators/cypress/index.ts +++ b/generators/cypress/index.ts @@ -18,5 +18,4 @@ */ export { default } from './generator.js'; export { default as command } from './command.js'; -export * from './generator.js'; export { cypressFiles, cypressEntityFiles } from './files.js'; diff --git a/generators/cypress/templates/eslint.config.js.jhi.cypress.ejs b/generators/cypress/templates/eslint.config.js.jhi.cypress.ejs index 41c496ee2eb7..e51bfbaed454 100644 --- a/generators/cypress/templates/eslint.config.js.jhi.cypress.ejs +++ b/generators/cypress/templates/eslint.config.js.jhi.cypress.ejs @@ -21,7 +21,7 @@ import cypress from 'eslint-plugin-cypress/flat'; <&_ } -&> <&_ if (fragment.configSection) { -&> { - files: ['<%- this.relativeDir(clientRootDir, cypressDir) %>**/*.cy.ts'], + files: ['<%- this.relativeDir(clientRootDir, cypressDir) %>**/*.ts'], extends: [...tseslint.configs.recommendedTypeChecked, cypress.configs.recommended], languageOptions: { parserOptions: { @@ -29,13 +29,12 @@ import cypress from 'eslint-plugin-cypress/flat'; }, }, rules: { - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/no-unsafe-argument': 'warn', - '@typescript-eslint/no-unsafe-assignment': 'warn', - '@typescript-eslint/no-unsafe-call': 'warn', - '@typescript-eslint/no-unsafe-member-access': 'warn', - '@typescript-eslint/unbound-method': 'warn', - '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/unbound-method': 'off', }, }, <&_ } -&> diff --git a/generators/cypress/templates/src/test/javascript/cypress/.eslintrc.json.ejs b/generators/cypress/templates/src/test/javascript/cypress/.eslintrc.json.ejs deleted file mode 100644 index d779d5a2527b..000000000000 --- a/generators/cypress/templates/src/test/javascript/cypress/.eslintrc.json.ejs +++ /dev/null @@ -1,20 +0,0 @@ -{ - "root": true, - "parser": "@typescript-eslint/parser", - "plugins": [ - "cypress", - "@typescript-eslint" - ], - "env": { - "cypress/globals": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:cypress/recommended" - ], - "rules": { - "@typescript-eslint/no-namespace": ["error", { "allowDeclarations": true }], - "@typescript-eslint/no-unused-vars": "off" - } -} diff --git a/generators/cypress/templates/src/test/javascript/cypress/e2e/account/login-page.cy.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/e2e/account/login-page.cy.ts.ejs index f5575e3c3796..3e075c280f95 100644 --- a/generators/cypress/templates/src/test/javascript/cypress/e2e/account/login-page.cy.ts.ejs +++ b/generators/cypress/templates/src/test/javascript/cypress/e2e/account/login-page.cy.ts.ejs @@ -24,7 +24,7 @@ import { submitLoginSelector, } from '../../support/commands'; -describe('login modal', () => { +describe('login page', () => { const username = Cypress.env('E2E_USERNAME') ?? '<%= skipUserManagement && (applicationTypeMonolith || applicationTypeGateway) ? 'admin' : 'user' %>'; const password = Cypress.env('E2E_PASSWORD') ?? '<%= skipUserManagement && (applicationTypeMonolith || applicationTypeGateway) ? 'admin' : 'user' %>'; @@ -78,7 +78,7 @@ describe('login modal', () => { cy.get(errorLoginSelector).should('be.visible'); }); - it('go to login page when successfully logs in', () => { + it('go to home page when successfully logs in', () => { cy.get(usernameLoginSelector).type(username); cy.get(passwordLoginSelector).type(password); cy.get(submitLoginSelector).click(); diff --git a/generators/cypress/templates/src/test/javascript/cypress/e2e/account/logout.cy.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/e2e/account/logout.cy.ts.ejs new file mode 100644 index 000000000000..dcf891b02419 --- /dev/null +++ b/generators/cypress/templates/src/test/javascript/cypress/e2e/account/logout.cy.ts.ejs @@ -0,0 +1,39 @@ +<%# + Copyright 2013-2024 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. +-%> +import { + accountMenuSelector, + navbarSelector, + loginItemSelector, +} from '../../support/commands'; + +describe('logout', () => { + const username = Cypress.env('E2E_USERNAME') ?? '<%- generateInMemoryUserCredentials ? 'admin' : 'user' %>'; + const password = Cypress.env('E2E_PASSWORD') ?? '<%- generateInMemoryUserCredentials ? 'admin' : 'user' %>'; + + it<%- clientFrameworkReact ? '.skip' : '' %>('go to home page when successfully logs out', () => { + cy.login(username, password); + cy.visit(''); + cy.clickOnLogoutItem(); + // Wait logout + cy.wait(500); // eslint-disable-line cypress/no-unnecessary-waiting + cy.visit(''); + cy.get(navbarSelector).get(accountMenuSelector).click(); + cy.get(navbarSelector).get(accountMenuSelector).get(loginItemSelector).should('be.visible'); + }); +}); diff --git a/generators/cypress/templates/src/test/javascript/cypress/e2e/entity/_entity_.cy.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/e2e/entity/_entity_.cy.ts.ejs index c1e7babd9760..94960c44f33e 100644 --- a/generators/cypress/templates/src/test/javascript/cypress/e2e/entity/_entity_.cy.ts.ejs +++ b/generators/cypress/templates/src/test/javascript/cypress/e2e/entity/_entity_.cy.ts.ejs @@ -52,7 +52,9 @@ describe('<%= entityClass %> e2e test', () => { const <%= entityInstance %>PageUrlPattern = new RegExp('/<%= entityPage %>(\\?.*)?$'); const username = Cypress.env('E2E_USERNAME') ?? '<%- adminEntity ? 'admin' : 'user' %>'; const password = Cypress.env('E2E_PASSWORD') ?? '<%- adminEntity ? 'admin' : 'user' %>'; +<%_ if (!readOnly) { _%> <% if (skipCreateTest) { %>// <% } %>const <%= entityInstance %>Sample = <%- JSON.stringify(this.generateTestEntity(sampleFields.map(field => field.reference))) %>; +<%_ } _%> let <%= entityInstance %>; <%_ for (otherEntity of requiredOtherEntities) { _%> @@ -179,7 +181,7 @@ describe('<%= entityClass %> e2e test', () => { <%_ } _%> describe('with existing value', () => { -<% if (!readOnly) { %> +<%_ if (!readOnly) { _%> <%_ if (skipCreateTest) { _%> /* Disabled due to incompatibility <%_ } _%> diff --git a/generators/cypress/templates/src/test/javascript/cypress/plugins/index.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/plugins/index.ts.ejs index 9fb8cc994b51..801c9195e29b 100644 --- a/generators/cypress/templates/src/test/javascript/cypress/plugins/index.ts.ejs +++ b/generators/cypress/templates/src/test/javascript/cypress/plugins/index.ts.ejs @@ -33,7 +33,7 @@ import { existsSync, mkdirSync, writeFileSync } from 'fs'; import { lighthouse, pa11y, prepareAudit } from 'cypress-audit'; <%_ } _%> -export default async (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => { +export default <% if (cypressCoverage) { %>async <% } %>(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => { on('before:browser:launch', (browser, launchOptions) => { <%_ if (cypressAudit) { _%> prepareAudit(launchOptions); @@ -60,7 +60,9 @@ export default async (on: Cypress.PluginEvents, config: Cypress.PluginConfigOpti on('task', { lighthouse: lighthouse(async (lighthouseReport) => { const { default: ReportGenerator } = await import('lighthouse/report/generator/report-generator'); - !existsSync('<%= cypressTemporaryDir %>') && mkdirSync('<%= cypressTemporaryDir %>', { recursive: true }); + if (!existsSync('<%= cypressTemporaryDir %>')) { + mkdirSync('<%= cypressTemporaryDir %>', { recursive: true }); + } writeFileSync('<%= cypressTemporaryDir %>lhreport.html', ReportGenerator.generateReport(lighthouseReport.lhr, 'html')); }), pa11y: pa11y(), diff --git a/generators/cypress/templates/src/test/javascript/cypress/support/account.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/support/account.ts.ejs index da5d3682b65d..769d6e2b9ede 100644 --- a/generators/cypress/templates/src/test/javascript/cypress/support/account.ts.ejs +++ b/generators/cypress/templates/src/test/javascript/cypress/support/account.ts.ejs @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-namespace */ export type Account = Record; Cypress.Commands.add('getAccount', () => { diff --git a/generators/cypress/templates/src/test/javascript/cypress/support/commands.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/support/commands.ts.ejs index 686fe0da4ec3..b17d938fb4ac 100644 --- a/generators/cypress/templates/src/test/javascript/cypress/support/commands.ts.ejs +++ b/generators/cypress/templates/src/test/javascript/cypress/support/commands.ts.ejs @@ -17,9 +17,6 @@ limitations under the License. -%> /* eslint-disable @typescript-eslint/no-namespace */ -/* eslint-disable @typescript-eslint/no-use-before-define */ -// eslint-disable-next-line spaced-comment -/// // *********************************************** // This commands.ts shows you how to diff --git a/generators/cypress/templates/src/test/javascript/cypress/support/entity.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/support/entity.ts.ejs index a2406a80b65b..9c7f8b5409e6 100644 --- a/generators/cypress/templates/src/test/javascript/cypress/support/entity.ts.ejs +++ b/generators/cypress/templates/src/test/javascript/cypress/support/entity.ts.ejs @@ -17,9 +17,6 @@ limitations under the License. -%> /* eslint-disable @typescript-eslint/no-namespace */ -/* eslint-disable @typescript-eslint/no-use-before-define */ -// eslint-disable-next-line spaced-comment -/// // *********************************************** // Begin Specific Selector Attributes for Cypress diff --git a/generators/cypress/templates/src/test/javascript/cypress/support/management.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/support/management.ts.ejs index 4e4612249011..93e0da07269f 100644 --- a/generators/cypress/templates/src/test/javascript/cypress/support/management.ts.ejs +++ b/generators/cypress/templates/src/test/javascript/cypress/support/management.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> /* eslint-disable @typescript-eslint/no-namespace */ -/* eslint-disable @typescript-eslint/no-use-before-define */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ Cypress.Commands.add('getManagementInfo', () => { return cy.request({ diff --git a/generators/cypress/templates/src/test/javascript/cypress/support/navbar.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/support/navbar.ts.ejs index 5604fa0782c5..355ce86f64ba 100644 --- a/generators/cypress/templates/src/test/javascript/cypress/support/navbar.ts.ejs +++ b/generators/cypress/templates/src/test/javascript/cypress/support/navbar.ts.ejs @@ -17,7 +17,6 @@ limitations under the License. -%> /* eslint-disable @typescript-eslint/no-namespace */ -/* eslint-disable @typescript-eslint/no-use-before-define */ import { navbarSelector, diff --git a/generators/cypress/templates/src/test/javascript/cypress/support/oauth2.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/support/oauth2.ts.ejs index eb3d3334ba8c..af1591fb00cd 100644 --- a/generators/cypress/templates/src/test/javascript/cypress/support/oauth2.ts.ejs +++ b/generators/cypress/templates/src/test/javascript/cypress/support/oauth2.ts.ejs @@ -16,8 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. -%> -// eslint-disable-next-line spaced-comment -/// +/* eslint-disable @typescript-eslint/no-namespace */ Cypress.Commands.add('getOauth2Data', () => { cy.request({ @@ -157,6 +156,7 @@ Cypress.Commands.add('oauthLogout', () => { declare global { namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars interface Chainable { getOauth2Data(): Cypress.Chainable; oauthLogin(oauth2Data, username: string, password: string): Cypress.Chainable; diff --git a/generators/docker-compose/__snapshots__/docker-compose.spec.ts.snap b/generators/docker-compose/__snapshots__/docker-compose.spec.ts.snap index fd20c85e92f0..7f14394a0e93 100644 --- a/generators/docker-compose/__snapshots__/docker-compose.spec.ts.snap +++ b/generators/docker-compose/__snapshots__/docker-compose.spec.ts.snap @@ -103,12 +103,12 @@ jhipster: - SPRING_R2DBC_URL=r2dbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_LIQUIBASE_URL=jdbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -128,7 +128,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -149,7 +149,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -294,12 +294,12 @@ jhipster: - SPRING_R2DBC_URL=r2dbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_LIQUIBASE_URL=jdbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -319,7 +319,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -339,7 +339,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -366,11 +366,13 @@ jhipster: test: - CMD - cqlsh - - '-e' + - -e - describe keyspaces interval: 5s timeout: 25s retries: 20 + labels: + org.springframework.boot.ignore: true consul: image: consul-placeholder @@ -547,12 +549,12 @@ jhipster: - SPRING_R2DBC_URL=r2dbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_LIQUIBASE_URL=jdbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -572,7 +574,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -592,7 +594,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -612,7 +614,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -633,7 +635,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -647,7 +649,7 @@ jhipster: image: postgresql-placeholder environment: - POSTGRES_USER=mspsql - - POSTGRES_PASSWORD= + - POSTGRES_PASSWORD=password - POSTGRES_HOST_AUTH_METHOD=trust healthcheck: test: @@ -666,7 +668,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:9200/_cluster/health?wait_for_status=green&timeout=10s interval: 5s timeout: 10s @@ -685,7 +687,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -699,11 +701,11 @@ jhipster: test: - CMD - echo - - '''db.runCommand("ping").ok''' - - '|' + - "'db.runCommand(\\"ping\\").ok'" + - "|" - mongo - localhost:27017/test - - '--quiet' + - --quiet interval: 5s timeout: 5s retries: 10 @@ -722,7 +724,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -736,14 +738,15 @@ jhipster: - ./config/mariadb:/etc/mariadb/conf.d environment: - MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=yes + - MARIADB_ALLOW_EMPTY_PASSWORD=yes - MARIADB_DATABASE=msmariadb command: mariadbd --lower_case_table_names=1 --character_set_server=utf8mb4 --explicit_defaults_for_timestamp healthcheck: test: - CMD - /usr/local/bin/healthcheck.sh - - '--connect' - - '--innodb_initialized' + - --connect + - --innodb_initialized interval: 5s timeout: 5s retries: 10 @@ -928,12 +931,12 @@ jhipster: - SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID=web_app - SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET=web_app ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -955,7 +958,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -978,7 +981,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1000,7 +1003,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -1024,7 +1027,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1040,7 +1043,7 @@ jhipster: image: postgresql-placeholder environment: - POSTGRES_USER=mspsql - - POSTGRES_PASSWORD= + - POSTGRES_PASSWORD=password - POSTGRES_HOST_AUTH_METHOD=trust healthcheck: test: @@ -1059,7 +1062,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:9200/_cluster/health?wait_for_status=green&timeout=10s interval: 5s timeout: 10s @@ -1083,7 +1086,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1103,7 +1106,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8091/ui/index.html interval: 5s timeout: 5s @@ -1126,7 +1129,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1142,14 +1145,15 @@ jhipster: - ./config/mariadb:/etc/mariadb/conf.d environment: - MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=yes + - MARIADB_ALLOW_EMPTY_PASSWORD=yes - MARIADB_DATABASE=msmariadb command: mariadbd --lower_case_table_names=1 --character_set_server=utf8mb4 --explicit_defaults_for_timestamp healthcheck: test: - CMD - /usr/local/bin/healthcheck.sh - - '--connect' - - '--innodb_initialized' + - --connect + - --innodb_initialized interval: 5s timeout: 5s retries: 10 @@ -1357,12 +1361,12 @@ jhipster: - SPRING_R2DBC_URL=r2dbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_LIQUIBASE_URL=jdbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -1382,7 +1386,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -1402,7 +1406,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1422,7 +1426,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -1443,7 +1447,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1457,7 +1461,7 @@ jhipster: image: postgresql-placeholder environment: - POSTGRES_USER=mspsql - - POSTGRES_PASSWORD= + - POSTGRES_PASSWORD=password - POSTGRES_HOST_AUTH_METHOD=trust healthcheck: test: @@ -1476,7 +1480,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:9200/_cluster/health?wait_for_status=green&timeout=10s interval: 5s timeout: 10s @@ -1495,7 +1499,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1692,12 +1696,12 @@ jhipster: - SPRING_R2DBC_URL=r2dbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_LIQUIBASE_URL=jdbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -1717,7 +1721,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -1737,7 +1741,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1757,7 +1761,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -1778,7 +1782,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1792,7 +1796,7 @@ jhipster: image: postgresql-placeholder environment: - POSTGRES_USER=mspsql - - POSTGRES_PASSWORD= + - POSTGRES_PASSWORD=password - POSTGRES_HOST_AUTH_METHOD=trust healthcheck: test: @@ -1811,7 +1815,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:9200/_cluster/health?wait_for_status=green&timeout=10s interval: 5s timeout: 10s @@ -1832,7 +1836,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1850,7 +1854,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8091/ui/index.html interval: 5s timeout: 5s @@ -1870,7 +1874,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -1884,14 +1888,15 @@ jhipster: - ./config/mariadb:/etc/mariadb/conf.d environment: - MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=yes + - MARIADB_ALLOW_EMPTY_PASSWORD=yes - MARIADB_DATABASE=msmariadb command: mariadbd --lower_case_table_names=1 --character_set_server=utf8mb4 --explicit_defaults_for_timestamp healthcheck: test: - CMD - /usr/local/bin/healthcheck.sh - - '--connect' - - '--innodb_initialized' + - --connect + - --innodb_initialized interval: 5s timeout: 5s retries: 10 @@ -2017,12 +2022,12 @@ jhipster: - SPRING_R2DBC_URL=r2dbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_LIQUIBASE_URL=jdbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -2042,7 +2047,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -2062,7 +2067,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -2082,7 +2087,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -2209,12 +2214,12 @@ jhipster: - SPRING_R2DBC_URL=r2dbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_LIQUIBASE_URL=jdbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -2234,7 +2239,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -2254,7 +2259,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -2274,7 +2279,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -2426,12 +2431,12 @@ management: - SPRING_R2DBC_URL=r2dbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_LIQUIBASE_URL=jdbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -2451,7 +2456,7 @@ management: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -2471,7 +2476,7 @@ management: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -2491,7 +2496,7 @@ management: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -2707,12 +2712,12 @@ jhipster: - SPRING_R2DBC_URL=r2dbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_LIQUIBASE_URL=jdbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -2732,7 +2737,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -2752,7 +2757,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -2772,7 +2777,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -2864,12 +2869,12 @@ Launch all your infrastructure by running: \`docker compose up -d\`. - SPRING_LIQUIBASE_URL=jdbc:mysql://samplemysql-mysql:3306/samplemysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_ELASTICSEARCH_URIS=http://samplemysql-elasticsearch:9200 ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -2891,7 +2896,7 @@ Launch all your infrastructure by running: \`docker compose up -d\`. test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -2906,7 +2911,7 @@ Launch all your infrastructure by running: \`docker compose up -d\`. test: - CMD - curl - - '-f' + - -f - http://localhost:9200/_cluster/health?wait_for_status=green&timeout=10s interval: 5s timeout: 10s @@ -3003,7 +3008,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -3023,7 +3028,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -3132,12 +3137,12 @@ jhipster: - SPRING_R2DBC_URL=r2dbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - SPRING_LIQUIBASE_URL=jdbc:mysql://jhgate-mysql:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s @@ -3157,7 +3162,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -3269,7 +3274,7 @@ jhipster: test: - CMD - curl - - '-f' + - -f - http://localhost:8081/management/health interval: 5s timeout: 5s @@ -3289,7 +3294,7 @@ jhipster: test: - CMD - mysql - - '-e' + - -e - SHOW DATABASES; interval: 5s timeout: 5s @@ -3378,12 +3383,12 @@ Launch all your infrastructure by running: \`docker compose up -d\`. - SPRING_DATASOURCE_URL=jdbc:oracle:thin:@oracle-mono-oracle:1521:oracle-mono - SPRING_LIQUIBASE_URL=jdbc:oracle:thin:@oracle-mono-oracle:1521:oracle-mono ports: - - '8080:8080' + - 8080:8080 healthcheck: test: - CMD - curl - - '-f' + - -f - http://localhost:8080/management/health interval: 5s timeout: 5s diff --git a/generators/docker-compose/command.ts b/generators/docker-compose/command.ts index d4cf73b0f409..ced0fd76c6b6 100644 --- a/generators/docker-compose/command.ts +++ b/generators/docker-compose/command.ts @@ -1,4 +1,4 @@ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { arguments: { @@ -7,7 +7,15 @@ const command: JHipsterCommandDefinition = { description: 'Application folders', }, }, - options: {}, + configs: { + jwtSecretKey: { + cli: { + type: String, + env: 'JHI_JWT_SECRET_KEY', + }, + scope: 'generator', + }, + }, }; export default command; diff --git a/generators/docker-compose/docker-compose.spec.ts b/generators/docker-compose/docker-compose.spec.ts index ae3ddf4cca04..30cab6b592df 100644 --- a/generators/docker-compose/docker-compose.spec.ts +++ b/generators/docker-compose/docker-compose.spec.ts @@ -1,8 +1,8 @@ -import { before, it, describe, expect } from 'esmocha'; -import monitoringTypes from '../../jdl/jhipster/monitoring-types.js'; -import applicationTypes from '../../jdl/jhipster/application-types.js'; +import { before, describe, expect, it } from 'esmocha'; +import monitoringTypes from '../../lib/jhipster/monitoring-types.js'; +import applicationTypes from '../../lib/jhipster/application-types.js'; import { GENERATOR_DOCKER_COMPOSE } from '../generator-list.js'; -import { defaultHelpers as helpers, getGenerator, runResult } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; const { PROMETHEUS } = monitoringTypes; const { MICROSERVICE, MONOLITH } = applicationTypes; @@ -17,24 +17,20 @@ const expectedFiles = { describe('generator - Docker Compose', () => { describe('only gateway', () => { - let runResult; const chosenApps = ['01-gateway']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - monitoring: NO_MONITORING, - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + monitoring: NO_MONITORING, + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -53,24 +49,20 @@ describe('generator - Docker Compose', () => { }); describe('only one microservice', () => { - let runResult; const chosenApps = ['02-mysql']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces() .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - monitoring: NO_MONITORING, - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + monitoring: NO_MONITORING, + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -89,24 +81,20 @@ describe('generator - Docker Compose', () => { }); describe('one microservice and a directory path without a trailing slash', () => { - let runResult; const chosenApps = ['02-mysql']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces() .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: '.', - appsFolders: chosenApps, - clusteredDbApps: [], - monitoring: NO_MONITORING, - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: '.', + appsFolders: chosenApps, + clusteredDbApps: [], + monitoring: NO_MONITORING, + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -127,16 +115,13 @@ describe('generator - Docker Compose', () => { .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - monitoring: NO_MONITORING, - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + monitoring: NO_MONITORING, + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -155,23 +140,19 @@ describe('generator - Docker Compose', () => { }); describe('gateway and one microservice', () => { - let runResult; const chosenApps = ['01-gateway', '02-mysql']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -193,23 +174,19 @@ describe('generator - Docker Compose', () => { }); describe('gateway and one microservice, with curator', () => { - let runResult; const chosenApps = ['01-gateway', '02-mysql']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -231,24 +208,20 @@ describe('generator - Docker Compose', () => { }); describe('gateway and one microservice, with prometheus', () => { - let runResult; const chosenApps = ['01-gateway', '02-mysql']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - monitoring: PROMETHEUS, - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + monitoring: PROMETHEUS, + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -270,23 +243,19 @@ describe('generator - Docker Compose', () => { }); describe('gateway and multi microservices', () => { - let runResult; const chosenApps = ['01-gateway', '02-mysql', '03-psql', '04-mongo', '07-mariadb']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -305,23 +274,19 @@ describe('generator - Docker Compose', () => { }); describe('gateway and multi microservices, with 1 mongodb cluster', () => { - let runResult; const chosenApps = ['01-gateway', '02-mysql', '03-psql', '04-mongo']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: ['04-mongo'], - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: ['04-mongo'], + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -340,23 +305,19 @@ describe('generator - Docker Compose', () => { }); describe('gateway and 1 microservice, with Cassandra', () => { - let runResult; const chosenApps = ['01-gateway', '05-cassandra']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -375,23 +336,19 @@ describe('generator - Docker Compose', () => { }); describe('monolith', () => { - let runResult; const chosenApps = ['08-monolith']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces() .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MONOLITH, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MONOLITH, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -407,23 +364,19 @@ describe('generator - Docker Compose', () => { }); describe('gateway and multi microservices using oauth2', () => { - let runResult; const chosenApps = ['01-gateway', '02-mysql', '03-psql', '10-couchbase', '07-mariadb']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ authenticationType: 'oauth2' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot({ @@ -447,23 +400,19 @@ describe('generator - Docker Compose', () => { }); describe('gateway and multi microservices, with couchbase', () => { - let runResult; const chosenApps = ['01-gateway', '02-mysql', '03-psql', '10-couchbase', '07-mariadb']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -482,23 +431,19 @@ describe('generator - Docker Compose', () => { }); describe('gateway and 1 microservice, with 1 couchbase cluster', () => { - let runResult; const chosenApps = ['01-gateway', '10-couchbase']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MICROSERVICE, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: ['10-couchbase'], - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MICROSERVICE, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: ['10-couchbase'], + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -517,24 +462,20 @@ describe('generator - Docker Compose', () => { }); describe('oracle monolith', () => { - let runResult; const chosenApps = ['12-oracle']; before(async () => { - runResult = await helpers + await helpers .generateDeploymentWorkspaces() .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_DOCKER_COMPOSE)) - .withAnswers({ - deploymentApplicationType: MONOLITH, - directoryPath: './', - appsFolders: chosenApps, - clusteredDbApps: [], - monitoring: NO_MONITORING, - }) - .run(); + await helpers.runJHipsterInApplication(GENERATOR_DOCKER_COMPOSE).withAnswers({ + deploymentApplicationType: MONOLITH, + directoryPath: './', + appsFolders: chosenApps, + clusteredDbApps: [], + monitoring: NO_MONITORING, + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); diff --git a/generators/docker-compose/files.js b/generators/docker-compose/files.ts similarity index 96% rename from generators/docker-compose/files.js rename to generators/docker-compose/files.ts index 1c2bfaa04102..71eb8d702a01 100644 --- a/generators/docker-compose/files.js +++ b/generators/docker-compose/files.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,13 +17,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { applicationTypes, authenticationTypes, monitoringTypes } from '../../jdl/jhipster/index.js'; +import { applicationTypes, authenticationTypes, monitoringTypes } from '../../lib/jhipster/index.js'; const { PROMETHEUS } = monitoringTypes; const { MICROSERVICE } = applicationTypes; const { OAUTH2 } = authenticationTypes; -// eslint-disable-next-line import/prefer-default-export export function writeFiles() { return { cleanup() { diff --git a/generators/kubernetes-knative/generator.spec.js b/generators/docker-compose/generator.spec.ts similarity index 96% rename from generators/kubernetes-knative/generator.spec.js rename to generators/docker-compose/generator.spec.ts index b25895cf89f4..d90bf385002d 100644 --- a/generators/kubernetes-knative/generator.spec.js +++ b/generators/docker-compose/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures } from '../../test/support/tests.js'; diff --git a/generators/docker-compose/generator.js b/generators/docker-compose/generator.ts similarity index 91% rename from generators/docker-compose/generator.js rename to generators/docker-compose/generator.ts index 17bf0692b875..b6b1845bf032 100644 --- a/generators/docker-compose/generator.js +++ b/generators/docker-compose/generator.ts @@ -19,15 +19,15 @@ import { existsSync } from 'fs'; import pathjs from 'path'; import chalk from 'chalk'; -import jsyaml from 'js-yaml'; +import { parse as parseYaml, stringify as stringifyYaml } from 'yaml'; import normalize from 'normalize-path'; import { defaults } from 'lodash-es'; import BaseWorkspacesGenerator from '../base-workspaces/index.js'; -import { deploymentOptions, monitoringTypes, serviceDiscoveryTypes } from '../../jdl/jhipster/index.js'; +import { deploymentOptions, monitoringTypes, serviceDiscoveryTypes } from '../../lib/jhipster/index.js'; import { GENERATOR_BOOTSTRAP_WORKSPACES } from '../generator-list.js'; -import { stringHashCode, createFaker, convertSecretToBase64, createBase64Secret } from '../base/support/index.js'; +import { convertSecretToBase64, createBase64Secret, createFaker, stringHashCode } from '../base/support/index.js'; import { checkDocker } from '../base-workspaces/internal/docker-base.js'; import { loadDockerDependenciesTask } from '../base-workspaces/internal/index.js'; import { loadDerivedPlatformConfig, loadPlatformConfig } from '../server/support/index.js'; @@ -38,17 +38,17 @@ const { PROMETHEUS, NO: NO_MONITORING } = monitoringTypes; const { CONSUL, EUREKA, NO: NO_SERVICE_DISCOVERY } = serviceDiscoveryTypes; const { Options: DeploymentOptions } = deploymentOptions; -/* eslint-disable consistent-return */ /** * @class * @extends {import('../base/index.js')} */ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { existingDeployment; + jwtSecretKey!: string; async beforeQueue() { this.parseJHipsterArguments(command.arguments); - if (this.appsFolders?.length > 0) { + if (this.appsFolders && this.appsFolders.length > 0) { this.jhipsterConfig.appsFolders = this.appsFolders; } @@ -59,7 +59,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { } get initializing() { - return { + return this.asInitializingTaskGroup({ sayHello() { this.log.log(chalk.white(`${chalk.bold('🐳')} Welcome to the JHipster Docker Compose Sub-Generator ${chalk.bold('🐳')}`)); this.log.log(chalk.white(`Files will be generated in folder: ${chalk.yellow(this.destinationRoot())}`)); @@ -75,7 +75,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { `); } }, - }; + }); } get [BaseWorkspacesGenerator.INITIALIZING]() { @@ -83,11 +83,11 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { } get loading() { - return { + return this.asLoadingTaskGroup({ loadWorkspacesConfig() { this.loadWorkspacesConfig(); }, - }; + }); } get [BaseWorkspacesGenerator.LOADING]() { @@ -95,7 +95,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { } get promptingWorkspaces() { - return { + return this.asAnyTaskGroup({ async askForMonitoring({ workspaces }) { if (workspaces.existingWorkspaces && !this.options.askAnswered) return; @@ -111,7 +111,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { await this.askForServiceDiscovery({ applications }); }, - }; + }); } get [BaseWorkspacesGenerator.PROMPTING_WORKSPACES]() { @@ -119,14 +119,15 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { } get configuringWorkspaces() { - return { + return this.asAnyTaskGroup({ configureBaseDeployment({ applications }) { - this.jhipsterConfig.jwtSecretKey = this.jhipsterConfig.jwtSecretKey ?? createBase64Secret(this.options.reproducibleTests); + this.jhipsterConfig.jwtSecretKey = + this.jhipsterConfig.jwtSecretKey ?? this.jwtSecretKey ?? createBase64Secret(this.options.reproducibleTests); if (applications.some(app => app.serviceDiscoveryEureka)) { this.jhipsterConfig.adminPassword = this.jhipsterConfig.adminPassword ?? 'admin'; } }, - }; + }); } get [BaseWorkspacesGenerator.CONFIGURING_WORKSPACES]() { @@ -134,16 +135,16 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { } get loadingWorkspaces() { - return { - loadBaseDeployment({ deployment }) { + return this.asAnyTaskGroup({ + async loadBaseDeployment({ deployment }) { deployment.jwtSecretKey = this.jhipsterConfig.jwtSecretKey; - loadDockerDependenciesTask.call(this, { context: deployment }); + await loadDockerDependenciesTask.call(this, { context: deployment }); }, loadPlatformConfig({ deployment }) { this.loadDeploymentConfig({ deployment }); }, - }; + }); } get [BaseWorkspacesGenerator.LOADING_WORKSPACES]() { @@ -151,11 +152,11 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { } get preparingWorkspaces() { - return { + return this.asAnyTaskGroup({ prepareDeployment({ deployment, applications }) { this.prepareDeploymentDerivedProperties({ deployment, applications }); }, - }; + }); } get [BaseWorkspacesGenerator.PREPARING_WORKSPACES]() { @@ -163,7 +164,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { } get default() { - return { + return this.asAnyTaskGroup({ async setAppsYaml({ workspaces, deployment, applications }) { const faker = await createFaker(); @@ -174,7 +175,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { const parentConfiguration = {}; const path = this.destinationPath(workspaces.directoryPath, appConfig.appFolder); // Add application configuration - const yaml = jsyaml.load(this.fs.read(`${path}/src/main/docker/app.yml`)); + const yaml = parseYaml(this.fs.read(`${path}/src/main/docker/app.yml`)!); const yamlConfig = yaml.services.app; if (yamlConfig.depends_on) { yamlConfig.depends_on = Object.fromEntries( @@ -253,7 +254,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { if (appConfig.databaseTypeAny && !appConfig.prodDatabaseTypeOracle) { const database = appConfig.databaseTypeSql ? appConfig.prodDatabaseType : appConfig.databaseType; const relativePath = normalize(pathjs.relative(this.destinationRoot(), `${path}/src/main/docker`)); - const databaseYaml = jsyaml.load(this.fs.read(`${path}/src/main/docker/${database}.yml`)); + const databaseYaml = parseYaml(this.fs.read(`${path}/src/main/docker/${database}.yml`)!); const databaseServiceName = `${lowercaseBaseName}-${database}`; let databaseYamlConfig = databaseYaml.services[database]; // Don't export database ports @@ -261,7 +262,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { if (appConfig.databaseTypeCassandra) { // migration service config - const cassandraMigrationYaml = jsyaml.load(this.fs.read(`${path}/src/main/docker/cassandra-migration.yml`)); + const cassandraMigrationYaml = parseYaml(this.fs.read(`${path}/src/main/docker/cassandra-migration.yml`)!); const cassandraMigrationConfig = cassandraMigrationYaml.services[`${database}-migration`]; cassandraMigrationConfig.build.context = relativePath; const cqlFilesRelativePath = normalize(pathjs.relative(this.destinationRoot(), `${path}/src/main/resources/config/cql`)); @@ -275,7 +276,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { } if (appConfig.clusteredDb) { - const clusterDbYaml = jsyaml.load(this.fs.read(`${path}/src/main/docker/${database}-cluster.yml`)); + const clusterDbYaml = parseYaml(this.fs.read(`${path}/src/main/docker/${database}-cluster.yml`)!); const dbNodeConfig = clusterDbYaml.services[`${database}-node`]; dbNodeConfig.build.context = relativePath; databaseYamlConfig = clusterDbYaml.services[database]; @@ -294,14 +295,14 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { if (appConfig.searchEngineElasticsearch) { // Add search engine configuration const searchEngine = appConfig.searchEngine; - const searchEngineYaml = jsyaml.load(this.fs.read(`${path}/src/main/docker/${searchEngine}.yml`)); + const searchEngineYaml = parseYaml(this.fs.read(`${path}/src/main/docker/${searchEngine}.yml`)!); const searchEngineConfig = searchEngineYaml.services[searchEngine]; delete searchEngineConfig.ports; parentConfiguration[`${lowercaseBaseName}-${searchEngine}`] = searchEngineConfig; } // Add Memcached support if (appConfig.cacheProviderMemcached) { - const memcachedYaml = jsyaml.load(this.readDestination(`${path}/src/main/docker/memcached.yml`)); + const memcachedYaml = parseYaml(this.readDestination(`${path}/src/main/docker/memcached.yml`)!.toString()); const memcachedConfig = memcachedYaml.services.memcached; delete memcachedConfig.ports; parentConfiguration[`${lowercaseBaseName}-memcached`] = memcachedConfig; @@ -309,7 +310,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { // Add Redis support if (appConfig.cacheProviderRedis) { - const redisYaml = jsyaml.load(this.readDestination(`${path}/src/main/docker/redis.yml`)); + const redisYaml = parseYaml(this.readDestination(`${path}/src/main/docker/redis.yml`)!.toString()); const redisConfig = redisYaml.services.redis; delete redisConfig.ports; parentConfiguration[`${lowercaseBaseName}-redis`] = redisConfig; @@ -318,7 +319,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { deployment.authenticationType = appConfig.authenticationType; // Dump the file - let yamlString = jsyaml.dump(parentConfiguration, { indent: 2, lineWidth: -1 }); + let yamlString = stringifyYaml(parentConfiguration, { indent: 2, lineWidth: 0 }); // Add extra indentation for each lines const yamlArray = yamlString.split('\n'); @@ -329,7 +330,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { return yamlString; }); }, - }; + }); } get [BaseWorkspacesGenerator.DEFAULT]() { @@ -345,7 +346,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { } get end() { - return { + return this.asAnyTaskGroup({ end({ workspaces, applications }) { this.checkApplicationsDockerImages({ workspaces, applications }); @@ -361,7 +362,7 @@ export default class DockerComposeGenerator extends BaseWorkspacesGenerator { this.log.log('\n'); } }, - }; + }); } get [BaseWorkspacesGenerator.END]() { diff --git a/generators/docker/__test-support/service-discovery-matcher.ts b/generators/docker/__test-support/service-discovery-matcher.ts index c43e4b5b30c6..2ec97ee5e164 100644 --- a/generators/docker/__test-support/service-discovery-matcher.ts +++ b/generators/docker/__test-support/service-discovery-matcher.ts @@ -1,7 +1,7 @@ -import type { RunResult } from 'yeoman-test'; +import { it } from 'esmocha'; import { JAVA_DOCKER_DIR } from '../../generator-constants.js'; -import { matchWrittenConfig, matchWrittenFiles } from '../../../testing/index.js'; +import { matchWrittenConfig, matchWrittenFiles } from '../../../lib/testing/index.js'; const expectedEurekaFiles = () => { return [ @@ -31,12 +31,12 @@ const desiredConsulConfig = { }, }; -export const matchEureka = (resultGetter: () => RunResult, shouldMatch: boolean) => { - matchWrittenFiles('eureka', resultGetter, expectedEurekaFiles, shouldMatch); - matchWrittenConfig('eureka', resultGetter, desiredEurekaConfig, shouldMatch); +export const matchEureka = (shouldMatch: boolean) => { + it(...matchWrittenFiles('eureka', expectedEurekaFiles, shouldMatch)); + it(...matchWrittenConfig('eureka', desiredEurekaConfig, shouldMatch)); }; -export const matchConsul = (resultGetter: () => RunResult, shouldMatch: boolean) => { - matchWrittenFiles('consul', resultGetter, expectedConsulFiles, shouldMatch); - matchWrittenConfig('consul', resultGetter, desiredConsulConfig, shouldMatch); +export const matchConsul = (shouldMatch: boolean) => { + it(...matchWrittenFiles('consul', expectedConsulFiles, shouldMatch)); + it(...matchWrittenConfig('consul', desiredConsulConfig, shouldMatch)); }; diff --git a/generators/docker/constants.js b/generators/docker/constants.ts similarity index 100% rename from generators/docker/constants.js rename to generators/docker/constants.ts diff --git a/generators/docker/files.js b/generators/docker/files.ts similarity index 99% rename from generators/docker/files.js rename to generators/docker/files.ts index ba00e1ef0b48..3abff2b75785 100644 --- a/generators/docker/files.js +++ b/generators/docker/files.ts @@ -2,7 +2,6 @@ import { TEMPLATES_DOCKER_DIR } from '../generator-constants.js'; const renameTo = (ctx, filepath) => `${ctx.dockerServicesDir}${filepath}`.replace('/_eureka_', '').replace('/_consul_', ''); -// eslint-disable-next-line import/prefer-default-export export const dockerFiles = { commonFiles: [ { diff --git a/generators/docker/generator.spec.ts b/generators/docker/generator.spec.ts index 0912712d9768..356c2a197312 100644 --- a/generators/docker/generator.spec.ts +++ b/generators/docker/generator.spec.ts @@ -16,23 +16,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { buildSamplesFromMatrix, + buildServerMatrix, extendFilteredMatrix, extendMatrix, defaultHelpers as helpers, runResult, - buildServerMatrix, -} from '../../testing/index.js'; +} from '../../lib/testing/index.js'; import { matchElasticSearchDocker } from '../spring-data-elasticsearch/__test-support/elastic-search-matcher.js'; -import { databaseTypes, searchEngineTypes, serviceDiscoveryTypes, cacheTypes } from '../../jdl/jhipster/index.js'; -import { MESSAGE_BROKER_KAFKA, MESSAGE_BROKER_NO, MESSAGE_BROKER_PULSAR } from '../server/options/message-broker.js'; +import { cacheTypes, databaseTypes, searchEngineTypes, serviceDiscoveryTypes } from '../../lib/jhipster/index.js'; import { shouldSupportFeatures } from '../../test/support/tests.js'; import { matchConsul, matchEureka } from './__test-support/service-discovery-matcher.js'; import Generator from './index.js'; @@ -46,7 +45,6 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorFile = join(__dirname, 'index.ts'); const NO_SQL = [CASSANDRA, COUCHBASE, MONGODB, NEO4J]; @@ -56,7 +54,6 @@ matrix = extendMatrix(matrix, { prodDatabaseType: [POSTGRESQL, MARIADB, MYSQL, MSSQL, ORACLE, ...NO_SQL], }); -// eslint-disable-next-line @typescript-eslint/no-unused-vars Object.entries(matrix).forEach(([_name, config]) => { if (NO_SQL.includes(config.prodDatabaseType)) { config.databaseType = config.prodDatabaseType; @@ -68,7 +65,7 @@ matrix = extendMatrix(matrix, { searchEngine: [NO_SEARCH_ENGINE, ELASTICSEARCH], serviceDiscoveryType: [NO_SERVICE_DISCOVERY, EUREKA, CONSUL], enableSwaggerCodegen: [false, true], - messageBroker: [MESSAGE_BROKER_NO, MESSAGE_BROKER_KAFKA, MESSAGE_BROKER_PULSAR], + messageBroker: ['no', 'kafka', 'pulsar'], }); matrix = extendFilteredMatrix(matrix, ({ reactive }) => !reactive, { @@ -88,7 +85,7 @@ describe(`generator - ${generator}`, () => { describe(name, () => { before(async () => { - await helpers.run(generatorFile).withJHipsterConfig(sampleConfig); + await helpers.runJHipster(generator).withJHipsterConfig(sampleConfig); }); it('should match generated files snapshot', () => { @@ -99,18 +96,18 @@ describe(`generator - ${generator}`, () => { }); describe('searchEngine', () => { const elasticsearch = searchEngine === ELASTICSEARCH; - matchElasticSearchDocker(() => runResult, elasticsearch); + matchElasticSearchDocker(elasticsearch); }); describe('serviceDiscoveryType', () => { - matchEureka(() => runResult, serviceDiscoveryType === EUREKA); - matchConsul(() => runResult, serviceDiscoveryType === CONSUL); + matchEureka(serviceDiscoveryType === EUREKA); + matchConsul(serviceDiscoveryType === CONSUL); }); }); describe(`custom path for ${name}`, () => { before(async () => { await helpers - .run(generatorFile) + .runJHipster(generator) .withSharedApplication({ dockerServicesDir: 'foo/', }) diff --git a/generators/docker/generator.js b/generators/docker/generator.ts similarity index 92% rename from generators/docker/generator.js rename to generators/docker/generator.ts index 08daf0989f29..664d62264c67 100644 --- a/generators/docker/generator.js +++ b/generators/docker/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,11 +17,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable camelcase */ + import { intersection } from 'lodash-es'; import BaseApplicationGenerator from '../base-application/index.js'; import { createDockerComposeFile, createDockerExtendedServices } from '../docker/support/index.js'; -import { stringHashCode, createFaker } from '../base/support/index.js'; +import { createFaker, stringHashCode } from '../base/support/index.js'; import { getJdbcUrl, getR2dbcUrl } from '../spring-data-relational/support/index.js'; import { dockerFiles } from './files.js'; import { SERVICE_COMPLETED_SUCCESSFULLY, SERVICE_HEALTHY } from './constants.js'; @@ -119,6 +120,11 @@ export default class DockerGenerator extends BaseApplicationGenerator { this.mergeDestinationYaml(`${application.dockerServicesDir}services.yml`, extendedServices); }; + source.addDockerExtendedServiceToApplication = (...services) => { + const extendedServices = createDockerExtendedServices(...services); + this.mergeDestinationYaml(`${application.dockerServicesDir}app.yml`, extendedServices); + }; + source.addDockerDependencyToApplication = (...services) => { this.mergeDestinationYaml(`${application.dockerServicesDir}app.yml`, { services: { @@ -178,8 +184,16 @@ export default class DockerGenerator extends BaseApplicationGenerator { ); } + for (const serviceName of intersection(['postgresql', 'mysql', 'mariadb', 'mssql'], application.dockerServices)) { + // Blank profile services starts if no profile is passed. + const profiles = application.prodDatabaseType === application.devDatabaseType ? undefined : ['', 'prod']; + source.addDockerExtendedServiceToApplication({ serviceName }); + source.addDockerExtendedServiceToServices({ serviceName, additionalConfig: { profiles } }); + source.addDockerDependencyToApplication({ serviceName, condition: SERVICE_HEALTHY }); + } + for (const serviceName of intersection( - ['couchbase', 'mongodb', 'neo4j', 'postgresql', 'mysql', 'mariadb', 'mssql', 'elasticsearch', 'keycloak'], + ['couchbase', 'mongodb', 'neo4j', 'elasticsearch', 'keycloak'], application.dockerServices, )) { source.addDockerExtendedServiceToApplicationAndServices({ serviceName }); diff --git a/generators/docker/support/check-docker.js b/generators/docker/support/check-docker.ts similarity index 93% rename from generators/docker/support/check-docker.js rename to generators/docker/support/check-docker.ts index 9027cafbb7c6..fcb0766670ad 100644 --- a/generators/docker/support/check-docker.js +++ b/generators/docker/support/check-docker.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -17,12 +18,13 @@ * limitations under the License. */ import chalk from 'chalk'; +import type CoreGenerator from '../../base-core/generator.js'; /** * Check that Docker exists. * @this {import('../../base-core/index.js').default} */ -export const checkDocker = async function () { +export const checkDocker = async function (this: CoreGenerator) { if (this.abort || this.skipChecks) return; const ret = await this.spawnCommand('docker -v', { reject: false, stdio: 'pipe' }); if (ret.exitCode !== 0) { diff --git a/generators/docker/support/docker-compose-file.spec.ts b/generators/docker/support/docker-compose-file.spec.ts index 2f3cc1fe68cd..fca234be36de 100644 --- a/generators/docker/support/docker-compose-file.spec.ts +++ b/generators/docker/support/docker-compose-file.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { createDockerComposeFile } from './docker-compose-file.js'; describe('generator - docker - docker-compose-file', () => { diff --git a/generators/docker/support/docker-compose-file.js b/generators/docker/support/docker-compose-file.ts similarity index 100% rename from generators/docker/support/docker-compose-file.js rename to generators/docker/support/docker-compose-file.ts diff --git a/generators/docker/templates/docker/cassandra.yml.ejs b/generators/docker/templates/docker/cassandra.yml.ejs index 4c502790997d..d7eca68c57a8 100644 --- a/generators/docker/templates/docker/cassandra.yml.ejs +++ b/generators/docker/templates/docker/cassandra.yml.ejs @@ -37,6 +37,10 @@ services: interval: 5s timeout: 25s retries: 20 +<%_ if (backendTypeSpringBoot) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> cassandra-migration: environment: - CASSANDRA_CONTACT_POINT=<%= baseName.toLowerCase() %>-cassandra @@ -48,3 +52,7 @@ services: dockerfile: cassandra/Cassandra-Migration.Dockerfile volumes: - ../resources/config/cql:/cql:ro +<%_ if (backendTypeSpringBoot) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> diff --git a/generators/docker/templates/docker/consul.yml.ejs b/generators/docker/templates/docker/consul.yml.ejs index 90b9079bad33..39516c46f6ad 100644 --- a/generators/docker/templates/docker/consul.yml.ejs +++ b/generators/docker/templates/docker/consul.yml.ejs @@ -28,6 +28,10 @@ services: - 127.0.0.1:8500:8500 - 127.0.0.1:8600:8600 command: consul agent -dev -ui -client 0.0.0.0 -log-level=INFO +<%_ if (backendTypeSpringBoot) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> consul-config-loader: image: <%- dockerContainers.consulConfigLoader %> @@ -41,3 +45,7 @@ services: # as configured in central-server-config/git2consul.json # Also set SPRING_CLOUD_CONSUL_CONFIG_FORMAT=files on your apps # - CONFIG_MODE=git +<%_ if (backendTypeSpringBoot) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> diff --git a/generators/docker/templates/docker/jhipster-registry.yml.ejs b/generators/docker/templates/docker/jhipster-registry.yml.ejs index eb30e260ae88..0c73a83fa195 100644 --- a/generators/docker/templates/docker/jhipster-registry.yml.ejs +++ b/generators/docker/templates/docker/jhipster-registry.yml.ejs @@ -52,3 +52,7 @@ services: interval: 5s timeout: 5s retries: 20 +<%_ if (backendTypeSpringBoot) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> diff --git a/generators/docker/templates/docker/kafka.yml.ejs b/generators/docker/templates/docker/kafka.yml.ejs index 9167a0cd90b1..af20c2ddcc1d 100644 --- a/generators/docker/templates/docker/kafka.yml.ejs +++ b/generators/docker/templates/docker/kafka.yml.ejs @@ -33,8 +33,16 @@ services: KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 KAFKA_ADVERTISED_HOST_NAME: kafka +<%_ if (backendTypeSpringBoot) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> zookeeper: image: <%- dockerContainers.zookeeper %> environment: ZOOKEEPER_CLIENT_PORT: 2181 ZOOKEEPER_TICK_TIME: 2000 +<%_ if (backendTypeSpringBoot) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> diff --git a/generators/docker/templates/docker/keycloak.yml.ejs b/generators/docker/templates/docker/keycloak.yml.ejs index 6a29e6aa2f09..8b3153b57b27 100644 --- a/generators/docker/templates/docker/keycloak.yml.ejs +++ b/generators/docker/templates/docker/keycloak.yml.ejs @@ -43,5 +43,10 @@ services: test: 'bash /opt/keycloak/health-check.sh' interval: 5s timeout: 5s - retries: 40 + # Increased retries due to slow Keycloak startup in GitHub Actions using MacOS + retries: 50 start_period: 10s +<%_ if (backendTypeSpringBoot) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> diff --git a/generators/docker/templates/docker/mariadb.yml.ejs b/generators/docker/templates/docker/mariadb.yml.ejs index 97bfba19f933..c3d597aeef0a 100644 --- a/generators/docker/templates/docker/mariadb.yml.ejs +++ b/generators/docker/templates/docker/mariadb.yml.ejs @@ -27,7 +27,11 @@ services: # - ~/volumes/jhipster/<%= baseName %>/mariadb/:/var/lib/mariadb/ environment: - MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=yes + - MARIADB_ALLOW_EMPTY_PASSWORD=yes - MARIADB_DATABASE=<%= baseName.toLowerCase() %> +<%_ if (prodDatabasePassword) { _%> + - MARIADB_PASSWORD=<%- prodDatabasePassword %> +<%_ } _%> # If you want to expose these ports outside your dev PC, # remove the "127.0.0.1:" prefix ports: @@ -38,3 +42,7 @@ services: interval: 5s timeout: 5s retries: 10 +<%_ if (backendTypeSpringBoot && reactive) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> diff --git a/generators/docker/templates/docker/memcached.yml.ejs b/generators/docker/templates/docker/memcached.yml.ejs index 7f85299291e9..ef38fd338244 100644 --- a/generators/docker/templates/docker/memcached.yml.ejs +++ b/generators/docker/templates/docker/memcached.yml.ejs @@ -25,3 +25,7 @@ services: # remove the "127.0.0.1:" prefix ports: - 127.0.0.1:11211:11211 +<%_ if (backendTypeSpringBoot) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> diff --git a/generators/docker/templates/docker/mysql.yml.ejs b/generators/docker/templates/docker/mysql.yml.ejs index 8f6855b6fd32..964a78d8e439 100644 --- a/generators/docker/templates/docker/mysql.yml.ejs +++ b/generators/docker/templates/docker/mysql.yml.ejs @@ -26,6 +26,9 @@ services: environment: - MYSQL_ALLOW_EMPTY_PASSWORD=yes - MYSQL_DATABASE=<%= baseName.toLowerCase() %> +<%_ if (prodDatabasePassword) { _%> + - MYSQL_PASSWORD=<%- prodDatabasePassword %> +<%_ } _%> # If you want to expose these ports outside your dev PC, # remove the "127.0.0.1:" prefix ports: diff --git a/generators/docker/templates/docker/postgresql.yml.ejs b/generators/docker/templates/docker/postgresql.yml.ejs index f0446263385a..3755c8f8d70b 100644 --- a/generators/docker/templates/docker/postgresql.yml.ejs +++ b/generators/docker/templates/docker/postgresql.yml.ejs @@ -25,7 +25,9 @@ services: # - ~/volumes/jhipster/<%= baseName %>/postgresql/:/var/lib/postgresql/data/ environment: - POSTGRES_USER=<%= baseName %> - - POSTGRES_PASSWORD= +<%_ if (prodDatabasePassword) { _%> + - POSTGRES_PASSWORD=<%- prodDatabasePassword %> +<%_ } _%> - POSTGRES_HOST_AUTH_METHOD=trust healthcheck: test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER}'] diff --git a/generators/docker/templates/docker/pulsar.yml.ejs b/generators/docker/templates/docker/pulsar.yml.ejs index 98d8a0fff68d..8959e34c7559 100644 --- a/generators/docker/templates/docker/pulsar.yml.ejs +++ b/generators/docker/templates/docker/pulsar.yml.ejs @@ -29,3 +29,7 @@ services: environment: PULSAR_MEM: " -Xms512m -Xmx512m -XX:MaxDirectMemorySize=1g" command: bin/pulsar standalone +<%_ if (backendTypeSpringBoot) { _%> + labels: + org.springframework.boot.ignore: true +<%_ } _%> diff --git a/generators/docker/templates/eslint.config.js.jhi.docker.ejs b/generators/docker/templates/eslint.config.js.jhi.docker.ejs index 29c527bc5d0c..2ff48d70bd5c 100644 --- a/generators/docker/templates/eslint.config.js.jhi.docker.ejs +++ b/generators/docker/templates/eslint.config.js.jhi.docker.ejs @@ -17,5 +17,5 @@ limitations under the License. -%> <&_ if (fragment.configSection) { -&> - { files: ['**/*.js'], ignores: ['<%- dockerServicesDir %>'] }, + { ignores: ['<%- dockerServicesDir %>'] }, <&_ } -&> diff --git a/generators/docker/utils.js b/generators/docker/utils.ts similarity index 94% rename from generators/docker/utils.js rename to generators/docker/utils.ts index 682566eb9858..73a378d19ead 100644 --- a/generators/docker/utils.js +++ b/generators/docker/utils.ts @@ -34,7 +34,7 @@ export function getDockerfileContainers(dockerfileContent) { let alias; if (instruction.getKeyword() === 'FROM') { imageWithTag = instruction.getArgumentsContent(); - const split = instruction.getArgumentsContent().split(':'); + const split = instruction.getArgumentsContent()!.split(':'); image = split[0]; tag = split[1]; containers[image] = imageWithTag; @@ -43,7 +43,7 @@ export function getDockerfileContainers(dockerfileContent) { alias = camelCase(image); } } else if (instruction.getKeyword() === 'LABEL') { - const split = instruction.getArgumentsContent().split('='); + const split = instruction.getArgumentsContent()!.split('='); if (split[0].toUpperCase() === 'ALIAS') { alias = camelCase(split[1]); } diff --git a/generators/entities/__snapshots__/generator.spec.ts.snap b/generators/entities/__snapshots__/generator.spec.ts.snap index 40919b37c45a..a8f1244a7fcc 100644 --- a/generators/entities/__snapshots__/generator.spec.ts.snap +++ b/generators/entities/__snapshots__/generator.spec.ts.snap @@ -355,11 +355,13 @@ exports[`generator - entities regenerating all entities should match source call "addEntitiesToClient": [ { "application": "Application[jhipster]", + "control": "TaskParameter[control]", "entities": [ "Entity[Foo]", "Entity[Bar]", "Entity[Skip]", ], + "source": "TaskParameter[source]", }, ], "addEntityToCache": [ @@ -672,10 +674,12 @@ exports[`generator - entities regenerating some entities should match source cal "addEntitiesToClient": [ { "application": "Application[jhipster]", + "control": "TaskParameter[control]", "entities": [ "Entity[Foo]", "Entity[Bar]", ], + "source": "TaskParameter[source]", }, ], "addEntityToCache": [ diff --git a/generators/entities/command.ts b/generators/entities/command.ts index a79afc6e9c16..a0a13c51e7f3 100644 --- a/generators/entities/command.ts +++ b/generators/entities/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import serverCommand from '../server/command.js'; const command: JHipsterCommandDefinition = { diff --git a/generators/entities/generator.spec.ts b/generators/entities/generator.spec.ts index 94cb19108dad..0546950c60c4 100644 --- a/generators/entities/generator.spec.ts +++ b/generators/entities/generator.spec.ts @@ -18,18 +18,17 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { SERVER_MAIN_RES_DIR, SERVER_MAIN_SRC_DIR, CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; +import { CLIENT_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR, SERVER_MAIN_SRC_DIR } from '../generator-constants.js'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { skipPrettierHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import Generator from './generator.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorPath = `${__dirname}/index.ts`; describe(`generator - ${generator}`, () => { it('generator-list constant matches folder name', async () => { @@ -75,7 +74,7 @@ describe(`generator - ${generator}`, () => { describe('some entities', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({}, entities) .withArguments(['Foo', 'Bar']) .withOptions({ @@ -110,7 +109,7 @@ describe(`generator - ${generator}`, () => { describe('all entities', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({}, entities) .withOptions({ regenerate: true, diff --git a/generators/entities/generator.js b/generators/entities/generator.ts similarity index 99% rename from generators/entities/generator.js rename to generators/entities/generator.ts index d112e8a34021..f3a8fc22e7cc 100644 --- a/generators/entities/generator.js +++ b/generators/entities/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * diff --git a/generators/entity/__snapshots__/single-entity.spec.ts.snap b/generators/entity/__snapshots__/single-entity.spec.ts.snap index be4141a56a85..62ab22476c27 100644 --- a/generators/entity/__snapshots__/single-entity.spec.ts.snap +++ b/generators/entity/__snapshots__/single-entity.spec.ts.snap @@ -5,9 +5,11 @@ exports[`generator - entity --single-entity when regenerating with default confi "addEntitiesToClient": [ { "application": "Application[jhipster]", + "control": "TaskParameter[control]", "entities": [ "Entity[Foo]", ], + "source": "TaskParameter[source]", }, ], "addEntityToCache": [ diff --git a/generators/entity/command.ts b/generators/entity/command.ts index c3b8e16ef4f5..6d1099157368 100644 --- a/generators/entity/command.ts +++ b/generators/entity/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { arguments: { diff --git a/generators/entity/database-changelog.spec.ts b/generators/entity/database-changelog.spec.ts index d2d06a1491c0..f3d125770f53 100644 --- a/generators/entity/database-changelog.spec.ts +++ b/generators/entity/database-changelog.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe } from 'esmocha'; -import { defaultHelpers as helpers, runResult, getGenerator } from '../../testing/index.js'; +import { before, describe, it } from 'esmocha'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { SERVER_MAIN_RES_DIR } from '../generator-constants.js'; import BaseApplicationGenerator from '../base-application/generator.js'; @@ -20,7 +20,7 @@ describe('generator - entity database changelogs', () => { describe('with cassandra database', () => { before(async () => { await helpers - .run(getGenerator('entity')) + .runJHipster('entity') .withGenerators([[MockedLanguagesGenerator, { namespace: 'jhipster:languages' }]]) .withJHipsterConfig({ databaseType: 'cassandra' }, [entityFoo]) .withArguments(['Foo']) @@ -34,11 +34,9 @@ describe('generator - entity database changelogs', () => { describe('with gateway application type', () => { before(async () => { await helpers - .run(getGenerator('entity')) + .runJHipster('entity') .withGenerators([[MockedLanguagesGenerator, { namespace: 'jhipster:languages' }]]) - .withJHipsterConfig({ applicationType: 'gateway' }, [ - { ...entityFoo, microservicePath: 'microservice1', microserviceName: 'microservice1' }, - ]) + .withJHipsterConfig({ applicationType: 'gateway' }, [{ ...entityFoo, microserviceName: 'microservice1' }]) .withArguments(['Foo']) .withOptions({ regenerate: true, force: true, ignoreNeedlesError: true }); }); diff --git a/generators/entity/generator.spec.js b/generators/entity/generator.spec.ts similarity index 96% rename from generators/entity/generator.spec.js rename to generators/entity/generator.spec.ts index 8dc47a0b505b..2e293135ab20 100644 --- a/generators/entity/generator.spec.js +++ b/generators/entity/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; diff --git a/generators/entity/generator.js b/generators/entity/generator.ts similarity index 92% rename from generators/entity/generator.js rename to generators/entity/generator.ts index 635695110db4..e0b4e18673e9 100644 --- a/generators/entity/generator.js +++ b/generators/entity/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,25 +17,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return */ + import fs from 'fs'; import path from 'path'; import chalk from 'chalk'; import { upperFirst } from 'lodash-es'; +import type { Storage } from 'yeoman-generator'; import BaseApplicationGenerator from '../base-application/index.js'; import { JHIPSTER_CONFIG_DIR } from '../generator-constants.js'; -import { applicationTypes, reservedKeywords } from '../../jdl/jhipster/index.js'; +import { applicationTypes, reservedKeywords } from '../../lib/jhipster/index.js'; import { GENERATOR_ENTITIES } from '../generator-list.js'; import { getDBTypeFromDBValue, hibernateSnakeCase } from '../server/support/index.js'; +import type { Entity } from '../../lib/types/application/entity.js'; import prompts from './prompts.js'; const { GATEWAY, MICROSERVICE } = applicationTypes; const { isReservedClassName } = reservedKeywords; export default class EntityGenerator extends BaseApplicationGenerator { - name; - application = {}; + name!: string; + application: any = {}; + entityStorage!: Storage; + entityConfig!: Entity; + entityData!: { name: string; filename: string; configExisted: any; entityExisted: boolean; configurationFileExists: boolean }; constructor(args, options, features) { super(args, options, { unique: 'argument', ...features }); @@ -55,8 +61,8 @@ export default class EntityGenerator extends BaseApplicationGenerator { return this.asInitializingTaskGroup({ parseOptions() { const name = upperFirst(this.name).replace('.json', ''); - this.entityStorage = this.getEntityConfig(name, true); - this.entityConfig = this.entityStorage.createProxy(); + this.entityStorage = this.getEntityConfig(name, true)!; + this.entityConfig = this.entityStorage.createProxy() as Entity; const configExisted = this.entityStorage.existed; const filename = path.join(JHIPSTER_CONFIG_DIR, `${name}.json`); @@ -134,7 +140,9 @@ export default class EntityGenerator extends BaseApplicationGenerator { context.microserviceFileName = this.destinationPath(this.entityConfig.microservicePath, context.filename); context.useConfigurationFile = true; - this.log.verboseInfo(`\nThe entity ${context.name} is being updated.\n`); + this.log.verboseInfo(` +The entity ${context.name} is being updated. +`); try { // We are generating a entity from a microservice. // Load it directly into our entity configuration. @@ -177,14 +185,20 @@ export default class EntityGenerator extends BaseApplicationGenerator { } context.useConfigurationFile = context.configurationFileExists || context.useConfigurationFile; if (context.configurationFileExists) { - this.log.log(chalk.green(`\nFound the ${context.filename} configuration file, entity can be automatically generated!\n`)); + this.log.log( + chalk.green(` +Found the ${context.filename} configuration file, entity can be automatically generated! +`), + ); } // Structure for prompts. this.entityStorage.defaults({ fields: [], relationships: [] }); if (!context.useConfigurationFile) { - this.log.verboseInfo(`\nThe entity ${entityName} is being created.\n`); + this.log.verboseInfo(` +The entity ${entityName} is being created. +`); } }, }); @@ -226,11 +240,11 @@ export default class EntityGenerator extends BaseApplicationGenerator { // Public API method used by the getter and also by Blueprints get end() { - return { + return this.asEndTaskGroup({ end() { this.log.log(chalk.bold.green(`Entity ${this.entityData.entityNameCapitalized} generated successfully.`)); }, - }; + }); } get [BaseApplicationGenerator.END]() { diff --git a/generators/entity/prompts.js b/generators/entity/prompts.ts similarity index 97% rename from generators/entity/prompts.js rename to generators/entity/prompts.ts index 7619f80f7dc2..2348ac3b33f7 100644 --- a/generators/entity/prompts.js +++ b/generators/entity/prompts.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -20,15 +21,16 @@ import fs from 'fs'; import chalk from 'chalk'; import { isArray, lowerFirst, snakeCase, uniq, upperFirst } from 'lodash-es'; import { - reservedKeywords, - databaseTypes, applicationTypes, + clientFrameworkTypes, + databaseTypes, entityOptions, fieldTypes, + reservedKeywords, validations, - clientFrameworkTypes, -} from '../../jdl/jhipster/index.js'; +} from '../../lib/jhipster/index.js'; import { inputIsNumber, inputIsSignedDecimalNumber, inputIsSignedNumber } from './support/index.js'; +import type EntityGenerator from './generator.js'; const { isReservedPaginationWords, isReservedFieldName, isReservedTableName } = reservedKeywords; const { NO: NO_DATABASE, CASSANDRA, SQL } = databaseTypes; @@ -74,7 +76,7 @@ const getFieldNameUndercored = fields => }), ); -function askForMicroserviceJson() { +function askForMicroserviceJson(this: EntityGenerator) { const context = this.entityData; if (this.jhipsterConfig.applicationType !== GATEWAY || context.configExisted) { return undefined; @@ -114,7 +116,7 @@ function askForMicroserviceJson() { }); } -function askForUpdate() { +function askForUpdate(this: EntityGenerator) { const context = this.entityData; // ask only if running an existing entity without arg option --force or --regenerate const isForce = this.options.force || context.regenerate; @@ -211,7 +213,7 @@ function askForFieldsToRemove() { }); } -function askForRelationships(...args) { +function askForRelationships(this: EntityGenerator, ...args) { const context = this.entityData; // don't prompt if data is imported from a file if (context.useConfigurationFile && context.updateEntity !== 'add') { @@ -224,7 +226,7 @@ function askForRelationships(...args) { return askForRelationship.call(this, ...args); } -function askForRelationsToRemove() { +function askForRelationsToRemove(this: EntityGenerator) { const context = this.entityData; // prompt only if data is imported from a file if (!context.useConfigurationFile || context.updateEntity !== 'remove' || this.entityConfig.relationships.length === 0) { @@ -270,7 +272,7 @@ function askForRelationsToRemove() { }); } -function askForFiltering() { +function askForFiltering(this: EntityGenerator) { const context = this.entityData; // don't prompt if server is skipped, or the backend is not sql, or no service requested if (context.useConfigurationFile || context.skipServer || context.databaseType !== 'sql' || this.entityConfig.service === 'no') { @@ -299,7 +301,7 @@ function askForFiltering() { }); } -function askForReadOnly() { +function askForReadOnly(this: EntityGenerator) { const context = this.entityData; // don't prompt if data is imported from a file if (context.useConfigurationFile) { @@ -318,7 +320,7 @@ function askForReadOnly() { }); } -function askForDTO() { +function askForDTO(this: EntityGenerator) { const context = this.entityData; // don't prompt if data is imported from a file or server is skipped or if no service layer if (context.useConfigurationFile || context.skipServer || this.entityConfig.service === 'no') { @@ -347,7 +349,7 @@ function askForDTO() { }); } -function askForService() { +function askForService(this: EntityGenerator) { const context = this.entityData; // don't prompt if data is imported from a file or server is skipped if (context.useConfigurationFile || context.skipServer) { @@ -380,7 +382,7 @@ function askForService() { }); } -function askForPagination() { +function askForPagination(this: EntityGenerator) { const context = this.entityData; // don't prompt if data are imported from a file if (context.useConfigurationFile) { @@ -420,7 +422,7 @@ function askForPagination() { /** * ask question for a field creation */ -async function askForField() { +async function askForField(this: EntityGenerator) { const context = this.entityData; this.log.log(chalk.green(`\nGenerating field #${this.entityConfig.fields.length + 1}\n`)); const databaseType = context.databaseType; @@ -514,7 +516,7 @@ async function askForField() { if (!/^[A-Za-z0-9_]*$/.test(input)) { return 'Your enum name cannot contain special characters (allowed characters: A-Z, a-z, 0-9 and _)'; } - if (context.enums && context.enums.includes(input)) { + if (context.enums?.includes(input)) { context.existingEnum = true; } else if (context.enums) { context.enums.push(input); @@ -735,7 +737,7 @@ async function askForField() { /** * ask question for a relationship creation */ -async function askForRelationship(...args) { +async function askForRelationship(this: EntityGenerator, ...args) { const [{ application }] = args; const context = this.entityData; const name = context.name; @@ -888,7 +890,7 @@ async function askForRelationship(...args) { /** * Show the entity and it's fields and relationships in console */ -function logFieldsAndRelationships() { +function logFieldsAndRelationships(this: EntityGenerator) { const context = this.entityData; if (this.entityConfig.fields.length > 0 || this.entityConfig.relationships.length > 0) { this.log.log(chalk.red(chalk.white('\n================= ') + context.name + chalk.white(' ================='))); @@ -939,7 +941,7 @@ function logFieldsAndRelationships() { this.log.log(chalk.white('Relationships')); this.entityConfig.relationships.forEach(relationship => { const validationDetails = []; - if (relationship.relationshipValidateRules && relationship.relationshipValidateRules.includes(REQUIRED)) { + if (relationship.relationshipValidateRules?.includes(REQUIRED)) { validationDetails.push(REQUIRED); } this.log.log( diff --git a/generators/entity/single-entity.spec.ts b/generators/entity/single-entity.spec.ts index 60bb4cdbe71c..6f64769ad7e9 100644 --- a/generators/entity/single-entity.spec.ts +++ b/generators/entity/single-entity.spec.ts @@ -1,6 +1,6 @@ -import { before, it, describe, after, expect } from 'esmocha'; -import { skipPrettierHelpers as helpers, result as runResult } from '../../testing/index.js'; -import { SERVER_MAIN_RES_DIR, SERVER_MAIN_SRC_DIR, CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; +import { before, describe, expect, it } from 'esmocha'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; +import { CLIENT_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR, SERVER_MAIN_SRC_DIR } from '../generator-constants.js'; import BaseApplicationGenerator from '../base-application/generator.js'; import { GENERATOR_ENTITY } from '../generator-list.js'; @@ -52,9 +52,8 @@ describe('generator - entity --single-entity', () => { }); describe('with cassandra database', () => { - let runResult; before(async () => { - runResult = await helpers + await helpers .runJHipster(GENERATOR_ENTITY) .withGenerators([[MockedLanguagesGenerator, { namespace: 'jhipster:languages' }]]) .withJHipsterConfig({ databaseType: 'cassandra' }, [entityFoo, entityBar]) @@ -62,8 +61,6 @@ describe('generator - entity --single-entity', () => { .withOptions({ ignoreNeedlesError: true, regenerate: true, force: true, singleEntity: true }); }); - after(() => runResult.cleanup()); - it('should create files for entity Foo', () => { runResult.assertFile([ `${SERVER_MAIN_RES_DIR}config/cql/changelog/20160926101210_added_entity_Foo.cql`, diff --git a/generators/entity/support/asserts.js b/generators/entity/support/asserts.ts similarity index 84% rename from generators/entity/support/asserts.js rename to generators/entity/support/asserts.ts index 6663141860e0..38e402980eca 100644 --- a/generators/entity/support/asserts.js +++ b/generators/entity/support/asserts.ts @@ -26,9 +26,9 @@ * @param isDecimal - flag indicating whether to check for decimal number or not * @returns {number} parsed number if valid input; NaN otherwise */ -const filterNumber = (input, isSigned, isDecimal) => { - const signed = isSigned ? '(\\-|\\+)?' : ''; - const decimal = isDecimal ? '(\\.[0-9]+)?' : ''; +const filterNumber = (input: any, isSigned = false, isDecimal = false) => { + const signed = isSigned ? '(-|+)?' : ''; + const decimal = isDecimal ? '(.[0-9]+)?' : ''; const regex = new RegExp(`^${signed}([0-9]+${decimal})$`); if (regex.test(input)) return Number(input); @@ -41,7 +41,7 @@ const filterNumber = (input, isSigned, isDecimal) => { * @param {any} input input * @returns {boolean} true if input is number; false otherwise */ -const isNumber = input => { +const isNumber = (input: any): input is number => { return !isNaN(filterNumber(input)); }; @@ -50,7 +50,7 @@ const isNumber = input => { * @param {any} input input * @returns {boolean} true if input is a signed number; false otherwise */ -const isSignedNumber = input => { +const isSignedNumber = (input: any): boolean => { return !isNaN(filterNumber(input, true)); }; @@ -59,7 +59,7 @@ const isSignedNumber = input => { * @param {any} input input * @returns {boolean} true if input is a signed decimal number; false otherwise */ -const isSignedDecimalNumber = input => { +const isSignedDecimalNumber = (input: any): boolean => { return !isNaN(filterNumber(input, true, true)); }; diff --git a/generators/entity/support/index.ts b/generators/entity/support/index.ts index 7fb102603143..2fed641c9877 100644 --- a/generators/entity/support/index.ts +++ b/generators/entity/support/index.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// eslint-disable-next-line import/prefer-default-export + export { isNumber as inputIsNumber, isSignedNumber as inputIsSignedNumber, diff --git a/generators/export-jdl/__snapshots__/export-jdl.spec.ts.snap b/generators/export-jdl/__snapshots__/export-jdl.spec.ts.snap index b82a6e00c4f2..db8ddf979404 100644 --- a/generators/export-jdl/__snapshots__/export-jdl.spec.ts.snap +++ b/generators/export-jdl/__snapshots__/export-jdl.spec.ts.snap @@ -26,7 +26,6 @@ exports[`generator - export-jdl exports entities to a JDL file with file argumen serverPort 8080 skipClient true skipServer true - testFrameworks [] websocket no } @@ -145,7 +144,6 @@ exports[`generator - export-jdl exports entities to a JDL file without argument serverPort 8080 skipClient true skipServer true - testFrameworks [] websocket no } diff --git a/generators/export-jdl/export-jdl.spec.ts b/generators/export-jdl/export-jdl.spec.ts index a54d6fbeec6d..77682ec80bd2 100644 --- a/generators/export-jdl/export-jdl.spec.ts +++ b/generators/export-jdl/export-jdl.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe, expect } from 'esmocha'; -import { defaultHelpers as helpers } from '../../testing/index.js'; +import { before, describe, expect, it } from 'esmocha'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { GENERATOR_EXPORT_JDL } from '../generator-list.js'; const files = { @@ -358,21 +358,18 @@ const applicationConfig = { buildTool: 'gradle', rememberMeKey: '5f1100e7eae25e2abe32d7b2031ac1f2acc778d8', applicationType: 'monolith', - testFrameworks: [], jhiPrefix: 'jhi', enableTranslation: true, nativeLanguage: 'en', languages: ['en'], skipClient: true, skipServer: true, -}; +} as const; describe('generator - export-jdl', () => { describe('exports entities to a JDL file without argument', () => { - let runResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_EXPORT_JDL).withJHipsterConfig(applicationConfig).withFiles(files).commitFiles(); + await helpers.runJHipster(GENERATOR_EXPORT_JDL).withJHipsterConfig(applicationConfig).withFiles(files).commitFiles(); }); it('should match snapshot', () => { @@ -384,12 +381,10 @@ describe('generator - export-jdl', () => { }); describe('exports entities to a JDL file with file argument', () => { - let runResult; - before(async () => { - runResult = await helpers + await helpers .runJHipster(GENERATOR_EXPORT_JDL) - .withJHipsterConfig(applicationConfig) + .withJHipsterConfig(applicationConfig) .withFiles(files) .commitFiles() .withArguments('custom-app.jdl'); diff --git a/generators/export-jdl/generator.spec.ts b/generators/export-jdl/generator.spec.ts index b25895cf89f4..d90bf385002d 100644 --- a/generators/export-jdl/generator.spec.ts +++ b/generators/export-jdl/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures } from '../../test/support/tests.js'; diff --git a/generators/export-jdl/generator.ts b/generators/export-jdl/generator.ts index b324dbc0d2d9..9591cdf6320a 100644 --- a/generators/export-jdl/generator.ts +++ b/generators/export-jdl/generator.ts @@ -20,9 +20,9 @@ import chalk from 'chalk'; import BaseGenerator from '../base/index.js'; -import { applicationOptions } from '../../jdl/jhipster/index.js'; -import JSONToJDLConverter from '../../jdl/converters/json-to-jdl-converter.js'; -import type { JHipsterGeneratorOptions, JHipsterGeneratorFeatures } from '../base/api.js'; +import { applicationOptions } from '../../lib/jhipster/index.js'; +import { convertToJDL } from '../../lib/jdl/converters/json-to-jdl-converter.js'; +import type { JHipsterGeneratorFeatures, JHipsterGeneratorOptions } from '../base/api.js'; const { OptionNames } = applicationOptions; @@ -50,12 +50,11 @@ export default class extends BaseGenerator { return this.asDefaultTaskGroup({ convertToJDL() { try { - const jdlObject = JSONToJDLConverter.convertToJDL(this.destinationPath(), false); + const jdlObject = convertToJDL(this.destinationPath(), false, this.options.jdlDefinition); if (jdlObject) { this.jdlContent = jdlObject.toString(); } } catch (error: unknown) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any throw new Error(`An error occurred while exporting to JDL: ${(error as any).message}\n${error}`, { cause: error }); } }, diff --git a/generators/feign-client/generator.spec.ts b/generators/feign-client/generator.spec.ts index ef896b7559f3..22e01f037471 100644 --- a/generators/feign-client/generator.spec.ts +++ b/generators/feign-client/generator.spec.ts @@ -1,8 +1,8 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; -import { defaultHelpers as helpers, runResult } from '../../testing/index.js'; -import { shouldSupportFeatures, testBlueprintSupport, checkEnforcements } from '../../test/support/index.js'; +import { before, describe, expect, it } from 'esmocha'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; +import { checkEnforcements, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/index.js'; import Generator from '../server/index.js'; import { GENERATOR_FEIGN_CLIENT } from '../generator-list.js'; diff --git a/generators/gatling/entity-files.ts b/generators/gatling/entity-files.ts index 99b916e27db2..dac3b2d884ca 100644 --- a/generators/gatling/entity-files.ts +++ b/generators/gatling/entity-files.ts @@ -17,7 +17,7 @@ * limitations under the License. */ import { TEST_DIR } from '../generator-constants.js'; -import Generator from './generator.js'; +import type Generator from './generator.js'; export const gatlingFiles = { gatlingFiles: [ diff --git a/generators/gatling/files.ts b/generators/gatling/files.ts index e9b70c5529b4..ffdeb7cd331b 100644 --- a/generators/gatling/files.ts +++ b/generators/gatling/files.ts @@ -16,12 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TEST_DIR, GRADLE_BUILD_SRC_MAIN_DIR } from '../generator-constants.js'; -import { WriteFileSection } from '../base/api.js'; -import { SpringBootApplication } from '../server/types.js'; -import Generator from './generator.js'; +import { GRADLE_BUILD_SRC_MAIN_DIR, TEST_DIR } from '../generator-constants.js'; +import type { WriteFileSection } from '../base/api.js'; +import type Generator from './generator.js'; -const gatlingFiles: WriteFileSection = { +const gatlingFiles: WriteFileSection = { gatlingFiles: [ { templates: ['README.md.jhi.gatling'], diff --git a/generators/gatling/generator.spec.ts b/generators/gatling/generator.spec.ts index 3eac68382a35..90e216ead5e2 100644 --- a/generators/gatling/generator.spec.ts +++ b/generators/gatling/generator.spec.ts @@ -1,10 +1,10 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../lib/testing/index.js'; import { GENERATOR_GATLING } from '../generator-list.js'; import Generator from './index.js'; diff --git a/generators/generate-blueprint/__snapshots__/generator.spec.js.snap b/generators/generate-blueprint/__snapshots__/generator.spec.ts.snap similarity index 99% rename from generators/generate-blueprint/__snapshots__/generator.spec.js.snap rename to generators/generate-blueprint/__snapshots__/generator.spec.ts.snap index 04c95f53a9ea..7a5521ffb139 100644 --- a/generators/generate-blueprint/__snapshots__/generator.spec.js.snap +++ b/generators/generate-blueprint/__snapshots__/generator.spec.ts.snap @@ -26,6 +26,9 @@ exports[`generator - generate-blueprint with all option should match snapshot 1` "README.md": { "stateCleared": "modified", }, + "cli/cli-customizations.cjs": { + "stateCleared": "modified", + }, "cli/cli.cjs": { "stateCleared": "modified", }, @@ -860,9 +863,6 @@ exports[`generator - generate-blueprint with all option should match snapshot 1` "vitest.config.ts": { "stateCleared": "modified", }, - "vitest.test-setup.ts": { - "stateCleared": "modified", - }, } `; @@ -892,6 +892,9 @@ exports[`generator - generate-blueprint with default config should write files a "README.md": { "stateCleared": "modified", }, + "cli/cli-customizations.cjs": { + "stateCleared": "modified", + }, "cli/cli.cjs": { "stateCleared": "modified", }, @@ -904,8 +907,5 @@ exports[`generator - generate-blueprint with default config should write files a "vitest.config.ts": { "stateCleared": "modified", }, - "vitest.test-setup.ts": { - "stateCleared": "modified", - }, } `; diff --git a/generators/generate-blueprint/command.ts b/generators/generate-blueprint/command.ts index ff8d36422ea2..bfed7cb39f1b 100644 --- a/generators/generate-blueprint/command.ts +++ b/generators/generate-blueprint/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_INIT } from '../generator-list.js'; import { ADDITIONAL_SUB_GENERATORS, @@ -31,8 +31,36 @@ import { SUB_GENERATORS, } from './constants.js'; -const command: JHipsterCommandDefinition = { +const command = { configs: { + caret: { + cli: { + description: 'Use caret in package.json engines', + type: Boolean, + }, + scope: 'storage', + }, + recreatePackageLock: { + description: 'Recreate package lock', + cli: { + type: Boolean, + }, + scope: 'generator', + }, + skipWorkflows: { + description: 'Skip github workflows', + cli: { + type: Boolean, + }, + scope: 'generator', + }, + ignoreExistingGenerators: { + description: 'Ignore existing generators', + cli: { + type: Boolean, + }, + scope: 'generator', + }, githubRepository: { cli: { description: 'Github Repository', @@ -99,6 +127,6 @@ const command: JHipsterCommandDefinition = { }, }, import: [GENERATOR_INIT], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/generate-blueprint/constants.js b/generators/generate-blueprint/constants.ts similarity index 99% rename from generators/generate-blueprint/constants.js rename to generators/generate-blueprint/constants.ts index 9f1853b36d5f..9f08ae586a84 100644 --- a/generators/generate-blueprint/constants.js +++ b/generators/generate-blueprint/constants.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * diff --git a/generators/generate-blueprint/files.js b/generators/generate-blueprint/files.ts similarity index 62% rename from generators/generate-blueprint/files.js rename to generators/generate-blueprint/files.ts index 651c284c424b..a80f107d63fa 100644 --- a/generators/generate-blueprint/files.js +++ b/generators/generate-blueprint/files.ts @@ -16,10 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { asWriteFilesSection } from '../base-application/support/task-type-inference.js'; +import { asWriteFilesSection } from '../base-application/support/index.js'; import { LOCAL_BLUEPRINT_OPTION } from './constants.js'; -export const files = asWriteFilesSection({ +export const files = asWriteFilesSection({ baseFiles: [ { condition: ctx => !ctx[LOCAL_BLUEPRINT_OPTION], @@ -30,11 +30,13 @@ export const files = asWriteFilesSection({ 'README.md', 'tsconfig.json', 'vitest.config.ts', - 'vitest.test-setup.ts', '.blueprint/cli/commands.mjs', '.blueprint/generate-sample/command.mjs', '.blueprint/generate-sample/generator.mjs', '.blueprint/generate-sample/index.mjs', + // Always write cli for devBlueprint usage + 'cli/cli.cjs', + { sourceFile: 'cli/cli-customizations.cjs', override: false }, ], }, { @@ -43,17 +45,15 @@ export const files = asWriteFilesSection({ '.blueprint/github-build-matrix/build-matrix.mjs', '.blueprint/github-build-matrix/generator.mjs', '.blueprint/github-build-matrix/index.mjs', - '.github/workflows/build-cache.yml', - '.github/workflows/samples.yml', ], }, { - condition: ctx => !ctx[LOCAL_BLUEPRINT_OPTION] && !ctx.sampleWritten, - templates: ['.blueprint/generate-sample/templates/samples/sample.jdl'], + condition: ctx => !ctx[LOCAL_BLUEPRINT_OPTION] && ctx.githubWorkflows && !ctx.skipWorkflows, + templates: ['.github/workflows/build-cache.yml', '.github/workflows/samples.yml'], }, { - condition: ctx => ctx.cli, - templates: ['cli/cli.cjs'], + condition: ctx => !ctx[LOCAL_BLUEPRINT_OPTION] && !ctx.sampleWritten, + templates: ['.blueprint/generate-sample/templates/samples/sample.jdl'], }, { condition: ctx => ctx.commands.length > 0, @@ -62,30 +62,28 @@ export const files = asWriteFilesSection({ ], }); -export const generatorFiles = { +export const generatorFiles = asWriteFilesSection({ generator: [ { path: 'generators/generator', to: ctx => `${ctx.application.blueprintsPath}${ctx.generator}`, templates: [ - { file: 'generator.mjs.jhi', renameTo: ctx => (ctx.js ? 'generator.js.jhi' : 'generator.mjs.jhi') }, - { file: 'index.mjs', renameTo: ctx => (ctx.js ? 'index.js' : 'index.mjs') }, - ], - }, - { - path: 'generators/generator', - condition: ctx => ctx.priorities.find(priority => priority.name === 'initializing'), - to: ctx => `${ctx.application.blueprintsPath}${ctx.generator}`, - templates: [{ file: 'command.mjs', renameTo: ctx => (ctx.js ? 'command.js' : 'command.mjs') }], - }, - { - path: 'generators/generator', - to: ctx => `${ctx.application.blueprintsPath}${ctx.generator}`, - condition: ctx => !ctx.generator.startsWith('entity') && !ctx.application[LOCAL_BLUEPRINT_OPTION], - templates: [ + { sourceFile: 'index.mjs', destinationFile: ctx => `index.${ctx.blueprintMjsExtension}` }, { - file: 'generator.spec.mjs', - renameTo: ctx => (ctx.js ? 'generator.spec.js' : 'generator.spec.mjs'), + sourceFile: 'command.mjs', + destinationFile: ctx => `command.${ctx.blueprintMjsExtension}`, + override: data => !data.ignoreExistingGenerators, + }, + { + sourceFile: 'generator.mjs.jhi', + destinationFile: ctx => `generator.${ctx.blueprintMjsExtension}.jhi`, + override: data => !data.ignoreExistingGenerators, + }, + { + condition: data => !data.generator.startsWith('entity') && !data.application[LOCAL_BLUEPRINT_OPTION], + sourceFile: 'generator.spec.mjs', + destinationFile: data => `generator.spec.${data.blueprintMjsExtension}`, + override: data => !data.ignoreExistingGenerators, }, ], }, @@ -93,15 +91,15 @@ export const generatorFiles = { path: 'generators/generator', to: ctx => `${ctx.application.blueprintsPath}${ctx.generator}`, condition(ctx) { - return (this.options.force || !ctx.written) && ctx.priorities.find(priority => priority.name === 'writing'); + return !ctx.written && ctx.priorities.find(priority => priority.name === 'writing'); }, transform: false, templates: [ { - file: 'templates/template-file.ejs', - renameTo: ctx => `templates/template-file-${ctx.generator}.ejs`, + sourceFile: 'templates/template-file.ejs', + destinationFile: ctx => `templates/template-file-${ctx.generator}.ejs`, }, ], }, ], -}; +}); diff --git a/generators/generate-blueprint/generator.spec.js b/generators/generate-blueprint/generator.spec.ts similarity index 76% rename from generators/generate-blueprint/generator.spec.js rename to generators/generate-blueprint/generator.spec.ts index 6450c03acac1..fc7170f28553 100644 --- a/generators/generate-blueprint/generator.spec.js +++ b/generators/generate-blueprint/generator.spec.ts @@ -16,19 +16,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { defaultHelpers as helpers, runResult } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const generatorPath = join(__dirname, 'index.js'); const generator = basename(__dirname); const mockedGenerators = ['jhipster:init']; @@ -44,10 +43,10 @@ describe(`generator - ${generator}`, () => { describe('with', () => { describe('default config', () => { before(async () => { - await helpers.run(generatorPath).withJHipsterConfig().withMockedGenerators(mockedGenerators); + await helpers.runJHipster(generator).withJHipsterConfig().withMockedGenerators(mockedGenerators); }); it('should compose with init generator', () => { - expect(runResult.mockedGenerators['jhipster:init'].calledOnce).toBe(true); + runResult.assertGeneratorComposedOnce('jhipster:init'); }); it('should write files and match snapshot', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); @@ -55,22 +54,21 @@ describe(`generator - ${generator}`, () => { }); describe('all option', () => { before(async () => { - await helpers.run(generatorPath).withOptions({ allGenerators: true }).withMockedGenerators(mockedGenerators); + await helpers.runJHipster(generator).withOptions({ allGenerators: true }).withMockedGenerators(mockedGenerators); }); it('should compose with init generator', () => { - expect(runResult.mockedGenerators['jhipster:init'].calledOnce).toBe(true); + runResult.assertGeneratorComposedOnce('jhipster:init'); }); it('should match snapshot', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); }); }); describe('local-blueprint option', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath).withOptions({ localBlueprint: true }).withMockedGenerators(mockedGenerators); + await helpers.runJHipster(generator).withOptions({ localBlueprint: true }).withMockedGenerators(mockedGenerators); }); it('should not compose with init generator', () => { - expect(runResult.mockedGenerators['jhipster:init'].calledOnce).toBe(false); + runResult.assertGeneratorNotComposed('jhipster:init'); }); it('should match snapshot', () => { expect(runResult.getStateSnapshot()).toMatchInlineSnapshot(` @@ -83,15 +81,14 @@ describe(`generator - ${generator}`, () => { }); }); describe('local-blueprint option and app generator', () => { - let runResult; before(async () => { - runResult = await helpers - .run(generatorPath) + await helpers + .runJHipster(generator) .withOptions({ localBlueprint: true, subGenerators: ['app'], allPriorities: true }) .withMockedGenerators(mockedGenerators); }); it('should not compose with init generator', () => { - expect(runResult.mockedGenerators['jhipster:init'].calledOnce).toBe(false); + runResult.assertGeneratorNotComposed('jhipster:init'); }); it('should write java files with gradle build tool and match snapshot', () => { expect(runResult.getStateSnapshot()).toMatchInlineSnapshot(` diff --git a/generators/generate-blueprint/generator.js b/generators/generate-blueprint/generator.ts similarity index 78% rename from generators/generate-blueprint/generator.js rename to generators/generate-blueprint/generator.ts index 29208857a971..148cae668d2a 100644 --- a/generators/generate-blueprint/generator.js +++ b/generators/generate-blueprint/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,8 +17,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { rm } from 'node:fs/promises'; import chalk from 'chalk'; -import { camelCase, upperFirst, snakeCase } from 'lodash-es'; +import { camelCase, snakeCase, upperFirst } from 'lodash-es'; import BaseGenerator from '../base-application/index.js'; import { PRIORITY_NAMES_LIST as BASE_PRIORITY_NAMES_LIST } from '../base/priorities.js'; @@ -27,23 +29,23 @@ import { packageJson } from '../../lib/index.js'; import { BLUEPRINT_API_VERSION, NODE_VERSION } from '../generator-constants.js'; import { files, generatorFiles } from './files.js'; import { - requiredConfig, - defaultConfig, - defaultSubGeneratorConfig, - allGeneratorsConfig, - prompts, - subGeneratorPrompts, - GENERATE_SNAPSHOTS, - LINK_JHIPSTER_DEPENDENCY, + ADDITIONAL_SUB_GENERATORS, ALL_GENERATORS, + ALL_PRIORITIES, + DYNAMIC, + GENERATE_SNAPSHOTS, GENERATORS, + LINK_JHIPSTER_DEPENDENCY, + LOCAL_BLUEPRINT_OPTION, PRIORITIES, SUB_GENERATORS, - ADDITIONAL_SUB_GENERATORS, WRITTEN, - LOCAL_BLUEPRINT_OPTION, - ALL_PRIORITIES, - DYNAMIC, + allGeneratorsConfig, + defaultConfig, + defaultSubGeneratorConfig, + prompts, + requiredConfig, + subGeneratorPrompts, } from './constants.js'; const { GENERATOR_PROJECT_NAME, GENERATOR_INIT } = GENERATOR_LIST; @@ -51,6 +53,11 @@ const { GENERATOR_PROJECT_NAME, GENERATOR_INIT } = GENERATOR_LIST; const defaultPublishedFiles = ['generators', '!**/__*', '!**/*.snap', '!**/*.spec.?(c|m)js']; export default class extends BaseGenerator { + application!: any; + recreatePackageLock!: boolean; + skipWorkflows!: boolean; + ignoreExistingGenerators!: boolean; + async _beforeQueue() { if (!this.fromBlueprint) { await this.composeWithBlueprints(); @@ -79,7 +86,7 @@ export default class extends BaseGenerator { } get prompting() { - return { + return this.asPromptingTaskGroup({ async prompting() { await this.prompt(prompts(this), this.config); }, @@ -110,7 +117,7 @@ export default class extends BaseGenerator { await this.prompt(subGeneratorPrompts({ subGenerator, localBlueprint, additionalSubGenerator: true }), subGeneratorStorage); } }, - }; + }); } get [BaseGenerator.PROMPTING]() { @@ -118,7 +125,7 @@ export default class extends BaseGenerator { } get configuring() { - return { + return this.asConfiguringTaskGroup({ requiredConfig() { this.config.defaults(requiredConfig()); }, @@ -130,7 +137,7 @@ export default class extends BaseGenerator { }); } }, - }; + }); } get [BaseGenerator.CONFIGURING]() { @@ -138,13 +145,16 @@ export default class extends BaseGenerator { } get composing() { - return { + return this.asComposingTaskGroup({ + storeCurrentVersion() { + this.storeCurrentJHipsterVersion(); + }, async compose() { if (this.jhipsterConfig[LOCAL_BLUEPRINT_OPTION]) return; const initGenerator = await this.composeWithJHipster(GENERATOR_INIT, { generatorOptions: { packageJsonType: 'module' } }); initGenerator.generateReadme = false; }, - }; + }); } get [BaseGenerator.COMPOSING]() { @@ -183,9 +193,10 @@ export default class extends BaseGenerator { preparePath() { this.application.blueprintsPath = this.application[LOCAL_BLUEPRINT_OPTION] ? '.blueprint/' : 'generators/'; }, - prepare() { + prepare({ application }) { const { cli, cliName, baseName } = this.application; this.application.githubRepository = this.jhipsterConfig.githubRepository ?? `jhipster/generator-jhipster-${baseName}`; + application.blueprintMjsExtension = this.application.js ? 'js' : 'mjs'; if (cli) { this.application.cliName = cliName ?? `jhipster-${baseName}`; } @@ -200,18 +211,28 @@ export default class extends BaseGenerator { get writing() { return this.asWritingTaskGroup({ async cleanup({ control }) { - await control.cleanupFiles({ '8.5.1': ['.eslintrc.json'] }); + await control.cleanupFiles({ + '8.5.1': ['.eslintrc.json'], + '8.7.2': ['.eslintignore', 'vitest.test-setup.ts'], + }); }, - async writing() { + async writing({ application }) { this.application.sampleWritten = this.jhipsterConfig.sampleWritten; + const { skipWorkflows, ignoreExistingGenerators } = this; await this.writeFiles({ sections: files, - context: this.application, + context: { + ...application, + skipWorkflows, + ignoreExistingGenerators, + ...this.application, + }, }); this.jhipsterConfig.sampleWritten = true; }, - async writingGenerators() { + async writingGenerators({ application }) { if (!this.application[GENERATORS]) return; + const { skipWorkflows, ignoreExistingGenerators } = this; for (const generator of Object.keys(this.application[GENERATORS])) { const subGeneratorStorage = this.getSubGeneratorStorage(generator); const subGeneratorConfig = subGeneratorStorage.getAll(); @@ -223,7 +244,9 @@ export default class extends BaseGenerator { const customGenerator = !Object.values(GENERATOR_LIST).includes(generator); const jhipsterGenerator = customGenerator || subGeneratorConfig.sbs ? 'base-application' : generator; const subTemplateData = { - js: this.application.js, + ...application, + skipWorkflows, + ignoreExistingGenerators, application: this.application, ...defaultSubGeneratorConfig(), ...subGeneratorConfig, @@ -250,6 +273,33 @@ export default class extends BaseGenerator { get postWriting() { return this.asPostWritingTaskGroup({ + upgrade({ application }) { + if (!this.application[GENERATORS]) return; + if (!this.isJhipsterVersionLessThan('8.7.2')) return; + for (const generator of Object.keys(this.application[GENERATORS])) { + const commandFile = `${this.application.blueprintsPath}${generator}/command.${application.blueprintMjsExtension}`; + this.editFile(commandFile, content => + content + .replace( + `/** + * @type {import('generator-jhipster').JHipsterCommandDefinition} + */`, + `import { asCommand } from 'generator-jhipster'; +`, + ) + .replace('const command = ', 'export default asCommand(') + .replace( + ` +};`, + '});', + ) + .replace('export default command;', ''), + ); + + const generatorSpec = `${this.application.blueprintsPath}${generator}/generator.spec.${application.blueprintMjsExtension}`; + this.editFile(generatorSpec, content => content.replaceAll(/blueprint: '([\w-]*)'/g, "blueprint: ['$1']")); + } + }, packageJson() { if (this.jhipsterConfig[LOCAL_BLUEPRINT_OPTION]) return; const { packagejs } = this.application; @@ -304,26 +354,22 @@ export default class extends BaseGenerator { addGeneratorJHipsterDependency() { if (this.jhipsterConfig[LOCAL_BLUEPRINT_OPTION]) return; const { packagejs } = this.application; + const exactDependency = { + 'generator-jhipster': `${packagejs.version}`, + }; + const caretDependency = { + 'generator-jhipster': `^${packagejs.version}`, + }; if (this.jhipsterConfig.dynamic) { this.packageJson.merge({ - devDependencies: { - 'generator-jhipster': `${packagejs.version}`, - }, - peerDependencies: { - 'generator-jhipster': `^${packagejs.version}`, - }, - engines: { - 'generator-jhipster': `^${packagejs.version}`, - }, + devDependencies: exactDependency, + peerDependencies: caretDependency, + engines: caretDependency, }); } else { this.packageJson.merge({ - dependencies: { - 'generator-jhipster': `${packagejs.version}`, - }, - engines: { - 'generator-jhipster': `${packagejs.version}`, - }, + dependencies: exactDependency, + engines: this.jhipsterConfig.caret ? caretDependency : exactDependency, }); } }, @@ -335,8 +381,8 @@ export default class extends BaseGenerator { } get postInstall() { - return { - async addSnapshot() { + return this.asPostInstallTaskGroup({ + async addSnapshot({ control }) { const { [LOCAL_BLUEPRINT_OPTION]: localBlueprint } = this.jhipsterConfig; const { skipInstall, @@ -346,6 +392,12 @@ export default class extends BaseGenerator { } = this.options; if (!generateSnapshots) return; + if (this.recreatePackageLock) { + await rm(this.destinationPath('package-lock.json'), { force: true }); + await rm(this.destinationPath('node_modules'), { force: true, recursive: true }); + await this.spawnCommand('npm', ['install'], { stdio: 'inherit' }); + } + try { if (this.options[LINK_JHIPSTER_DEPENDENCY]) { this.log.verboseInfo('Linking generator-jhipster'); @@ -363,8 +415,23 @@ This is a new blueprint, executing '${chalk.yellow('npm run update-snapshot')}' } this.log.warn('Fail to generate snapshots'); } + + if (control.jhipsterOldVersion) { + // Apply prettier and eslint to fix non generated files on upgrade. + try { + await this.spawnCommand('npm', ['run', 'prettier-format']); + } catch { + // Ignore error + } + + try { + await this.spawnCommand('npm', ['run', 'lint-fix']); + } catch { + // Ignore error + } + } }, - }; + }); } get [BaseGenerator.POST_INSTALL]() { @@ -372,7 +439,7 @@ This is a new blueprint, executing '${chalk.yellow('npm run update-snapshot')}' } get end() { - return { + return this.asEndTaskGroup({ end() { if (this.jhipsterConfig[LOCAL_BLUEPRINT_OPTION]) return; @@ -388,7 +455,7 @@ To begin to work: - then, come back here, and begin to code! `); }, - }; + }); } get [BaseGenerator.END]() { diff --git a/generators/generate-blueprint/resources/package.json b/generators/generate-blueprint/resources/package.json index f0653937f38f..8aeea6c0580a 100644 --- a/generators/generate-blueprint/resources/package.json +++ b/generators/generate-blueprint/resources/package.json @@ -1,7 +1,7 @@ { "dependencies": { - "eslint": "9.7.0", - "globals": "15.8.0", - "vitest": "2.0.3" + "eslint": "9.13.0", + "globals": "15.11.0", + "vitest": "2.1.4" } } diff --git a/generators/generate-blueprint/templates/.github/workflows/samples.yml.ejs b/generators/generate-blueprint/templates/.github/workflows/samples.yml.ejs index 97c8c71d0618..a64c3a74b8b2 100644 --- a/generators/generate-blueprint/templates/.github/workflows/samples.yml.ejs +++ b/generators/generate-blueprint/templates/.github/workflows/samples.yml.ejs @@ -26,7 +26,7 @@ jobs: npm install ./cli/cli.cjs github-build-matrix samples: - name: ${{ matrix.sample-name }} + name: ${{ matrix.job-name || matrix.sample-name }} runs-on: ubuntu-latest needs: build-matrix defaults: @@ -48,11 +48,9 @@ jobs: maven-cache: true gradle-cache: true binary-dir: ${{ github.workspace }}/generator-jhipster-<%= baseName %>/cli/ - - name: 'Install blueprint' - run: npm install + - run: npm install working-directory: ${{ github.workspace }}/generator-jhipster-<%= baseName %> - - name: 'Generate Project' - run: cli.cjs generate-sample ${{ matrix.sample-name }} --skip-jhipster-dependencies --force + - run: cli.cjs generate-sample ${{ matrix.sample-name }} --skip-jhipster-dependencies ${{ matrix.extra-args }} - uses: jhipster/actions/compare-sample@v0 id: compare if: >- @@ -60,7 +58,7 @@ jobs: !contains(github.event.pull_request.labels.*.name, 'pr: disable-compare') with: generator-path: generator-jhipster-<%= baseName %> - cmd: cli.cjs generate-sample ${{ matrix.sample-name }} --skip-jhipster-dependencies --force --skip-install + cmd: cli.cjs generate-sample ${{ matrix.sample-name }} --skip-jhipster-dependencies --skip-install ${{ matrix.extra-args }} - run: npm run ci:backend:test if: steps.compare.outputs.equals != 'true' id: backend @@ -73,7 +71,7 @@ jobs: - run: npm run ci:e2e:run --if-present if: steps.compare.outputs.equals != 'true' id: e2e - - name: 'BACKEND: Store failure logs' + - name: Store backend test failure logs uses: actions/upload-artifact@v4 if: always() && steps.backend.outcome == 'failure' with: @@ -81,7 +79,7 @@ jobs: path: | ${{ github.workspace }}/app/build/test-results/**/*.xml ${{ github.workspace }}/app/target/surefire-reports - - name: 'E2E: Store failure screenshots' + - name: Store cypress screenshots uses: actions/upload-artifact@v4 if: always() && steps.e2e.outcome == 'failure' with: diff --git a/generators/generate-blueprint/templates/README.md.ejs b/generators/generate-blueprint/templates/README.md.ejs index 10e4f399a1f8..5e48313df6c3 100644 --- a/generators/generate-blueprint/templates/README.md.ejs +++ b/generators/generate-blueprint/templates/README.md.ejs @@ -46,13 +46,23 @@ npm install -g generator-jhipster-<%= baseName %> To use this blueprint, run the below command -```bash <%_ if (cli) { _%> +```bash <%= cliName %> + <%_ if (caret) { _%> +``` + +or + +```bash +jhipster --blueprints <%= baseName %> +``` + <%_ } _%> <%_ } else { _%> +```bash jhipster --blueprints <%= baseName %> -<%_ } _%> ``` +<%_ } _%> You can look for updated <%= baseName %> blueprint specific options by running diff --git a/generators/generate-blueprint/templates/cli/cli-customizations.cjs.ejs b/generators/generate-blueprint/templates/cli/cli-customizations.cjs.ejs new file mode 100644 index 000000000000..20a8a77ad8b9 --- /dev/null +++ b/generators/generate-blueprint/templates/cli/cli-customizations.cjs.ejs @@ -0,0 +1,2 @@ +// This file will not be overwritten by generate-blueprint +module.exports = {}; diff --git a/generators/generate-blueprint/templates/cli/cli.cjs.ejs b/generators/generate-blueprint/templates/cli/cli.cjs.ejs index 7d955918471d..9f06eee6e866 100755 --- a/generators/generate-blueprint/templates/cli/cli.cjs.ejs +++ b/generators/generate-blueprint/templates/cli/cli.cjs.ejs @@ -23,10 +23,11 @@ const blueprint = packageFolderName.startsWith('jhipster-') ? `generator-${packa [blueprint]: version, }, printBlueprintLogo: () => { - console.log('===================== JHipster <%= baseName %> ====================='); + console.log('===================== JHipster <%= humanizedBaseName %> ====================='); console.log(''); }, lookups: [{ packagePaths: [packagePath] }], + ...require('./cli-customizations.cjs'), }).catch(done); process.on('unhandledRejection', up => { diff --git a/generators/generate-blueprint/templates/cli/commands.cjs.ejs b/generators/generate-blueprint/templates/cli/commands.cjs.ejs index 9d463ab9fb33..19ca55ceaaa0 100644 --- a/generators/generate-blueprint/templates/cli/commands.cjs.ejs +++ b/generators/generate-blueprint/templates/cli/commands.cjs.ejs @@ -19,7 +19,7 @@ module.exports = { <% for (const command of commands) { %> '<%= command %>': { - description: 'Run <%= command %> sub-generator (<%= baseName %> blueprint)', + desc: 'Run <%= command %> sub-generator (<%= baseName %> blueprint)', blueprint: 'generator-jhipster-<%= baseName %>', }, <% } %> diff --git a/generators/generate-blueprint/templates/eslint.config.js.jhi.blueprint.ejs b/generators/generate-blueprint/templates/eslint.config.js.jhi.blueprint.ejs index 89180c3b7a0c..e34f05b52fbf 100644 --- a/generators/generate-blueprint/templates/eslint.config.js.jhi.blueprint.ejs +++ b/generators/generate-blueprint/templates/eslint.config.js.jhi.blueprint.ejs @@ -17,8 +17,9 @@ limitations under the License. -%> <&_ if (fragment.importsSection) { -&> -import jhipster from 'generator-jhipster/eslint/recommended'; +import jhipster from 'generator-jhipster/eslint'; <&_ } -&> <&_ if (fragment.configSection) { -&> - jhipster, + { ignores: ['coverage/**'] }, + jhipster.recommended, <&_ } -&> diff --git a/generators/generate-blueprint/templates/generators/generator/command.mjs.ejs b/generators/generate-blueprint/templates/generators/generator/command.mjs.ejs index 36f29dc995b4..046bebeece2a 100644 --- a/generators/generate-blueprint/templates/generators/generator/command.mjs.ejs +++ b/generators/generate-blueprint/templates/generators/generator/command.mjs.ejs @@ -16,29 +16,25 @@ See the License for the specific language governing permissions and limitations under the License. -%> +import { asCommand } from 'generator-jhipster'; <%_ if (!sbs && !customGenerator) { _%> import { command as jhipsterCommand } from 'generator-jhipster/generators/<%- subGenerator %>'; - <%_ } _%> -/** - * @type {import('generator-jhipster').JHipsterCommandDefinition} - */ -const command = { - options: { + +export default asCommand({ <%_ if (!sbs && !customGenerator) { _%> + options: { ...jhipsterCommand.options, -<%_ } _%> }, +<%_ } _%> configs: { <%_ if (!sbs && !customGenerator) { _%> ...jhipsterCommand.configs, <%_ } _%> }, - arguments: { <%_ if (!sbs && !customGenerator) { _%> + arguments: { ...jhipsterCommand.arguments, -<%_ } _%> }, -}; - -export default command; +<%_ } _%> +}); diff --git a/generators/generate-blueprint/templates/generators/generator/generator.mjs.jhi.ejs b/generators/generate-blueprint/templates/generators/generator/generator.mjs.jhi.ejs index a31274532275..8b394fb3025e 100644 --- a/generators/generate-blueprint/templates/generators/generator/generator.mjs.jhi.ejs +++ b/generators/generate-blueprint/templates/generators/generator/generator.mjs.jhi.ejs @@ -28,7 +28,7 @@ import <%= generatorClass %>Generator from 'generator-jhipster/generators/<%= jhipsterGenerator %>'; <%_ } _%> <%_ if (priorities.find(priority => priority.name === 'initializing')) { _%> -import command from './command.<%- js ? '' : 'm' %>js'; +import command from './command.<%- blueprintMjsExtension %>'; <%_ } _%> <%_ if (application.dynamic) { _%> @@ -48,21 +48,21 @@ export async function createGenerator(env) { <%_ } else { _%> export default class extends <%= generatorClass %>Generator { <%_ } _%> -<%_ if (sbs) { _%> - constructor(args, opts, features) { - super(args, opts, { ...features, sbsBlueprint: true }); - } - -<%_ } else if (!customGenerator) { _%> constructor(args, opts, features) { super(args, opts, { ...features, + queueCommandTasks: true, +<%_ if (sbs) { _%> + sbsBlueprint: true, +<%_ } else if (!customGenerator) { _%> checkBlueprint: true, // Dropped it once migration is done. jhipster7Migration: true, +<%_ } _%> }); } +<%_ if (!sbs && !customGenerator) { _%> async beforeQueue() { await super.beforeQueue(); } @@ -82,10 +82,7 @@ export default class extends <%= generatorClass %>Generator { { application } <%_ } _%> ) { - <%_ if (priority.name === 'initializing') { _%> - this.parseJHipsterArguments(command.arguments); - this.parseJHipsterOptions(command.options); - <%_ } else if (priority.name === 'writing') { _%> + <%_ if (priority.name === 'writing') { _%> await this.writeFiles({ sections: { files: [ diff --git a/generators/generate-blueprint/templates/generators/generator/generator.spec.mjs.ejs b/generators/generate-blueprint/templates/generators/generator/generator.spec.mjs.ejs index 2fce660b257e..9fd887094e3d 100644 --- a/generators/generate-blueprint/templates/generators/generator/generator.spec.mjs.ejs +++ b/generators/generate-blueprint/templates/generators/generator/generator.spec.mjs.ejs @@ -36,13 +36,13 @@ describe('SubGenerator <%= subGenerator %> of <%= application.baseName %> JHipst .withOptions({ ignoreNeedlesError: true, <%_ if (!customGenerator) { _%> - blueprint: '<%= application.baseName %>', + blueprint: ['<%= application.baseName %>'], <%_ } _%> <%_ if (subGenerator === 'jdl') { _%> inline: 'application { }', <%_ } _%> }) - .withJHipsterLookup() + .withJHipsterGenerators() .withParentBlueprintLookup(); }); diff --git a/generators/generate-blueprint/templates/generators/generator/index.mjs.ejs b/generators/generate-blueprint/templates/generators/generator/index.mjs.ejs index 9969e170d894..6652acd673b4 100644 --- a/generators/generate-blueprint/templates/generators/generator/index.mjs.ejs +++ b/generators/generate-blueprint/templates/generators/generator/index.mjs.ejs @@ -16,7 +16,5 @@ See the License for the specific language governing permissions and limitations under the License. -%> -export { <%- application.dynamic ? 'createGenerator' : 'default' %> } from './generator.<%- js ? '' : 'm' %>js'; -<%_ if (priorities.find(priority => priority.name === 'initializing')) { _%> -export { default as command } from './command.<%- js ? '' : 'm' %>js'; -<%_ } _%> +export { <%- application.dynamic ? 'createGenerator' : 'default' %> } from './generator.<%- blueprintMjsExtension %>'; +export { default as command } from './command.<%- blueprintMjsExtension %>'; diff --git a/generators/generate-blueprint/templates/vitest.config.ts.ejs b/generators/generate-blueprint/templates/vitest.config.ts.ejs index d1fa83cf8397..d46556a90a3b 100644 --- a/generators/generate-blueprint/templates/vitest.config.ts.ejs +++ b/generators/generate-blueprint/templates/vitest.config.ts.ejs @@ -5,6 +5,5 @@ export default defineConfig({ pool: 'forks', hookTimeout: 20000, exclude: [...defaultExclude.filter(val => val !== '**/cypress/**'), '**/templates/**', '**/resources/**'], - setupFiles: ['./vitest.test-setup.ts'], }, }); diff --git a/generators/generate-blueprint/templates/vitest.test-setup.ts.ejs b/generators/generate-blueprint/templates/vitest.test-setup.ts.ejs deleted file mode 100644 index b94ccb061ea0..000000000000 --- a/generators/generate-blueprint/templates/vitest.test-setup.ts.ejs +++ /dev/null @@ -1,6 +0,0 @@ -import { vi } from 'vitest'; -import { defineDefaults } from 'generator-jhipster/testing'; - -defineDefaults({ - mockFactory: () => vi.fn(), -}); diff --git a/generators/generator-constants.js b/generators/generator-constants.js index 0a07a3645b58..4dac7fec75fb 100644 --- a/generators/generator-constants.js +++ b/generators/generator-constants.js @@ -22,10 +22,11 @@ import { fileURLToPath } from 'url'; export const BLUEPRINT_API_VERSION = 'jhipster-8'; // jhipster-bom version -export const JHIPSTER_DEPENDENCIES_VERSION = '8.6.1-SNAPSHOT'; +export const JHIPSTER_DEPENDENCIES_VERSION = '8.7.2'; // Version of Java export const JAVA_VERSION = '17'; -export const JAVA_COMPATIBLE_VERSIONS = ['17', '18', '19', '20', '21', '22']; +// Supported Java versions, https://www.oracle.com/java/technologies/java-se-support-roadmap.html +export const JAVA_COMPATIBLE_VERSIONS = ['17', '21', '23']; // Force spring milestone repository. Spring Boot milestones are detected. export const ADD_SPRING_MILESTONE_REPOSITORY = false; @@ -34,7 +35,7 @@ export const NODE_VERSION = readFileSync(join(fileURLToPath(import.meta.url), '. export const OPENAPI_GENERATOR_CLI_VERSION = '2.13.1'; // The version should be coherent with the one from spring-data-elasticsearch project -export const ELASTICSEARCH_TAG = '8.10.4'; +export const ELASTICSEARCH_TAG = '8.13.4'; export const ELASTICSEARCH_IMAGE = 'docker.elastic.co/elasticsearch/elasticsearch'; /** diff --git a/generators/generator-list.js b/generators/generator-list.ts similarity index 100% rename from generators/generator-list.js rename to generators/generator-list.ts diff --git a/generators/git/command.ts b/generators/git/command.ts index 744aa7cfe437..bd6c9078c745 100644 --- a/generators/git/command.ts +++ b/generators/git/command.ts @@ -16,17 +16,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; -const command: JHipsterCommandDefinition = { - options: { +const command = { + configs: { skipGit: { description: 'Skip git repository initialization', - type: Boolean, + cli: { + type: Boolean, + }, + scope: 'generator', + }, + forceGit: { + description: 'Force commit to git repository', + cli: { + type: Boolean, + }, + scope: 'generator', + }, + commitMsg: { + description: 'Commit changes (implies forceGit)', + cli: { + type: String, + implies: { + forceGit: true, + }, + }, scope: 'generator', }, - }, - configs: { monorepository: { description: 'Use monorepository', cli: { @@ -35,6 +52,6 @@ const command: JHipsterCommandDefinition = { scope: 'storage', }, }, -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/git/files.js b/generators/git/files.ts similarity index 93% rename from generators/git/files.js rename to generators/git/files.ts index 7464803c7f6d..9a00c7089aed 100644 --- a/generators/git/files.js +++ b/generators/git/files.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// eslint-disable-next-line import/prefer-default-export + export const files = { git: [ { diff --git a/generators/git/generator.spec.ts b/generators/git/generator.spec.ts index bced2abedc1f..b26480b10a0e 100644 --- a/generators/git/generator.spec.ts +++ b/generators/git/generator.spec.ts @@ -16,19 +16,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join, resolve } from 'path'; +import { basename, dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; import { access } from 'fs/promises'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { testBlueprintSupport } from '../../test/support/tests.js'; -import { skipPrettierHelpers as helpers } from '../../testing/index.js'; +import { skipPrettierHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { GENERATOR_GIT } from '../generator-list.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorPath = join(__dirname, 'index.ts'); describe(`generator - ${generator}`, () => { it('generator-list constant matches folder name', () => { @@ -37,9 +36,8 @@ describe(`generator - ${generator}`, () => { describe('blueprint support', () => testBlueprintSupport(generator)); describe('with', () => { describe('default config', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath); + await helpers.runJHipster(generator); }); it('should write files and match snapshot', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); @@ -48,9 +46,8 @@ describe(`generator - ${generator}`, () => { }); describe('git feature', () => { describe('with default option', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath); + await helpers.runJHipster(generator).withOptions({ skipGit: false }); }); it('should create .git', async () => { await expect(access(resolve(runResult.cwd, '.git'))).resolves.toBeUndefined(); @@ -64,24 +61,32 @@ describe(`generator - ${generator}`, () => { }); }); describe('with skipGit option', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath).withOptions({ skipGit: true }); + await helpers.runJHipster(generator).withOptions({ skipGit: true }); }); it('should not create .git', async () => { await expect(access(resolve(runResult.cwd, '.git'))).rejects.toMatchObject({ code: 'ENOENT' }); }); }); describe('regenerating', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath); - runResult = await runResult.create(generatorPath).withOptions({ baseName: 'changed' }).run(); + await helpers.runJHipster(generator).withOptions({ skipGit: false }); + await helpers.runJHipsterInApplication(generator).withOptions({ skipGit: false, baseName: 'changed' }); }); - it('should have 1 commit', async () => { + it('should create a single commit', async () => { const git = runResult.generator.createGit(); await expect(git.log()).resolves.toMatchObject({ total: 1 }); }); }); + describe('regenerating with --force-git', () => { + before(async () => { + await helpers.runJHipster(generator).withOptions({ skipGit: false }); + await helpers.runJHipsterInApplication(generator).withOptions({ skipGit: false, forceGit: true, baseName: 'changed' }); + }); + it('should create 2 commits', async () => { + const git = runResult.generator.createGit(); + await expect(git.log()).resolves.toMatchObject({ total: 2 }); + }); + }); }); }); diff --git a/generators/git/generator.ts b/generators/git/generator.ts index e3eed603b3ea..82501db5fff3 100644 --- a/generators/git/generator.ts +++ b/generators/git/generator.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return */ + import chalk from 'chalk'; import type { QueuedAdapter } from '@yeoman/types'; @@ -27,10 +27,12 @@ import { files } from './files.js'; * @class * @extends {BaseGenerator} */ -export default class InitGenerator extends BaseGenerator { - gitInstalled; - gitInitialized; - skipGit; +export default class GitGenerator extends BaseGenerator { + gitInitialized!: boolean; + skipGit!: boolean; + forceGit!: boolean; + existingRepository!: boolean; + commitMsg!: string; async beforeQueue() { if (!this.fromBlueprint) { @@ -42,8 +44,8 @@ export default class InitGenerator extends BaseGenerator { return this.asInitializingTaskGroup({ async checkGit() { if (!this.skipGit) { - this.gitInstalled = (await this.createGit().version()).installed; - if (!this.gitInstalled) { + const gitInstalled = (await this.createGit().version()).installed; + if (!gitInstalled) { this.log.warn('Git repository will not be created, as Git is not installed on your system'); this.skipGit = true; } @@ -61,6 +63,21 @@ export default class InitGenerator extends BaseGenerator { return this.delegateTasksToBlueprint(() => this.initializing); } + get preparing() { + return this.asPreparingTaskGroup({ + async preparing() { + if (!this.skipGit) { + // Force write .yo-rc.json to disk, it's used to check if the application is regenerated + this.jhipsterConfig.skipGit = undefined; + } + }, + }); + } + + get [BaseGenerator.PREPARING]() { + return this.delegateTasksToBlueprint(() => this.preparing); + } + get writing() { return this.asWritingTaskGroup({ async writeFiles() { @@ -102,25 +119,32 @@ export default class InitGenerator extends BaseGenerator { this.debug('Committing files to git'); const git = this.createGit(); const repositoryRoot = await git.revparse(['--show-toplevel']); - const result = await git.log(['-n', '1', '--', '.yo-rc.json']).catch(() => {}); - if (result && result.total > 0) { + const result = await git.log(['-n', '1', '--', '.yo-rc.json']).catch(() => ({ total: 0 })); + const existingApplication = result.total > 0; + if (existingApplication && !this.forceGit) { this.log.info( `Found .yo-rc.json in Git from ${repositoryRoot}. So we assume this is application regeneration. Therefore automatic Git commit is not done. You can do Git commit manually.`, ); return; } - try { + if (!this.forceGit) { const statusResult = await git.status(); if (statusResult.staged.length > 0) { this.log.verboseInfo(`The repository ${repositoryRoot} has staged files, skipping commit.`); return; } - let commitMsg = `Initial version of ${this.jhipsterConfig.baseName} generated by generator-jhipster@${this.jhipsterConfig.jhipsterVersion}`; + } + try { + let commitMsg = + this.commitMsg ?? + (existingApplication + ? `Regenerated ${this.jhipsterConfig.baseName} using generator-jhipster@${this.jhipsterConfig.jhipsterVersion}` + : `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}`; } - await git.add(['.']).commit(commitMsg); + await git.add(['.']).commit(commitMsg, { '--allow-empty': null, '--no-verify': null }); this.log.ok(`Application successfully committed to Git from ${repositoryRoot}.`); } catch (e) { this.log.warn( @@ -146,10 +170,13 @@ export default class InitGenerator extends BaseGenerator { async initializeGitRepository() { try { const git = this.createGit(); - if (await git.checkIsRepo('root' as any)) { - this.log.info('Using existing git repository.'); - } else if (await git.checkIsRepo()) { - this.log.info('Using existing git repository at parent folder.'); + if (await git.checkIsRepo()) { + if (await git.checkIsRepo('root' as any)) { + this.log.info('Using existing git repository.'); + } else { + this.log.info('Using existing git repository at parent folder.'); + } + this.existingRepository = true; } else if (await git.init()) { this.log.ok('Git repository initialized.'); } diff --git a/generators/gradle/__snapshots__/generator.spec.js.snap b/generators/gradle/__snapshots__/generator.spec.ts.snap similarity index 100% rename from generators/gradle/__snapshots__/generator.spec.js.snap rename to generators/gradle/__snapshots__/generator.spec.ts.snap diff --git a/generators/gradle/command.ts b/generators/gradle/command.ts index 6e19eda9e19d..2324e3f637f9 100644 --- a/generators/gradle/command.ts +++ b/generators/gradle/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { options: {}, diff --git a/generators/gradle/constants.js b/generators/gradle/constants.ts similarity index 100% rename from generators/gradle/constants.js rename to generators/gradle/constants.ts diff --git a/generators/gradle/generator.spec.js b/generators/gradle/generator.spec.ts similarity index 84% rename from generators/gradle/generator.spec.js rename to generators/gradle/generator.spec.ts index 8ee34a1d5518..e76fe7cc7d05 100644 --- a/generators/gradle/generator.spec.js +++ b/generators/gradle/generator.spec.ts @@ -16,18 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { testBlueprintSupport } from '../../test/support/tests.js'; -import { defaultHelpers as helpers, runResult } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { GENERATOR_JHIPSTER } from '../generator-constants.js'; import { GENERATOR_GRADLE } from '../generator-list.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorFile = join(__dirname, 'index.js'); describe(`generator - ${generator}`, () => { it('generator-list constant matches folder name', () => { @@ -36,7 +35,7 @@ describe(`generator - ${generator}`, () => { describe('blueprint support', () => testBlueprintSupport(generator)); describe('with valid configuration', () => { before(async () => { - await helpers.run(generatorFile).withJHipsterConfig({ + await helpers.runJHipster(generator).withJHipsterConfig({ baseName: 'existing', packageName: 'tech.jhipster', }); @@ -50,7 +49,7 @@ describe(`generator - ${generator}`, () => { }); describe('with empty configuration', () => { before(async () => { - await helpers.run(generatorFile).withJHipsterConfig(); + await helpers.runJHipster(generator).withJHipsterConfig(); }); it('should generate only gradle files', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); @@ -63,7 +62,7 @@ describe(`generator - ${generator}`, () => { describe('with custom gradleVersion', () => { const gradleVersion = 'fooVersion'; before(async () => { - await helpers.run(generatorFile).withSharedApplication({ gradleVersion }).withJHipsterConfig(); + await helpers.runJHipster(generator).withSharedApplication({ gradleVersion }).withJHipsterConfig(); }); it('should set gradleVersion at gradle-wrapper.properties', () => { runResult.assertFileContent('gradle/wrapper/gradle-wrapper.properties', `-${gradleVersion}-`); diff --git a/generators/gradle/generator.ts b/generators/gradle/generator.ts index 0d97d52b8333..824736a1ddae 100644 --- a/generators/gradle/generator.ts +++ b/generators/gradle/generator.ts @@ -16,31 +16,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return */ + import assert from 'assert/strict'; import BaseApplicationGenerator from '../base-application/index.js'; import { GRADLE_BUILD_SRC_DIR } from '../generator-constants.js'; -import { mutateData } from '../base/support/config.js'; +import { mutateData } from '../../lib/utils/object.js'; +import { QUEUES } from '../base/priorities.js'; import files from './files.js'; import { GRADLE } from './constants.js'; import cleanupOldServerFilesTask from './cleanup.js'; import { - applyFromGradleCallback, addGradleDependenciesCallback, - addGradleMavenRepositoryCallback, - addGradlePluginCallback, - addGradlePluginManagementCallback, - addGradlePropertyCallback, addGradleDependenciesCatalogVersionCallback, addGradleDependencyCatalogLibrariesCallback, addGradleDependencyCatalogPluginsCallback, - addGradleDependencyFromCatalogCallback, + addGradleMavenRepositoryCallback, + addGradlePluginCallback, addGradlePluginFromCatalogCallback, - sortDependencies, + addGradlePluginManagementCallback, + addGradlePropertyCallback, + applyFromGradleCallback, gradleNeedleOptionsWithDefaults, + sortDependencies, } from './internal/needles.js'; +import type { GradleDependency } from './types.js'; + +const { PRE_CONFLICTS_QUEUE } = QUEUES; export default class GradleGenerator extends BaseApplicationGenerator { gradleVersionFromWrapper; @@ -103,6 +106,20 @@ export default class GradleGenerator extends BaseApplicationGenerator { source.applyFromGradle = script => this.editFile('build.gradle', applyFromGradleCallback(script)); source.addGradleDependencies = (dependencies, options = {}) => { const { gradleFile } = gradleNeedleOptionsWithDefaults(options); + if (gradleFile === 'build.gradle') { + source._gradleDependencies = source._gradleDependencies ?? []; + source._gradleDependencies.push(...dependencies); + this.queueTask({ + method: () => { + this.editFile(gradleFile, addGradleDependenciesCallback((source as any)._gradleDependencies.sort(sortDependencies))); + (source as any)._gradleDependencies = []; + }, + taskName: '_persiteGradleDependencies', + once: true, + queueName: PRE_CONFLICTS_QUEUE, + }); + return; + } dependencies = [...dependencies].sort(sortDependencies); this.editFile(gradleFile, addGradleDependenciesCallback(dependencies)); }; @@ -121,7 +138,7 @@ export default class GradleGenerator extends BaseApplicationGenerator { const { gradleFile, gradleVersionCatalogFile } = gradleNeedleOptionsWithDefaults(options); libs = [...libs].sort((a, b) => a.libraryName.localeCompare(b.libraryName)); this.editFile(gradleVersionCatalogFile, addGradleDependencyCatalogLibrariesCallback(libs)); - this.editFile(gradleFile, addGradleDependencyFromCatalogCallback(libs)); + source.addGradleDependencies!(libs.filter(lib => lib.scope) as GradleDependency[], { gradleFile }); }; source.addGradleDependencyCatalogLibrary = (lib, options) => source.addGradleDependencyCatalogLibraries!([lib], options); source.addGradleDependencyCatalogPlugins = plugins => { diff --git a/generators/gradle/generators/code-quality/generator.spec.ts b/generators/gradle/generators/code-quality/generator.spec.ts index 1a83f071acf4..791b1266bbef 100644 --- a/generators/gradle/generators/code-quality/generator.spec.ts +++ b/generators/gradle/generators/code-quality/generator.spec.ts @@ -1,9 +1,9 @@ import { basename, dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); diff --git a/generators/gradle/generators/jib/__snapshots__/generator.spec.ts.snap b/generators/gradle/generators/jib/__snapshots__/generator.spec.ts.snap index e58a1e36a5bd..6681bbcff1e6 100644 --- a/generators/gradle/generators/jib/__snapshots__/generator.spec.ts.snap +++ b/generators/gradle/generators/jib/__snapshots__/generator.spec.ts.snap @@ -51,6 +51,7 @@ jib-plugin = { module = "com.google.cloud.tools:jib-gradle-plugin", version = "' } jib { + configurationName = "productionRuntimeClasspath" from { image = "java-jre-placeholder" platforms { diff --git a/generators/gradle/generators/jib/generator.spec.ts b/generators/gradle/generators/jib/generator.spec.ts index 1a83f071acf4..791b1266bbef 100644 --- a/generators/gradle/generators/jib/generator.spec.ts +++ b/generators/gradle/generators/jib/generator.spec.ts @@ -1,9 +1,9 @@ import { basename, dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); diff --git a/generators/gradle/generators/jib/templates/buildSrc/src/main/groovy/jhipster.docker-conventions.gradle.ejs b/generators/gradle/generators/jib/templates/buildSrc/src/main/groovy/jhipster.docker-conventions.gradle.ejs index 87530f152cb7..bd5155d6bcfb 100644 --- a/generators/gradle/generators/jib/templates/buildSrc/src/main/groovy/jhipster.docker-conventions.gradle.ejs +++ b/generators/gradle/generators/jib/templates/buildSrc/src/main/groovy/jhipster.docker-conventions.gradle.ejs @@ -21,6 +21,9 @@ plugins { } jib { +<%_ if (backendTypeSpringBoot) { _%> + configurationName = "productionRuntimeClasspath" +<%_ } _%> from { image = "<%- dockerContainers.javaJre %>" platforms { diff --git a/generators/gradle/generators/node-gradle/templates/buildSrc/src/main/groovy/jhipster.node-gradle-conventions.gradle.ejs b/generators/gradle/generators/node-gradle/templates/buildSrc/src/main/groovy/jhipster.node-gradle-conventions.gradle.ejs index 76180541fd09..14f7dd732ac8 100644 --- a/generators/gradle/generators/node-gradle/templates/buildSrc/src/main/groovy/jhipster.node-gradle-conventions.gradle.ejs +++ b/generators/gradle/generators/node-gradle/templates/buildSrc/src/main/groovy/jhipster.node-gradle-conventions.gradle.ejs @@ -66,23 +66,29 @@ task webapp_test(type: NpmTask) { inputs.files("tsconfig.json", "tsconfig.app.json") .withPropertyName("tsconfig") .withPathSensitivity(PathSensitivity.RELATIVE) - <%_ if (microfrontend) { _%> - def webpackDevFiles = fileTree("<%= CLIENT_WEBPACK_DIR %>") - webpackDevFiles.exclude("webpack.prod.js") - inputs.files(webpackDevFiles) - .withPropertyName("webpack-dir") + inputs.files(".postcssrc") + .withPropertyName("postcssrc") .withPathSensitivity(PathSensitivity.RELATIVE) - <%_ } else { _%> + <%_ } _%> + <%_ if (clientBundlerVite && clientFrameworkBuiltIn) { _%> - inputs.files("vite.config.ts") + inputs.files("vite.config.mts") .withPropertyName("vite") .withPathSensitivity(PathSensitivity.RELATIVE) + <%_ } _%> + <%_ if (clientFrameworkVue) { _%> + <%_ if (clientBundlerWebpack) { _%> + def webpackDevFiles = fileTree("<%= CLIENT_WEBPACK_DIR %>") + webpackDevFiles.exclude("webpack.prod.js") + inputs.files(webpackDevFiles) + .withPropertyName("webpack-dir") <%_ } _%> - - inputs.files(".postcssrc") - .withPropertyName("postcssrc") + <%_ if (microfrontend) { _%> + inputs.files("module-federation.config.cjs") + .withPropertyName("module-federation") .withPathSensitivity(PathSensitivity.RELATIVE) + <%_ } _%> <%_ } _%> outputs.dir("build/test-results/jest/") diff --git a/generators/gradle/internal/needles.ts b/generators/gradle/internal/needles.ts index c221e810d6c6..4c9cff52c98c 100644 --- a/generators/gradle/internal/needles.ts +++ b/generators/gradle/internal/needles.ts @@ -18,16 +18,16 @@ */ import { createNeedleCallback } from '../../base/support/index.js'; import type { - GradleScript, + GradleComment, GradleDependency, + GradleLibraryDependency, + GradleNeedleOptions, GradlePlugin, GradleProperty, GradleRepository, - GradleTomlVersion, - GradleLibrary, + GradleScript, GradleTomlPlugin, - GradleComment, - GradleNeedleOptions, + GradleTomlVersion, } from '../types.js'; const tomlItemToString = (item: Record) => @@ -43,6 +43,30 @@ const scopeSortOrder = { implementation: 2, compileOnly: 3, runtimeOnly: 4, + testImplementation: 5, + testRuntimeOnly: 6, +}; + +const wrapScope = (scope: string, dependency: string, closure?: string[]) => { + if (closure?.length || scope === 'implementation platform') { + return `${scope}(${dependency})${closure?.length ? ` {\n${closure.join('\n')}\n}` : ''}`; + } + return `${scope} ${dependency}`; +}; + +const serializeDependency = (dependency: GradleDependency) => { + if ('libraryName' in dependency) { + return wrapScope(dependency.scope, `libs.${gradleNameToReference(dependency.libraryName)}`, dependency.closure); + } + + const { groupId, artifactId, version, classifier, scope, closure } = dependency; + return wrapScope( + scope, + classifier && !version + ? `group: "${groupId}", name: "${artifactId}", classifier: "${classifier}"` + : `"${groupId}:${artifactId}${version ? `:${version}` : ''}${classifier ? `:${classifier}` : ''}"`, + closure, + ); }; export const gradleNeedleOptionsWithDefaults = (options: GradleNeedleOptions): Required => { @@ -52,21 +76,32 @@ export const gradleNeedleOptionsWithDefaults = (options: GradleNeedleOptions): R export const sortDependencies = (a: GradleDependency, b: GradleDependency): number => { let ret = (scopeSortOrder[a.scope] ?? 100) - (scopeSortOrder[b.scope] ?? 100); - if (ret === 0) { - ret = a.groupId.localeCompare(b.groupId); - if (ret !== 0) { - // Keep Spring dependencies on top - const aIsSpring = a.groupId.startsWith('org.springframework.'); - const bIsSpring = b.groupId.startsWith('org.springframework.'); - if (aIsSpring !== bIsSpring && (aIsSpring || bIsSpring)) { - return aIsSpring ? -1 : 1; - } + // Keep implementation platform scope dependencies in the order they were added + if (ret !== 0 || a.scope === 'implementation platform') { + return ret; + } + ret = a.scope.localeCompare(b.scope); + if (ret !== 0) { + return ret; + } + if ('libraryName' in a || 'libraryName' in b) { + // Keep catalog dependencies on top + if ('libraryName' in a && 'libraryName' in b) { + return a.libraryName.localeCompare(b.libraryName); } + return 'libraryName' in a ? -1 : 1; } - if (ret === 0) { - ret = a.artifactId.localeCompare(b.artifactId); + ret = a.groupId.localeCompare(b.groupId); + if (ret !== 0) { + // Keep Spring dependencies on top + const aIsSpring = a.groupId.startsWith('org.springframework.'); + const bIsSpring = b.groupId.startsWith('org.springframework.'); + if (aIsSpring !== bIsSpring && (aIsSpring || bIsSpring)) { + return aIsSpring ? -1 : 1; + } + return ret; } - return ret; + return ret === 0 ? a.artifactId.localeCompare(b.artifactId) : ret; }; export const applyFromGradleCallback = ({ script }: GradleScript) => @@ -78,18 +113,14 @@ export const applyFromGradleCallback = ({ script }: GradleScript) => export const addGradleDependenciesCallback = (dependencies: GradleDependency[]) => createNeedleCallback({ needle: 'gradle-dependency', - contentToAdd: dependencies.map(({ groupId, artifactId, version, scope, classifier }) => - classifier && !version - ? `${scope} group: "${groupId}", name: "${artifactId}", classifier: "${classifier}"` - : `${scope} "${groupId}:${artifactId}${version ? `:${version}` : ''}${classifier ? `:${classifier}` : ''}"`, - ), + contentToAdd: dependencies.map(serializeDependency), }); /** @deprecated use addGradleDependenciesCallback */ -export const addGradleBuildSrcDependencyCallback = ({ groupId, artifactId, version, scope }: GradleDependency) => +export const addGradleBuildSrcDependencyCallback = (dependency: GradleDependency) => createNeedleCallback({ needle: 'gradle-build-src-dependency', - contentToAdd: `${scope} "${groupId}:${artifactId}${version ? `:${version}` : ''}"`, + contentToAdd: serializeDependency(dependency), }); export const addGradleDependenciesCatalogVersionCallback = (versions: GradleTomlVersion[]) => @@ -98,26 +129,14 @@ export const addGradleDependenciesCatalogVersionCallback = (versions: GradleToml contentToAdd: versions.map(({ name, version }) => `${name} = "${version}"`), }); -export const addGradleDependencyCatalogLibrariesCallback = (libraries: GradleLibrary[]) => +export const addGradleDependencyCatalogLibrariesCallback = (libraries: (GradleLibraryDependency & { closure?: string[] })[]) => createNeedleCallback({ needle: 'gradle-dependency-catalog-libraries', - contentToAdd: libraries.map(({ libraryName, scope: _scope, ...others }) => + contentToAdd: libraries.map(({ libraryName, scope: _scope, closure: _closure, ...others }) => 'library' in others ? `${libraryName} = "${others.library}"` : `${libraryName} = ${tomlItemToString(others)}`, ), }); -export const addGradleDependencyFromCatalogCallback = (libraries: GradleLibrary[]) => - createNeedleCallback({ - needle: 'gradle-dependency', - contentToAdd: libraries - .filter(({ scope }) => scope) - .map(({ libraryName, scope }) => - scope === 'implementation platform' - ? `${scope}(libs.${gradleNameToReference(libraryName)})` - : `${scope} libs.${gradleNameToReference(libraryName)}`, - ), - }); - export const addGradleDependencyCatalogPluginsCallback = (plugins: GradleTomlPlugin[]) => createNeedleCallback({ needle: 'gradle-dependency-catalog-plugins', diff --git a/generators/gradle/needles.spec.ts b/generators/gradle/needles.spec.ts index 9c4b112d7f56..ee5fb78c7341 100644 --- a/generators/gradle/needles.spec.ts +++ b/generators/gradle/needles.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe } from 'esmocha'; -import { dryRunHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { before, describe, it } from 'esmocha'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import BaseApplicationGenerator from '../base-application/index.js'; import { GENERATOR_SERVER } from '../generator-list.js'; @@ -45,10 +45,12 @@ describe('needle API server gradle: JHipster server generator with blueprint', ( await helpers .runJHipster(GENERATOR_SERVER) .withJHipsterConfig({ - blueprint: 'myblueprint', clientFramework: 'no', buildTool: 'gradle', }) + .withOptions({ + blueprint: ['myblueprint'], + }) .withGenerators([[mockBlueprintSubGen, { namespace: 'jhipster-myblueprint:server' }]]); }); diff --git a/generators/gradle/support/dependabot-gradle.ts b/generators/gradle/support/dependabot-gradle.ts index 6a2aafcfe25c..8be6b838fc75 100644 --- a/generators/gradle/support/dependabot-gradle.ts +++ b/generators/gradle/support/dependabot-gradle.ts @@ -24,7 +24,6 @@ type LibsToml = { plugins?: Record; }; -// eslint-disable-next-line import/prefer-default-export export function getGradleLibsVersionsProperties(libsVersionsContent: string): Record { const parsed = parse(libsVersionsContent) as LibsToml; return { diff --git a/generators/gradle/templates/gradle/wrapper/gradle-wrapper.properties b/generators/gradle/templates/gradle/wrapper/gradle-wrapper.properties index 19cfad969baf..1e2fbf0d4587 100644 --- a/generators/gradle/templates/gradle/wrapper/gradle-wrapper.properties +++ b/generators/gradle/templates/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/generators/gradle/types.d.ts b/generators/gradle/types.d.ts index f488f15fb771..e8a8c97094da 100644 --- a/generators/gradle/types.d.ts +++ b/generators/gradle/types.d.ts @@ -1,10 +1,15 @@ -import { RequireOneOrNone } from 'type-fest'; +import type { RequireOneOrNone } from 'type-fest'; export type GradleComment = { comment?: string }; export type GradleScript = { script: string }; -export type GradleDependency = { groupId: string; artifactId: string; version?: string; scope: string; classifier?: string }; +export type GradleLibraryDependency = { libraryName: string; scope?: string }; + +export type GradleDependency = ( + | { groupId: string; artifactId: string; version?: string; scope: string; classifier?: string } + | Required +) & { closure?: string[] }; export type GradlePlugin = { id: string; version?: string }; @@ -18,10 +23,7 @@ export type GradleTomlAnyItemVersion = RequireOneOrNone<{ version: string; 'vers export type GradleTomlLibraryId = { module: string } | { group: string; name: string }; -export type GradleLibrary = { libraryName: string; scope?: string } & ( - | { library: string } - | (GradleTomlLibraryId & GradleTomlAnyItemVersion) -); +export type GradleLibrary = GradleLibraryDependency & ({ library: string } | (GradleTomlLibraryId & GradleTomlAnyItemVersion)); export type GradleTomlPlugin = { pluginName: string; addToBuild?: boolean } & ( | { plugin: string } @@ -34,6 +36,7 @@ export type GradleCatalogNeedleOptions = { gradleVersionCatalogFile?: string }; export type GradleNeedleOptions = GradleFileNeedleOptions & GradleCatalogNeedleOptions; export type GradleSourceType = { + _gradleDependencies?: GradleDependency[]; applyFromGradle?(script: GradleScript): void; addGradleDependency?(dependency: GradleDependency, options?: GradleFileNeedleOptions): void; addGradleDependencies?(dependency: GradleDependency[], options?: GradleFileNeedleOptions): void; diff --git a/generators/ci-cd/generator.spec.js b/generators/heroku/generator.spec.ts similarity index 96% rename from generators/ci-cd/generator.spec.js rename to generators/heroku/generator.spec.ts index 2ba7f42964c7..eac371cd8f9f 100644 --- a/generators/ci-cd/generator.spec.js +++ b/generators/heroku/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; diff --git a/generators/heroku/generator.js b/generators/heroku/generator.ts similarity index 99% rename from generators/heroku/generator.js rename to generators/heroku/generator.ts index 1d3921feb6eb..1765265366cd 100644 --- a/generators/heroku/generator.js +++ b/generators/heroku/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return */ + import { kebabCase } from 'lodash-es'; import chalk from 'chalk'; import { glob } from 'glob'; @@ -139,7 +140,7 @@ export default class HerokuGenerator extends BaseGenerator { type: 'input', name: 'herokuAppName', message: 'Name to deploy as:', - default: this.baseName, + default: this.jhipsterConfigWithDefaults.baseName, }, ], this.config, diff --git a/generators/heroku/heroku.spec.ts b/generators/heroku/heroku.spec.ts index 6ef288bc4283..58611e020bc4 100644 --- a/generators/heroku/heroku.spec.ts +++ b/generators/heroku/heroku.spec.ts @@ -1,13 +1,18 @@ -import sinon, { SinonStub } from 'sinon'; -import { it, describe, expect, beforeEach } from 'esmocha'; +import type { SinonStub } from 'sinon'; +import sinon from 'sinon'; +import { beforeEach, describe, expect, it } from 'esmocha'; import { SERVER_MAIN_RES_DIR } from '../generator-constants.js'; -import { defaultHelpers as helpers, runResult } from '../../testing/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { GENERATOR_HEROKU } from '../generator-list.js'; const expectedFiles = { monolith: ['Procfile', `${SERVER_MAIN_RES_DIR}/config/bootstrap-heroku.yml`, `${SERVER_MAIN_RES_DIR}/config/application-heroku.yml`], }; +const getSinonRunResultCalls = () => { + return runResult.spawnStub!.getCalls().map(call => call.args); +}; + const createSpawnCommandReturn = (resolvedValue?, data?) => Object.assign( Promise.resolve({ @@ -43,7 +48,7 @@ describe('generator - Heroku', () => { describe('with JAR deployment', () => { beforeEach(async () => { await helpers - .createJHipster(GENERATOR_HEROKU) + .runJHipster(GENERATOR_HEROKU) .withJHipsterConfig({ applicationType: 'microservice' }) .withOptions({ skipBuild: true }) .withAnswers({ @@ -55,8 +60,7 @@ describe('generator - Heroku', () => { herokuJHipsterRegistryPassword: 'changeme', herokuJavaVersion: '17', }) - .withSpawnMock(stub) - .run(); + .withSpawnMock(stub); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -79,7 +83,7 @@ describe('generator - Heroku', () => { .returns(createSpawnCommandReturn({ stdout: `https://git.heroku.com/${autogeneratedAppName}.git` })); await helpers - .createJHipster(GENERATOR_HEROKU) + .runJHipster(GENERATOR_HEROKU) .withJHipsterConfig() .withOptions({ skipBuild: true }) .withAnswers({ @@ -89,8 +93,7 @@ describe('generator - Heroku', () => { herokuForceName: 'No', herokuJavaVersion: '11', }) - .withSpawnMock(stub) - .run(); + .withSpawnMock(stub); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -100,14 +103,14 @@ describe('generator - Heroku', () => { runResult.assertJsonFileContent('.yo-rc.json', { 'generator-jhipster': { herokuAppName: autogeneratedAppName } }); }); it('calls should match snapshot', () => { - expect(runResult.getSpawnArgsUsingDefaultImplementation()).toMatchSnapshot(); + expect(getSinonRunResultCalls()).toMatchSnapshot(); }); }); describe('with Git deployment', () => { beforeEach(async () => { await helpers - .createJHipster(GENERATOR_HEROKU) + .runJHipster(GENERATOR_HEROKU) .withJHipsterConfig() .withAnswers({ herokuAppName, @@ -115,8 +118,7 @@ describe('generator - Heroku', () => { herokuDeployType: 'git', herokuJavaVersion: '11', }) - .withSpawnMock(stub) - .run(); + .withSpawnMock(stub); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -126,14 +128,14 @@ describe('generator - Heroku', () => { runResult.assertFileContent('.yo-rc.json', '"herokuDeployType": "git"'); }); it('calls should match snapshot', () => { - expect(runResult.getSpawnArgsUsingDefaultImplementation()).toMatchSnapshot(); + expect(getSinonRunResultCalls()).toMatchSnapshot(); }); }); describe('in the US', () => { beforeEach(async () => { await helpers - .createJHipster(GENERATOR_HEROKU) + .runJHipster(GENERATOR_HEROKU) .withJHipsterConfig() .withOptions({ skipBuild: true }) .withAnswers({ @@ -142,8 +144,7 @@ describe('generator - Heroku', () => { herokuDeployType: 'jar', herokuJavaVersion: '11', }) - .withSpawnMock(stub) - .run(); + .withSpawnMock(stub); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -155,14 +156,14 @@ describe('generator - Heroku', () => { runResult.assertNoFileContent(`${SERVER_MAIN_RES_DIR}/config/application-heroku.yml`, 'mongodb:'); }); it('calls should match snapshot', () => { - expect(runResult.getSpawnArgsUsingDefaultImplementation()).toMatchSnapshot(); + expect(getSinonRunResultCalls()).toMatchSnapshot(); }); }); describe('in the EU', () => { beforeEach(async () => { await helpers - .createJHipster(GENERATOR_HEROKU) + .runJHipster(GENERATOR_HEROKU) .withJHipsterConfig() .withOptions({ skipBuild: true }) .withAnswers({ @@ -171,8 +172,7 @@ describe('generator - Heroku', () => { herokuDeployType: 'jar', herokuJavaVersion: '11', }) - .withSpawnMock(stub) - .run(); + .withSpawnMock(stub); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -181,14 +181,14 @@ describe('generator - Heroku', () => { runResult.assertFile(expectedFiles.monolith); }); it('calls should match snapshot', () => { - expect(runResult.getSpawnArgsUsingDefaultImplementation()).toMatchSnapshot(); + expect(getSinonRunResultCalls()).toMatchSnapshot(); }); }); describe('with PostgreSQL', () => { beforeEach(async () => { await helpers - .createJHipster(GENERATOR_HEROKU) + .runJHipster(GENERATOR_HEROKU) .withJHipsterConfig() .withOptions({ skipBuild: true }) .withAnswers({ @@ -197,8 +197,7 @@ describe('generator - Heroku', () => { herokuDeployType: 'jar', herokuJavaVersion: '11', }) - .withSpawnMock(stub) - .run(); + .withSpawnMock(stub); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -209,7 +208,7 @@ describe('generator - Heroku', () => { runResult.assertNoFileContent(`${SERVER_MAIN_RES_DIR}/config/application-heroku.yml`, 'mongodb:'); }); it('calls should match snapshot', () => { - expect(runResult.getSpawnArgsUsingDefaultImplementation()).toMatchSnapshot(); + expect(getSinonRunResultCalls()).toMatchSnapshot(); }); }); @@ -220,11 +219,10 @@ describe('generator - Heroku', () => { .withArgs('spawn', 'heroku', sinon.match(['apps:info', '--json', existingHerokuAppName])) .returns(createSpawnCommandReturn({ stdout: `{"app":{"name":"${existingHerokuAppName}"}, "dynos":[]}` })); await helpers - .createJHipster(GENERATOR_HEROKU) - .withJHipsterConfig({ herokuAppName: 'jhipster-existing', herokuDeployType: 'git' }) + .runJHipster(GENERATOR_HEROKU) + .withJHipsterConfig({ herokuAppName: 'jhipster-existing', herokuDeployType: 'git' }) .withOptions({ skipBuild: true }) - .withSpawnMock(stub) - .run(); + .withSpawnMock(stub); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -234,14 +232,14 @@ describe('generator - Heroku', () => { runResult.assertFileContent('.yo-rc.json', `"herokuAppName": "${existingHerokuAppName}"`); }); it('calls should match snapshot', () => { - expect(runResult.getSpawnArgsUsingDefaultImplementation()).toMatchSnapshot(); + expect(getSinonRunResultCalls()).toMatchSnapshot(); }); }); describe('with elasticsearch', () => { beforeEach(async () => { await helpers - .createJHipster(GENERATOR_HEROKU) + .runJHipster(GENERATOR_HEROKU) .withJHipsterConfig({ searchEngine: 'elasticsearch' }) .withOptions({ skipBuild: true }) .withAnswers({ @@ -250,8 +248,7 @@ describe('generator - Heroku', () => { herokuDeployType: 'jar', herokuJavaVersion: '11', }) - .withSpawnMock(stub) - .run(); + .withSpawnMock(stub); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -263,7 +260,7 @@ describe('generator - Heroku', () => { runResult.assertNoFileContent(`${SERVER_MAIN_RES_DIR}/config/application-heroku.yml`, 'mongodb:'); }); it('calls should match snapshot', () => { - expect(runResult.getSpawnArgsUsingDefaultImplementation()).toMatchSnapshot(); + expect(getSinonRunResultCalls()).toMatchSnapshot(); }); }); }); diff --git a/generators/heroku/templates.js b/generators/heroku/templates.ts similarity index 98% rename from generators/heroku/templates.js rename to generators/heroku/templates.ts index 4663ca893080..5fb22eb660c6 100644 --- a/generators/heroku/templates.js +++ b/generators/heroku/templates.ts @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/prefer-default-export export const mavenProfileContent = data => { return ` diff --git a/generators/index.ts b/generators/index.ts index 967b7d6cc808..2f85e379e6ed 100644 --- a/generators/index.ts +++ b/generators/index.ts @@ -23,7 +23,9 @@ export { CLIENT_TEST_SRC_DIR as TEMPLATES_JAVASCRIPT_TEST_DIR, } from './generator-constants.js'; -export type { JHipsterCommandDefinition } from './base/api.js'; +export * from './type-utils.js'; + +export type { JHipsterCommandDefinition } from '../lib/command/index.js'; export { default as GeneratorBase } from './base/index.js'; export { default as GeneratorBaseCore } from './base-core/index.js'; diff --git a/generators/info/generator.spec.ts b/generators/info/generator.spec.ts index b25895cf89f4..d90bf385002d 100644 --- a/generators/info/generator.spec.ts +++ b/generators/info/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures } from '../../test/support/tests.js'; diff --git a/generators/info/generator.ts b/generators/info/generator.ts index 2abfa3bfa582..9ff2b5a328fc 100644 --- a/generators/info/generator.ts +++ b/generators/info/generator.ts @@ -22,11 +22,13 @@ import chalk from 'chalk'; import BaseApplicationGenerator from '../base-application/index.js'; -import JSONToJDLEntityConverter from '../../jdl/converters/json-to-jdl-entity-converter.js'; -import JSONToJDLOptionConverter from '../../jdl/converters/json-to-jdl-option-converter.js'; +import JSONToJDLEntityConverter from '../../lib/jdl/converters/json-to-jdl-entity-converter.js'; +import JSONToJDLOptionConverter from '../../lib/jdl/converters/json-to-jdl-option-converter.js'; import type { JHipsterGeneratorFeatures, JHipsterGeneratorOptions } from '../base/api.js'; import { YO_RC_FILE } from '../generator-constants.js'; -import { JSONEntity } from '../../jdl/converters/types.js'; +import { applicationsLookup } from '../workspaces/support/applications-lookup.js'; +import type { Entity } from '../../lib/types/base/entity.js'; +import { convertFieldBlobType } from '../../lib/application/field-types.js'; import { replaceSensitiveConfig } from './support/utils.js'; const isInfoCommand = commandName => commandName === 'info' || undefined; @@ -53,7 +55,7 @@ export default class InfoGenerator extends BaseApplicationGenerator { console.log(`\n\`\`\`\n${stdout}\`\`\`\n`); }, - displayConfiguration() { + async displayConfiguration() { // Omit sensitive information. const yoRc = this.readDestinationJSON(YO_RC_FILE); if (yoRc) { @@ -64,7 +66,11 @@ export default class InfoGenerator extends BaseApplicationGenerator { console.log('\n##### **JHipster configuration not found**\n'); } - const packages = this.jhipsterConfig.appsFolders ?? this.jhipsterConfig.packages ?? []; + let packages = this.jhipsterConfig.appsFolders ?? this.jhipsterConfig.packages ?? []; + if (!yoRc && packages.length === 0) { + packages = await applicationsLookup(this.destinationRoot()); + } + if (packages.length > 0) { for (const pkg of packages) { const yoRc = this.readDestinationJSON(this.destinationPath(pkg, YO_RC_FILE)); @@ -125,7 +131,7 @@ export default class InfoGenerator extends BaseApplicationGenerator { ) { try { printInfo(await this.spawn(command, args, { stdio: 'pipe' })); - } catch (_error) { + } catch { console.log(chalk.red(`'${command}' command could not be found`)); } } @@ -135,10 +141,17 @@ export default class InfoGenerator extends BaseApplicationGenerator { */ generateJDLFromEntities() { let jdlObject; - const entities = new Map(); + const entities = new Map(); try { - this.getExistingEntities().forEach(entity => { - entities.set(entity.name, entity.definition); + this.getExistingEntities().forEach(({ name, definition: entity }) => { + if (entity.fields) { + for (const field of entity.fields) { + if (field.fieldType === 'byte[]') { + convertFieldBlobType(field); + } + } + } + entities.set(name, entity); }); jdlObject = JSONToJDLEntityConverter.convertEntitiesToJDL(entities); JSONToJDLOptionConverter.convertServerOptionsToJDL({ 'generator-jhipster': this.config.getAll() }, jdlObject); diff --git a/generators/init/__snapshots__/generator.spec.ts.snap b/generators/init/__snapshots__/generator.spec.ts.snap index 18b0abd3ff78..bfca045fdd95 100644 --- a/generators/init/__snapshots__/generator.spec.ts.snap +++ b/generators/init/__snapshots__/generator.spec.ts.snap @@ -11,9 +11,12 @@ Options: --skip-install Do not automatically install dependencies (default: false) --force-install Fail on install dependencies error (default: false) --ask-answered Show prompts for already configured options (default: false) - --base-name Application base name - --prettier-tab-width Default tab width for prettier + --skip-git Skip git repository initialization + --force-git Force commit to git repository + --commit-msg Commit changes (implies forceGit) --monorepository Use monorepository + --base-name Application base name + --prettier-tab-width Default tab width for prettier (default: 2) --skip-commit-hook Skip adding husky commit hooks -h, --help display help for command " diff --git a/generators/init/command.ts b/generators/init/command.ts index 042d1f91fdf8..8935ece74f6e 100644 --- a/generators/init/command.ts +++ b/generators/init/command.ts @@ -16,12 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_PROJECT_NAME } from '../generator-list.js'; -const command: JHipsterCommandDefinition = { +const command = { options: {}, - import: [GENERATOR_PROJECT_NAME, 'jhipster:javascript:prettier', 'jhipster:javascript:husky'], -}; + import: ['jhipster:git', GENERATOR_PROJECT_NAME, 'jhipster:javascript:prettier', 'jhipster:javascript:husky'], +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/init/config.js b/generators/init/config.ts similarity index 100% rename from generators/init/config.js rename to generators/init/config.ts diff --git a/generators/init/files.js b/generators/init/files.ts similarity index 100% rename from generators/init/files.js rename to generators/init/files.ts diff --git a/generators/init/generator.spec.ts b/generators/init/generator.spec.ts index 9df83da53818..df267c5d6a13 100644 --- a/generators/init/generator.spec.ts +++ b/generators/init/generator.spec.ts @@ -16,11 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { basicTests, getCommandHelpOutput, testBlueprintSupport } from '../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../lib/testing/index.js'; import { GENERATOR_INIT } from '../generator-list.js'; import { defaultConfig, requiredConfig } from './config.js'; @@ -28,19 +28,16 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorPath = join(__dirname, 'index.js'); - -const contextBuilder = () => helpers.create(generatorPath); describe(`generator - ${generator}`, () => { it('generator-list constant matches folder name', () => { expect(GENERATOR_INIT).toBe(generator); }); basicTests({ + generatorNamespace: generator, requiredConfig, defaultConfig, customPrompts: {}, - contextBuilder, }); describe('blueprint support', () => testBlueprintSupport(generator)); describe('help', () => { @@ -54,7 +51,7 @@ describe(`generator - ${generator}`, () => { await helpers .runJHipster('init') .withMockedJHipsterGenerators(['bootstrap']) - .withSharedApplication({ projectDescription: 'projectDescription' }) + .withSharedApplication({ projectDescription: 'projectDescription', prettierTabWidth: 'prettierTabWidth' }) .withJHipsterConfig(); }); it('should write files and match snapshot', () => { @@ -62,7 +59,7 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ "jhipster:git", "jhipster:javascript:bootstrap", diff --git a/generators/init/generator.js b/generators/init/generator.ts similarity index 95% rename from generators/init/generator.js rename to generators/init/generator.ts index a88e68cbb9c2..aa045f4f23c1 100644 --- a/generators/init/generator.js +++ b/generators/init/generator.ts @@ -20,10 +20,6 @@ import BaseApplicationGenerator from '../base-application/index.js'; import { GENERATOR_GIT } from '../generator-list.js'; import { files, readme } from './files.js'; -/** - * @class - * @extends {BaseApplicationGenerator} - */ export default class InitGenerator extends BaseApplicationGenerator { generateReadme = true; diff --git a/generators/init/resources/.node-version b/generators/init/resources/.node-version index 119f15a0aa05..fdb2eaaff0ca 100644 --- a/generators/init/resources/.node-version +++ b/generators/init/resources/.node-version @@ -1 +1 @@ -20.15.1 \ No newline at end of file +22.11.0 \ No newline at end of file diff --git a/generators/init/templates/.editorconfig.jhi.ejs b/generators/init/templates/.editorconfig.jhi.ejs index 93af72ebeaf3..9d8ad5dbf6a0 100644 --- a/generators/init/templates/.editorconfig.jhi.ejs +++ b/generators/init/templates/.editorconfig.jhi.ejs @@ -32,7 +32,7 @@ insert_final_newline = true # Change these settings to your own preference indent_style = space -indent_size = 2 +indent_size = <%= prettierTabWidth %> [*.md] trim_trailing_whitespace = false diff --git a/generators/java/command.ts b/generators/java/command.ts index 1a0e29b0d6d2..e76ee29b9ad8 100644 --- a/generators/java/command.ts +++ b/generators/java/command.ts @@ -16,11 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/types.js'; -const command: JHipsterCommandDefinition = { +const command = { options: {}, import: ['jhipster:java:bootstrap', 'jhipster:java:domain', 'jhipster:java:build-tool'], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/java/generator.spec.ts b/generators/java/generator.spec.ts index d72cd0a9a9ad..acd97da14b73 100644 --- a/generators/java/generator.spec.ts +++ b/generators/java/generator.spec.ts @@ -1,10 +1,10 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); diff --git a/generators/java/generators/bootstrap/command.ts b/generators/java/generators/bootstrap/command.ts index 0aff06b3d21d..57f8320ec33d 100644 --- a/generators/java/generators/bootstrap/command.ts +++ b/generators/java/generators/bootstrap/command.ts @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition, PromptSpec } from '../../../../lib/command/index.js'; -const command: JHipsterCommandDefinition = { +const command = { options: { withGeneratedFlag: { description: 'Add a GeneratedByJHipster annotation to all generated java classes and interfaces', @@ -38,7 +38,7 @@ const command: JHipsterCommandDefinition = { cli: { type: String, }, - prompt: gen => ({ + prompt: (gen): PromptSpec => ({ type: 'input', message: 'What is your default Java package name?', default: gen.jhipsterConfigWithDefaults.packageName, @@ -50,8 +50,15 @@ const command: JHipsterCommandDefinition = { scope: 'storage', description: 'The package name for the generated application', }, + packageFolder: { + cli: { + type: String, + hide: true, + }, + scope: 'storage', + }, }, import: [], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/java/generators/bootstrap/generator.spec.ts b/generators/java/generators/bootstrap/generator.spec.ts index f46d90524453..496ceb4cd007 100644 --- a/generators/java/generators/bootstrap/generator.spec.ts +++ b/generators/java/generators/bootstrap/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); diff --git a/generators/java/generators/bootstrap/generator.ts b/generators/java/generators/bootstrap/generator.ts index ddacd234e4f8..02462d836977 100644 --- a/generators/java/generators/bootstrap/generator.ts +++ b/generators/java/generators/bootstrap/generator.ts @@ -20,14 +20,14 @@ import { isFileStateModified } from 'mem-fs-editor/state'; import BaseApplicationGenerator from '../../../base-application/index.js'; import { JAVA_COMPATIBLE_VERSIONS } from '../../../generator-constants.js'; import { - packageInfoTransform, - generatedAnnotationTransform, + addJavaAnnotation, + addJavaImport, checkJava, + generatedAnnotationTransform, isReservedJavaKeyword, - matchMainJavaFiles, javaMainPackageTemplatesBlock, - addJavaImport, - addJavaAnnotation, + matchMainJavaFiles, + packageInfoTransform, } from '../../support/index.js'; export default class BootstrapGenerator extends BaseApplicationGenerator { @@ -61,7 +61,7 @@ export default class BootstrapGenerator extends BaseApplicationGenerator { return this.asConfiguringTaskGroup({ checkConfig() { const { packageName } = this.jhipsterConfigWithDefaults; - const reservedKeywork = packageName.split('.').find(isReservedJavaKeyword); + const reservedKeywork = packageName!.split('.').find(isReservedJavaKeyword); if (reservedKeywork) { throw new Error(`The package name "${packageName}" contains a reserved Java keyword "${reservedKeywork}".`); } @@ -75,6 +75,9 @@ export default class BootstrapGenerator extends BaseApplicationGenerator { get preparing() { return this.asPreparingTaskGroup({ + applicationDefaults({ application }) { + application.addPrettierExtensions?.(['java']); + }, prepareJavaApplication({ application, source }) { source.hasJavaProperty = (property: string) => application.javaProperties![property] !== undefined; source.hasJavaManagedProperty = (property: string) => application.javaManagedProperties![property] !== undefined; @@ -89,6 +92,19 @@ export default class BootstrapGenerator extends BaseApplicationGenerator { ...editFileCallback, ); }, + imperativeOrReactive({ applicationDefaults }) { + applicationDefaults({ + optionalOrMono: ({ reactive }) => (reactive ? 'Mono' : 'Optional'), + optionalOrMonoOfNullable: ({ reactive }) => (reactive ? 'Mono.justOrEmpty' : 'Optional.ofNullable'), + optionalOrMonoClassPath: ({ reactive }) => (reactive ? 'reactor.core.publisher.Mono' : 'java.util.Optional'), + wrapMono: + ({ reactive }) => + className => + reactive ? `Mono<${className}>` : className, + listOrFlux: ({ reactive }) => (reactive ? 'Flux' : 'List'), + listOrFluxClassPath: ({ reactive }) => (reactive ? 'reactor.core.publisher.Flux' : 'java.util.List'), + }); + }, }); } @@ -122,8 +138,8 @@ export default class BootstrapGenerator extends BaseApplicationGenerator { const { srcMainJava } = application; if (this.packageInfoFile && srcMainJava) { - const mainPackageMatch = matchMainJavaFiles(srcMainJava!); - const root = this.destinationPath(srcMainJava!); + const mainPackageMatch = matchMainJavaFiles(srcMainJava); + const root = this.destinationPath(srcMainJava); this.queueTransformStream( { name: 'adding package-info.java files', @@ -169,6 +185,7 @@ export default class BootstrapGenerator extends BaseApplicationGenerator { javaMainPackageTemplatesBlock({ templates: ['GeneratedByJHipster.java'], }), + { templates: ['.editorconfig.jhi.java'] }, ], context: application, }); diff --git a/generators/java/generators/bootstrap/templates/.editorconfig.jhi.java.ejs b/generators/java/generators/bootstrap/templates/.editorconfig.jhi.java.ejs new file mode 100644 index 000000000000..f17912e7730e --- /dev/null +++ b/generators/java/generators/bootstrap/templates/.editorconfig.jhi.java.ejs @@ -0,0 +1,3 @@ +# Generated by jhipster:java:bootstrap generator +[*.java] +indent_size = 4 diff --git a/generators/java/generators/build-tool/command.ts b/generators/java/generators/build-tool/command.ts index eee4d7155901..38265ab2eaff 100644 --- a/generators/java/generators/build-tool/command.ts +++ b/generators/java/generators/build-tool/command.ts @@ -16,13 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { buildToolTypes } from '../../../../jdl/index.js'; -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/types.js'; +import { buildToolTypes } from '../../../../lib/jhipster/index.js'; import { GENERATOR_GRADLE, GENERATOR_MAVEN } from '../../../generator-list.js'; const { GRADLE, MAVEN } = buildToolTypes; -const command: JHipsterCommandDefinition = { +const command = { options: {}, configs: { buildTool: { @@ -44,6 +44,6 @@ const command: JHipsterCommandDefinition = { }, }, import: [GENERATOR_GRADLE, GENERATOR_MAVEN], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/java/generators/build-tool/generator.spec.ts b/generators/java/generators/build-tool/generator.spec.ts index 426b8cc3e0d0..7d9af89b8a19 100644 --- a/generators/java/generators/build-tool/generator.spec.ts +++ b/generators/java/generators/build-tool/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result, runResult } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -45,9 +45,8 @@ describe(`generator - ${generator}`, () => { describe('buildTool option', () => { describe('maven', () => { - let runResult; before(async () => { - runResult = await helpers + await helpers .runJHipster(generator) .withJHipsterConfig({ buildTool: 'maven', @@ -57,16 +56,15 @@ describe(`generator - ${generator}`, () => { }); it('should compose with maven generator', () => { - expect(runResult.mockedGenerators['jhipster:maven'].calledOnce).toBe(true); + runResult.assertGeneratorComposedOnce('jhipster:maven'); }); it('should not compose with others buildTool generators', () => { - expect(runResult.mockedGenerators['jhipster:gradle'].notCalled).toBe(true); + runResult.assertGeneratorNotComposed('jhipster:gradle'); }); }); describe('gradle', () => { - let runResult; before(async () => { - runResult = await helpers + await helpers .runJHipster(generator) .withJHipsterConfig({ buildTool: 'gradle', @@ -76,10 +74,10 @@ describe(`generator - ${generator}`, () => { }); it('should compose with gradle generator', () => { - expect(runResult.mockedGenerators['jhipster:gradle'].called).toBe(true); + runResult.assertGeneratorComposedOnce('jhipster:gradle'); }); it('should not compose with others buildTool generators', () => { - expect(runResult.mockedGenerators['jhipster:maven'].notCalled).toBe(true); + runResult.assertGeneratorNotComposed('jhipster:maven'); }); }); }); diff --git a/generators/java/generators/build-tool/generator.ts b/generators/java/generators/build-tool/generator.ts index 51d709d54098..bc349b9e4f09 100644 --- a/generators/java/generators/build-tool/generator.ts +++ b/generators/java/generators/build-tool/generator.ts @@ -16,12 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { buildToolTypes } from '../../../../jdl/index.js'; +import { buildToolTypes } from '../../../../lib/jhipster/index.js'; import BaseApplicationGenerator from '../../../base-application/index.js'; import { GENERATOR_GRADLE, GENERATOR_MAVEN } from '../../../generator-list.js'; import type { MavenDependency } from '../../../maven/types.js'; import { javaScopeToGradleScope } from '../../support/index.js'; -import type { JavaDependency } from '../../types.js'; +import type { ConditionalJavaDefinition, JavaDependency, JavaNeedleOptions } from '../../types.js'; const { GRADLE, MAVEN } = buildToolTypes; @@ -61,30 +61,55 @@ export default class BuildToolGenerator extends BaseApplicationGenerator { prepareJavaApplication({ application, source }) { source.addJavaDependencies = (dependencies, options) => { if (application.buildToolMaven) { - const annotationProcessors = dependencies.filter(dep => dep.scope === 'annotationProcessor'); - const importDependencies = dependencies.filter(dep => dep.scope === 'import'); - const commonDependencies = dependencies.filter(dep => !['annotationProcessor', 'import'].includes(dep.scope!)); - const convertVersionToRef = ({ version, versionRef, ...artifact }: JavaDependency): MavenDependency => - version || versionRef ? { ...artifact, version: `\${${versionRef ?? artifact.artifactId}.version}` } : artifact; - const removeScope = ({ scope: _scope, ...artifact }: MavenDependency) => artifact; + const convertVersionToMavenDependency = ({ versionRef, version, exclusions, ...artifact }: JavaDependency): MavenDependency => { + // If a version is provided, convert to version ref using artifactId + versionRef ??= version ? artifact.artifactId : undefined; + version = versionRef ? `\${${versionRef}.version}` : undefined; + const additionalContent = exclusions?.length + ? `${exclusions.map( + e => ` + + ${e.groupId} + ${e.artifactId} + `, + )} + ` + : ''; + return additionalContent ? { ...artifact, version, additionalContent } : { ...artifact, version }; + }; + const removeScope = ({ scope: _scope, ...artifact }: JavaDependency) => artifact; + + const properties = dependencies + .filter(dep => dep.version) + .map(({ artifactId, version }) => ({ property: `${artifactId}.version`, value: version })); + const annotationProcessors = dependencies + .filter(dep => dep.scope === 'annotationProcessor') + .map(removeScope) + .map(convertVersionToMavenDependency); + const dependencyManagement = dependencies.filter(dep => dep.scope === 'import').map(convertVersionToMavenDependency); + const commonDependencies = dependencies + .filter(dep => !['annotationProcessor', 'import'].includes(dep.scope!)) + .map(convertVersionToMavenDependency); source.addMavenDefinition?.({ - properties: dependencies - .filter(dep => dep.version) - .map(({ artifactId, version }) => ({ property: `${artifactId}.version`, value: version })), + properties, dependencies: [ - ...commonDependencies.map(convertVersionToRef), + ...commonDependencies, // Add a provided scope for annotation processors so that version is not required in annotationProcessor dependencies - ...annotationProcessors.filter(dep => !dep.version).map(artifact => ({ ...artifact, scope: 'provided' })), + ...annotationProcessors.filter(dep => !dep.version).map(artifact => ({ ...artifact, scope: 'provided' as const })), ], - dependencyManagement: importDependencies.map(convertVersionToRef), - annotationProcessors: annotationProcessors.map(convertVersionToRef).map(removeScope), + dependencyManagement, + annotationProcessors, }); } if (application.buildToolGradle) { + const gradleDependencies = dependencies.map(({ exclusions, ...dep }) => ({ + ...dep, + closure: exclusions?.map(({ groupId, artifactId }) => ` exclude group: '${groupId}', module: '${artifactId}'`), + })); source.addGradleDependencies?.( - dependencies + gradleDependencies .filter(dep => !dep.version && !dep.versionRef) .map(({ scope, type, ...artifact }) => ({ ...artifact, @@ -93,13 +118,14 @@ export default class BuildToolGenerator extends BaseApplicationGenerator { options, ); source.addGradleDependencyCatalogLibraries?.( - dependencies + gradleDependencies .filter(dep => dep.version || dep.versionRef) - .map(({ scope, type, groupId, artifactId, version, versionRef }) => { + .map(({ scope, type, groupId, artifactId, version, versionRef, closure }) => { const library = { libraryName: artifactId, module: `${groupId}:${artifactId}`, scope: javaScopeToGradleScope({ scope, type }), + closure, }; return version ? { ...library, version } : { ...library, 'version.ref': versionRef! }; }), @@ -109,7 +135,7 @@ export default class BuildToolGenerator extends BaseApplicationGenerator { }; source.addJavaDefinition = (definition, options) => { - const { dependencies, versions } = definition; + const { dependencies, versions, mavenDefinition } = definition; if (dependencies) { source.addJavaDependencies!( dependencies.filter(dep => { @@ -128,7 +154,27 @@ export default class BuildToolGenerator extends BaseApplicationGenerator { }); } if (application.buildToolGradle) { - source.addGradleDependencyCatalogVersions?.(versions, options); + source.addGradleDependencyCatalogVersions!(versions, options); + } + } + if (application.buildToolMaven && mavenDefinition) { + source.addMavenDefinition!(mavenDefinition); + } + }; + + source.addJavaDefinitions = ( + optionsOrDefinition: JavaNeedleOptions | ConditionalJavaDefinition, + ...definitions: ConditionalJavaDefinition[] + ) => { + let options: JavaNeedleOptions | undefined = undefined; + if ('gradleFile' in optionsOrDefinition || 'gradleVersionCatalogFile' in optionsOrDefinition) { + options = optionsOrDefinition; + } else { + definitions.unshift(optionsOrDefinition as ConditionalJavaDefinition); + } + for (const definition of definitions) { + if (definition.condition ?? true) { + source.addJavaDefinition!(definition, options); } } }; diff --git a/generators/java/generators/code-quality/command.ts b/generators/java/generators/code-quality/command.ts index 7d3ac0741f15..4afecbf25013 100644 --- a/generators/java/generators/code-quality/command.ts +++ b/generators/java/generators/code-quality/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; const command: JHipsterCommandDefinition = { configs: {}, diff --git a/generators/java/generators/code-quality/generator.spec.ts b/generators/java/generators/code-quality/generator.spec.ts index 0597abe19d97..f68c137d381a 100644 --- a/generators/java/generators/code-quality/generator.spec.ts +++ b/generators/java/generators/code-quality/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -47,10 +47,12 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ + "jhipster:bootstrap", "jhipster:java:build-tool", "jhipster:maven:code-quality", + "jhipster:project-name", ] `); }); @@ -75,10 +77,12 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ + "jhipster:bootstrap", "jhipster:gradle:code-quality", "jhipster:java:build-tool", + "jhipster:project-name", ] `); }); diff --git a/generators/java/generators/domain/command.ts b/generators/java/generators/domain/command.ts index 02126bd03b31..378ed4bb180c 100644 --- a/generators/java/generators/domain/command.ts +++ b/generators/java/generators/domain/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; const command: JHipsterCommandDefinition = { options: { diff --git a/generators/java/generators/domain/entity-files.ts b/generators/java/generators/domain/entity-files.ts index ad0e23422d86..754a8a640bd4 100644 --- a/generators/java/generators/domain/entity-files.ts +++ b/generators/java/generators/domain/entity-files.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { WriteFileSection } from '../../../base/api.js'; +import type { WriteFileSection } from '../../../base/api.js'; import { javaMainPackageTemplatesBlock, javaTestPackageTemplatesBlock } from '../../support/index.js'; export const entityServerFiles: WriteFileSection = { @@ -51,7 +51,7 @@ export const entityServerFiles: WriteFileSection = { export const enumFiles: WriteFileSection = { enumFiles: [ javaMainPackageTemplatesBlock({ - renameTo: (data, filepath) => filepath.replace('_enumName_', data.enumName), + renameTo: (data, filepath) => filepath.replace('_enumName_', (data as any).enumName), templates: ['_entityPackage_/domain/enumeration/_enumName_.java'], }), ], diff --git a/generators/java/generators/domain/generator.spec.ts b/generators/java/generators/domain/generator.spec.ts index 9c29cda1d6e5..38b5700b6b9d 100644 --- a/generators/java/generators/domain/generator.spec.ts +++ b/generators/java/generators/domain/generator.spec.ts @@ -1,9 +1,9 @@ import { basename, dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -61,9 +61,10 @@ describe(`generator - ${generator}`, () => { }); it('should have options defaults set', () => { - expect(result.generator.generateEntities).toBe(true); - expect(result.generator.generateEnums).toBe(true); - expect(result.generator.useJakartaValidation).toBe(true); + const generator: any = result.generator; + expect(generator.generateEntities).toBe(true); + expect(generator.generateEnums).toBe(true); + expect(generator.useJakartaValidation).toBe(true); }); }); @@ -118,7 +119,7 @@ describe(`generator - ${generator}`, () => { await helpers .runJHipster(generator) .withJHipsterConfig({}) - .onGenerator(generator => { + .onGenerator((generator: any) => { generator.generateEntities = false; generator.generateEnums = false; generator.useJakartaValidation = false; @@ -126,9 +127,10 @@ describe(`generator - ${generator}`, () => { }); it('should not override custom values', () => { - expect(result.generator.generateEntities).toBe(false); - expect(result.generator.generateEnums).toBe(false); - expect(result.generator.useJakartaValidation).toBe(false); + const generator: any = result.generator; + expect(generator.generateEntities).toBe(false); + expect(generator.generateEnums).toBe(false); + expect(generator.useJakartaValidation).toBe(false); }); }); }); diff --git a/generators/java/generators/domain/generator.ts b/generators/java/generators/domain/generator.ts index 91e5b0877ebb..43f0681b8093 100644 --- a/generators/java/generators/domain/generator.ts +++ b/generators/java/generators/domain/generator.ts @@ -152,6 +152,7 @@ export default class DomainGenerator extends BaseApplicationGenerator { for (const entity of entities.filter(entity => !entity.skipServer)) { for (const field of entity.fields.filter(field => field.fieldIsEnum)) { const enumInfo = { + ...application, ...getEnumInfo(field, (entity as any).clientRootFolder), frontendAppName: (entity as any).frontendAppName, packageName: application.packageName, diff --git a/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs b/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs index d19fe3f98112..5105aac59ef7 100644 --- a/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs +++ b/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs @@ -137,8 +137,8 @@ public class <%= persistClass %> <&- fragments.extendsSection() -&>implements Se for (relationship of relationships) { if (typeof relationship.fieldApiDescription) { _%> <%- relationship.relationshipJavadoc %> - <%_ if (!dtoMapstruct && relationship.relationshipyApiDescription) { _%> - @Schema(description = "<%- relationship.relationshipyApiDescription %>") + <%_ if (!dtoMapstruct && relationship.relationshipApiDescription) { _%> + @Schema(description = "<%- relationship.relationshipApiDescription %>") <%_ } _%> <%_ } _%> <&- fragments.relationship<%- relationship.relationshipNameCapitalized %>AnnotationSection() -&> diff --git a/generators/java/generators/domain/templates/src/test/java/_package_/domain/AssertUtils.java.ejs b/generators/java/generators/domain/templates/src/test/java/_package_/domain/AssertUtils.java.ejs index 118d39643810..1b19c8e611c1 100644 --- a/generators/java/generators/domain/templates/src/test/java/_package_/domain/AssertUtils.java.ejs +++ b/generators/java/generators/domain/templates/src/test/java/_package_/domain/AssertUtils.java.ejs @@ -25,8 +25,8 @@ import java.util.Comparator; public class AssertUtils { - public static Comparator zonedDataTimeSameInstant = Comparator.nullsFirst( - (e1, a2) -> e1.withZoneSameInstant(ZoneOffset.UTC).compareTo(a2.withZoneSameInstant(ZoneOffset.UTC)) + public static Comparator zonedDataTimeSameInstant = Comparator.nullsFirst((e1, a2) -> + e1.withZoneSameInstant(ZoneOffset.UTC).compareTo(a2.withZoneSameInstant(ZoneOffset.UTC)) ); public static Comparator bigDecimalCompareTo = Comparator.nullsFirst((e1, a2) -> e1.compareTo(a2)); diff --git a/generators/java/generators/graalvm/__snapshots__/generator.spec.ts.snap b/generators/java/generators/graalvm/__snapshots__/generator.spec.ts.snap new file mode 100644 index 000000000000..f5985e082143 --- /dev/null +++ b/generators/java/generators/graalvm/__snapshots__/generator.spec.ts.snap @@ -0,0 +1,272 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generator - java:graalvm with default options should call source snapshot 1`] = ` +{ + "addMavenDefinition": [ + { + "pluginManagement": [ + { + "additionalContent": " + + false + \${project.build.outputDirectory} + + true + + \${native-image-name} + true + + -Duser.language=en + -H:IncludeLocales= + + + -Xms4g + -Xmx10g + + ", + "artifactId": "native-maven-plugin", + "groupId": "org.graalvm.buildtools", + "version": "\${native-buildtools.version}", + }, + { + "additionalContent": " + + true + ", + "artifactId": "hibernate-enhance-maven-plugin", + "groupId": "org.hibernate.orm.tooling", + "version": "\${hibernate.version}", + }, + ], + "profiles": [ + { + "content": " + + exec + true + false + + + + + org.hibernate.orm.tooling + hibernate-enhance-maven-plugin + + + + enhance + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + paketobuildpacks/builder:tiny + + true + + + + + + process-aot + + process-aot + + + + + + org.graalvm.buildtools + native-maven-plugin + + + add-reachability-metadata + + add-reachability-metadata + + + + build-native + + compile-no-fork + + package + + + test-native + + test + + test + + + + + ", + "id": "native", + }, + ], + "properties": [ + { + "property": "repackage.classifier", + }, + { + "property": "native-image-name", + "value": "native-executable", + }, + { + "property": "native-buildtools.version", + "value": "'NATIVE-BUILD-TOOLS-VERSION'", + }, + ], + }, + ], + "addNativeHint": [ + { + "advanced": [ + "hints.reflection().registerType(sun.misc.Unsafe.class, (hint) -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));", + "hints.reflection().registerType(java.util.Locale.class, (hint) -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));", + ], + "resources": [ + "i18n/*", + ], + }, + ], + "editJavaFile": [ + [ + "src/main/java/com/mycompany/myapp/JhipsterApp.java", + { + "annotations": [ + { + "annotation": "ImportRuntimeHints", + "package": "org.springframework.context.annotation", + "parameters": [Function], + }, + ], + }, + ], + [ + "src/main/java/com/mycompany/myapp//web/rest/errors/FieldErrorVM.java", + { + "annotations": [ + { + "annotation": "RegisterReflectionForBinding", + "package": "org.springframework.aot.hint.annotation", + "parameters": [Function], + }, + ], + }, + ], + ], +} +`; + +exports[`generator - java:graalvm with default options should call source snapshot 2`] = ` +{ + "addGradleDependencyCatalogPlugin": [ + { + "addToBuild": true, + "id": "org.graalvm.buildtools.native", + "pluginName": "graalvm", + "version": "'NATIVE-BUILD-TOOLS-VERSION'", + }, + ], + "addNativeHint": [ + { + "advanced": [ + "hints.reflection().registerType(sun.misc.Unsafe.class, (hint) -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));", + "hints.reflection().registerType(java.util.Locale.class, (hint) -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));", + ], + "resources": [ + "i18n/*", + ], + }, + ], + "applyFromGradle": [ + { + "script": "gradle/native.gradle", + }, + ], + "editJavaFile": [ + [ + "src/main/java/com/mycompany/myapp/JhipsterApp.java", + { + "annotations": [ + { + "annotation": "ImportRuntimeHints", + "package": "org.springframework.context.annotation", + "parameters": [Function], + }, + ], + }, + ], + [ + "src/main/java/com/mycompany/myapp//web/rest/errors/FieldErrorVM.java", + { + "annotations": [ + { + "annotation": "RegisterReflectionForBinding", + "package": "org.springframework.aot.hint.annotation", + "parameters": [Function], + }, + ], + }, + ], + [ + "src/test/java/com/mycompany/myapp//TechnicalStructureTest.java", + { + "staticImports": [ + "com.tngtech.archunit.core.domain.JavaClass.Predicates.simpleNameEndingWith", + ], + }, + [Function], + ], + ], +} +`; + +exports[`generator - java:graalvm with default options should match files snapshot 1`] = ` +{ + ".yo-rc.json": { + "stateCleared": "modified", + }, + "README.md.jhi.native": { + "stateCleared": "modified", + }, + "src/main/java/com/mycompany/myapp/config/NativeConfiguration.java": { + "stateCleared": "modified", + }, +} +`; + +exports[`generator - java:graalvm with default options should match files snapshot 2`] = ` +{ + ".yo-rc.json": { + "stateCleared": "modified", + }, + "README.md.jhi.native": { + "stateCleared": "modified", + }, + "gradle/native.gradle": { + "stateCleared": "modified", + }, + "src/main/java/com/mycompany/myapp/config/NativeConfiguration.java": { + "stateCleared": "modified", + }, +} +`; diff --git a/generators/base-application/types/field.d.ts b/generators/java/generators/graalvm/command.ts similarity index 78% rename from generators/base-application/types/field.d.ts rename to generators/java/generators/graalvm/command.ts index 77c0305cc8b8..de9446fa3118 100644 --- a/generators/base-application/types/field.d.ts +++ b/generators/java/generators/graalvm/command.ts @@ -16,12 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import type { JHipsterCommandDefinition } from '../../../../lib/command/types.js'; -type Field = { - fieldName: string; - fieldType: string; - fieldTypeBlobContent?: string; - propertyName: string; -} & Record; +const command = { + configs: {}, + import: [], +} as const satisfies JHipsterCommandDefinition; -export default Field; +export default command; diff --git a/generators/heroku/generator.spec.js b/generators/java/generators/graalvm/generator.spec.ts similarity index 52% rename from generators/heroku/generator.spec.js rename to generators/java/generators/graalvm/generator.spec.ts index 2ba7f42964c7..46730f590b54 100644 --- a/generators/heroku/generator.spec.js +++ b/generators/java/generators/graalvm/generator.spec.ts @@ -16,23 +16,42 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname } from 'path'; -import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; -import { snakeCase } from 'lodash-es'; +import { basename, dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { before, describe, expect, it } from 'esmocha'; -import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; +import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const generator = basename(__dirname); +const generator = `${basename(resolve(__dirname, '../../'))}:${basename(__dirname)}`; describe(`generator - ${generator}`, () => { - it('generator-list constant matches folder name', async () => { - await expect((await import('../generator-list.js'))[`GENERATOR_${snakeCase(generator).toUpperCase()}`]).toBe(generator); - }); shouldSupportFeatures(Generator); describe('blueprint support', () => testBlueprintSupport(generator)); + + for (const buildTool of ['maven', 'gradle']) { + describe('with default options', () => { + before(async () => { + await helpers + .runJHipster(generator) + .withMockedJHipsterGenerators() + .withMockedSource() + .withOptions({ ignoreNeedlesError: true }) + .withSharedApplication({}) + .withJHipsterConfig({ buildTool }); + }); + + it('should match files snapshot', () => { + expect(result.getStateSnapshot()).toMatchSnapshot(); + }); + + it('should call source snapshot', () => { + expect(result.sourceCallsArg).toMatchSnapshot(); + }); + }); + } }); diff --git a/generators/java/generators/graalvm/generator.ts b/generators/java/generators/graalvm/generator.ts new file mode 100644 index 000000000000..bfbc78453524 --- /dev/null +++ b/generators/java/generators/graalvm/generator.ts @@ -0,0 +1,265 @@ +/** + * Copyright 2013-2024 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. + */ +import { extname } from 'path'; +import { isFileStateDeleted, isFileStateModified } from 'mem-fs-editor/state'; +import { passthrough } from '@yeoman/transform'; +import BaseApplicationGenerator from '../../../base-application/index.js'; +import { createNeedleCallback } from '../../../base/support/needles.js'; +import { addJavaAnnotation, addJavaImport } from '../../../java/support/add-java-annotation.js'; +import { javaMainPackageTemplatesBlock } from '../../../java/support/files.js'; +import { mavenDefinition } from './internal/maven-definition.js'; + +export default class GraalvmGenerator extends BaseApplicationGenerator { + async beforeQueue() { + if (!this.fromBlueprint) { + await this.composeWithBlueprints(); + } + + if (!this.delegateToBlueprint) { + await this.dependsOnBootstrapApplication(); + } + } + + get initializing() { + return this.asInitializingTaskGroup({ + forceConfig() { + // Cache is not supported for GraalVM native image + this.jhipsterConfig.cacheProvider ??= 'no'; + }, + }); + } + + get [BaseApplicationGenerator.INITIALIZING]() { + return this.delegateTasksToBlueprint(() => this.initializing); + } + + get preparing() { + return this.asPreparingTaskGroup({ + load({ application }) { + this.loadJavaDependenciesFromGradleCatalog(application.javaDependencies!); + }, + addNativeHint({ source, application }) { + source.addNativeHint = ({ advanced = [], declaredConstructors = [], publicConstructors = [], resources = [] }) => { + this.editFile( + `${application.javaPackageSrcDir}config/NativeConfiguration.java`, + addJavaImport('org.springframework.aot.hint.MemberCategory'), + createNeedleCallback({ + contentToAdd: [ + ...advanced, + ...resources.map(resource => `hints.resources().registerPattern("${resource}");`), + ...publicConstructors.map( + classPath => + `hints.reflection().registerType(${classPath}, (hint) -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));`, + ), + ...declaredConstructors.map( + classPath => + `hints.reflection().registerType(${classPath}, (hint) -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));`, + ), + ], + needle: 'add-native-hints', + ignoreWhitespaces: true, + }), + ); + }; + }, + async packageJson({ application }) { + const { buildToolGradle, packageJsonScripts } = application; + const scripts = buildToolGradle + ? { + 'native-package': './gradlew nativeCompile -Pnative -Pprod -x test -x integrationTest', + 'native-package-dev': './gradlew nativeCompile -Pnative -Pdev -x test -x integrationTest', + 'native-start': './build/native/nativeCompile/native-executable', + } + : { + 'native-package': './mvnw package -B -ntp -Pnative,prod -DskipTests', + 'native-package-dev': './mvnw package -B -ntp -Pnative,dev,webapp -DskipTests', + 'native-start': './target/native-executable', + }; + Object.assign(packageJsonScripts!, { + 'native-e2e': 'concurrently -k -s first -n application,e2e -c red,blue npm:native-start npm:e2e:headless', + ...scripts, + }); + }, + }); + } + + get [BaseApplicationGenerator.PREPARING]() { + return this.delegateTasksToBlueprint(() => this.preparing); + } + + get default() { + return this.asDefaultTaskGroup({ + // workaround for https://github.com/spring-projects/spring-boot/issues/32195 + async disabledInAotModeAnnotation({ application }) { + this.queueTransformStream( + { + name: 'adding @DisabledInAotMode annotations', + filter: file => + !isFileStateDeleted(file) && + isFileStateModified(file) && + file.path.startsWith(this.destinationPath(application.srcTestJava!)) && + extname(file.path) === '.java', + refresh: false, + }, + passthrough(file => { + const contents = file.contents.toString('utf8'); + if (/@(MockBean|SpyBean)/.test(contents) || (application.reactive && /@AuthenticationIntegrationTest/.test(contents))) { + file.contents = Buffer.from( + addJavaAnnotation(contents, { package: 'org.springframework.test.context.aot', annotation: 'DisabledInAotMode' }), + ); + } + }), + ); + }, + }); + } + + get [BaseApplicationGenerator.DEFAULT]() { + return this.delegateTasksToBlueprint(() => this.default); + } + + get writing() { + return this.asWritingTaskGroup({ + async writingTemplateTask({ application }) { + await this.writeFiles({ + sections: { + common: [{ templates: ['README.md.jhi.native'] }], + config: [ + javaMainPackageTemplatesBlock({ + templates: ['config/NativeConfiguration.java'], + }), + ], + gradle: [ + { + condition: ctx => ctx.buildToolGradle, + templates: ['gradle/native.gradle'], + }, + ], + }, + context: application, + }); + }, + }); + } + + get [BaseApplicationGenerator.WRITING]() { + return this.delegateTasksToBlueprint(() => this.writing); + } + + get postWriting() { + return this.asPostWritingTaskGroup({ + async customizeGradle({ application, source }) { + const { buildToolGradle, javaDependencies } = application; + if (!buildToolGradle) return; + + source.addGradleDependencyCatalogPlugin!({ + addToBuild: true, + pluginName: 'graalvm', + id: 'org.graalvm.buildtools.native', + version: javaDependencies!.nativeBuildTools!, + }); + + source.applyFromGradle!({ script: 'gradle/native.gradle' }); + }, + + async customizeMaven({ application, source }) { + const { buildToolMaven, reactive, databaseTypeSql, javaDependencies, nativeLanguageDefinition, languagesDefinition } = application; + if (!buildToolMaven) return; + + source.addMavenDefinition!( + mavenDefinition({ + reactive, + nativeBuildToolsVersion: javaDependencies!.nativeBuildTools!, + databaseTypeSql, + userLanguage: nativeLanguageDefinition.languageTag, + languages: languagesDefinition.map(def => def.languageTag), + }), + ); + }, + + springBootHintsConfiguration({ application, source }) { + const { mainClass, javaPackageSrcDir, packageName, backendTypeSpringBoot } = application; + + if (backendTypeSpringBoot) { + source.editJavaFile!(`${javaPackageSrcDir}${mainClass}.java`, { + annotations: [ + { + package: 'org.springframework.context.annotation', + annotation: 'ImportRuntimeHints', + parameters: () => `{ ${packageName}.config.NativeConfiguration.JHipsterNativeRuntimeHints.class }`, + }, + ], + }); + } + }, + + springBootRestErrors({ application, source }) { + const { javaPackageSrcDir, backendTypeSpringBoot } = application; + if (backendTypeSpringBoot) { + source.editJavaFile!(`${javaPackageSrcDir}/web/rest/errors/FieldErrorVM.java`, { + annotations: [ + { + package: 'org.springframework.aot.hint.annotation', + annotation: 'RegisterReflectionForBinding', + parameters: () => '{ FieldErrorVM.class }', + }, + ], + }); + } + }, + + // workaround for arch error in backend:unit:test caused by gradle's org.graalvm.buildtools.native plugin + springBootTechnicalStructureTest({ application, source }) { + const { buildToolGradle, javaPackageTestDir, backendTypeSpringBoot } = application; + if (!buildToolGradle || !backendTypeSpringBoot) return; + source.editJavaFile!( + `${javaPackageTestDir}/TechnicalStructureTest.java`, + { + staticImports: ['com.tngtech.archunit.core.domain.JavaClass.Predicates.simpleNameEndingWith'], + }, + contents => + contents.includes('__BeanFactoryRegistrations') + ? contents + : contents.replace( + '.ignoreDependency(belongToAnyOf', + `.ignoreDependency(simpleNameEndingWith("_BeanFactoryRegistrations"), alwaysTrue()) + .ignoreDependency(belongToAnyOf`, + ), + ); + }, + nativeHints({ source, application }) { + if (!application.backendTypeSpringBoot) return; + + source.addNativeHint!({ + advanced: [ + // Undertow + 'hints.reflection().registerType(sun.misc.Unsafe.class, (hint) -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));', + // Thymeleaf template + 'hints.reflection().registerType(java.util.Locale.class, (hint) -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));', + ], + resources: ['i18n/*'], + }); + }, + }); + } + + get [BaseApplicationGenerator.POST_WRITING]() { + return this.delegateTasksToBlueprint(() => this.postWriting); + } +} diff --git a/generators/app/jdl/index.ts b/generators/java/generators/graalvm/index.ts similarity index 89% rename from generators/app/jdl/index.ts rename to generators/java/generators/graalvm/index.ts index 5f8a8ff1c57e..1cfadd692bb6 100644 --- a/generators/app/jdl/index.ts +++ b/generators/java/generators/graalvm/index.ts @@ -16,4 +16,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { default } from './application-options.js'; +export { default } from './generator.js'; +export { default as command } from './command.js'; diff --git a/generators/java/generators/graalvm/internal/maven-definition.ts b/generators/java/generators/graalvm/internal/maven-definition.ts new file mode 100644 index 000000000000..f6dcb2cfc0c1 --- /dev/null +++ b/generators/java/generators/graalvm/internal/maven-definition.ts @@ -0,0 +1,147 @@ +/* eslint-disable no-template-curly-in-string */ +import type { MavenDefinition } from '../../../../maven/types.js'; + +export const mavenDefinition = ({ + reactive, + nativeBuildToolsVersion, + databaseTypeSql, + userLanguage, + languages, +}: { + reactive?: boolean; + nativeBuildToolsVersion?: string; + databaseTypeSql?: boolean; + userLanguage: string; + languages: string[]; +}): MavenDefinition => ({ + properties: [ + { property: 'repackage.classifier' }, + { property: 'native-image-name', value: 'native-executable' }, + { property: 'native-buildtools.version', value: nativeBuildToolsVersion }, + ], + pluginManagement: [ + { + groupId: 'org.graalvm.buildtools', + artifactId: 'native-maven-plugin', + version: '${native-buildtools.version}', + additionalContent: ` + + false + \${project.build.outputDirectory} + + true + + \${native-image-name} + true + + -Duser.language=${userLanguage} + -H:IncludeLocales=${languages.join(',')} + + + -Xms4g + -Xmx10g + + `, + }, + ...(reactive || !databaseTypeSql + ? [] + : [ + { + groupId: 'org.hibernate.orm.tooling', + artifactId: 'hibernate-enhance-maven-plugin', + version: '${hibernate.version}', + additionalContent: ` + + true + `, + }, + ]), + ], + profiles: [ + { + id: 'native', + content: ` + + exec + true + false + + + ${ + databaseTypeSql && !reactive + ? ` + + org.hibernate.orm.tooling + hibernate-enhance-maven-plugin + + + + enhance + + + + ` + : `` + } + + org.apache.maven.plugins + maven-jar-plugin + + + + true + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + paketobuildpacks/builder:tiny + + true + + + + + + process-aot + + process-aot + + + + + + org.graalvm.buildtools + native-maven-plugin + + + add-reachability-metadata + + add-reachability-metadata + + + + build-native + + compile-no-fork + + package + + + test-native + + test + + test + + + + + `, + }, + ], +}); diff --git a/generators/java/generators/graalvm/resources/build.gradle b/generators/java/generators/graalvm/resources/build.gradle new file mode 100644 index 000000000000..fd4321c8b9f5 --- /dev/null +++ b/generators/java/generators/graalvm/resources/build.gradle @@ -0,0 +1 @@ +// required by dependabot diff --git a/generators/java/generators/graalvm/resources/gradle/libs.versions.toml b/generators/java/generators/graalvm/resources/gradle/libs.versions.toml new file mode 100644 index 000000000000..99aa491fd0d2 --- /dev/null +++ b/generators/java/generators/graalvm/resources/gradle/libs.versions.toml @@ -0,0 +1,5 @@ +[versions] +nativeBuildTools = '0.10.3' + +[libraries] +nativeGradlePlugin = { module = 'org.graalvm.buildtools:native-gradle-plugin', version.ref = 'nativeBuildTools' } diff --git a/generators/java/generators/graalvm/templates/README.md.jhi.native.ejs b/generators/java/generators/graalvm/templates/README.md.jhi.native.ejs new file mode 100644 index 000000000000..4d2b0f439fcb --- /dev/null +++ b/generators/java/generators/graalvm/templates/README.md.jhi.native.ejs @@ -0,0 +1,53 @@ +<%# + Copyright 2013-2024 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. +-%> +<%# + This is a fragment file, it will be merged into to root template if available. + EJS fragments will process % delimiter tags in template and & delimiter tags in the merge process. +-%> +<&_ if (fragment.othersSection) { -&> +### About Native Build + +#### Installation + +To build a Native image, you need to install a JDK that is compatible with GraalVM. Please refer to the [GraalVM Release Notes](https://www.graalvm.org/release-notes/) and install the appropriate JDK. Using SDKMAN simplifies the installation process. +``` +sdk install java 21-graalce +``` +#### How to Build a Native Image + +To build a native image, execute the following command: +```bash +npm run native-package +# <%- packageJsonScripts['native-package'] %> +``` + +After that, set up peripheral services like PostgreSQL using `npm run services:up`(<%- packageJsonScripts['services:up'] %>) and ensure everything is ready. + +Lastly, run the Native image and experience its fast startup 😊. +```bash +npm run native-start +# <%- packageJsonScripts['native-start'] %> +``` + +If you've enabled e2e testing with Cypress, you can verify its operation using the following command: +```bash +npm run native-e2e +# <%- packageJsonScripts['native-e2e'] %> +``` +<&_ } -&> diff --git a/generators/java/generators/graalvm/templates/gradle/native.gradle.ejs b/generators/java/generators/graalvm/templates/gradle/native.gradle.ejs new file mode 100644 index 000000000000..5e286ba13f42 --- /dev/null +++ b/generators/java/generators/graalvm/templates/gradle/native.gradle.ejs @@ -0,0 +1,44 @@ +graalvmNative { + toolchainDetection = true + binaries { + main { + imageName = 'native-executable' + //this is only needed when you toolchain can't be detected + //javaLauncher = javaToolchains.launcherFor { + // languageVersion = JavaLanguageVersion.of(19) + // vendor = JvmVendorSpec.matching("GraalVM Community") + //} + buildArgs.add("-Duser.language=<%- nativeLanguageDefinition.languageTag %>") + buildArgs.add("-H:IncludeLocales=<%- languagesDefinition.map(def => def.languageTag).join(',') %>") + } + } + binaries.all { + verbose = true + jvmArgs.add('-Xms4g') + jvmArgs.add('-Xmx10g') + } +} + +processTestAot { + jvmArgs += ["-XX:+AllowRedefinitionToAddDeleteMethods"] +} +<%_ if (!reactive && databaseTypeSql) { _%> + <%_ if (devDatabaseTypeH2Any) { _%> + +processResources { + filesMatching("**/application-dev.yml") { + filter { + it.replace("@spring.h2.console.enabled@", String.valueOf(!project.hasProperty("native"))) + } + } +} + <%_ } _%> + +if (project.hasProperty("native")) { + hibernate { + enhancement { + enableLazyInitialization = true + } + } +} +<%_ } _%> diff --git a/generators/java/generators/graalvm/templates/src/main/java/_package_/config/NativeConfiguration.java.ejs b/generators/java/generators/graalvm/templates/src/main/java/_package_/config/NativeConfiguration.java.ejs new file mode 100644 index 000000000000..1820d9a014ca --- /dev/null +++ b/generators/java/generators/graalvm/templates/src/main/java/_package_/config/NativeConfiguration.java.ejs @@ -0,0 +1,14 @@ +package <%=packageName%>.config; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +public class NativeConfiguration { + + public static class JHipsterNativeRuntimeHints implements RuntimeHintsRegistrar { + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + // jhipster-needle-add-native-hints - JHipster will add native hints here + } + } +} diff --git a/generators/java/generators/jib/__snapshots__/generator.spec.ts.snap b/generators/java/generators/jib/__snapshots__/generator.spec.ts.snap index 2612874bd86a..ef3ea3eef1ac 100644 --- a/generators/java/generators/jib/__snapshots__/generator.spec.ts.snap +++ b/generators/java/generators/jib/__snapshots__/generator.spec.ts.snap @@ -23,9 +23,6 @@ exports[`generator - java:jib with defaults options should match files snapshot "package.json": { "stateCleared": "modified", }, - "pom.xml": { - "stateCleared": "modified", - }, "src/main/docker/jib/entrypoint.sh": { "stateCleared": "modified", }, @@ -82,7 +79,22 @@ exports[`generator - java:jib with defaults options should match source snapshot -", + + + com.google.cloud.tools.jib.maven.extension.springboot.JibSpringBootExtension + + + + + + + com.google.cloud.tools + jib-spring-boot-extension-maven + 'JIB-SPRING-BOOT-EXTENSION-MAVEN-VERSION' + + + +", "artifactId": "jib-maven-plugin", "groupId": "com.google.cloud.tools", "version": "\${jib-maven-plugin.version}", diff --git a/generators/java/generators/jib/command.ts b/generators/java/generators/jib/command.ts index 7d3ac0741f15..4afecbf25013 100644 --- a/generators/java/generators/jib/command.ts +++ b/generators/java/generators/jib/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; const command: JHipsterCommandDefinition = { configs: {}, diff --git a/generators/java/generators/jib/generator.spec.ts b/generators/java/generators/jib/generator.spec.ts index 1a2be8d0ef13..49bfaf569062 100644 --- a/generators/java/generators/jib/generator.spec.ts +++ b/generators/java/generators/jib/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); diff --git a/generators/java/generators/node/command.ts b/generators/java/generators/node/command.ts index 7d3ac0741f15..4afecbf25013 100644 --- a/generators/java/generators/node/command.ts +++ b/generators/java/generators/node/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; const command: JHipsterCommandDefinition = { configs: {}, diff --git a/generators/java/generators/node/generator.spec.ts b/generators/java/generators/node/generator.spec.ts index 3f0278cca9e9..c26200ff31b3 100644 --- a/generators/java/generators/node/generator.spec.ts +++ b/generators/java/generators/node/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -47,10 +47,12 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ + "jhipster:bootstrap", "jhipster:java:build-tool", "jhipster:maven:frontend-plugin", + "jhipster:project-name", ] `); }); @@ -70,10 +72,12 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ + "jhipster:bootstrap", "jhipster:gradle:node-gradle", "jhipster:java:build-tool", + "jhipster:project-name", ] `); }); diff --git a/generators/java/generators/node/generator.ts b/generators/java/generators/node/generator.ts index 089bc32b203f..e4c51b7a31fa 100644 --- a/generators/java/generators/node/generator.ts +++ b/generators/java/generators/node/generator.ts @@ -16,6 +16,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import chalk from 'chalk'; +import type { ExecaError } from 'execa'; import BaseApplicationGenerator from '../../../base-application/index.js'; export default class NodeGenerator extends BaseApplicationGenerator { @@ -47,6 +49,20 @@ export default class NodeGenerator extends BaseApplicationGenerator { return this.delegateTasksToBlueprint(() => this.composing); } + get postPreparing() { + return this.asPostPreparingTaskGroup({ + useNpmWrapper({ application }) { + if (application.useNpmWrapper) { + this.useNpmWrapperInstallTask(); + } + }, + }); + } + + get [BaseApplicationGenerator.POST_PREPARING]() { + return this.delegateTasksToBlueprint(() => this.postPreparing); + } + get writing() { return this.asWritingTaskGroup({ async writing({ application }) { @@ -67,4 +83,25 @@ export default class NodeGenerator extends BaseApplicationGenerator { get [BaseApplicationGenerator.WRITING]() { return this.delegateTasksToBlueprint(() => this.writing); } + + useNpmWrapperInstallTask() { + this.setFeatures({ + customInstallTask: async (preferredPm, defaultInstallTask) => { + const buildTool = this.jhipsterConfigWithDefaults.buildTool; + if ((preferredPm && preferredPm !== 'npm') || this.jhipsterConfig.skipClient || (buildTool !== 'gradle' && buildTool !== 'maven')) { + await defaultInstallTask(); + return; + } + + const npmCommand = process.platform === 'win32' ? 'npmw' : './npmw'; + try { + await this.spawn(npmCommand, ['install'], { preferLocal: true }); + } catch (error: unknown) { + this.log.error( + chalk.red(`Error executing '${npmCommand} install', please execute it yourself. (${(error as ExecaError).shortMessage})`), + ); + } + }, + }); + } } diff --git a/generators/java/generators/openapi-generator/__snapshots__/generator.spec.ts.snap b/generators/java/generators/openapi-generator/__snapshots__/generator.spec.ts.snap index b14e5b375462..3b12070bc224 100644 --- a/generators/java/generators/openapi-generator/__snapshots__/generator.spec.ts.snap +++ b/generators/java/generators/openapi-generator/__snapshots__/generator.spec.ts.snap @@ -2,12 +2,61 @@ exports[`generator - java:openapi-generator gradle-addOpenapiGeneratorPlugin(false) should call source snapshot 1`] = ` { - "addJavaDependencies": [ + "addJavaDefinitions": [ [ { - "artifactId": "jackson-databind-nullable", - "groupId": "org.openapitools", - "version": "'JACKSON-DATABIND-NULLABLE-VERSION'", + "dependencies": [ + { + "artifactId": "jackson-databind-nullable", + "groupId": "org.openapitools", + "version": "'JACKSON-DATABIND-NULLABLE-VERSION'", + }, + ], + }, + { + "condition": false, + "mavenDefinition": { + "pluginManagement": [ + { + "additionalContent": " + + + generate + + + \${project.basedir}/src/main/resources/swagger/api.yml + spring + com.mycompany.myapp.web.api + com.mycompany.myapp.service.api.dto + ApiUtil.java + false + + true + jhipster + true + + + + +", + "artifactId": "openapi-generator-maven-plugin", + "groupId": "org.openapitools", + "version": "\${openapi-generator-maven-plugin.version}", + }, + ], + "plugins": [ + { + "artifactId": "openapi-generator-maven-plugin", + "groupId": "org.openapitools", + }, + ], + "properties": [ + { + "property": "openapi-generator-maven-plugin.version", + "value": "'OPENAPI-GENERATOR-MAVEN-PLUGIN-VERSION'", + }, + ], + }, }, ], ], @@ -16,7 +65,9 @@ exports[`generator - java:openapi-generator gradle-addOpenapiGeneratorPlugin(fal exports[`generator - java:openapi-generator gradle-addOpenapiGeneratorPlugin(false) should compose with generators 1`] = ` [ + "jhipster:bootstrap", "jhipster:java:build-tool", + "jhipster:project-name", ] `; @@ -51,12 +102,61 @@ exports[`generator - java:openapi-generator gradle-addOpenapiGeneratorPlugin(tru "id": "jhipster.openapi-generator-conventions", }, ], - "addJavaDependencies": [ + "addJavaDefinitions": [ [ { - "artifactId": "jackson-databind-nullable", - "groupId": "org.openapitools", - "version": "'JACKSON-DATABIND-NULLABLE-VERSION'", + "dependencies": [ + { + "artifactId": "jackson-databind-nullable", + "groupId": "org.openapitools", + "version": "'JACKSON-DATABIND-NULLABLE-VERSION'", + }, + ], + }, + { + "condition": true, + "mavenDefinition": { + "pluginManagement": [ + { + "additionalContent": " + + + generate + + + \${project.basedir}/src/main/resources/swagger/api.yml + spring + com.mycompany.myapp.web.api + com.mycompany.myapp.service.api.dto + ApiUtil.java + false + + true + jhipster + true + + + + +", + "artifactId": "openapi-generator-maven-plugin", + "groupId": "org.openapitools", + "version": "\${openapi-generator-maven-plugin.version}", + }, + ], + "plugins": [ + { + "artifactId": "openapi-generator-maven-plugin", + "groupId": "org.openapitools", + }, + ], + "properties": [ + { + "property": "openapi-generator-maven-plugin.version", + "value": "'OPENAPI-GENERATOR-MAVEN-PLUGIN-VERSION'", + }, + ], + }, }, ], ], @@ -65,7 +165,9 @@ exports[`generator - java:openapi-generator gradle-addOpenapiGeneratorPlugin(tru exports[`generator - java:openapi-generator gradle-addOpenapiGeneratorPlugin(true) should compose with generators 1`] = ` [ + "jhipster:bootstrap", "jhipster:java:build-tool", + "jhipster:project-name", ] `; @@ -88,12 +190,61 @@ exports[`generator - java:openapi-generator gradle-addOpenapiGeneratorPlugin(tru exports[`generator - java:openapi-generator maven-addOpenapiGeneratorPlugin(false) should call source snapshot 1`] = ` { - "addJavaDependencies": [ + "addJavaDefinitions": [ [ { - "artifactId": "jackson-databind-nullable", - "groupId": "org.openapitools", - "version": "'JACKSON-DATABIND-NULLABLE-VERSION'", + "dependencies": [ + { + "artifactId": "jackson-databind-nullable", + "groupId": "org.openapitools", + "version": "'JACKSON-DATABIND-NULLABLE-VERSION'", + }, + ], + }, + { + "condition": false, + "mavenDefinition": { + "pluginManagement": [ + { + "additionalContent": " + + + generate + + + \${project.basedir}/src/main/resources/swagger/api.yml + spring + com.mycompany.myapp.web.api + com.mycompany.myapp.service.api.dto + ApiUtil.java + false + + true + jhipster + true + + + + +", + "artifactId": "openapi-generator-maven-plugin", + "groupId": "org.openapitools", + "version": "\${openapi-generator-maven-plugin.version}", + }, + ], + "plugins": [ + { + "artifactId": "openapi-generator-maven-plugin", + "groupId": "org.openapitools", + }, + ], + "properties": [ + { + "property": "openapi-generator-maven-plugin.version", + "value": "'OPENAPI-GENERATOR-MAVEN-PLUGIN-VERSION'", + }, + ], + }, }, ], ], @@ -102,7 +253,9 @@ exports[`generator - java:openapi-generator maven-addOpenapiGeneratorPlugin(fals exports[`generator - java:openapi-generator maven-addOpenapiGeneratorPlugin(false) should compose with generators 1`] = ` [ + "jhipster:bootstrap", "jhipster:java:build-tool", + "jhipster:project-name", ] `; @@ -122,20 +275,23 @@ exports[`generator - java:openapi-generator maven-addOpenapiGeneratorPlugin(fals exports[`generator - java:openapi-generator maven-addOpenapiGeneratorPlugin(true) should call source snapshot 1`] = ` { - "addJavaDependencies": [ + "addJavaDefinitions": [ [ { - "artifactId": "jackson-databind-nullable", - "groupId": "org.openapitools", - "version": "'JACKSON-DATABIND-NULLABLE-VERSION'", + "dependencies": [ + { + "artifactId": "jackson-databind-nullable", + "groupId": "org.openapitools", + "version": "'JACKSON-DATABIND-NULLABLE-VERSION'", + }, + ], }, - ], - ], - "addMavenDefinition": [ - { - "pluginManagement": [ - { - "additionalContent": " + { + "condition": true, + "mavenDefinition": { + "pluginManagement": [ + { + "additionalContent": " generate @@ -156,31 +312,35 @@ exports[`generator - java:openapi-generator maven-addOpenapiGeneratorPlugin(true ", - "artifactId": "openapi-generator-maven-plugin", - "groupId": "org.openapitools", - "version": "\${openapi-generator-maven-plugin.version}", - }, - ], - "plugins": [ - { - "artifactId": "openapi-generator-maven-plugin", - "groupId": "org.openapitools", + "artifactId": "openapi-generator-maven-plugin", + "groupId": "org.openapitools", + "version": "\${openapi-generator-maven-plugin.version}", + }, + ], + "plugins": [ + { + "artifactId": "openapi-generator-maven-plugin", + "groupId": "org.openapitools", + }, + ], + "properties": [ + { + "property": "openapi-generator-maven-plugin.version", + "value": "'OPENAPI-GENERATOR-MAVEN-PLUGIN-VERSION'", + }, + ], }, - ], - "properties": [ - { - "property": "openapi-generator-maven-plugin.version", - "value": "'OPENAPI-GENERATOR-MAVEN-PLUGIN-VERSION'", - }, - ], - }, + }, + ], ], } `; exports[`generator - java:openapi-generator maven-addOpenapiGeneratorPlugin(true) should compose with generators 1`] = ` [ + "jhipster:bootstrap", "jhipster:java:build-tool", + "jhipster:project-name", ] `; diff --git a/generators/java/generators/openapi-generator/command.ts b/generators/java/generators/openapi-generator/command.ts index 8bc635837dc5..0703c340e48f 100644 --- a/generators/java/generators/openapi-generator/command.ts +++ b/generators/java/generators/openapi-generator/command.ts @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/types.js'; -const command: JHipsterCommandDefinition = { +const command = { configs: { addOpenapiGeneratorPlugin: { cli: { @@ -30,6 +30,8 @@ const command: JHipsterCommandDefinition = { }, }, import: [], -}; +} as const satisfies JHipsterCommandDefinition; + +export type Command = typeof command; export default command; diff --git a/generators/java/generators/openapi-generator/generator.spec.ts b/generators/java/generators/openapi-generator/generator.spec.ts index 0b4a4a5b9690..7b4591c0d18c 100644 --- a/generators/java/generators/openapi-generator/generator.spec.ts +++ b/generators/java/generators/openapi-generator/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { fromMatrix, defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { fromMatrix, defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -53,7 +53,7 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchSnapshot(); + expect(result.getComposedGenerators()).toMatchSnapshot(); }); }); } diff --git a/generators/java/generators/openapi-generator/generator.ts b/generators/java/generators/openapi-generator/generator.ts index 05ed6c29fca8..752d70a9d304 100644 --- a/generators/java/generators/openapi-generator/generator.ts +++ b/generators/java/generators/openapi-generator/generator.ts @@ -34,8 +34,8 @@ export default class OpenapiGeneratorGenerator extends BaseApplicationGenerator get writing() { return this.asWritingTaskGroup({ - cleanup({ application, control }) { - control.cleanupFiles({ + async cleanup({ application, control }) { + await control.cleanupFiles({ '8.6.1': [[application.buildToolGradle!, 'gradle/swagger.gradle']], }); }, @@ -62,18 +62,20 @@ export default class OpenapiGeneratorGenerator extends BaseApplicationGenerator get postWriting() { return this.asPostWritingTaskGroup({ addDependencies({ source, application }) { - const { addOpenapiGeneratorPlugin, buildToolGradle, buildToolMaven, javaDependencies } = application; - source.addJavaDependencies!([ + const { addOpenapiGeneratorPlugin, buildToolGradle, javaDependencies } = application; + source.addJavaDefinitions!( { - groupId: 'org.openapitools', - artifactId: 'jackson-databind-nullable', - version: javaDependencies!['jackson-databind-nullable'], + dependencies: [ + { + groupId: 'org.openapitools', + artifactId: 'jackson-databind-nullable', + version: javaDependencies!['jackson-databind-nullable'], + }, + ], }, - ]); - - if (addOpenapiGeneratorPlugin) { - if (buildToolMaven) { - source.addMavenDefinition!({ + { + condition: addOpenapiGeneratorPlugin, + mavenDefinition: { properties: [ { property: 'openapi-generator-maven-plugin.version', value: javaDependencies!['openapi-generator-maven-plugin'] }, ], @@ -82,6 +84,7 @@ export default class OpenapiGeneratorGenerator extends BaseApplicationGenerator { groupId: 'org.openapitools', artifactId: 'openapi-generator-maven-plugin', + // eslint-disable-next-line no-template-curly-in-string version: '${openapi-generator-maven-plugin.version}', additionalContent: ` @@ -112,8 +115,11 @@ export default class OpenapiGeneratorGenerator extends BaseApplicationGenerator `, }, ], - }); - } + }, + }, + ); + + if (addOpenapiGeneratorPlugin) { if (buildToolGradle) { source.addGradleBuildSrcDependencyCatalogLibraries?.([ { diff --git a/generators/java/support/add-java-annotation.spec.ts b/generators/java/support/add-java-annotation.spec.ts index b9ec5a9caa7f..2a8c9f1bf93e 100644 --- a/generators/java/support/add-java-annotation.spec.ts +++ b/generators/java/support/add-java-annotation.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { addJavaAnnotation, addJavaImport } from './add-java-annotation.js'; describe('generator > java', () => { diff --git a/generators/java/support/artifacts.ts b/generators/java/support/artifacts.ts index 2abaf30dccc5..e19c08f13fa5 100644 --- a/generators/java/support/artifacts.ts +++ b/generators/java/support/artifacts.ts @@ -1,4 +1,4 @@ -import { JavaArtifactType } from '../types.js'; +import type { JavaArtifactType } from '../types.js'; export const javaScopeToGradleScope = (artifactType: JavaArtifactType): string => { const { scope = 'compile', type = 'jar' } = artifactType; diff --git a/generators/java/support/checks/check-java.spec.ts b/generators/java/support/checks/check-java.spec.ts index ec9874de81a0..49576d5634b4 100644 --- a/generators/java/support/checks/check-java.spec.ts +++ b/generators/java/support/checks/check-java.spec.ts @@ -1,7 +1,6 @@ -import { after, before, it, describe, expect, resetAllMocks, esmocha } from 'esmocha'; -import quibble from 'quibble'; +import { after, before, describe, esmocha, expect, it, resetAllMocks } from 'esmocha'; -const execa = { execa: esmocha.fn(), execaSync: esmocha.fn(), execaCommandSync: esmocha.fn(), execaCommand: esmocha.fn() }; +const { execaCommandSync } = await esmocha.mock('execa', import('execa')); const baseResult = { cwd: '', @@ -15,13 +14,9 @@ const baseResult = { } as any; describe('generator - server - checkJava', () => { - before(async () => { - await quibble.esm('execa', execa); - }); after(() => { - quibble.reset(); + esmocha.reset(); }); - afterEach(() => { resetAllMocks(); }); @@ -31,7 +26,7 @@ describe('generator - server - checkJava', () => { let result; before(async () => { - execa.execaCommandSync.mockReturnValue({ ...baseResult, stderr } as any); + execaCommandSync.mockReturnValue({ ...baseResult, stderr }); const { default: checkJava } = await import('./check-java.js'); result = checkJava([]); }); @@ -50,7 +45,7 @@ describe('generator - server - checkJava', () => { let result; before(async () => { - execa.execaCommandSync.mockReturnValue({ ...baseResult, exitCode, stderr } as any); + execaCommandSync.mockReturnValue({ ...baseResult, exitCode, stderr }); const { default: checkJava } = await import('./check-java.js'); result = checkJava([]); }); @@ -64,7 +59,7 @@ describe('generator - server - checkJava', () => { let result; before(async () => { - execa.execaCommandSync.mockImplementation(() => { + execaCommandSync.mockImplementation(() => { throw new Error('foo'); }); const { default: checkJava } = await import('./check-java.js'); diff --git a/generators/java/support/checks/check-java.ts b/generators/java/support/checks/check-java.ts index 654f4544a835..dacca95d598b 100644 --- a/generators/java/support/checks/check-java.ts +++ b/generators/java/support/checks/check-java.ts @@ -28,11 +28,11 @@ export default (javaCompatibleVersions: string[]): ValidationResult & { javaVers try { const { exitCode, stderr } = execaCommandSync('java -version', { stdio: 'pipe' }); if (exitCode === 0 && stderr) { - const matchResult = stderr.match(/(?:java|openjdk)(?: version)? "?(.*)"? /s); + const matchResult = /(?:java|openjdk)(?: version)? "?(.*)"? /s.exec(stderr); if (matchResult && matchResult.length > 0) { const javaVersion = matchResult[1]; const debug = `Detected java version ${javaVersion}`; - if (javaCompatibleVersions && !javaVersion.match(new RegExp(`(${javaCompatibleVersions.map(ver => `^${ver}`).join('|')})`))) { + if (javaCompatibleVersions && !new RegExp(`(${javaCompatibleVersions.map(ver => `^${ver}`).join('|')})`).exec(javaVersion)) { const [latest, ...others] = javaCompatibleVersions.concat().reverse(); const humanizedVersions = `${others.reverse().join(', ')} or ${latest}`; const warning = `Java ${humanizedVersions} are not found on your computer. Your Java version is: ${chalk.yellow(javaVersion)}`; diff --git a/generators/java/support/checks/index.ts b/generators/java/support/checks/index.ts index 32d9c4cbc8d3..54b65f4caa84 100644 --- a/generators/java/support/checks/index.ts +++ b/generators/java/support/checks/index.ts @@ -1,2 +1 @@ -// eslint-disable-next-line import/prefer-default-export export { default as checkJava } from './check-java.js'; diff --git a/generators/java/support/doc.spec.ts b/generators/java/support/doc.spec.ts index e08c8fe2c518..e3122a3065f7 100644 --- a/generators/java/support/doc.spec.ts +++ b/generators/java/support/doc.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { formatDocAsApiDescription, formatDocAsJavaDoc } from './doc.js'; describe('generator - server - support - doc', () => { diff --git a/generators/java/support/files.ts b/generators/java/support/files.ts index d6025fa705cf..8271aa2fb56e 100644 --- a/generators/java/support/files.ts +++ b/generators/java/support/files.ts @@ -19,7 +19,9 @@ import type { WriteFileBlock } from '../../base/api.js'; import type CoreGenerator from '../../base-core/generator.js'; -import { SERVER_TEST_SRC_DIR, SERVER_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR, SERVER_TEST_RES_DIR } from '../../generator-constants.js'; +import { SERVER_MAIN_RES_DIR, SERVER_MAIN_SRC_DIR, SERVER_TEST_RES_DIR, SERVER_TEST_SRC_DIR } from '../../generator-constants.js'; +import type { ApplicationType } from '../../../lib/types/application/application.js'; +import type { Entity } from '../../../lib/types/application/entity.js'; export const replaceEntityFilePathVariables = (data: any, filePath: string) => { filePath = filePath @@ -60,7 +62,9 @@ export const moveToSrcTestResourcesDir = (data: any, filePath: string) => type RelativeWriteFileBlock = WriteFileBlock & { relativePath?: string }; -export function javaMainPackageTemplatesBlock(blockOrRelativePath?: string): Pick; +export function javaMainPackageTemplatesBlock>( + blockOrRelativePath?: string, +): Pick, 'path' | 'renameTo'>; export function javaMainPackageTemplatesBlock(blockOrRelativePath: RelativeWriteFileBlock): WriteFileBlock; export function javaMainPackageTemplatesBlock( blockOrRelativePath: string | RelativeWriteFileBlock = '', diff --git a/generators/java/support/generated-annotation-transform.spec.ts b/generators/java/support/generated-annotation-transform.spec.ts index 6a5a44115364..604909844aa7 100644 --- a/generators/java/support/generated-annotation-transform.spec.ts +++ b/generators/java/support/generated-annotation-transform.spec.ts @@ -1,6 +1,6 @@ -import { Readable } from 'stream'; -import { it, describe, expect } from 'esmocha'; -import { pipeline } from 'p-transform'; +import { Readable } from 'node:stream'; +import { pipeline } from 'node:stream/promises'; +import { describe, expect, it } from 'esmocha'; import generatedAnnotationTransform from './generated-annotation-transform.js'; describe('generators - java - generated-annotation-transform', () => { diff --git a/generators/java/support/key-store.ts b/generators/java/support/key-store.ts index 71884d274ab4..da1d355f4dde 100644 --- a/generators/java/support/key-store.ts +++ b/generators/java/support/key-store.ts @@ -1,12 +1,12 @@ -import { mkdir, lstat } from 'fs/promises'; +import { lstat, mkdir } from 'fs/promises'; import { dirname } from 'path'; import { execa } from 'execa'; -import { ValidationResult } from '../../base/api.js'; +import type { ValidationResult } from '../../base/api.js'; /** * Generate a KeyStore. */ -// eslint-disable-next-line import/prefer-default-export + export async function generateKeyStore(keyStoreFile: string, { packageName }: { packageName: string }): Promise { try { const stat = await lstat(keyStoreFile); diff --git a/generators/java/support/util.spec.ts b/generators/java/support/util.spec.ts index 027acae9d473..b6b6e825e905 100644 --- a/generators/java/support/util.spec.ts +++ b/generators/java/support/util.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { getMainClassName } from './util.js'; describe('generator > java', () => { diff --git a/generators/java/types.d.ts b/generators/java/types.d.ts index 23b21b66fac1..8358fed1c37d 100644 --- a/generators/java/types.d.ts +++ b/generators/java/types.d.ts @@ -1,8 +1,14 @@ -import { RequireOneOrNone } from 'type-fest'; -import { BaseApplication } from '../base-application/types.js'; -import { GradleApplication, GradleNeedleOptions } from '../gradle/types.js'; -import { EditFileCallback } from '../base/api.js'; -import { JavaAnnotation } from './support/add-java-annotation.ts'; +import type { RequireOneOrNone } from 'type-fest'; +import type { GradleApplication, GradleNeedleOptions } from '../gradle/types.js'; +import type { EditFileCallback } from '../base/api.js'; +import type { MavenDefinition } from '../maven/types.js'; +import type { ExportStoragePropertiesFromCommand } from '../../lib/command/index.js'; +import type { JavaAnnotation } from './support/add-java-annotation.ts'; +import type { default as OpenapiGeneratorCommand } from './generators/openapi-generator/command.js'; +import type { default as BootstrapCommand } from './generators/bootstrap/command.js'; + +type JavaBootstrapStorageProperties = ExportStoragePropertiesFromCommand; +type JavaOpenapiGeneratorStorageProperties = ExportStoragePropertiesFromCommand; export type JavaDependencyVersion = { name: string; @@ -22,20 +28,23 @@ export type JavaArtifact = { export type JavaArtifactVersion = RequireOneOrNone<{ version?: string; versionRef?: string }, 'version' | 'versionRef'>; -export type JavaDependency = JavaArtifact & JavaArtifactVersion; +export type JavaDependency = JavaArtifact & + JavaArtifactVersion & { + exclusions?: JavaArtifact[]; + }; export type JavaDefinition = { versions?: JavaDependencyVersion[]; dependencies?: JavaDependency[]; + mavenDefinition?: MavenDefinition; }; export type JavaNeedleOptions = GradleNeedleOptions; -export type JavaApplication = BaseApplication & +export type JavaApplication = JavaBootstrapStorageProperties & GradleApplication & { javaVersion: string; - packageName: string; packageFolder: string; entityPackages: string[]; @@ -67,6 +76,8 @@ export type JavaApplication = BaseApplication & addOpenapiGeneratorPlugin: boolean; }; +export type ConditionalJavaDefinition = JavaDefinition & { condition?: boolean }; + export type JavaSourceType = { /** * Add a JavaDefinition to the application. @@ -74,6 +85,10 @@ export type JavaSourceType = { * A dependency with versionRef requires a valid referenced version at `versions` otherwise it will be ignored. */ addJavaDefinition?(definition: JavaDefinition, options?: JavaNeedleOptions): void; + addJavaDefinitions?( + optionsOrDefinition: JavaNeedleOptions | ConditionalJavaDefinition, + ...definitions: ConditionalJavaDefinition[] + ): void; addJavaDependencies?(dependency: JavaDependency[], options?: JavaNeedleOptions): void; hasJavaProperty?(propertyName: string): boolean; hasJavaManagedProperty?(propertyName: string): boolean; diff --git a/generators/javascript/generators/bootstrap/__snapshots__/generator.spec.ts.snap b/generators/javascript/generators/bootstrap/__snapshots__/generator.spec.ts.snap index 498e89996569..cdc6b7b6c88d 100644 --- a/generators/javascript/generators/bootstrap/__snapshots__/generator.spec.ts.snap +++ b/generators/javascript/generators/bootstrap/__snapshots__/generator.spec.ts.snap @@ -9,18 +9,17 @@ exports[`generator - javascript:bootstrap customVersion-commonjs should match fi }, "package.json": { "contents": "{ - "name": "dasherizedBaseName", - "version": "0.0.0", - "description": "projectDescription", "private": true, - "license": "UNLICENSED", "dependencies": {}, "devDependencies": {}, "engines": { "node": "customVersion" }, "scripts": {}, - "type": "commonjs" + "name": "dasherizedBaseName", + "version": "0.0.0", + "description": "projectDescription", + "license": "UNLICENSED" } ", "stateCleared": "modified", @@ -37,15 +36,15 @@ exports[`generator - javascript:bootstrap packageJsonNodeEngine(false)-module sh }, "package.json": { "contents": "{ - "name": "dasherizedBaseName", - "version": "0.0.0", - "description": "projectDescription", "private": true, - "license": "UNLICENSED", "dependencies": {}, "devDependencies": {}, "engines": {}, "scripts": {}, + "name": "dasherizedBaseName", + "version": "0.0.0", + "description": "projectDescription", + "license": "UNLICENSED", "type": "module" } ", @@ -63,18 +62,17 @@ exports[`generator - javascript:bootstrap packageJsonNodeEngine(true) should mat }, "package.json": { "contents": "{ - "name": "dasherizedBaseName", - "version": "0.0.0", - "description": "projectDescription", "private": true, - "license": "UNLICENSED", "dependencies": {}, "devDependencies": {}, "engines": { "node": "^18.19.0 || >= 20.6.1" }, "scripts": {}, - "type": "commonjs" + "name": "dasherizedBaseName", + "version": "0.0.0", + "description": "projectDescription", + "license": "UNLICENSED" } ", "stateCleared": "modified", diff --git a/generators/javascript/generators/bootstrap/command.ts b/generators/javascript/generators/bootstrap/command.ts index f101f2fb6c46..cfdbedb71364 100644 --- a/generators/javascript/generators/bootstrap/command.ts +++ b/generators/javascript/generators/bootstrap/command.ts @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; -const command: JHipsterCommandDefinition = { +const command = { configs: { packageJsonNodeEngine: { cli: { @@ -39,6 +39,6 @@ const command: JHipsterCommandDefinition = { }, }, import: [], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/javascript/generators/bootstrap/generator.spec.ts b/generators/javascript/generators/bootstrap/generator.spec.ts index 5a209ad1d74d..50b03e08eb04 100644 --- a/generators/javascript/generators/bootstrap/generator.spec.ts +++ b/generators/javascript/generators/bootstrap/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { extendMatrix, fromMatrix, defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { extendMatrix, fromMatrix, defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -57,7 +57,7 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toHaveLength(0); + expect(result.getComposedGenerators()).toHaveLength(2); }); }); } diff --git a/generators/javascript/generators/bootstrap/generator.ts b/generators/javascript/generators/bootstrap/generator.ts index 3c6066554771..1520c327fd8d 100644 --- a/generators/javascript/generators/bootstrap/generator.ts +++ b/generators/javascript/generators/bootstrap/generator.ts @@ -21,10 +21,6 @@ import BaseApplicationGenerator from '../../../base-application/index.js'; import { GENERATOR_PROJECT_NAME } from '../../../generator-list.js'; export default class BootstrapGenerator extends BaseApplicationGenerator { - constructor(args, options, features) { - super(args, options, { queueCommandTasks: true, ...features }); - } - async beforeQueue() { if (!this.fromBlueprint) { await this.composeWithBlueprints(); @@ -43,6 +39,12 @@ export default class BootstrapGenerator extends BaseApplicationGenerator { this.fetchFromInstalledJHipster('javascript', 'resources', 'package.json'), ); }, + jsExtensions({ applicationDefaults, application }) { + applicationDefaults({ + cjsExtension: application.packageJsonTypeCommonjs ? '.js' : '.cjs', + mjsExtension: application.packageJsonTypeCommonjs ? '.js' : '.mjs', + }); + }, }); } @@ -68,15 +70,22 @@ export default class BootstrapGenerator extends BaseApplicationGenerator { get postWriting() { return this.asPostWritingTaskGroup({ addPrettierDependencies({ application }) { - const { packageJsonNodeEngine, packageJsonType } = application; - if (packageJsonType) { + const { packageJsonNodeEngine, packageJsonType, dasherizedBaseName, projectDescription, packageJsonScripts } = application; + this.packageJson.merge({ scripts: packageJsonScripts! }); + this.packageJson.defaults({ + name: dasherizedBaseName, + version: '0.0.0', + description: projectDescription, + license: 'UNLICENSED', + }); + if (packageJsonType === 'module') { this.packageJson.merge({ type: packageJsonType }); } if (packageJsonNodeEngine) { - this.packageJson.merge({ - engines: { - node: typeof packageJsonNodeEngine === 'string' ? packageJsonNodeEngine : packageJson.engines.node, - }, + const packageJsonEngines: any = this.packageJson.get('engines') ?? {}; + this.packageJson.set('engines', { + ...packageJsonEngines, + node: typeof packageJsonNodeEngine === 'string' ? packageJsonNodeEngine : packageJson.engines.node, }); } }, diff --git a/generators/javascript/generators/bootstrap/templates/package.json.ejs b/generators/javascript/generators/bootstrap/templates/package.json.ejs index f39db40aca7d..3bd2d4152ac0 100644 --- a/generators/javascript/generators/bootstrap/templates/package.json.ejs +++ b/generators/javascript/generators/bootstrap/templates/package.json.ejs @@ -17,11 +17,7 @@ limitations under the License. -%> { - "name": "<%= dasherizedBaseName %>", - "version": "0.0.0", - "description": "<%= projectDescription %>", "private": true, - "license": "UNLICENSED", "dependencies": {}, "devDependencies": {}, "engines": {}, diff --git a/generators/javascript/generators/eslint/__snapshots__/generator.spec.ts.snap b/generators/javascript/generators/eslint/__snapshots__/generator.spec.ts.snap index 7c67f1afea45..4218eeab3872 100644 --- a/generators/javascript/generators/eslint/__snapshots__/generator.spec.ts.snap +++ b/generators/javascript/generators/eslint/__snapshots__/generator.spec.ts.snap @@ -10,7 +10,6 @@ exports[`generator - javascript:eslint with defaults options should match files "eslint.config.mjs": { "contents": "import globals from 'globals'; import prettier from 'eslint-plugin-prettier/recommended'; - // jhipster-needle-eslint-add-import - JHipster will add additional import here export default [ @@ -21,7 +20,6 @@ export default [ }, }, }, - // jhipster-needle-eslint-add-config - JHipster will add additional config here prettier, ]; diff --git a/generators/javascript/generators/eslint/command.ts b/generators/javascript/generators/eslint/command.ts index 56be6cd837a2..99f9a064ba35 100644 --- a/generators/javascript/generators/eslint/command.ts +++ b/generators/javascript/generators/eslint/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; const command: JHipsterCommandDefinition = { configs: { diff --git a/generators/javascript/generators/eslint/generator.spec.ts b/generators/javascript/generators/eslint/generator.spec.ts index c3fe18868704..bb936d1519ef 100644 --- a/generators/javascript/generators/eslint/generator.spec.ts +++ b/generators/javascript/generators/eslint/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -52,7 +52,7 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ "jhipster:javascript:bootstrap", ] diff --git a/generators/javascript/generators/eslint/generator.ts b/generators/javascript/generators/eslint/generator.ts index bf5d7c244172..c8172c419e6a 100644 --- a/generators/javascript/generators/eslint/generator.ts +++ b/generators/javascript/generators/eslint/generator.ts @@ -56,7 +56,7 @@ export default class EslintGenerator extends BaseApplicationGenerator { importToAdd ? createNeedleCallback({ needle: 'eslint-add-import', contentToAdd: importToAdd }) : content => content, ); source.addEslintIgnore = ({ ignorePattern }) => - source.addEslintConfig({ config: `{ ignores: '${ignorePattern.replaceAll("'", "\\')}")},` }); + source.addEslintConfig!({ config: `{ ignores: '${ignorePattern.replaceAll("'", "\\')}")},` }); }, }); } diff --git a/generators/javascript/generators/eslint/support/tasks.ts b/generators/javascript/generators/eslint/support/tasks.ts index cb6b7d114842..4848e19ce711 100644 --- a/generators/javascript/generators/eslint/support/tasks.ts +++ b/generators/javascript/generators/eslint/support/tasks.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { asWritingTask } from '../../../../base-application/support/task-type-inference.js'; +import { asWritingTask } from '../../../../base-application/support/index.js'; import { clientRootTemplatesBlock } from '../../../../client/support/files.js'; export const writeEslintClientRootConfigFile = asWritingTask(async function writingEslintFile({ application }) { diff --git a/generators/javascript/generators/eslint/templates/eslint.config.js.jhi.ejs b/generators/javascript/generators/eslint/templates/eslint.config.js.jhi.ejs index 8b7515f3078a..b69dbce80259 100644 --- a/generators/javascript/generators/eslint/templates/eslint.config.js.jhi.ejs +++ b/generators/javascript/generators/eslint/templates/eslint.config.js.jhi.ejs @@ -21,6 +21,7 @@ fragments.registerSections({ importsSection: 0, configSection: 0, + endConfigSection: 0, }); _&> <%_ if (typescriptEslint) { _%> @@ -32,7 +33,7 @@ import prettier from 'eslint-plugin-prettier/recommended'; <%_ if (typescriptEslint) { _%> import tseslint from 'typescript-eslint'; <%_ } _%> -<&- fragments.importsSection() &> +<&- fragments.importsSection() -&> // jhipster-needle-eslint-add-import - JHipster will add additional import here <%_ if (typescriptEslint) { _%> @@ -47,9 +48,10 @@ export default [ }, }, }, -<&- fragments.configSection() &> +<&- fragments.configSection() -&> // jhipster-needle-eslint-add-config - JHipster will add additional config here prettier, +<&- fragments.endConfigSection() -&> <%_ if (typescriptEslint) { _%> ); <%_ } else { _%> diff --git a/generators/javascript/generators/husky/__snapshots__/generator.spec.ts.snap b/generators/javascript/generators/husky/__snapshots__/generator.spec.ts.snap index 81c4151375dd..82daa45ae1eb 100644 --- a/generators/javascript/generators/husky/__snapshots__/generator.spec.ts.snap +++ b/generators/javascript/generators/husky/__snapshots__/generator.spec.ts.snap @@ -5,15 +5,13 @@ exports[`generator - javascript:husky skipCommitHook(false) should call source s exports[`generator - javascript:husky skipCommitHook(false) should match files snapshot 1`] = ` { ".husky/pre-commit": { - "contents": "#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -npx --no-install lint-staged", + "contents": "lint-staged +", "stateCleared": "modified", }, ".lintstagedrc.cjs": { "contents": "module.exports = { - '{,src/**/,webpack/}*.{md,json,yml,html,js,ts,tsx,css,scss,vue,java}': ['prettier --write'], + '{PRETTIER_FOLDERS}*.{PRETTIER_EXTENSIONS}': ['prettier --write'], }; ", "stateCleared": "modified", diff --git a/generators/javascript/generators/husky/command.ts b/generators/javascript/generators/husky/command.ts index 58bbdb424ef2..15daab75d785 100644 --- a/generators/javascript/generators/husky/command.ts +++ b/generators/javascript/generators/husky/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; const command: JHipsterCommandDefinition = { configs: { diff --git a/generators/javascript/generators/husky/generator.spec.ts b/generators/javascript/generators/husky/generator.spec.ts index 770e6cc1e377..7cfd2c95b3db 100644 --- a/generators/javascript/generators/husky/generator.spec.ts +++ b/generators/javascript/generators/husky/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { fromMatrix, defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { fromMatrix, defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -41,7 +41,7 @@ describe(`generator - ${generator}`, () => { .withMockedJHipsterGenerators() .withMockedSource() .withMockedNodeDependencies() - .withSharedApplication({}) + .withSharedApplication({ prettierExtensions: 'PRETTIER_EXTENSIONS', prettierFolders: 'PRETTIER_FOLDERS' }) .withJHipsterConfig(config); }); @@ -54,7 +54,7 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchObject(expect.arrayContaining(['jhipster:javascript:bootstrap'])); + expect(result.getComposedGenerators()).toMatchObject(['jhipster:bootstrap', 'jhipster:javascript:prettier'] as any); }); }); } diff --git a/generators/javascript/generators/husky/generator.ts b/generators/javascript/generators/husky/generator.ts index c1055a723ff2..f751c7b713f5 100644 --- a/generators/javascript/generators/husky/generator.ts +++ b/generators/javascript/generators/husky/generator.ts @@ -29,7 +29,7 @@ export default class HuskyGenerator extends BaseApplicationGenerator { } if (!this.delegateToBlueprint) { - await this.dependsOnJHipster('jhipster:javascript:bootstrap'); + await this.dependsOnJHipster('jhipster:javascript:prettier'); } } diff --git a/generators/javascript/generators/husky/templates/.husky/pre-commit.ejs b/generators/javascript/generators/husky/templates/.husky/pre-commit.ejs index c70c608e786c..c27d8893a994 100755 --- a/generators/javascript/generators/husky/templates/.husky/pre-commit.ejs +++ b/generators/javascript/generators/husky/templates/.husky/pre-commit.ejs @@ -1,4 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -npx --no-install lint-staged \ No newline at end of file +lint-staged diff --git a/generators/javascript/generators/husky/templates/.lintstagedrc.cjs.ejs b/generators/javascript/generators/husky/templates/.lintstagedrc.cjs.ejs index 4ae14f966d2e..31cc54366c92 100644 --- a/generators/javascript/generators/husky/templates/.lintstagedrc.cjs.ejs +++ b/generators/javascript/generators/husky/templates/.lintstagedrc.cjs.ejs @@ -17,5 +17,5 @@ limitations under the License. -%> module.exports = { - '{,src/**/,webpack/}*.{md,json,yml,html,js,ts,tsx,css,scss,vue,java}': ['prettier --write'], + '{<%= prettierFolders %>}*.{<%= prettierExtensions %>}': ['prettier --write'], }; diff --git a/generators/javascript/generators/prettier/__snapshots__/generator.spec.ts.snap b/generators/javascript/generators/prettier/__snapshots__/generator.spec.ts.snap index abc19a26cb1d..8dd7e7b2e9e3 100644 --- a/generators/javascript/generators/prettier/__snapshots__/generator.spec.ts.snap +++ b/generators/javascript/generators/prettier/__snapshots__/generator.spec.ts.snap @@ -1,5 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`generator - javascript:prettier fromInit(false) should compose with generators 1`] = ` +[ + "jhipster:javascript:bootstrap", + "jhipster:project-name", +] +`; + exports[`generator - javascript:prettier fromInit(false) should match files snapshot 1`] = ` { ".prettierignore": { @@ -37,6 +44,12 @@ plugins: } `; +exports[`generator - javascript:prettier fromInit(true) should compose with generators 1`] = ` +[ + "jhipster:javascript:bootstrap", +] +`; + exports[`generator - javascript:prettier fromInit(true) should match files snapshot 1`] = ` { ".prettierignore": { @@ -78,6 +91,13 @@ plugins: } `; +exports[`generator - javascript:prettier monorepository(true)-monorepositoryRoot(false) should compose with generators 1`] = ` +[ + "jhipster:javascript:bootstrap", + "jhipster:project-name", +] +`; + exports[`generator - javascript:prettier monorepository(true)-monorepositoryRoot(false) should match files snapshot 1`] = ` { ".prettierignore": { @@ -115,6 +135,13 @@ plugins: } `; +exports[`generator - javascript:prettier monorepository(true)-monorepositoryRoot(true) should compose with generators 1`] = ` +[ + "jhipster:javascript:bootstrap", + "jhipster:project-name", +] +`; + exports[`generator - javascript:prettier monorepository(true)-monorepositoryRoot(true) should match files snapshot 1`] = ` { ".prettierignore": { diff --git a/generators/javascript/generators/prettier/command.ts b/generators/javascript/generators/prettier/command.ts index b8a14e2ab40e..1656ed37a6ad 100644 --- a/generators/javascript/generators/prettier/command.ts +++ b/generators/javascript/generators/prettier/command.ts @@ -16,12 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; import gitCommand from '../../../git/command.js'; const { monorepository } = gitCommand.configs!; -const command: JHipsterCommandDefinition = { +const command = { configs: { fromInit: { description: 'Generate prettier config using init defaults', @@ -60,6 +60,6 @@ const command: JHipsterCommandDefinition = { }, }, import: [], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/javascript/generators/prettier/generator.spec.ts b/generators/javascript/generators/prettier/generator.spec.ts index a24d503fda95..bafb8bf38934 100644 --- a/generators/javascript/generators/prettier/generator.spec.ts +++ b/generators/javascript/generators/prettier/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { fromMatrix, defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { fromMatrix, defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -52,7 +52,7 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot('[]'); + expect(result.getComposedGenerators()).toMatchSnapshot(); }); }); }); diff --git a/generators/javascript/generators/prettier/generator.ts b/generators/javascript/generators/prettier/generator.ts index 04533140e2b1..4fda149c7507 100644 --- a/generators/javascript/generators/prettier/generator.ts +++ b/generators/javascript/generators/prettier/generator.ts @@ -33,13 +33,16 @@ export default class PrettierGenerator extends BaseApplicationGenerator { await this.composeWithBlueprints(); } - if (!this.delegateToBlueprint && !this.options.fromInit) { - await this.dependsOnBootstrapApplication(); + if (!this.delegateToBlueprint) { + if (!this.options.fromInit) { + await this.dependsOnBootstrapApplication(); + } + await this.dependsOnJHipster('jhipster:javascript:bootstrap'); } } - get preparing() { - return this.asPreparingTaskGroup({ + get loading() { + return this.asLoadingTaskGroup({ loadNodeDependencies({ application }) { this.loadNodeDependencies(application.nodeDependencies, { prettier: packageJson.dependencies.prettier, @@ -47,6 +50,29 @@ export default class PrettierGenerator extends BaseApplicationGenerator { 'prettier-plugin-packagejson': packageJson.dependencies['prettier-plugin-packagejson'], }); }, + loadDefaults({ application, applicationDefaults }) { + applicationDefaults({ + prettierFolders: ',**/', + prettierExtensions: 'md,json,yml,js,cjs,mjs,ts,cts,mts', + }); + + application.addPrettierExtensions = (extensions: string[]) => { + const currentExtensions = application.prettierExtensions!.split(','); + const extensionsToAdd = extensions.filter(ext => !currentExtensions.includes(ext)); + if (extensionsToAdd.length > 0) { + application.prettierExtensions = `${application.prettierExtensions},${extensionsToAdd.join(',')}`; + } + }; + }, + }); + } + + get [BaseApplicationGenerator.LOADING]() { + return this.delegateTasksToBlueprint(() => this.loading); + } + + get preparing() { + return this.asPreparingTaskGroup({ source({ source }) { source.mergePrettierConfig = config => this.mergeDestinationYaml(this.prettierConfigFile, config); // `.prettierignore` file is only supported in the root of a project refer to https://github.com/prettier/prettier/issues/4081. diff --git a/generators/javascript/resources/package.json b/generators/javascript/resources/package.json index 48b53a677e1c..7090fd3478d6 100644 --- a/generators/javascript/resources/package.json +++ b/generators/javascript/resources/package.json @@ -2,7 +2,7 @@ "dependencies": { "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.2.1", - "husky": "9.0.11", - "lint-staged": "15.2.7" + "husky": "9.1.6", + "lint-staged": "15.2.10" } } diff --git a/generators/javascript/types.d.ts b/generators/javascript/types.d.ts index 5af8355d8a83..fab53b454aaa 100644 --- a/generators/javascript/types.d.ts +++ b/generators/javascript/types.d.ts @@ -1,10 +1,22 @@ +import type { ExportApplicationPropertiesFromCommand } from '../../lib/command/types.js'; +import type JavascriptBootstrapCommand from './generators/bootstrap/command.ts'; + +type JavascriptBootstrapProperties = ExportApplicationPropertiesFromCommand; + export type JavaScriptSourceType = { mergePrettierConfig?: (config: Record) => void; addPrettierIgnore?: (newContent: string) => void; + + addEslintIgnore?: (opts: { ignorePattern: string }) => void; + addEslintConfig?: (opts: { import?: string | string[]; config?: string | string[] }) => void; }; -export type JavaScriptApplication = { +export type JavaScriptApplication = JavascriptBootstrapProperties & { packageJsonNodeEngine?: boolean | string; - packageJsonType?: string; eslintConfigFile?: string; + cjsExtension?: string; + mjsExtension?: string; + packageJsonScripts: Record; + + addPrettierExtensions?: (extensions: string[]) => void; }; diff --git a/generators/jdl/__snapshots__/generator.spec.ts.snap b/generators/jdl/__snapshots__/generator.spec.ts.snap index 68fe9f049134..0c2f5f73b771 100644 --- a/generators/jdl/__snapshots__/generator.spec.ts.snap +++ b/generators/jdl/__snapshots__/generator.spec.ts.snap @@ -164,7 +164,7 @@ Options: --ignore-application Ignores application generation --ignore-deployments Ignores deployments generation --skip-sample-repository Disable fetching sample files when the file is not a URL - --inline Pass JDL content inline. Argument can be skipped when passing this + --inline Pass JDL content inline. Argument can be skipped when passing this (env: JHI_JDL) --skip-user-management Skip the user management module during app generation --skip-cache Do not remember prompt answers (default: false) --skip-install Do not automatically install dependencies (default: false) @@ -173,6 +173,8 @@ Options: --workspaces-folders Folders to use as monorepository workspace --workspaces Generate workspaces for multiples applications --skip-git Skip git repository initialization + --force-git Force commit to git repository + --commit-msg Commit changes (implies forceGit) --monorepository Use monorepository --defaults Execute jhipster with default config --skip-client Skip the client-side application generation @@ -187,18 +189,16 @@ Options: --client-package-manager Force an unsupported client package manager --test-frameworks Test frameworks to be generated --base-name Application base name - --skip-jhipster-dependencies Don't write jhipster dependencies to package.json. + --skip-jhipster-dependencies Don't write jhipster dependencies to package.json. (env: JHI_SKIP_JHIPSTER_DEPENDENCIES) --creation-timestamp Project creation timestamp (used for reproducible builds) --jdl-store JDL store + --prettier-tab-width Default tab width for prettier (default: 2) --skip-commit-hook Skip adding husky commit hooks - --prettier-tab-width Default tab width for prettier --db Provide DB name for the application when skipping server side generation - --incremental-changelog Creates incremental database changelogs --recreate-initial-changelog Recreate the initial database changelog based on the current config --cache-provider Cache provider --enable-swagger-codegen API first development using OpenAPI-generator --enable-hibernate-cache Enable hibernate cache - --message-broker message broker --search-engine Provide search engine for the application when skipping server side generation --skip-check-length-of-identifier Skip check the length of the identifier, only for recent Oracle databases that support 30+ characters metadata --skip-db-changelog Skip the generation of database migrations @@ -210,13 +210,17 @@ Options: --reactive Generate a reactive backend --service-discovery-type Service discovery type (choices: "consul", "eureka", "no") --auth Provide authentication type for the application when skipping server side generation (choices: "jwt", "oauth2", "session") - --feign-client Generate a feign client + --feign-client Generate a feign client (default: false) --sync-user-with-idp Allow relationships with User for oauth2 applications + --message-broker message broker (choices: "kafka", "pulsar", "no") + --database-migration Database migration (choices: "liquibase") + --graalvm-support Experimental GraalVM Native support --with-generated-flag Add a GeneratedByJHipster annotation to all generated java classes and interfaces --package-name The package name for the generated application - --build Provide build tool for the application when skipping server side generation (choices: "maven", "gradle") - --enable-gradle-enterprise Enable Gradle Enterprise integration + --build Provide build tool for the application when skipping server side generation (default: maven) (choices: "maven", "gradle") + --enable-gradle-enterprise Enable Gradle Enterprise integration (default: false) --gradle-enterprise-host Gradle Enterprise Host + --incremental-changelog Creates incremental database changelogs --dev-database-type Development database --client-framework Provide client framework for the application (choices: "angular", "react", "vue", "no") --microfrontend Enable microfrontend support diff --git a/generators/jdl/command.ts b/generators/jdl/command.ts index 7468e7ba0c22..e5887da2cc8a 100644 --- a/generators/jdl/command.ts +++ b/generators/jdl/command.ts @@ -1,7 +1,7 @@ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_WORKSPACES } from '../generator-list.js'; -const command: JHipsterCommandDefinition = { +const command = { arguments: { jdlFiles: { type: Array, @@ -44,6 +44,7 @@ const command: JHipsterCommandDefinition = { description: 'Pass JDL content inline. Argument can be skipped when passing this', type: String, scope: 'generator', + env: 'JHI_JDL', }, skipUserManagement: { description: 'Skip the user management module during app generation', @@ -52,6 +53,6 @@ const command: JHipsterCommandDefinition = { }, }, import: [GENERATOR_WORKSPACES], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/jdl/generator.spec.ts b/generators/jdl/generator.spec.ts index b670f2a34b23..b35b5a14d5e1 100644 --- a/generators/jdl/generator.spec.ts +++ b/generators/jdl/generator.spec.ts @@ -18,13 +18,11 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { SinonSpy } from 'sinon'; -import { RunResult } from 'yeoman-test'; import { getCommandHelpOutput, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { defaultHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import * as GENERATORS from '../generator-list.js'; import { GENERATOR_JDL } from '../generator-list.js'; import Generator from './index.js'; @@ -78,10 +76,8 @@ describe(`generator - ${generator}`, () => { }); describe('with valid parameters', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ inline: 'entity Foo {}', db: 'postgresql', baseName: 'jhipster', @@ -89,14 +85,13 @@ describe(`generator - ${generator}`, () => { }); it('should not compose with app', () => { - const mock = runResult.mockedGenerators[MOCKED_APP] as SinonSpy; - expect(mock.callCount).toBe(0); + runResult.assertGeneratorNotComposed(MOCKED_APP); }); it('should compose with entities', () => { - const mock = runResult.mockedGenerators[MOCKED_ENTITIES] as SinonSpy; - expect(mock.callCount).toBe(1); - expect(mock.lastCall.args).toStrictEqual([['Foo'], expect.any(Object)]); + runResult.assertGeneratorComposedOnce(MOCKED_ENTITIES); + const calls = runResult.getGeneratorMock(MOCKED_ENTITIES).calls; + expect(calls[calls.length - 1].arguments).toStrictEqual([['Foo'], expect.any(Object)]); }); it('should write expected files', () => { @@ -107,23 +102,20 @@ describe(`generator - ${generator}`, () => { }); describe('with valid config', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withJHipsterConfig().withMockedGenerators(mockedGenerators).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withJHipsterConfig().withMockedGenerators(mockedGenerators).withOptions({ inline: 'entity Foo {}', }); }); it('should not compose with app', () => { - const mock = runResult.mockedGenerators[MOCKED_APP] as SinonSpy; - expect(mock.callCount).toBe(0); + runResult.assertGeneratorNotComposed(MOCKED_APP); }); it('should compose with entities', () => { - const mock = runResult.mockedGenerators[MOCKED_ENTITIES] as SinonSpy; - expect(mock.callCount).toBe(1); - expect(mock.lastCall.args).toStrictEqual([['Foo'], expect.any(Object)]); + runResult.assertGeneratorComposedOnce(MOCKED_ENTITIES); + const calls = runResult.getGeneratorMock(MOCKED_ENTITIES).calls; + expect(calls[calls.length - 1].arguments).toStrictEqual([['Foo'], expect.any(Object)]); }); it('should write expected files', () => { @@ -136,22 +128,21 @@ describe(`generator - ${generator}`, () => { describe('for application jdl', () => { describe('with valid jdl', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ inline: 'application { }', }); }); it('should not compose with entities', () => { - const mock = runResult.mockedGenerators[MOCKED_ENTITIES] as SinonSpy; - expect(mock.callCount).toBe(0); + runResult.assertGeneratorNotComposed(MOCKED_ENTITIES); }); it('should compose with app', () => { - const mock = runResult.mockedGenerators[MOCKED_APP] as SinonSpy; - expect(mock.callCount).toBe(1); - expect(mock.lastCall.args).toStrictEqual([[], expect.not.objectContaining({ applicationWithEntities: expect.any(Object) })]); + runResult.assertGeneratorComposedOnce(MOCKED_APP); + expect(runResult.getGeneratorMock(MOCKED_APP).calls[0].arguments).toStrictEqual([ + [], + expect.not.objectContaining({ applicationWithEntities: expect.any(Object) }), + ]); }); it('should write expected files', () => { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -159,10 +150,8 @@ describe(`generator - ${generator}`, () => { }); describe('with blueprint jdl with blueprint config', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withOptions({ jsonOnly: true, inline: 'application { config { blueprints [foo, bar] } config(foo) { config fooValue } config(bar) { config barValue } }', }); @@ -200,22 +189,22 @@ describe(`generator - ${generator}`, () => { describe('for one application and entity jdl', () => { describe('with valid jdl', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ inline: 'application { entities Foo } entity Foo {}', }); }); it('should not compose with entities', () => { - const mock = runResult.mockedGenerators[MOCKED_ENTITIES] as SinonSpy; - expect(mock.callCount).toBe(0); + runResult.assertGeneratorNotComposed(MOCKED_ENTITIES); }); it('should compose with app', () => { - const mock = runResult.mockedGenerators[MOCKED_APP] as SinonSpy; - expect(mock.callCount).toBe(1); - expect(mock.lastCall.args).toStrictEqual([[], expect.not.objectContaining({ applicationWithEntities: expect.any(Object) })]); + runResult.assertGeneratorComposedOnce(MOCKED_APP); + const calls = runResult.getGeneratorMock(MOCKED_APP).calls; + expect(calls[calls.length - 1].arguments).toStrictEqual([ + [], + expect.not.objectContaining({ applicationWithEntities: expect.any(Object) }), + ]); }); it('should write expected files', () => { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -223,10 +212,8 @@ describe(`generator - ${generator}`, () => { }); describe('with --ignore-application option', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ ignoreApplication: true, inline: 'application { entities Foo } entity Foo {}', }); @@ -240,26 +227,22 @@ describe(`generator - ${generator}`, () => { describe('for two applications and entity jdl', () => { describe('with valid jdl', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ inline: 'application { entities Foo } entity Foo {} application { config { baseName jhipster2 } entities Bar } entity Bar', }); }); it('should not compose with entities', () => { - const mock = runResult.mockedGenerators[MOCKED_ENTITIES] as SinonSpy; - expect(mock.callCount).toBe(0); + runResult.assertGeneratorNotComposed(MOCKED_ENTITIES); }); it('should not compose with app', () => { - const mock = runResult.mockedGenerators[MOCKED_APP] as SinonSpy; - expect(mock.callCount).toBe(0); + runResult.assertGeneratorNotComposed(MOCKED_APP); }); it('should compose with workspaces', () => { - const mock = runResult.mockedGenerators[MOCKED_WORKSPACES] as SinonSpy; - expect(mock.callCount).toBe(1); - expect(mock.lastCall.args).toStrictEqual([ + runResult.assertGeneratorComposedOnce(MOCKED_WORKSPACES); + const calls = runResult.getGeneratorMock(MOCKED_WORKSPACES).calls; + expect(calls[calls.length - 1].arguments).toStrictEqual([ [], expect.objectContaining({ workspacesFolders: ['jhipster', 'jhipster2'], generateApplications: expect.any(Function) }), ]); @@ -270,27 +253,23 @@ describe(`generator - ${generator}`, () => { }); describe('with --ignore-application option', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withMockedGenerators(mockedGenerators).withOptions({ ignoreApplication: true, inline: 'application { entities Foo } entity Foo {} application { config { baseName jhipster2 } entities Bar } entity Bar', }); }); it('should compose with entities', () => { - const mock = runResult.mockedGenerators[MOCKED_ENTITIES] as SinonSpy; - expect(mock.callCount).toBe(2); - expect(mock.lastCall.args).toStrictEqual([['Bar'], expect.any(Object)]); + expect(runResult.getGeneratorComposeCount(MOCKED_ENTITIES)).toBe(2); + const calls = runResult.getGeneratorMock(MOCKED_ENTITIES).calls; + expect(calls[calls.length - 1].arguments).toStrictEqual([['Bar'], expect.any(Object)]); }); it('should not compose with app', () => { - const mock = runResult.mockedGenerators[MOCKED_APP] as SinonSpy; - expect(mock.callCount).toBe(0); + runResult.assertGeneratorNotComposed(MOCKED_APP); }); it('should not compose with workspaces', () => { - const mock = runResult.mockedGenerators[MOCKED_WORKSPACES] as SinonSpy; - expect(mock.callCount).toBe(0); + runResult.assertGeneratorNotComposed(MOCKED_WORKSPACES); }); it('should write expected files', () => { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -301,10 +280,8 @@ describe(`generator - ${generator}`, () => { describe('--json-only option', () => { describe('for entities only jdl', () => { describe('with valid parameters', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withOptions({ jsonOnly: true, inline: 'entity Foo {}', db: 'postgresql', @@ -320,10 +297,8 @@ describe(`generator - ${generator}`, () => { }); describe('with valid config', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withJHipsterConfig().withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withJHipsterConfig().withOptions({ jsonOnly: true, inline: 'entity Foo {}', }); @@ -339,10 +314,8 @@ describe(`generator - ${generator}`, () => { describe('for application jdl', () => { describe('with valid jdl', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withOptions({ jsonOnly: true, inline: 'application { }', }); @@ -358,10 +331,8 @@ describe(`generator - ${generator}`, () => { describe('for one application and entity jdl', () => { describe('with valid jdl', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withOptions({ jsonOnly: true, inline: 'application { entities Foo } entity Foo {}', }); @@ -376,10 +347,8 @@ describe(`generator - ${generator}`, () => { }); describe('with --ignore-application option', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withOptions({ jsonOnly: true, ignoreApplication: true, inline: 'application { entities Foo } entity Foo {}', @@ -396,10 +365,8 @@ describe(`generator - ${generator}`, () => { describe('for two applications and entity jdl', () => { describe('with valid jdl', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withOptions({ jsonOnly: true, inline: 'application { entities Foo } entity Foo {} application { config { baseName jhipster2 } entities Bar } entity Bar', }); @@ -411,10 +378,8 @@ describe(`generator - ${generator}`, () => { }); describe('with --ignore-application option', () => { - let runResult: RunResult; - before(async () => { - runResult = await helpers.runJHipster(GENERATOR_JDL).withOptions({ + await helpers.runJHipster(GENERATOR_JDL).withOptions({ jsonOnly: true, ignoreApplication: true, inline: 'application { entities Foo } entity Foo {} application { config { baseName jhipster2 } entities Bar } entity Bar', @@ -443,17 +408,14 @@ entity Bar }); it('should not compose with entities', () => { - const mock = runResult.mockedGenerators[MOCKED_ENTITIES] as SinonSpy; - expect(mock.callCount).toBe(0); + runResult.assertGeneratorNotComposed(MOCKED_ENTITIES); }); it('should not compose with app', () => { - const mock = runResult.mockedGenerators[MOCKED_APP] as SinonSpy; - expect(mock.callCount).toBe(0); + runResult.assertGeneratorNotComposed(MOCKED_APP); }); it('should compose with workspaces', () => { - const mock = runResult.mockedGenerators[MOCKED_WORKSPACES] as SinonSpy; - expect(mock.callCount).toBe(1); - expect(mock.lastCall.args).toStrictEqual([ + runResult.assertGeneratorComposedOnce(MOCKED_WORKSPACES); + expect(runResult.getGeneratorMock(MOCKED_WORKSPACES).calls[0].arguments).toStrictEqual([ [], expect.objectContaining({ workspacesFolders: ['gatewayApp', 'jhipster'], generateApplications: expect.any(Function) }), ]); @@ -501,8 +463,7 @@ application { config { baseName gatewayApp applicationType gateway } } }); it('should generate expected config', () => { - const mock = runResult.mockedGenerators['foo:bar'] as SinonSpy; - expect(mock.callCount).toBe(1); + runResult.assertGeneratorComposedOnce('foo:bar'); }); }); }); diff --git a/generators/jdl/generator.ts b/generators/jdl/generator.ts index 14781b951b52..0eb7f1cac601 100644 --- a/generators/jdl/generator.ts +++ b/generators/jdl/generator.ts @@ -18,19 +18,19 @@ */ import { extname } from 'path'; import { readFile } from 'fs/promises'; -import { QueuedAdapter } from '@yeoman/adapter'; import { upperFirst } from 'lodash-es'; -import { create as createMemFs, type Store as MemFs } from 'mem-fs'; -import { create as createMemFsEditor, type MemFsEditor } from 'mem-fs-editor'; +import { type Store as MemFs, create as createMemFs } from 'mem-fs'; +import { type MemFsEditor, create as createMemFsEditor } from 'mem-fs-editor'; import BaseGenerator from '../base/index.js'; import { downloadJdlFile } from '../../cli/download.mjs'; import EnvironmentBuilder from '../../cli/environment-builder.mjs'; import { CLI_NAME } from '../../cli/utils.mjs'; import { GENERATOR_APP, GENERATOR_ENTITIES, GENERATOR_WORKSPACES } from '../generator-list.js'; -import { ApplicationWithEntities, createImporterFromContent } from '../../jdl/jdl-importer.js'; +import type { ApplicationWithEntities } from '../../lib/jdl/jdl-importer.js'; +import { createImporterFromContent } from '../../lib/jdl/jdl-importer.js'; import { GENERATOR_JHIPSTER, JHIPSTER_CONFIG_DIR } from '../generator-constants.js'; -import { mergeYoRcContent } from '../../jdl/index.js'; +import { mergeYoRcContent } from '../../lib/utils/yo-rc.js'; import { normalizeBlueprintName } from '../base/internal/blueprint.js'; import { updateApplicationEntitiesTransform } from '../base-application/support/update-application-entities-transform.js'; import { addApplicationIndex, allNewApplications, customizeForMicroservices } from './internal/index.js'; @@ -134,7 +134,7 @@ export default class JdlGenerator extends BaseGenerator { skipUserManagement: this.options.skipUserManagement, }; - const importer = createImporterFromContent(this.jdlContents.join('\n'), configuration); + const importer = createImporterFromContent(this.jdlContents.join('\n'), configuration, this.options.jdlDefinition); const importState = importer.import(); @@ -270,7 +270,7 @@ export default class JdlGenerator extends BaseGenerator { applications.map(async application => { const rootCwd = this.destinationPath(); const cwd = application.folder ? this.destinationPath(application.folder) : rootCwd; - const adapter = (this.env.adapter as QueuedAdapter).newAdapter(); + const adapter = this.env.adapter.newAdapter(); const envOptions: any = { cwd, logCwd: rootCwd, sharedFs: application.sharedFs, adapter }; const generatorOptions = { ...this.options, ...options, skipPriorities: ['prompting'] }; diff --git a/generators/jdl/internal/application.ts b/generators/jdl/internal/application.ts index 711f7352ad29..da281ccf9e38 100644 --- a/generators/jdl/internal/application.ts +++ b/generators/jdl/internal/application.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ApplicationWithEntities } from '../../../jdl/jdl-importer.js'; +import type { ApplicationWithEntities } from '../../../lib/jdl/jdl-importer.js'; export const addApplicationIndex = (applicationsWithEntities: ApplicationWithEntities[]) => { applicationsWithEntities.forEach((applicationWithEntities, applicationIndex) => { diff --git a/generators/jdl/internal/utils.js b/generators/jdl/internal/utils.ts similarity index 89% rename from generators/jdl/internal/utils.js rename to generators/jdl/internal/utils.ts index e75f5261cbf6..86837eed1a02 100644 --- a/generators/jdl/internal/utils.js +++ b/generators/jdl/internal/utils.ts @@ -24,7 +24,8 @@ import { join } from 'path'; * @param {string} baseName * @return {boolean} */ -export const baseNameConfigExists = baseName => existsSync(baseName === undefined ? '.yo-rc.json' : join(baseName, '.yo-rc.json')); +export const baseNameConfigExists = (baseName?: string) => + existsSync(baseName === undefined ? '.yo-rc.json' : join(baseName, '.yo-rc.json')); /** * Check if every application is new. diff --git a/generators/kubernetes-helm/__snapshots__/kubernetes.helm.spec.ts.snap b/generators/kubernetes-helm/__snapshots__/kubernetes.helm.spec.ts.snap index 9237accfc49c..a048b2ee1231 100644 --- a/generators/kubernetes-helm/__snapshots__/kubernetes.helm.spec.ts.snap +++ b/generators/kubernetes-helm/__snapshots__/kubernetes.helm.spec.ts.snap @@ -5,7 +5,9 @@ exports[`generator - Kubernetes Helm Kafka application should match files snapsh ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["09-kafka"], + "appsFolders": [ + "09-kafka" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "monolith", @@ -42,16 +44,15 @@ To use the templates generated by this sub-generator \`helm cli and tiller\` sho at [https://github.com/helm/helm](https://github.com/helm/helm) Once Helm is installed you need to add the below repositories: - \`\`\` helm repo add stable https://charts.helm.sh/stable helm repo add incubator https://charts.helm.sh/incubator \`\`\` - These repositories should be added to the local cache, because this sub-generator will pull some charts from them. This repository in turn uses the \`kubernetes\` sub-generator for the microservices manifests and few service like database, Elasticsearch, Prometheus etc. that are referred from the above repositories. + ## Deployment You can deploy all your applications by running the following bash command: @@ -72,8 +73,8 @@ For Kubernetes specific information, refer to the \`kubernetes\` sub-generator R ### Backlogs to be covered -- helm upgrade - to be tested -- Istio - to be tested +* helm upgrade - to be tested +* Istio - to be tested ", "stateCleared": "modified", }, @@ -287,71 +288,71 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 samplekafka-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 samplekafka-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: samplekafka-app - image: jhipster/samplekafka - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://samplekafka-mysql.default.svc.cluster.local:3306/samplekafka?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://samplekafka-mysql.default.svc.cluster.local:3306/samplekafka?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: KAFKA_CONSUMER_KEY_DESERIALIZER - value: "org.apache.kafka.common.serialization.StringDeserializer" - - name: KAFKA_CONSUMER_VALUE_DESERIALIZER - value: "org.apache.kafka.common.serialization.StringDeserializer" - - name: KAFKA_CONSUMER_BOOTSTRAP_SERVERS - value: "jhipster-kafka.default.svc.cluster.local:9092" - - name: KAFKA_CONSUMER_GROUP_ID - value: "samplekafka" - - name: KAFKA_CONSUMER_AUTO_OFFSET_RESET - value: "earliest" - - name: KAFKA_PRODUCER_BOOTSTRAP_SERVERS - value: "jhipster-kafka.default.svc.cluster.local:9092" - - name: KAFKA_PRODUCER_KEY_DESERIALIZER - value: "org.apache.kafka.common.serialization.StringDeserializer" - - name: KAFKA_PRODUCER_VALUE_DESERIALIZER - value: "org.apache.kafka.common.serialization.StringDeserializer" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: samplekafka-app + image: jhipster/samplekafka + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://samplekafka-mysql.default.svc.cluster.local:3306/samplekafka?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://samplekafka-mysql.default.svc.cluster.local:3306/samplekafka?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: KAFKA_CONSUMER_KEY_DESERIALIZER + value: 'org.apache.kafka.common.serialization.StringDeserializer' + - name: KAFKA_CONSUMER_VALUE_DESERIALIZER + value: 'org.apache.kafka.common.serialization.StringDeserializer' + - name: KAFKA_CONSUMER_BOOTSTRAP_SERVERS + value: 'jhipster-kafka.default.svc.cluster.local:9092' + - name: KAFKA_CONSUMER_GROUP_ID + value: 'samplekafka' + - name: KAFKA_CONSUMER_AUTO_OFFSET_RESET + value: 'earliest' + - name: KAFKA_PRODUCER_BOOTSTRAP_SERVERS + value: 'jhipster-kafka.default.svc.cluster.local:9092' + - name: KAFKA_PRODUCER_KEY_DESERIALIZER + value: 'org.apache.kafka.common.serialization.StringDeserializer' + - name: KAFKA_PRODUCER_VALUE_DESERIALIZER + value: 'org.apache.kafka.common.serialization.StringDeserializer' + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -368,9 +369,9 @@ spec: app: samplekafka type: LoadBalancer ports: - - name: http - port: 80 - targetPort: 8080 + - name: http + port: 80 + targetPort: 8080 ", "stateCleared": "modified", }, @@ -393,7 +394,10 @@ exports[`generator - Kubernetes Helm MySQL and PostgreSQL microservices without ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql", "03-psql"], + "appsFolders": [ + "02-mysql", + "03-psql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -433,16 +437,15 @@ To use the templates generated by this sub-generator \`helm cli and tiller\` sho at [https://github.com/helm/helm](https://github.com/helm/helm) Once Helm is installed you need to add the below repositories: - \`\`\` helm repo add stable https://charts.helm.sh/stable helm repo add incubator https://charts.helm.sh/incubator \`\`\` - These repositories should be added to the local cache, because this sub-generator will pull some charts from them. This repository in turn uses the \`kubernetes\` sub-generator for the microservices manifests and few service like database, Elasticsearch, Prometheus etc. that are referred from the above repositories. + ## Deployment You can deploy all your applications by running the following bash command: @@ -463,8 +466,8 @@ For Kubernetes specific information, refer to the \`kubernetes\` sub-generator R ### Backlogs to be covered -- helm upgrade - to be tested -- Istio - to be tested +* helm upgrade - to be tested +* Istio - to be tested ", "stateCleared": "modified", }, @@ -539,23 +542,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -939,61 +942,61 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -1009,8 +1012,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -1109,70 +1112,70 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 mspsql-postgresql 5432) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 mspsql-postgresql 5432) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: mspsql-app - image: jhipster/mspsql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_DATASOURCE_USERNAME - value: mspsql - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - - name: SPRING_LIQUIBASE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: mspsql-app + image: jhipster/mspsql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_DATASOURCE_USERNAME + value: mspsql + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + - name: SPRING_LIQUIBASE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -1195,40 +1198,40 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -1239,12 +1242,12 @@ spec: selector: app: mspsql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -1260,8 +1263,8 @@ spec: selector: app: mspsql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -1281,7 +1284,9 @@ exports[`generator - Kubernetes Helm gateway and ingress should match files snap ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -1319,16 +1324,15 @@ To use the templates generated by this sub-generator \`helm cli and tiller\` sho at [https://github.com/helm/helm](https://github.com/helm/helm) Once Helm is installed you need to add the below repositories: - \`\`\` helm repo add stable https://charts.helm.sh/stable helm repo add incubator https://charts.helm.sh/incubator \`\`\` - These repositories should be added to the local cache, because this sub-generator will pull some charts from them. This repository in turn uses the \`kubernetes\` sub-generator for the microservices manifests and few service like database, Elasticsearch, Prometheus etc. that are referred from the above repositories. + ## Deployment You can deploy all your applications by running the following bash command: @@ -1349,8 +1353,8 @@ For Kubernetes specific information, refer to the \`kubernetes\` sub-generator R ### Backlogs to be covered -- helm upgrade - to be tested -- Istio - to be tested +* helm upgrade - to be tested +* Istio - to be tested ", "stateCleared": "modified", }, @@ -1425,23 +1429,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -1812,63 +1816,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -1880,16 +1884,16 @@ metadata: namespace: default spec: rules: - - host: jhgate.default.example.com - http: - paths: - - path: /* - pathType: ImplementationSpecific - backend: - service: - name: jhgate - port: - name: http + - host: jhgate.default.example.com + http: + paths: + - path: /* + pathType: ImplementationSpecific + backend: + service: + name: jhgate + port: + name: http ", "stateCleared": "modified", }, @@ -1906,8 +1910,8 @@ spec: app: jhgate type: NodePort ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -1930,7 +1934,10 @@ exports[`generator - Kubernetes Helm gateway and mysql microservice should match ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway", "02-mysql"], + "appsFolders": [ + "01-gateway", + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -1970,16 +1977,15 @@ To use the templates generated by this sub-generator \`helm cli and tiller\` sho at [https://github.com/helm/helm](https://github.com/helm/helm) Once Helm is installed you need to add the below repositories: - \`\`\` helm repo add stable https://charts.helm.sh/stable helm repo add incubator https://charts.helm.sh/incubator \`\`\` - These repositories should be added to the local cache, because this sub-generator will pull some charts from them. This repository in turn uses the \`kubernetes\` sub-generator for the microservices manifests and few service like database, Elasticsearch, Prometheus etc. that are referred from the above repositories. + ## Deployment You can deploy all your applications by running the following bash command: @@ -2000,8 +2006,8 @@ For Kubernetes specific information, refer to the \`kubernetes\` sub-generator R ### Backlogs to be covered -- helm upgrade - to be tested -- Istio - to be tested +* helm upgrade - to be tested +* Istio - to be tested ", "stateCleared": "modified", }, @@ -2076,23 +2082,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -2476,63 +2482,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -2549,8 +2555,8 @@ spec: app: jhgate type: LoadBalancer ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -2649,61 +2655,61 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -2719,8 +2725,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -2743,7 +2749,9 @@ exports[`generator - Kubernetes Helm gateway with istio should match files snaps ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -2781,16 +2789,15 @@ To use the templates generated by this sub-generator \`helm cli and tiller\` sho at [https://github.com/helm/helm](https://github.com/helm/helm) Once Helm is installed you need to add the below repositories: - \`\`\` helm repo add stable https://charts.helm.sh/stable helm repo add incubator https://charts.helm.sh/incubator \`\`\` - These repositories should be added to the local cache, because this sub-generator will pull some charts from them. This repository in turn uses the \`kubernetes\` sub-generator for the microservices manifests and few service like database, Elasticsearch, Prometheus etc. that are referred from the above repositories. + ## Deployment You can deploy all your applications by running the following bash command: @@ -2811,8 +2818,8 @@ For Kubernetes specific information, refer to the \`kubernetes\` sub-generator R ### Backlogs to be covered -- helm upgrade - to be tested -- Istio - to be tested +* helm upgrade - to be tested +* Istio - to be tested ", "stateCleared": "modified", }, @@ -2887,23 +2894,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -3148,18 +3155,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -3168,16 +3175,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system.example.com + - grafana.istio-system.example.com gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -3194,18 +3201,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -3214,9 +3221,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system.example.com + - kiali.istio-system.example.com gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -3239,18 +3246,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -3259,16 +3266,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system.example.com + - zipkin.istio-system.example.com gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -3414,69 +3421,69 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -3505,9 +3512,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -3527,18 +3534,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.default.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.default.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.default.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.default.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -3549,13 +3556,13 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.default.example.com + - jhgate.default.example.com gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate + - route: + - destination: + host: jhgate ", "stateCleared": "modified", }, @@ -3570,10 +3577,10 @@ metadata: spec: selector: app: jhgate - type: + type: ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -3585,16 +3592,16 @@ metadata: namespace: default spec: hosts: - - jhgate + - jhgate http: - - route: - - destination: - host: jhgate - subset: "v1" - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate + subset: "v1" + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -3672,16 +3679,15 @@ To use the templates generated by this sub-generator \`helm cli and tiller\` sho at [https://github.com/helm/helm](https://github.com/helm/helm) Once Helm is installed you need to add the below repositories: - \`\`\` helm repo add stable https://charts.helm.sh/stable helm repo add incubator https://charts.helm.sh/incubator \`\`\` - These repositories should be added to the local cache, because this sub-generator will pull some charts from them. This repository in turn uses the \`kubernetes\` sub-generator for the microservices manifests and few service like database, Elasticsearch, Prometheus etc. that are referred from the above repositories. + ## Deployment You can deploy all your applications by running the following bash command: @@ -3702,8 +3708,8 @@ For Kubernetes specific information, refer to the \`kubernetes\` sub-generator R ### Backlogs to be covered -- helm upgrade - to be tested -- Istio - to be tested +* helm upgrade - to be tested +* Istio - to be tested ", "stateCleared": "modified", }, @@ -3778,23 +3784,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -4217,63 +4223,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -4290,8 +4296,8 @@ spec: app: jhgate type: LoadBalancer ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -4390,66 +4396,66 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmariadb-mariadb 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmariadb-mariadb 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmariadb-app - image: jhipster/msmariadb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false - - name: SPRING_LIQUIBASE_URL - value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: msmariadb-mariadb - key: mariadb-root-password - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmariadb-app + image: jhipster/msmariadb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false + - name: SPRING_LIQUIBASE_URL + value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: msmariadb-mariadb + key: mariadb-root-password + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -4465,8 +4471,8 @@ spec: selector: app: msmariadb ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -4564,59 +4570,59 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmongodb-mongodb 27017) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmongodb-mongodb 27017) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmongodb-app - image: jhipster/msmongodb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATA_MONGODB_URI - value: "mongodb://msmongodb-mongodb-0.msmongodb-mongodb.default:27017/msmongodb" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmongodb-app + image: jhipster/msmongodb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATA_MONGODB_URI + value: "mongodb://msmongodb-mongodb-0.msmongodb-mongodb.default:27017/msmongodb" + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -4632,8 +4638,8 @@ spec: selector: app: msmongodb ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -4729,61 +4735,61 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -4799,8 +4805,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -4899,70 +4905,70 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 mspsql-postgresql 5432) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 mspsql-postgresql 5432) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: mspsql-app - image: jhipster/mspsql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_DATASOURCE_USERNAME - value: mspsql - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - - name: SPRING_LIQUIBASE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: mspsql-app + image: jhipster/mspsql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_DATASOURCE_USERNAME + value: mspsql + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + - name: SPRING_LIQUIBASE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -4985,40 +4991,40 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -5029,12 +5035,12 @@ spec: selector: app: mspsql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -5050,8 +5056,8 @@ spec: selector: app: mspsql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -5071,7 +5077,9 @@ exports[`generator - Kubernetes Helm monolith application should match files sna ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["08-monolith"], + "appsFolders": [ + "08-monolith" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "monolith", @@ -5108,16 +5116,15 @@ To use the templates generated by this sub-generator \`helm cli and tiller\` sho at [https://github.com/helm/helm](https://github.com/helm/helm) Once Helm is installed you need to add the below repositories: - \`\`\` helm repo add stable https://charts.helm.sh/stable helm repo add incubator https://charts.helm.sh/incubator \`\`\` - These repositories should be added to the local cache, because this sub-generator will pull some charts from them. This repository in turn uses the \`kubernetes\` sub-generator for the microservices manifests and few service like database, Elasticsearch, Prometheus etc. that are referred from the above repositories. + ## Deployment You can deploy all your applications by running the following bash command: @@ -5138,8 +5145,8 @@ For Kubernetes specific information, refer to the \`kubernetes\` sub-generator R ### Backlogs to be covered -- helm upgrade - to be tested -- Istio - to be tested +* helm upgrade - to be tested +* Istio - to be tested ", "stateCleared": "modified", }, @@ -5280,57 +5287,57 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 samplemysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 samplemysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: samplemysql-app - image: jhipster/samplemysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://samplemysql-mysql.default.svc.cluster.local:3306/samplemysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://samplemysql-mysql.default.svc.cluster.local:3306/samplemysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://samplemysql-elasticsearch.default.svc.cluster.local:9200 - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: samplemysql-app + image: jhipster/samplemysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://samplemysql-mysql.default.svc.cluster.local:3306/samplemysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://samplemysql-mysql.default.svc.cluster.local:3306/samplemysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://samplemysql-elasticsearch.default.svc.cluster.local:9200 + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -5353,40 +5360,40 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -5397,12 +5404,12 @@ spec: selector: app: samplemysql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -5419,9 +5426,9 @@ spec: app: samplemysql type: LoadBalancer ports: - - name: http - port: 80 - targetPort: 8080 + - name: http + port: 80 + targetPort: 8080 ", "stateCleared": "modified", }, @@ -5444,7 +5451,9 @@ exports[`generator - Kubernetes Helm mysql microservice with custom namespace an ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql"], + "appsFolders": [ + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -5482,16 +5491,15 @@ To use the templates generated by this sub-generator \`helm cli and tiller\` sho at [https://github.com/helm/helm](https://github.com/helm/helm) Once Helm is installed you need to add the below repositories: - \`\`\` helm repo add stable https://charts.helm.sh/stable helm repo add incubator https://charts.helm.sh/incubator \`\`\` - These repositories should be added to the local cache, because this sub-generator will pull some charts from them. This repository in turn uses the \`kubernetes\` sub-generator for the microservices manifests and few service like database, Elasticsearch, Prometheus etc. that are referred from the above repositories. + ## Deployment You can deploy all your applications by running the following bash command: @@ -5512,8 +5520,8 @@ For Kubernetes specific information, refer to the \`kubernetes\` sub-generator R ### Backlogs to be covered -- helm upgrade - to be tested -- Istio - to be tested +* helm upgrade - to be tested +* Istio - to be tested ", "stateCleared": "modified", }, @@ -5638,23 +5646,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.mynamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.mynamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -8321,63 +8329,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.mynamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED - value: "true" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.mynamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED + value: 'true' + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -8393,8 +8401,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -8414,6 +8422,7 @@ spec: kind: Namespace metadata: name: mynamespace + ", "stateCleared": "modified", }, @@ -8425,7 +8434,9 @@ exports[`generator - Kubernetes Helm mysql microservice with custom namespace sh ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql"], + "appsFolders": [ + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -8463,16 +8474,15 @@ To use the templates generated by this sub-generator \`helm cli and tiller\` sho at [https://github.com/helm/helm](https://github.com/helm/helm) Once Helm is installed you need to add the below repositories: - \`\`\` helm repo add stable https://charts.helm.sh/stable helm repo add incubator https://charts.helm.sh/incubator \`\`\` - These repositories should be added to the local cache, because this sub-generator will pull some charts from them. This repository in turn uses the \`kubernetes\` sub-generator for the microservices manifests and few service like database, Elasticsearch, Prometheus etc. that are referred from the above repositories. + ## Deployment You can deploy all your applications by running the following bash command: @@ -8493,8 +8503,8 @@ For Kubernetes specific information, refer to the \`kubernetes\` sub-generator R ### Backlogs to be covered -- helm upgrade - to be tested -- Istio - to be tested +* helm upgrade - to be tested +* Istio - to be tested ", "stateCleared": "modified", }, @@ -8569,23 +8579,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.mynamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.mynamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -8957,61 +8967,61 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.mynamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.mynamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -9027,8 +9037,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -9048,6 +9058,7 @@ spec: kind: Namespace metadata: name: mynamespace + ", "stateCleared": "modified", }, @@ -9059,7 +9070,9 @@ exports[`generator - Kubernetes Helm only gateway should match files snapshot 1` ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -9097,16 +9110,15 @@ To use the templates generated by this sub-generator \`helm cli and tiller\` sho at [https://github.com/helm/helm](https://github.com/helm/helm) Once Helm is installed you need to add the below repositories: - \`\`\` helm repo add stable https://charts.helm.sh/stable helm repo add incubator https://charts.helm.sh/incubator \`\`\` - These repositories should be added to the local cache, because this sub-generator will pull some charts from them. This repository in turn uses the \`kubernetes\` sub-generator for the microservices manifests and few service like database, Elasticsearch, Prometheus etc. that are referred from the above repositories. + ## Deployment You can deploy all your applications by running the following bash command: @@ -9127,8 +9139,8 @@ For Kubernetes specific information, refer to the \`kubernetes\` sub-generator R ### Backlogs to be covered -- helm upgrade - to be tested -- Istio - to be tested +* helm upgrade - to be tested +* Istio - to be tested ", "stateCleared": "modified", }, @@ -9203,23 +9215,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.jhipsternamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.jhipsternamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -9591,63 +9603,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipsterrepository/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.jhipsternamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipsterrepository/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.jhipsternamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -9664,8 +9676,8 @@ spec: app: jhgate type: LoadBalancer ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -9685,6 +9697,7 @@ spec: kind: Namespace metadata: name: jhipsternamespace + ", "stateCleared": "modified", }, diff --git a/generators/kubernetes-helm/files.js b/generators/kubernetes-helm/files.ts similarity index 99% rename from generators/kubernetes-helm/files.js rename to generators/kubernetes-helm/files.ts index 8a397235cdf9..d629a4cf4638 100644 --- a/generators/kubernetes-helm/files.js +++ b/generators/kubernetes-helm/files.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -23,7 +24,7 @@ import { monitoringTypes, searchEngineTypes, serviceDiscoveryTypes, -} from '../../jdl/jhipster/index.js'; +} from '../../lib/jhipster/index.js'; const { ELASTICSEARCH } = searchEngineTypes; const { GATEWAY, MONOLITH } = applicationTypes; diff --git a/generators/docker-compose/generator.spec.js b/generators/kubernetes-helm/generator.spec.ts similarity index 96% rename from generators/docker-compose/generator.spec.js rename to generators/kubernetes-helm/generator.spec.ts index b25895cf89f4..d90bf385002d 100644 --- a/generators/docker-compose/generator.spec.js +++ b/generators/kubernetes-helm/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures } from '../../test/support/tests.js'; diff --git a/generators/kubernetes-helm/generator.js b/generators/kubernetes-helm/generator.ts similarity index 94% rename from generators/kubernetes-helm/generator.js rename to generators/kubernetes-helm/generator.ts index 3fc4c6915b91..76cdbab45bfa 100644 --- a/generators/kubernetes-helm/generator.js +++ b/generators/kubernetes-helm/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,23 +17,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return, import/no-named-as-default-member */ + import fs from 'fs'; import chalk from 'chalk'; import BaseWorkspacesGenerator from '../base-workspaces/index.js'; import prompts from '../kubernetes/prompts.js'; -import { checkImages, generateJwtSecret, configureImageNames, loadFromYoRc } from '../base-workspaces/internal/docker-base.js'; +import { checkImages, configureImageNames, generateJwtSecret, loadFromYoRc } from '../base-workspaces/internal/docker-base.js'; import { - checkKubernetes, checkHelm, + checkKubernetes, + derivedKubernetesPlatformProperties, loadConfig, - setupKubernetesConstants, setupHelmConstants, - derivedKubernetesPlatformProperties, + setupKubernetesConstants, } from '../kubernetes/kubernetes-base.js'; -import { messageBrokerTypes } from '../../jdl/jhipster/index.js'; +import { messageBrokerTypes } from '../../lib/jhipster/index.js'; import { getJdbcUrl, getR2dbcUrl } from '../spring-data-relational/support/index.js'; import { loadDeploymentConfig, loadDockerDependenciesTask } from '../base-workspaces/internal/index.js'; import { checkDocker } from '../docker/support/index.js'; @@ -113,10 +114,10 @@ export default class KubernetesHelmGenerator extends BaseWorkspacesGenerator { return { loadFromYoRc, loadSharedConfig() { - this.appConfigs.forEach(element => { - loadDerivedAppConfig({ application: element }); - loadDerivedServerConfig({ application: element }); - }); + for (const app of this.appConfigs) { + loadDerivedAppConfig({ application: app }); + loadDerivedServerConfig({ application: app }); + } loadDeploymentConfig.call(this); derivedKubernetesPlatformProperties(this); }, @@ -133,6 +134,7 @@ export default class KubernetesHelmGenerator extends BaseWorkspacesGenerator { setPostPromptProp() { this.appConfigs.forEach(element => { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions element.clusteredDb ? (element.dbPeerCount = 3) : (element.dbPeerCount = 1); if (element.messageBroker === KAFKA) { this.useKafka = true; @@ -185,7 +187,7 @@ export default class KubernetesHelmGenerator extends BaseWorkspacesGenerator { try { fs.chmodSync('helm-apply.sh', '755'); fs.chmodSync('helm-upgrade.sh', '755'); - } catch (err) { + } catch { this.log.warn( "Failed to make 'helm-apply.sh', 'helm-upgrade.sh' executable, you may need to run 'chmod +x helm-apply.sh helm-upgrade.sh", ); diff --git a/generators/kubernetes-helm/index.ts b/generators/kubernetes-helm/index.ts index 58ac334eafae..870818641c5d 100644 --- a/generators/kubernetes-helm/index.ts +++ b/generators/kubernetes-helm/index.ts @@ -16,4 +16,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +export { default as command } from '../kubernetes/command.js'; export { default } from './generator.js'; diff --git a/generators/kubernetes-helm/kubernetes.helm.spec.ts b/generators/kubernetes-helm/kubernetes.helm.spec.ts index ffd54128d57e..f53d1f7cc228 100644 --- a/generators/kubernetes-helm/kubernetes.helm.spec.ts +++ b/generators/kubernetes-helm/kubernetes.helm.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe, expect } from 'esmocha'; -import { basicHelpers as helpers, getGenerator } from '../../testing/index.js'; +import { before, describe, expect, it } from 'esmocha'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { GENERATOR_KUBERNETES_HELM } from '../generator-list.js'; const expectedFiles = { @@ -72,17 +72,16 @@ const expectedFiles = { describe('generator - Kubernetes Helm', () => { describe('only gateway', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_HELM)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_HELM) .withOptions({ askAnswered: true, }) @@ -97,8 +96,7 @@ describe('generator - Kubernetes Helm', () => { jhipsterConsole: false, kubernetesServiceType: 'LoadBalancer', clusteredDbApps: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -117,17 +115,16 @@ describe('generator - Kubernetes Helm', () => { }); describe('gateway and mysql microservice', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway', '02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_HELM)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_HELM) .withOptions({ askAnswered: true, }) @@ -141,8 +138,7 @@ describe('generator - Kubernetes Helm', () => { jhipsterConsole: false, kubernetesServiceType: 'LoadBalancer', clusteredDbApps: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -164,17 +160,16 @@ describe('generator - Kubernetes Helm', () => { }); describe('mysql microservice with custom namespace', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_HELM)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_HELM) .withOptions({ askAnswered: true, }) @@ -188,8 +183,7 @@ describe('generator - Kubernetes Helm', () => { jhipsterConsole: true, kubernetesServiceType: 'LoadBalancer', clusteredDbApps: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -211,17 +205,16 @@ describe('generator - Kubernetes Helm', () => { }); describe('gateway and ingress', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_HELM)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_HELM) .withOptions({ askAnswered: true, }) @@ -237,8 +230,7 @@ describe('generator - Kubernetes Helm', () => { ingressType: 'gke', ingressDomain: 'example.com', clusteredDbApps: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -263,17 +255,16 @@ describe('generator - Kubernetes Helm', () => { }); describe('MySQL and PostgreSQL microservices without gateway', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql', '03-psql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_HELM)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_HELM) .withOptions({ askAnswered: true, }) @@ -287,8 +278,7 @@ describe('generator - Kubernetes Helm', () => { jhipsterConsole: false, kubernetesServiceType: 'LoadBalancer', clusteredDbApps: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -315,17 +305,16 @@ describe('generator - Kubernetes Helm', () => { }); describe('gateway, mysql, psql, mongodb, mariadb microservices', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway', '02-mysql', '03-psql', '04-mongo', '07-mariadb']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_HELM)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_HELM) .withOptions({ askAnswered: true, }) @@ -340,8 +329,7 @@ describe('generator - Kubernetes Helm', () => { kubernetesServiceType: 'LoadBalancer', clusteredDbApps: [], istio: false, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -376,17 +364,16 @@ describe('generator - Kubernetes Helm', () => { }); describe('monolith application', () => { - let runResult; before(async () => { const chosenApps = ['08-monolith']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces() .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_HELM)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_HELM) .withOptions({ askAnswered: true, }) @@ -400,8 +387,7 @@ describe('generator - Kubernetes Helm', () => { jhipsterConsole: false, kubernetesServiceType: 'LoadBalancer', clusteredDbApps: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -419,17 +405,16 @@ describe('generator - Kubernetes Helm', () => { }); describe('Kafka application', () => { - let runResult; before(async () => { const chosenApps = ['09-kafka']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces() .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_HELM)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_HELM) .withOptions({ askAnswered: true, }) @@ -443,8 +428,7 @@ describe('generator - Kubernetes Helm', () => { jhipsterConsole: false, kubernetesServiceType: 'LoadBalancer', clusteredDbApps: [], - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -461,17 +445,16 @@ describe('generator - Kubernetes Helm', () => { }); describe('mysql microservice with custom namespace and jhipster prometheus monitoring', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_HELM)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_HELM) .withOptions({ askAnswered: true, }) @@ -484,8 +467,7 @@ describe('generator - Kubernetes Helm', () => { kubernetesNamespace: 'mynamespace', monitoring: 'prometheus', kubernetesServiceType: 'LoadBalancer', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -511,17 +493,16 @@ describe('generator - Kubernetes Helm', () => { }); describe('gateway with istio', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_HELM)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_HELM) .withOptions({ askAnswered: true, }) @@ -535,8 +516,7 @@ describe('generator - Kubernetes Helm', () => { ingressDomain: 'example.com', clusteredDbApps: [], istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); diff --git a/generators/kubernetes-knative/__snapshots__/knative.spec.ts.snap b/generators/kubernetes-knative/__snapshots__/knative.spec.ts.snap index a7b6e298eecd..33a6acdd62dd 100644 --- a/generators/kubernetes-knative/__snapshots__/knative.spec.ts.snap +++ b/generators/kubernetes-knative/__snapshots__/knative.spec.ts.snap @@ -5,7 +5,10 @@ exports[`generator - Knative Using Helm generator type MySQL and PostgreSQL micr ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql", "03-psql"], + "appsFolders": [ + "02-mysql", + "03-psql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -27,10 +30,10 @@ exports[`generator - Knative Using Helm generator type MySQL and PostgreSQL micr ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag msmysql jhipster/msmysql @@ -38,13 +41,11 @@ $ docker push jhipster/msmysql $ docker image tag mspsql jhipster/mspsql $ docker push jhipster/mspsql \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash helm-knative-apply.sh (or) ./helm-knative-apply.sh \`\`\` @@ -132,23 +133,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -393,18 +394,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -413,16 +414,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -439,18 +440,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -459,9 +460,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -484,18 +485,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -504,16 +505,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -659,9 +660,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -690,50 +691,50 @@ spec: version: "v1" spec: containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmysql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmysql - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmysql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmysql + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -749,23 +750,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmysql-knative + - msmysql-knative http: - - route: - - destination: - host: msmysql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmysql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmysql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmysql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -857,9 +858,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -884,40 +885,40 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -928,12 +929,12 @@ spec: selector: app: mspsql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -962,59 +963,59 @@ spec: version: "v1" spec: containers: - - name: mspsql-app - image: jhipster/mspsql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: mspsql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: mspsql - - name: SPRING_DATASOURCE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_DATASOURCE_USERNAME - value: mspsql - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: mspsql-app + image: jhipster/mspsql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: mspsql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: mspsql + - name: SPRING_DATASOURCE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_DATASOURCE_USERNAME + value: mspsql + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -1030,23 +1031,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - mspsql-knative + - mspsql-knative http: - - route: - - destination: - host: mspsql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: mspsql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: mspsql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: mspsql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -1072,7 +1073,9 @@ exports[`generator - Knative Using Helm generator type gateway and ingress shoul ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -1094,22 +1097,20 @@ exports[`generator - Knative Using Helm generator type gateway and ingress shoul ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag jhgate jhipster/jhgate $ docker push jhipster/jhgate \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash helm-knative-apply.sh (or) ./helm-knative-apply.sh \`\`\` @@ -1197,23 +1198,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -1458,18 +1459,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -1478,16 +1479,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system.example.com + - grafana.istio-system.example.com gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -1504,18 +1505,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -1524,9 +1525,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system.example.com + - kiali.istio-system.example.com gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -1549,18 +1550,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -1569,16 +1570,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system.example.com + - zipkin.istio-system.example.com gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -1711,9 +1712,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -1733,18 +1734,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.default.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.default.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.default.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.default.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -1755,18 +1756,18 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.default.example.com + - jhgate.default.example.com gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate-knative - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative + - route: + - destination: + host: jhgate-knative + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative ", "stateCleared": "modified", }, @@ -1795,50 +1796,50 @@ spec: version: "v1" spec: containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -1854,23 +1855,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - jhgate-knative + - jhgate-knative http: - - route: - - destination: - host: jhgate-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -1895,7 +1896,10 @@ exports[`generator - Knative Using Helm generator type gateway and mysql microse ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway", "02-mysql"], + "appsFolders": [ + "01-gateway", + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -1917,10 +1921,10 @@ exports[`generator - Knative Using Helm generator type gateway and mysql microse ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag jhgate jhipster/jhgate @@ -1928,13 +1932,11 @@ $ docker push jhipster/jhgate $ docker image tag msmysql jhipster/msmysql $ docker push jhipster/msmysql \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash helm-knative-apply.sh (or) ./helm-knative-apply.sh \`\`\` @@ -2022,23 +2024,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -2283,18 +2285,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -2303,16 +2305,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -2329,18 +2331,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -2349,9 +2351,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -2374,18 +2376,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -2394,16 +2396,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -2549,9 +2551,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -2571,18 +2573,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.default. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.default. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.default. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.default. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -2593,18 +2595,18 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.default. + - jhgate.default. gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate-knative - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative + - route: + - destination: + host: jhgate-knative + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative ", "stateCleared": "modified", }, @@ -2633,50 +2635,50 @@ spec: version: "v1" spec: containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -2692,23 +2694,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - jhgate-knative + - jhgate-knative http: - - route: - - destination: - host: jhgate-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -2800,9 +2802,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -2831,50 +2833,50 @@ spec: version: "v1" spec: containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmysql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmysql - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmysql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmysql + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -2890,23 +2892,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmysql-knative + - msmysql-knative http: - - route: - - destination: - host: msmysql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmysql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmysql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmysql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -2931,7 +2933,9 @@ exports[`generator - Knative Using Helm generator type gateway with istio routin ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -2953,22 +2957,20 @@ exports[`generator - Knative Using Helm generator type gateway with istio routin ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag jhgate jhipster/jhgate $ docker push jhipster/jhgate \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash helm-knative-apply.sh (or) ./helm-knative-apply.sh \`\`\` @@ -3056,23 +3058,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -3317,18 +3319,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -3337,16 +3339,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system.example.com + - grafana.istio-system.example.com gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -3363,18 +3365,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -3383,9 +3385,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system.example.com + - kiali.istio-system.example.com gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -3408,18 +3410,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -3428,16 +3430,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system.example.com + - zipkin.istio-system.example.com gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -3570,9 +3572,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -3592,18 +3594,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.default.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.default.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.default.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.default.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -3614,18 +3616,18 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.default.example.com + - jhgate.default.example.com gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate-knative - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative + - route: + - destination: + host: jhgate-knative + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative ", "stateCleared": "modified", }, @@ -3654,50 +3656,50 @@ spec: version: "v1" spec: containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -3713,23 +3715,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - jhgate-knative + - jhgate-knative http: - - route: - - destination: - host: jhgate-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -3783,10 +3785,10 @@ exports[`generator - Knative Using Helm generator type gateway, mysql, psql, mon ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag jhgate jhipster/jhgate @@ -3800,13 +3802,11 @@ $ docker push jhipster/msmongodb $ docker image tag msmariadb jhipster/msmariadb $ docker push jhipster/msmariadb \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash helm-knative-apply.sh (or) ./helm-knative-apply.sh \`\`\` @@ -3894,23 +3894,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -4155,18 +4155,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -4175,16 +4175,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -4201,18 +4201,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -4221,9 +4221,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -4246,18 +4246,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -4266,16 +4266,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -4460,9 +4460,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -4482,18 +4482,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.default. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.default. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.default. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.default. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -4504,18 +4504,18 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.default. + - jhgate.default. gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate-knative - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative + - route: + - destination: + host: jhgate-knative + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative ", "stateCleared": "modified", }, @@ -4544,50 +4544,50 @@ spec: version: "v1" spec: containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -4603,23 +4603,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - jhgate-knative + - jhgate-knative http: - - route: - - destination: - host: jhgate-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -4711,9 +4711,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -4742,55 +4742,55 @@ spec: version: "v1" spec: containers: - - name: msmariadb-app - image: jhipster/msmariadb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmariadb - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmariadb - - name: SPRING_DATASOURCE_URL - value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: msmariadb-mariadb - key: mariadb-root-password - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmariadb-app + image: jhipster/msmariadb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmariadb + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmariadb + - name: SPRING_DATASOURCE_URL + value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: msmariadb-mariadb + key: mariadb-root-password + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -4806,23 +4806,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmariadb-knative + - msmariadb-knative http: - - route: - - destination: - host: msmariadb-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmariadb-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmariadb-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmariadb-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -4917,9 +4917,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -4948,50 +4948,50 @@ spec: version: "v1" spec: containers: - - name: msmongodb-app - image: jhipster/msmongodb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmongodb - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmongodb - - name: SPRING_DATA_MONGODB_URI - value: "mongodb://msmongodb-mongodb-0.msmongodb-mongodb.default:27017/msmongodb" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmongodb-app + image: jhipster/msmongodb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmongodb + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmongodb + - name: SPRING_DATA_MONGODB_URI + value: "mongodb://msmongodb-mongodb-0.msmongodb-mongodb.default:27017/msmongodb" + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -5007,23 +5007,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmongodb-knative + - msmongodb-knative http: - - route: - - destination: - host: msmongodb-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmongodb-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmongodb-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmongodb-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -5112,9 +5112,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -5143,50 +5143,50 @@ spec: version: "v1" spec: containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmysql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmysql - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmysql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmysql + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -5202,23 +5202,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmysql-knative + - msmysql-knative http: - - route: - - destination: - host: msmysql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmysql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmysql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmysql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -5310,9 +5310,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -5337,40 +5337,40 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -5381,12 +5381,12 @@ spec: selector: app: mspsql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -5415,59 +5415,59 @@ spec: version: "v1" spec: containers: - - name: mspsql-app - image: jhipster/mspsql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: mspsql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: mspsql - - name: SPRING_DATASOURCE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_DATASOURCE_USERNAME - value: mspsql - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: mspsql-app + image: jhipster/mspsql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: mspsql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: mspsql + - name: SPRING_DATASOURCE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_DATASOURCE_USERNAME + value: mspsql + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -5483,23 +5483,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - mspsql-knative + - mspsql-knative http: - - route: - - destination: - host: mspsql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: mspsql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: mspsql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: mspsql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -5525,7 +5525,9 @@ exports[`generator - Knative Using Helm generator type mysql microservice with c ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql"], + "appsFolders": [ + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -5547,22 +5549,20 @@ exports[`generator - Knative Using Helm generator type mysql microservice with c ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag msmysql jhipster/msmysql $ docker push jhipster/msmysql \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash helm-knative-apply.sh (or) ./helm-knative-apply.sh \`\`\` @@ -5700,23 +5700,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.mynamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.mynamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -5961,18 +5961,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -5981,16 +5981,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -6007,18 +6007,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhipster-grafana.mynamespace. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhipster-grafana.mynamespace. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhipster-grafana.mynamespace. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhipster-grafana.mynamespace. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -6027,16 +6027,16 @@ metadata: namespace: mynamespace spec: hosts: - - jhipster-grafana.mynamespace. + - jhipster-grafana.mynamespace. gateways: - - jhipster-grafana-gateway + - jhipster-grafana-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: jhipster-grafana + - match: + - uri: + prefix: / + route: + - destination: + host: jhipster-grafana ", "stateCleared": "modified", }, @@ -6053,18 +6053,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -6073,9 +6073,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -6098,18 +6098,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -6118,16 +6118,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -6153,2284 +6153,2284 @@ grafana: datasources.yaml: apiVersion: 1 datasources: - - name: prometheus - type: prometheus - url: http://jhipster-prometheus:9090 - access: proxy - isDefault: true - basicAuth: false + - name: prometheus + type: prometheus + url: http://jhipster-prometheus:9090 + access: proxy + isDefault: true + basicAuth: false dashboardProviders: dashboardproviders.yaml: apiVersion: 1 providers: - - name: "prometheus" - orgId: 1 - folder: "" - type: file - disableDeletion: false - editable: true - options: - path: /var/lib/grafana/dashboards/prometheus + - name: 'prometheus' + orgId: 1 + folder: '' + type: file + disableDeletion: false + editable: true + options: + path: /var/lib/grafana/dashboards/prometheus dashboards: prometheus: prometheus-dashboard: json: |- - { - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "5.0.4" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "5.0.0" - }, - { - "type": "panel", - "id": "singlestat", - "name": "Singlestat", - "version": "" - } - ], - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "description": "JHipster metrics", - "editable": true, - "gnetId": 3308, - "graphTooltip": 0, - "hideControls": false, - "id": null, - "links": [], - "refresh": false, - "rows": [ - { - "collapse": false, - "height": "250px", - "panels": [ - { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "datasource": "prometheus", - "decimals": null, - "description": "Service status", - "format": "none", - "gauge": { - "maxValue": 1, - "minValue": 0, - "show": true, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "height": "", - "id": 1, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "100%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "span": 4, - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false - }, - "tableColumn": "Value", - "targets": [ - { - "expr": "up{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "table", - "intervalFactor": 2, - "refId": "A", - "step": 20, - "metric": "up", - "legendFormat": "service" - } - ], - "thresholds": "0", - "title": "Service Status Now", - "type": "singlestat", - "valueFontSize": "120%", - "valueMaps": [ - { - "op": "=", - "text": "Down", - "value": "0" - }, - { - "value": "1", - "op": "=", - "text": "Up" - } - ], - "valueName": "current", - "hideTimeOverride": false, - "minSpan": null, - "repeat": null, - "transparent": false - }, - { - "id": 29, - "title": "Service Uptime", - "span": 8, - "type": "graph", - "targets": [ - { - "refId": "A", - "expr": "up{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "step": 2, - "legendFormat": "{{pod}}" - } - ], - "datasource": "prometheus", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": "0", - "max": "1", - "format": "short" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": "0", - "max": "1", - "format": "short" - } - ], - "xaxis": { - "show": true, - "mode": "time", - "name": null, - "values": [], - "buckets": null - }, - "lines": true, - "fill": 1, - "linewidth": 1, - "dashes": false, - "dashLength": 10, - "spaceLength": 10, - "points": true, - "pointradius": 3, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": false, - "min": false, - "max": false, - "current": false, - "total": false, - "avg": false, - "alignAsTable": true - }, - "nullPointMode": "null", - "steppedLine": true, - "tooltip": { - "value_type": "individual", - "shared": true, - "sort": 0 - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "thresholds": [], - "links": [], - "description": "The uptime of the service" - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Uptime Metrics", - "titleSize": "h6" - }, - { - "collapse": false, - "height": 250, - "panels": [ - { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": true, - "colors": [ - "rgba(32, 176, 9, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "datasource": "prometheus", - "description": "Total requests count", - "format": "none", - "gauge": { - "maxValue": 10000000000000, - "minValue": 0, - "show": true, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "id": 5, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "span": 3, - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false - }, - "tableColumn": "Value", - "targets": [ - { - "expr": "com_codahale_metrics_servlet_InstrumentedFilter_requests_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "table", - "intervalFactor": 2, - "refId": "A", - "step": 20, - "metric": "com_codahale_metrics_servlet_InstrumentedFilter_requests_count" - } - ], - "thresholds": "", - "title": "Total Requests", - "type": "singlestat", - "valueFontSize": "70%", - "valueMaps": [ - { - "op": "=", - "text": "N/A", - "value": "null" - } - ], - "valueName": "total", - "transparent": false - }, - { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "datasource": "prometheus", - "description": "Number of 200 OK requests", - "format": "none", - "gauge": { - "maxValue": 10000000000000000, - "minValue": 0, - "show": true, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "id": 6, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "span": 3, - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.78)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": true - }, - "tableColumn": "Value", - "targets": [ - { - "expr": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_ok_total{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "table", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A", - "step": 20, - "metric": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_ok_total" - } - ], - "thresholds": "", - "title": "Total Successful hits", - "type": "singlestat", - "valueFontSize": "80%", - "valueMaps": [ - { - "op": "=", - "text": "N/A", - "value": "null" - } - ], - "valueName": "total" - }, - { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "datasource": "prometheus", - "description": "Number of server errors and bad requests", - "format": "none", - "gauge": { - "maxValue": 1, - "minValue": 0, - "show": true, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "id": 7, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "span": 3, - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false - }, - "tableColumn": "Value", - "targets": [ - { - "expr": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_serverError_total{namespace =\\"$namespace\\", service =\\"$service_name\\"} + com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_badRequest_total{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 20, - "metric": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_serverError_total" - } - ], - "thresholds": "1", - "title": "Total Bad hits", - "type": "singlestat", - "valueFontSize": "70%", - "valueMaps": [ - { - "op": "=", - "text": "N/A", - "value": "null" - } - ], - "valueName": "total" - }, - { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "datasource": "prometheus", - "description": "Number of 404 not found requests", - "format": "none", - "gauge": { - "maxValue": 1, - "minValue": 0, - "show": true, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "id": 8, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "span": 3, - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false - }, - "tableColumn": "", - "targets": [ - { - "expr": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_notFound_total{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 20, - "metric": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_notFound_total" - } - ], - "thresholds": "1", - "title": "Trace 404 hits", - "type": "singlestat", - "valueFontSize": "80%", - "valueMaps": [ - { - "op": "=", - "text": "N/A", - "value": "null" - } - ], - "valueName": "total" - }, - { - "id": 30, - "title": "Active Requests", - "span": 12, - "type": "graph", - "targets": [ - { - "refId": "A", - "expr": "com_codahale_metrics_servlet_InstrumentedFilter_activeRequests{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "metric": "com_codahale_metrics_servlet_InstrumentedFilter_activeRequests", - "step": 2, - "legendFormat": "{{service}}" - } - ], - "datasource": "prometheus", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true, - "mode": "time", - "name": null, - "values": [ - "total" - ], - "buckets": null - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "dashes": false, - "dashLength": 10, - "spaceLength": 10, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": true, - "max": true, - "current": true, - "total": false, - "avg": true, - "alignAsTable": true - }, - "nullPointMode": "null", - "steppedLine": false, - "tooltip": { - "value_type": "individual", - "shared": false, - "sort": 0 - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "thresholds": [], - "links": [] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Requests Metrics", - "titleSize": "h6" - }, - { - "collapse": false, - "height": 250, - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "The current number of live threads including daemon and non-daemon and runnable threads", - "fill": 4, - "id": 10, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true, - "rightSide": false, - "hideEmpty": false - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": true, - "targets": [ - { - "expr": "jvm_threads_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Total threads", - "refId": "A", - "step": 4, - "metric": "jvm_threads_count" - }, - { - "expr": "jvm_threads_daemon_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "B", - "metric": "jvm_threads_daemon_count", - "step": 4, - "legendFormat": "Daemon threads" - }, - { - "expr": "jvm_threads_runnable_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "C", - "metric": "jvm_threads_runnable_count", - "step": 4, - "legendFormat": "Runnable threads" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Live Threads", - "tooltip": { - "shared": false, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ - "total" - ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ], - "transparent": false - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "The current number of blocked and deadlock threads", - "fill": 1, - "id": 11, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_threads_blocked_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Blocked threads", - "refId": "A", - "step": 4, - "metric": "jvm_threads_blocked_count" - }, - { - "expr": "jvm_threads_deadlock_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "B", - "metric": "jvm_threads_deadlock_count", - "step": 4, - "legendFormat": "Deadlock threads" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Blocked and Deadlock Threads", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "The current number of waiting threads", - "fill": 1, - "id": 12, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_threads_waiting_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Waiting threads", - "refId": "A", - "step": 4, - "metric": "jvm_threads_waiting_count" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Waiting Threads", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Thread Metrics", - "titleSize": "h6" - }, - { - "collapse": false, - "height": 250, - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "An estimate of the number of buffers in the pool", - "fill": 1, - "id": 13, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_buffers_direct_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{service}}", - "refId": "A", - "step": 4, - "metric": "jvm_buffers_direct_count" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Buffer Count", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "An estimate of the memory that the Java virtual machine is using for this buffer pool", - "fill": 1, - "id": 14, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_buffers_direct_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{service}}", - "refId": "A", - "step": 4, - "metric": "jvm_buffers_direct_used" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Buffer Mem Used", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "An estimate of the total capacity of the buffers in this pool", - "fill": 1, - "id": 15, - "legend": { - "alignAsTable": true, - "avg": false, - "current": true, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_buffers_direct_capacity{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{service}}", - "refId": "A", - "step": 4, - "metric": "jvm_buffers_direct_capacity" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Buffer Capacity", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "The total amount of heap memory", - "fill": 1, - "id": 18, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_memory_heap_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Used", - "refId": "A", - "step": 4, - "metric": "jvm_memory_heap_used" - }, - { - "expr": "jvm_memory_heap_max{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "B", - "metric": "jvm_memory_heap_max", - "step": 4, - "legendFormat": "Maximum" - }, - { - "expr": "jvm_memory_heap_committed{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "C", - "metric": "jvm_memory_heap_committed", - "step": 4, - "legendFormat": "Committed" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Heap Memory", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "The amount of used, committed and max memory", - "fill": 1, - "id": 16, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_memory_total_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Used", - "refId": "A", - "step": 4, - "metric": "jvm_memory_total_used" - }, - { - "expr": "jvm_memory_total_max{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "B", - "metric": "jvm_memory_total_max", - "step": 4, - "legendFormat": "Max" - }, - { - "expr": "jvm_memory_total_committed{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "C", - "metric": "jvm_memory_total_committed", - "step": 4, - "legendFormat": "Committed" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Total Memory", - "tooltip": { - "shared": false, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ - "total" - ] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "The total amount of non heap memory", - "fill": 1, - "id": 17, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_memory_non_heap_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Non Heap Used", - "refId": "A", - "step": 4, - "metric": "jvm_memory_non_heap_used" - }, - { - "expr": "jvm_memory_non_heap_committed{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "B", - "metric": "jvm_memory_non_heap_max", - "step": 4, - "legendFormat": "Non Heap Committed" - }, - { - "expr": "jvm_memory_pools_Metaspace_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "C", - "metric": "jvm_memory_pools_Metaspace_used", - "step": 4, - "legendFormat": "Metaspace Used" - }, - { - "expr": "jvm_memory_pools_Code_Cache_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "D", - "metric": "jvm_memory_pools_Code_Cache_used", - "step": 4, - "legendFormat": "Code Cache Used" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Other Memory", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Memory Metrics", - "titleSize": "h6" - }, - { - "collapse": false, - "height": 250, - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "Memory space of new generation", - "fill": 2, - "id": 19, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 6, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_memory_pools_PS_Eden_Space_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Used", - "refId": "A", - "step": 2, - "metric": "jvm_memory_pools_PS_Eden_Space_used" - }, - { - "expr": "jvm_memory_pools_PS_Eden_Space_max{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "B", - "metric": "jvm_memory_pools_PS_Eden_Space_max", - "step": 2, - "legendFormat": "Max" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Eden Space", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "Memory space of new generation", - "fill": 1, - "id": 20, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 6, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_memory_pools_PS_Survivor_Space_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Used", - "refId": "A", - "step": 2, - "metric": "jvm_memory_pools_PS_Old_Gen_used" - }, - { - "expr": "jvm_memory_pools_PS_Survivor_Space_max{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "B", - "metric": "", - "step": 2, - "legendFormat": "Max" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Survivor Space", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "Memory space of old generation", - "fill": 1, - "id": 24, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 12, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_memory_pools_PS_Old_Gen_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Used", - "refId": "A", - "step": 2, - "metric": "jvm_memory_pools_PS_Old_Gen_used" - }, - { - "expr": "jvm_memory_pools_PS_Old_Gen_max{namespace =\\"$namespace\\", service =\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "refId": "B", - "step": 2, - "legendFormat": "Max" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Old Generation", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "s", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Memory Space Metrics", - "titleSize": "h6" - }, - { - "collapse": false, - "height": 250, - "panels": [ - { - "id": 31, - "title": "Cache Hits", - "span": 6, - "type": "graph", - "targets": [ - { - "refId": "A", - "expr": "{__name__=~\\"^jcache_statistics.*cache_hits\\", namespace=\\"$namespace\\", service=\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "step": 2, - "legendFormat": "{{__name__}}" - } - ], - "datasource": "prometheus", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": "0", - "max": null, - "format": "none" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": "0", - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true, - "mode": "time", - "name": null, - "values": [ - "total" - ], - "buckets": null - }, - "lines": true, - "fill": 1, - "linewidth": 1, - "dashes": false, - "dashLength": 10, - "spaceLength": 10, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": true, - "max": true, - "current": true, - "total": true, - "avg": true, - "alignAsTable": true - }, - "nullPointMode": "null", - "steppedLine": false, - "tooltip": { - "value_type": "individual", - "shared": false, - "sort": 0 - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "thresholds": [], - "links": [], - "description": "The total number of cache hits" - }, - { - "id": 32, - "title": "Cache Misses", - "span": 6, - "type": "graph", - "targets": [ - { - "refId": "A", - "expr": "{__name__=~\\"^jcache_statistics.*cache_misses\\", namespace=\\"$namespace\\", service=\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "step": 2, - "legendFormat": "{{__name__}}" - } - ], - "datasource": "prometheus", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": "0", - "max": null, - "format": "short" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": "0", - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true, - "mode": "time", - "name": null, - "values": [], - "buckets": null - }, - "lines": true, - "fill": 1, - "linewidth": 1, - "dashes": false, - "dashLength": 10, - "spaceLength": 10, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": true, - "max": true, - "current": true, - "total": true, - "avg": true, - "alignAsTable": true - }, - "nullPointMode": "null", - "steppedLine": false, - "tooltip": { - "value_type": "individual", - "shared": true, - "sort": 0 - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "thresholds": [], - "links": [], - "description": "The total number of cache misses" - }, - { - "id": 33, - "title": "Cache Gets", - "span": 6, - "type": "graph", - "targets": [ - { - "refId": "A", - "expr": "{__name__=~\\"^jcache_statistics.*cache_gets\\", namespace=\\"$namespace\\", service=\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "step": 2, - "legendFormat": "{{__name__}}" - } - ], - "datasource": "prometheus", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": "0", - "max": null, - "format": "short" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": "0", - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true, - "mode": "time", - "name": null, - "values": [], - "buckets": null - }, - "lines": true, - "fill": 1, - "linewidth": 1, - "dashes": false, - "dashLength": 10, - "spaceLength": 10, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": true, - "max": true, - "current": true, - "total": true, - "avg": true, - "alignAsTable": true - }, - "nullPointMode": "null", - "steppedLine": false, - "tooltip": { - "value_type": "individual", - "shared": true, - "sort": 0 - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "thresholds": [], - "links": [], - "description": "The total number of cache gets" - }, - { - "id": 34, - "title": "Cache Puts", - "span": 6, - "type": "graph", - "targets": [ - { - "refId": "A", - "expr": "{__name__=~\\"^jcache_statistics.*cache_puts\\", namespace=\\"$namespace\\", service=\\"$service_name\\"}", - "intervalFactor": 2, - "format": "time_series", - "step": 2, - "legendFormat": "{{__name__}}" - } - ], - "datasource": "prometheus", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": "0", - "max": null, - "format": "short" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": "0", - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true, - "mode": "time", - "name": null, - "values": [], - "buckets": null - }, - "lines": true, - "fill": 1, - "linewidth": 1, - "dashes": false, - "dashLength": 10, - "spaceLength": 10, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": true, - "max": true, - "current": true, - "total": true, - "avg": true, - "alignAsTable": true - }, - "nullPointMode": "null", - "steppedLine": false, - "tooltip": { - "value_type": "individual", - "shared": true, - "sort": 0 - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "thresholds": [], - "links": [], - "description": "The total number of cache puts" - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Cache Metrics", - "titleSize": "h6" - }, - { - "collapse": false, - "height": 250, - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "prometheus", - "description": "Count of REST requests", - "fill": 1, - "id": 27, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 12, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "{__name__=~\\".*rest.*_count\\", namespace=\\"$namespace\\", service=\\"$service_name\\"} ", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{__name__}}", - "refId": "A", - "step": 2 - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "REST Requests Metrics", - "tooltip": { - "shared": false, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ - "total" - ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ], - "decimals": 0 - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "REST Metrics", - "titleSize": "h6" - } - ], - "schemaVersion": 14, - "style": "dark", - "tags": [ - "java", - "jhipster", - "spring-boot" - ], - "templating": { - "list": [ - { - "allValue": null, - "current": {}, - "datasource": "prometheus", - "hide": 0, - "includeAll": false, - "label": "Namespace", - "multi": false, - "name": "namespace", - "options": [], - "query": "label_values(jvm_files, namespace)", - "refresh": 2, - "regex": "", - "sort": 1, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allValue": null, - "current": {}, - "datasource": "prometheus", - "hide": 0, - "includeAll": false, - "label": "Service Name", - "multi": false, - "name": "service_name", - "options": [], - "query": "label_values(jvm_files, service)", - "refresh": 2, - "regex": "", - "sort": 1, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-15m", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "", - "title": "JHipster Metrics", - "version": 3 - } + { + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.4" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "JHipster metrics", + "editable": true, + "gnetId": 3308, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [], + "refresh": false, + "rows": [ + { + "collapse": false, + "height": "250px", + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "prometheus", + "decimals": null, + "description": "Service status", + "format": "none", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "", + "id": 1, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 4, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "Value", + "targets": [ + { + "expr": "up{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "table", + "intervalFactor": 2, + "refId": "A", + "step": 20, + "metric": "up", + "legendFormat": "service" + } + ], + "thresholds": "0", + "title": "Service Status Now", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "Down", + "value": "0" + }, + { + "value": "1", + "op": "=", + "text": "Up" + } + ], + "valueName": "current", + "hideTimeOverride": false, + "minSpan": null, + "repeat": null, + "transparent": false + }, + { + "id": 29, + "title": "Service Uptime", + "span": 8, + "type": "graph", + "targets": [ + { + "refId": "A", + "expr": "up{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "step": 2, + "legendFormat": "{{pod}}" + } + ], + "datasource": "prometheus", + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": "0", + "max": "1", + "format": "short" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": "0", + "max": "1", + "format": "short" + } + ], + "xaxis": { + "show": true, + "mode": "time", + "name": null, + "values": [], + "buckets": null + }, + "lines": true, + "fill": 1, + "linewidth": 1, + "dashes": false, + "dashLength": 10, + "spaceLength": 10, + "points": true, + "pointradius": 3, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": false, + "min": false, + "max": false, + "current": false, + "total": false, + "avg": false, + "alignAsTable": true + }, + "nullPointMode": "null", + "steppedLine": true, + "tooltip": { + "value_type": "individual", + "shared": true, + "sort": 0 + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "thresholds": [], + "links": [], + "description": "The uptime of the service" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Uptime Metrics", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "rgba(32, 176, 9, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "prometheus", + "description": "Total requests count", + "format": "none", + "gauge": { + "maxValue": 10000000000000, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "Value", + "targets": [ + { + "expr": "com_codahale_metrics_servlet_InstrumentedFilter_requests_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "table", + "intervalFactor": 2, + "refId": "A", + "step": 20, + "metric": "com_codahale_metrics_servlet_InstrumentedFilter_requests_count" + } + ], + "thresholds": "", + "title": "Total Requests", + "type": "singlestat", + "valueFontSize": "70%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "total", + "transparent": false + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "prometheus", + "description": "Number of 200 OK requests", + "format": "none", + "gauge": { + "maxValue": 10000000000000000, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 6, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.78)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "Value", + "targets": [ + { + "expr": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_ok_total{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "table", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 20, + "metric": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_ok_total" + } + ], + "thresholds": "", + "title": "Total Successful hits", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "total" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "prometheus", + "description": "Number of server errors and bad requests", + "format": "none", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 7, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "Value", + "targets": [ + { + "expr": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_serverError_total{namespace =\\"$namespace\\", service =\\"$service_name\\"} + com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_badRequest_total{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "refId": "A", + "step": 20, + "metric": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_serverError_total" + } + ], + "thresholds": "1", + "title": "Total Bad hits", + "type": "singlestat", + "valueFontSize": "70%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "total" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "prometheus", + "description": "Number of 404 not found requests", + "format": "none", + "gauge": { + "maxValue": 1, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 8, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_notFound_total{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "refId": "A", + "step": 20, + "metric": "com_codahale_metrics_servlet_InstrumentedFilter_responseCodes_notFound_total" + } + ], + "thresholds": "1", + "title": "Trace 404 hits", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "total" + }, + { + "id": 30, + "title": "Active Requests", + "span": 12, + "type": "graph", + "targets": [ + { + "refId": "A", + "expr": "com_codahale_metrics_servlet_InstrumentedFilter_activeRequests{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "metric": "com_codahale_metrics_servlet_InstrumentedFilter_activeRequests", + "step": 2, + "legendFormat": "{{service}}" + } + ], + "datasource": "prometheus", + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + } + ], + "xaxis": { + "show": true, + "mode": "time", + "name": null, + "values": [ + "total" + ], + "buckets": null + }, + "lines": true, + "fill": 1, + "linewidth": 2, + "dashes": false, + "dashLength": 10, + "spaceLength": 10, + "points": false, + "pointradius": 5, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": true, + "min": true, + "max": true, + "current": true, + "total": false, + "avg": true, + "alignAsTable": true + }, + "nullPointMode": "null", + "steppedLine": false, + "tooltip": { + "value_type": "individual", + "shared": false, + "sort": 0 + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "thresholds": [], + "links": [] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Requests Metrics", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "The current number of live threads including daemon and non-daemon and runnable threads", + "fill": 4, + "id": 10, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true, + "rightSide": false, + "hideEmpty": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "jvm_threads_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total threads", + "refId": "A", + "step": 4, + "metric": "jvm_threads_count" + }, + { + "expr": "jvm_threads_daemon_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "B", + "metric": "jvm_threads_daemon_count", + "step": 4, + "legendFormat": "Daemon threads" + }, + { + "expr": "jvm_threads_runnable_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "C", + "metric": "jvm_threads_runnable_count", + "step": 4, + "legendFormat": "Runnable threads" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Live Threads", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "transparent": false + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "The current number of blocked and deadlock threads", + "fill": 1, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_threads_blocked_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Blocked threads", + "refId": "A", + "step": 4, + "metric": "jvm_threads_blocked_count" + }, + { + "expr": "jvm_threads_deadlock_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "B", + "metric": "jvm_threads_deadlock_count", + "step": 4, + "legendFormat": "Deadlock threads" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Blocked and Deadlock Threads", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "The current number of waiting threads", + "fill": 1, + "id": 12, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_threads_waiting_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Waiting threads", + "refId": "A", + "step": 4, + "metric": "jvm_threads_waiting_count" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Waiting Threads", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Thread Metrics", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "An estimate of the number of buffers in the pool", + "fill": 1, + "id": 13, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_buffers_direct_count{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{service}}", + "refId": "A", + "step": 4, + "metric": "jvm_buffers_direct_count" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Buffer Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "An estimate of the memory that the Java virtual machine is using for this buffer pool", + "fill": 1, + "id": 14, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_buffers_direct_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{service}}", + "refId": "A", + "step": 4, + "metric": "jvm_buffers_direct_used" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Buffer Mem Used", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "An estimate of the total capacity of the buffers in this pool", + "fill": 1, + "id": 15, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_buffers_direct_capacity{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{service}}", + "refId": "A", + "step": 4, + "metric": "jvm_buffers_direct_capacity" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Buffer Capacity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "The total amount of heap memory", + "fill": 1, + "id": 18, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_memory_heap_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Used", + "refId": "A", + "step": 4, + "metric": "jvm_memory_heap_used" + }, + { + "expr": "jvm_memory_heap_max{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "B", + "metric": "jvm_memory_heap_max", + "step": 4, + "legendFormat": "Maximum" + }, + { + "expr": "jvm_memory_heap_committed{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "C", + "metric": "jvm_memory_heap_committed", + "step": 4, + "legendFormat": "Committed" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Heap Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "The amount of used, committed and max memory", + "fill": 1, + "id": 16, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_memory_total_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Used", + "refId": "A", + "step": 4, + "metric": "jvm_memory_total_used" + }, + { + "expr": "jvm_memory_total_max{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "B", + "metric": "jvm_memory_total_max", + "step": 4, + "legendFormat": "Max" + }, + { + "expr": "jvm_memory_total_committed{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "C", + "metric": "jvm_memory_total_committed", + "step": 4, + "legendFormat": "Committed" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Total Memory", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "The total amount of non heap memory", + "fill": 1, + "id": 17, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_memory_non_heap_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Non Heap Used", + "refId": "A", + "step": 4, + "metric": "jvm_memory_non_heap_used" + }, + { + "expr": "jvm_memory_non_heap_committed{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "B", + "metric": "jvm_memory_non_heap_max", + "step": 4, + "legendFormat": "Non Heap Committed" + }, + { + "expr": "jvm_memory_pools_Metaspace_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "C", + "metric": "jvm_memory_pools_Metaspace_used", + "step": 4, + "legendFormat": "Metaspace Used" + }, + { + "expr": "jvm_memory_pools_Code_Cache_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "D", + "metric": "jvm_memory_pools_Code_Cache_used", + "step": 4, + "legendFormat": "Code Cache Used" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Other Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Metrics", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "Memory space of new generation", + "fill": 2, + "id": 19, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_memory_pools_PS_Eden_Space_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Used", + "refId": "A", + "step": 2, + "metric": "jvm_memory_pools_PS_Eden_Space_used" + }, + { + "expr": "jvm_memory_pools_PS_Eden_Space_max{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "B", + "metric": "jvm_memory_pools_PS_Eden_Space_max", + "step": 2, + "legendFormat": "Max" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Eden Space", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "Memory space of new generation", + "fill": 1, + "id": 20, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_memory_pools_PS_Survivor_Space_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Used", + "refId": "A", + "step": 2, + "metric": "jvm_memory_pools_PS_Old_Gen_used" + }, + { + "expr": "jvm_memory_pools_PS_Survivor_Space_max{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "B", + "metric": "", + "step": 2, + "legendFormat": "Max" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Survivor Space", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "Memory space of old generation", + "fill": 1, + "id": 24, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_memory_pools_PS_Old_Gen_used{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Used", + "refId": "A", + "step": 2, + "metric": "jvm_memory_pools_PS_Old_Gen_used" + }, + { + "expr": "jvm_memory_pools_PS_Old_Gen_max{namespace =\\"$namespace\\", service =\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "refId": "B", + "step": 2, + "legendFormat": "Max" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Old Generation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Space Metrics", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "id": 31, + "title": "Cache Hits", + "span": 6, + "type": "graph", + "targets": [ + { + "refId": "A", + "expr": "{__name__=~\\"^jcache_statistics.*cache_hits\\", namespace=\\"$namespace\\", service=\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "step": 2, + "legendFormat": "{{__name__}}" + } + ], + "datasource": "prometheus", + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": "0", + "max": null, + "format": "none" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": "0", + "max": null, + "format": "short" + } + ], + "xaxis": { + "show": true, + "mode": "time", + "name": null, + "values": [ + "total" + ], + "buckets": null + }, + "lines": true, + "fill": 1, + "linewidth": 1, + "dashes": false, + "dashLength": 10, + "spaceLength": 10, + "points": false, + "pointradius": 5, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": true, + "min": true, + "max": true, + "current": true, + "total": true, + "avg": true, + "alignAsTable": true + }, + "nullPointMode": "null", + "steppedLine": false, + "tooltip": { + "value_type": "individual", + "shared": false, + "sort": 0 + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "thresholds": [], + "links": [], + "description": "The total number of cache hits" + }, + { + "id": 32, + "title": "Cache Misses", + "span": 6, + "type": "graph", + "targets": [ + { + "refId": "A", + "expr": "{__name__=~\\"^jcache_statistics.*cache_misses\\", namespace=\\"$namespace\\", service=\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "step": 2, + "legendFormat": "{{__name__}}" + } + ], + "datasource": "prometheus", + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": "0", + "max": null, + "format": "short" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": "0", + "max": null, + "format": "short" + } + ], + "xaxis": { + "show": true, + "mode": "time", + "name": null, + "values": [], + "buckets": null + }, + "lines": true, + "fill": 1, + "linewidth": 1, + "dashes": false, + "dashLength": 10, + "spaceLength": 10, + "points": false, + "pointradius": 5, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": true, + "min": true, + "max": true, + "current": true, + "total": true, + "avg": true, + "alignAsTable": true + }, + "nullPointMode": "null", + "steppedLine": false, + "tooltip": { + "value_type": "individual", + "shared": true, + "sort": 0 + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "thresholds": [], + "links": [], + "description": "The total number of cache misses" + }, + { + "id": 33, + "title": "Cache Gets", + "span": 6, + "type": "graph", + "targets": [ + { + "refId": "A", + "expr": "{__name__=~\\"^jcache_statistics.*cache_gets\\", namespace=\\"$namespace\\", service=\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "step": 2, + "legendFormat": "{{__name__}}" + } + ], + "datasource": "prometheus", + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": "0", + "max": null, + "format": "short" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": "0", + "max": null, + "format": "short" + } + ], + "xaxis": { + "show": true, + "mode": "time", + "name": null, + "values": [], + "buckets": null + }, + "lines": true, + "fill": 1, + "linewidth": 1, + "dashes": false, + "dashLength": 10, + "spaceLength": 10, + "points": false, + "pointradius": 5, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": true, + "min": true, + "max": true, + "current": true, + "total": true, + "avg": true, + "alignAsTable": true + }, + "nullPointMode": "null", + "steppedLine": false, + "tooltip": { + "value_type": "individual", + "shared": true, + "sort": 0 + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "thresholds": [], + "links": [], + "description": "The total number of cache gets" + }, + { + "id": 34, + "title": "Cache Puts", + "span": 6, + "type": "graph", + "targets": [ + { + "refId": "A", + "expr": "{__name__=~\\"^jcache_statistics.*cache_puts\\", namespace=\\"$namespace\\", service=\\"$service_name\\"}", + "intervalFactor": 2, + "format": "time_series", + "step": 2, + "legendFormat": "{{__name__}}" + } + ], + "datasource": "prometheus", + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": "0", + "max": null, + "format": "short" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": "0", + "max": null, + "format": "short" + } + ], + "xaxis": { + "show": true, + "mode": "time", + "name": null, + "values": [], + "buckets": null + }, + "lines": true, + "fill": 1, + "linewidth": 1, + "dashes": false, + "dashLength": 10, + "spaceLength": 10, + "points": false, + "pointradius": 5, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": true, + "min": true, + "max": true, + "current": true, + "total": true, + "avg": true, + "alignAsTable": true + }, + "nullPointMode": "null", + "steppedLine": false, + "tooltip": { + "value_type": "individual", + "shared": true, + "sort": 0 + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "thresholds": [], + "links": [], + "description": "The total number of cache puts" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Cache Metrics", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "prometheus", + "description": "Count of REST requests", + "fill": 1, + "id": 27, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "{__name__=~\\".*rest.*_count\\", namespace=\\"$namespace\\", service=\\"$service_name\\"} ", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{__name__}}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "REST Requests Metrics", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "decimals": 0 + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "REST Metrics", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "java", + "jhipster", + "spring-boot" + ], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "prometheus", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(jvm_files, namespace)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "prometheus", + "hide": 0, + "includeAll": false, + "label": "Service Name", + "multi": false, + "name": "service_name", + "options": [], + "query": "label_values(jvm_files, service)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "JHipster Metrics", + "version": 3 + } ", "stateCleared": "modified", }, @@ -8560,9 +8560,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -8591,52 +8591,52 @@ spec: version: "v1" spec: containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.mynamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmysql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmysql - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED - value: "true" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.mynamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmysql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmysql + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED + value: 'true' + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -8652,23 +8652,23 @@ metadata: namespace: mynamespace spec: gateways: - - mesh + - mesh hosts: - - msmysql-knative + - msmysql-knative http: - - route: - - destination: - host: msmysql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: mynamespace - Knative-Serving-Revision: msmysql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmysql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: mynamespace + Knative-Serving-Revision: msmysql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -8690,6 +8690,7 @@ spec: kind: Namespace metadata: name: mynamespace + ", "stateCleared": "modified", }, @@ -8701,7 +8702,9 @@ exports[`generator - Knative Using Helm generator type mysql microservice with c ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql"], + "appsFolders": [ + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -8723,22 +8726,20 @@ exports[`generator - Knative Using Helm generator type mysql microservice with c ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag msmysql jhipster/msmysql $ docker push jhipster/msmysql \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash helm-knative-apply.sh (or) ./helm-knative-apply.sh \`\`\` @@ -8826,23 +8827,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.mynamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.mynamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -9087,18 +9088,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -9107,16 +9108,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -9133,18 +9134,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -9153,9 +9154,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -9178,18 +9179,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -9198,16 +9199,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -9341,9 +9342,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -9372,50 +9373,50 @@ spec: version: "v1" spec: containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.mynamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmysql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmysql - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.mynamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmysql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmysql + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -9431,23 +9432,23 @@ metadata: namespace: mynamespace spec: gateways: - - mesh + - mesh hosts: - - msmysql-knative + - msmysql-knative http: - - route: - - destination: - host: msmysql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: mynamespace - Knative-Serving-Revision: msmysql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmysql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: mynamespace + Knative-Serving-Revision: msmysql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -9469,6 +9470,7 @@ spec: kind: Namespace metadata: name: mynamespace + ", "stateCleared": "modified", }, @@ -9480,7 +9482,9 @@ exports[`generator - Knative Using Helm generator type only gateway should match ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -9502,22 +9506,20 @@ exports[`generator - Knative Using Helm generator type only gateway should match ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag jhgate jhipsterrepository/jhgate $ docker push jhipsterrepository/jhgate \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash helm-knative-apply.sh (or) ./helm-knative-apply.sh \`\`\` @@ -9605,23 +9607,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.jhipsternamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.jhipsternamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -9866,18 +9868,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -9886,16 +9888,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -9912,18 +9914,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -9932,9 +9934,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -9957,18 +9959,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -9977,16 +9979,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -10120,9 +10122,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -10142,18 +10144,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.jhipsternamespace. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.jhipsternamespace. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.jhipsternamespace. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.jhipsternamespace. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -10164,18 +10166,18 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.jhipsternamespace. + - jhgate.jhipsternamespace. gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate-knative - headers: - request: - add: - Knative-Serving-Namespace: jhipsternamespace - Knative-Serving-Revision: jhgate-knative + - route: + - destination: + host: jhgate-knative + headers: + request: + add: + Knative-Serving-Namespace: jhipsternamespace + Knative-Serving-Revision: jhgate-knative ", "stateCleared": "modified", }, @@ -10204,50 +10206,50 @@ spec: version: "v1" spec: containers: - - name: jhgate-app - image: jhipsterrepository/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.jhipsternamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: jhgate-app + image: jhipsterrepository/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.jhipsternamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -10263,23 +10265,23 @@ metadata: namespace: jhipsternamespace spec: gateways: - - mesh + - mesh hosts: - - jhgate-knative + - jhgate-knative http: - - route: - - destination: - host: jhgate-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: jhipsternamespace - Knative-Serving-Revision: jhgate-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: jhipsternamespace + Knative-Serving-Revision: jhgate-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -10301,6 +10303,7 @@ spec: kind: Namespace metadata: name: jhipsternamespace + ", "stateCleared": "modified", }, @@ -10312,7 +10315,10 @@ exports[`generator - Knative Using K8s generator type MySQL and PostgreSQL micro ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql", "03-psql"], + "appsFolders": [ + "02-mysql", + "03-psql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -10334,10 +10340,10 @@ exports[`generator - Knative Using K8s generator type MySQL and PostgreSQL micro ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag msmysql jhipster/msmysql @@ -10345,13 +10351,11 @@ $ docker push jhipster/msmysql $ docker image tag mspsql jhipster/mspsql $ docker push jhipster/mspsql \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash kubectl-knative-apply.sh (or) ./kubectl-knative-apply.sh \`\`\` @@ -10373,18 +10377,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -10393,16 +10397,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -10419,18 +10423,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -10439,9 +10443,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -10464,18 +10468,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -10484,16 +10488,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -10549,9 +10553,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -10574,33 +10578,33 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -10611,7 +10615,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -10640,50 +10644,50 @@ spec: version: "v1" spec: containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmysql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmysql - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmysql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmysql + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -10699,23 +10703,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmysql-knative + - msmysql-knative http: - - route: - - destination: - host: msmysql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmysql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmysql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmysql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -10744,9 +10748,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -10771,40 +10775,40 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -10815,12 +10819,12 @@ spec: selector: app: mspsql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -10854,32 +10858,32 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: postgres - image: postgresql-placeholder - env: - - name: POSTGRES_USER - value: mspsql - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - ports: - - containerPort: 5432 - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - subPath: postgres - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: postgres + image: postgresql-placeholder + env: + - name: POSTGRES_USER + value: mspsql + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + ports: + - containerPort: 5432 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + subPath: postgres + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -10890,7 +10894,7 @@ spec: selector: app: mspsql-postgresql ports: - - port: 5432 + - port: 5432 ", "stateCleared": "modified", }, @@ -10919,59 +10923,59 @@ spec: version: "v1" spec: containers: - - name: mspsql-app - image: jhipster/mspsql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: mspsql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: mspsql - - name: SPRING_DATASOURCE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_DATASOURCE_USERNAME - value: mspsql - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: mspsql-app + image: jhipster/mspsql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: mspsql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: mspsql + - name: SPRING_DATASOURCE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_DATASOURCE_USERNAME + value: mspsql + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -10987,23 +10991,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - mspsql-knative + - mspsql-knative http: - - route: - - destination: - host: mspsql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: mspsql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: mspsql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: mspsql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -11045,23 +11049,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -11301,7 +11305,9 @@ exports[`generator - Knative Using K8s generator type gateway and ingress should ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -11323,22 +11329,20 @@ exports[`generator - Knative Using K8s generator type gateway and ingress should ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag jhgate jhipster/jhgate $ docker push jhipster/jhgate \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash kubectl-knative-apply.sh (or) ./kubectl-knative-apply.sh \`\`\` @@ -11360,18 +11364,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -11380,16 +11384,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system.example.com + - grafana.istio-system.example.com gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -11406,18 +11410,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -11426,9 +11430,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system.example.com + - kiali.istio-system.example.com gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -11451,18 +11455,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -11471,16 +11475,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system.example.com + - zipkin.istio-system.example.com gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -11509,9 +11513,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -11531,18 +11535,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.default.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.default.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.default.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.default.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -11553,18 +11557,18 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.default.example.com + - jhgate.default.example.com gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate-knative - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative + - route: + - destination: + host: jhgate-knative + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative ", "stateCleared": "modified", }, @@ -11587,33 +11591,33 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -11624,7 +11628,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -11653,50 +11657,50 @@ spec: version: "v1" spec: containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -11712,23 +11716,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - jhgate-knative + - jhgate-knative http: - - route: - - destination: - host: jhgate-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -11797,23 +11801,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -12053,7 +12057,10 @@ exports[`generator - Knative Using K8s generator type gateway and mysql microser ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway", "02-mysql"], + "appsFolders": [ + "01-gateway", + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -12075,10 +12082,10 @@ exports[`generator - Knative Using K8s generator type gateway and mysql microser ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag jhgate jhipster/jhgate @@ -12086,13 +12093,11 @@ $ docker push jhipster/jhgate $ docker image tag msmysql jhipster/msmysql $ docker push jhipster/msmysql \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash kubectl-knative-apply.sh (or) ./kubectl-knative-apply.sh \`\`\` @@ -12114,18 +12119,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -12134,16 +12139,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -12160,18 +12165,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -12180,9 +12185,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -12205,18 +12210,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -12225,16 +12230,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -12263,9 +12268,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -12285,18 +12290,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.default. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.default. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.default. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.default. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -12307,18 +12312,18 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.default. + - jhgate.default. gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate-knative - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative + - route: + - destination: + host: jhgate-knative + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative ", "stateCleared": "modified", }, @@ -12341,33 +12346,33 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -12378,7 +12383,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -12407,50 +12412,50 @@ spec: version: "v1" spec: containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -12466,23 +12471,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - jhgate-knative + - jhgate-knative http: - - route: - - destination: - host: jhgate-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -12539,9 +12544,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -12564,33 +12569,33 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -12601,7 +12606,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -12630,50 +12635,50 @@ spec: version: "v1" spec: containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmysql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmysql - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmysql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmysql + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -12689,23 +12694,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmysql-knative + - msmysql-knative http: - - route: - - destination: - host: msmysql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmysql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmysql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmysql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -12747,23 +12752,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -13003,7 +13008,9 @@ exports[`generator - Knative Using K8s generator type gateway with istio routing ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -13025,22 +13032,20 @@ exports[`generator - Knative Using K8s generator type gateway with istio routing ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag jhgate jhipster/jhgate $ docker push jhipster/jhgate \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash kubectl-knative-apply.sh (or) ./kubectl-knative-apply.sh \`\`\` @@ -13062,18 +13067,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -13082,16 +13087,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system.example.com + - grafana.istio-system.example.com gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -13108,18 +13113,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -13128,9 +13133,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system.example.com + - kiali.istio-system.example.com gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -13153,18 +13158,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -13173,16 +13178,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system.example.com + - zipkin.istio-system.example.com gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -13211,9 +13216,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -13233,18 +13238,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.default.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.default.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.default.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.default.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -13255,18 +13260,18 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.default.example.com + - jhgate.default.example.com gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate-knative - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative + - route: + - destination: + host: jhgate-knative + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative ", "stateCleared": "modified", }, @@ -13289,33 +13294,33 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -13326,7 +13331,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -13355,50 +13360,50 @@ spec: version: "v1" spec: containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -13414,23 +13419,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - jhgate-knative + - jhgate-knative http: - - route: - - destination: - host: jhgate-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -13499,23 +13504,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -13785,10 +13790,10 @@ exports[`generator - Knative Using K8s generator type gateway, mysql, psql, mong ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag jhgate jhipster/jhgate @@ -13804,13 +13809,11 @@ $ docker push jhipster/msmariadb $ docker image tag msmssqldb jhipster/msmssqldb $ docker push jhipster/msmssqldb \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash kubectl-knative-apply.sh (or) ./kubectl-knative-apply.sh \`\`\` @@ -13832,18 +13835,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -13852,16 +13855,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -13878,18 +13881,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -13898,9 +13901,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -13923,18 +13926,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -13943,16 +13946,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -13981,9 +13984,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -14003,18 +14006,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.default. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.default. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.default. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.default. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -14025,18 +14028,18 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.default. + - jhgate.default. gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate-knative - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative + - route: + - destination: + host: jhgate-knative + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative ", "stateCleared": "modified", }, @@ -14059,33 +14062,33 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -14096,7 +14099,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -14125,50 +14128,50 @@ spec: version: "v1" spec: containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -14184,23 +14187,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - jhgate-knative + - jhgate-knative http: - - route: - - destination: - host: jhgate-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: jhgate-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: jhgate-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -14261,9 +14264,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -14297,37 +14300,37 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mariadb - image: mariadb-placeholder - env: - - name: MYSQL_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: msmariadb-mariadb - key: mariadb-root-password - - name: MYSQL_DATABASE - value: msmariadb - # command: - # - mysqld - # - --lower_case_table_names=1 - # - --skip-ssl - # - --character_set_server=utf8mb4 - # - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mariadb + image: mariadb-placeholder + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: msmariadb-mariadb + key: mariadb-root-password + - name: MYSQL_DATABASE + value: msmariadb +# command: +# - mysqld +# - --lower_case_table_names=1 +# - --skip-ssl +# - --character_set_server=utf8mb4 +# - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -14338,7 +14341,7 @@ spec: selector: app: msmariadb-mariadb ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -14367,55 +14370,55 @@ spec: version: "v1" spec: containers: - - name: msmariadb-app - image: jhipster/msmariadb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmariadb - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmariadb - - name: SPRING_DATASOURCE_URL - value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: msmariadb-mariadb - key: mariadb-root-password - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmariadb-app + image: jhipster/msmariadb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmariadb + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmariadb + - name: SPRING_DATASOURCE_URL + value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: msmariadb-mariadb + key: mariadb-root-password + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -14431,23 +14434,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmariadb-knative + - msmariadb-knative http: - - route: - - destination: - host: msmariadb-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmariadb-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmariadb-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmariadb-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -14476,9 +14479,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -14829,50 +14832,50 @@ spec: version: "v1" spec: containers: - - name: msmongodb-app - image: jhipster/msmongodb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmongodb - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmongodb - - name: SPRING_DATA_MONGODB_URI - value: "mongodb://msmongodb-mongodb-0.msmongodb-mongodb.default:27017/msmongodb" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmongodb-app + image: jhipster/msmongodb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmongodb + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmongodb + - name: SPRING_DATA_MONGODB_URI + value: "mongodb://msmongodb-mongodb-0.msmongodb-mongodb.default:27017/msmongodb" + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -14888,23 +14891,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmongodb-knative + - msmongodb-knative http: - - route: - - destination: - host: msmongodb-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmongodb-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmongodb-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmongodb-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -14933,9 +14936,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -14958,36 +14961,36 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: mssqldb - persistentVolumeClaim: - claimName: mssql-data - - name: data - emptyDir: {} + - name: mssqldb + persistentVolumeClaim: + claimName: mssql-data + - name: data + emptyDir: {} containers: - - name: mysql - image: mssql-placeholder - env: - - name: MSSQL_PID - value: "Express" - - name: ACCEPT_EULA - value: "Y" - - name: MSSQL_SA_PASSWORD - valueFrom: - secretKeyRef: - name: mssql - key: SA_PASSWORD - ports: - - containerPort: 1433 - volumeMounts: - - name: mssqldb - mountPath: /var/opt/mssql - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mssql-placeholder + env: + - name: MSSQL_PID + value: "Express" + - name: ACCEPT_EULA + value: "Y" + - name: MSSQL_SA_PASSWORD + valueFrom: + secretKeyRef: + name: mssql + key: SA_PASSWORD + ports: + - containerPort: 1433 + volumeMounts: + - name: mssqldb + mountPath: /var/opt/mssql + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 @@ -15010,7 +15013,7 @@ metadata: name: mssql-data spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce storageClassName: managed-premium resources: requests: @@ -15043,48 +15046,48 @@ spec: version: "v1" spec: containers: - - name: msmssqldb-app - image: jhipster/msmssqldb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmssqldb - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmssqldb - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmssqldb-app + image: jhipster/msmssqldb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmssqldb + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmssqldb + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -15100,23 +15103,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmssqldb-knative + - msmssqldb-knative http: - - route: - - destination: - host: msmssqldb-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmssqldb-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmssqldb-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmssqldb-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -15145,9 +15148,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -15170,33 +15173,33 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -15207,7 +15210,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -15236,50 +15239,50 @@ spec: version: "v1" spec: containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmysql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmysql - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmysql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmysql + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -15295,23 +15298,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - msmysql-knative + - msmysql-knative http: - - route: - - destination: - host: msmysql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: msmysql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmysql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: msmysql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -15340,9 +15343,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -15367,40 +15370,40 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -15411,12 +15414,12 @@ spec: selector: app: mspsql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -15439,43 +15442,43 @@ metadata: namespace: default spec: replicas: 1 - selector: - matchLabels: - app: mspsql-postgresql - template: - metadata: - labels: - app: mspsql-postgresql - annotations: - sidecar.istio.io/inject: "false" - spec: - volumes: - - name: data - emptyDir: {} - containers: - - name: postgres - image: postgresql-placeholder - env: - - name: POSTGRES_USER - value: mspsql - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - ports: - - containerPort: 5432 - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - subPath: postgres - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + selector: + matchLabels: + app: mspsql-postgresql + template: + metadata: + labels: + app: mspsql-postgresql + annotations: + sidecar.istio.io/inject: "false" + spec: + volumes: + - name: data + emptyDir: {} + containers: + - name: postgres + image: postgresql-placeholder + env: + - name: POSTGRES_USER + value: mspsql + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + ports: + - containerPort: 5432 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + subPath: postgres + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -15486,7 +15489,7 @@ spec: selector: app: mspsql-postgresql ports: - - port: 5432 + - port: 5432 ", "stateCleared": "modified", }, @@ -15515,59 +15518,59 @@ spec: version: "v1" spec: containers: - - name: mspsql-app - image: jhipster/mspsql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: mspsql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: mspsql - - name: SPRING_DATASOURCE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_DATASOURCE_USERNAME - value: mspsql - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: mspsql-app + image: jhipster/mspsql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: mspsql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: mspsql + - name: SPRING_DATASOURCE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_DATASOURCE_USERNAME + value: mspsql + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -15583,23 +15586,23 @@ metadata: namespace: default spec: gateways: - - mesh + - mesh hosts: - - mspsql-knative + - mspsql-knative http: - - route: - - destination: - host: mspsql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: default - Knative-Serving-Revision: mspsql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: mspsql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: default + Knative-Serving-Revision: mspsql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -15641,23 +15644,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -15897,7 +15900,9 @@ exports[`generator - Knative Using K8s generator type mysql microservice with cu ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql"], + "appsFolders": [ + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -15919,22 +15924,20 @@ exports[`generator - Knative Using K8s generator type mysql microservice with cu ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag msmysql jhipster/msmysql $ docker push jhipster/msmysql \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash kubectl-knative-apply.sh (or) ./kubectl-knative-apply.sh \`\`\` @@ -15956,18 +15959,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -15976,16 +15979,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -16002,18 +16005,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -16022,9 +16025,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -16047,18 +16050,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -16067,16 +16070,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -18419,51 +18422,52 @@ spec: - name: init-dependent-services-check image: busybox command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - until nc -z -w 1 jhipster-prometheus 9090 - do - echo Waiting for prometheus to get initialized - sleep 5 - done - until nc -z -w 1 jhipster-grafana 3000 - do - echo Waiting for grafana to get initialized - sleep 5 - done + until nc -z -w 1 jhipster-prometheus 9090 + do + echo Waiting for prometheus to get initialized + sleep 5 + done + until nc -z -w 1 jhipster-grafana 3000 + do + echo Waiting for grafana to get initialized + sleep 5 + done containers: - - name: grafana-configurer - image: grafana-watcher-placeholder - args: - - "--watch-dir=/var/grafana-dashboard" - - "--grafana-url=http://jhipster-grafana:3000" - env: - - name: GRAFANA_USER - valueFrom: - secretKeyRef: - name: jhipster-grafana-credentials - key: username - - name: GRAFANA_PASSWORD - valueFrom: - secretKeyRef: - name: jhipster-grafana-credentials - key: password - resources: - requests: - memory: "16Mi" - cpu: "50m" - limits: - memory: "32Mi" - cpu: "100m" - volumeMounts: - - name: grafana-dashboard - mountPath: /var/grafana-dashboard - volumes: + - name: grafana-configurer + image: grafana-watcher-placeholder + args: + - '--watch-dir=/var/grafana-dashboard' + - '--grafana-url=http://jhipster-grafana:3000' + env: + - name: GRAFANA_USER + valueFrom: + secretKeyRef: + name: jhipster-grafana-credentials + key: username + - name: GRAFANA_PASSWORD + valueFrom: + secretKeyRef: + name: jhipster-grafana-credentials + key: password + resources: + requests: + memory: "16Mi" + cpu: "50m" + limits: + memory: "32Mi" + cpu: "100m" + volumeMounts: - name: grafana-dashboard - configMap: - name: jhipster-grafana-dashboard + mountPath: /var/grafana-dashboard + volumes: + - name: grafana-dashboard + configMap: + name: jhipster-grafana-dashboard restartPolicy: OnFailure + ", "stateCleared": "modified", }, @@ -18480,18 +18484,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhipster-grafana.mynamespace. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhipster-grafana.mynamespace. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhipster-grafana.mynamespace. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhipster-grafana.mynamespace. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -18500,16 +18504,16 @@ metadata: namespace: mynamespace spec: hosts: - - jhipster-grafana.mynamespace. + - jhipster-grafana.mynamespace. gateways: - - jhipster-grafana-gateway + - jhipster-grafana-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: jhipster-grafana + - match: + - uri: + prefix: / + route: + - destination: + host: jhipster-grafana ", "stateCleared": "modified", }, @@ -18541,38 +18545,38 @@ spec: sidecar.istio.io/inject: "false" spec: containers: - - name: jhipster-grafana - image: grafana-placeholder - ports: - - containerPort: 3000 - name: http - protocol: TCP - env: - - name: GF_SECURITY_ADMIN_USER - valueFrom: - secretKeyRef: - name: jhipster-grafana-credentials - key: username - - name: GF_SECURITY_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - name: jhipster-grafana-credentials - key: password - - name: GF_USERS_ALLOW_SIGN_UP - value: "false" - resources: - requests: - memory: "100Mi" - cpu: "100m" - limits: - memory: "250Mi" - cpu: "200m" - volumeMounts: - - name: grafana-storage - mountPath: /var/grafana-storage - volumes: + - name: jhipster-grafana + image: grafana-placeholder + ports: + - containerPort: 3000 + name: http + protocol: TCP + env: + - name: GF_SECURITY_ADMIN_USER + valueFrom: + secretKeyRef: + name: jhipster-grafana-credentials + key: username + - name: GF_SECURITY_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: jhipster-grafana-credentials + key: password + - name: GF_USERS_ALLOW_SIGN_UP + value: "false" + resources: + requests: + memory: "100Mi" + cpu: "100m" + limits: + memory: "250Mi" + cpu: "200m" + volumeMounts: - name: grafana-storage - emptyDir: {} + mountPath: /var/grafana-storage + volumes: + - name: grafana-storage + emptyDir: {} restartPolicy: Always --- apiVersion: v1 @@ -18584,14 +18588,13 @@ metadata: app: jhipster-grafana spec: ports: - - name: http - port: 3000 - targetPort: 3000 + - name: http + port: 3000 + targetPort: 3000 type: LoadBalancer selector: app: jhipster-grafana --- - ", "stateCleared": "modified", }, @@ -18608,17 +18611,17 @@ metadata: name: jhipster-prometheus-role namespace: mynamespace rules: - - apiGroups: [""] - resources: - - nodes - - services - - endpoints - - pods - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: - - configmaps - verbs: ["get"] +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1beta1 # limit to the namespace @@ -18631,8 +18634,8 @@ roleRef: kind: Role name: jhipster-prometheus-role subjects: - - kind: ServiceAccount - name: jhipster-prometheus-sa +- kind: ServiceAccount + name: jhipster-prometheus-sa --- apiVersion: monitoring.coreos.com/v1 kind: Prometheus @@ -18656,10 +18659,10 @@ metadata: namespace: mynamespace spec: ports: - - name: web - port: 9090 - protocol: TCP - targetPort: web + - name: web + port: 9090 + protocol: TCP + targetPort: web selector: prometheus: jhipster-prometheus ", @@ -18671,54 +18674,54 @@ kind: ClusterRole metadata: name: jhipster-prometheus-operator-cr rules: - - apiGroups: - - extensions - resources: - - thirdpartyresources - verbs: - - "*" - - apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - "*" - - apiGroups: - - monitoring.coreos.com - resources: - - alertmanagers - - prometheuses - - servicemonitors - - prometheusrules - verbs: - - "*" - - apiGroups: - - apps - resources: - - statefulsets - verbs: ["*"] - - apiGroups: [""] - resources: - - configmaps - - secrets - verbs: ["*"] - - apiGroups: [""] - resources: - - pods - verbs: ["list", "delete"] - - apiGroups: [""] - resources: - - services - - endpoints - verbs: ["get", "create", "update"] - - apiGroups: [""] - resources: - - nodes - verbs: ["list", "watch"] - - apiGroups: [""] - resources: - - namespaces - verbs: ["list", "watch"] +- apiGroups: + - extensions + resources: + - thirdpartyresources + verbs: + - "*" +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - "*" +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - prometheuses + - servicemonitors + - prometheusrules + verbs: + - "*" +- apiGroups: + - apps + resources: + - statefulsets + verbs: ["*"] +- apiGroups: [""] + resources: + - configmaps + - secrets + verbs: ["*"] +- apiGroups: [""] + resources: + - pods + verbs: ["list", "delete"] +- apiGroups: [""] + resources: + - services + - endpoints + verbs: ["get", "create", "update"] +- apiGroups: [""] + resources: + - nodes + verbs: ["list", "watch"] +- apiGroups: [""] + resources: + - namespaces + verbs: ["list", "watch"] --- apiVersion: v1 kind: ServiceAccount @@ -18736,9 +18739,9 @@ roleRef: kind: ClusterRole name: jhipster-prometheus-operator-cr subjects: - - kind: ServiceAccount - name: jhipster-prometheus-operator-sa - namespace: mynamespace +- kind: ServiceAccount + name: jhipster-prometheus-operator-sa + namespace: mynamespace --- apiVersion: apps/v1 kind: Deployment @@ -18760,21 +18763,21 @@ spec: sidecar.istio.io/inject: "false" spec: containers: - - args: - - --kubelet-service=kube-system/kubelet - - --config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1 - image: prometheus-operator-placeholder - name: prometheus-operator - ports: - - containerPort: 8080 - name: http - resources: - limits: - cpu: 200m - memory: 100Mi - requests: - cpu: 100m - memory: 50Mi + - args: + - --kubelet-service=kube-system/kubelet + - --config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1 + image: prometheus-operator-placeholder + name: prometheus-operator + ports: + - containerPort: 8080 + name: http + resources: + limits: + cpu: 200m + memory: 100Mi + requests: + cpu: 100m + memory: 50Mi serviceAccountName: jhipster-prometheus-operator-sa ", "stateCleared": "modified", @@ -18804,9 +18807,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -18829,33 +18832,33 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -18866,7 +18869,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -18883,8 +18886,8 @@ spec: matchLabels: app: msmysql endpoints: - - port: web - path: /prometheusMetrics + - port: web + path: /prometheusMetrics ", "stateCleared": "modified", }, @@ -18913,52 +18916,52 @@ spec: version: "v1" spec: containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.mynamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmysql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmysql - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED - value: "true" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.mynamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmysql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmysql + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED + value: 'true' + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -18974,23 +18977,23 @@ metadata: namespace: mynamespace spec: gateways: - - mesh + - mesh hosts: - - msmysql-knative + - msmysql-knative http: - - route: - - destination: - host: msmysql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: mynamespace - Knative-Serving-Revision: msmysql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmysql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: mynamespace + Knative-Serving-Revision: msmysql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -18999,6 +19002,7 @@ spec: kind: Namespace metadata: name: mynamespace + ", "stateCleared": "modified", }, @@ -19040,23 +19044,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.mynamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.mynamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -19296,7 +19300,9 @@ exports[`generator - Knative Using K8s generator type mysql microservice with cu ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql"], + "appsFolders": [ + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -19318,22 +19324,20 @@ exports[`generator - Knative Using K8s generator type mysql microservice with cu ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag msmysql jhipster/msmysql $ docker push jhipster/msmysql \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash kubectl-knative-apply.sh (or) ./kubectl-knative-apply.sh \`\`\` @@ -19355,18 +19359,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -19375,16 +19379,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -19401,18 +19405,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -19421,9 +19425,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -19446,18 +19450,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -19466,16 +19470,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -19531,9 +19535,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -19556,33 +19560,33 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -19593,7 +19597,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -19622,50 +19626,50 @@ spec: version: "v1" spec: containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.mynamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: msmysql - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: msmysql - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.mynamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: msmysql + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: msmysql + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -19681,23 +19685,23 @@ metadata: namespace: mynamespace spec: gateways: - - mesh + - mesh hosts: - - msmysql-knative + - msmysql-knative http: - - route: - - destination: - host: msmysql-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: mynamespace - Knative-Serving-Revision: msmysql-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: msmysql-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: mynamespace + Knative-Serving-Revision: msmysql-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -19706,6 +19710,7 @@ spec: kind: Namespace metadata: name: mynamespace + ", "stateCleared": "modified", }, @@ -19747,23 +19752,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.mynamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.mynamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -20003,7 +20008,9 @@ exports[`generator - Knative Using K8s generator type only gateway should match ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "directoryPath": "./", @@ -20025,22 +20032,20 @@ exports[`generator - Knative Using K8s generator type only gateway should match ## Preparation -- Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed - in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. +* Knative depends on Istio. In order to use the manifests generated by k8s-knative generator, you should have Istio and Knative installed +in the cluster. Follow [this link](https://knative.dev/docs/install/) for instructions. -- You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: +* You will need to push your image(s) to a registry. If you have not done so, use the following commands to tag and push the images: \`\`\` $ docker image tag jhgate jhipsterrepository/jhgate $ docker push jhipsterrepository/jhgate \`\`\` - -- This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. +* This generator uses k8s generator for most of the part, except the core microservices apps that are (k)native. ## Deployment You can deploy all your apps by running the below terminal command: - \`\`\` bash kubectl-knative-apply.sh (or) ./kubectl-knative-apply.sh \`\`\` @@ -20062,18 +20067,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -20082,16 +20087,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system. + - grafana.istio-system. gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -20108,18 +20113,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -20128,9 +20133,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system. + - kiali.istio-system. gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -20153,18 +20158,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -20173,16 +20178,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system. + - zipkin.istio-system. gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -20211,9 +20216,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -20233,18 +20238,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.jhipsternamespace. - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.jhipsternamespace. + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.jhipsternamespace. + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.jhipsternamespace. --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -20255,18 +20260,18 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.jhipsternamespace. + - jhgate.jhipsternamespace. gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate-knative - headers: - request: - add: - Knative-Serving-Namespace: jhipsternamespace - Knative-Serving-Revision: jhgate-knative + - route: + - destination: + host: jhgate-knative + headers: + request: + add: + Knative-Serving-Namespace: jhipsternamespace + Knative-Serving-Revision: jhgate-knative ", "stateCleared": "modified", }, @@ -20289,33 +20294,33 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - emptyDir: {} + - name: data + emptyDir: {} containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -20326,7 +20331,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -20355,50 +20360,50 @@ spec: version: "v1" spec: containers: - - name: jhgate-app - image: jhipsterrepository/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul.jhipsternamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - timeoutSeconds: 5 - livenessProbe: - httpGet: - path: /management/health/liveness - initialDelaySeconds: 120 - timeoutSeconds: 5 + - name: jhgate-app + image: jhipsterrepository/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul.jhipsternamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /management/health/liveness + initialDelaySeconds: 120 + timeoutSeconds: 5 traffic: - tag: latest percent: 100 @@ -20414,23 +20419,23 @@ metadata: namespace: jhipsternamespace spec: gateways: - - mesh + - mesh hosts: - - jhgate-knative + - jhgate-knative http: - - route: - - destination: - host: jhgate-knative - subset: "v1" - headers: - request: - add: - Knative-Serving-Namespace: jhipsternamespace - Knative-Serving-Revision: jhgate-knative - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate-knative + subset: "v1" + headers: + request: + add: + Knative-Serving-Namespace: jhipsternamespace + Knative-Serving-Revision: jhgate-knative + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -20467,6 +20472,7 @@ logSummary kind: Namespace metadata: name: jhipsternamespace + ", "stateCleared": "modified", }, @@ -20508,23 +20514,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.jhipsternamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.jhipsternamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, diff --git a/generators/kubernetes-knative/files.js b/generators/kubernetes-knative/files.ts similarity index 98% rename from generators/kubernetes-knative/files.js rename to generators/kubernetes-knative/files.ts index a3d0455a2cfa..6cb71b880b7e 100644 --- a/generators/kubernetes-knative/files.js +++ b/generators/kubernetes-knative/files.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -24,7 +25,7 @@ import { monitoringTypes, searchEngineTypes, serviceDiscoveryTypes, -} from '../../jdl/jhipster/index.js'; +} from '../../lib/jhipster/index.js'; const { ELASTICSEARCH } = searchEngineTypes; const { GATEWAY, MONOLITH } = applicationTypes; @@ -37,7 +38,6 @@ const { GeneratorTypes } = kubernetesPlatformTypes; const { K8S } = GeneratorTypes; -// eslint-disable-next-line import/prefer-default-export export function writeFiles() { const suffix = 'knative'; return { diff --git a/generators/kubernetes-helm/generator.spec.js b/generators/kubernetes-knative/generator.spec.ts similarity index 96% rename from generators/kubernetes-helm/generator.spec.js rename to generators/kubernetes-knative/generator.spec.ts index b25895cf89f4..d90bf385002d 100644 --- a/generators/kubernetes-helm/generator.spec.js +++ b/generators/kubernetes-knative/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures } from '../../test/support/tests.js'; diff --git a/generators/kubernetes-knative/generator.js b/generators/kubernetes-knative/generator.ts similarity index 94% rename from generators/kubernetes-knative/generator.js rename to generators/kubernetes-knative/generator.ts index 447344e0fd49..e6cab36183bc 100644 --- a/generators/kubernetes-knative/generator.js +++ b/generators/kubernetes-knative/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,22 +17,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return */ + import fs from 'fs'; import chalk from 'chalk'; import BaseWorkspacesGenerator from '../base-workspaces/index.js'; -import { checkImages, generateJwtSecret, configureImageNames, loadFromYoRc } from '../base-workspaces/internal/docker-base.js'; +import { checkImages, configureImageNames, generateJwtSecret, loadFromYoRc } from '../base-workspaces/internal/docker-base.js'; import { checkHelm, checkKubernetes, + derivedKubernetesPlatformProperties, loadConfig, - setupKubernetesConstants, setupHelmConstants, - derivedKubernetesPlatformProperties, + setupKubernetesConstants, } from '../kubernetes/kubernetes-base.js'; -import { kubernetesPlatformTypes, buildToolTypes, messageBrokerTypes } from '../../jdl/jhipster/index.js'; +import { buildToolTypes, kubernetesPlatformTypes, messageBrokerTypes } from '../../lib/jhipster/index.js'; import { getJdbcUrl } from '../spring-data-relational/support/index.js'; import { loadDeploymentConfig, loadDockerDependenciesTask } from '../base-workspaces/internal/index.js'; import { checkDocker } from '../docker/support/index.js'; @@ -76,7 +77,7 @@ export default class KubernetesKnativeGenerator extends BaseWorkspacesGenerator await this.spawnCommand( 'kubectl get deploy -n knative-serving --label-columns=serving.knative.dev/release | grep -E "v0\\.[8-9]{1,3}\\.[0-9]*', ); - } catch (error) { + } catch { this.log.warn( 'Knative 0.8.* or later is not installed on your computer.\n' + 'Make sure you have Knative and Istio installed. Read https://knative.dev/docs/install/\n', @@ -131,10 +132,10 @@ export default class KubernetesKnativeGenerator extends BaseWorkspacesGenerator return { loadFromYoRc, loadSharedConfig() { - this.appConfigs.forEach(element => { - loadDerivedAppConfig({ application: element }); - loadDerivedServerConfig({ application: element }); - }); + for (const app of this.appConfigs) { + loadDerivedAppConfig({ application: app }); + loadDerivedServerConfig({ application: app }); + } loadDeploymentConfig.call(this); derivedKubernetesPlatformProperties(this); }, @@ -151,6 +152,7 @@ export default class KubernetesKnativeGenerator extends BaseWorkspacesGenerator setPostPromptProp() { this.appConfigs.forEach(element => { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions element.clusteredDb ? (element.dbPeerCount = 3) : (element.dbPeerCount = 1); if (element.messageBroker === KAFKA) { this.useKafka = true; @@ -218,7 +220,7 @@ export default class KubernetesKnativeGenerator extends BaseWorkspacesGenerator // Make the apply script executable try { fs.chmodSync('kubectl-knative-apply.sh', '755'); - } catch (err) { + } catch { this.log.warn("Failed to make 'kubectl-knative-apply.sh' executable, you may need to run 'chmod +x kubectl-knative-apply.sh'"); } } else { @@ -229,7 +231,7 @@ export default class KubernetesKnativeGenerator extends BaseWorkspacesGenerator try { fs.chmodSync('helm-knative-apply.sh', '755'); fs.chmodSync('helm-knative-upgrade.sh', '755'); - } catch (err) { + } catch { this.log.warn( "Failed to make 'helm-knative-apply.sh', 'helm-knative-upgrade.sh' executable, you may need to run 'chmod +x helm-knative-apply.sh helm-knative-upgrade.sh", ); diff --git a/generators/kubernetes-knative/index.ts b/generators/kubernetes-knative/index.ts index 58ac334eafae..870818641c5d 100644 --- a/generators/kubernetes-knative/index.ts +++ b/generators/kubernetes-knative/index.ts @@ -16,4 +16,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +export { default as command } from '../kubernetes/command.js'; export { default } from './generator.js'; diff --git a/generators/kubernetes-knative/knative.spec.ts b/generators/kubernetes-knative/knative.spec.ts index da73577302c7..9f9965c7a181 100644 --- a/generators/kubernetes-knative/knative.spec.ts +++ b/generators/kubernetes-knative/knative.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe, expect } from 'esmocha'; -import { dryRunHelpers as helpers, getGenerator } from '../../testing/index.js'; +import { before, describe, expect, it } from 'esmocha'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { GENERATOR_KUBERNETES_KNATIVE } from '../generator-list.js'; const expectedFiles = { @@ -98,17 +98,16 @@ const helmExpectedFiles = { describe('generator - Knative', () => { describe('Using K8s generator type', () => { describe('only gateway', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -124,8 +123,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'k8s', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -144,17 +142,16 @@ describe('generator - Knative', () => { }); describe('gateway and mysql microservice', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway', '02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -169,8 +166,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'k8s', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -190,17 +186,16 @@ describe('generator - Knative', () => { }); describe('mysql microservice with custom namespace', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -215,8 +210,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'k8s', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -236,17 +230,16 @@ describe('generator - Knative', () => { }); describe('gateway and ingress', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -262,8 +255,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'k8s', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -280,17 +272,16 @@ describe('generator - Knative', () => { }); describe('MySQL and PostgreSQL microservices without gateway', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql', '03-psql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -305,8 +296,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'k8s', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -329,17 +319,16 @@ describe('generator - Knative', () => { }); describe('gateway, mysql, psql, mongodb, mariadb, mssql microservices', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway', '02-mysql', '03-psql', '04-mongo', '07-mariadb', '11-mssql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -354,8 +343,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'k8s', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -387,17 +375,16 @@ describe('generator - Knative', () => { }); describe('mysql microservice with custom namespace and jhipster prometheus monitoring', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -411,8 +398,7 @@ describe('generator - Knative', () => { monitoring: 'prometheus', generatorType: 'k8s', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -435,17 +421,16 @@ describe('generator - Knative', () => { }); describe('gateway with istio routing files', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -460,8 +445,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'k8s', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -483,17 +467,16 @@ describe('generator - Knative', () => { describe('Using Helm generator type', () => { describe('only gateway', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -509,8 +492,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'helm', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -529,17 +511,16 @@ describe('generator - Knative', () => { }); describe('gateway and mysql microservice', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway', '02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -554,8 +535,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'helm', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -577,17 +557,16 @@ describe('generator - Knative', () => { }); describe('mysql microservice with custom namespace', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -602,8 +581,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'helm', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -625,17 +603,16 @@ describe('generator - Knative', () => { }); describe('gateway and ingress', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -651,8 +628,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'helm', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -676,17 +652,16 @@ describe('generator - Knative', () => { }); describe('MySQL and PostgreSQL microservices without gateway', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql', '03-psql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -701,8 +676,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'helm', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -729,17 +703,16 @@ describe('generator - Knative', () => { }); describe('gateway, mysql, psql, mongodb, mariadb microservices', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway', '02-mysql', '03-psql', '04-mongo', '07-mariadb']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -755,8 +728,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'helm', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -791,17 +763,16 @@ describe('generator - Knative', () => { }); describe('mysql microservice with custom namespace and jhipster prometheus monitoring', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -815,8 +786,7 @@ describe('generator - Knative', () => { monitoring: 'prometheus', generatorType: 'helm', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -842,17 +812,16 @@ describe('generator - Knative', () => { }); describe('gateway with istio routing files', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES_KNATIVE)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES_KNATIVE) .withOptions({ askAnswered: true, }) @@ -867,8 +836,7 @@ describe('generator - Knative', () => { clusteredDbApps: [], generatorType: 'helm', istio: true, - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); diff --git a/generators/kubernetes-knative/prompts.js b/generators/kubernetes-knative/prompts.ts similarity index 95% rename from generators/kubernetes-knative/prompts.js rename to generators/kubernetes-knative/prompts.ts index e1b22da9d30b..e9a625be4349 100644 --- a/generators/kubernetes-knative/prompts.js +++ b/generators/kubernetes-knative/prompts.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -17,7 +18,7 @@ * limitations under the License. */ import k8sPrompts from '../kubernetes/prompts.js'; -import { kubernetesPlatformTypes } from '../../jdl/jhipster/index.js'; +import { kubernetesPlatformTypes } from '../../lib/jhipster/index.js'; import { generatorDefaultConfig } from '../kubernetes/kubernetes-constants.js'; const { GeneratorTypes } = kubernetesPlatformTypes; diff --git a/generators/kubernetes/__snapshots__/kubernetes.spec.ts.snap b/generators/kubernetes/__snapshots__/kubernetes.spec.ts.snap index 03edc89ae11a..d94528c0419a 100644 --- a/generators/kubernetes/__snapshots__/kubernetes.spec.ts.snap +++ b/generators/kubernetes/__snapshots__/kubernetes.spec.ts.snap @@ -5,7 +5,9 @@ exports[`generator - Kubernetes Kafka application should match files snapshot 1` ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["09-kafka"], + "appsFolders": [ + "09-kafka" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "monolith", @@ -60,6 +62,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -79,12 +82,15 @@ kubectl scale deployment --replicas The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` -kubectl set image deployment/-app = +kubectl set image deployment/-app = \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + + + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -98,6 +104,7 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` > my applications are starting very slow, despite I have a cluster with many resources The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! + ", "stateCleared": "modified", }, @@ -162,13 +169,14 @@ logSummary "contents": "commonLabels: app.kubernetes.io/genereted-by: JHipster + resources: - # Individual apps - - samplekafka-k8s/samplekafka-deployment.yml - - samplekafka-k8s/samplekafka-service.yml - - samplekafka-k8s/samplekafka-mysql.yml - # messagebroker - - messagebroker-k8s/kafka.yml +# Individual apps +- samplekafka-k8s/samplekafka-deployment.yml +- samplekafka-k8s/samplekafka-service.yml +- samplekafka-k8s/samplekafka-mysql.yml +# messagebroker +- messagebroker-k8s/kafka.yml # service discovery eureka/consul patchesJson6902: @@ -192,26 +200,26 @@ spec: app: jhipster-kafka spec: containers: - - name: kafka - image: kafka-placeholder - env: - - name: KAFKA_ADVERTISED_LISTENERS - value: "PLAINTEXT://jhipster-kafka.default.svc.cluster.local:9092" - - name: KAFKA_ZOOKEEPER_CONNECT - value: "jhipster-zookeeper.default.svc.cluster.local:2181" - - name: KAFKA_BROKER_ID - value: "2" - - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR - value: "1" - ports: - - containerPort: 9092 - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: kafka + image: kafka-placeholder + env: + - name: KAFKA_ADVERTISED_LISTENERS + value: 'PLAINTEXT://jhipster-kafka.default.svc.cluster.local:9092' + - name: KAFKA_ZOOKEEPER_CONNECT + value: 'jhipster-zookeeper.default.svc.cluster.local:2181' + - name: KAFKA_BROKER_ID + value: '2' + - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR + value: '1' + ports: + - containerPort: 9092 + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -222,7 +230,7 @@ spec: selector: app: jhipster-kafka ports: - - port: 9092 + - port: 9092 --- apiVersion: apps/v1 kind: Deployment @@ -240,24 +248,24 @@ spec: app: jhipster-zookeeper spec: containers: - - name: zookeeper - image: zookeeper-placeholder - env: - - name: ZOOKEEPER_CLIENT_PORT - value: "2181" - - name: ZOOKEEPER_TICK_TIME - value: "2000" - - name: ZOOKEEPER_SYNC_LIMIT - value: "2" - ports: - - containerPort: 2181 - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: zookeeper + image: zookeeper-placeholder + env: + - name: ZOOKEEPER_CLIENT_PORT + value: '2181' + - name: ZOOKEEPER_TICK_TIME + value: '2000' + - name: ZOOKEEPER_SYNC_LIMIT + value: '2' + ports: + - containerPort: 2181 + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -268,7 +276,7 @@ spec: selector: app: jhipster-zookeeper ports: - - port: 2181 + - port: 2181 ", "stateCleared": "modified", }, @@ -306,71 +314,71 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 samplekafka-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 samplekafka-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: samplekafka-app - image: jhipster/samplekafka - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://samplekafka-mysql.default.svc.cluster.local:3306/samplekafka?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://samplekafka-mysql.default.svc.cluster.local:3306/samplekafka?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: KAFKA_CONSUMER_KEY_DESERIALIZER - value: "org.apache.kafka.common.serialization.StringDeserializer" - - name: KAFKA_CONSUMER_VALUE_DESERIALIZER - value: "org.apache.kafka.common.serialization.StringDeserializer" - - name: KAFKA_CONSUMER_BOOTSTRAP_SERVERS - value: "jhipster-kafka.default.svc.cluster.local:9092" - - name: KAFKA_CONSUMER_GROUP_ID - value: "samplekafka" - - name: KAFKA_CONSUMER_AUTO_OFFSET_RESET - value: "earliest" - - name: KAFKA_PRODUCER_BOOTSTRAP_SERVERS - value: "jhipster-kafka.default.svc.cluster.local:9092" - - name: KAFKA_PRODUCER_KEY_DESERIALIZER - value: "org.apache.kafka.common.serialization.StringDeserializer" - - name: KAFKA_PRODUCER_VALUE_DESERIALIZER - value: "org.apache.kafka.common.serialization.StringDeserializer" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: samplekafka-app + image: jhipster/samplekafka + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://samplekafka-mysql.default.svc.cluster.local:3306/samplekafka?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://samplekafka-mysql.default.svc.cluster.local:3306/samplekafka?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: KAFKA_CONSUMER_KEY_DESERIALIZER + value: 'org.apache.kafka.common.serialization.StringDeserializer' + - name: KAFKA_CONSUMER_VALUE_DESERIALIZER + value: 'org.apache.kafka.common.serialization.StringDeserializer' + - name: KAFKA_CONSUMER_BOOTSTRAP_SERVERS + value: 'jhipster-kafka.default.svc.cluster.local:9092' + - name: KAFKA_CONSUMER_GROUP_ID + value: 'samplekafka' + - name: KAFKA_CONSUMER_AUTO_OFFSET_RESET + value: 'earliest' + - name: KAFKA_PRODUCER_BOOTSTRAP_SERVERS + value: 'jhipster-kafka.default.svc.cluster.local:9092' + - name: KAFKA_PRODUCER_KEY_DESERIALIZER + value: 'org.apache.kafka.common.serialization.StringDeserializer' + - name: KAFKA_PRODUCER_VALUE_DESERIALIZER + value: 'org.apache.kafka.common.serialization.StringDeserializer' + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -382,7 +390,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -403,34 +411,34 @@ spec: app: samplekafka-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: samplekafka-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: samplekafka-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: samplekafka - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: samplekafka + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -441,7 +449,7 @@ spec: selector: app: samplekafka-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -458,9 +466,9 @@ spec: app: samplekafka type: LoadBalancer ports: - - name: http - port: 80 - targetPort: 8080 + - name: http + port: 80 + targetPort: 8080 ", "stateCleared": "modified", }, @@ -469,9 +477,9 @@ spec: kind: Config build: artifacts: - - image: jhipster/samplekafka - context: ./09-kafka - jib: {} + - image: jhipster/samplekafka + context: ./09-kafka + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -490,7 +498,10 @@ exports[`generator - Kubernetes MySQL and PostgreSQL microservices without gatew ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql", "03-psql"], + "appsFolders": [ + "02-mysql", + "03-psql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -548,6 +559,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + \`\`\` ## Scaling your deployments @@ -555,9 +567,7 @@ skaffold run [or] skaffold deploy You can scale your apps using: \`\`\` - kubectl scale deployment --replicas - \`\`\` ## Zero-downtime deployments @@ -565,9 +575,7 @@ kubectl scale deployment --replicas The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` - -kubectl set image deployment/-app = - +kubectl set image deployment/-app = \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. @@ -590,7 +598,6 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! -\`\`\` ", "stateCleared": "modified", }, @@ -656,19 +663,20 @@ logSummary "contents": "commonLabels: app.kubernetes.io/genereted-by: JHipster + resources: - # Individual apps - - msmysql-k8s/msmysql-deployment.yml - - msmysql-k8s/msmysql-service.yml - - msmysql-k8s/msmysql-mysql.yml - - mspsql-k8s/mspsql-deployment.yml - - mspsql-k8s/mspsql-service.yml - - mspsql-k8s/mspsql-postgresql.yml - - mspsql-k8s/mspsql-elasticsearch.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml +# Individual apps +- msmysql-k8s/msmysql-deployment.yml +- msmysql-k8s/msmysql-service.yml +- msmysql-k8s/msmysql-mysql.yml +- mspsql-k8s/mspsql-deployment.yml +- mspsql-k8s/mspsql-service.yml +- mspsql-k8s/mspsql-postgresql.yml +- mspsql-k8s/mspsql-elasticsearch.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -708,61 +716,61 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -774,7 +782,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -795,34 +803,34 @@ spec: app: msmysql-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: msmysql-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: msmysql-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -833,7 +841,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -849,8 +857,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -888,70 +896,70 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 mspsql-postgresql 5432) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 mspsql-postgresql 5432) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: mspsql-app - image: jhipster/mspsql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_DATASOURCE_USERNAME - value: mspsql - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - - name: SPRING_LIQUIBASE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: mspsql-app + image: jhipster/mspsql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_DATASOURCE_USERNAME + value: mspsql + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + - name: SPRING_LIQUIBASE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -963,7 +971,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -986,41 +994,41 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - persistentVolumeClaim: - claimName: mspsql-elasticsearch-pvc + - name: data + persistentVolumeClaim: + claimName: mspsql-elasticsearch-pvc initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -1031,12 +1039,12 @@ spec: selector: app: mspsql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -1048,7 +1056,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -1080,33 +1088,33 @@ spec: app: mspsql-postgresql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: mspsql-postgresql-pvc + - name: data + persistentVolumeClaim: + claimName: mspsql-postgresql-pvc containers: - - name: postgres - image: postgresql-placeholder - env: - - name: POSTGRES_USER - value: mspsql - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - ports: - - containerPort: 5432 - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - subPath: postgres - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: postgres + image: postgresql-placeholder + env: + - name: POSTGRES_USER + value: mspsql + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + ports: + - containerPort: 5432 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + subPath: postgres + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -1117,7 +1125,7 @@ spec: selector: app: mspsql-postgresql ports: - - port: 5432 + - port: 5432 ", "stateCleared": "modified", }, @@ -1133,8 +1141,8 @@ spec: selector: app: mspsql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -1176,23 +1184,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -1427,12 +1435,12 @@ spec: kind: Config build: artifacts: - - image: jhipster/msmysql - context: ./02-mysql - jib: {} - - image: jhipster/mspsql - context: ./03-psql - jib: {} + - image: jhipster/msmysql + context: ./02-mysql + jib: {} + - image: jhipster/mspsql + context: ./03-psql + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -1451,7 +1459,9 @@ exports[`generator - Kubernetes gateway and ingress should match files snapshot ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -1507,6 +1517,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -1526,12 +1537,15 @@ kubectl scale deployment --replicas The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` -kubectl set image deployment/-app = +kubectl set image deployment/-app = \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + + + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -1545,6 +1559,7 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` > my applications are starting very slow, despite I have a cluster with many resources The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! + ", "stateCleared": "modified", }, @@ -1582,63 +1597,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -1651,16 +1666,16 @@ metadata: spec: ingressClassName: nginx rules: - - host: jhgate.default.example.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: jhgate - port: - name: http + - host: jhgate.default.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: jhgate + port: + name: http ", "stateCleared": "modified", }, @@ -1672,7 +1687,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -1693,34 +1708,34 @@ spec: app: jhgate-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: jhgate-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: jhgate-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -1731,7 +1746,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -1748,8 +1763,8 @@ spec: app: jhgate type: ClusterIP ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -1818,16 +1833,17 @@ logSummary "contents": "commonLabels: app.kubernetes.io/genereted-by: JHipster + resources: - # Individual apps - - jhgate-k8s/jhgate-deployment.yml - - jhgate-k8s/jhgate-service.yml - - jhgate-k8s/jhgate-mysql.yml - - jhgate-k8s/jhgate-ingress.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml +# Individual apps +- jhgate-k8s/jhgate-deployment.yml +- jhgate-k8s/jhgate-service.yml +- jhgate-k8s/jhgate-mysql.yml +- jhgate-k8s/jhgate-ingress.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -1871,23 +1887,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -2122,9 +2138,9 @@ spec: kind: Config build: artifacts: - - image: jhipster/jhgate - context: ./01-gateway - jib: {} + - image: jhipster/jhgate + context: ./01-gateway + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -2143,7 +2159,9 @@ exports[`generator - Kubernetes gateway and ingressType gke should match files s ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -2199,6 +2217,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -2218,14 +2237,17 @@ kubectl scale deployment --replicas The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` -kubectl set image deployment/-app = +kubectl set image deployment/-app = \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + + ## Keycloak + Keycloak deployment in production mode requires the installation of [cert-manager](https://cert-manager.io/docs/installation/) Kubernetes add-on for the TLS certificate generation. \`\`\` @@ -2253,7 +2275,7 @@ When running the \`jhipster k8s\` generator, it will prompt for a root FQDN (ful It might take up to 15 minutes for the Let's Encrypt certificates to be issued. Use the following command to check the status: \`\`\` -kubectl describe certificate keycloak-ssl +kubectl describe certificate keycloak-ssl \`\`\` You need to look for the following two events to determine success: @@ -2269,6 +2291,7 @@ Events: cert-manager first creates a temporary certificate. Once you see the event "The certificate has been successfully issued", it means Let's Encrypt staging has issued the certificate. The staging certificate will be trusted by deployed applications, but not by browsers. Let's Encrypt production certificates are trusted by browsers, but the production issuer will probably not work with nip.io, and fail with "too many certificates already issued for nip.io". + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -2288,7 +2311,7 @@ The default setting are optimized for middle-scale clusters. You are free to inc The k8s sub-generator configures Let's Encrypt staging environment, which is not trusted by browsers and Java applications by default. In the Kubernetes descriptors, the staging CAs are added to the applications truststore and registry truststore. Note that cert-manager issues a temporary certificate first, but the applications and registry don't trust the ad-hoc CA, and will fail the startup until the Let's Encrypt certificate is ready and updated in the ingress service. You will see the application pod STATUS as Error and CrashLoopBackOff during the multiple startup attempts. You can check the certificate status with the following command: \`\`\` -kubectl describe certificate keycloak-ssl +kubectl describe certificate keycloak-ssl \`\`\` ", "stateCleared": "modified", @@ -2317,13 +2340,14 @@ metadata: spec: acme: server: https://acme-staging-v02.api.letsencrypt.org/directory - email: + email: privateKeySecretRef: name: letsencrypt-staging solvers: - - http01: - ingress: + - http01: + ingress: class: ingress-gce + ", "stateCleared": "modified", }, @@ -2361,82 +2385,82 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - # Custom trustStore required when using Let's Encrypt staging - - name: JAVA_OPTS - value: "-Djavax.net.ssl.trustStore=/etc/pki/java/cacerts -Djavax.net.ssl.trustStorePassword=123456 -Xmx256m -Xms256m" - - name: SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI - value: https://keycloak.default.example.com/realms/jhipster - - name: SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID - value: web_app - - name: SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET - value: web_app - - name: SERVER_SHUTDOWN - value: graceful - # Custom trustStore required when using Let's Encrypt staging - volumeMounts: - - name: java-truststore - mountPath: /etc/pki/java - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + # Custom trustStore required when using Let's Encrypt staging + - name: JAVA_OPTS + value: "-Djavax.net.ssl.trustStore=/etc/pki/java/cacerts -Djavax.net.ssl.trustStorePassword=123456 -Xmx256m -Xms256m" + - name: SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI + value: https://keycloak.default.example.com/realms/jhipster + - name: SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID + value: web_app + - name: SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET + value: web_app + - name: SERVER_SHUTDOWN + value: graceful + # Custom trustStore required when using Let's Encrypt staging + volumeMounts: + - name: java-truststore + mountPath: /etc/pki/java + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 volumes: - # When using Let's Encrypt staging certificates, for a successful start, add CAs to java truststore - - name: java-truststore - secret: - secretName: letsencrypt-ca-secret - items: - - key: truststore.jks - path: cacerts + # When using Let's Encrypt staging certificates, for a successful start, add CAs to java truststore + - name: java-truststore + secret: + secretName: letsencrypt-ca-secret + items: + - key: truststore.jks + path: cacerts ", "stateCleared": "modified", }, @@ -2454,26 +2478,26 @@ metadata: cert-manager.io/issue-temporary-certificate: "true" spec: rules: - - host: jhgate.default.example.com - http: - paths: - - path: /* - pathType: ImplementationSpecific - backend: - service: - name: jhgate - port: - name: http - - host: keycloak.default.example.com - http: - paths: - - path: /* - pathType: ImplementationSpecific - backend: - service: - name: keycloak - port: - number: 9080 + - host: jhgate.default.example.com + http: + paths: + - path: /* + pathType: ImplementationSpecific + backend: + service: + name: jhgate + port: + name: http + - host: keycloak.default.example.com + http: + paths: + - path: /* + pathType: ImplementationSpecific + backend: + service: + name: keycloak + port: + number: 9080 tls: - secretName: keycloak-ssl hosts: @@ -2489,7 +2513,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -2510,34 +2534,34 @@ spec: app: jhgate-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: jhgate-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: jhgate-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -2548,7 +2572,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -2565,8 +2589,8 @@ spec: app: jhgate type: NodePort ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -5090,7 +5114,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -5122,33 +5146,33 @@ spec: app: keycloak-postgresql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: keycloak-postgresql-pvc + - name: data + persistentVolumeClaim: + claimName: keycloak-postgresql-pvc containers: - - name: postgres - image: postgresql-placeholder - env: - - name: POSTGRES_USER - value: keycloak - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: keycloak-postgresql - key: postgresql-password - ports: - - containerPort: 5432 - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - subPath: postgres - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: postgres + image: postgresql-placeholder + env: + - name: POSTGRES_USER + value: keycloak + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: keycloak-postgresql + key: postgresql-password + ports: + - containerPort: 5432 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + subPath: postgres + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -5159,7 +5183,7 @@ spec: selector: app: keycloak-postgresql ports: - - port: 5432 + - port: 5432 ", "stateCleared": "modified", }, @@ -5173,12 +5197,12 @@ metadata: app: keycloak spec: ports: - - name: http - port: 9080 - targetPort: 8080 - - name: https - port: 9443 - targetPort: 8443 + - name: http + port: 9080 + targetPort: 8080 + - name: https + port: 9443 + targetPort: 8443 clusterIP: None publishNotReadyAddresses: true selector: @@ -5202,53 +5226,53 @@ spec: app: keycloak spec: containers: - - name: keycloak - image: keycloak-placeholder - args: "start --import-realm" - env: - - name: KEYCLOAK_ADMIN - value: "admin" - - name: KEYCLOAK_ADMIN_PASSWORD - value: "admin" - - name: KC_DB - value: postgres - - name: KC_DB_URL_HOST - value: keycloak-postgresql.default.svc.cluster.local - - name: KC_DB_USERNAME - value: keycloak - - name: KC_DB_PASSWORD - valueFrom: - secretKeyRef: - name: keycloak-postgresql - key: postgresql-password - - name: KC_FEATURES - value: scripts - - name: KC_PROXY - value: "edge" - - name: KC_HOSTNAME_URL - value: https://keycloak.default.example.com - - name: KC_HOSTNAME_ADMIN_URL - value: https://keycloak.default.example.com - - name: KC_CACHE_STACK - value: "kubernetes" - - name: JAVA_OPTS_APPEND - value: "-Djgroups.dns.query=keycloak.default.svc.cluster.local" - ports: - - name: http - containerPort: 8080 - - name: https - containerPort: 8443 - readinessProbe: - httpGet: - path: /realms/master - port: 8080 - volumeMounts: - - name: keycloak-volume - mountPath: /opt/keycloak/data/import - volumes: + - name: keycloak + image: keycloak-placeholder + args: "start --import-realm" + env: + - name: KEYCLOAK_ADMIN + value: "admin" + - name: KEYCLOAK_ADMIN_PASSWORD + value: "admin" + - name: KC_DB + value: postgres + - name: KC_DB_URL_HOST + value: keycloak-postgresql.default.svc.cluster.local + - name: KC_DB_USERNAME + value: keycloak + - name: KC_DB_PASSWORD + valueFrom: + secretKeyRef: + name: keycloak-postgresql + key: postgresql-password + - name: KC_FEATURES + value: scripts + - name: KC_PROXY + value: "edge" + - name: KC_HOSTNAME_URL + value: https://keycloak.default.example.com + - name: KC_HOSTNAME_ADMIN_URL + value: https://keycloak.default.example.com + - name: KC_CACHE_STACK + value: "kubernetes" + - name: JAVA_OPTS_APPEND + value: "-Djgroups.dns.query=keycloak.default.svc.cluster.local" + ports: + - name: http + containerPort: 8080 + - name: https + containerPort: 8443 + readinessProbe: + httpGet: + path: /realms/master + port: 8080 + volumeMounts: - name: keycloak-volume - configMap: - name: keycloak-config + mountPath: /opt/keycloak/data/import + volumes: + - name: keycloak-volume + configMap: + name: keycloak-config ", "stateCleared": "modified", }, @@ -5320,23 +5344,24 @@ logSummary "contents": "commonLabels: app.kubernetes.io/genereted-by: JHipster + resources: - # Individual apps - - jhgate-k8s/jhgate-deployment.yml - - jhgate-k8s/jhgate-service.yml - - jhgate-k8s/jhgate-mysql.yml - - jhgate-k8s/jhgate-ingress.yml - # cert-manager - - cert-manager/letsencrypt-staging-ca-secret.yml - - cert-manager/letsencrypt-staging-issuer.yml - # keycloak - - keycloak-k8s/keycloak-configmap.yml - - keycloak-k8s/keycloak-postgresql.yml - - keycloak-k8s/keycloak.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml +# Individual apps +- jhgate-k8s/jhgate-deployment.yml +- jhgate-k8s/jhgate-service.yml +- jhgate-k8s/jhgate-mysql.yml +- jhgate-k8s/jhgate-ingress.yml +# cert-manager +- cert-manager/letsencrypt-staging-ca-secret.yml +- cert-manager/letsencrypt-staging-issuer.yml +# keycloak +- keycloak-k8s/keycloak-configmap.yml +- keycloak-k8s/keycloak-postgresql.yml +- keycloak-k8s/keycloak.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -5380,23 +5405,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -5631,9 +5656,9 @@ spec: kind: Config build: artifacts: - - image: jhipster/jhgate - context: ./01-gateway - jib: {} + - image: jhipster/jhgate + context: ./01-gateway + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -5652,7 +5677,9 @@ exports[`generator - Kubernetes gateway and ingressType nginx should match files ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -5708,6 +5735,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -5727,12 +5755,14 @@ kubectl scale deployment --replicas The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` -kubectl set image deployment/-app = +kubectl set image deployment/-app = \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + + ## Keycloak The following Keycloak [best practices](https://www.keycloak.org/server/configuration-production) for production are included in the generated k8s: a production grade database PostgreSQL, the \`edge\` deployment mode, high availability through clustered deployment, and \`HOSTNAME\` configuration. HTTP/TLS is not enabled for ease of deployment, but it is required for a secure exchange of credentials and other sensitive data with Keycloak, preventing several attack vectors. @@ -5759,6 +5789,8 @@ ingress-nginx-controller LoadBalancer 10.103.44.162 10.103.44.162 80:309 When running the \`jhipster k8s\` generator, it will prompt for a root FQDN (fully qualified domain name). You can use \`nip.io\` as the DNS provider and set \`.nip.io\`. + + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -5772,6 +5804,7 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` > my applications are starting very slow, despite I have a cluster with many resources The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! + ", "stateCleared": "modified", }, @@ -5809,69 +5842,69 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: "-Xmx256m -Xms256m" - - name: SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI - value: http://keycloak.default.example.com/realms/jhipster - - name: SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID - value: web_app - - name: SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET - value: web_app - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: "-Xmx256m -Xms256m" + - name: SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI + value: http://keycloak.default.example.com/realms/jhipster + - name: SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID + value: web_app + - name: SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET + value: web_app + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -5884,26 +5917,26 @@ metadata: spec: ingressClassName: nginx rules: - - host: jhgate.default.example.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: jhgate - port: - name: http - - host: keycloak.default.example.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: keycloak - port: - number: 9080 + - host: jhgate.default.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: jhgate + port: + name: http + - host: keycloak.default.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: keycloak + port: + number: 9080 ", "stateCleared": "modified", }, @@ -5915,7 +5948,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -5936,34 +5969,34 @@ spec: app: jhgate-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: jhgate-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: jhgate-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -5974,7 +6007,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -5991,8 +6024,8 @@ spec: app: jhgate type: ClusterIP ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -8516,7 +8549,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -8548,33 +8581,33 @@ spec: app: keycloak-postgresql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: keycloak-postgresql-pvc + - name: data + persistentVolumeClaim: + claimName: keycloak-postgresql-pvc containers: - - name: postgres - image: postgresql-placeholder - env: - - name: POSTGRES_USER - value: keycloak - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: keycloak-postgresql - key: postgresql-password - ports: - - containerPort: 5432 - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - subPath: postgres - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: postgres + image: postgresql-placeholder + env: + - name: POSTGRES_USER + value: keycloak + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: keycloak-postgresql + key: postgresql-password + ports: + - containerPort: 5432 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + subPath: postgres + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -8585,7 +8618,7 @@ spec: selector: app: keycloak-postgresql ports: - - port: 5432 + - port: 5432 ", "stateCleared": "modified", }, @@ -8599,12 +8632,12 @@ metadata: app: keycloak spec: ports: - - name: http - port: 9080 - targetPort: 8080 - - name: https - port: 9443 - targetPort: 8443 + - name: http + port: 9080 + targetPort: 8080 + - name: https + port: 9443 + targetPort: 8443 clusterIP: None publishNotReadyAddresses: true selector: @@ -8628,53 +8661,53 @@ spec: app: keycloak spec: containers: - - name: keycloak - image: keycloak-placeholder - args: "start --import-realm" - env: - - name: KEYCLOAK_ADMIN - value: "admin" - - name: KEYCLOAK_ADMIN_PASSWORD - value: "admin" - - name: KC_DB - value: postgres - - name: KC_DB_URL_HOST - value: keycloak-postgresql.default.svc.cluster.local - - name: KC_DB_USERNAME - value: keycloak - - name: KC_DB_PASSWORD - valueFrom: - secretKeyRef: - name: keycloak-postgresql - key: postgresql-password - - name: KC_FEATURES - value: scripts - - name: KC_PROXY - value: "edge" - - name: KC_HOSTNAME_URL - value: http://keycloak.default.example.com - - name: KC_HOSTNAME_ADMIN_URL - value: http://keycloak.default.example.com - - name: KC_CACHE_STACK - value: "kubernetes" - - name: JAVA_OPTS_APPEND - value: "-Djgroups.dns.query=keycloak.default.svc.cluster.local" - ports: - - name: http - containerPort: 8080 - - name: https - containerPort: 8443 - readinessProbe: - httpGet: - path: /realms/master - port: 8080 - volumeMounts: - - name: keycloak-volume - mountPath: /opt/keycloak/data/import - volumes: + - name: keycloak + image: keycloak-placeholder + args: "start --import-realm" + env: + - name: KEYCLOAK_ADMIN + value: "admin" + - name: KEYCLOAK_ADMIN_PASSWORD + value: "admin" + - name: KC_DB + value: postgres + - name: KC_DB_URL_HOST + value: keycloak-postgresql.default.svc.cluster.local + - name: KC_DB_USERNAME + value: keycloak + - name: KC_DB_PASSWORD + valueFrom: + secretKeyRef: + name: keycloak-postgresql + key: postgresql-password + - name: KC_FEATURES + value: scripts + - name: KC_PROXY + value: "edge" + - name: KC_HOSTNAME_URL + value: http://keycloak.default.example.com + - name: KC_HOSTNAME_ADMIN_URL + value: http://keycloak.default.example.com + - name: KC_CACHE_STACK + value: "kubernetes" + - name: JAVA_OPTS_APPEND + value: "-Djgroups.dns.query=keycloak.default.svc.cluster.local" + ports: + - name: http + containerPort: 8080 + - name: https + containerPort: 8443 + readinessProbe: + httpGet: + path: /realms/master + port: 8080 + volumeMounts: - name: keycloak-volume - configMap: - name: keycloak-config + mountPath: /opt/keycloak/data/import + volumes: + - name: keycloak-volume + configMap: + name: keycloak-config ", "stateCleared": "modified", }, @@ -8745,20 +8778,21 @@ logSummary "contents": "commonLabels: app.kubernetes.io/genereted-by: JHipster + resources: - # Individual apps - - jhgate-k8s/jhgate-deployment.yml - - jhgate-k8s/jhgate-service.yml - - jhgate-k8s/jhgate-mysql.yml - - jhgate-k8s/jhgate-ingress.yml - # keycloak - - keycloak-k8s/keycloak-configmap.yml - - keycloak-k8s/keycloak-postgresql.yml - - keycloak-k8s/keycloak.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml +# Individual apps +- jhgate-k8s/jhgate-deployment.yml +- jhgate-k8s/jhgate-service.yml +- jhgate-k8s/jhgate-mysql.yml +- jhgate-k8s/jhgate-ingress.yml +# keycloak +- keycloak-k8s/keycloak-configmap.yml +- keycloak-k8s/keycloak-postgresql.yml +- keycloak-k8s/keycloak.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -8802,23 +8836,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -9053,9 +9087,9 @@ spec: kind: Config build: artifacts: - - image: jhipster/jhgate - context: ./01-gateway - jib: {} + - image: jhipster/jhgate + context: ./01-gateway + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -9074,7 +9108,10 @@ exports[`generator - Kubernetes gateway and mysql microservice should match file ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway", "02-mysql"], + "appsFolders": [ + "01-gateway", + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -9132,6 +9169,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -9151,12 +9189,15 @@ kubectl scale deployment --replicas The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` -kubectl set image deployment/-app = +kubectl set image deployment/-app = \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + + + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -9170,6 +9211,7 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` > my applications are starting very slow, despite I have a cluster with many resources The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! + ", "stateCleared": "modified", }, @@ -9207,63 +9249,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -9275,7 +9317,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -9296,34 +9338,34 @@ spec: app: jhgate-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: jhgate-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: jhgate-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -9334,7 +9376,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -9351,8 +9393,8 @@ spec: app: jhgate type: LoadBalancer ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -9418,18 +9460,19 @@ logSummary "contents": "commonLabels: app.kubernetes.io/genereted-by: JHipster + resources: - # Individual apps - - jhgate-k8s/jhgate-deployment.yml - - jhgate-k8s/jhgate-service.yml - - jhgate-k8s/jhgate-mysql.yml - - msmysql-k8s/msmysql-deployment.yml - - msmysql-k8s/msmysql-service.yml - - msmysql-k8s/msmysql-mysql.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml +# Individual apps +- jhgate-k8s/jhgate-deployment.yml +- jhgate-k8s/jhgate-service.yml +- jhgate-k8s/jhgate-mysql.yml +- msmysql-k8s/msmysql-deployment.yml +- msmysql-k8s/msmysql-service.yml +- msmysql-k8s/msmysql-mysql.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -9469,61 +9512,61 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -9535,7 +9578,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -9556,34 +9599,34 @@ spec: app: msmysql-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: msmysql-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: msmysql-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -9594,7 +9637,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -9610,8 +9653,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -9653,23 +9696,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -9904,12 +9947,12 @@ spec: kind: Config build: artifacts: - - image: jhipster/jhgate - context: ./01-gateway - jib: {} - - image: jhipster/msmysql - context: ./02-mysql - jib: {} + - image: jhipster/jhgate + context: ./01-gateway + jib: {} + - image: jhipster/msmysql + context: ./02-mysql + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -9928,7 +9971,9 @@ exports[`generator - Kubernetes gateway with istio routing should match files sn ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -9984,6 +10029,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -10003,12 +10049,15 @@ kubectl scale deployment --replicas The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` -kubectl set image deployment/-app = +kubectl set image deployment/-app = \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + + + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -10022,6 +10071,7 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` > my applications are starting very slow, despite I have a cluster with many resources The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! + ", "stateCleared": "modified", }, @@ -10038,18 +10088,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - grafana.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - grafana.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - grafana.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - grafana.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -10058,16 +10108,16 @@ metadata: namespace: istio-system spec: hosts: - - grafana.istio-system.example.com + - grafana.istio-system.example.com gateways: - - grafana-observability-gateway + - grafana-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: grafana + - match: + - uri: + prefix: / + route: + - destination: + host: grafana ", "stateCleared": "modified", }, @@ -10084,18 +10134,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - kiali.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - kiali.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - kiali.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - kiali.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -10104,9 +10154,9 @@ metadata: namespace: istio-system spec: hosts: - - kiali.istio-system.example.com + - kiali.istio-system.example.com gateways: - - kiali-observability-gateway + - kiali-observability-gateway http: - route: - destination: @@ -10129,18 +10179,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - zipkin.istio-system.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - zipkin.istio-system.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - zipkin.istio-system.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - zipkin.istio-system.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -10149,16 +10199,16 @@ metadata: namespace: istio-system spec: hosts: - - zipkin.istio-system.example.com + - zipkin.istio-system.example.com gateways: - - zipkin-observability-gateway + - zipkin-observability-gateway http: - - match: - - uri: - prefix: / - route: - - destination: - host: zipkin + - match: + - uri: + prefix: / + route: + - destination: + host: zipkin ", "stateCleared": "modified", }, @@ -10196,69 +10246,69 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS - value: "false" - - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME - value: jhgate - - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME - value: jhgate - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS + value: "false" + - name: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME + value: jhgate + - name: SPRING_CLOUD_CONSUL_DISCOVERY_SERVICE_NAME + value: jhgate + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -10287,9 +10337,9 @@ spec: interval: 30s baseEjectionTime: 60s subsets: - - name: v1 - labels: - version: "v1" + - name: v1 + labels: + version: "v1" ", "stateCleared": "modified", }, @@ -10309,18 +10359,18 @@ spec: selector: istio: ingressgateway servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - jhgate.default.example.com - - port: - number: 80 - name: http2 - protocol: HTTP2 - hosts: - - jhgate.default.example.com + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - jhgate.default.example.com + - port: + number: 80 + name: http2 + protocol: HTTP2 + hosts: + - jhgate.default.example.com --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService @@ -10331,13 +10381,13 @@ metadata: service: jhgate-gw-virtualservice spec: hosts: - - jhgate.default.example.com + - jhgate.default.example.com gateways: - - jhgate-gateway + - jhgate-gateway http: - - route: - - destination: - host: jhgate + - route: + - destination: + host: jhgate ", "stateCleared": "modified", }, @@ -10349,7 +10399,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -10372,34 +10422,34 @@ spec: sidecar.istio.io/inject: "false" spec: volumes: - - name: data - persistentVolumeClaim: - claimName: jhgate-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: jhgate-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -10410,7 +10460,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -10425,10 +10475,10 @@ metadata: spec: selector: app: jhgate - type: + type: ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -10440,16 +10490,16 @@ metadata: namespace: default spec: hosts: - - jhgate + - jhgate http: - - route: - - destination: - host: jhgate - subset: "v1" - weight: 100 - retries: - attempts: 3 - perTryTimeout: 2s + - route: + - destination: + host: jhgate + subset: "v1" + weight: 100 + retries: + attempts: 3 + perTryTimeout: 2s ", "stateCleared": "modified", }, @@ -10518,71 +10568,72 @@ logSummary "contents": "commonLabels: app.kubernetes.io/genereted-by: JHipster + resources: - # Individual apps - - jhgate-k8s/jhgate-deployment.yml - - jhgate-k8s/jhgate-service.yml - - jhgate-k8s/jhgate-mysql.yml - - jhgate-k8s/jhgate-gateway.yml - - jhgate-k8s/jhgate-destination-rule.yml - - jhgate-k8s/jhgate-virtual-service.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml - # istio - - istio-k8s/grafana-gateway.yml - - istio-k8s/zipkin-gateway.yml - - istio-k8s/kiali-gateway.yml +# Individual apps +- jhgate-k8s/jhgate-deployment.yml +- jhgate-k8s/jhgate-service.yml +- jhgate-k8s/jhgate-mysql.yml +- jhgate-k8s/jhgate-gateway.yml +- jhgate-k8s/jhgate-destination-rule.yml +- jhgate-k8s/jhgate-virtual-service.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml +# istio +- istio-k8s/grafana-gateway.yml +- istio-k8s/zipkin-gateway.yml +- istio-k8s/kiali-gateway.yml patchesJson6902: - - target: - version: v1 - kind: Namespace - name: default - path: patch-k8s/istio-label.yml - - target: - group: networking.istio.io - version: v1alpha3 - kind: Gateway - name: grafana-observability-gateway - namespace: default - path: patch-k8s/istio-namespace.yml - - target: - group: networking.istio.io - version: v1alpha3 - name: grafana-gw-virtualservice - kind: VirtualService - namespace: default - path: patch-k8s/istio-namespace.yml - - target: - group: networking.istio.io - version: v1alpha3 - kind: Gateway - name: kiali-observability-gateway - namespace: default - path: patch-k8s/istio-namespace.yml - - target: - group: networking.istio.io - version: v1alpha3 - name: kiali-gw-virtualservice - kind: VirtualService - namespace: default - path: patch-k8s/istio-namespace.yml - - target: - group: networking.istio.io - version: v1alpha3 - kind: Gateway - name: zipkin-observability-gateway - namespace: default - path: patch-k8s/istio-namespace.yml - - target: - group: networking.istio.io - version: v1alpha3 - name: zipkin-gw-virtualservice - kind: VirtualService - namespace: default - path: patch-k8s/istio-namespace.yml +- target: + version: v1 + kind: Namespace + name: default + path: patch-k8s/istio-label.yml +- target: + group: networking.istio.io + version: v1alpha3 + kind: Gateway + name: grafana-observability-gateway + namespace: default + path: patch-k8s/istio-namespace.yml +- target: + group: networking.istio.io + version: v1alpha3 + name: grafana-gw-virtualservice + kind: VirtualService + namespace: default + path: patch-k8s/istio-namespace.yml +- target: + group: networking.istio.io + version: v1alpha3 + kind: Gateway + name: kiali-observability-gateway + namespace: default + path: patch-k8s/istio-namespace.yml +- target: + group: networking.istio.io + version: v1alpha3 + name: kiali-gw-virtualservice + kind: VirtualService + namespace: default + path: patch-k8s/istio-namespace.yml +- target: + group: networking.istio.io + version: v1alpha3 + kind: Gateway + name: zipkin-observability-gateway + namespace: default + path: patch-k8s/istio-namespace.yml +- target: + group: networking.istio.io + version: v1alpha3 + name: zipkin-gw-virtualservice + kind: VirtualService + namespace: default + path: patch-k8s/istio-namespace.yml ", "stateCleared": "modified", }, @@ -10638,23 +10689,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -10891,9 +10942,9 @@ spec: kind: Config build: artifacts: - - image: jhipster/jhgate - context: ./01-gateway - jib: {} + - image: jhipster/jhgate + context: ./01-gateway + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -10996,6 +11047,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -11015,12 +11067,15 @@ kubectl scale deployment --replicas The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` -kubectl set image deployment/-app = +kubectl set image deployment/-app = \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + + + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -11034,6 +11089,7 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` > my applications are starting very slow, despite I have a cluster with many resources The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! + ", "stateCleared": "modified", }, @@ -11071,63 +11127,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -11139,7 +11195,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -11160,34 +11216,34 @@ spec: app: jhgate-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: jhgate-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: jhgate-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -11198,7 +11254,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -11215,8 +11271,8 @@ spec: app: jhgate type: LoadBalancer ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -11286,31 +11342,32 @@ logSummary "contents": "commonLabels: app.kubernetes.io/genereted-by: JHipster + resources: - # Individual apps - - jhgate-k8s/jhgate-deployment.yml - - jhgate-k8s/jhgate-service.yml - - jhgate-k8s/jhgate-mysql.yml - - msmysql-k8s/msmysql-deployment.yml - - msmysql-k8s/msmysql-service.yml - - msmysql-k8s/msmysql-mysql.yml - - mspsql-k8s/mspsql-deployment.yml - - mspsql-k8s/mspsql-service.yml - - mspsql-k8s/mspsql-postgresql.yml - - mspsql-k8s/mspsql-elasticsearch.yml - - msmongodb-k8s/msmongodb-deployment.yml - - msmongodb-k8s/msmongodb-service.yml - - msmongodb-k8s/msmongodb-mongodb.yml - - msmariadb-k8s/msmariadb-deployment.yml - - msmariadb-k8s/msmariadb-service.yml - - msmariadb-k8s/msmariadb-mariadb.yml - - msmssqldb-k8s/msmssqldb-deployment.yml - - msmssqldb-k8s/msmssqldb-service.yml - - msmssqldb-k8s/msmssqldb-mssql.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml +# Individual apps +- jhgate-k8s/jhgate-deployment.yml +- jhgate-k8s/jhgate-service.yml +- jhgate-k8s/jhgate-mysql.yml +- msmysql-k8s/msmysql-deployment.yml +- msmysql-k8s/msmysql-service.yml +- msmysql-k8s/msmysql-mysql.yml +- mspsql-k8s/mspsql-deployment.yml +- mspsql-k8s/mspsql-service.yml +- mspsql-k8s/mspsql-postgresql.yml +- mspsql-k8s/mspsql-elasticsearch.yml +- msmongodb-k8s/msmongodb-deployment.yml +- msmongodb-k8s/msmongodb-service.yml +- msmongodb-k8s/msmongodb-mongodb.yml +- msmariadb-k8s/msmariadb-deployment.yml +- msmariadb-k8s/msmariadb-service.yml +- msmariadb-k8s/msmariadb-mariadb.yml +- msmssqldb-k8s/msmssqldb-deployment.yml +- msmssqldb-k8s/msmssqldb-service.yml +- msmssqldb-k8s/msmssqldb-mssql.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -11350,66 +11407,66 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmariadb-mariadb 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmariadb-mariadb 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmariadb-app - image: jhipster/msmariadb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false - - name: SPRING_LIQUIBASE_URL - value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: msmariadb-mariadb - key: mariadb-root-password - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmariadb-app + image: jhipster/msmariadb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false + - name: SPRING_LIQUIBASE_URL + value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: msmariadb-mariadb + key: mariadb-root-password + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -11421,7 +11478,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -11453,38 +11510,38 @@ spec: app: msmariadb-mariadb spec: volumes: - - name: data - persistentVolumeClaim: - claimName: msmariadb-mariadb-pvc + - name: data + persistentVolumeClaim: + claimName: msmariadb-mariadb-pvc containers: - - name: mariadb - image: mariadb-placeholder - env: - - name: MYSQL_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: msmariadb-mariadb - key: mariadb-root-password - - name: MYSQL_DATABASE - value: msmariadb - # command: - # - mysqld - # - --lower_case_table_names=1 - # - --skip-ssl - # - --character_set_server=utf8mb4 - # - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mariadb + image: mariadb-placeholder + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: msmariadb-mariadb + key: mariadb-root-password + - name: MYSQL_DATABASE + value: msmariadb +# command: +# - mysqld +# - --lower_case_table_names=1 +# - --skip-ssl +# - --character_set_server=utf8mb4 +# - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -11495,7 +11552,7 @@ spec: selector: app: msmariadb-mariadb ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -11511,8 +11568,8 @@ spec: selector: app: msmariadb ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -11550,59 +11607,59 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmongodb-mongodb 27017) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmongodb-mongodb 27017) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmongodb-app - image: jhipster/msmongodb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATA_MONGODB_URI - value: "mongodb://msmongodb-mongodb-0.msmongodb-mongodb.default:27017/msmongodb" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmongodb-app + image: jhipster/msmongodb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATA_MONGODB_URI + value: "mongodb://msmongodb-mongodb-0.msmongodb-mongodb.default:27017/msmongodb" + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -11909,7 +11966,7 @@ spec: - metadata: name: datadir spec: - accessModes: ["ReadWriteOnce"] + accessModes: [ "ReadWriteOnce" ] resources: requests: storage: "1Gi" @@ -11944,8 +12001,8 @@ spec: selector: app: msmongodb ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -11983,56 +12040,56 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmssqldb-app - image: jhipster/msmssqldb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmssqldb-app + image: jhipster/msmssqldb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -12044,7 +12101,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -12065,37 +12122,37 @@ spec: app: msmssqldb-mssql spec: volumes: - - name: mssqldb - persistentVolumeClaim: - claimName: mssql-data - - name: data - persistentVolumeClaim: - claimName: msmssqldb-mssql-pvc + - name: mssqldb + persistentVolumeClaim: + claimName: mssql-data + - name: data + persistentVolumeClaim: + claimName: msmssqldb-mssql-pvc containers: - - name: mysql - image: mssql-placeholder - env: - - name: MSSQL_PID - value: "Express" - - name: ACCEPT_EULA - value: "Y" - - name: MSSQL_SA_PASSWORD - valueFrom: - secretKeyRef: - name: mssql - key: SA_PASSWORD - ports: - - containerPort: 1433 - volumeMounts: - - name: mssqldb - mountPath: /var/opt/mssql - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mssql-placeholder + env: + - name: MSSQL_PID + value: "Express" + - name: ACCEPT_EULA + value: "Y" + - name: MSSQL_SA_PASSWORD + valueFrom: + secretKeyRef: + name: mssql + key: SA_PASSWORD + ports: + - containerPort: 1433 + volumeMounts: + - name: mssqldb + mountPath: /var/opt/mssql + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 @@ -12118,7 +12175,7 @@ metadata: name: mssql-data spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce storageClassName: managed-premium resources: requests: @@ -12138,8 +12195,8 @@ spec: selector: app: msmssqldb ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -12177,61 +12234,61 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -12243,7 +12300,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -12264,34 +12321,34 @@ spec: app: msmysql-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: msmysql-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: msmysql-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -12302,7 +12359,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -12318,8 +12375,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -12357,70 +12414,70 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 mspsql-postgresql 5432) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 mspsql-postgresql 5432) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: mspsql-app - image: jhipster/mspsql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_DATASOURCE_USERNAME - value: mspsql - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - - name: SPRING_LIQUIBASE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: mspsql-app + image: jhipster/mspsql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_DATASOURCE_USERNAME + value: mspsql + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + - name: SPRING_LIQUIBASE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -12432,7 +12489,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -12455,41 +12512,41 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - persistentVolumeClaim: - claimName: mspsql-elasticsearch-pvc + - name: data + persistentVolumeClaim: + claimName: mspsql-elasticsearch-pvc initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -12500,12 +12557,12 @@ spec: selector: app: mspsql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -12517,7 +12574,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -12549,33 +12606,33 @@ spec: app: mspsql-postgresql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: mspsql-postgresql-pvc + - name: data + persistentVolumeClaim: + claimName: mspsql-postgresql-pvc containers: - - name: postgres - image: postgresql-placeholder - env: - - name: POSTGRES_USER - value: mspsql - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - ports: - - containerPort: 5432 - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - subPath: postgres - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: postgres + image: postgresql-placeholder + env: + - name: POSTGRES_USER + value: mspsql + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + ports: + - containerPort: 5432 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + subPath: postgres + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -12586,7 +12643,7 @@ spec: selector: app: mspsql-postgresql ports: - - port: 5432 + - port: 5432 ", "stateCleared": "modified", }, @@ -12602,8 +12659,8 @@ spec: selector: app: mspsql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -12645,23 +12702,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -12896,24 +12953,24 @@ spec: kind: Config build: artifacts: - - image: jhipster/jhgate - context: ./01-gateway - jib: {} - - image: jhipster/msmysql - context: ./02-mysql - jib: {} - - image: jhipster/mspsql - context: ./03-psql - jib: {} - - image: jhipster/msmongodb - context: ./04-mongo - jib: {} - - image: jhipster/msmariadb - context: ./07-mariadb - jib: {} - - image: jhipster/msmssqldb - context: ./11-mssql - jib: {} + - image: jhipster/jhgate + context: ./01-gateway + jib: {} + - image: jhipster/msmysql + context: ./02-mysql + jib: {} + - image: jhipster/mspsql + context: ./03-psql + jib: {} + - image: jhipster/msmongodb + context: ./04-mongo + jib: {} + - image: jhipster/msmariadb + context: ./07-mariadb + jib: {} + - image: jhipster/msmssqldb + context: ./11-mssql + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -12932,7 +12989,9 @@ exports[`generator - Kubernetes monolith application should match files snapshot ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["08-monolith"], + "appsFolders": [ + "08-monolith" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "monolith", @@ -12987,6 +13046,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -13006,12 +13066,15 @@ kubectl scale deployment --replicas The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` -kubectl set image deployment/-app = +kubectl set image deployment/-app = \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + + + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -13025,6 +13088,7 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` > my applications are starting very slow, despite I have a cluster with many resources The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! + ", "stateCleared": "modified", }, @@ -13088,12 +13152,13 @@ logSummary "contents": "commonLabels: app.kubernetes.io/genereted-by: JHipster + resources: - # Individual apps - - samplemysql-k8s/samplemysql-deployment.yml - - samplemysql-k8s/samplemysql-service.yml - - samplemysql-k8s/samplemysql-mysql.yml - - samplemysql-k8s/samplemysql-elasticsearch.yml +# Individual apps +- samplemysql-k8s/samplemysql-deployment.yml +- samplemysql-k8s/samplemysql-service.yml +- samplemysql-k8s/samplemysql-mysql.yml +- samplemysql-k8s/samplemysql-elasticsearch.yml # service discovery eureka/consul patchesJson6902: @@ -13134,57 +13199,57 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 samplemysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 samplemysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: samplemysql-app - image: jhipster/samplemysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://samplemysql-mysql.default.svc.cluster.local:3306/samplemysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://samplemysql-mysql.default.svc.cluster.local:3306/samplemysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://samplemysql-elasticsearch.default.svc.cluster.local:9200 - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: samplemysql-app + image: jhipster/samplemysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://samplemysql-mysql.default.svc.cluster.local:3306/samplemysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://samplemysql-mysql.default.svc.cluster.local:3306/samplemysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://samplemysql-elasticsearch.default.svc.cluster.local:9200 + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -13196,7 +13261,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -13219,41 +13284,41 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - persistentVolumeClaim: - claimName: samplemysql-elasticsearch-pvc + - name: data + persistentVolumeClaim: + claimName: samplemysql-elasticsearch-pvc initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -13264,12 +13329,12 @@ spec: selector: app: samplemysql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -13281,7 +13346,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -13302,34 +13367,34 @@ spec: app: samplemysql-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: samplemysql-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: samplemysql-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: samplemysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: samplemysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -13340,7 +13405,7 @@ spec: selector: app: samplemysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -13357,9 +13422,9 @@ spec: app: samplemysql type: LoadBalancer ports: - - name: http - port: 80 - targetPort: 8080 + - name: http + port: 80 + targetPort: 8080 ", "stateCleared": "modified", }, @@ -13368,9 +13433,9 @@ spec: kind: Config build: artifacts: - - image: jhipster/samplemysql - context: ./08-monolith - jib: {} + - image: jhipster/samplemysql + context: ./08-monolith + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -13389,7 +13454,9 @@ exports[`generator - Kubernetes mysql microservice with custom namespace and jhi ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql"], + "appsFolders": [ + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -13445,6 +13512,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + \`\`\` ## Scaling your deployments @@ -13452,9 +13520,7 @@ skaffold run [or] skaffold deploy You can scale your apps using: \`\`\` - kubectl scale deployment --replicas -n mynamespace - \`\`\` ## Zero-downtime deployments @@ -13462,9 +13528,7 @@ kubectl scale deployment --replicas -n mynamespace The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` - -kubectl set image deployment/-app = -n mynamespace - +kubectl set image deployment/-app = -n mynamespace \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. @@ -13481,17 +13545,13 @@ Generator is also packaged with [Prometheus operator by CoreOS](https://github.c Application metrics can be explored in Prometheus through: \`\`\` - kubectl get svc jhipster-prometheus -n mynamespace - \`\`\` Also the visualisation can be explored in Grafana which is pre-configured with a dashboard view. You can find the service details by running: \`\`\` - kubectl get svc jhipster-grafana -n mynamespace - \`\`\` * If you have chosen *Ingress*, then you should be able to access Grafana using the given ingress domain. @@ -13515,7 +13575,6 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! -\`\`\` ", "stateCleared": "modified", }, @@ -13596,21 +13655,21 @@ logSummary namespace: mynamespace resources: - - namespace.yml - # Individual apps - - msmysql-k8s/msmysql-deployment.yml - - msmysql-k8s/msmysql-service.yml - - msmysql-k8s/msmysql-mysql.yml - - msmysql-k8s/msmysql-prometheus-sm.yml - # monitoring prometheus - - monitoring-k8s/jhipster-prometheus-cr.yml - - monitoring-k8s/jhipster-prometheus-crd.yml - - monitoring-k8s/jhipster-grafana.yml - - monitoring-k8s/jhipster-grafana-dashboard.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml +- namespace.yml +# Individual apps +- msmysql-k8s/msmysql-deployment.yml +- msmysql-k8s/msmysql-service.yml +- msmysql-k8s/msmysql-mysql.yml +- msmysql-k8s/msmysql-prometheus-sm.yml +# monitoring prometheus +- monitoring-k8s/jhipster-prometheus-cr.yml +- monitoring-k8s/jhipster-prometheus-crd.yml +- monitoring-k8s/jhipster-grafana.yml +- monitoring-k8s/jhipster-grafana-dashboard.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -15917,51 +15976,52 @@ spec: - name: init-dependent-services-check image: busybox command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - until nc -z -w 1 jhipster-prometheus 9090 - do - echo Waiting for prometheus to get initialized - sleep 5 - done - until nc -z -w 1 jhipster-grafana 3000 - do - echo Waiting for grafana to get initialized - sleep 5 - done + until nc -z -w 1 jhipster-prometheus 9090 + do + echo Waiting for prometheus to get initialized + sleep 5 + done + until nc -z -w 1 jhipster-grafana 3000 + do + echo Waiting for grafana to get initialized + sleep 5 + done containers: - - name: grafana-configurer - image: grafana-watcher-placeholder - args: - - "--watch-dir=/var/grafana-dashboard" - - "--grafana-url=http://jhipster-grafana:3000" - env: - - name: GRAFANA_USER - valueFrom: - secretKeyRef: - name: jhipster-grafana-credentials - key: username - - name: GRAFANA_PASSWORD - valueFrom: - secretKeyRef: - name: jhipster-grafana-credentials - key: password - resources: - requests: - memory: "16Mi" - cpu: "50m" - limits: - memory: "32Mi" - cpu: "100m" - volumeMounts: - - name: grafana-dashboard - mountPath: /var/grafana-dashboard - volumes: + - name: grafana-configurer + image: grafana-watcher-placeholder + args: + - '--watch-dir=/var/grafana-dashboard' + - '--grafana-url=http://jhipster-grafana:3000' + env: + - name: GRAFANA_USER + valueFrom: + secretKeyRef: + name: jhipster-grafana-credentials + key: username + - name: GRAFANA_PASSWORD + valueFrom: + secretKeyRef: + name: jhipster-grafana-credentials + key: password + resources: + requests: + memory: "16Mi" + cpu: "50m" + limits: + memory: "32Mi" + cpu: "100m" + volumeMounts: - name: grafana-dashboard - configMap: - name: jhipster-grafana-dashboard + mountPath: /var/grafana-dashboard + volumes: + - name: grafana-dashboard + configMap: + name: jhipster-grafana-dashboard restartPolicy: OnFailure + ", "stateCleared": "modified", }, @@ -15991,38 +16051,38 @@ spec: app: jhipster-grafana spec: containers: - - name: jhipster-grafana - image: grafana-placeholder - ports: - - containerPort: 3000 - name: http - protocol: TCP - env: - - name: GF_SECURITY_ADMIN_USER - valueFrom: - secretKeyRef: - name: jhipster-grafana-credentials - key: username - - name: GF_SECURITY_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - name: jhipster-grafana-credentials - key: password - - name: GF_USERS_ALLOW_SIGN_UP - value: "false" - resources: - requests: - memory: "100Mi" - cpu: "100m" - limits: - memory: "250Mi" - cpu: "200m" - volumeMounts: - - name: grafana-storage - mountPath: /var/grafana-storage - volumes: + - name: jhipster-grafana + image: grafana-placeholder + ports: + - containerPort: 3000 + name: http + protocol: TCP + env: + - name: GF_SECURITY_ADMIN_USER + valueFrom: + secretKeyRef: + name: jhipster-grafana-credentials + key: username + - name: GF_SECURITY_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: jhipster-grafana-credentials + key: password + - name: GF_USERS_ALLOW_SIGN_UP + value: "false" + resources: + requests: + memory: "100Mi" + cpu: "100m" + limits: + memory: "250Mi" + cpu: "200m" + volumeMounts: - name: grafana-storage - emptyDir: {} + mountPath: /var/grafana-storage + volumes: + - name: grafana-storage + emptyDir: {} restartPolicy: Always --- apiVersion: v1 @@ -16034,14 +16094,13 @@ metadata: app: jhipster-grafana spec: ports: - - name: http - port: 3000 - targetPort: 3000 + - name: http + port: 3000 + targetPort: 3000 type: LoadBalancer selector: app: jhipster-grafana --- - ", "stateCleared": "modified", }, @@ -16058,17 +16117,17 @@ metadata: name: jhipster-prometheus-role namespace: mynamespace rules: - - apiGroups: [""] - resources: - - nodes - - services - - endpoints - - pods - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: - - configmaps - verbs: ["get"] +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1beta1 # limit to the namespace @@ -16081,8 +16140,8 @@ roleRef: kind: Role name: jhipster-prometheus-role subjects: - - kind: ServiceAccount - name: jhipster-prometheus-sa +- kind: ServiceAccount + name: jhipster-prometheus-sa --- apiVersion: monitoring.coreos.com/v1 kind: Prometheus @@ -16106,10 +16165,10 @@ metadata: namespace: mynamespace spec: ports: - - name: web - port: 9090 - protocol: TCP - targetPort: web + - name: web + port: 9090 + protocol: TCP + targetPort: web selector: prometheus: jhipster-prometheus ", @@ -16121,54 +16180,54 @@ kind: ClusterRole metadata: name: jhipster-prometheus-operator-cr rules: - - apiGroups: - - extensions - resources: - - thirdpartyresources - verbs: - - "*" - - apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - "*" - - apiGroups: - - monitoring.coreos.com - resources: - - alertmanagers - - prometheuses - - servicemonitors - - prometheusrules - verbs: - - "*" - - apiGroups: - - apps - resources: - - statefulsets - verbs: ["*"] - - apiGroups: [""] - resources: - - configmaps - - secrets - verbs: ["*"] - - apiGroups: [""] - resources: - - pods - verbs: ["list", "delete"] - - apiGroups: [""] - resources: - - services - - endpoints - verbs: ["get", "create", "update"] - - apiGroups: [""] - resources: - - nodes - verbs: ["list", "watch"] - - apiGroups: [""] - resources: - - namespaces - verbs: ["list", "watch"] +- apiGroups: + - extensions + resources: + - thirdpartyresources + verbs: + - "*" +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - "*" +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - prometheuses + - servicemonitors + - prometheusrules + verbs: + - "*" +- apiGroups: + - apps + resources: + - statefulsets + verbs: ["*"] +- apiGroups: [""] + resources: + - configmaps + - secrets + verbs: ["*"] +- apiGroups: [""] + resources: + - pods + verbs: ["list", "delete"] +- apiGroups: [""] + resources: + - services + - endpoints + verbs: ["get", "create", "update"] +- apiGroups: [""] + resources: + - nodes + verbs: ["list", "watch"] +- apiGroups: [""] + resources: + - namespaces + verbs: ["list", "watch"] --- apiVersion: v1 kind: ServiceAccount @@ -16186,9 +16245,9 @@ roleRef: kind: ClusterRole name: jhipster-prometheus-operator-cr subjects: - - kind: ServiceAccount - name: jhipster-prometheus-operator-sa - namespace: mynamespace +- kind: ServiceAccount + name: jhipster-prometheus-operator-sa + namespace: mynamespace --- apiVersion: apps/v1 kind: Deployment @@ -16208,21 +16267,21 @@ spec: k8s-app: prometheus-operator spec: containers: - - args: - - --kubelet-service=kube-system/kubelet - - --config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1 - image: prometheus-operator-placeholder - name: prometheus-operator - ports: - - containerPort: 8080 - name: http - resources: - limits: - cpu: 200m - memory: 100Mi - requests: - cpu: 100m - memory: 50Mi + - args: + - --kubelet-service=kube-system/kubelet + - --config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1 + image: prometheus-operator-placeholder + name: prometheus-operator + ports: + - containerPort: 8080 + name: http + resources: + limits: + cpu: 200m + memory: 100Mi + requests: + cpu: 100m + memory: 50Mi serviceAccountName: jhipster-prometheus-operator-sa ", "stateCleared": "modified", @@ -16261,63 +16320,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.mynamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED - value: "true" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.mynamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED + value: 'true' + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -16329,7 +16388,7 @@ metadata: namespace: mynamespace spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -16350,34 +16409,34 @@ spec: app: msmysql-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: msmysql-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: msmysql-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -16388,7 +16447,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -16405,8 +16464,8 @@ spec: matchLabels: app: msmysql endpoints: - - port: web - path: /prometheusMetrics + - port: web + path: /prometheusMetrics ", "stateCleared": "modified", }, @@ -16422,8 +16481,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -16432,6 +16491,7 @@ spec: kind: Namespace metadata: name: mynamespace + ", "stateCleared": "modified", }, @@ -16473,23 +16533,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.mynamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.mynamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -16724,9 +16784,9 @@ spec: kind: Config build: artifacts: - - image: jhipster/msmysql - context: ./02-mysql - jib: {} + - image: jhipster/msmysql + context: ./02-mysql + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -16745,7 +16805,9 @@ exports[`generator - Kubernetes mysql microservice with custom namespace should ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["02-mysql"], + "appsFolders": [ + "02-mysql" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "microservice", @@ -16801,6 +16863,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + \`\`\` ## Scaling your deployments @@ -16808,9 +16871,7 @@ skaffold run [or] skaffold deploy You can scale your apps using: \`\`\` - kubectl scale deployment --replicas -n mynamespace - \`\`\` ## Zero-downtime deployments @@ -16818,9 +16879,7 @@ kubectl scale deployment --replicas -n mynamespace The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` - -kubectl set image deployment/-app = -n mynamespace - +kubectl set image deployment/-app = -n mynamespace \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. @@ -16843,7 +16902,6 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! -\`\`\` ", "stateCleared": "modified", }, @@ -16912,15 +16970,15 @@ logSummary namespace: mynamespace resources: - - namespace.yml - # Individual apps - - msmysql-k8s/msmysql-deployment.yml - - msmysql-k8s/msmysql-service.yml - - msmysql-k8s/msmysql-mysql.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml +- namespace.yml +# Individual apps +- msmysql-k8s/msmysql-deployment.yml +- msmysql-k8s/msmysql-service.yml +- msmysql-k8s/msmysql-mysql.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -16960,61 +17018,61 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.mynamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.mynamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.mynamespace.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -17026,7 +17084,7 @@ metadata: namespace: mynamespace spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -17047,34 +17105,34 @@ spec: app: msmysql-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: msmysql-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: msmysql-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -17085,7 +17143,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -17101,8 +17159,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -17111,6 +17169,7 @@ spec: kind: Namespace metadata: name: mynamespace + ", "stateCleared": "modified", }, @@ -17152,23 +17211,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.mynamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.mynamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -17403,9 +17462,9 @@ spec: kind: Config build: artifacts: - - image: jhipster/msmysql - context: ./02-mysql - jib: {} + - image: jhipster/msmysql + context: ./02-mysql + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -17498,6 +17557,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -17517,12 +17577,15 @@ kubectl scale deployment --replicas The default way to update a running app in kubernetes, is to deploy a new image tag to your docker registry and then deploy it using: \`\`\` -kubectl set image deployment/-app = +kubectl set image deployment/-app = \`\`\` Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + + + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -17536,6 +17599,7 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` > my applications are starting very slow, despite I have a cluster with many resources The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! + ", "stateCleared": "modified", }, @@ -17573,63 +17637,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipster/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipster/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.default.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -17641,7 +17705,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -17662,34 +17726,34 @@ spec: app: jhgate-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: jhgate-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: jhgate-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -17700,7 +17764,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -17717,8 +17781,8 @@ spec: app: jhgate type: LoadBalancer ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -17788,31 +17852,32 @@ logSummary "contents": "commonLabels: app.kubernetes.io/genereted-by: JHipster + resources: - # Individual apps - - jhgate-k8s/jhgate-deployment.yml - - jhgate-k8s/jhgate-service.yml - - jhgate-k8s/jhgate-mysql.yml - - msmysql-k8s/msmysql-deployment.yml - - msmysql-k8s/msmysql-service.yml - - msmysql-k8s/msmysql-mysql.yml - - mspsql-k8s/mspsql-deployment.yml - - mspsql-k8s/mspsql-service.yml - - mspsql-k8s/mspsql-postgresql.yml - - mspsql-k8s/mspsql-elasticsearch.yml - - msmongodb-k8s/msmongodb-deployment.yml - - msmongodb-k8s/msmongodb-service.yml - - msmongodb-k8s/msmongodb-mongodb.yml - - msmariadb-k8s/msmariadb-deployment.yml - - msmariadb-k8s/msmariadb-service.yml - - msmariadb-k8s/msmariadb-mariadb.yml - - msmssqldb-k8s/msmssqldb-deployment.yml - - msmssqldb-k8s/msmssqldb-service.yml - - msmssqldb-k8s/msmssqldb-mssql.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml +# Individual apps +- jhgate-k8s/jhgate-deployment.yml +- jhgate-k8s/jhgate-service.yml +- jhgate-k8s/jhgate-mysql.yml +- msmysql-k8s/msmysql-deployment.yml +- msmysql-k8s/msmysql-service.yml +- msmysql-k8s/msmysql-mysql.yml +- mspsql-k8s/mspsql-deployment.yml +- mspsql-k8s/mspsql-service.yml +- mspsql-k8s/mspsql-postgresql.yml +- mspsql-k8s/mspsql-elasticsearch.yml +- msmongodb-k8s/msmongodb-deployment.yml +- msmongodb-k8s/msmongodb-service.yml +- msmongodb-k8s/msmongodb-mongodb.yml +- msmariadb-k8s/msmariadb-deployment.yml +- msmariadb-k8s/msmariadb-service.yml +- msmariadb-k8s/msmariadb-mariadb.yml +- msmssqldb-k8s/msmssqldb-deployment.yml +- msmssqldb-k8s/msmssqldb-service.yml +- msmssqldb-k8s/msmssqldb-mssql.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -17852,66 +17917,66 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmariadb-mariadb 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmariadb-mariadb 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmariadb-app - image: jhipster/msmariadb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false - - name: SPRING_LIQUIBASE_URL - value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: msmariadb-mariadb - key: mariadb-root-password - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmariadb-app + image: jhipster/msmariadb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false + - name: SPRING_LIQUIBASE_URL + value: jdbc:mariadb://msmariadb-mariadb.default.svc.cluster.local:3306/msmariadb?useLegacyDatetimeCode=false + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: msmariadb-mariadb + key: mariadb-root-password + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -17923,7 +17988,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -17955,38 +18020,38 @@ spec: app: msmariadb-mariadb spec: volumes: - - name: data - persistentVolumeClaim: - claimName: msmariadb-mariadb-pvc - containers: - - name: mariadb - image: mariadb-placeholder - env: - - name: MYSQL_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: msmariadb-mariadb - key: mariadb-root-password - - name: MYSQL_DATABASE - value: msmariadb - # command: - # - mysqld - # - --lower_case_table_names=1 - # - --skip-ssl - # - --character_set_server=utf8mb4 - # - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: data + persistentVolumeClaim: + claimName: msmariadb-mariadb-pvc + containers: + - name: mariadb + image: mariadb-placeholder + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: msmariadb-mariadb + key: mariadb-root-password + - name: MYSQL_DATABASE + value: msmariadb +# command: +# - mysqld +# - --lower_case_table_names=1 +# - --skip-ssl +# - --character_set_server=utf8mb4 +# - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -17997,7 +18062,7 @@ spec: selector: app: msmariadb-mariadb ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -18013,8 +18078,8 @@ spec: selector: app: msmariadb ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -18052,59 +18117,59 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmongodb-mongodb 27017) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmongodb-mongodb 27017) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmongodb-app - image: jhipster/msmongodb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATA_MONGODB_URI - value: "mongodb://msmongodb-mongodb-0.msmongodb-mongodb.default:27017/msmongodb" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmongodb-app + image: jhipster/msmongodb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATA_MONGODB_URI + value: "mongodb://msmongodb-mongodb-0.msmongodb-mongodb.default:27017/msmongodb" + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -18411,7 +18476,7 @@ spec: - metadata: name: datadir spec: - accessModes: ["ReadWriteOnce"] + accessModes: [ "ReadWriteOnce" ] resources: requests: storage: "1Gi" @@ -18446,8 +18511,8 @@ spec: selector: app: msmongodb ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -18485,56 +18550,56 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmssqldb-app - image: jhipster/msmssqldb - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmssqldb-app + image: jhipster/msmssqldb + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -18546,7 +18611,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -18567,37 +18632,37 @@ spec: app: msmssqldb-mssql spec: volumes: - - name: mssqldb - persistentVolumeClaim: - claimName: mssql-data - - name: data - persistentVolumeClaim: - claimName: msmssqldb-mssql-pvc + - name: mssqldb + persistentVolumeClaim: + claimName: mssql-data + - name: data + persistentVolumeClaim: + claimName: msmssqldb-mssql-pvc containers: - - name: mysql - image: mssql-placeholder - env: - - name: MSSQL_PID - value: "Express" - - name: ACCEPT_EULA - value: "Y" - - name: MSSQL_SA_PASSWORD - valueFrom: - secretKeyRef: - name: mssql - key: SA_PASSWORD - ports: - - containerPort: 1433 - volumeMounts: - - name: mssqldb - mountPath: /var/opt/mssql - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mssql-placeholder + env: + - name: MSSQL_PID + value: "Express" + - name: ACCEPT_EULA + value: "Y" + - name: MSSQL_SA_PASSWORD + valueFrom: + secretKeyRef: + name: mssql + key: SA_PASSWORD + ports: + - containerPort: 1433 + volumeMounts: + - name: mssqldb + mountPath: /var/opt/mssql + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 @@ -18620,7 +18685,7 @@ metadata: name: mssql-data spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce storageClassName: managed-premium resources: requests: @@ -18640,8 +18705,8 @@ spec: selector: app: msmssqldb ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -18679,61 +18744,61 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 msmysql-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 msmysql-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: msmysql-app - image: jhipster/msmysql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: msmysql-app + image: jhipster/msmysql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://msmysql-mysql.default.svc.cluster.local:3306/msmysql?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -18745,7 +18810,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -18766,34 +18831,34 @@ spec: app: msmysql-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: msmysql-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: msmysql-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: msmysql - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: msmysql + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -18804,7 +18869,7 @@ spec: selector: app: msmysql-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -18820,8 +18885,8 @@ spec: selector: app: msmysql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -18859,70 +18924,70 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 mspsql-postgresql 5432) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 mspsql-postgresql 5432) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: mspsql-app - image: jhipster/mspsql - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.default.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_DATASOURCE_USERNAME - value: mspsql - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - - name: SPRING_LIQUIBASE_URL - value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql - - name: SPRING_ELASTICSEARCH_REST_URIS - value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8081 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: mspsql-app + image: jhipster/mspsql + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.default.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_DATASOURCE_USERNAME + value: mspsql + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + - name: SPRING_LIQUIBASE_URL + value: jdbc:postgresql://mspsql-postgresql.default.svc.cluster.local:5432/mspsql + - name: SPRING_ELASTICSEARCH_REST_URIS + value: http://mspsql-elasticsearch.default.svc.cluster.local:9200 + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8081 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -18934,7 +18999,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -18957,41 +19022,41 @@ spec: securityContext: fsGroup: 1000 volumes: - - name: data - persistentVolumeClaim: - claimName: mspsql-elasticsearch-pvc + - name: data + persistentVolumeClaim: + claimName: mspsql-elasticsearch-pvc initContainers: - - name: init-sysctl - image: busybox - command: - - sysctl - - -w - - vm.max_map_count=262144 - securityContext: - privileged: true + - name: init-sysctl + image: busybox + command: + - sysctl + - -w + - vm.max_map_count=262144 + securityContext: + privileged: true containers: - - name: elasticsearch - image: elasticsearch-placeholder - env: - - name: discovery.type - value: single-node - ports: - - containerPort: 9200 - name: http - protocol: TCP - - containerPort: 9300 - name: transport - protocol: TCP - volumeMounts: - - name: data - mountPath: /usr/share/elasticsearch/data/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" + - name: elasticsearch + image: elasticsearch-placeholder + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + - containerPort: 9300 + name: transport + protocol: TCP + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -19002,12 +19067,12 @@ spec: selector: app: mspsql-elasticsearch ports: - - port: 9200 - name: http - protocol: TCP - - port: 9300 - name: transport - protocol: TCP + - port: 9200 + name: http + protocol: TCP + - port: 9300 + name: transport + protocol: TCP ", "stateCleared": "modified", }, @@ -19019,7 +19084,7 @@ metadata: namespace: default spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -19051,33 +19116,33 @@ spec: app: mspsql-postgresql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: mspsql-postgresql-pvc + - name: data + persistentVolumeClaim: + claimName: mspsql-postgresql-pvc containers: - - name: postgres - image: postgresql-placeholder - env: - - name: POSTGRES_USER - value: mspsql - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: mspsql-postgresql - key: postgresql-password - ports: - - containerPort: 5432 - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - subPath: postgres - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: postgres + image: postgresql-placeholder + env: + - name: POSTGRES_USER + value: mspsql + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: mspsql-postgresql + key: postgresql-password + ports: + - containerPort: 5432 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + subPath: postgres + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -19088,7 +19153,7 @@ spec: selector: app: mspsql-postgresql ports: - - port: 5432 + - port: 5432 ", "stateCleared": "modified", }, @@ -19104,8 +19169,8 @@ spec: selector: app: mspsql ports: - - name: http - port: 8081 + - name: http + port: 8081 ", "stateCleared": "modified", }, @@ -19147,23 +19212,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.default.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.default.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -19398,24 +19463,24 @@ spec: kind: Config build: artifacts: - - image: jhipster/jhgate - context: ./01-gateway - jib: {} - - image: jhipster/msmysql - context: ./02-mysql - jib: {} - - image: jhipster/mspsql - context: ./03-psql - jib: {} - - image: jhipster/msmongodb - context: ./04-mongo - jib: {} - - image: jhipster/msmariadb - context: ./07-mariadb - jib: {} - - image: jhipster/msmssqldb - context: ./11-mssql - jib: {} + - image: jhipster/jhgate + context: ./01-gateway + jib: {} + - image: jhipster/msmysql + context: ./02-mysql + jib: {} + - image: jhipster/mspsql + context: ./03-psql + jib: {} + - image: jhipster/msmongodb + context: ./04-mongo + jib: {} + - image: jhipster/msmariadb + context: ./07-mariadb + jib: {} + - image: jhipster/msmssqldb + context: ./11-mssql + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -19434,7 +19499,9 @@ exports[`generator - Kubernetes only gateway should match files snapshot 1`] = ` ".yo-rc.json": { "contents": "{ "generator-jhipster": { - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "gateway", @@ -19490,6 +19557,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -19515,6 +19583,9 @@ kubectl set image deployment/-app = -n jhipstern Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + + + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -19528,6 +19599,7 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` > my applications are starting very slow, despite I have a cluster with many resources The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! + ", "stateCleared": "modified", }, @@ -19565,63 +19637,63 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipsterrepository/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONSUL_HOST - value: consul-headless.jhipsternamespace.svc.cluster.local - - name: SPRING_CLOUD_CONSUL_PORT - value: "8500" - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipsterrepository/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONSUL_HOST + value: consul-headless.jhipsternamespace.svc.cluster.local + - name: SPRING_CLOUD_CONSUL_PORT + value: "8500" + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -19633,7 +19705,7 @@ metadata: namespace: jhipsternamespace spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -19654,34 +19726,34 @@ spec: app: jhgate-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: jhgate-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: jhgate-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -19692,7 +19764,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -19709,8 +19781,8 @@ spec: app: jhgate type: LoadBalancer ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -19779,15 +19851,15 @@ logSummary namespace: jhipsternamespace resources: - - namespace.yml - # Individual apps - - jhgate-k8s/jhgate-deployment.yml - - jhgate-k8s/jhgate-service.yml - - jhgate-k8s/jhgate-mysql.yml - # service discovery eureka/consul - - registry-k8s/consul.yml - - registry-k8s/consul-config-loader.yml - - registry-k8s/application-configmap.yml +- namespace.yml +# Individual apps +- jhgate-k8s/jhgate-deployment.yml +- jhgate-k8s/jhgate-service.yml +- jhgate-k8s/jhgate-mysql.yml +# service discovery eureka/consul +- registry-k8s/consul.yml +- registry-k8s/consul-config-loader.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -19798,6 +19870,7 @@ patchesJson6902: kind: Namespace metadata: name: jhipsternamespace + ", "stateCleared": "modified", }, @@ -19839,23 +19912,23 @@ spec: app: consul-config-loader spec: containers: - - name: consul-config-loader - image: consul-config-loader-placeholder - imagePullPolicy: IfNotPresent - env: - - name: INIT_SLEEP_SECONDS - value: "5" - - name: CONSUL_URL - value: consul-headless.jhipsternamespace.svc.cluster.local - - name: CONSUL_PORT - value: "8500" - volumeMounts: - - name: config-volume - mountPath: /config - volumes: + - name: consul-config-loader + image: consul-config-loader-placeholder + imagePullPolicy: IfNotPresent + env: + - name: INIT_SLEEP_SECONDS + value: "5" + - name: CONSUL_URL + value: consul-headless.jhipsternamespace.svc.cluster.local + - name: CONSUL_PORT + value: "8500" + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -20090,9 +20163,9 @@ spec: kind: Config build: artifacts: - - image: jhipsterrepository/jhgate - context: ./01-gateway - jib: {} + - image: jhipsterrepository/jhgate + context: ./01-gateway + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" @@ -20112,7 +20185,9 @@ exports[`generator - Kubernetes only gateway with eureka should match files snap "contents": "{ "generator-jhipster": { "adminPassword": "meetup", - "appsFolders": ["01-gateway"], + "appsFolders": [ + "01-gateway" + ], "baseName": "workspaces", "dbRandomPassword": "SECRET-PASSWORD", "deploymentApplicationType": "monolith", @@ -20167,6 +20242,7 @@ skaffold run [or] skaffold deploy ## Exploring your services + Use these commands to find your application's IP addresses: \`\`\` @@ -20192,6 +20268,7 @@ kubectl set image deployment/-app = -n jhipstern Using livenessProbes and readinessProbe allow you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of two replicas for every application deployment if you want to have zero-downtime. This is because the rolling upgrade strategy first stops a running replica in order to place a new. Running only one replica, will cause a short downtime during upgrades. + ## JHipster Registry The registry is deployed using a headless service in Kubernetes, so the primary service has no IP address, and cannot get a node port. You can create a secondary service for any type, using: @@ -20212,6 +20289,7 @@ For scaling the JHipster registry, use: kubectl scale statefulset jhipster-registry --replicas 3 -n jhipsternamespace \`\`\` + ## Troubleshooting > my app doesn't get pulled, because of 'imagePullBackof' @@ -20225,6 +20303,7 @@ This can occur if your cluster has low resource (e.g. Minikube). Increase the \` > my applications are starting very slow, despite I have a cluster with many resources The default setting are optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, and resource requests and limits to improve the performance. Be careful! + ", "stateCleared": "modified", }, @@ -20262,68 +20341,68 @@ spec: - name: init-ds image: busybox:latest command: - - "/bin/sh" - - "-c" + - '/bin/sh' + - '-c' - | - while true - do - rt=$(nc -z -w 1 jhgate-mysql 3306) - if [ $? -eq 0 ]; then - echo "DB is UP" - break - fi - echo "DB is not yet reachable;sleep for 10s before retry" - sleep 10 - done + while true + do + rt=$(nc -z -w 1 jhgate-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done containers: - - name: jhgate-app - image: jhipsterrepository/jhgate - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_CLOUD_CONFIG_URI - value: http://admin:\${jhipster.registry.password}@jhipster-registry.jhipsternamespace.svc.cluster.local:8761/config - - name: JHIPSTER_REGISTRY_PASSWORD - valueFrom: - secretKeyRef: - name: registry-secret - key: registry-admin-password - - name: EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE - value: http://admin:\${jhipster.registry.password}@jhipster-registry.jhipsternamespace.svc.cluster.local:8761/eureka/ - - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_LIQUIBASE_URL - value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: SPRING_R2DBC_URL - value: r2dbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true - - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS - value: "x-request-id,x-ot-span-context" - - name: JAVA_OPTS - value: " -Xmx256m -Xms256m" - - name: SERVER_SHUTDOWN - value: graceful - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /management/health/readiness - port: http - initialDelaySeconds: 20 - periodSeconds: 15 - failureThreshold: 6 - livenessProbe: - httpGet: - path: /management/health/liveness - port: http - initialDelaySeconds: 120 + - name: jhgate-app + image: jhipsterrepository/jhgate + env: + - name: SPRING_PROFILES_ACTIVE + value: prod + - name: SPRING_CLOUD_CONFIG_URI + value: http://admin:\${jhipster.registry.password}@jhipster-registry.jhipsternamespace.svc.cluster.local:8761/config + - name: JHIPSTER_REGISTRY_PASSWORD + valueFrom: + secretKeyRef: + name: registry-secret + key: registry-admin-password + - name: EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE + value: http://admin:\${jhipster.registry.password}@jhipster-registry.jhipsternamespace.svc.cluster.local:8761/eureka/ + - name: SPRING_DATASOURCE_URL + value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_LIQUIBASE_URL + value: jdbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: SPRING_R2DBC_URL + value: r2dbc:mysql://jhgate-mysql.jhipsternamespace.svc.cluster.local:3306/jhgate?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + - name: MANAGEMENT_TRACING_BAGGAGE_REMOTE_FIELDS + value: "x-request-id,x-ot-span-context" + - name: JAVA_OPTS + value: " -Xmx256m -Xms256m" + - name: SERVER_SHUTDOWN + value: graceful + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" + ports: + - name: http + containerPort: 8080 + readinessProbe: + httpGet: + path: /management/health/readiness + port: http + initialDelaySeconds: 20 + periodSeconds: 15 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /management/health/liveness + port: http + initialDelaySeconds: 120 ", "stateCleared": "modified", }, @@ -20335,7 +20414,7 @@ metadata: namespace: jhipsternamespace spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 2Gi @@ -20356,34 +20435,34 @@ spec: app: jhgate-mysql spec: volumes: - - name: data - persistentVolumeClaim: - claimName: jhgate-mysql-pvc + - name: data + persistentVolumeClaim: + claimName: jhgate-mysql-pvc containers: - - name: mysql - image: mysql-placeholder - env: - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "yes" - - name: MYSQL_DATABASE - value: jhgate - args: - - --lower_case_table_names=1 - - --skip-mysqlx - - --character_set_server=utf8mb4 - - --explicit_defaults_for_timestamp - ports: - - containerPort: 3306 - volumeMounts: - - name: data - mountPath: /var/lib/mysql/ - resources: - requests: - memory: "512Mi" - cpu: "500m" - limits: - memory: "1Gi" - cpu: "1" + - name: mysql + image: mysql-placeholder + env: + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: 'yes' + - name: MYSQL_DATABASE + value: jhgate + args: + - --lower_case_table_names=1 + - --skip-mysqlx + - --character_set_server=utf8mb4 + - --explicit_defaults_for_timestamp + ports: + - containerPort: 3306 + volumeMounts: + - name: data + mountPath: /var/lib/mysql/ + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" --- apiVersion: v1 kind: Service @@ -20394,7 +20473,7 @@ spec: selector: app: jhgate-mysql ports: - - port: 3306 + - port: 3306 ", "stateCleared": "modified", }, @@ -20411,8 +20490,8 @@ spec: app: jhgate type: LoadBalancer ports: - - name: http - port: 8080 + - name: http + port: 8080 ", "stateCleared": "modified", }, @@ -20481,14 +20560,14 @@ logSummary namespace: jhipsternamespace resources: - - namespace.yml - # Individual apps - - jhgate-k8s/jhgate-deployment.yml - - jhgate-k8s/jhgate-service.yml - - jhgate-k8s/jhgate-mysql.yml - # service discovery eureka/consul - - registry-k8s/jhipster-registry.yml - - registry-k8s/application-configmap.yml +- namespace.yml +# Individual apps +- jhgate-k8s/jhgate-deployment.yml +- jhgate-k8s/jhgate-service.yml +- jhgate-k8s/jhgate-mysql.yml +# service discovery eureka/consul +- registry-k8s/jhipster-registry.yml +- registry-k8s/application-configmap.yml patchesJson6902: ", @@ -20499,6 +20578,7 @@ patchesJson6902: kind: Namespace metadata: name: jhipsternamespace + ", "stateCleared": "modified", }, @@ -20572,8 +20652,8 @@ metadata: app: jhipster-registry spec: ports: - - port: 8761 - name: http + - port: 8761 + name: http clusterIP: None publishNotReadyAddresses: true selector: @@ -20601,53 +20681,53 @@ spec: spec: terminationGracePeriodSeconds: 10 containers: - - name: jhipster-registry - image: jhipster-registry-placeholder - ports: - - containerPort: 8761 - env: - # StatefulSet specific configuration - # Registry configuration - - name: SPRING_PROFILES_ACTIVE - value: prod,k8s - - name: SPRING_SECURITY_USER_PASSWORD - valueFrom: - secretKeyRef: - name: registry-secret - key: registry-admin-password - - name: JHIPSTER_SECURITY_AUTHENTICATION_JWT_BASE64_SECRET - value: YlhrdGMyVmpjbVYwTFhSdmEyVnVMWFJ2TFdOb1lXNW5aUzFwYmkxd2NtOWtkV04wYVc5dUxXRnVaQzEwYnkxclpXVndMV2x1TFdFdGMyVmpkWEpsTFhCc1lXTmwK - - name: SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_TYPE - value: native - - name: SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_SEARCH_LOCATIONS - value: file:./central-config - - name: EUREKA_INSTANCE_LEASE_RENEWAL_INTERVAL_IN_SECONDS - value: "15" - - name: EUREKA_INSTANCE_LEASE_EXPIRATION_DURATION_IN_SECONDS - value: "30" - - name: EUREKA_SERVER_PEER_EUREKA_NODES_UPDATE_INTERVAL_MS - value: "15000" - - name: EUREKA_SERVER_RENAWAL_THRESHOLD_UPDATE_INTERVAL_MS - value: "15000" - - name: EUREKA_SERVER_REGISTRY_SYNC_RETRIES - value: "3" - - name: EUREKA_SERVER_ENABLE_SELF_PRESERVATION - value: "false" - - name: EUREKA_SERVER_PEER_NODE_CONNECT_TIMEOUT_MS - value: "2000" - - name: EUREKA_CLIENT_FETCH_REGISTRY - value: "true" - - name: EUREKA_CLIENT_REGISTER_WITH_EUREKA - value: "true" - - name: K8S_CONFIG_PATH - value: "/central-config/" - volumeMounts: - - name: config-volume - mountPath: /central-config - volumes: + - name: jhipster-registry + image: jhipster-registry-placeholder + ports: + - containerPort: 8761 + env: + # StatefulSet specific configuration + # Registry configuration + - name: SPRING_PROFILES_ACTIVE + value: prod,k8s + - name: SPRING_SECURITY_USER_PASSWORD + valueFrom: + secretKeyRef: + name: registry-secret + key: registry-admin-password + - name: JHIPSTER_SECURITY_AUTHENTICATION_JWT_BASE64_SECRET + value: YlhrdGMyVmpjbVYwTFhSdmEyVnVMWFJ2TFdOb1lXNW5aUzFwYmkxd2NtOWtkV04wYVc5dUxXRnVaQzEwYnkxclpXVndMV2x1TFdFdGMyVmpkWEpsTFhCc1lXTmwK + - name: SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_TYPE + value: native + - name: SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_SEARCH_LOCATIONS + value: file:./central-config + - name: EUREKA_INSTANCE_LEASE_RENEWAL_INTERVAL_IN_SECONDS + value: '15' + - name: EUREKA_INSTANCE_LEASE_EXPIRATION_DURATION_IN_SECONDS + value: '30' + - name: EUREKA_SERVER_PEER_EUREKA_NODES_UPDATE_INTERVAL_MS + value: '15000' + - name: EUREKA_SERVER_RENAWAL_THRESHOLD_UPDATE_INTERVAL_MS + value: '15000' + - name: EUREKA_SERVER_REGISTRY_SYNC_RETRIES + value: '3' + - name: EUREKA_SERVER_ENABLE_SELF_PRESERVATION + value: 'false' + - name: EUREKA_SERVER_PEER_NODE_CONNECT_TIMEOUT_MS + value: '2000' + - name: EUREKA_CLIENT_FETCH_REGISTRY + value: 'true' + - name: EUREKA_CLIENT_REGISTER_WITH_EUREKA + value: 'true' + - name: K8S_CONFIG_PATH + value: '/central-config/' + volumeMounts: - name: config-volume - configMap: - name: application-config + mountPath: /central-config + volumes: + - name: config-volume + configMap: + name: application-config ", "stateCleared": "modified", }, @@ -20656,9 +20736,9 @@ spec: kind: Config build: artifacts: - - image: jhipsterrepository/jhgate - context: ./01-gateway - jib: {} + - image: jhipsterrepository/jhgate + context: ./01-gateway + jib: {} tagPolicy: envTemplate: template: "{{.IMAGE_NAME}}:latest" diff --git a/generators/kubernetes/command.ts b/generators/kubernetes/command.ts new file mode 100644 index 000000000000..c83d0d88f6d2 --- /dev/null +++ b/generators/kubernetes/command.ts @@ -0,0 +1,33 @@ +/** + * Copyright 2013-2024 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. + */ +import type { JHipsterCommandDefinition } from '../../lib/command/types.js'; + +const command = { + configs: { + jwtSecretKey: { + cli: { + type: String, + env: 'JHI_JWT_SECRET_KEY', + }, + scope: 'generator', + }, + }, +} as const satisfies JHipsterCommandDefinition; + +export default command; diff --git a/generators/kubernetes/files.js b/generators/kubernetes/files.ts similarity index 99% rename from generators/kubernetes/files.js rename to generators/kubernetes/files.ts index 004c91ec2498..ff1298cf0ca2 100644 --- a/generators/kubernetes/files.js +++ b/generators/kubernetes/files.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -22,11 +23,11 @@ import { applicationTypes, authenticationTypes, databaseTypes, + ingressTypes, monitoringTypes, searchEngineTypes, serviceDiscoveryTypes, - ingressTypes, -} from '../../jdl/jhipster/index.js'; +} from '../../lib/jhipster/index.js'; const { ELASTICSEARCH } = searchEngineTypes; const { GATEWAY, MONOLITH } = applicationTypes; diff --git a/generators/kubernetes/generator.spec.js b/generators/kubernetes/generator.spec.ts similarity index 96% rename from generators/kubernetes/generator.spec.js rename to generators/kubernetes/generator.spec.ts index b25895cf89f4..d90bf385002d 100644 --- a/generators/kubernetes/generator.spec.js +++ b/generators/kubernetes/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures } from '../../test/support/tests.js'; diff --git a/generators/kubernetes/generator.js b/generators/kubernetes/generator.ts similarity index 94% rename from generators/kubernetes/generator.js rename to generators/kubernetes/generator.ts index 3bc3ebf3b494..dafa5580f6ae 100644 --- a/generators/kubernetes/generator.js +++ b/generators/kubernetes/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,21 +17,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return, import/no-named-as-default-member */ + import fs from 'fs'; import chalk from 'chalk'; import BaseWorkspacesGenerator from '../base-workspaces/index.js'; -import { buildToolTypes, messageBrokerTypes } from '../../jdl/jhipster/index.js'; +import { buildToolTypes, messageBrokerTypes } from '../../lib/jhipster/index.js'; -import { checkImages, generateJwtSecret, configureImageNames, loadFromYoRc } from '../base-workspaces/internal/docker-base.js'; +import { checkImages, configureImageNames, generateJwtSecret, loadFromYoRc } from '../base-workspaces/internal/docker-base.js'; import { getJdbcUrl, getR2dbcUrl } from '../spring-data-relational/support/index.js'; import { loadDeploymentConfig, loadDockerDependenciesTask } from '../base-workspaces/internal/index.js'; import { checkDocker } from '../docker/support/index.js'; import { loadDerivedServerConfig } from '../server/support/index.js'; import { loadDerivedAppConfig } from '../app/support/index.js'; -import { checkKubernetes, loadConfig, setupKubernetesConstants, derivedKubernetesPlatformProperties } from './kubernetes-base.js'; +import { checkKubernetes, derivedKubernetesPlatformProperties, loadConfig, setupKubernetesConstants } from './kubernetes-base.js'; import { writeFiles } from './files.js'; import prompts from './prompts.js'; @@ -108,10 +109,10 @@ export default class KubernetesGenerator extends BaseWorkspacesGenerator { return { loadFromYoRc, loadSharedConfig() { - this.appConfigs.forEach(element => { - loadDerivedAppConfig({ application: element }); - loadDerivedServerConfig({ application: element }); - }); + for (const app of this.appConfigs) { + loadDerivedAppConfig({ application: app }); + loadDerivedServerConfig({ application: app }); + } loadDeploymentConfig.call(this); derivedKubernetesPlatformProperties(this); }, @@ -128,6 +129,7 @@ export default class KubernetesGenerator extends BaseWorkspacesGenerator { setPostPromptProp() { this.appConfigs.forEach(element => { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions element.clusteredDb ? (element.dbPeerCount = 3) : (element.dbPeerCount = 1); if (element.messageBroker === KAFKA) { this.useKafka = true; @@ -211,7 +213,7 @@ export default class KubernetesGenerator extends BaseWorkspacesGenerator { // Make the apply script executable try { fs.chmodSync('kubectl-apply.sh', '755'); - } catch (err) { + } catch { this.log.warn("Failed to make 'kubectl-apply.sh' executable, you may need to run 'chmod +x kubectl-apply.sh'"); } }, diff --git a/generators/kubernetes/index.ts b/generators/kubernetes/index.ts index 58ac334eafae..2d8013d19f51 100644 --- a/generators/kubernetes/index.ts +++ b/generators/kubernetes/index.ts @@ -16,4 +16,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +export { default as command } from './command.js'; export { default } from './generator.js'; diff --git a/generators/kubernetes/kubernetes-base.js b/generators/kubernetes/kubernetes-base.ts similarity index 97% rename from generators/kubernetes/kubernetes-base.js rename to generators/kubernetes/kubernetes-base.ts index f86b7d535c7a..f227b97028d0 100644 --- a/generators/kubernetes/kubernetes-base.js +++ b/generators/kubernetes/kubernetes-base.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -19,26 +20,25 @@ import crypto from 'crypto'; import { defaults } from 'lodash-es'; -import { loadFromYoRc } from '../base-workspaces/internal/docker-base.js'; import { - KUBERNETES_CORE_API_VERSION, - KUBERNETES_BATCH_API_VERSION, - KUBERNETES_DEPLOYMENT_API_VERSION, - KUBERNETES_STATEFULSET_API_VERSION, - KUBERNETES_INGRESS_API_VERSION, - KUBERNETES_ISTIO_NETWORKING_API_VERSION, - KUBERNETES_RBAC_API_VERSION, - HELM_KAFKA, + HELM_COUCHBASE_OPERATOR, HELM_ELASTICSEARCH, - HELM_PROMETHEUS, HELM_GRAFANA, + HELM_KAFKA, HELM_MARIADB, + HELM_MONGODB_REPLICASET, HELM_MYSQL, HELM_POSTGRESQL, - HELM_MONGODB_REPLICASET, - HELM_COUCHBASE_OPERATOR, + HELM_PROMETHEUS, + KUBERNETES_BATCH_API_VERSION, + KUBERNETES_CORE_API_VERSION, + KUBERNETES_DEPLOYMENT_API_VERSION, + KUBERNETES_INGRESS_API_VERSION, + KUBERNETES_ISTIO_NETWORKING_API_VERSION, + KUBERNETES_RBAC_API_VERSION, + KUBERNETES_STATEFULSET_API_VERSION, } from '../generator-constants.js'; -import { applicationTypes, kubernetesPlatformTypes } from '../../jdl/jhipster/index.js'; +import { applicationTypes, kubernetesPlatformTypes } from '../../lib/jhipster/index.js'; import { defaultKubernetesConfig } from './kubernetes-constants.js'; const { MICROSERVICE } = applicationTypes; @@ -75,7 +75,6 @@ export const checkHelm = async function () { }; export function loadConfig() { - loadFromYoRc.call(this); if (!this.jhipsterConfig.dbRandomPassword) { this.jhipsterConfig.dbRandomPassword = this.options.reproducibleTests ? 'SECRET-PASSWORD' : crypto.randomBytes(30).toString('hex'); } diff --git a/generators/kubernetes/kubernetes-constants.js b/generators/kubernetes/kubernetes-constants.ts similarity index 94% rename from generators/kubernetes/kubernetes-constants.js rename to generators/kubernetes/kubernetes-constants.ts index 5fa155bf1841..4f45a231fe67 100644 --- a/generators/kubernetes/kubernetes-constants.js +++ b/generators/kubernetes/kubernetes-constants.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { monitoringTypes, kubernetesPlatformTypes } from '../../jdl/jhipster/index.js'; +import { kubernetesPlatformTypes, monitoringTypes } from '../../lib/jhipster/index.js'; const { NO } = monitoringTypes; const { ServiceTypes, IngressTypes, GeneratorTypes } = kubernetesPlatformTypes; diff --git a/generators/kubernetes/kubernetes.spec.ts b/generators/kubernetes/kubernetes.spec.ts index f9781ed11094..698e02374d38 100644 --- a/generators/kubernetes/kubernetes.spec.ts +++ b/generators/kubernetes/kubernetes.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe, expect } from 'esmocha'; -import { basicHelpers as helpers, getGenerator, runResult } from '../../testing/index.js'; +import { before, describe, expect, it } from 'esmocha'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { GENERATOR_KUBERNETES } from '../generator-list.js'; const expectedFiles = { @@ -44,17 +44,16 @@ const expectedFiles = { describe('generator - Kubernetes', () => { describe('only gateway', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces() .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -72,8 +71,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -96,17 +94,16 @@ describe('generator - Kubernetes', () => { }); describe('only gateway with eureka', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'eureka' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -123,8 +120,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -147,17 +143,16 @@ describe('generator - Kubernetes', () => { }); describe('gateway and mysql microservice', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway', '02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -174,8 +169,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -206,8 +200,8 @@ describe('generator - Kubernetes', () => { .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -224,8 +218,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -248,17 +241,16 @@ describe('generator - Kubernetes', () => { }); describe('gateway and ingress', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -275,8 +267,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -299,17 +290,16 @@ describe('generator - Kubernetes', () => { }); describe('gateway and ingressType gke', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ authenticationType: 'oauth2' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -327,8 +317,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -357,17 +346,16 @@ describe('generator - Kubernetes', () => { }); describe('gateway and ingressType nginx', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ authenticationType: 'oauth2' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -384,8 +372,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -414,17 +401,16 @@ describe('generator - Kubernetes', () => { }); describe('MySQL and PostgreSQL microservices without gateway', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql', '03-psql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -441,8 +427,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -468,17 +453,16 @@ describe('generator - Kubernetes', () => { }); describe('gateway, mysql, psql, mongodb, mariadb, mssql microservices', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway', '02-mysql', '03-psql', '04-mongo', '07-mariadb', '11-mssql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -495,8 +479,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -531,17 +514,16 @@ describe('generator - Kubernetes', () => { }); describe('monolith application', () => { - let runResult; before(async () => { const chosenApps = ['08-monolith']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces() .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -558,8 +540,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -580,17 +561,16 @@ describe('generator - Kubernetes', () => { }); describe('Kafka application', () => { - let runResult; before(async () => { const chosenApps = ['09-kafka']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces() .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -607,8 +587,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -629,17 +608,16 @@ describe('generator - Kubernetes', () => { }); describe('mysql microservice with custom namespace and jhipster prometheus monitoring', () => { - let runResult; before(async () => { const chosenApps = ['02-mysql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -655,8 +633,7 @@ describe('generator - Kubernetes', () => { kubernetesServiceType: 'LoadBalancer', kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -682,17 +659,16 @@ describe('generator - Kubernetes', () => { }); describe('gateway with istio routing', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -709,8 +685,7 @@ describe('generator - Kubernetes', () => { istio: true, kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); @@ -733,17 +708,16 @@ describe('generator - Kubernetes', () => { }); describe('mysql, psql, mongodb, mariadb, mssql microservices with dynamic storage provisioning', () => { - let runResult; before(async () => { const chosenApps = ['01-gateway', '02-mysql', '03-psql', '04-mongo', '07-mariadb', '11-mssql']; - runResult = await helpers + await helpers .generateDeploymentWorkspaces({ serviceDiscoveryType: 'consul' }) .withWorkspacesSamples(...chosenApps) .withGenerateWorkspaceApplications(); - runResult = await runResult - .create(getGenerator(GENERATOR_KUBERNETES)) + await helpers + .runJHipsterInApplication(GENERATOR_KUBERNETES) .withSpawnMock() .withOptions({ askAnswered: true, @@ -760,8 +734,7 @@ describe('generator - Kubernetes', () => { clusteredDbApps: [], kubernetesUseDynamicStorage: true, kubernetesStorageClassName: '', - }) - .run(); + }); }); it('should match files snapshot', function () { expect(runResult.getSnapshot()).toMatchSnapshot(); diff --git a/generators/kubernetes/prompts.js b/generators/kubernetes/prompts.ts similarity index 97% rename from generators/kubernetes/prompts.js rename to generators/kubernetes/prompts.ts index 703a2d85221d..9cf8abd8472d 100644 --- a/generators/kubernetes/prompts.js +++ b/generators/kubernetes/prompts.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -17,7 +18,7 @@ * limitations under the License. */ import dockerPrompts from '../base-workspaces/internal/docker-prompts.js'; -import { applicationTypes, databaseTypes, kubernetesPlatformTypes } from '../../jdl/jhipster/index.js'; +import { applicationTypes, databaseTypes, kubernetesPlatformTypes } from '../../lib/jhipster/index.js'; import { defaultKubernetesConfig, ingressDefaultConfig } from './kubernetes-constants.js'; const { MONOLITH } = applicationTypes; @@ -119,7 +120,7 @@ export async function askForIngressDomain() { if (!this.options.askAnswered && (this.regenerate || this.config.existed)) return; const kubernetesServiceType = this.kubernetesServiceType; const istio = this.istio; - this.ingressDomain = this.ingressDomain && this.ingressDomain.startsWith('.') ? this.ingressDomain.substring(1) : this.ingressDomain; + this.ingressDomain = this.ingressDomain?.startsWith('.') ? this.ingressDomain.substring(1) : this.ingressDomain; const istioIpCommand = "kubectl -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}'"; let istioMessage = ''; @@ -132,7 +133,7 @@ export async function askForIngressDomain() { try { const { stdout: istioIngressIp } = this.spawnCommandSync(istioIpCommand, { stdio: 'pipe' }); defaultValue = `${istioIngressIp}.nip.io`; - } catch (ex) { + } catch { istioMessage = `Unable to determine Istio Ingress IP address. You can find the Istio Ingress IP address by running the command line:\n ${istioIpCommand}`; } } else if (this.ingressType === NGINX) { diff --git a/generators/languages/command.ts b/generators/languages/command.ts index 35a79a0a3769..8424fd9247e8 100644 --- a/generators/languages/command.ts +++ b/generators/languages/command.ts @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; -const command: JHipsterCommandDefinition = { +const command = { arguments: { languages: { description: 'Languages to generate', @@ -26,30 +26,46 @@ const command: JHipsterCommandDefinition = { required: false, }, }, - options: { + configs: { + languages: { + cli: { + type: Array, + hide: true, + }, + scope: 'storage', + }, enableTranslation: { - description: 'Enable translation', - type: Boolean, - required: false, + cli: { + description: 'Enable translation', + type: Boolean, + }, scope: 'storage', }, language: { - alias: 'l', - description: 'Language to be added to application (existing languages are not removed)', - type: Array, + cli: { + alias: 'l', + description: 'Language to be added to application (existing languages are not removed)', + type: Array, + }, + scope: 'none', }, nativeLanguage: { - alias: 'n', - description: 'Set application native language', - type: String, - required: false, + cli: { + alias: 'n', + description: 'Set application native language', + type: String, + required: false, + }, + scope: 'storage', }, regenerateLanguages: { - description: 'Regenerate languages', - type: Boolean, + cli: { + description: 'Regenerate languages', + type: Boolean, + }, scope: 'generator', }, }, -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/languages/entity-files.js b/generators/languages/entity-files.ts similarity index 89% rename from generators/languages/entity-files.js rename to generators/languages/entity-files.ts index 97d046f22649..c284793f37fa 100644 --- a/generators/languages/entity-files.js +++ b/generators/languages/entity-files.ts @@ -16,8 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { getEnumInfo } from '../base-application/support/index.js'; +import { asWritingEntitiesTask, getEnumInfo } from '../base-application/support/index.js'; import { CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; +import type LanguagesGenerator from './generator.js'; /** * The default is to use a file path string. It implies use of the template method. @@ -62,7 +63,7 @@ export const enumClientI18nFiles = { export function writeEntityFiles() { return { - async writeEnumFiles({ entities, application }) { + writeEnumFiles: asWritingEntitiesTask(async function (this: LanguagesGenerator, { entities, application }) { if (application.skipClient) return; const languagesToApply = application.enableTranslation ? this.languagesToApply : [...new Set([application.nativeLanguage, 'en'])]; entities = entities.filter(entity => !entity.skipClient && !entity.builtInUser); @@ -90,12 +91,12 @@ export function writeEntityFiles() { ) .flat(), ); - }, + }), - async writeClientFiles({ application, entities }) { + writeClientFiles: asWritingEntitiesTask(async function (this: LanguagesGenerator, { application, entities }) { if (application.skipClient) return; const entitiesToWriteTranslationFor = entities.filter(entity => !entity.skipClient && !entity.builtInUser); - if (application.userManagement && application.userManagement.skipClient) { + if (application.userManagement?.skipClient) { entitiesToWriteTranslationFor.push(application.userManagement); } @@ -111,6 +112,6 @@ export function writeEntityFiles() { } } } - }, + }), }; } diff --git a/generators/languages/files.js b/generators/languages/files.ts similarity index 97% rename from generators/languages/files.js rename to generators/languages/files.ts index 573aa7528932..e7dfc3cea204 100644 --- a/generators/languages/files.js +++ b/generators/languages/files.ts @@ -18,7 +18,6 @@ */ import { CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; -// eslint-disable-next-line import/prefer-default-export export const clientI18nFiles = { clientI18nFiles: [ { diff --git a/generators/languages/generator-needles.spec.ts b/generators/languages/generator-needles.spec.ts index f647f96ccb5e..20fcaa21e8b7 100644 --- a/generators/languages/generator-needles.spec.ts +++ b/generators/languages/generator-needles.spec.ts @@ -1,12 +1,11 @@ -import { before, it, describe } from 'esmocha'; -import { defaultHelpers as helpers, result as runResult, getGenerator } from '../../testing/index.js'; +import { before, describe, it } from 'esmocha'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import { CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; import LanguagesGenerator from './index.js'; -const generatorPath = getGenerator('languages'); +const generator = 'languages'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any const mockBlueprintSubGen: any = class extends LanguagesGenerator { constructor(args, opts, features) { super(args, opts, features); @@ -31,14 +30,14 @@ const mockBlueprintSubGen: any = class extends LanguagesGenerator { describe('needle API i18n: JHipster language generator with blueprint', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({ baseName: 'jhipster' }) .withOptions({ ignoreNeedlesError: true }) .withOptions({ build: 'maven', auth: 'jwt', db: 'mysql', - blueprint: 'myblueprint', + blueprint: ['myblueprint'], nativeLanguage: 'en', languages: ['en', 'fr'], }) diff --git a/generators/languages/generator.spec.js b/generators/languages/generator.spec.ts similarity index 96% rename from generators/languages/generator.spec.js rename to generators/languages/generator.spec.ts index 7a87d7ddc914..37e0a1ea0884 100644 --- a/generators/languages/generator.spec.js +++ b/generators/languages/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { defaultHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; import { GENERATOR_LANGUAGES } from '../generator-list.js'; import Generator from './index.js'; diff --git a/generators/languages/generator.js b/generators/languages/generator.ts similarity index 97% rename from generators/languages/generator.js rename to generators/languages/generator.ts index 55f0e9870ada..3f39291f2f94 100644 --- a/generators/languages/generator.js +++ b/generators/languages/generator.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return */ + import chalk from 'chalk'; import { padEnd, startCase } from 'lodash-es'; @@ -28,7 +29,7 @@ import { updateLanguagesTask as updateLanguagesInJava } from '../server/support/ import { SERVER_MAIN_RES_DIR, SERVER_TEST_RES_DIR } from '../generator-constants.js'; import { QUEUES } from '../base-application/priorities.js'; import { PRIORITY_NAMES } from '../base/priorities.js'; -import { clientFrameworkTypes } from '../../jdl/index.js'; +import { clientFrameworkTypes } from '../../lib/jhipster/index.js'; import { findLanguageForTag, supportedLanguages } from './support/languages.js'; import TranslationData, { createTranslationsFileFilter, createTranslationsFilter } from './translation-data.js'; import { writeEntityFiles } from './entity-files.js'; @@ -43,6 +44,8 @@ const { NO: NO_CLIENT_FRAMEWORK, ANGULAR } = clientFrameworkTypes; * @extends {BaseApplicationGenerator} */ export default class LanguagesGenerator extends BaseApplicationGenerator { + askForMoreLanguages!: boolean; + askForNativeLanguage!: boolean; translationData; supportedLanguages; languages; @@ -51,7 +54,7 @@ export default class LanguagesGenerator extends BaseApplicationGenerator { * Can be incremental or every language. */ languagesToApply; - composedBlueprints = []; + composedBlueprints: string[] = []; languageCommand; writeJavaLanguageFiles; regenerateLanguages; @@ -273,7 +276,7 @@ export default class LanguagesGenerator extends BaseApplicationGenerator { return; await Promise.all( this.languagesToApply.map(async lang => { - const language = findLanguageForTag(lang); + const language = findLanguageForTag(lang)!; if (language.javaLocaleMessageSourceSuffix) { await this.writeFiles({ sections: { @@ -376,10 +379,10 @@ export default class LanguagesGenerator extends BaseApplicationGenerator { migrateLanguages(languagesToMigrate) { const { languages, nativeLanguage } = this.jhipsterConfig; - if (languagesToMigrate[nativeLanguage]) { - this.jhipsterConfig.nativeLanguage = languagesToMigrate[nativeLanguage]; + if (languagesToMigrate[nativeLanguage!]) { + this.jhipsterConfig.nativeLanguage = languagesToMigrate[nativeLanguage!]; } - if (languages && languages.some(lang => languagesToMigrate[lang])) { + if (languages?.some(lang => languagesToMigrate[lang])) { this.jhipsterConfig.languages = languages.map(lang => languagesToMigrate[lang] ?? lang); } } diff --git a/generators/languages/languages.spec.js b/generators/languages/languages.spec.ts similarity index 91% rename from generators/languages/languages.spec.js rename to generators/languages/languages.spec.ts index ec8cbd974a48..dc501d17b357 100644 --- a/generators/languages/languages.spec.js +++ b/generators/languages/languages.spec.ts @@ -1,7 +1,7 @@ import { fileURLToPath } from 'url'; -import { dirname, join } from 'path'; -import { before, it, describe } from 'esmocha'; -import { basicHelpers, defaultHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { basename, dirname } from 'path'; +import { before, describe, it } from 'esmocha'; +import { basicHelpers, defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import { CLIENT_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR } from '../generator-constants.js'; import { supportedLanguages } from './support/index.js'; @@ -9,9 +9,9 @@ import { supportedLanguages } from './support/index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const generatorPath = join(__dirname, 'index.js'); +const generator = basename(__dirname); -const createClientProject = options => +const createClientProject = (options?) => basicHelpers .runJHipster('app') .withMockedGenerators(['jhipster:liquibase']) @@ -98,21 +98,20 @@ describe('generator - languages', () => { describe(`with prompts for ${language.name}`, () => { before(() => helpers - .create(generatorPath) + .runJHipster(generator) .withOptions({ ignoreNeedlesError: true }) .withAnswers({ enableTranslation: true, nativeLanguage: language.languageTag, languages: [language.languageTag], - }) - .run(), + }), ); containsLanguageFiles(language.languageTag); }); describe(`with options for ${language.name}`, () => { before(() => helpers - .run(generatorPath) + .runJHipster(generator) .withArguments([language.languageTag]) .withJHipsterConfig({ enableTranslation: true, nativeLanguage: language.languageTag }) .withOptions({ ignoreNeedlesError: true }), @@ -125,7 +124,7 @@ describe('generator - languages', () => { describe('for already generated native language', () => { before(() => helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({ enableTranslation: true, nativeLanguage: 'fr', languages: ['fr'], baseName: 'jhipster' }) .withOptions({ commandName: 'languages', ignoreNeedlesError: true }), ); @@ -134,7 +133,7 @@ describe('generator - languages', () => { describe('for already generated languages', () => { before(() => helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({ enableTranslation: true, nativeLanguage: 'fr', languages: ['en', 'fr'] }) .withOptions({ commandName: 'languages', ignoreNeedlesError: true }), ); @@ -145,7 +144,7 @@ describe('generator - languages', () => { describe('should create default i18n files for the native language', () => { describe('using prompts', () => { before(() => - helpers.run(generatorPath).withOptions({ ignoreNeedlesError: true }).withAnswers({ + helpers.runJHipster(generator).withOptions({ ignoreNeedlesError: true }).withAnswers({ enableTranslation: true, nativeLanguage: 'fr', languages: [], @@ -156,7 +155,7 @@ describe('generator - languages', () => { describe('using arguments', () => { before(() => helpers - .run(generatorPath) + .runJHipster(generator) .withLocalConfig({ enableTranslation: true }) .withOptions({ ignoreNeedlesError: true }) .withOptions({ nativeLanguage: 'fr', baseName: 'jhipster' }), @@ -166,7 +165,7 @@ describe('generator - languages', () => { describe('when regenerating', () => { before(() => helpers - .run(generatorPath) + .runJHipster(generator) .withLocalConfig({ enableTranslation: true, nativeLanguage: 'fr', languages: ['fr'] }) .withOptions({ ignoreNeedlesError: true }) .withOptions({ skipPrompts: true, regenerate: true, baseName: 'jhipster' }), @@ -176,13 +175,13 @@ describe('generator - languages', () => { }); describe('should create default i18n files for the native language and an additional language', () => { describe('by default', () => { - before(() => helpers.run(generatorPath).withJHipsterConfig().withOptions({ ignoreNeedlesError: true })); + before(() => helpers.runJHipster(generator).withJHipsterConfig().withOptions({ ignoreNeedlesError: true })); containsLanguageFiles('en'); }); describe('using prompts', () => { before(() => helpers - .run(generatorPath) + .runJHipster(generator) .withOptions({ ignoreNeedlesError: true }) .withAnswers({ enableTranslation: true, @@ -205,7 +204,7 @@ describe('generator - languages', () => { describe('using arguments', () => { before(() => helpers - .run(generatorPath) + .runJHipster(generator) .withLocalConfig({ enableTranslation: true }) .withArguments(['en']) .withOptions({ ignoreNeedlesError: true }) @@ -217,7 +216,7 @@ describe('generator - languages', () => { describe('when regenerating', () => { before(() => helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({ enableTranslation: true, nativeLanguage: 'fr', languages: ['en', 'fr'] }) .withOptions({ ignoreNeedlesError: true }) .withOptions({ skipPrompts: true, regenerate: true, baseName: 'jhipster' }), @@ -239,7 +238,7 @@ describe('generator - languages', () => { describe('with prompts', () => { before(() => helpers - .run(generatorPath) + .runJHipster(generator) .withOptions({ ignoreNeedlesError: true }) .withAnswers({ enableTranslation: true, @@ -253,7 +252,7 @@ describe('generator - languages', () => { describe('with options', () => { before(() => helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({ enableTranslation: true, nativeLanguage: 'en' }) .withOptions({ ignoreNeedlesError: true }) .withArguments(['fr', 'de']) @@ -276,20 +275,19 @@ describe('generator - languages', () => { describe('Creates default i18n files for Vue applications', () => { describe('using prompts', () => { before(async () => { - const result = await createClientProject().withJHipsterConfig({ + await createClientProject().withJHipsterConfig({ clientFramework: 'vue', enableTranslation: true, nativeLanguage: 'en', }); - await result - .create('jhipster:languages') + await helpers + .runJHipsterInApplication('jhipster:languages') .withAnswers({ languages: ['fr', 'de'], }) .withOptions({ commandName: 'languages', - }) - .run(); + }); }); it('creates expected configuration values', () => { runResult.assertJsonFileContent('.yo-rc.json', { @@ -314,12 +312,14 @@ describe('generator - languages', () => { describe('using arguments', () => { before(async () => { - const result = await createClientProject().withJHipsterConfig({ + await createClientProject().withJHipsterConfig({ clientFramework: 'vue', enableTranslation: true, nativeLanguage: 'en', }); - await result.create('jhipster:languages').withArguments(['fr', 'de']).withOptions({ baseName: 'jhipster' }).run(); + await helpers.runJHipsterInApplication('jhipster:languages').withArguments(['fr', 'de']).withOptions({ + baseName: 'jhipster', + }); }); it('creates expected configuration values', () => { runResult.assertJsonFileContent('.yo-rc.json', { diff --git a/generators/languages/prompts.js b/generators/languages/prompts.ts similarity index 93% rename from generators/languages/prompts.js rename to generators/languages/prompts.ts index b9841f8e6562..56e1e97d0edd 100644 --- a/generators/languages/prompts.js +++ b/generators/languages/prompts.ts @@ -16,10 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import type LanguagesGenerator from './generator.js'; import detectLanguage from './support/detect-language.js'; import { languagesAsChoices } from './support/languages.js'; -export async function askI18n() { +export async function askI18n(this: LanguagesGenerator) { if (!this.askForMoreLanguages) return; const nativeLanguage = this.jhipsterConfig.nativeLanguage; const answers = await this.prompt( @@ -46,7 +47,7 @@ export async function askI18n() { } } -export async function askForLanguages({ control }) { +export async function askForLanguages(this: LanguagesGenerator, { control }) { if (!this.askForMoreLanguages) { return; } diff --git a/generators/languages/support/detect-language.ts b/generators/languages/support/detect-language.ts index 152a129741e3..ef081e04e136 100644 --- a/generators/languages/support/detect-language.ts +++ b/generators/languages/support/detect-language.ts @@ -18,9 +18,10 @@ */ import { osLocaleSync } from 'os-locale'; -import { findLanguageForTag, Language, supportedLanguages } from './languages.js'; +import type { Language } from './languages.js'; +import { findLanguageForTag, supportedLanguages } from './languages.js'; -const detectLanguage = (languages: ReadonlyArray = supportedLanguages) => { +const detectLanguage = (languages: readonly Language[] = supportedLanguages) => { const locale = osLocaleSync(); if (locale) { const language = findLanguageForTag(locale.toLowerCase(), languages) ?? findLanguageForTag(locale.split('-')[0], languages); diff --git a/generators/languages/support/json/dates.js b/generators/languages/support/json/dates.ts similarity index 100% rename from generators/languages/support/json/dates.js rename to generators/languages/support/json/dates.ts diff --git a/generators/languages/support/languages.spec.ts b/generators/languages/support/languages.spec.ts index 4f88f2d20a93..26d6f52153c5 100644 --- a/generators/languages/support/languages.spec.ts +++ b/generators/languages/support/languages.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { findLanguageForTag, generateLanguagesWebappOptions } from './languages.js'; describe('generator - languages - support', () => { diff --git a/generators/languages/support/languages.ts b/generators/languages/support/languages.ts index 1a374139048b..6cfe9afeb750 100644 --- a/generators/languages/support/languages.ts +++ b/generators/languages/support/languages.ts @@ -263,7 +263,7 @@ const partialLanguages: PartialLanguage[] = [ }, ]; -export const supportedLanguages: ReadonlyArray = partialLanguages.map(language => ({ +export const supportedLanguages: readonly Language[] = partialLanguages.map(language => ({ rtl: false, javaLocaleMessageSourceSuffix: languageToJavaLanguage(language.languageTag), angularLocale: languageToAngularLanguage(language.languageTag), @@ -272,7 +272,7 @@ export const supportedLanguages: ReadonlyArray = partialLanguages.map( ...language, })); -export const findLanguageForTag = (languageTag: string, languages: ReadonlyArray = supportedLanguages): Language | undefined => +export const findLanguageForTag = (languageTag: string, languages: readonly Language[] = supportedLanguages): Language | undefined => languages.find(lang => lang.languageTag === languageTag); export const defaultLanguage = findLanguageForTag('en') as Required; @@ -281,7 +281,7 @@ export const defaultLanguage = findLanguageForTag('en') as Required; * Generate language objects in array of "'en': { name: 'English' }" format * @param languages */ -export const generateLanguagesWebappOptions = (languages: ReadonlyArray) => +export const generateLanguagesWebappOptions = (languages: readonly Language[]) => languages.map(language => `'${language.languageTag}': { name: '${language.displayName}'${language.rtl ? ', rtl: true' : ''} }`); type LanguageIdParts = { language: string; script?: string; country?: string; variant?: string }; @@ -325,6 +325,6 @@ function buildLanguageTag(parts: LanguageIdParts): string { return languageTag; } -export function languagesAsChoices(languages: ReadonlyArray = supportedLanguages) { +export function languagesAsChoices(languages: readonly Language[] = supportedLanguages) { return languages.map(language => ({ value: language.languageTag, name: language.name })); } diff --git a/generators/languages/support/load-config.ts b/generators/languages/support/load-config.ts index b990df9bf9fb..ebbb8fcb1fe4 100644 --- a/generators/languages/support/load-config.ts +++ b/generators/languages/support/load-config.ts @@ -17,7 +17,7 @@ * limitations under the License. */ import { type I18nApplication } from '../types.js'; -import { findLanguageForTag, supportedLanguages as baseSupportedLanguages, type Language } from './languages.js'; +import { type Language, supportedLanguages as baseSupportedLanguages, findLanguageForTag } from './languages.js'; /** * Load translation config into application diff --git a/generators/languages/support/translate.spec.js b/generators/languages/support/translate.spec.ts similarity index 98% rename from generators/languages/support/translate.spec.js rename to generators/languages/support/translate.spec.ts index 96e80293dbf6..6aa5366dafd0 100644 --- a/generators/languages/support/translate.spec.js +++ b/generators/languages/support/translate.spec.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { beforeEach, it, describe, expect, esmocha } from 'esmocha'; +import { beforeEach, describe, esmocha, expect, it } from 'esmocha'; import { createJhiTransformTranslateReplacer, createJhiTransformTranslateStringifyReplacer, diff --git a/generators/languages/support/translate.ts b/generators/languages/support/translate.ts index fe5050a7740b..95fd699a05c5 100644 --- a/generators/languages/support/translate.ts +++ b/generators/languages/support/translate.ts @@ -24,10 +24,6 @@ export const escapeHtmlTranslationValue = (translation: string) => export const escapeTsTranslationValue = (translation: string) => translation.replace(/'/g, "\\'").replace(/\\/g, '\\\\'); -function getTranslationValue(getWebappTranslation, key, data) { - return getWebappTranslation(key, data) || undefined; -} - export type TranslationReplaceOptions = { keyPattern?: string; interpolatePattern?: string; @@ -54,7 +50,7 @@ export const replaceTranslationKeysWithText = ( let key = match.groups?.key; if (!key && keyPattern) { - const keyMatch = target.match(new RegExp(keyPattern)); + const keyMatch = new RegExp(keyPattern).exec(target); key = keyMatch?.groups?.key; } if (!key) { @@ -63,7 +59,7 @@ export const replaceTranslationKeysWithText = ( let interpolate = match.groups?.interpolate; if (!interpolate && interpolatePattern) { - const interpolateMatch = target.match(new RegExp(interpolatePattern)); + const interpolateMatch = new RegExp(interpolatePattern).exec(target); interpolate = interpolateMatch?.groups?.interpolate; } @@ -77,7 +73,7 @@ export const replaceTranslationKeysWithText = ( } } - const translation = getTranslationValue(getWebappTranslation, key, data); + const translation = getWebappTranslation(key, data); let replacement = translation; if (!replacement) { @@ -90,7 +86,7 @@ export const replaceTranslationKeysWithText = ( } else if (stringify) { replacement = JSON.stringify(replacement); } - body = `${body.slice(0, match.index!)}${replacement}${body.slice(match.index! + target.length)}`; + body = `${body.slice(0, match.index)}${replacement}${body.slice(match.index + target.length)}`; } return body; }; @@ -144,7 +140,7 @@ export const replaceTranslateContents = (body: string, filePath: string, regexp: } } - body = `${body.slice(0, match.index!)}${converter({ filePath, key, interpolate, parsedInterpolate, type, prefix, suffix })}${body.slice(match.index! + target.length)}`; + body = `${body.slice(0, match.index)}${converter({ filePath, key, interpolate, parsedInterpolate, type, prefix, suffix })}${body.slice(match.index + target.length)}`; } return body; }; diff --git a/generators/languages/templates/entity/i18n/entity_ar-ly.json.ejs b/generators/languages/templates/entity/i18n/entity_ar-ly.json.ejs index 36546fb53082..860ee20971f6 100644 --- a/generators/languages/templates/entity/i18n/entity_ar-ly.json.ejs +++ b/generators/languages/templates/entity/i18n/entity_ar-ly.json.ejs @@ -22,24 +22,24 @@ let helpBlocks = 0; %> "<%= entityTranslationKey %>" : { "home": { "title": "<%= entityClassPluralHumanized %>", - "refreshListLabel": "Refresh list", + "refreshListLabel": "تحديث القائمة", <%_ if (!readOnly) { _%> - "createLabel": "Create a new <%= entityClassHumanized %>", - "createOrEditLabel": "Create or edit a <%= entityClassHumanized %>", + "createLabel": "إنشاء <%= entityClassHumanized %> جديد", + "createOrEditLabel": "إنشاء أو تعديل <%= entityClassHumanized %>", <%_ } _%> <%_ if (searchEngineAny) { _%> - "search": "Search for <%= entityClassHumanized %>", + "search": "البحث عن <%= entityClassHumanized %>", <%_ } _%> - "notFound": "No <%= entityClassPluralHumanized %> found" + "notFound": "لم يتم العثور على <%= entityClassPluralHumanized %>" }, <%_ if (!microserviceAppName && !readOnly) { _%> - "created": "A new <%= entityClassHumanized %> is created with identifier {{ param }}", - "updated": "A <%= entityClassHumanized %> is updated with identifier {{ param }}", - "deleted": "A <%= entityClassHumanized %> is deleted with identifier {{ param }}", + "created": "<%= entityClassHumanized %> جديد تم إنشاؤه بالمعرف {{ param }}", + "updated": "<%= entityClassHumanized %> تم تحديثه بالمعرف {{ param }}", + "deleted": "<%= entityClassHumanized %> تم حذفه بالمعرف {{ param }}", <%_ } _%> <%_ if (!readOnly) { _%> "delete": { - "question": "Are you sure you want to delete <%= entityClassHumanized %> {{ id }}?" + "question": "هل أنت متأكد أنك تريد حذف <%= entityClassHumanized %> {{ id }}؟" }, <%_ } _%> "detail": { @@ -60,9 +60,9 @@ let helpBlocks = 0; %> <%_ if (microserviceAppName && !readOnly) { _%>, "<%= microserviceAppName %>": { "<%= entityTranslationKey %>" : { - "created": "A new <%= entityClassHumanized %> is created with identifier {{ param }}", - "updated": "A <%= entityClassHumanized %> is updated with identifier {{ param }}", - "deleted": "A <%= entityClassHumanized %> is deleted with identifier {{ param }}" + "created": "<%= entityClassHumanized %> جديد تم إنشاؤه بالمعرف {{ param }}", + "updated": "<%= entityClassHumanized %> تم تحديثه بالمعرف {{ param }}", + "deleted": "<%= entityClassHumanized %> تم حذفه بالمعرف {{ param }}" } } <%_ } _%> diff --git a/generators/languages/translation-data.js b/generators/languages/translation-data.ts similarity index 100% rename from generators/languages/translation-data.js rename to generators/languages/translation-data.ts diff --git a/generators/languages/types.d.ts b/generators/languages/types.d.ts index 67ffc730bc23..85e93f7121a5 100644 --- a/generators/languages/types.d.ts +++ b/generators/languages/types.d.ts @@ -16,19 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Language } from './support/languages.js'; +import type { Language } from './support/languages.js'; + +export type LanguagesSource = { + addEntityTranslationKey: (arg: { translationKey: string; translationValue: string; language: string }) => void; +}; export type I18nApplication = { + enableTranslation: boolean; enableI18nRTL: boolean; nativeLanguage: string; nativeLanguageDefinition: Language; -} & ( - | { - enableTranslation: false; - } - | { - enableTranslation: true; - languages: string[]; - languagesDefinition: ReadonlyArray; - } -); + languages: string[]; + languagesDefinition: readonly Language[]; +}; diff --git a/generators/liquibase/__snapshots__/incremental-liquibase.spec.ts.snap b/generators/liquibase/__snapshots__/incremental-liquibase.spec.ts.snap index c76ae36465f0..5e336e7d6676 100644 --- a/generators/liquibase/__snapshots__/incremental-liquibase.spec.ts.snap +++ b/generators/liquibase/__snapshots__/incremental-liquibase.spec.ts.snap @@ -4,16 +4,16 @@ exports[`generator - app - --incremental-changelog entities with/without byte fi { "src/main/resources/config/liquibase/fake-data/20200101000100_entity_smarty.csv": { "contents": "id;name;price;description;picture;picture_content_type;specification;specification_content_type;category;inventory -1;so;27689.83;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Desktop;28870 -2;night;13757.31;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Desktop;27257 -3;left as;20119.26;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Accessory;4484 -4;who pressu;13543.06;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Accessory;12192 -5;justify lo;31004.02;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Accessory;12654 -6;incidental;10025.34;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Laptop;6701 -7;judgementa;987.58;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Accessory;19506 -8;pish;16423.03;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Desktop;30984 -9;whine conc;0.94;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Tablet;20142 -10;meager hit;3205.08;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Tablet;31836 +1;haul;22475.22;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Phone;13021 +2;distorted ;3290.96;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Tablet;31772 +3;loftily op;21967.32;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Phone;31546 +4;whose befo;864.8;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Tablet;15362 +5;mad vista;14038.24;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Phone;51 +6;sustenance;17923.05;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Desktop;11558 +7;monthly;27992.5;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Accessory;11447 +8;yet while ;19566.22;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Tablet;2955 +9;mobilize;19005.21;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Laptop;4530 +10;unlucky ja;15852.55;../fake-data/blob/hipster.txt;../fake-data/blob/hipster.png;image/png;../fake-data/blob/hipster.png;image/png;Laptop;12544 ", "stateCleared": "modified", }, @@ -24,16 +24,16 @@ exports[`generator - app - --incremental-changelog entities with/without byte fi { "src/main/resources/config/liquibase/fake-data/20200101000100_entity_smarty.csv": { "contents": "id;name;age;height;income;expense;savings;category;happy;dob;exact_time;travel_time;moment -1;so;27690;9228;28869.91;1523.27;11029.18;Laptop;true;2019-12-31;2019-12-31T07:33:17;8479;2019-12-31T09:44:59 -2;snow up;17956;196;6635.36;20119.26;30119.44;Laptop;true;2019-12-31;2019-12-31T05:33:26;27663;2019-12-31T02:26:03 -3;bubble loot;32476;6693;16764.28;2360.94;25178.99;Phone;true;2019-12-31;2019-12-31T22:43:36;21699;2019-12-31T18:00:55 -4;clear-cut vacant;20511;6897;13046.9;2776.1;11256.8;Accessory;false;2019-12-31;2019-12-31T16:07:42;13697;2019-12-31T20:36:00 -5;hedge supposing;1132;30538;4436.81;2931.45;12681.2;Laptop;true;2019-12-31;2019-12-31T11:59:15;7932;2019-12-31T01:19:21 -6;whine concerning pile;0;25903;20141.92;26507.48;24530.15;Phone;false;2019-12-31;2019-12-31T02:06:08;29017;2019-12-31T11:33:28 -7;thousand carelessly tasty;51;20191;8823.52;20755.4;26916.74;Tablet;true;2019-12-31;2019-12-31T17:46:32;12337;2019-12-31T10:52:56 -8;ugh revel shuck;11812;31986;30809.45;16008.41;1218.05;Phone;false;2019-12-31;2019-12-31T20:08:02;27053;2019-12-31T03:28:55 -9;hunch wonderfully;20533;32520;17780.32;14238.39;24671.07;Phone;true;2019-12-31;2019-12-31T19:23:49;24752;2019-12-31T13:02:54 -10;continent madly;25891;12035;16138.39;18899.17;13902.14;Phone;false;2019-12-31;2019-12-31T16:17:43;2955;2019-12-31T04:43:49 +1;haul;22475;19478;13020.74;12384.67;21292.79;Accessory;false;2019-12-31;2019-12-31T09:32:54;17956;2019-12-31T04:52:35 +2;calculating bleak underpants;12654;25637;20510.69;13046.9;11256.8;Phone;true;2019-12-31;2019-12-31T07:21:34;6701;2019-12-31T16:06:22 +3;evenly newsprint;11215;3484;864.8;25400.64;15361.81;Tablet;false;2019-12-31;2019-12-31T12:45:08;25434;2019-12-31T21:16:09 +4;along fax flood;11558;2143;27778.87;32012.96;4034.84;Tablet;false;2019-12-31;2019-12-31T11:47:33;27993;2019-12-31T19:49:52 +5;wash hm;29032;22472;4268.13;27926.7;8191.94;Phone;true;2019-12-31;2019-12-31T14:20:51;20105;2019-12-31T02:10:51 +6;mobilize;19005;1912;4530.43;25028.76;7467.08;Accessory;true;2019-12-31;2019-12-31T15:38:38;19139;2019-12-31T21:32:37 +7;coolly lock;3394;12544;6548.85;2431.98;11956.86;Phone;true;2019-12-31;2019-12-31T01:39:11;28606;2019-12-31T18:05:06 +8;anti baptise fooey;17804;154;15061.95;12875.59;14224.71;Desktop;true;2019-12-31;2019-12-31T01:10:26;25120;2019-12-31T09:37:22 +9;duh;28128;29585;16392.39;31787.99;8992.52;Accessory;false;2019-12-31;2019-12-31T13:36:54;26171;2019-12-31T20:55:47 +10;commonly carefully;17915;30132;27586.52;13849.5;18150.54;Tablet;true;2019-12-31;2019-12-31T04:38:50;14937;2019-12-31T21:01:44 ", "stateCleared": "modified", }, @@ -173,16 +173,16 @@ ROLE_USER }, "src/main/resources/config/liquibase/fake-data/20200102000100_entity_customer.csv": { "contents": "id;foo -1;yuck -2;for atop -3;uncurl -4;elaborate through weep -5;hopelessly -6;easily almost obvious -7;unionize joyously gah -8;half ink -9;psst majestically swiftly -10;ragged +1;an +2;ick +3;same incidentally +4;scarcely +5;violin +6;specific authorized under +7;preregister +8;rightfully +9;replicate newsletter deeply +10;although ", "stateCleared": "modified", }, @@ -299,16 +299,16 @@ ROLE_USER }, "src/main/resources/config/liquibase/fake-data/20200102000100_entity_customer.csv": { "contents": "id;foo -1;yuck -2;for atop -3;uncurl -4;elaborate through weep -5;hopelessly -6;easily almost obvious -7;unionize joyously gah -8;half ink -9;psst majestically swiftly -10;ragged +1;an +2;ick +3;same incidentally +4;scarcely +5;violin +6;specific authorized under +7;preregister +8;rightfully +9;replicate newsletter deeply +10;although ", "stateCleared": "modified", }, @@ -339,6 +339,174 @@ ROLE_USER } `; +exports[`generator - app - --incremental-changelog when adding a many-to-many relationship should match snapshot 1`] = ` +{ + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_One.xml": { + "contents": " + + + + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_constraints_One.xml": { + "contents": " + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_migrate_One.xml": { + "contents": " + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/authority.csv": { + "contents": "name +ROLE_ADMIN +ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user.csv": { + "contents": "id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user_authority.csv": { + "contents": "user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +2;ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/fake-data/20200102000100_entity_one.csv": { + "contents": "one_id +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/master.xml": { + "contents": " + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, +} +`; + exports[`generator - app - --incremental-changelog when adding a relationship should match snapshot 1`] = ` { "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_One.xml": { @@ -389,10 +557,11 @@ exports[`generator - app - --incremental-changelog when adding a relationship sh Added the relationship constraints for entity One. --> - @@ -542,10 +711,11 @@ exports[`generator - app - --incremental-changelog when adding a relationship wi Added the relationship constraints for entity One. --> - - - - @@ -2057,16 +2230,16 @@ ROLE_USER }, "src/main/resources/config/liquibase/fake-data/20200102000100_entity_one.csv": { "contents": "uuid;another_boolean -7b52c50c-94b7-4c95-8335-cb9118919bd4; -3633aeb5-f092-4aa0-b99b-90cc7c07af81; -531ef1f7-b464-4579-839a-9515641d4d5d; -b4dfec2f-a394-41e4-8e93-b3c2b8a6d8e6; -a9b65630-0e52-4a5f-b9e9-5158c941f1e8; -32202a03-207d-40ac-a599-4b7a589a4d97; -22d1e626-02b8-421a-9d17-376fc96da869; -ae017b20-ec7f-4701-94e3-176382308aac; -844915c0-0003-42f7-9c84-0f6179cfb6f2; -a7bcf876-d99f-47a9-93ea-6a721621598b; +33abf9a0-99c7-40a8-be3e-174473a554dd; +bde2a914-9bcb-4ade-a196-60e259918911; +3220270c-9475-4949-a921-66281d77f9d8; +a072e771-e168-438a-8449-5003fc4f19f6; +abf7d979-e671-4258-8548-f4e98d56ee9c; +1d92725c-d9ec-47ea-a520-f4d7cebb36aa; +12c05b9a-bb67-4ab7-aee4-e1c9338c0a26; +5935ced6-8827-473f-abde-ea86d1771534; +472f667d-4e4e-4e92-8ef1-30dbd7dd029e; +791d01d5-8f1d-42b4-a1ff-5db5cc5fe5de; ", "stateCleared": "modified", }, @@ -2087,16 +2260,16 @@ a7bcf876-d99f-47a9-93ea-6a721621598b; }, "src/main/resources/config/liquibase/fake-data/20200102000300_entity_one.csv": { "contents": "uuid -7b52c50c-94b7-4c95-8335-cb9118919bd4 -3633aeb5-f092-4aa0-b99b-90cc7c07af81 -531ef1f7-b464-4579-839a-9515641d4d5d -b4dfec2f-a394-41e4-8e93-b3c2b8a6d8e6 -a9b65630-0e52-4a5f-b9e9-5158c941f1e8 -32202a03-207d-40ac-a599-4b7a589a4d97 -22d1e626-02b8-421a-9d17-376fc96da869 -ae017b20-ec7f-4701-94e3-176382308aac -844915c0-0003-42f7-9c84-0f6179cfb6f2 -a7bcf876-d99f-47a9-93ea-6a721621598b +33abf9a0-99c7-40a8-be3e-174473a554dd +bde2a914-9bcb-4ade-a196-60e259918911 +3220270c-9475-4949-a921-66281d77f9d8 +a072e771-e168-438a-8449-5003fc4f19f6 +abf7d979-e671-4258-8548-f4e98d56ee9c +1d92725c-d9ec-47ea-a520-f4d7cebb36aa +12c05b9a-bb67-4ab7-aee4-e1c9338c0a26 +5935ced6-8827-473f-abde-ea86d1771534 +472f667d-4e4e-4e92-8ef1-30dbd7dd029e +791d01d5-8f1d-42b4-a1ff-5db5cc5fe5de ", "stateCleared": "modified", }, @@ -2318,10 +2491,11 @@ exports[`generator - app - --incremental-changelog when modifying fields and rel Added the relationship constraints for entity Another. --> - diff --git a/generators/liquibase/changelog-files.js b/generators/liquibase/changelog-files.ts similarity index 100% rename from generators/liquibase/changelog-files.js rename to generators/liquibase/changelog-files.ts diff --git a/generators/liquibase/command.ts b/generators/liquibase/command.ts index e18017226dad..fd90dd2bce88 100644 --- a/generators/liquibase/command.ts +++ b/generators/liquibase/command.ts @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; -const command: JHipsterCommandDefinition = { +const command = { options: { skipFakeData: { description: 'Skip generation of fake data for development', @@ -26,6 +26,19 @@ const command: JHipsterCommandDefinition = { scope: 'storage', }, }, -}; + configs: { + incrementalChangelog: { + cli: { + description: 'Creates incremental database changelogs', + type: Boolean, + }, + jdl: { + type: 'boolean', + tokenType: 'BOOLEAN', + }, + scope: 'storage', + }, + }, +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/liquibase/files.ts b/generators/liquibase/files.ts index 814594e158b2..00a331d38aed 100644 --- a/generators/liquibase/files.ts +++ b/generators/liquibase/files.ts @@ -19,11 +19,8 @@ import type { WriteFileSection } from '../base/api.js'; import { SERVER_MAIN_RES_DIR, SERVER_MAIN_SRC_DIR } from '../generator-constants.js'; import { moveToJavaPackageSrcDir } from '../server/support/index.js'; -import { CommonClientServerApplication } from '../base-application/types.js'; -import type LiquibaseGenerator from './generator.js'; -// eslint-disable-next-line import/prefer-default-export -export const liquibaseFiles: WriteFileSection = { +export const liquibaseFiles: WriteFileSection = { liquibase: [ { condition: ctx => ctx.backendTypeSpringBoot, @@ -64,4 +61,12 @@ export const liquibaseFiles: WriteFileSection ctx.graalvmSupport, + transform: false, + path: SERVER_MAIN_RES_DIR, + templates: ['META-INF/native-image/liquibase/reflect-config.json'], + }, + ], }; diff --git a/generators/liquibase/generator.spec.ts b/generators/liquibase/generator.spec.ts index 09dcf8638160..abe1797b8e97 100644 --- a/generators/liquibase/generator.spec.ts +++ b/generators/liquibase/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; diff --git a/generators/liquibase/generator.ts b/generators/liquibase/generator.ts index d32b214ccdb0..085d0f21b6e7 100644 --- a/generators/liquibase/generator.ts +++ b/generators/liquibase/generator.ts @@ -22,21 +22,21 @@ import { escape, min } from 'lodash-es'; import BaseEntityChangesGenerator from '../base-entity-changes/index.js'; import { getFKConstraintName, getUXConstraintName, prepareEntity as prepareEntityForServer } from '../server/support/index.js'; import { + loadRequiredConfigIntoEntity, + prepareEntity, prepareEntityPrimaryKeyForTemplates, - prepareRelationship, prepareField, - prepareEntity, - loadRequiredConfigIntoEntity, + prepareRelationship, } from '../base-application/support/index.js'; import { prepareSqlApplicationProperties } from '../spring-data-relational/support/index.js'; -import { fieldTypes } from '../../jdl/jhipster/index.js'; +import { fieldTypes } from '../../lib/jhipster/index.js'; import type { MavenProperty } from '../maven/types.js'; import { liquibaseFiles } from './files.js'; import { - prepareField as prepareFieldForLiquibase, + liquibaseComment, postPrepareEntity, + prepareField as prepareFieldForLiquibase, prepareRelationshipForLiquibase, - liquibaseComment, } from './support/index.js'; import mavenPlugin from './support/maven-plugin.js'; import { @@ -44,7 +44,7 @@ import { addLiquibaseConstraintsChangelogCallback, addLiquibaseIncrementalChangelogCallback, } from './internal/needles.js'; -import { addEntityFiles, updateEntityFiles, updateConstraintsFiles, updateMigrateFiles, fakeFiles } from './changelog-files.js'; +import { addEntityFiles, fakeFiles, updateConstraintsFiles, updateEntityFiles, updateMigrateFiles } from './changelog-files.js'; const { CommonDBTypes: { LONG: TYPE_LONG, INTEGER: TYPE_INTEGER }, @@ -148,9 +148,7 @@ export default class LiquibaseGenerator extends BaseEntityChangesGenerator { get postPreparingEachEntity() { return this.asPostPreparingEachEntityTaskGroup({ - postPrepareEntity({ application, entity }) { - postPrepareEntity({ application, entity }); - }, + postPrepareEntity, }); } @@ -192,7 +190,7 @@ export default class LiquibaseGenerator extends BaseEntityChangesGenerator { prepareRelationship(entity, relationship, this, true); prepareRelationshipForLiquibase(entity, relationship); } - postPrepareEntity({ application, entity }); + postPrepareEntity.call(this, { application, entity } as any); } } @@ -200,7 +198,7 @@ export default class LiquibaseGenerator extends BaseEntityChangesGenerator { this.options.entities ?? entities.filter(entity => !entity.builtIn && !entity.skipServer).map(entity => entity.name); // Write only specified entities changelogs. const changes = entityChanges.filter( - databaseChangelog => entitiesToWrite!.length === 0 || entitiesToWrite!.includes(databaseChangelog.entityName), + databaseChangelog => entitiesToWrite.length === 0 || entitiesToWrite.includes(databaseChangelog.entityName), ); for (const databaseChangelog of changes) { @@ -491,6 +489,9 @@ export default class LiquibaseGenerator extends BaseEntityChangesGenerator { source.addGradleProperty?.({ property: 'liquibaseTaskPrefix', value: 'liquibase' }); source.addGradleProperty?.({ property: 'liquibasePluginVersion', value: gradleLiquibaseVersion }); + if (application.javaManagedProperties?.['liquibase.version']) { + source.addGradleProperty?.({ property: 'liquibaseCoreVersion', value: application.javaManagedProperties['liquibase.version'] }); + } source.applyFromGradle?.({ script: 'gradle/liquibase.gradle' }); source.addGradlePlugin?.({ id: 'org.liquibase.gradle' }); @@ -510,6 +511,20 @@ export default class LiquibaseGenerator extends BaseEntityChangesGenerator { ); } }, + nativeHints({ source, application }) { + if (!application.graalvmSupport) return; + // Latest liquibase version supported by Reachability Repository is 4.23.0 + // Hints may be dropped if newer version is supported + // https://github.com/oracle/graalvm-reachability-metadata/blob/master/metadata/org.liquibase/liquibase-core/index.json + source.addNativeHint!({ + resources: ['config/liquibase/*'], + declaredConstructors: [ + 'liquibase.database.LiquibaseTableNamesFactory.class', + 'liquibase.report.ShowSummaryGeneratorFactory.class', + ], + publicConstructors: ['liquibase.ui.LoggerUIService.class'], + }); + }, }); } @@ -697,7 +712,6 @@ export default class LiquibaseGenerator extends BaseEntityChangesGenerator { return undefined; } - // eslint-disable-next-line no-nested-ternary const entityChanges = databaseChangelog.changelogData; entityChanges.skipFakeData = application.skipFakeData || entity.skipFakeData; diff --git a/generators/liquibase/incremental-liquibase.spec.ts b/generators/liquibase/incremental-liquibase.spec.ts index 5bcea2cddbe1..c2c275268602 100644 --- a/generators/liquibase/incremental-liquibase.spec.ts +++ b/generators/liquibase/incremental-liquibase.spec.ts @@ -1,13 +1,10 @@ import path, { basename, join } from 'path'; import { existsSync, mkdirSync, writeFileSync } from 'fs'; -import { fileURLToPath } from 'url'; -import { before, it, describe, after, expect } from 'esmocha'; -import { skipPrettierHelpers as helpers, runResult } from '../../testing/index.js'; +import { before, describe, expect, it } from 'esmocha'; +import { skipPrettierHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { SERVER_MAIN_RES_DIR } from '../generator-constants.js'; -import { createImporterFromContent } from '../../jdl/jdl-importer.js'; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +const exceptSourceMethods = ['addLiquibaseChangelog', 'addLiquibaseIncrementalChangelog', 'addLiquibaseConstraintsChangelog']; const incrementalFiles = [ `${SERVER_MAIN_RES_DIR}config/liquibase/master.xml`, @@ -18,7 +15,12 @@ const baseName = 'JhipsterApp'; const jdlApplication = ` application { - config { baseName ${baseName} } + config { + baseName ${baseName} + creationTimestamp ${new Date('2020-01-01').getTime()} + incrementalChangelog true + skipClient true + } entities * }`; @@ -159,27 +161,33 @@ relationship ManyToOne { } `; -const generatorPath = join(__dirname, '../server/index.js'); -const mockedGenerators = ['jhipster:common']; +const jdlApplicationWithEntitiesAndAddedNewMnyToManyRelationship = ` +${jdlApplicationWithEntities} +relationship ManyToMany { + One to Another +}`; + +const exceptMockedGenerators = [ + 'jdl', + 'app', + 'server', + 'spring-boot', + 'java:bootstrap', + 'java:domain', + 'liquibase', + 'spring-data-relational', +]; describe('generator - app - --incremental-changelog', function () { this.timeout(45000); - const options = { - creationTimestamp: '2020-01-01', - }; - const config = { - incrementalChangelog: true, - skipClient: true, - force: true, - }; describe('when creating a new application', () => { - let runResult; before(async () => { - runResult = await helpers.run(generatorPath).withJHipsterConfig(config).withOptions(options).withMockedGenerators(mockedGenerators); + await helpers + .runJHipster('server') + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -191,12 +199,12 @@ describe('generator - app - --incremental-changelog', function () { describe('when incremental liquibase files exists', () => { describe('with default options', () => { - let runResult; before(async () => { - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions(options) + await helpers + .runJHipster('server') + .withJHipsterConfig({ incrementalChangelog: true }) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .doInDir(cwd => { incrementalFiles.forEach(filePath => { filePath = join(cwd, filePath); @@ -206,12 +214,9 @@ describe('generator - app - --incremental-changelog', function () { } writeFileSync(filePath, basename(filePath)); }); - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -228,12 +233,13 @@ describe('generator - app - --incremental-changelog', function () { }); describe('with --recreate-initial-changelog', () => { - let runResult; before(async () => { - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, recreateInitialChangelog: true }) + await helpers + .runJHipster('server') + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) + .withJHipsterConfig({ incrementalChangelog: true }) + .withOptions({ recreateInitialChangelog: true }) .doInDir(cwd => { incrementalFiles.forEach(filePath => { filePath = join(cwd, filePath); @@ -243,12 +249,9 @@ describe('generator - app - --incremental-changelog', function () { } writeFileSync(filePath, basename(filePath)); }); - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -266,35 +269,17 @@ describe('generator - app - --incremental-changelog', function () { }); describe('regenerating the application', () => { - let runResult; before(async () => { - const initialState = createImporterFromContent(jdlApplicationWithRelationshipToUser, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(2); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - const state = createImporterFromContent(jdlApplicationWithRelationshipToUser, { - ...options, - }).import(); - runResult = await runResult - .create(generatorPath) - .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities.JhipsterApp, - creationTimestamp: '2020-01-02', - }) - .run(); + await helpers + .runJDL(jdlApplicationWithRelationshipToUser) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + await helpers.runJHipsterInApplication('jhipster:jdl').withOptions({ + inline: jdlApplicationWithRelationshipToUser, + creationTimestamp: '2020-01-02', + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -328,54 +313,31 @@ describe('generator - app - --incremental-changelog', function () { }); describe('when adding a field without constraints', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent( - ` + await helpers.runJDL(` ${jdlApplication} entity Customer { original String } -`, - { - ...options, - creationTimestampConfig: options.creationTimestamp, - }, - ).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(1); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const state = createImporterFromContent( - ` +`); + + await helpers + .runJDLInApplication( + ` ${jdlApplication} entity Customer { original String foo String } `, - { - ...options, - }, - ).import(); - runResult = await runResult - .create(generatorPath) + ) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities.JhipsterApp, creationTimestamp: '2020-01-02', - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -412,55 +374,31 @@ entity Customer { }); describe('when adding a field with constraints', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent( - ` + await helpers.runJDL(` ${jdlApplication} entity Customer { original String } -`, - { - ...options, - creationTimestampConfig: options.creationTimestamp, - }, - ).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(1); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const regenerateState = createImporterFromContent( - ` +`); + + await helpers + .runJDLInApplication( + ` ${jdlApplication} entity Customer { original String foo String required } `, - { - ...options, - }, - ).import(); - - runResult = await runResult - .create(generatorPath) + ) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: regenerateState.exportedApplicationsWithEntities.JhipsterApp, creationTimestamp: '2020-01-02', - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -497,54 +435,31 @@ entity Customer { }); describe('when removing a field without constraints', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent( - ` + await helpers.runJDL(` ${jdlApplication} entity Customer { original String foo String } -`, - { - ...options, - creationTimestampConfig: options.creationTimestamp, - }, - ).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(1); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const state = createImporterFromContent( - ` +`); + + await helpers + .runJDLInApplication( + ` ${jdlApplication} entity Customer { original String } `, - { - ...options, - }, - ).import(); - runResult = await runResult - .create(generatorPath) + ) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-02', - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -581,54 +496,31 @@ entity Customer { }); describe('when removing a field with constraints', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent( - ` + await helpers.runJDL(` ${jdlApplication} entity Customer { original String foo String required } -`, - { - ...options, - creationTimestampConfig: options.creationTimestamp, - }, - ).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(1); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const state = createImporterFromContent( - ` +`); + + await helpers + .runJDLInApplication( + ` ${jdlApplication} entity Customer { original String } `, - { - ...options, - }, - ).import(); - runResult = await runResult - .create(generatorPath) + ) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-02', - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -665,37 +557,21 @@ entity Customer { }); describe('when adding a relationship', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent(jdlApplicationWithEntities, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(2); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const state = createImporterFromContent(jdlApplicationWithEntitiesAndRelationship, { - ...options, - }).import(); - runResult = await runResult - .create(generatorPath) + await helpers + .runJDL(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + + await helpers + .runJDLInApplication(jdlApplicationWithEntitiesAndRelationship) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-02', - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -723,44 +599,101 @@ entity Customer { ); runResult.assertNoFileContent(`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_One.xml`, 'dropColumn'); }); - it('should create the entity constraint update changelog', () => { + it('should create the entity constraint update changelog with fitting column names', () => { runResult.assertFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_One.xml`]); + runResult.assertFileContent( + `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_One.xml`, + 'baseColumnNames="another_another_id"', + ); + runResult.assertFileContent( + `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_One.xml`, + 'referencedColumnNames="another_id"', + ); }); it('should match snapshot', () => { expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); }); }); - describe('when adding a relationship with on handlers', () => { - let runResult; + + describe('when adding a many-to-many relationship', () => { before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent(jdlApplicationWithEntities, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(2); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const state = createImporterFromContent(jdlApplicationWithEntitiesAndRelationshipsWithOnHandlers, { - ...options, - }).import(); - runResult = await runResult - .create(generatorPath) + await helpers + .runJDL(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + + await helpers + .runJDLInApplication(jdlApplicationWithEntitiesAndAddedNewMnyToManyRelationship) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-02', - }) - .run(); + }); }); - after(() => runResult.cleanup()); + it('should create application', () => { + runResult.assertFile(['.yo-rc.json']); + }); + it('should create entity config file', () => { + runResult.assertFile([join('.jhipster', 'One.json'), join('.jhipster', 'Another.json')]); + }); + it('should create entity initial changelog', () => { + runResult.assertFile([ + `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200101000100_added_entity_One.xml`, + `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200101000200_added_entity_Another.xml`, + ]); + }); + it('should create entity initial fake data', () => { + runResult.assertFile([`${SERVER_MAIN_RES_DIR}config/liquibase/fake-data/20200101000100_entity_one.csv`]); + }); + it('should create relationship table', () => { + runResult.assertFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_One.xml`]); + runResult.assertFileContent( + `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_One.xml`, + 'createTable tableName="rel_one__another"', + ); + runResult.assertFileContent( + `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_One.xml`, + 'column name="another_another_id" type="bigint"', + ); + runResult.assertFileContent( + `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_One.xml`, + 'column name="one_one_id" type="bigint"', + ); + }); + it('should create the entity constraint update changelog referencing both columns of the join table', () => { + runResult.assertFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_One.xml`]); + + runResult.assertFileContent( + `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_One.xml`, + 'baseColumnNames="one_one_id"', + ); + + runResult.assertFileContent( + `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_One.xml`, + 'baseColumnNames="another_another_id"', + ); + }); + it('should match snapshot', () => { + expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); + }); + }); + + describe('when adding a relationship with on handlers', () => { + before(async () => { + await helpers + .runJDL(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + + await helpers + .runJDLInApplication(jdlApplicationWithEntitiesAndRelationshipsWithOnHandlers) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) + .withOptions({ + creationTimestamp: '2020-01-02', + }); + }); it('should create application', () => { runResult.assertFile(['.yo-rc.json']); @@ -807,49 +740,29 @@ entity Customer { }); }); describe('when modifying a relationship with on handlers, only at these handlers', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent(jdlApplicationWithEntities, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(2); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const state = createImporterFromContent(jdlApplicationWithEntitiesAndRelationshipsWithOnHandlers, { - ...options, - }).import(); - runResult = await runResult - .create(generatorPath) + await helpers + .runJDL(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + + await helpers + .runJDLInApplication(jdlApplicationWithEntitiesAndRelationshipsWithOnHandlers) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-02', - }) - .run(); - - const thirdState = createImporterFromContent(jdlApplicationWithEntitiesAndRelationshipsWithChangedOnHandlers, { - ...options, - }).import(); - runResult = await runResult - .create(generatorPath) + }); + + await helpers + .runJDLInApplication(jdlApplicationWithEntitiesAndRelationshipsWithChangedOnHandlers) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: thirdState.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-03', - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -930,49 +843,29 @@ entity Customer { }); describe('when modifying an existing relationship', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent(jdlApplicationWithEntities, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(2); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const state = createImporterFromContent(jdlApplicationWithEntitiesAndRelationshipsWithOnHandlers, { - ...options, - }).import(); - runResult = await runResult - .create(generatorPath) + await helpers + .runJDL(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + + await helpers + .runJDLInApplication(jdlApplicationWithEntitiesAndRelationshipsWithOnHandlers) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-02', - }) - .run(); - - const thirdState = createImporterFromContent(jdlApplicationWithEntitiesAndRelationshipsWithChangedOnHandlersAndChangedNaming, { - ...options, - }).import(); - runResult = await runResult - .create(generatorPath) + }); + + await helpers + .runJDLInApplication(jdlApplicationWithEntitiesAndRelationshipsWithChangedOnHandlersAndChangedNaming) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: thirdState.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-03', - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -1063,24 +956,12 @@ entity Customer { }); describe('when initially creating an application with entities with relationships having on handlers', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent(jdlApplicationWithEntitiesAndRelationshipsWithOnHandlers, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(2); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - }); - - after(() => runResult.cleanup()); + await helpers + .runJDL(jdlApplicationWithEntitiesAndRelationshipsWithOnHandlers) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + }); it('should create application', () => { runResult.assertFile(['.yo-rc.json']); @@ -1126,37 +1007,21 @@ entity Customer { }); describe('when removing a relationship', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent(jdlApplicationWithEntitiesAndRelationship, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(2); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const state = createImporterFromContent(jdlApplicationWithEntities, { - ...options, - }).import(); - runResult = await runResult - .create(generatorPath) + await helpers + .runJDL(jdlApplicationWithEntitiesAndRelationship) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + + await helpers + .runJDLInApplication(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-02', - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -1196,37 +1061,21 @@ entity Customer { }); describe('when modifying fields and relationships at the same time in different entities', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent(jdlApplicationWithEntities, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(2); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const state = createImporterFromContent(jdlApplicationWithChangedEntitiesAndRelationship, { - ...options, - }).import(); - runResult = await runResult - .create(generatorPath) + await helpers + .runJDL(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + + await helpers + .runJDLInApplication(jdlApplicationWithChangedEntitiesAndRelationship) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-02', - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -1293,24 +1142,9 @@ entity Customer { }); describe('when creating entities with default values', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent(jdlApplicationWithEntitiesWithDefaultValues, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(2); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - }); - - after(() => runResult.cleanup()); + await helpers.runJHipster('jdl').withOptions({ inline: jdlApplicationWithEntitiesWithDefaultValues }); + }); it('should create application', () => { runResult.assertFile(['.yo-rc.json']); @@ -1350,38 +1184,21 @@ entity Customer { }); describe('when modifying default values, fields with default values and relationships', () => { - let runResult; before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent(jdlApplicationWithEntitiesWithDefaultValues, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(2); - runResult = await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); - - const state = createImporterFromContent(jdlApplicationWithEntitiesWithChangedDefaultValuesAndNewRelationship, { - ...options, - }).import(); - - runResult = await runResult - .create(generatorPath) + await helpers + .runJDL(jdlApplicationWithEntitiesWithDefaultValues) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + + await helpers + .runJDLInApplication(jdlApplicationWithEntitiesWithChangedDefaultValuesAndNewRelationship) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], creationTimestamp: '2020-01-02', - }) - .run(); + }); }); - after(() => runResult.cleanup()); - it('should create application', () => { runResult.assertFile(['.yo-rc.json']); }); @@ -1432,19 +1249,10 @@ entity Customer { ].forEach(eachEntityConfig => { describe(`testing ${eachEntityConfig.bytesFields ? 'with' : 'without'} byte fields`, () => { before(async () => { - const baseName = 'JhipsterApp'; - const initialState = createImporterFromContent(eachEntityConfig.entity, { - ...options, - creationTimestampConfig: options.creationTimestamp, - }).import(); - const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; - expect(applicationWithEntities).toBeTruthy(); - expect(applicationWithEntities.entities.length).toBe(1); await helpers - .create(generatorPath) - .withJHipsterConfig(config) - .withOptions({ ...options, applicationWithEntities }) - .run(); + .runJDL(eachEntityConfig.entity) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); }); it('should create entity config file', () => { diff --git a/generators/liquibase/internal/needles.ts b/generators/liquibase/internal/needles.ts index 4850ba92629a..41099ea3e936 100644 --- a/generators/liquibase/internal/needles.ts +++ b/generators/liquibase/internal/needles.ts @@ -18,7 +18,7 @@ */ import { createNeedleCallback } from '../../base/support/needles.js'; -import { LiquibaseChangelog, LiquibaseChangelogSection } from '../types.js'; +import type { LiquibaseChangelog, LiquibaseChangelogSection } from '../types.js'; const changelogType = { base: 'liquibase-add-changelog', diff --git a/generators/liquibase/needles.spec.ts b/generators/liquibase/needles.spec.ts index 9dc5bf36dbd1..968eee6ab271 100644 --- a/generators/liquibase/needles.spec.ts +++ b/generators/liquibase/needles.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe } from 'esmocha'; -import { dryRunHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { before, describe, it } from 'esmocha'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import BaseApplicationGenerator from '../base-application/index.js'; import { SERVER_MAIN_RES_DIR } from '../generator-constants.js'; import { GENERATOR_LIQUIBASE } from '../generator-list.js'; @@ -39,10 +39,10 @@ describe('generator - liquibase - needles', () => { `, }) .withJHipsterConfig({ - blueprint: 'myblueprint', clientFramework: 'no', }) .withOptions({ + blueprint: ['myblueprint'], skipPriorities: ['writing'], }) .withGenerators([[mockBlueprintSubGen, { namespace: 'jhipster-myblueprint:liquibase' }]]); diff --git a/generators/liquibase/support/formatting.spec.ts b/generators/liquibase/support/formatting.spec.ts index c2cd7fc9b071..bb1691e5eea8 100644 --- a/generators/liquibase/support/formatting.spec.ts +++ b/generators/liquibase/support/formatting.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import formatAsLiquibaseRemarks from './formatting.js'; describe('generator - liquibase - support - formatting', () => { diff --git a/generators/liquibase/support/formatting.js b/generators/liquibase/support/formatting.ts similarity index 100% rename from generators/liquibase/support/formatting.js rename to generators/liquibase/support/formatting.ts diff --git a/generators/liquibase/support/post-prepare-entity.ts b/generators/liquibase/support/post-prepare-entity.ts index 95ad08612416..596ae73138cd 100644 --- a/generators/liquibase/support/post-prepare-entity.ts +++ b/generators/liquibase/support/post-prepare-entity.ts @@ -16,26 +16,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { fieldTypes } from '../../../jdl/jhipster/index.js'; -import { LiquibaseEntity } from '../types.js'; -import { GeneratorDefinition } from '../../base-application/generator.js'; +import { fieldTypes } from '../../../lib/jhipster/index.js'; +import type { LiquibaseEntity } from '../types.js'; +import { asPostPreparingEachEntityTask } from '../../base-application/support/task-type-inference.js'; const { CommonDBTypes } = fieldTypes; const { LONG: TYPE_LONG, INTEGER: TYPE_INTEGER } = CommonDBTypes; -export default function postPrepareEntity({ - application, - entity, -}: Pick) { +export default asPostPreparingEachEntityTask(function postPrepareEntity({ application, entity }) { const { relationships, builtIn, name, primaryKey } = entity; - if (builtIn && name === 'User') { + if (builtIn && name === 'User' && primaryKey) { const userIdType = primaryKey.type; const idField = primaryKey.fields[0]; const idFieldName = idField.fieldName ?? 'id'; const liquibaseFakeData = application.generateUserManagement ? [ - { [idFieldName]: [TYPE_INTEGER, TYPE_LONG].includes(userIdType) ? 1 : idField.generateFakeData() }, - { [idFieldName]: [TYPE_INTEGER, TYPE_LONG].includes(userIdType) ? 2 : idField.generateFakeData() }, + { [idFieldName]: [TYPE_INTEGER, TYPE_LONG].includes(userIdType) ? 1 : idField.generateFakeData!() }, + { [idFieldName]: [TYPE_INTEGER, TYPE_LONG].includes(userIdType) ? 2 : idField.generateFakeData!() }, ] : []; (entity as LiquibaseEntity).liquibaseFakeData = liquibaseFakeData; @@ -43,4 +40,4 @@ export default function postPrepareEntity({ } (entity as LiquibaseEntity).anyRelationshipIsOwnerSide = relationships.some(relationship => relationship.ownerSide); -} +}); diff --git a/generators/liquibase/support/prepare-field.js b/generators/liquibase/support/prepare-field.ts similarity index 98% rename from generators/liquibase/support/prepare-field.js rename to generators/liquibase/support/prepare-field.ts index e081cc00b52f..fb21d5087ab5 100644 --- a/generators/liquibase/support/prepare-field.js +++ b/generators/liquibase/support/prepare-field.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { databaseTypes, fieldTypes } from '../../../jdl/jhipster/index.js'; +import { databaseTypes, fieldTypes } from '../../../lib/jhipster/index.js'; import { mutateData } from '../../base/support/index.js'; const { MYSQL, MARIADB } = databaseTypes; diff --git a/generators/liquibase/templates/src/main/java/_package_/config/LiquibaseConfiguration.java.ejs b/generators/liquibase/templates/src/main/java/_package_/config/LiquibaseConfiguration.java.ejs index 4e46ee8ff107..fe226ea18d42 100644 --- a/generators/liquibase/templates/src/main/java/_package_/config/LiquibaseConfiguration.java.ejs +++ b/generators/liquibase/templates/src/main/java/_package_/config/LiquibaseConfiguration.java.ejs @@ -63,7 +63,7 @@ public class LiquibaseConfiguration { } <%_ if (databaseTypeSql && !reactive) { _%> - @Value( "${application.liquibase.async-start:true}" ) + @Value("${application.liquibase.async-start:true}") private Boolean asyncStart; <%_ } _%> diff --git a/generators/liquibase/templates/src/main/resources/META-INF/native-image/liquibase/reflect-config.json b/generators/liquibase/templates/src/main/resources/META-INF/native-image/liquibase/reflect-config.json new file mode 100644 index 000000000000..f96cd5d551c6 --- /dev/null +++ b/generators/liquibase/templates/src/main/resources/META-INF/native-image/liquibase/reflect-config.json @@ -0,0 +1,145 @@ +[ + { + "name": "liquibase.logging.mdc.MdcManagerFactory", + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.change.core.LoadDataColumnConfig", + "queryAllPublicMethods": true, + "allDeclaredMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.command.CommandFactory", + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.changelog.ChangeLogHistoryServiceFactory", + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.BigIntType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.BlobType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.BooleanType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.CharType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.ClobType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.CurrencyType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.DatabaseFunctionType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.DateTimeType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.DateType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.DecimalType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.DoubleType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.FloatType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.IntType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.MediumIntType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.NCharType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.NumberType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.NVarcharType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.SmallIntType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.TimestampType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.TimeType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.TinyIntType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.UnknownType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.UUIDType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.VarcharType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + }, + { + "name": "liquibase.datatype.core.XMLType", + "allPublicMethods": true, + "methods": [{ "name": "", "parameterTypes": [] }] + } +] diff --git a/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/add_relationship_constraints.ejs b/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/add_relationship_constraints.ejs new file mode 100644 index 000000000000..eb5c2e60d568 --- /dev/null +++ b/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/add_relationship_constraints.ejs @@ -0,0 +1,81 @@ +<%# + Copyright 2013-2024 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 relationshipType = relationship.relationshipType, +relationshipName = relationship.relationshipName, +ownerSide = relationship.ownerSide, +otherEntityTableName = relationship.otherEntityTableName, +onDelete = relationship.onDelete, +onUpdate = relationship.onUpdate; +if (relationshipType === 'many-to-one' || (relationshipType === 'one-to-one' && ownerSide)) { + const constraintName = this.getFKConstraintName(entity.entityTableName, relationshipName, prodDatabaseType); + let baseColumnNames; + let referencedColumnNames; + if (relationshipType === 'one-to-one' && ownerSide && relationship.id === true) { + baseColumnNames = relationship.otherEntity.primaryKey.fields.map(field => field.columnName).join(','); + referencedColumnNames = relationship.otherEntity.primaryKey.fields.map(field => field.columnName).join(','); + } else if (relationship.otherEntity) { + baseColumnNames = relationship.otherEntity.primaryKey.fields.map(field => relationship.columnName + '_' + field.columnName).join(','); + referencedColumnNames = relationship.otherEntity.primaryKey.fields.map(field => field.columnName).join(','); + } _%> + + + onDelete="<%= onDelete %>" + <%_ } _%> + <%_ if (onUpdate) { _%> + onUpdate="<%= onUpdate %>" + <%_ } _%> + /> +<%_ } else if (relationship.shouldWriteJoinTable) { _%> + + + onDelete="<%= onDelete %>" + <%_ } _%> + <%_ if (onUpdate) { _%> + onUpdate="<%= onUpdate %>" + <%_ } _%> + /> + + + <%_ if (relationship.otherRelationship.onDelete) { _%> + onDelete="<%= relationship.otherRelationship.onDelete %>" + <%_ } _%> + <%_ if (relationship.otherRelationship.onUpdate) { _%> + onUpdate="<%= relationship.otherRelationship.onUpdate %>" + <%_ } _%> + <%_ } _%> + /> +<%_ } _%> diff --git a/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs b/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs index d6840075d11b..82cce4f2419c 100644 --- a/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs +++ b/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs @@ -21,68 +21,8 @@ Added the constraints for entity <%= entity.entityClass %>. --> -<% for (relationship of relationships) { - const relationshipType = relationship.relationshipType, - relationshipName = relationship.relationshipName, - ownerSide = relationship.ownerSide, - otherEntityTableName = relationship.otherEntityTableName, - onDelete = relationship.onDelete, - onUpdate = relationship.onUpdate; - if (relationshipType === 'many-to-one' || (relationshipType === 'one-to-one' && ownerSide)) { - const constraintName = this.getFKConstraintName(entity.entityTableName, relationshipName, prodDatabaseType); - let baseColumnNames; - let referencedColumnNames; - if (relationshipType === 'one-to-one' && ownerSide && relationship.id === true) { - baseColumnNames = relationship.otherEntity.primaryKey.fields.map(field => field.columnName).join(','); - referencedColumnNames = relationship.otherEntity.primaryKey.fields.map(field => field.columnName).join(','); - } else if (relationship.otherEntity) { - baseColumnNames = relationship.otherEntity.primaryKey.fields.map(field => relationship.columnName + '_' + field.columnName).join(','); - referencedColumnNames = relationship.otherEntity.primaryKey.fields.map(field => field.columnName).join(','); - } %> - - onDelete="<%= onDelete %>" - <%_ } _%> - <%_ if (onUpdate) { _%> - onUpdate="<%= onUpdate %>" - <%_ } _%> - /> - <%_ } else if (relationship.shouldWriteJoinTable) { _%> - - - onDelete="<%= onDelete %>" - <%_ } _%> - <%_ if (onUpdate) { _%> - onUpdate="<%= onUpdate %>" - <%_ } _%> - /> - - - <%_ if (relationship.otherRelationship.onDelete) { _%> - onDelete="<%= relationship.otherRelationship.onDelete %>" - <%_ } _%> - <%_ if (relationship.otherRelationship.onUpdate) { _%> - onUpdate="<%= relationship.otherRelationship.onUpdate %>" - <%_ } _%> - <%_ } _%> - /> - <%_ } _%> +<%_ for (relationship of relationships) { _%> +<%- include('./add_relationship_constraints', { entity, relationship, prodDatabaseType }) -%> <%_ } _%> diff --git a/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/updated_entity_constraints.xml.ejs b/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/updated_entity_constraints.xml.ejs index 8936a0c18643..3ed246724759 100644 --- a/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/updated_entity_constraints.xml.ejs +++ b/generators/liquibase/templates/src/main/resources/config/liquibase/changelog/updated_entity_constraints.xml.ejs @@ -105,66 +105,9 @@ if (hasFieldConstraint) { _%> Added the relationship constraints for entity <%= entityClass %>. --> - <%_ for (idx in addedRelationships) { - const relationship = addedRelationships[idx]; - onDelete = relationship.onDelete, - onUpdate = relationship.onUpdate; - - if (relationship.shouldWriteRelationship) { - const constraintName = this.getFKConstraintName(entityTableName, relationship.columnName, prodDatabaseType); - let baseColumnName = relationship.columnName + '_id'; - if (relationship.relationshipType === 'one-to-one' && relationship.id === true) { - baseColumnName = 'id'; - } - _%> - - onDelete="<%= onDelete %>" - <%_ } _%> - <%_ if (onUpdate) { _%> - onUpdate="<%= onUpdate %>" - <%_ } _%> - /> - <%_ } else if (relationship.shouldWriteJoinTable) { - const constraintName = this.getFKConstraintName(relationship.joinTable.name, entityTableName, prodDatabaseType); - const otherEntityConstraintName = this.getFKConstraintName(relationship.joinTable.name, relationship.columnName, prodDatabaseType); - _%> - - - onDelete="<%= onDelete %>" - <%_ } _%> - <%_ if (onUpdate) { _%> - onUpdate="<%= onUpdate %>" - <%_ } _%> - /> - - - <%_ if (relationship.otherRelationship.onDelete) { _%> - onDelete="<%= relationship.otherRelationship.onDelete %>" - <%_ } _%> - <%_ if (relationship.otherRelationship.onUpdate) { _%> - onUpdate="<%= relationship.otherRelationship.onUpdate %>" - <%_ } _%> - <%_ } _%> - /> - <%_ } - } _%> + <%_ for (relationship of addedRelationships) { _%> +<%- include('./add_relationship_constraints', { entity, relationship, prodDatabaseType }) -%> + <%_ } _%> <%_ } _%> diff --git a/generators/maven/__snapshots__/generator.spec.ts.snap b/generators/maven/__snapshots__/generator.spec.ts.snap index 8bef0f57c3e0..abc08bb33575 100644 --- a/generators/maven/__snapshots__/generator.spec.ts.snap +++ b/generators/maven/__snapshots__/generator.spec.ts.snap @@ -66,9 +66,6 @@ exports[`generator - maven with empty configuration should generate only maven f "mvnw.cmd": { "stateCleared": "modified", }, - "pom.xml": { - "stateCleared": "modified", - }, } `; @@ -92,8 +89,5 @@ exports[`generator - maven with valid configuration should generate only maven f "mvnw.cmd": { "stateCleared": "modified", }, - "pom.xml": { - "stateCleared": "modified", - }, } `; diff --git a/generators/maven/__snapshots__/needles.spec.ts.snap b/generators/maven/__snapshots__/needles.spec.ts.snap index b27eb55d7461..b3a3b700d858 100644 --- a/generators/maven/__snapshots__/needles.spec.ts.snap +++ b/generators/maven/__snapshots__/needles.spec.ts.snap @@ -30,14 +30,27 @@ exports[`generator - maven - needles prod profile should match generated pom 1`] prod + + + snapshotsId + snapshotsUrl + + + releasesId + releasesUrl + + + + propertyValue + dependencyManagementGroupId dependencyManagementArtifactId version - type - scope + jar + test exclusionGroupId @@ -47,19 +60,6 @@ exports[`generator - maven - needles prod profile should match generated pom 1`] - - - snapshotsId - snapshotsUrl - - - releasesId - releasesUrl - - - - propertyValue - dependencyGroupId @@ -89,17 +89,6 @@ exports[`generator - maven - needles prod profile should match generated pom 1`] - - mavenPluginManagementGroupId - mavenPluginManagementArtifactId - version - - - exclusionGroupId - exclusionArtifactId - - - org.apache.maven.plugins maven-compiler-plugin @@ -113,6 +102,17 @@ exports[`generator - maven - needles prod profile should match generated pom 1`] + + mavenPluginManagementGroupId + mavenPluginManagementArtifactId + version + + + exclusionGroupId + exclusionArtifactId + + + diff --git a/generators/maven/command.ts b/generators/maven/command.ts index 2ada75a961a8..94903a44c7bd 100644 --- a/generators/maven/command.ts +++ b/generators/maven/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; const command: JHipsterCommandDefinition = { options: {}, @@ -26,6 +26,7 @@ const command: JHipsterCommandDefinition = { cli: { type: Boolean, hide: true, + default: true, }, scope: 'generator', }, diff --git a/generators/maven/constants.js b/generators/maven/constants.ts similarity index 100% rename from generators/maven/constants.js rename to generators/maven/constants.ts diff --git a/generators/maven/files.js b/generators/maven/files.ts similarity index 100% rename from generators/maven/files.js rename to generators/maven/files.ts diff --git a/generators/maven/generator.spec.ts b/generators/maven/generator.spec.ts index e59357f428c1..32263bf98372 100644 --- a/generators/maven/generator.spec.ts +++ b/generators/maven/generator.spec.ts @@ -16,18 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { testBlueprintSupport } from '../../test/support/tests.js'; -import { defaultHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import { GENERATOR_MAVEN } from '../generator-list.js'; import MavenGenerator from './generator.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorFile = join(__dirname, 'index.js'); describe(`generator - ${generator}`, () => { it('generator-list constant matches folder name', () => { @@ -36,7 +35,7 @@ describe(`generator - ${generator}`, () => { describe('blueprint support', () => testBlueprintSupport(generator)); describe('with valid configuration', () => { before(async () => { - await helpers.run(generatorFile).withJHipsterConfig({ + await helpers.runJHipster(generator).withJHipsterConfig({ baseName: 'existing', packageName: 'tech.jhipster', }); @@ -47,7 +46,7 @@ describe(`generator - ${generator}`, () => { }); describe('with empty configuration', () => { before(async () => { - await helpers.run(generatorFile).withJHipsterConfig(); + await helpers.runJHipster(generator).withJHipsterConfig(); }); it('should generate only maven files', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); diff --git a/generators/maven/generator.ts b/generators/maven/generator.ts index 32b5bd51cf3d..2f6af237fde9 100644 --- a/generators/maven/generator.ts +++ b/generators/maven/generator.ts @@ -16,18 +16,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return */ -import assert from 'assert/strict'; + +import assert from 'node:assert/strict'; +import { passthrough } from '@yeoman/transform'; +import { isFileStateModified } from 'mem-fs-editor/state'; import BaseApplicationGenerator from '../base-application/index.js'; -import { type GeneratorDefinition as SpringBootGeneratorDefinition } from '../server/index.js'; import files from './files.js'; import { MAVEN } from './constants.js'; import cleanupOldServerFilesTask from './cleanup.js'; -import { createPomStorage, type PomStorage } from './support/index.js'; +import { type PomStorage, createPomStorage, sortPomFile } from './support/index.js'; -export default class MavenGenerator extends BaseApplicationGenerator { +export default class MavenGenerator extends BaseApplicationGenerator { pomStorage!: PomStorage; sortMavenPom!: boolean; @@ -44,7 +45,7 @@ export default class MavenGenerator extends BaseApplicationGenerator this.preparing); } + get default() { + return this.asDefaultTaskGroup({ + queueTranslateTransform() { + if (this.sortMavenPom) { + this.queueTransformStream( + { + name: 'sorting pom.xml file', + filter: file => isFileStateModified(file) && file.path === this.destinationPath('pom.xml'), + refresh: false, + }, + passthrough(file => { + file.contents = Buffer.from(sortPomFile(file.contents.toString())); + }), + ); + } + }, + }); + } + + get [BaseApplicationGenerator.DEFAULT]() { + return this.delegateTasksToBlueprint(() => this.default); + } + get writing() { return this.asWritingTaskGroup({ cleanupOldServerFilesTask, diff --git a/generators/maven/generators/code-quality/command.ts b/generators/maven/generators/code-quality/command.ts index 7d3ac0741f15..4afecbf25013 100644 --- a/generators/maven/generators/code-quality/command.ts +++ b/generators/maven/generators/code-quality/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; const command: JHipsterCommandDefinition = { configs: {}, diff --git a/generators/maven/generators/code-quality/generator.spec.ts b/generators/maven/generators/code-quality/generator.spec.ts index 4db1e2896450..eee00f12d5e1 100644 --- a/generators/maven/generators/code-quality/generator.spec.ts +++ b/generators/maven/generators/code-quality/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -47,9 +47,11 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ + "jhipster:bootstrap", "jhipster:maven", + "jhipster:project-name", ] `); }); diff --git a/generators/maven/generators/frontend-plugin/command.ts b/generators/maven/generators/frontend-plugin/command.ts index 7d3ac0741f15..4afecbf25013 100644 --- a/generators/maven/generators/frontend-plugin/command.ts +++ b/generators/maven/generators/frontend-plugin/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; const command: JHipsterCommandDefinition = { configs: {}, diff --git a/generators/maven/generators/frontend-plugin/generator.spec.ts b/generators/maven/generators/frontend-plugin/generator.spec.ts index 67446df55f0b..8743203c9b6d 100644 --- a/generators/maven/generators/frontend-plugin/generator.spec.ts +++ b/generators/maven/generators/frontend-plugin/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -47,9 +47,11 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ + "jhipster:bootstrap", "jhipster:maven", + "jhipster:project-name", ] `); }); diff --git a/generators/maven/generators/frontend-plugin/generator.ts b/generators/maven/generators/frontend-plugin/generator.ts index bb6b3c2b3811..ac68d698f07f 100644 --- a/generators/maven/generators/frontend-plugin/generator.ts +++ b/generators/maven/generators/frontend-plugin/generator.ts @@ -40,6 +40,9 @@ export default class FrontendPluginGenerator extends BaseApplicationGenerator { clientFrameworkAngular, clientFrameworkReact, clientFrameworkVue, + clientFrameworkBuiltIn, + clientBundlerVite, + clientBundlerWebpack, microfrontend, srcMainWebapp, } = application; @@ -52,15 +55,20 @@ export default class FrontendPluginGenerator extends BaseApplicationGenerator { 'tsconfig.json', ]; if (clientFrameworkAngular) { - checksumIncludedFiles.push('tsconfig.app.json', 'webpack/*.*'); + checksumIncludedFiles.push('tsconfig.app.json'); } else if (clientFrameworkReact) { - checksumIncludedFiles.push('.postcss.config.js', 'webpack/*.*'); + checksumIncludedFiles.push('.postcss.config.js'); } else if (clientFrameworkVue) { checksumIncludedFiles.push('.postcssrc.js', 'tsconfig.app.json'); if (microfrontend) { + checksumIncludedFiles.push('module-federation.config.cjs'); + } + } + if (clientFrameworkBuiltIn) { + if (clientBundlerWebpack) { checksumIncludedFiles.push('webpack/*.*'); - } else { - checksumIncludedFiles.push('vite.config.ts'); + } else if (clientBundlerVite) { + checksumIncludedFiles.push('vite.config.mts'); } } source.addMavenDefinition!({ diff --git a/generators/maven/generators/jib/command.ts b/generators/maven/generators/jib/command.ts index 7d3ac0741f15..4afecbf25013 100644 --- a/generators/maven/generators/jib/command.ts +++ b/generators/maven/generators/jib/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; const command: JHipsterCommandDefinition = { configs: {}, diff --git a/generators/maven/generators/jib/generator.spec.ts b/generators/maven/generators/jib/generator.spec.ts index 8db761c07cab..8fb1850d62f2 100644 --- a/generators/maven/generators/jib/generator.spec.ts +++ b/generators/maven/generators/jib/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); diff --git a/generators/maven/generators/jib/generator.ts b/generators/maven/generators/jib/generator.ts index b981e579fd68..c3cb4253cbe9 100644 --- a/generators/maven/generators/jib/generator.ts +++ b/generators/maven/generators/jib/generator.ts @@ -97,8 +97,31 @@ export default class JibGenerator extends BaseApplicationGenerator { 755 - -`, + ${ + application.backendTypeSpringBoot + ? ` + + + com.google.cloud.tools.jib.maven.extension.springboot.JibSpringBootExtension + + +` + : '' + } +${ + application.backendTypeSpringBoot + ? ` + + + com.google.cloud.tools + jib-spring-boot-extension-maven + ${application.javaDependencies!['jib-spring-boot-extension-maven']} + + +` + : '' + } +`, }, ], }); diff --git a/generators/maven/internal/pom-sort.ts b/generators/maven/internal/pom-sort.ts new file mode 100644 index 000000000000..17691db2f196 --- /dev/null +++ b/generators/maven/internal/pom-sort.ts @@ -0,0 +1,162 @@ +/** + * Copyright 2013-2024 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. + */ +import sortKeys from 'sort-keys'; + +import type { MavenDependency, MavenProfile } from '../types.js'; + +export const formatPomFirstLevel = content => + content.replace( + /(\n {4}<(?:groupId|distributionManagement|repositories|pluginRepositories|properties|dependencyManagement|dependencies|build|profiles)>)/g, + '\n$1', + ); + +const rootAndProfileOrder = [ + 'id', + 'activation', + 'modelVersion', + 'groupId', + 'artifactId', + 'version', + 'packaging', + 'name', + 'description', + 'parent', + 'repositories', + 'pluginRepositories', + 'distributionManagement', + 'properties', + 'dependencyManagement', + 'dependencies', + 'build', + 'profiles', +]; + +const propertiesOrder = [ + 'maven.version', + 'java.version', + 'node.version', + 'npm.version', + 'project.build.sourceEncoding', + 'project.reporting.outputEncoding', + 'maven.build.timestamp.format', + 'maven.compiler.source', + 'maven.compiler.target', + 'start-class', + 'argLine', + 'm2e.apt.activation', + 'run.addResources', + 'jhipster-dependencies.version', + 'spring-boot.version', +]; + +const groupIdOrder = [ + 'tech.jhipster', + 'org.apache.maven.plugins', + 'org.springframework.boot', + 'org.springframework.security', + 'org.springdoc', +]; + +const sortSection = section => { + return Object.fromEntries( + Object.entries(section).sort(([key1, value1], [key2, value2]) => { + if (typeof value1 === typeof value2) key1.localeCompare(key2); + if (typeof value1 === 'string') return -1; + if (typeof value2 === 'string') return 1; + return 0; + }), + ); +}; + +const isComment = name => name.startsWith('#'); + +const toMaxInt = nr => (nr === -1 ? Number.MAX_SAFE_INTEGER : nr); + +const sortWithTemplate = (template: string[], a: string, b: string) => { + if (isComment(a)) return -1; + if (isComment(b)) return 1; + const indexOfA = toMaxInt(template.indexOf(a)); + const indexOfB = toMaxInt(template.indexOf(b)); + if (indexOfA === indexOfB) { + return a.localeCompare(b); + } + return indexOfA - indexOfB; +}; + +const comparator = (order: string[]) => (a: string, b: string) => sortWithTemplate(order, a, b); + +const sortProperties = properties => sortKeys(properties, { compare: comparator(propertiesOrder) }); + +const sortArtifacts = (artifacts: MavenDependency[]) => + artifacts.sort((a: MavenDependency, b: MavenDependency) => { + if (a.scope === 'import' || b.scope === 'import') { + if (a.scope === b.scope) { + return 1; + } + return a.scope === 'import' ? -1 : 1; + } + if (a.groupId !== b.groupId) { + if (a.groupId === undefined) { + return -1; + } + if (b.groupId === undefined) { + return 1; + } + const groupIdCompared = sortWithTemplate(groupIdOrder, a.groupId, b.groupId); + if (groupIdCompared) return groupIdCompared; + } + return a.artifactId.localeCompare(b.artifactId); + }); + +const sortProfiles = (profiles: MavenProfile[]) => profiles.sort((a, b) => a.id?.localeCompare(b.id) ?? 1); + +const sortProjectLike = (projectLike: any, options: { sortPlugins?: boolean } = {}): any => { + const { sortPlugins = true } = options; + projectLike = sortKeys(projectLike, { compare: comparator(rootAndProfileOrder) }); + if (projectLike.properties) { + projectLike.properties = sortProperties(projectLike.properties); + } + if (Array.isArray(projectLike.dependencies?.dependency)) { + projectLike.dependencies.dependency = sortArtifacts(projectLike.dependencies.dependency); + } + if (Array.isArray(projectLike.dependencyManagement?.dependencies?.dependency)) { + projectLike.dependencyManagement.dependencies.dependency = sortArtifacts(projectLike.dependencyManagement.dependencies.dependency); + } + if (projectLike.build) { + projectLike.build = sortSection(projectLike.build); + + if (sortPlugins && Array.isArray(projectLike.build.plugins?.plugin)) { + projectLike.build.plugins.plugin = sortArtifacts(projectLike.build.plugins.plugin); + } + if (Array.isArray(projectLike.build.pluginManagement?.plugins?.plugin)) { + projectLike.build.pluginManagement.plugins.plugin = sortArtifacts(projectLike.build.pluginManagement.plugins.plugin); + } + } + return projectLike; +}; + +export const sortPomProject = (project: any): any => { + project = sortProjectLike(project); + if (Array.isArray(project.profiles?.profile)) { + project.profiles.profile = sortProfiles(project.profiles.profile.map(profile => sortProjectLike(profile, { sortPlugins: false }))); + } else if (project.profiles?.profile) { + project.profiles.profile = sortProjectLike(project.profiles.profile, { sortPlugins: false }); + } + return project; +}; diff --git a/generators/maven/internal/xml-store.ts b/generators/maven/internal/xml-store.ts index be39af73984e..c703736416bb 100644 --- a/generators/maven/internal/xml-store.ts +++ b/generators/maven/internal/xml-store.ts @@ -18,21 +18,23 @@ */ import assert from 'assert'; -import { XMLParser, XMLBuilder, XmlBuilderOptions, X2jOptions } from 'fast-xml-parser'; +import type { X2jOptions, XmlBuilderOptions } from 'fast-xml-parser'; +import { XMLBuilder, XMLParser } from 'fast-xml-parser'; import { merge } from 'lodash-es'; const defaultXmlCommonOptions: Partial = { ignoreAttributes: false, attributeNamePrefix: '@@', commentPropName: '#comment', - parseAttributeValue: false, }; -const defaultXmlParserOptions: Partial = { +export const defaultXmlParserOptions: Partial = { + parseAttributeValue: false, + parseTagValue: false, ...defaultXmlCommonOptions, }; -const defaultXmlBuildOptions: Partial = { +export const defaultXmlBuildOptions: Partial = { ...defaultXmlCommonOptions, suppressBooleanAttributes: false, suppressEmptyNode: true, diff --git a/generators/maven/needles.spec.ts b/generators/maven/needles.spec.ts index ec026506edb9..4b3b4e40c22d 100644 --- a/generators/maven/needles.spec.ts +++ b/generators/maven/needles.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe, expect } from 'esmocha'; -import { dryRunHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { before, describe, expect, it } from 'esmocha'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import BaseApplicationGenerator from '../base-application/index.js'; import { GENERATOR_MAVEN } from '../generator-list.js'; @@ -23,8 +23,8 @@ class mockBlueprintSubGen extends BaseApplicationGenerator { groupId: 'dependencyManagementGroupId', artifactId: 'dependencyManagementArtifactId', version: 'version', - type: 'type', - scope: 'scope', + type: 'jar', + scope: 'test', additionalContent: ` @@ -122,8 +122,10 @@ describe('generator - maven - needles', () => { before(async () => { await helpers .runJHipster(GENERATOR_MAVEN) + .withOptions({ + blueprint: ['myblueprint'], + }) .withJHipsterConfig({ - blueprint: 'myblueprint', clientFramework: 'no', }) .withGenerators([[mockBlueprintSubGen, { namespace: 'jhipster-myblueprint:maven' }]]); @@ -137,8 +139,8 @@ describe('generator - maven - needles', () => { dependencyManagementGroupId dependencyManagementArtifactId version - type - scope + jar + test exclusionGroupId @@ -247,10 +249,10 @@ describe('generator - maven - needles', () => { await helpers .runJHipster(GENERATOR_MAVEN) .withJHipsterConfig({ - blueprint: 'myblueprint', clientFramework: 'no', }) .withOptions({ + blueprint: ['myblueprint'], profile: 'prod', }) .withGenerators([[mockBlueprintSubGen, { namespace: 'jhipster-myblueprint:maven' }]]); @@ -264,8 +266,8 @@ describe('generator - maven - needles', () => { dependencyManagementGroupId dependencyManagementArtifactId version - type - scope + jar + test exclusionGroupId diff --git a/generators/maven/support/dependabot-maven.spec.ts b/generators/maven/support/dependabot-maven.spec.ts new file mode 100644 index 000000000000..57955d7fdc5b --- /dev/null +++ b/generators/maven/support/dependabot-maven.spec.ts @@ -0,0 +1,49 @@ +/** + * Copyright 2013-2024 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. + */ +import { describe, expect } from 'esmocha'; +import { parseMavenPom } from './dependabot-maven.js'; + +describe('parseMavenPom', () => { + it('should parse a pom file', () => { + const pomContent = ` + + test + 1.0 + + 1.0 + +`; + const pom = parseMavenPom(pomContent); + expect(pom).toMatchInlineSnapshot(` +{ + "?xml": { + "@@encoding": "UTF-8", + "@@version": "1.0", + }, + "project": { + "artifactId": "test", + "properties": { + "test.version": "1.0", + }, + "version": "1.0", + }, +} +`); + }); +}); diff --git a/generators/maven/support/dependabot-maven.ts b/generators/maven/support/dependabot-maven.ts index 61ec67684b9c..afbfbf1a30e9 100644 --- a/generators/maven/support/dependabot-maven.ts +++ b/generators/maven/support/dependabot-maven.ts @@ -17,13 +17,14 @@ * limitations under the License. */ import { XMLParser } from 'fast-xml-parser'; +import { defaultXmlParserOptions } from '../internal/xml-store.js'; /** * Extract properties from pom content * @param pomContent */ export function getPomProperties(pomContent: string): Record { - return new XMLParser().parse(pomContent).project.properties; + return new XMLParser(defaultXmlParserOptions).parse(pomContent).project.properties; } export type MavenPom = { @@ -44,7 +45,7 @@ export type MavenPomAndVersions = { * @param fileContent */ export function parseMavenPom(fileContent: string): MavenPom { - return new XMLParser().parse(fileContent); + return new XMLParser(defaultXmlParserOptions).parse(fileContent); } /** diff --git a/generators/maven/support/index.ts b/generators/maven/support/index.ts index c3e3449ffe37..1f72e5fbc627 100644 --- a/generators/maven/support/index.ts +++ b/generators/maven/support/index.ts @@ -19,4 +19,5 @@ export * from './dependabot-maven.js'; export { default as PomStorage } from './pom-store.js'; +export * from './pom-file-sort.js'; export * from './pom-store.js'; diff --git a/generators/maven/support/pom-file-sort.spec.ts b/generators/maven/support/pom-file-sort.spec.ts new file mode 100644 index 000000000000..e482073c2c44 --- /dev/null +++ b/generators/maven/support/pom-file-sort.spec.ts @@ -0,0 +1,102 @@ +/** + * Copyright 2013-2024 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. + */ +import { describe, expect } from 'esmocha'; +import { sortPomFile } from './pom-file-sort.js'; + +describe('sortPomProject', () => { + it('should sort a pom file', () => { + const pomContent = ` + + test + 1.0 + + + 1.0 + + +`; + const sorted = sortPomFile(pomContent); + expect(sorted).toBe(pomContent); + }); + + it('should sort build.plugins', () => { + const pomContent = ` + + + + + + b + b + + + a + a + + + + +`; + const sorted = sortPomFile(pomContent); + expect(sorted).toBe(` + + + + + + a + a + + + b + b + + + + +`); + }); + + it('should not sort profiles build.plugins', () => { + const pomContent = ` + + + + + dev + + + + b + b + + + a + a + + + + + + +`; + const sorted = sortPomFile(pomContent); + expect(sorted).toBe(pomContent); + }); +}); diff --git a/generators/maven/support/pom-file-sort.ts b/generators/maven/support/pom-file-sort.ts new file mode 100644 index 000000000000..f96757c8bbb3 --- /dev/null +++ b/generators/maven/support/pom-file-sort.ts @@ -0,0 +1,34 @@ +/** + * Copyright 2013-2024 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. + */ +import type { X2jOptions, XmlBuilderOptions } from 'fast-xml-parser'; +import { XMLBuilder, XMLParser } from 'fast-xml-parser'; + +import { defaultXmlBuildOptions, defaultXmlParserOptions } from '../internal/xml-store.js'; +import { formatPomFirstLevel, sortPomProject } from '../internal/pom-sort.js'; + +type SortPomFileOptions = { xmlParserOptions?: Partial; xmlBuildOptions?: Partial }; + +export const sortPomFile = (pomFile: string, { xmlParserOptions, xmlBuildOptions }: SortPomFileOptions = {}): string => { + const parser = new XMLParser({ ...defaultXmlParserOptions, ...xmlParserOptions }); + const pomObject = parser.parse(pomFile); + pomObject.project = sortPomProject(pomObject.project); + + const builder = new XMLBuilder({ ...defaultXmlBuildOptions, ...xmlBuildOptions }); + return formatPomFirstLevel(builder.build(pomObject)); +}; diff --git a/generators/maven/support/pom-store.ts b/generators/maven/support/pom-store.ts index 1721494998ac..6dc234289879 100644 --- a/generators/maven/support/pom-store.ts +++ b/generators/maven/support/pom-store.ts @@ -17,12 +17,11 @@ * limitations under the License. */ -import { set, get } from 'lodash-es'; -import sortKeys from 'sort-keys'; +import { get, set } from 'lodash-es'; -import CoreGenerator from '../../base-core/index.js'; +import type CoreGenerator from '../../base-core/index.js'; import XmlStorage from '../internal/xml-store.js'; -import { +import type { MavenAnnotationProcessor, MavenArtifact, MavenDependency, @@ -32,79 +31,7 @@ import { MavenProperty, MavenRepository, } from '../types.js'; - -const rootOrder = [ - 'modelVersion', - 'groupId', - 'artifactId', - 'version', - 'packaging', - 'name', - 'description', - 'parent', - 'repositories', - 'pluginRepositories', - 'distributionManagement', - 'properties', - 'dependencyManagement', - 'dependencies', - 'build', - 'profiles', -]; - -const propertiesOrder = [ - 'maven.version', - 'java.version', - 'node.version', - 'npm.version', - 'project.build.sourceEncoding', - 'project.reporting.outputEncoding', - 'maven.build.timestamp.format', - 'maven.compiler.source', - 'maven.compiler.target', - 'start-class', - 'argLine', - 'm2e.apt.activation', - 'run.addResources', - 'jhipster-dependencies.version', - 'spring-boot.version', -]; - -const formatFirstXmlLevel = content => - content.replace( - /(\n {4}<(?:groupId|distributionManagement|repositories|pluginRepositories|properties|dependencyManagement|dependencies|build|profiles)>)/g, - '\n$1', - ); - -const sortSection = section => { - return Object.fromEntries( - Object.entries(section).sort(([key1, value1], [key2, value2]) => { - if (typeof value1 === typeof value2) key1.localeCompare(key2); - if (typeof value1 === 'string') return -1; - if (typeof value2 === 'string') return 1; - return 0; - }), - ); -}; - -const isComment = name => name.startsWith('#'); - -const toMaxInt = nr => (nr === -1 ? Number.MAX_SAFE_INTEGER : nr); - -const sortWithTemplate = (template: string[], a: string, b: string) => { - if (isComment(a)) return -1; - if (isComment(b)) return 1; - const indexOfA = toMaxInt(template.findIndex(item => item === a)); - const indexOfB = toMaxInt(template.findIndex(item => item === b)); - if (indexOfA === indexOfB) { - return a.localeCompare(b); - } - return indexOfA - indexOfB; -}; - -const comparator = (order: string[]) => (a: string, b: string) => sortWithTemplate(order, a, b); - -const sortProperties = properties => sortKeys(properties, { compare: comparator(propertiesOrder) }); +import { formatPomFirstLevel, sortPomProject } from '../internal/pom-sort.js'; const artifactEquals = (a: MavenArtifact, b: MavenArtifact) => { return a.groupId === b.groupId && a.artifactId === b.artifactId; @@ -154,25 +81,6 @@ const ensureProfile = (project, profileId: string) => { return appendOrGet(profileArray, { id: profileId }, idEquals); }; -const groupIdOrder = ['tech.jhipster', 'org.springframework.boot', 'org.springframework.security', 'org.springdoc']; - -const sortArtifacts = (artifacts: MavenArtifact[]) => - artifacts.sort((a: MavenArtifact, b: MavenArtifact) => { - if (a.groupId !== b.groupId) { - if (a.groupId === undefined) { - return -1; - } - if (b.groupId === undefined) { - return 1; - } - const groupIdCompared = sortWithTemplate(groupIdOrder, a.groupId, b.groupId); - if (groupIdCompared) return groupIdCompared; - } - return a.artifactId.localeCompare(b.artifactId); - }); - -const sortProfiles = (profiles: MavenProfile[]) => profiles.sort((a, b) => a.id?.localeCompare(b.id) ?? 1); - const ensureChildPath = (node: any, childPath) => { let child = get(node, childPath); if (child) return child; @@ -334,30 +242,7 @@ export default class PomStorage extends XmlStorage { protected sort() { if (this.store.project) { - const project = sortKeys(this.store.project, { compare: comparator(rootOrder) }); - this.store.project = project; - if (project.properties) { - project.properties = sortProperties(project.properties); - } - if (Array.isArray(project.dependencies?.dependency)) { - project.dependencies.dependency = sortArtifacts(project.dependencies.dependency); - } - if (Array.isArray(project.dependencyManagement?.dependencies?.dependency)) { - project.dependencyManagement.dependencies.dependency = sortArtifacts(project.dependencyManagement.dependencies.dependency); - } - if (project.build) { - project.build = sortSection(project.build); - - if (Array.isArray(project.build.plugins?.plugin)) { - project.build.plugins.plugin = sortArtifacts(project.build.plugins.plugin); - } - if (Array.isArray(project.build.pluginManagement?.plugins?.plugin)) { - project.build.pluginManagement.plugins.plugin = sortArtifacts(project.build.pluginManagement.plugins.plugin); - } - } - if (Array.isArray(project.profiles?.profile)) { - project.profiles.profile = sortProfiles(project.profiles.profile); - } + this.store.project = sortPomProject(this.store.project); } } } @@ -373,7 +258,7 @@ export const createPomStorage = (generator: CoreGenerator, { sortFile }: { sortF const loadFile = () => generator.readDestination('pom.xml', { defaults: emptyPomFile })?.toString() ?? ''; const pomStorage = new PomStorage({ loadFile, - saveFile: content => generator.writeDestination('pom.xml', formatFirstXmlLevel(content)), + saveFile: content => generator.writeDestination('pom.xml', formatPomFirstLevel(content)), sortFile, }); generator.fs.store.on('change', filename => { diff --git a/generators/maven/templates/.mvn/wrapper/maven-wrapper.properties b/generators/maven/templates/.mvn/wrapper/maven-wrapper.properties index 9e89223c9b15..b558da459ac0 100644 --- a/generators/maven/templates/.mvn/wrapper/maven-wrapper.properties +++ b/generators/maven/templates/.mvn/wrapper/maven-wrapper.properties @@ -15,4 +15,4 @@ # specific language governing permissions and limitations # under the License. wrapperVersion=3.3.2 -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.8/apache-maven-3.9.8-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/generators/maven/types.d.ts b/generators/maven/types.d.ts index 6301cfb5ca9e..a146a84180db 100644 --- a/generators/maven/types.d.ts +++ b/generators/maven/types.d.ts @@ -17,9 +17,9 @@ * limitations under the License. */ -export type MavenArtifact = { - groupId?: string; - artifactId: string; +import type { JavaArtifact } from '../java/types.js'; + +export type MavenArtifact = JavaArtifact & { version?: string; inProfile?: string; }; @@ -40,9 +40,7 @@ export type MavenRepository = { }; export type MavenDependency = MavenArtifact & { - type?: string; - scope?: string; - classifier?: string; + optional?: boolean; additionalContent?: string; }; @@ -76,7 +74,7 @@ export type MavenDefinition = { }; export type MavenSourceType = { - mergeMavenPomContent?(content: any): void; + mergeMavenPomContent?(content: Record): void; addMavenAnnotationProcessor?(artifact: MavenAnnotationProcessor | MavenAnnotationProcessor[]): void; addMavenDependency?(dependency: MavenDependency | MavenDependency[]): void; addMavenDependencyManagement?(dependency: MavenDependency | MavenDependency[]): void; diff --git a/generators/needle-api.js b/generators/needle-api.ts similarity index 92% rename from generators/needle-api.js rename to generators/needle-api.ts index f5516ca81d82..ebeef04f0a73 100644 --- a/generators/needle-api.js +++ b/generators/needle-api.ts @@ -23,6 +23,12 @@ import ClientReact from './react/needle-api/needle-client-react.js'; import ClientVue from './client/needle-api/needle-client-vue.js'; export default class NeedleApi { + base: Base; + client: Client; + clientAngular: ClientAngular; + clientReact: ClientReact; + clientVue: ClientVue; + constructor(generator) { this.base = new Base(generator); this.client = new Client(generator); diff --git a/generators/needle-base.ts b/generators/needle-base.ts index 56d0f397f82f..dee39d9798cb 100644 --- a/generators/needle-base.ts +++ b/generators/needle-base.ts @@ -17,8 +17,9 @@ * limitations under the License. */ import chalk from 'chalk'; -import BaseGenerator from './base/index.js'; -import { createNeedleCallback, NeedleInsertion } from './base/support/needles.js'; +import type BaseGenerator from './base/index.js'; +import type { NeedleInsertion } from './base/support/needles.js'; +import { createNeedleCallback } from './base/support/needles.js'; export type NeedleFileModel = { /** diff --git a/generators/project-name/command.ts b/generators/project-name/command.ts index e8d1ea371518..c0faea90d1b5 100644 --- a/generators/project-name/command.ts +++ b/generators/project-name/command.ts @@ -16,17 +16,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; -import { BASE_NAME, BASE_NAME_DESCRIPTION } from './constants.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; +import { BASE_NAME_DESCRIPTION } from './constants.js'; -const command: JHipsterCommandDefinition = { - options: { - [BASE_NAME]: { +const command = { + configs: { + defaultBaseName: { + internal: true, + scope: 'generator', + }, + validateBaseName: { + internal: true, + scope: 'generator', + }, + baseName: { description: BASE_NAME_DESCRIPTION, - type: String, + cli: { + type: String, + }, + prompt: gen => ({ + type: 'input', + validate: input => gen.validateBaseName(input), + message: 'What is the base name of your application?', + default: () => gen.defaultBaseName(), + }), scope: 'storage', }, }, -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/project-name/constants.js b/generators/project-name/constants.ts similarity index 100% rename from generators/project-name/constants.js rename to generators/project-name/constants.ts diff --git a/generators/project-name/generator.spec.ts b/generators/project-name/generator.spec.ts index cf104de3ce71..18a6d264bb4e 100644 --- a/generators/project-name/generator.spec.ts +++ b/generators/project-name/generator.spec.ts @@ -18,9 +18,10 @@ */ import { basename, dirname, join } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { basicTests, testBlueprintSupport } from '../../test/support/tests.js'; import { GENERATOR_PROJECT_NAME } from '../generator-list.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/helpers.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -41,4 +42,27 @@ describe(`generator - ${generator}`, () => { }, generatorPath, }); + describe('run', () => { + before(async () => { + await helpers.runJHipster(generator); + }); + it('should apply default baseName', () => { + expect(runResult.askedQuestions).toMatchInlineSnapshot(` +[ + { + "answer": "jhipster", + "name": "baseName", + }, +] +`); + }); + }); + describe('with defaultBaseName option', () => { + before(async () => { + await helpers.runJHipster(generator).withOptions({ defaults: true, defaultBaseName: () => 'foo' }); + }); + it('should apply default baseName', () => { + runResult.assertJsonFileContent('.yo-rc.json', { 'generator-jhipster': { baseName: 'foo' } }); + }); + }); }); diff --git a/generators/project-name/generator.js b/generators/project-name/generator.ts similarity index 66% rename from generators/project-name/generator.js rename to generators/project-name/generator.ts index 9035149bf2fd..bb08d95f8f25 100644 --- a/generators/project-name/generator.js +++ b/generators/project-name/generator.ts @@ -16,26 +16,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable consistent-return */ -import { defaults, kebabCase, upperFirst, camelCase, startCase } from 'lodash-es'; + +import { camelCase, defaults, kebabCase, startCase, upperFirst } from 'lodash-es'; import BaseApplicationGenerator from '../base-application/index.js'; import { getHipster } from '../base/support/index.js'; import { getDefaultAppName } from './support/index.js'; -import { BASE_NAME } from './constants.js'; import { validateProjectName } from './support/name-resolver.js'; -/** - * @class - * @extends {BaseApplicationGenerator} - */ export default class ProjectNameGenerator extends BaseApplicationGenerator { - javaApplication; + javaApplication?: boolean; + defaultBaseName: () => string = () => + getDefaultAppName({ + reproducible: this.options.reproducible, + javaApplication: this.javaApplication, + }); + validateBaseName: (input: string) => boolean | string = (input: string) => + validateProjectName(input, { javaApplication: this.javaApplication }); async beforeQueue() { - this.sharedData.getControl().existingProject = - this.options.defaults || this.options.applicationWithConfig || (this.jhipsterConfig.baseName !== undefined && this.config.existed); + this.sharedData.getControl().existingProject = Boolean( + this.options.defaults || this.options.applicationWithConfig || (this.jhipsterConfig.baseName !== undefined && this.config.existed), + ); if (!this.fromBlueprint) { await this.composeWithBlueprints(); @@ -47,10 +50,7 @@ export default class ProjectNameGenerator extends BaseApplicationGenerator { parseOptions() { if (this.options.defaults) { if (!this.jhipsterConfig.baseName) { - this.jhipsterConfig.baseName = getDefaultAppName({ - reproducible: this.options.reproducible, - javaApplication: this.javaApplication, - }); + this.jhipsterConfig.baseName = this.defaultBaseName(); } } }, @@ -61,29 +61,6 @@ export default class ProjectNameGenerator extends BaseApplicationGenerator { return this.delegateTasksToBlueprint(() => this.initializing); } - get prompting() { - return { - async showPrompts() { - await this.prompt( - [ - { - name: BASE_NAME, - type: 'input', - validate: input => this.validateBaseName(input), - message: 'What is the base name of your application?', - default: () => getDefaultAppName({ reproducible: this.options.reproducible, javaApplication: this.javaApplication }), - }, - ], - this.config, - ); - }, - }; - } - - get [BaseApplicationGenerator.PROMPTING]() { - return this.delegateTasksToBlueprint(() => this.prompting); - } - get loading() { return this.asLoadingTaskGroup({ load({ application }) { @@ -120,17 +97,4 @@ export default class ProjectNameGenerator extends BaseApplicationGenerator { get [BaseApplicationGenerator.PREPARING]() { return this.delegateTasksToBlueprint(() => this.preparing); } - - /* - * Start of local public API, blueprints may override to customize the generator behavior. - */ - - /** - * Validates baseName - * @param {String} input - Base name to be checked - * @returns Boolean - */ - validateBaseName(input) { - return validateProjectName(input, { javaApplication: this.javaApplication }); - } } diff --git a/generators/project-name/support/index.ts b/generators/project-name/support/index.ts index 3e03e5cd6d03..92495851ff5a 100644 --- a/generators/project-name/support/index.ts +++ b/generators/project-name/support/index.ts @@ -17,5 +17,4 @@ * limitations under the License. */ -// eslint-disable-next-line import/prefer-default-export export { default as getDefaultAppName } from './name-resolver.js'; diff --git a/generators/project-name/support/name-resolver.ts b/generators/project-name/support/name-resolver.ts index 790d5bf9110e..68348a226e3f 100644 --- a/generators/project-name/support/name-resolver.ts +++ b/generators/project-name/support/name-resolver.ts @@ -27,7 +27,7 @@ export const validateJavaApplicationName = (name: string) => { if (!/^([\w]*)$/.test(name)) { return 'Your base name cannot contain special characters or a blank space'; } - if (/_/.test(name)) { + if (name.includes('_')) { return 'Your base name cannot contain underscores as this does not meet the URI spec'; } if (name.toLowerCase() === 'application') { diff --git a/generators/react/application/entities/index.ts b/generators/react/application/entities/index.ts index 078e35eeeb4b..914752ebf222 100644 --- a/generators/react/application/entities/index.ts +++ b/generators/react/application/entities/index.ts @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/prefer-default-export export function prepareEntity({ entity, application }) { entity.entityReactState = application.applicationTypeMonolith ? entity.entityInstance diff --git a/generators/react/cleanup.js b/generators/react/cleanup.ts similarity index 96% rename from generators/react/cleanup.js rename to generators/react/cleanup.ts index 6b023d5d3e78..aeb5cab540ea 100644 --- a/generators/react/cleanup.js +++ b/generators/react/cleanup.ts @@ -17,11 +17,13 @@ * limitations under the License. */ +import { asWritingTask } from '../base-application/support/task-type-inference.js'; + /** * Removes files that where generated in previous JHipster versions and therefore * need to be removed. */ -export default function cleanupOldFilesTask({ application } = {}) { +export default asWritingTask(function cleanupOldFilesTask({ application }) { if (this.isJhipsterVersionLessThan('6.3.0')) { this.removeFile('tslint.json'); } @@ -74,4 +76,4 @@ export default function cleanupOldFilesTask({ application } = {}) { if (this.isJhipsterVersionLessThan('7.9.3')) { this.removeFile(`${application.clientSrcDir}app/config/translation-middleware.ts`); } -} +}); diff --git a/generators/react/entity-files-react.js b/generators/react/entity-files-react.ts similarity index 79% rename from generators/react/entity-files-react.js rename to generators/react/entity-files-react.ts index 73f452694b78..458c2193ce06 100644 --- a/generators/react/entity-files-react.js +++ b/generators/react/entity-files-react.ts @@ -16,6 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { asPostWritingEntitiesTask, asWritingEntitiesTask } from '../base-application/support/task-type-inference.js'; import { clientApplicationTemplatesBlock } from '../client/support/index.js'; export const reactFiles = { @@ -50,7 +51,7 @@ export const reactFiles = { ], }; -export async function writeEntitiesFiles({ control, application, entities }) { +export const writeEntitiesFiles = asWritingEntitiesTask(async function ({ control, application, entities }) { for (const entity of (control.filterEntitiesAndPropertiesForClient ?? (entities => entities))(entities).filter( entity => !entity.builtInUser, )) { @@ -59,24 +60,29 @@ export async function writeEntitiesFiles({ control, application, entities }) { context: { ...application, ...entity }, }); } -} +}); -export async function postWriteEntitiesFiles({ control, application, entities }) { +export const postWriteEntitiesFiles = asPostWritingEntitiesTask(async function ({ control, application, entities }) { for (const entity of (control.filterEntitiesForClient ?? (entities => entities))(entities).filter(entity => !entity.builtInUser)) { if (!entity.embedded) { const { entityInstance, entityClass, entityAngularName, entityFolderName, entityFileName } = entity; const { applicationTypeMicroservice, clientSrcDir } = application; this.needleApi.clientReact.addEntityToModule(entityInstance, entityClass, entityAngularName, entityFolderName, entityFileName, { - applicationTypeMicroservice, - clientSrcDir, + applicationTypeMicroservice: applicationTypeMicroservice!, + clientSrcDir: clientSrcDir!, }); - this.addEntityToMenu(entity.entityPage, application.enableTranslation, entity.entityTranslationKeyMenu, entity.entityClassHumanized); + (this as any).addEntityToMenu( + entity.entityPage, + application.enableTranslation, + entity.entityTranslationKeyMenu, + entity.entityClassHumanized, + ); } } -} +}); -export function cleanupEntitiesFiles({ control, application, entities }) { +export const cleanupEntitiesFiles = asWritingEntitiesTask(function cleanupEntitiesFiles({ control, application, entities }) { for (const entity of (control.filterEntitiesForClient ?? (entities => entities))(entities).filter(entity => !entity.builtInUser)) { const { entityFolderName, entityFileName } = entity; @@ -84,4 +90,4 @@ export function cleanupEntitiesFiles({ control, application, entities }) { this.removeFile(`${application.clientTestDir}spec/app/entities/${entityFolderName}/${entityFileName}-reducer.spec.ts`); } } -} +}); diff --git a/generators/react/files-react.js b/generators/react/files-react.ts similarity index 98% rename from generators/react/files-react.js rename to generators/react/files-react.ts index 566291b9100c..69681c39ed1f 100644 --- a/generators/react/files-react.js +++ b/generators/react/files-react.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { asWriteFilesSection } from '../base-application/support/index.js'; +import { asWriteFilesSection, asWritingTask } from '../base-application/support/index.js'; import { clientApplicationTemplatesBlock, clientRootTemplatesBlock, clientSrcTemplatesBlock } from '../client/support/files.js'; export const files = asWriteFilesSection({ @@ -307,11 +307,11 @@ export const files = asWriteFilesSection({ ], }); -export async function writeFiles({ application }) { +export const writeFiles = asWritingTask(async function writeFiles({ application }) { if (!application.clientFrameworkReact) return; await this.writeFiles({ sections: files, context: application, }); -} +}); diff --git a/generators/react/generator.spec.ts b/generators/react/generator.spec.ts index 5c0aeb7f6b35..33ceee03817d 100644 --- a/generators/react/generator.spec.ts +++ b/generators/react/generator.spec.ts @@ -1,12 +1,12 @@ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { buildClientSamples, entitiesClientSamples as entities, defaultHelpers as helpers, runResult } from '../../testing/index.js'; -import { shouldSupportFeatures, testBlueprintSupport, checkEnforcements } from '../../test/support/index.js'; +import { buildClientSamples, entitiesClientSamples as entities, defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; +import { checkEnforcements, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/index.js'; -import { clientFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { clientFrameworkTypes } from '../../lib/jhipster/index.js'; import { CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; import BaseApplicationGenerator from '../base-application/index.js'; import { GENERATOR_REACT } from '../generator-list.js'; @@ -16,7 +16,6 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorFile = join(__dirname, 'index.ts'); const { REACT: clientFramework } = clientFrameworkTypes; const commonConfig = { clientFramework, nativeLanguage: 'en', languages: ['fr', 'en'] }; @@ -59,7 +58,7 @@ describe(`generator - ${clientFramework}`, () => { describe(name, () => { before(async () => { await helpers - .run(generatorFile) + .runJHipster(generator) .withJHipsterConfig(sampleConfig, entities) .withSharedApplication({ gatewayServicesApiAvailable: sampleConfig.applicationType === 'gateway' }) .withGenerators([[MockedLanguagesGenerator, { namespace: 'jhipster:languages' }]]) @@ -99,7 +98,7 @@ describe(`generator - ${clientFramework}`, () => { assertion( `${clientSrcDir}app/modules/administration/administration.reducer.ts`, 'logs: {\n' + - ' loggers: [] as any[]\n' + + ' loggers: [] as any[],\n' + ' },\n' + ' health: {} as any,\n' + ' metrics: {} as any,\n' + diff --git a/generators/react/generator.js b/generators/react/generator.ts similarity index 92% rename from generators/react/generator.js rename to generators/react/generator.ts index 91d809b41142..114ce1840e51 100644 --- a/generators/react/generator.js +++ b/generators/react/generator.ts @@ -22,17 +22,17 @@ import { camelCase, startCase } from 'lodash-es'; import BaseApplicationGenerator from '../base-application/index.js'; import { GENERATOR_CLIENT, GENERATOR_LANGUAGES, GENERATOR_REACT } from '../generator-list.js'; -import { fieldTypes, clientFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { clientFrameworkTypes, fieldTypes } from '../../lib/jhipster/index.js'; import { + generateEntityClientImports as formatEntityClientImports, generateEntityClientEnumImports as getClientEnumImportsFormat, generateEntityClientFields as getHydratedEntityClientFields, - generateEntityClientImports as formatEntityClientImports, generateTestEntityId as getTestEntityId, generateTestEntityPrimaryKey as getTestEntityPrimaryKey, } from '../client/support/index.js'; import { createNeedleCallback, upperFirstCamelCase } from '../base/support/index.js'; import { writeEslintClientRootConfigFile } from '../javascript/generators/eslint/support/tasks.js'; -import { writeEntitiesFiles, postWriteEntitiesFiles, cleanupEntitiesFiles } from './entity-files-react.js'; +import { cleanupEntitiesFiles, postWriteEntitiesFiles, writeEntitiesFiles } from './entity-files-react.js'; import cleanupOldFilesTask from './cleanup.js'; import { writeFiles } from './files-react.js'; import { prepareEntity } from './application/entities/index.js'; @@ -90,7 +90,9 @@ export default class ReactGenerator extends BaseApplicationGenerator { get preparing() { return this.asPreparingTaskGroup({ - applicationDefauts({ applicationDefaults }) { + applicationDefauts({ application, applicationDefaults }) { + application.addPrettierExtensions?.(['html', 'tsx', 'css', 'scss']); + applicationDefaults({ __override__: true, eslintConfigFile: app => `eslint.config.${app.packageJsonType === 'module' ? 'js' : 'mjs'}`, @@ -153,8 +155,8 @@ export default class ReactGenerator extends BaseApplicationGenerator { get writing() { return this.asWritingTaskGroup({ - cleanup({ control }) { - control.cleanupFiles({ + async cleanup({ control }) { + await control.cleanupFiles({ '8.6.1': ['.eslintrc.json', '.eslintignore'], }); }, @@ -187,6 +189,18 @@ export default class ReactGenerator extends BaseApplicationGenerator { get postWriting() { return this.asPostWritingTaskGroup({ + addMicrofrontendDependencies({ application }) { + if (!application.microfrontend) return; + const { applicationTypeGateway } = application; + if (applicationTypeGateway) { + this.packageJson.merge({ + devDependencies: { '@module-federation/utilities': null }, + }); + } + this.packageJson.merge({ + devDependencies: { '@module-federation/enhanced': null }, + }); + }, addWebsocketDependencies({ application }) { const { communicationSpringWebsocket, nodeDependencies } = application; if (communicationSpringWebsocket) { @@ -261,11 +275,11 @@ export default class ReactGenerator extends BaseApplicationGenerator { * @param {string} pageTitle - The translation key or the text for the page title in the browser */ addEntityToModule( - entityInstance = this.entityInstance, - entityClass = this.entityClass, - entityName = this.entityAngularName, - entityFolderName = this.entityFolderName, - entityFileName = this.entityFileName, + entityInstance, + entityClass, + entityName, + entityFolderName, + entityFileName, { applicationTypeMicroservice, clientSrcDir }, ) { this.needleApi.clientReact.addEntityToModule(entityInstance, entityClass, entityName, entityFolderName, entityFileName, { @@ -333,7 +347,7 @@ export default class ReactGenerator extends BaseApplicationGenerator { * } * */ - addAppSCSSStyle(style, comment) { + addAppSCSSStyle(style, comment?) { this.needleApi.clientReact.addAppSCSSStyle(style, comment); } diff --git a/generators/react/needle-api/needle-client-react.ts b/generators/react/needle-api/needle-client-react.ts index faa166b24181..33f75f777c2e 100644 --- a/generators/react/needle-api/needle-client-react.ts +++ b/generators/react/needle-api/needle-client-react.ts @@ -23,7 +23,7 @@ import needleClientBase from '../../client/needle-api/needle-client.js'; import { stripMargin } from '../../base/support/index.js'; export default class extends needleClientBase { - addAppSCSSStyle(style: string, comment: string) { + addAppSCSSStyle(style: string, comment?: string) { const filePath = `${this.clientSrcDir}app/app.scss`; this.addStyle(style, comment, filePath, 'jhipster-needle-scss-add-main'); } diff --git a/generators/react/resources/package.json b/generators/react/resources/package.json index 466383efe717..08d780ecfbca 100644 --- a/generators/react/resources/package.json +++ b/generators/react/resources/package.json @@ -3,59 +3,60 @@ "@fortawesome/fontawesome-svg-core": "6.6.0", "@fortawesome/free-solid-svg-icons": "6.6.0", "@fortawesome/react-fontawesome": "0.2.2", - "@reduxjs/toolkit": "2.2.6", - "axios": "1.7.2", + "@reduxjs/toolkit": "2.3.0", + "axios": "1.7.7", "bootstrap": "5.3.3", "bootswatch": "5.3.3", "lodash": "4.17.21", "path-browserify": "1.0.1", "react": "18.3.1", "react-dom": "18.3.1", - "react-hook-form": "7.52.1", + "react-hook-form": "7.53.1", "react-jhipster": "0.25.3", "react-loadable": "5.5.0", "react-redux": "9.1.2", "react-redux-loading-bar": "5.0.8", - "react-router-dom": "6.25.1", - "react-toastify": "10.0.5", + "react-router-dom": "6.27.0", + "react-toastify": "10.0.6", "react-transition-group": "4.4.5", - "reactstrap": "9.2.2", + "reactstrap": "9.2.3", "redux": "5.0.1", "rxjs": "7.8.1", "sockjs-client": "1.6.1", "sonar-scanner": "3.1.0", - "tslib": "2.6.3", - "uuid": "10.0.0", + "tslib": "2.8.0", + "uuid": "11.0.2", "webstomp-client": "1.2.6" }, "devDependencies": { - "@eslint/js": "8.57.0", - "@module-federation/utilities": "3.0.3-0", - "@testing-library/react": "16.0.0", - "@types/jest": "29.5.12", - "@types/lodash": "4.17.7", + "@eslint/js": "9.13.0", + "@module-federation/enhanced": "0.6.13", + "@module-federation/utilities": "3.1.19", + "@testing-library/react": "16.0.1", + "@types/jest": "29.5.14", + "@types/lodash": "4.17.13", "@types/node": "20.11.25", - "@types/react": "18.3.3", - "@types/react-dom": "18.3.0", - "@types/react-redux": "7.1.33", + "@types/react": "18.3.12", + "@types/react-dom": "18.3.1", + "@types/react-redux": "7.1.34", "@types/redux": "3.6.31", "@types/webpack-env": "1.18.5", - "autoprefixer": "10.4.19", + "autoprefixer": "10.4.20", "browser-sync": "2.29.3", "browser-sync-webpack-plugin": "2.3.0", "copy-webpack-plugin": "12.0.2", - "core-js": "3.37.1", + "core-js": "3.38.1", "cross-env": "7.0.3", "css-loader": "7.1.2", "css-minimizer-webpack-plugin": "7.0.0", - "eslint": "8.57.0", + "eslint": "9.13.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.2.1", - "eslint-plugin-react": "7.34.4", + "eslint-plugin-react": "7.37.2", "eslint-webpack-plugin": "4.2.0", "folder-hash": "4.0.4", "fork-ts-checker-webpack-plugin": "9.0.2", - "html-webpack-plugin": "5.6.0", + "html-webpack-plugin": "5.6.3", "identity-obj-proxy": "3.0.0", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", @@ -63,30 +64,30 @@ "jest-sonar": "0.2.16", "json-loader": "0.5.7", "merge-jsons-webpack-plugin": "2.0.1", - "mini-css-extract-plugin": "2.9.0", + "mini-css-extract-plugin": "2.9.1", "postcss-loader": "8.1.1", - "postcss-rtlcss": "5.3.0", + "postcss-rtlcss": "5.5.0", "react-infinite-scroll-component": "6.1.0", - "redux-mock-store": "1.5.4", + "redux-mock-store": "1.5.5", "rimraf": "5.0.8", - "sass": "1.77.8", - "sass-loader": "14.2.1", + "sass": "1.77.6", + "sass-loader": "16.0.2", "simple-progress-webpack-plugin": "2.0.0", - "sinon": "18.0.0", + "sinon": "19.0.2", "source-map-loader": "5.0.0", "sourcemap-istanbul-instrumenter-loader": "0.2.0", "style-loader": "4.0.0", "terser-webpack-plugin": "5.3.10", - "thread-loader": "4.0.2", - "ts-jest": "29.2.2", + "thread-loader": "4.0.4", + "ts-jest": "29.2.5", "ts-loader": "9.5.1", - "typescript": "5.5.3", - "typescript-eslint": "7.16.1", - "webpack": "5.93.0", + "typescript": "5.6.3", + "typescript-eslint": "8.12.2", + "webpack": "5.95.0", "webpack-cli": "5.1.4", - "webpack-dev-server": "5.0.4", + "webpack-dev-server": "5.1.0", "webpack-merge": "6.0.1", "webpack-notifier": "1.15.0", - "workbox-webpack-plugin": "7.1.0" + "workbox-webpack-plugin": "7.3.0" } } diff --git a/generators/react/support/needles.js b/generators/react/support/needles.ts similarity index 100% rename from generators/react/support/needles.js rename to generators/react/support/needles.ts diff --git a/generators/react/support/translate-react.spec.js b/generators/react/support/translate-react.spec.ts similarity index 99% rename from generators/react/support/translate-react.spec.js rename to generators/react/support/translate-react.spec.ts index 20699c99e054..78d961dcfa21 100644 --- a/generators/react/support/translate-react.spec.js +++ b/generators/react/support/translate-react.spec.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { beforeEach, it, describe, expect, esmocha } from 'esmocha'; +import { beforeEach, describe, esmocha, expect, it } from 'esmocha'; import { createTranslationReplacer } from './translate-react.js'; describe('generator - react - transform', () => { diff --git a/generators/react/support/translate-react.js b/generators/react/support/translate-react.ts similarity index 83% rename from generators/react/support/translate-react.js rename to generators/react/support/translate-react.ts index cf2b8e0d929a..d1d61b1a2652 100644 --- a/generators/react/support/translate-react.js +++ b/generators/react/support/translate-react.ts @@ -30,15 +30,13 @@ const INTERPOLATE_ATTRIBUTE = 'interpolate=\\{(?\\{[^\\}]+\\})\\}\\ const COMPONENT_ATTRIBUTE = 'component="(?[^"]+)"\\s*'; const TRANSLATE_TAG = `(?[\\s\\S]*?)<\\/Translate>`; -function getTranslationValue(getWebappTranslation, key, data) { - return getWebappTranslation(key, data) || undefined; -} +type Options = { keyPattern?: string; interpolatePattern?: string; wrapTranslation?: string | string[]; escapeHtml?: boolean }; const replaceTranslationKeysWithText = ( getWebappTranslation, - body, - regexp, - { keyPattern, interpolatePattern, wrapTranslation, escapeHtml } = {}, + body: string, + regexp: string, + { keyPattern, interpolatePattern, wrapTranslation, escapeHtml }: Options = {}, ) => { const matches = body.matchAll(new RegExp(regexp, 'g')); if (typeof wrapTranslation === 'string') { @@ -47,19 +45,19 @@ const replaceTranslationKeysWithText = ( for (const match of matches) { const target = match[0]; - let key = match.groups && match.groups.key; + let key = match.groups?.key; if (!key && keyPattern) { - const keyMatch = target.match(new RegExp(keyPattern)); - key = keyMatch && keyMatch.groups && keyMatch.groups.key; + const keyMatch = new RegExp(keyPattern).exec(target); + key = keyMatch?.groups?.key; } if (!key) { throw new Error(`Translation key not found for ${target}`); } - let interpolate = match.groups && match.groups.interpolate; + let interpolate = match.groups?.interpolate; if (!interpolate && interpolatePattern) { - const interpolateMatch = target.match(new RegExp(interpolatePattern)); - interpolate = interpolateMatch && interpolateMatch.groups && interpolateMatch.groups.interpolate; + const interpolateMatch = new RegExp(interpolatePattern).exec(target); + interpolate = interpolateMatch?.groups?.interpolate; } let data; @@ -67,8 +65,8 @@ const replaceTranslationKeysWithText = ( const interpolateMatches = interpolate.matchAll(/(?[^{\s:,}]+)(?::\s*(?[^,}]+))?/g); data = {}; for (const interpolateMatch of interpolateMatches) { - const field = interpolateMatch.groups.field; - let value = interpolateMatch.groups.value; + const field = interpolateMatch?.groups?.field; + let value: string | number | undefined = interpolateMatch?.groups?.value; if (value === undefined) { value = key; } @@ -83,11 +81,11 @@ const replaceTranslationKeysWithText = ( // wrap expression value = `{${value}}`; } - data[field] = value; + data[field!] = value; } } - const translation = getTranslationValue(getWebappTranslation, key, data); + const translation = getWebappTranslation(key, data); let replacement = translation; if (!replacement) { @@ -109,8 +107,8 @@ const replaceTranslationKeysWithText = ( * @return {import('../../base/api.js').EditFileCallback} */ export const createTranslationReplacer = getWebappTranslation => - function replaceReactTranslations(body, filePath) { - if (/\.tsx$/.test(filePath)) { + function replaceReactTranslations(body: string, filePath: string) { + if (filePath.endsWith('.tsx')) { body = body.replace(new RegExp(TRANSLATE_IMPORT, 'g'), ''); body = replaceTranslationKeysWithText(getWebappTranslation, body, `\\{\\s*${TRANSLATE_FUNCTION}\\s*\\}`, { wrapTranslation: '"' }); body = replaceTranslationKeysWithText(getWebappTranslation, body, TRANSLATE_FUNCTION, { wrapTranslation: '"' }); diff --git a/generators/react/templates/eslint.config.js.jhi.react.ejs b/generators/react/templates/eslint.config.js.jhi.react.ejs index 37229fa6d7a4..75e9c21ce623 100644 --- a/generators/react/templates/eslint.config.js.jhi.react.ejs +++ b/generators/react/templates/eslint.config.js.jhi.react.ejs @@ -18,7 +18,6 @@ -%> <&_ if (fragment.importsSection) { -&> import eslint from '@eslint/js'; -import tseslint from 'typescript-eslint'; import react from 'eslint-plugin-react/configs/recommended.js'; <&_ } -&> <&_ if (fragment.configSection) { -&> @@ -66,14 +65,6 @@ import react from 'eslint-plugin-react/configs/recommended.js'; '@typescript-eslint/restrict-template-expressions': 'off', '@typescript-eslint/restrict-plus-operands': 'off', '@typescript-eslint/no-floating-promises': 'off', - '@typescript-eslint/ban-types': [ - 'error', - { - types: { - Object: 'Use {} instead.', - }, - }, - ], '@typescript-eslint/interface-name-prefix': 'off', '@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/unbound-method': 'off', @@ -94,7 +85,7 @@ import react from 'eslint-plugin-react/configs/recommended.js'; 'prefer-const': 'error', 'object-shorthand': ['error', 'always', { avoidExplicitReturnArrows: true }], 'default-case': 'error', - complexity: ['error', 40], + complexity: ['warn', 40], 'no-invalid-this': 'off', 'react/prop-types': 'off', 'react/display-name': 'off', diff --git a/generators/react/templates/jest.conf.js.ejs b/generators/react/templates/jest.conf.js.ejs index 7f88be20c161..d05d739aad6a 100644 --- a/generators/react/templates/jest.conf.js.ejs +++ b/generators/react/templates/jest.conf.js.ejs @@ -3,11 +3,14 @@ const tsconfig = require('./tsconfig.test.json'); module.exports = { testEnvironment: 'jsdom', transform: { - '^.+\\.tsx?$': ['ts-jest', { - tsconfig: './tsconfig.test.json', - compiler: 'typescript', - diagnostics: false, - }], + '^.+\\.tsx?$': [ + 'ts-jest', + { + tsconfig: './tsconfig.test.json', + compiler: 'typescript', + diagnostics: false, + }, + ], }, testEnvironmentOptions: { url: 'http://localhost/', @@ -16,21 +19,17 @@ module.exports = { coverageDirectory: '/<%= this.relativeDir(clientRootDir, temporaryDir) %>test-results/', testMatch: ['/<%= this.relativeDir(clientRootDir, clientSrcDir) %>app/**/@(*.)@(spec.ts?(x))'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], - coveragePathIgnorePatterns: [ - '/<%= this.relativeDir(clientRootDir, clientTestDir) %>', - ], + coveragePathIgnorePatterns: ['/<%= this.relativeDir(clientRootDir, clientTestDir) %>'], moduleNameMapper: mapTypescriptAliasToJestAlias({ '\\.(css|scss)$': 'identity-obj-proxy', - 'sinon': require.resolve('sinon/pkg/sinon.js') + sinon: require.resolve('sinon/pkg/sinon.js'), }), reporters: [ 'default', ['jest-junit', { outputDirectory: './<%= this.relativeDir(clientRootDir, temporaryDir) %>test-results/', outputName: 'TESTS-results-jest.xml' }], ['jest-sonar', { outputDirectory: './<%= this.relativeDir(clientRootDir, temporaryDir) %>test-results/jest', outputName: 'TESTS-results-sonar.xml' }], ], - testPathIgnorePatterns: [ - '/node_modules/' - ], + testPathIgnorePatterns: ['/node_modules/'], setupFiles: ['/<%= this.relativeDir(clientRootDir, clientSrcDir) %>app/setup-tests.ts'], globals: { <%_ if (enableTranslation) { _%> @@ -38,34 +37,34 @@ module.exports = { <%_ } _%> ...require('./webpack/environment'), DEVELOPMENT: false, - } + }, }; function mapTypescriptAliasToJestAlias(alias = {}) { - const jestAliases = { ...alias }; - if (!tsconfig.compilerOptions.paths) { - return jestAliases; - } - Object.entries(tsconfig.compilerOptions.paths) - .filter(([_key, value]) => { - // use Typescript alias in Jest only if this has value - if (value.length) { - return true; - } - return false; - }) - .map(([key, value]) => { - // if Typescript alias ends with /* then in Jest: - // - alias key must end with /(.*) - // - alias value must end with /$1 - const regexToReplace = /(.*)\/\*$/; - const aliasKey = key.replace(regexToReplace, '$1/(.*)'); - const aliasValue = value[0].replace(regexToReplace, '$1/$$1'); - return [aliasKey, `/${aliasValue}`]; - }) - .reduce((aliases, [key, value]) => { - aliases[key] = value; - return aliases; - }, jestAliases); + const jestAliases = { ...alias }; + if (!tsconfig.compilerOptions.paths) { return jestAliases; } + Object.entries(tsconfig.compilerOptions.paths) + .filter(([_key, value]) => { + // use Typescript alias in Jest only if this has value + if (value.length) { + return true; + } + return false; + }) + .map(([key, value]) => { + // if Typescript alias ends with /* then in Jest: + // - alias key must end with /(.*) + // - alias value must end with /$1 + const regexToReplace = /(.*)\/\*$/; + const aliasKey = key.replace(regexToReplace, '$1/(.*)'); + const aliasValue = value[0].replace(regexToReplace, '$1/$$1'); + return [aliasKey, `/${aliasValue}`]; + }) + .reduce((aliases, [key, value]) => { + aliases[key] = value; + return aliases; + }, jestAliases); + return jestAliases; +} diff --git a/generators/react/templates/package.json.ejs b/generators/react/templates/package.json.ejs index 0a7691982536..f319645b111a 100644 --- a/generators/react/templates/package.json.ejs +++ b/generators/react/templates/package.json.ejs @@ -59,9 +59,6 @@ "uuid": "<%= nodeDependencies['uuid'] %>" }, "devDependencies": { -<%_ if (applicationTypeGateway && microfrontend) { _%> - "@module-federation/utilities": "<%= nodeDependencies['@module-federation/utilities'] %>", -<%_ } _%> "@testing-library/react": "<%= nodeDependencies['@testing-library/react'] %>", "@types/jest": "<%= nodeDependencies['@types/jest'] %>", "@types/lodash": "<%= nodeDependencies['@types/lodash'] %>", diff --git a/generators/react/templates/src/main/webapp/app/_bootstrap-variables.scss.ejs b/generators/react/templates/src/main/webapp/app/_bootstrap-variables.scss.ejs index b062a6c35638..8046d74d04f5 100644 --- a/generators/react/templates/src/main/webapp/app/_bootstrap-variables.scss.ejs +++ b/generators/react/templates/src/main/webapp/app/_bootstrap-variables.scss.ejs @@ -26,23 +26,23 @@ <%_ if (clientThemeNone) { _%> // Options: // Quickly modify global styling by enabling or disabling optional features. -$enable-rounded: true; -$enable-shadows: false; -$enable-gradients: false; -$enable-transitions: true; -$enable-hover-media-query: false; -$enable-grid-classes: true; -$enable-print-styles: true; +$enable-rounded: true; +$enable-shadows: false; +$enable-gradients: false; +$enable-transitions: true; +$enable-hover-media-query: false; +$enable-grid-classes: true; +$enable-print-styles: true; // Components: // Define common padding and border radius sizes and more. -$border-radius: .15rem; -$border-radius-lg: .125rem; -$border-radius-sm: .1rem; +$border-radius: 0.15rem; +$border-radius-lg: 0.125rem; +$border-radius-sm: 0.1rem; // Body: // Settings for the `` element. -$body-bg: #ffffff; +$body-bg: #ffffff; <%_ } _%> diff --git a/generators/react/templates/src/main/webapp/app/app.tsx.ejs b/generators/react/templates/src/main/webapp/app/app.tsx.ejs index 3b8a855f76a8..d9d1f1e524b3 100644 --- a/generators/react/templates/src/main/webapp/app/app.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/app.tsx.ejs @@ -67,7 +67,7 @@ export const App = () => { return (
- +
-import axios from 'axios'; +import axios, { type AxiosError } from 'axios'; import { Storage } from 'react-jhipster'; const TIMEOUT = 1 * 60 * 1000; @@ -34,7 +34,7 @@ const setupAxiosInterceptors = onUnauthenticated => { return config; }; const onResponseSuccess = response => response; - const onResponseError = err => { + const onResponseError = (err: AxiosError) => { const status = err.status || (err.response ? err.response.status : 0); if (status === 401) { onUnauthenticated(); diff --git a/generators/react/templates/src/main/webapp/app/config/error-middleware.ts.ejs b/generators/react/templates/src/main/webapp/app/config/error-middleware.ts.ejs index 694809a6bb28..a775f8d8e744 100644 --- a/generators/react/templates/src/main/webapp/app/config/error-middleware.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/config/error-middleware.ts.ejs @@ -17,7 +17,7 @@ limitations under the License. -%> const getErrorMessage = errorData => { - let message = errorData.message; + let { message } = errorData; if (errorData.fieldErrors) { errorData.fieldErrors.forEach(fErr => { message += `\nfield: ${fErr.field}, Object: ${fErr.objectName}, message: ${fErr.message}\n`; diff --git a/generators/react/templates/src/main/webapp/app/config/notification-middleware.ts.ejs b/generators/react/templates/src/main/webapp/app/config/notification-middleware.ts.ejs index 6f326b9ce4e1..92683b9a58bb 100644 --- a/generators/react/templates/src/main/webapp/app/config/notification-middleware.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/config/notification-middleware.ts.ejs @@ -57,6 +57,7 @@ const getFieldErrorsTosts = (fieldErrors: FieldErrorVM[]): TostMessage[] => <%_ } _%> }); +// eslint-disable-next-line complexity export default () => next => action => { const { error, payload } = action; @@ -77,7 +78,7 @@ export default () => next => action => { if (isRejectedAction(action) && isAxiosError(error)) { if (error.response) { - const response = error.response; + const { response } = error; if (response.status === 401) { // Ignore, page will be redirected to login. } else if (error.config?.url?.endsWith('api/account') || error.config?.url?.endsWith('api/authenticate')) { @@ -98,7 +99,7 @@ export default () => next => action => { <%_ } _%> }); } else { - const data = response.data; + const { data } = response; const problem = isProblemWithMessage(data) ? data : null; if (problem?.fieldErrors) { getFieldErrorsTosts(problem.fieldErrors).forEach(message => addErrorAlert(message)); diff --git a/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.tsx.ejs b/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.tsx.ejs index 5d18d66200fc..2bf755bf5f3d 100644 --- a/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.tsx.ejs @@ -126,7 +126,6 @@ export const <%= entityReactName %>Update = () => { } }, [updateSuccess]); - // eslint-disable-next-line complexity const saveEntity = values => { <%_ for (field of fields) { const fieldName = field.fieldName; diff --git a/generators/react/templates/src/main/webapp/app/modules/account/password-reset/init/password-reset-init.tsx.ejs b/generators/react/templates/src/main/webapp/app/modules/account/password-reset/init/password-reset-init.tsx.ejs index 0c74d56a9505..7855031595b6 100644 --- a/generators/react/templates/src/main/webapp/app/modules/account/password-reset/init/password-reset-init.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/modules/account/password-reset/init/password-reset-init.tsx.ejs @@ -50,38 +50,40 @@ export const PasswordResetInit = () => { } }, [successMessage]); - return ( -
- - -

Reset your password

- -

Enter the email address you used to register

-
- - isEmail(v) || translate('global.messages.validate.email.invalid'), - }} - data-cy="emailResetPassword" - /> - - - -
-
- ); -} + return ( +
+ + +

+ Reset your password +

+ +

+ Enter the email address you used to register +

+
+ + isEmail(v) || translate('global.messages.validate.email.invalid'), + }} + data-cy="emailResetPassword" + /> + + + +
+
+ ); +}; export default PasswordResetInit; diff --git a/generators/react/templates/src/main/webapp/app/modules/account/password-reset/password-reset.reducer.ts.ejs b/generators/react/templates/src/main/webapp/app/modules/account/password-reset/password-reset.reducer.ts.ejs index aec9e4dc9036..d9c3800719a0 100644 --- a/generators/react/templates/src/main/webapp/app/modules/account/password-reset/password-reset.reducer.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/modules/account/password-reset/password-reset.reducer.ts.ejs @@ -36,7 +36,7 @@ const apiUrl = 'api/account/reset-password'; export const handlePasswordResetInit = createAsyncThunk( 'passwordReset/reset_password_init', // If the content-type isn't set that way, axios will try to encode the body and thus modify the data sent to the server. - async (mail: string) => axios.post(`${apiUrl}/init`, mail, { headers: { ['Content-Type']: 'text/plain' } }), + async (mail: string) => axios.post(`${apiUrl}/init`, mail, { headers: { 'Content-Type': 'text/plain' } }), { serializeError: serializeAxiosError }, ); diff --git a/generators/react/templates/src/main/webapp/app/modules/account/register/register.reducer.spec.ts.ejs b/generators/react/templates/src/main/webapp/app/modules/account/register/register.reducer.spec.ts.ejs index b0d50ac8125f..10bd904fefd6 100644 --- a/generators/react/templates/src/main/webapp/app/modules/account/register/register.reducer.spec.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/modules/account/register/register.reducer.spec.ts.ejs @@ -67,7 +67,7 @@ describe('Creating account tests', () => { register(undefined, { type: handleRegister.fulfilled.type, payload: 'fake payload', - }) + }), ).toEqual({ ...initialState, registrationSuccess: true, diff --git a/generators/react/templates/src/main/webapp/app/modules/account/register/register.tsx.ejs b/generators/react/templates/src/main/webapp/app/modules/account/register/register.tsx.ejs index 3e889a1c1e9f..9014914613a4 100644 --- a/generators/react/templates/src/main/webapp/app/modules/account/register/register.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/modules/account/register/register.tsx.ejs @@ -37,7 +37,7 @@ export const RegisterPage = () => { () => () => { dispatch(reset()); }, - [] + [], ); <%_ if (enableTranslation) { _%> diff --git a/generators/react/templates/src/main/webapp/app/modules/account/settings/settings.reducer.ts.ejs b/generators/react/templates/src/main/webapp/app/modules/account/settings/settings.reducer.ts.ejs index 222c1e2d78eb..981a665a251b 100644 --- a/generators/react/templates/src/main/webapp/app/modules/account/settings/settings.reducer.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/modules/account/settings/settings.reducer.ts.ejs @@ -29,10 +29,10 @@ const initialState = { errorMessage: null, successMessage: null, updateSuccess: false, - updateFailure: false + updateFailure: false, }; -export type SettingsState = Readonly; +export type SettingsState = Readonly; // Actions const apiUrl = 'api/account'; diff --git a/generators/react/templates/src/main/webapp/app/modules/administration/administration.reducer.spec.ts.ejs b/generators/react/templates/src/main/webapp/app/modules/administration/administration.reducer.spec.ts.ejs index 13a6852f7d8f..acc026cb36d2 100644 --- a/generators/react/templates/src/main/webapp/app/modules/administration/administration.reducer.spec.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/modules/administration/administration.reducer.spec.ts.ejs @@ -52,7 +52,7 @@ describe('Administration reducer tests', () => { expect(state).toMatchObject({ loading: false, errorMessage: null, - totalItems: 0 + totalItems: 0, }); <%_ if (applicationTypeGateway && gatewayServicesApiAvailable) { _%> expect(isEmpty(state.gateway.routes)); @@ -98,9 +98,9 @@ describe('Administration reducer tests', () => { state => { expect(state).toMatchObject({ errorMessage: null, - loading: true + loading: true, }); - } + }, ); }); }); @@ -130,7 +130,7 @@ describe('Administration reducer tests', () => { }, { message: 'error', - } + }, ); }); }); @@ -149,19 +149,20 @@ describe('Administration reducer tests', () => { <%_ } _%> <%_ if (withAdminUi) { _%> it('should update state according to a successful fetch logs request', () => { - const payload = { data: { + const payload = { + data: { loggers: { main: { - effectiveLevel: 'WARN' - } - } - } + effectiveLevel: 'WARN', + }, + }, + }, }; const toTest = administration(undefined, { type: getLoggers.fulfilled.type, payload }); expect(toTest).toMatchObject({ loading: false, - logs: payload.data + logs: payload.data, }); }); @@ -216,8 +217,8 @@ describe('Administration reducer tests', () => { loading: false, configuration: { configProps: {}, - env: payload.data - } + env: payload.data, + }, }); }); <%_ } _%> diff --git a/generators/react/templates/src/main/webapp/app/modules/administration/administration.reducer.ts.ejs b/generators/react/templates/src/main/webapp/app/modules/administration/administration.reducer.ts.ejs index d37dafdfd962..71ef4adb1669 100644 --- a/generators/react/templates/src/main/webapp/app/modules/administration/administration.reducer.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/modules/administration/administration.reducer.ts.ejs @@ -32,7 +32,7 @@ const initialState = { <%_ } _%> <%_ if (withAdminUi) { _%> logs: { - loggers: [] as any[] + loggers: [] as any[], }, health: {} as any, metrics: {} as any, @@ -85,7 +85,7 @@ export const setLoggers = createAsyncThunk( async ({ name, configuredLevel }: any) => axios.post(`management/loggers/${name}`, { configuredLevel }), { serializeError: serializeAxiosError, - } + }, ); export const changeLogLevel: (name, configuredLevel) => AppThunk = (name, configuredLevel) => async dispatch => { @@ -93,9 +93,13 @@ export const changeLogLevel: (name, configuredLevel) => AppThunk = (name, config dispatch(getLoggers()); }; -export const getConfigurations = createAsyncThunk('administration/fetch_configurations', async () => axios.get('management/configprops'), { - serializeError: serializeAxiosError, -}); +export const getConfigurations = createAsyncThunk( + 'administration/fetch_configurations', + async () => axios.get('management/configprops'), + { + serializeError: serializeAxiosError, + }, +); export const getEnv = createAsyncThunk('administration/fetch_env', async () => axios.get('management/env'), { serializeError: serializeAxiosError, @@ -197,7 +201,7 @@ export const AdministrationSlice = createSlice({ (state, action) => { state.errorMessage = action.error.message; state.loading = false; - } + }, ); <%_ } _%> }, diff --git a/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management-detail.tsx.ejs b/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management-detail.tsx.ejs index fd00656458e1..8e75e47db1c4 100644 --- a/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management-detail.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management-detail.tsx.ejs @@ -79,21 +79,24 @@ export const UserManagementDetail = () => {
    { user.authorities ? ( - user.authorities.map((authority, i) => ( -
  • - {authority} -
  • - ))) : null - } + user.authorities.map( + (authority, i) => ( +
  • + {authority} +
  • + ) + ) + ) + : null}
-
); diff --git a/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management.reducer.spec.ts.ejs b/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management.reducer.spec.ts.ejs index 8158d84cc46b..4b15639bc013 100644 --- a/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management.reducer.spec.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management.reducer.spec.ts.ejs @@ -39,9 +39,8 @@ describe('User management reducer tests', () => { function isEmpty(element): boolean { if (element instanceof Array) { return element.length === 0; - } else { - return Object.keys(element).length === 0; } + return Object.keys(element).length === 0; } function testInitialState(state) { diff --git a/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management.tsx.ejs b/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management.tsx.ejs index 014d9a738df2..d2458b3a3f7f 100644 --- a/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/modules/administration/user-management/user-management.tsx.ejs @@ -156,8 +156,7 @@ export const UserManagement = () => { - { - users.map((user, i) => ( + {users.map((user, i) => ( ) : ( - )} @@ -181,14 +180,13 @@ export const UserManagement = () => { {user.langKey} <%_ } _%> - { - user.authorities ? ( - user.authorities.map((authority, j) => ( -
- {authority} -
- ))) : null - } + {user.authorities + ? user.authorities.map((authority, j) => ( +
+ {authority} +
+ )) + : null} <%_ if (!databaseTypeCassandra) { _%> @@ -204,13 +202,22 @@ export const UserManagement = () => {
diff --git a/generators/react/templates/src/main/webapp/app/routes.tsx.ejs b/generators/react/templates/src/main/webapp/app/routes.tsx.ejs index e436689ddaba..d1e36a71769e 100644 --- a/generators/react/templates/src/main/webapp/app/routes.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/routes.tsx.ejs @@ -49,7 +49,7 @@ import { sendActivity } from 'app/config/websocket-middleware'; const loading =
loading ...
; <%_ if (generateUserManagement) { _%> - const Account = Loadable({ +const Account = Loadable({ loader: () => import(/* webpackChunkName: "account" */ 'app/modules/account'), loading: () => loading, }); diff --git a/generators/react/templates/src/main/webapp/app/shared/DurationFormat.tsx.ejs b/generators/react/templates/src/main/webapp/app/shared/DurationFormat.tsx.ejs index d33faf51ee71..1cfe18cd98be 100644 --- a/generators/react/templates/src/main/webapp/app/shared/DurationFormat.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/shared/DurationFormat.tsx.ejs @@ -17,5 +17,12 @@ export const DurationFormat = ({ value, blankOnInvalid, locale }: IDurationForma locale = TranslatorContext.context.locale; } - return {dayjs.duration(value).locale(locale || '<% if (enableTranslation) { %><%= nativeLanguage %><% } else { %>en<% } %>').humanize()}; + return ( + + {dayjs + .duration(value) + .locale(locale || '<% if (enableTranslation) { %><%= nativeLanguage %><% } else { %>en<% } %>') + .humanize()} + + ); }; diff --git a/generators/react/templates/src/main/webapp/app/shared/layout/header/header-components.tsx.ejs b/generators/react/templates/src/main/webapp/app/shared/layout/header/header-components.tsx.ejs index 9af383c92d4d..b63239babe17 100644 --- a/generators/react/templates/src/main/webapp/app/shared/layout/header/header-components.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/shared/layout/header/header-components.tsx.ejs @@ -25,10 +25,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; export const BrandIcon = props => (
- Logo + Logo
); @@ -44,7 +41,9 @@ export const Home = () => ( - Home + + Home + ); diff --git a/generators/react/templates/src/main/webapp/app/shared/layout/header/header.spec.tsx.ejs b/generators/react/templates/src/main/webapp/app/shared/layout/header/header.spec.tsx.ejs index 3c6c9a919198..b06bc72cfee5 100644 --- a/generators/react/templates/src/main/webapp/app/shared/layout/header/header.spec.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/shared/layout/header/header.spec.tsx.ejs @@ -34,22 +34,22 @@ describe('Header', () => { <%_ } _%> ribbonEnv: 'dev', isInProduction: false, - isOpenAPIEnabled: true + isOpenAPIEnabled: true, }; const prodProps = { ...devProps, ribbonEnv: 'prod', isInProduction: true, - isOpenAPIEnabled: false + isOpenAPIEnabled: false, }; const userProps = { ...prodProps, - isAdmin: false + isAdmin: false, }; const guestProps = { ...prodProps, isAdmin: false, - isAuthenticated: false + isAuthenticated: false, }; const wrapper = (props = devProps) => { diff --git a/generators/react/templates/src/main/webapp/app/shared/reducers/authentication.spec.ts.ejs b/generators/react/templates/src/main/webapp/app/shared/reducers/authentication.spec.ts.ejs index 40815753eab6..96be2b6a75dc 100644 --- a/generators/react/templates/src/main/webapp/app/shared/reducers/authentication.spec.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/shared/reducers/authentication.spec.ts.ejs @@ -70,10 +70,10 @@ describe('Authentication reducer tests', () => { describe('Requests', () => { it('should detect a request', () => { expect(authentication(undefined, { type: authenticate.pending.type })).toMatchObject({ - loading: true + loading: true, }); expect(authentication(undefined, { type: getAccount.pending.type })).toMatchObject({ - loading: true + loading: true, }); }); }); @@ -87,7 +87,7 @@ describe('Authentication reducer tests', () => { loading: false, loginError: false, loginSuccess: true, - showModalLogin: false + showModalLogin: false, }); }); <%_ } _%> @@ -122,7 +122,7 @@ describe('Authentication reducer tests', () => { expect(toTest).toMatchObject({ errorMessage: error.message, showModalLogin: true, - loginError: true + loginError: true, }); expect(isAccountEmpty(toTest)); }); @@ -165,7 +165,7 @@ describe('Authentication reducer tests', () => { showModalLogin: true, <%_ } _%> errorMessage: null, - redirectMessage: null + redirectMessage: null, }); expect(isAccountEmpty(toTest)); }); @@ -182,7 +182,7 @@ describe('Authentication reducer tests', () => { showModalLogin: true, <%_ } _%> errorMessage: null, - redirectMessage: message + redirectMessage: message, }); expect(isAccountEmpty(toTest)); }); @@ -257,15 +257,12 @@ describe('Authentication reducer tests', () => { <%_ if (authenticationTypeJwt) { _%> describe('clearAuthToken', () => { let store; - const reducer = createReducer( - { authentication: { account: { langKey: 'en' } } }, - (builder) => { - builder.addDefaultCase(() => {}) - } - ); + const reducer = createReducer({ authentication: { account: { langKey: 'en' } } }, builder => { + builder.addDefaultCase(() => {}); + }); beforeEach(() => { store = configureStore({ - reducer + reducer, }); }); it('clears the session token on clearAuthToken', async () => { diff --git a/generators/react/templates/src/main/webapp/app/shared/reducers/authentication.ts.ejs b/generators/react/templates/src/main/webapp/app/shared/reducers/authentication.ts.ejs index ae2984ae7dc7..c103524e8780 100644 --- a/generators/react/templates/src/main/webapp/app/shared/reducers/authentication.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/shared/reducers/authentication.ts.ejs @@ -45,7 +45,7 @@ export const initialState = { logoutUrl: null as unknown as string, }; -export type AuthenticationState = Readonly; +export type AuthenticationState = Readonly; // Actions diff --git a/generators/react/templates/src/main/webapp/app/shared/reducers/reducer.utils.ts.ejs b/generators/react/templates/src/main/webapp/app/shared/reducers/reducer.utils.ts.ejs index e48c919fc3c4..39fde2bf4bd8 100644 --- a/generators/react/templates/src/main/webapp/app/shared/reducers/reducer.utils.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/shared/reducers/reducer.utils.ts.ejs @@ -71,16 +71,15 @@ export const serializeAxiosError = (value: any): AxiosError | SerializedError => if (typeof value === 'object' && value !== null) { if (isAxiosError(value)) { return value; - } else { - const simpleError: SerializedError = {}; - for (const property of commonErrorProperties) { - if (typeof value[property] === 'string') { - simpleError[property] = value[property]; - } + } + const simpleError: SerializedError = {}; + for (const property of commonErrorProperties) { + if (typeof value[property] === 'string') { + simpleError[property] = value[property]; } - - return simpleError; } + + return simpleError; } return { message: String(value) }; }; diff --git a/generators/react/templates/src/main/webapp/app/shared/reducers/user-management.spec.ts.ejs b/generators/react/templates/src/main/webapp/app/shared/reducers/user-management.spec.ts.ejs index 19c06bdb8a28..ad1ee06b4c01 100644 --- a/generators/react/templates/src/main/webapp/app/shared/reducers/user-management.spec.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/shared/reducers/user-management.spec.ts.ejs @@ -29,7 +29,7 @@ import userManagement, { describe('User management reducer tests', () => { const initialState = { users: [], - errorMessage: null + errorMessage: null, }; describe('Common', () => { diff --git a/generators/react/templates/src/main/webapp/app/shared/util/entity-utils.ts.ejs b/generators/react/templates/src/main/webapp/app/shared/util/entity-utils.ts.ejs index 68f50c57f507..7dce0ba7bbc9 100644 --- a/generators/react/templates/src/main/webapp/app/shared/util/entity-utils.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/shared/util/entity-utils.ts.ejs @@ -27,7 +27,7 @@ import { IPaginationBaseState, ISortBaseState } from 'react-jhipster'; * @param entity Object to clean. */ export const cleanEntity = entity => { - const keysToKeep = Object.keys(entity).filter(k => !(entity[k] instanceof Object) || (entity[k]['id'] !== '' && entity[k]['id'] !== -1)); + const keysToKeep = Object.keys(entity).filter(k => !(entity[k] instanceof Object) || (entity[k].id !== '' && entity[k].id !== -1)); return pick(entity, keysToKeep); }; diff --git a/generators/react/templates/src/main/webapp/app/typings.d.ts.ejs b/generators/react/templates/src/main/webapp/app/typings.d.ts.ejs index 14a3b3d0c064..7a1dd34e661a 100644 --- a/generators/react/templates/src/main/webapp/app/typings.d.ts.ejs +++ b/generators/react/templates/src/main/webapp/app/typings.d.ts.ejs @@ -24,8 +24,8 @@ declare const I18N_HASH: string; <%_ } _%> declare module '*.json' { - const value: any; - export default value; + const value: any; + export default value; } <%_ if (applicationTypeGateway && microfrontend) { _%> diff --git a/generators/react/templates/webpack/environment.js.ejs b/generators/react/templates/webpack/environment.js.ejs index 6573e4518af3..87789bc80f94 100644 --- a/generators/react/templates/webpack/environment.js.ejs +++ b/generators/react/templates/webpack/environment.js.ejs @@ -31,5 +31,5 @@ module.exports = { // If this URL is left empty (""), then it will be relative to the current context. // If you use an API server, in `prod` mode, you will need to enable CORS // (see the `jhipster.cors` common JHipster property in the `application-*.yml` configurations) - SERVER_API_URL: '' + SERVER_API_URL: '', }; diff --git a/generators/react/templates/webpack/webpack.common.js.ejs b/generators/react/templates/webpack/webpack.common.js.ejs index 9401cb4d4e46..df67c0b19ce6 100644 --- a/generators/react/templates/webpack/webpack.common.js.ejs +++ b/generators/react/templates/webpack/webpack.common.js.ejs @@ -128,7 +128,6 @@ return merge( }), new ESLintPlugin({ configType: 'flat', - eslintPath: 'eslint/use-at-your-own-risk', extensions: ['ts', 'tsx'], }), new ForkTsCheckerWebpackPlugin(), diff --git a/generators/server/__snapshots__/generator.spec.js.snap b/generators/server/__snapshots__/generator.spec.ts.snap similarity index 99% rename from generators/server/__snapshots__/generator.spec.js.snap rename to generators/server/__snapshots__/generator.spec.ts.snap index 45d21d555a06..28811ab52b30 100644 --- a/generators/server/__snapshots__/generator.spec.js.snap +++ b/generators/server/__snapshots__/generator.spec.ts.snap @@ -752,9 +752,6 @@ exports[`generator - server with entities should match files snapshot 1`] = ` "src/main/docker/prometheus/prometheus.yml": { "stateCleared": "modified", }, - "src/main/docker/services.yml": { - "stateCleared": "modified", - }, "src/main/docker/sonar.yml": { "stateCleared": "modified", }, diff --git a/generators/server/__test-support/index.ts b/generators/server/__test-support/index.ts index 7f45d20c380c..e24582830f11 100644 --- a/generators/server/__test-support/index.ts +++ b/generators/server/__test-support/index.ts @@ -1,14 +1,11 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import assert from 'assert'; - -import { messageBrokerTypes, databaseTypes } from '../../../jdl/jhipster/index.js'; +import { databaseTypes, messageBrokerTypes } from '../../../lib/jhipster/index.js'; import { - GENERATOR_SPRING_CLOUD_STREAM, + GENERATOR_BOOTSTRAP, GENERATOR_JAVA, GENERATOR_PROJECT_NAME, GENERATOR_SERVER, GENERATOR_SPRING_BOOT, - GENERATOR_BOOTSTRAP, + GENERATOR_SPRING_CLOUD_STREAM, } from '../../generator-list.js'; const { KAFKA, PULSAR } = messageBrokerTypes; @@ -18,11 +15,11 @@ export const shouldComposeWithLiquibase = (testSample, runResultSupplier) => { const liquibaseEnabled = typeof testSample === 'boolean' ? testSample : testSample?.databaseType === SQL; if (liquibaseEnabled) { it('should compose with liquibase generator', () => { - assert(runResultSupplier().mockedGenerators['jhipster:liquibase'].calledOnce); + runResultSupplier().assertGeneratorComposedOnce('jhipster:liquibase'); }); } else { it('should not compose with liquibase generator', () => { - assert(runResultSupplier().mockedGenerators['jhipster:liquibase'].notCalled); + runResultSupplier().assertGeneratorNotComposed('jhipster:liquibase'); }); } }; @@ -32,11 +29,11 @@ export const shouldComposeWithSpringCloudStream = (sampleConfig, runResultSuppli const kafkaEnabled = typeof sampleConfig === 'boolean' ? sampleConfig : sampleConfig?.messageBroker === KAFKA; if (pulsarEnabled || kafkaEnabled) { it(`should compose with ${GENERATOR_SPRING_CLOUD_STREAM} generator`, () => { - assert(runResultSupplier().mockedGenerators[`jhipster:${GENERATOR_SPRING_CLOUD_STREAM}`].calledOnce); + runResultSupplier().assertGeneratorComposedOnce(`jhipster:${GENERATOR_SPRING_CLOUD_STREAM}`); }); } else { it(`should not compose with ${GENERATOR_SPRING_CLOUD_STREAM} generator`, () => { - assert(runResultSupplier().mockedGenerators[`jhipster:${GENERATOR_SPRING_CLOUD_STREAM}`].notCalled); + runResultSupplier().assertGeneratorNotComposed(`jhipster:${GENERATOR_SPRING_CLOUD_STREAM}`); }); } }; @@ -45,11 +42,11 @@ const shouldComposeWithDatabasetype = (databaseType: string, shouldCompose: bool const generator = databaseType; if (shouldCompose) { it(`should compose with ${generator} generator`, () => { - assert(runResultSupplier().mockedGenerators[`jhipster:spring-data-${generator}`].calledOnce); + runResultSupplier().assertGeneratorComposedOnce(`jhipster:spring-data-${generator}`); }); } else { it(`should not compose with ${generator} generator`, () => { - assert(runResultSupplier().mockedGenerators[`jhipster:spring-data-${generator}`].notCalled); + runResultSupplier().assertGeneratorNotComposed(`jhipster:spring-data-${generator}`); }); } }; diff --git a/generators/server/command.ts b/generators/server/command.ts index d2b06eb3090a..2f966e19b0e6 100644 --- a/generators/server/command.ts +++ b/generators/server/command.ts @@ -17,20 +17,16 @@ * limitations under the License. */ import chalk from 'chalk'; -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_COMMON, GENERATOR_SPRING_BOOT } from '../generator-list.js'; -import { APPLICATION_TYPE_GATEWAY, APPLICATION_TYPE_MICROSERVICE, APPLICATION_TYPE_MONOLITH } from '../../jdl/index.js'; +import { APPLICATION_TYPE_GATEWAY, APPLICATION_TYPE_MICROSERVICE, APPLICATION_TYPE_MONOLITH } from '../../lib/jhipster/index.js'; -const command: JHipsterCommandDefinition = { +const command = { options: { db: { description: 'Provide DB name for the application when skipping server side generation', type: String, - }, - incrementalChangelog: { - description: 'Creates incremental database changelogs', - type: Boolean, - scope: 'storage', + scope: 'none', }, skipUserManagement: { description: 'Skip the user management module during app generation', @@ -40,6 +36,7 @@ const command: JHipsterCommandDefinition = { recreateInitialChangelog: { description: 'Recreate the initial database changelog based on the current config', type: Boolean, + scope: 'none', }, cacheProvider: { description: 'Cache provider', @@ -56,11 +53,6 @@ const command: JHipsterCommandDefinition = { type: Boolean, scope: 'storage', }, - messageBroker: { - description: 'message broker', - type: String, - scope: 'storage', - }, searchEngine: { description: 'Provide search engine for the application when skipping server side generation', type: String, @@ -74,6 +66,7 @@ const command: JHipsterCommandDefinition = { skipDbChangelog: { description: 'Skip the generation of database migrations', type: Boolean, + scope: 'none', }, skipFakeData: { description: 'Skip generation of fake data for development', @@ -122,9 +115,10 @@ const command: JHipsterCommandDefinition = { name: 'Microservice application', }, ], + scope: 'storage', }, }, import: [GENERATOR_COMMON, GENERATOR_SPRING_BOOT], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/server/generator.spec.js b/generators/server/generator.spec.ts similarity index 76% rename from generators/server/generator.spec.js rename to generators/server/generator.spec.ts index ff59637adab3..2308b53a0b54 100644 --- a/generators/server/generator.spec.js +++ b/generators/server/generator.spec.ts @@ -16,13 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { shouldSupportFeatures, testBlueprintSupport, checkEnforcements } from '../../test/support/index.js'; -import { defaultHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { checkEnforcements, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/index.js'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import { GENERATOR_SERVER, GENERATOR_SPRING_BOOT } from '../generator-list.js'; import { filterBasicServerGenerators, shouldComposeWithCouchbase, shouldComposeWithSpringCloudStream } from './__test-support/index.js'; import Generator from './index.js'; @@ -31,7 +31,6 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorPath = join(__dirname, 'index.js'); describe(`generator - ${generator}`, () => { it('generator-list constant matches folder name', async () => { @@ -44,41 +43,41 @@ describe(`generator - ${generator}`, () => { describe('composing', () => { describe('messageBroker option', () => { describe('no', () => { - let runResult; before(async () => { - runResult = await helpers - .run(generatorPath) + await helpers + .runJHipster(generator) .withJHipsterConfig({ messageBroker: 'no', }) .withSkipWritingPriorities() + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); shouldComposeWithSpringCloudStream(false, () => runResult); }); describe('kafka', () => { - let runResult; before(async () => { - runResult = await helpers - .run(generatorPath) + await helpers + .runJHipster(generator) .withJHipsterConfig({ messageBroker: 'kafka', }) .withSkipWritingPriorities() + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); shouldComposeWithSpringCloudStream(true, () => runResult); }); describe('pulsar', () => { - let runResult; before(async () => { - runResult = await helpers - .run(generatorPath) + await helpers + .runJHipster(generator) .withJHipsterConfig({ messageBroker: 'pulsar', }) .withSkipWritingPriorities() + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); shouldComposeWithSpringCloudStream(true, () => runResult); @@ -89,11 +88,12 @@ describe(`generator - ${generator}`, () => { describe('no with jwt', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({ databaseType: 'no', authenticationType: 'jwt', }) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); @@ -106,11 +106,12 @@ describe(`generator - ${generator}`, () => { describe('no with session', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({ databaseType: 'no', authenticationType: 'session', }) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); @@ -123,11 +124,12 @@ describe(`generator - ${generator}`, () => { describe('no with oauth2', () => { before(async () => { await helpers - .run(generatorPath) + .runJHipster(generator) .withJHipsterConfig({ databaseType: 'no', authenticationType: 'oauth2', }) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); @@ -138,14 +140,14 @@ describe(`generator - ${generator}`, () => { shouldComposeWithCouchbase(false, () => runResult); }); describe('couchbase', () => { - let runResult; before(async () => { - runResult = await helpers - .run(generatorPath) + await helpers + .runJHipster(generator) .withJHipsterConfig({ databaseType: 'couchbase', }) .withSkipWritingPriorities() + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); shouldComposeWithCouchbase(true, () => runResult); @@ -155,15 +157,18 @@ describe(`generator - ${generator}`, () => { describe('with entities', () => { before(async () => { - await helpers.runJHipster(GENERATOR_SERVER).withJHipsterConfig({ skipClient: true }, [ - { name: 'Foo', changelogDate: '20160926101210', fields: [{ fieldName: 'name', fieldType: 'String' }] }, - { - name: 'Bar', - changelogDate: '20160926101211', - dto: 'mapstruct', - fields: [{ fieldName: 'name', fieldType: 'String', fieldValidateRules: ['required'] }], - }, - ]); + await helpers + .runJHipster(GENERATOR_SERVER) + .withMockedSource({ except: ['addTestSpringFactory'] }) + .withJHipsterConfig({ skipClient: true }, [ + { name: 'Foo', changelogDate: '20160926101210', fields: [{ fieldName: 'name', fieldType: 'String' }] }, + { + name: 'Bar', + changelogDate: '20160926101211', + dto: 'mapstruct', + fields: [{ fieldName: 'name', fieldType: 'String', fieldValidateRules: ['required'] }], + }, + ]); }); it('should match files snapshot', () => { diff --git a/generators/server/generator.js b/generators/server/generator.ts similarity index 87% rename from generators/server/generator.js rename to generators/server/generator.ts index 14bb8e7aa412..03a1fe4a27c0 100644 --- a/generators/server/generator.js +++ b/generators/server/generator.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -18,51 +17,49 @@ * limitations under the License. */ -/* eslint-disable consistent-return */ import { existsSync } from 'fs'; -import chalk from 'chalk'; import { GENERATOR_COMMON, GENERATOR_SPRING_BOOT } from '../generator-list.js'; import BaseApplicationGenerator from '../base-application/index.js'; import { packageJson } from '../../lib/index.js'; import { - SERVER_MAIN_SRC_DIR, - SERVER_MAIN_RES_DIR, - SERVER_TEST_SRC_DIR, - SERVER_TEST_RES_DIR, CLIENT_WEBPACK_DIR, - MAIN_DIR, - LOGIN_REGEX, - TEST_DIR, - JAVA_VERSION, JAVA_COMPATIBLE_VERSIONS, + JAVA_VERSION, JHIPSTER_DEPENDENCIES_VERSION, + LOGIN_REGEX, + MAIN_DIR, + SERVER_MAIN_RES_DIR, + SERVER_MAIN_SRC_DIR, + SERVER_TEST_RES_DIR, + SERVER_TEST_SRC_DIR, + TEST_DIR, } from '../generator-constants.js'; import { applicationTypes, buildToolTypes, + clientFrameworkTypes, databaseTypes, - fieldTypes, entityOptions, - validations, + fieldTypes, reservedKeywords, searchEngineTypes, - clientFrameworkTypes, -} from '../../jdl/jhipster/index.js'; + validations, +} from '../../lib/jhipster/index.js'; import { stringifyApplicationData } from '../base-application/support/index.js'; import { createNeedleCallback, mutateData } from '../base/support/index.js'; -import { isReservedPaginationWords } from '../../jdl/jhipster/reserved-keywords.js'; +import { isReservedPaginationWords } from '../../lib/jhipster/reserved-keywords.js'; import { loadStoredAppOptions } from '../app/support/index.js'; import { isReservedH2Keyword } from '../spring-data-relational/support/h2-reserved-keywords.js'; import { - buildJavaGet as javaGetCall, - javaBeanCase as javaBeanClassNameFormat, - buildJavaGetter as javaGetter, - buildJavaSetter as javaSetter, getJavaValueGeneratorForType as getJavaValueForType, getPrimaryKeyValue as getPKValue, hibernateSnakeCase, + javaBeanCase as javaBeanClassNameFormat, + buildJavaGet as javaGetCall, + buildJavaGetter as javaGetter, + buildJavaSetter as javaSetter, } from './support/index.js'; const dbTypes = fieldTypes; @@ -83,13 +80,13 @@ const { SUPPORTED_VALIDATION_RULES } = validations; const { isReservedTableName } = reservedKeywords; const { ANGULAR, REACT, VUE } = clientFrameworkTypes; const { GRADLE, MAVEN } = buildToolTypes; -const { CASSANDRA, SQL, NO: NO_DATABASE } = databaseTypes; +const { SQL, NO: NO_DATABASE } = databaseTypes; const { GATEWAY } = applicationTypes; const { NO: NO_SEARCH_ENGINE } = searchEngineTypes; const { CommonDBTypes, RelationalOnlyDBTypes } = fieldTypes; const { INSTANT } = CommonDBTypes; -const { BYTES, BYTE_BUFFER } = RelationalOnlyDBTypes; +const { BYTE_BUFFER } = RelationalOnlyDBTypes; const { PaginationTypes, ServiceTypes } = entityOptions; const { Validations: { MAX, MIN, MAXLENGTH, MINLENGTH, MAXBYTES, MINBYTES, PATTERN }, @@ -150,20 +147,24 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { this.log.info(`Using ${application.defaultPackaging} as default packaging`); } }, - setupServerconsts({ application }) { + setupServerconsts({ application, applicationDefaults }) { // Make constants available in templates - application.MAIN_DIR = MAIN_DIR; - application.TEST_DIR = TEST_DIR; - application.LOGIN_REGEX = LOGIN_REGEX; - application.CLIENT_WEBPACK_DIR = CLIENT_WEBPACK_DIR; - application.SERVER_MAIN_SRC_DIR = SERVER_MAIN_SRC_DIR; - application.SERVER_MAIN_RES_DIR = SERVER_MAIN_RES_DIR; - application.SERVER_TEST_SRC_DIR = SERVER_TEST_SRC_DIR; - application.SERVER_TEST_RES_DIR = SERVER_TEST_RES_DIR; - - application.JAVA_VERSION = this.useVersionPlaceholders ? 'JAVA_VERSION' : JAVA_VERSION; - application.JAVA_COMPATIBLE_VERSIONS = JAVA_COMPATIBLE_VERSIONS; - application.javaCompatibleVersions = JAVA_COMPATIBLE_VERSIONS; + applicationDefaults({ + MAIN_DIR, + TEST_DIR, + LOGIN_REGEX, + CLIENT_WEBPACK_DIR, + SERVER_MAIN_SRC_DIR, + SERVER_MAIN_RES_DIR, + SERVER_TEST_SRC_DIR, + SERVER_TEST_RES_DIR, + JAVA_VERSION: this.useVersionPlaceholders ? 'JAVA_VERSION' : JAVA_VERSION, + JAVA_COMPATIBLE_VERSIONS, + javaCompatibleVersions: JAVA_COMPATIBLE_VERSIONS, + ANGULAR, + VUE, + REACT, + }); if (this.projectVersion) { application.projectVersion = this.projectVersion; @@ -181,11 +182,6 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { application.jhipsterDependenciesVersion = JHIPSTER_DEPENDENCIES_VERSION; } - application.ANGULAR = ANGULAR; - application.VUE = VUE; - application.REACT = REACT; - - this.packagejs = packageJson; application.jhipsterPackageJson = packageJson; }, }); @@ -217,20 +213,6 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { return this.delegateTasksToBlueprint(() => this.preparing); } - get postPreparing() { - return this.asPostPreparingTaskGroup({ - useNpmWrapper({ application }) { - if (application.useNpmWrapper) { - this.useNpmWrapperInstallTask(); - } - }, - }); - } - - get [BaseApplicationGenerator.POST_PREPARING]() { - return this.delegateTasksToBlueprint(() => this.postPreparing); - } - get configuringEachEntity() { return this.asConfiguringEachEntityTaskGroup({ configureMicroservice({ application, entityConfig }) { @@ -334,29 +316,16 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { }, configureFields({ application, entityConfig, entityName }) { - const databaseType = entityConfig.databaseType ?? application.databaseType; // Validate entity json field content const fields = entityConfig.fields; - fields.forEach(field => { + fields!.forEach(field => { // Migration from JodaTime to Java Time if (field.fieldType === 'DateTime' || field.fieldType === 'Date') { field.fieldType = INSTANT; } - if (field.fieldType === BYTES && databaseType === CASSANDRA) { - field.fieldType = BYTE_BUFFER; - } this._validateField(entityName, field); - if (field.fieldType === BYTE_BUFFER) { - this.log.warn( - `Cannot use validation in .jhipster/${entityName}.json for field ${stringifyApplicationData( - field, - )} \nHibernate JPA 2 Metamodel does not work with Bean Validation 2 for LOB fields, so LOB validation is disabled`, - ); - field.fieldValidate = false; - field.fieldValidateRules = []; - } if (entityConfig.pagination && entityConfig.pagination !== NO_PAGINATION && isReservedPaginationWords(field.fieldName)) { throw new Error( `Field name '${field.fieldName}' found in ${entityConfig.name} is a reserved keyword, as it is used by Spring for pagination in the URL.`, @@ -380,7 +349,7 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { configureRelationships({ entityConfig, entityName }) { // Validate entity json relationship content const relationships = entityConfig.relationships; - relationships.forEach(relationship => { + relationships!.forEach(relationship => { this._validateRelationship(entityName, relationship); if (relationship.relationshipName === undefined) { @@ -391,9 +360,11 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { )}, using ${relationship.otherEntityName} as fallback`, ); } + // @ts-ignore deprecated property if (relationship.useJPADerivedIdentifier) { this.log.verboseInfo('Option useJPADerivedIdentifier is deprecated, use id instead'); - relationship.id = true; + relationship.options ??= {}; + relationship.options.id = true; } }); entityConfig.relationships = relationships; @@ -405,6 +376,26 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { return this.delegateTasksToBlueprint(() => this.configuringEachEntity); } + get loadingEntities() { + return this.asLoadingEntitiesTaskGroup({ + loadEntityConfig({ entitiesToLoad }) { + for (const { entityName, entityBootstrap } of entitiesToLoad) { + for (const field of entityBootstrap.fields) { + if (field.fieldType === BYTE_BUFFER) { + this.log.warn(`Cannot use validation in .jhipster/${entityName}.json for field ${stringifyApplicationData(field)}`); + field.fieldValidate = false; + field.fieldValidateRules = []; + } + } + } + }, + }); + } + + get [BaseApplicationGenerator.LOADING_ENTITIES]() { + return this.delegateTasksToBlueprint(() => this.loadingEntities); + } + get preparingEachEntity() { return this.asPreparingEachEntityTaskGroup({ prepareEntity({ entity }) { @@ -423,7 +414,8 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { get postPreparingEachEntity() { return this.asPostPreparingEachEntityTaskGroup({ checkForTableName({ application, entity }) { - const databaseType = entity.prodDatabaseType ?? application.prodDatabaseType ?? entity.databaseType ?? application.databaseType; + const databaseType = + (entity as any).prodDatabaseType ?? application.prodDatabaseType ?? entity.databaseType ?? application.databaseType; const validation = this._validateTableName(entity.entityTableName, databaseType, entity); if (validation !== true) { throw new Error(validation); @@ -444,7 +436,7 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { if (entitiesWithCompositeIds.length > 0) { throw new Error( `Composite id is not supported. Defined in ${entitiesWithCompositeIds.map( - entity => `${entity.name} (${entity.primaryKey.fields.map(field => field.fieldName)})`, + entity => `${entity.name} (${entity.primaryKey!.fields.map(field => field.fieldName)})`, )}`, ); } @@ -460,8 +452,8 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { return this.asPostWritingTaskGroup({ packageJsonScripts({ application }) { const packageJsonConfigStorage = this.packageJson.createStorage('config').createProxy(); - packageJsonConfigStorage.backend_port = application.gatewayServerPort || application.serverPort; - packageJsonConfigStorage.packaging = application.defaultPackaging; + (packageJsonConfigStorage as any).backend_port = application.gatewayServerPort || application.serverPort; + (packageJsonConfigStorage as any).packaging = application.defaultPackaging; }, packageJsonBackendScripts({ application }) { const scriptsStorage = this.packageJson.createStorage('scripts'); @@ -524,9 +516,10 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { }, packageJsonE2eScripts({ application }) { const scriptsStorage = this.packageJson.createStorage('scripts'); - const buildCmd = application.buildToolGradle ? 'gradlew' : 'mvnw'; + const buildCmd = application.buildToolGradle ? 'gradlew' : 'mvnw -ntp'; - const applicationWaitTimeout = WAIT_TIMEOUT * (application.applicationTypeGateway ? 2 : 1); + let applicationWaitTimeout = WAIT_TIMEOUT * (application.applicationTypeGateway ? 2 : 1); + applicationWaitTimeout = application.authenticationTypeOauth2 ? applicationWaitTimeout * 2 : applicationWaitTimeout; const applicationEndpoint = application.applicationTypeMicroservice ? `http-get://127.0.0.1:${application.gatewayServerPort}/${application.endpointPrefix}/management/health/readiness` : 'http-get://127.0.0.1:$npm_package_config_backend_port/management/health'; @@ -538,9 +531,10 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { if (this.jhipsterConfig.testFrameworks?.includes('cypress')) { scriptsStorage.set({ 'pree2e:headless': 'npm run ci:server:await', - 'ci:e2e:run': 'concurrently -k -s first "npm run ci:e2e:server:start" "npm run e2e:headless"', - 'e2e:dev': `concurrently -k -s first "./${buildCmd}" "npm run e2e"`, - 'e2e:devserver': `concurrently -k -s first "npm run backend:start" "npm start" "wait-on -t ${WAIT_TIMEOUT} http-get://127.0.0.1:9000 && npm run e2e:headless -- -c baseUrl=http://localhost:9000"`, + 'ci:e2e:run': 'concurrently -k -s first -n application,e2e -c red,blue npm:ci:e2e:server:start npm:e2e:headless', + 'ci:e2e:dev': `concurrently -k -s first -n application,e2e -c red,blue "./${buildCmd}" npm:e2e:headless`, + 'e2e:dev': `concurrently -k -s first -n application,e2e -c red,blue "./${buildCmd}" npm:e2e`, + 'e2e:devserver': `concurrently -k -s first -n backend,frontend,e2e -c red,yellow,blue npm:backend:start npm:start "wait-on -t ${WAIT_TIMEOUT} http-get://127.0.0.1:9000 && npm run e2e:headless -- -c baseUrl=http://localhost:9000"`, }); } }, @@ -560,7 +554,8 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { const instructions = `You can specify a different table name in your JDL file or change it in .jhipster/${entity.name}.json file and then run again 'jhipster entity ${entity.name}.'`; if (!/^([a-zA-Z0-9_]*)$/.test(entityTableName)) { - return `The table name cannot contain special characters.\n${instructions}`; + return `The table name cannot contain special characters. +${instructions}`; } if (!entityTableName) { return 'The table name cannot be empty'; @@ -568,12 +563,14 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { if (isReservedTableName(entityTableName, prodDatabaseType)) { if (jhiTablePrefix) { this.log.warn( - `The table name cannot contain the '${entityTableName.toUpperCase()}' reserved keyword, so it will be prefixed with '${jhiTablePrefix}_'.\n${instructions}`, + `The table name cannot contain the '${entityTableName.toUpperCase()}' reserved keyword, so it will be prefixed with '${jhiTablePrefix}_'. +${instructions}`, ); entity.entityTableName = `${jhiTablePrefix}_${entityTableName}`; } else { this.log.warn( - `The table name contain the '${entityTableName.toUpperCase()}' reserved keyword but you have defined an empty jhiPrefix so it won't be prefixed and thus the generated application might not work'.\n${instructions}`, + `The table name contain the '${entityTableName.toUpperCase()}' reserved keyword but you have defined an empty jhiPrefix so it won't be prefixed and thus the generated application might not work'. +${instructions}`, ); } } @@ -636,25 +633,6 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { } } - useNpmWrapperInstallTask() { - this.setFeatures({ - customInstallTask: async function customInstallTask(preferredPm, defaultInstallTask) { - const buildTool = this.jhipsterConfig.buildTool; - if ((preferredPm && preferredPm !== 'npm') || this.jhipsterConfig.skipClient || (buildTool !== GRADLE && buildTool !== MAVEN)) { - return defaultInstallTask(); - } - - const npmCommand = process.platform === 'win32' ? 'npmw' : './npmw'; - try { - await this.spawnCommand(npmCommand, ['install'], { preferLocal: true }); - } catch (error) { - this.log.error(chalk.red(`Error executing '${npmCommand} install', please execute it yourself. (${error.shortMessage})`)); - } - return true; - }.bind(this), - }); - } - _validateRelationship(entityName, relationship) { if (relationship.otherEntityName === undefined) { throw new Error( diff --git a/generators/server/index.ts b/generators/server/index.ts index 784af9923300..1cfadd692bb6 100644 --- a/generators/server/index.ts +++ b/generators/server/index.ts @@ -16,18 +16,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import { BaseApplicationGeneratorDefinition, GenericApplicationDefinition } from '../base-application/tasks.js'; -import { GenericSourceTypeDefinition } from '../base/tasks.js'; -import { SpringBootApplication, SpringBootSourceType } from './types.js'; - export { default } from './generator.js'; export { default as command } from './command.js'; - -// TODO move to ./generator.mts -export type ApplicationDefinition = GenericApplicationDefinition; - -// TODO move to ./generator.mts -export type GeneratorDefinition = BaseApplicationGeneratorDefinition< - ApplicationDefinition & GenericSourceTypeDefinition ->; diff --git a/generators/server/jdl/application-definition.ts b/generators/server/jdl/application-definition.ts deleted file mode 100644 index b5990d68d407..000000000000 --- a/generators/server/jdl/application-definition.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright 2013-2024 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. - */ -import { upperCase, snakeCase } from 'lodash-es'; -import { JDLApplicationConfig, JHipsterOptionDefinition } from '../../../jdl/types/types.js'; -import databaseMigrationOption from '../options/database-migration.js'; -import messageBrokerOption from '../options/message-broker.js'; -import { feignClientDefinition, syncUserWithIdpDefinition } from '../options/index.js'; -import { jdlRoutesOptions } from '../../spring-cloud/generators/gateway/jdl/jdl-routes-option.js'; - -const jdlOptions: JHipsterOptionDefinition[] = [ - databaseMigrationOption, - messageBrokerOption, - feignClientDefinition, - syncUserWithIdpDefinition, - jdlRoutesOptions, -]; - -const applicationConfig: JDLApplicationConfig = { - tokenConfigs: jdlOptions.map(option => ({ - name: upperCase(snakeCase(option.name)), - pattern: option.name, - })), - validatorConfig: Object.fromEntries( - jdlOptions.map(option => [ - upperCase(snakeCase(option.name)), - { - type: option.tokenType, - pattern: option.tokenValuePattern, - msg: `${option.name} property`, - }, - ]), - ), - optionsValues: Object.fromEntries( - jdlOptions - .filter(option => option.knownChoices) - .map(option => [option.name, Object.fromEntries(option.knownChoices!.map(choice => [choice, choice]))]), - ), - optionsTypes: Object.fromEntries( - jdlOptions.map(option => [ - option.name, - { - type: option.type, - }, - ]), - ), -}; - -export default applicationConfig; diff --git a/generators/server/jdl/index.ts b/generators/server/jdl/index.ts deleted file mode 100644 index c72947223780..000000000000 --- a/generators/server/jdl/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright 2013-2024 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. - */ -export { default } from './application-definition.js'; diff --git a/generators/server/needle-logback.spec.ts b/generators/server/needle-logback.spec.ts index 29f85ca37d49..2d5431c9a06c 100644 --- a/generators/server/needle-logback.spec.ts +++ b/generators/server/needle-logback.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe } from 'esmocha'; -import { dryRunHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { before, describe, it } from 'esmocha'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import BaseApplicationGenerator from '../base-application/index.js'; import { SERVER_MAIN_RES_DIR } from '../generator-constants.js'; import { GENERATOR_SERVER } from '../generator-list.js'; @@ -26,8 +26,10 @@ describe('generators - server - needle - logback', () => { before(async () => { await helpers .runJHipster(GENERATOR_SERVER) + .withOptions({ + blueprint: ['myblueprint'], + }) .withJHipsterConfig({ - blueprint: 'myblueprint', clientFramework: 'no', }) .withGenerators([[mockBlueprintSubGen, { namespace: 'jhipster-myblueprint:server' }]]); diff --git a/generators/server/options/database-migration.spec.ts b/generators/server/options/database-migration.spec.ts deleted file mode 100644 index 2f40b0933b7d..000000000000 --- a/generators/server/options/database-migration.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { before, it, describe, expect } from 'esmocha'; -import { createImporterFromContent, ImportState } from '../../../jdl/jdl-importer.js'; -import optionDefinition from './database-migration.js'; -import { DATABASE_MIGRATION as optionName } from './index.js'; - -describe(`generators - server - jdl - ${optionName}`, () => { - optionDefinition.knownChoices!.forEach(optionValue => { - describe(`with ${optionValue} value`, () => { - let state: ImportState; - - before(() => { - const importer = createImporterFromContent(`application { config { ${optionName} ${optionValue} } }`); - state = importer.import(); - }); - - it('should set expected value', () => { - expect(state.exportedApplicationsWithEntities.jhipster.config[optionName]).toBe(optionValue); - }); - }); - }); -}); diff --git a/generators/server/options/feign-client.spec.ts b/generators/server/options/feign-client.spec.ts deleted file mode 100644 index 1de2e8ea01c4..000000000000 --- a/generators/server/options/feign-client.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { before, it, describe, expect } from 'esmocha'; -import { createImporterFromContent, ImportState } from '../../../jdl/jdl-importer.js'; -import { FEIGN_CLIENT as optionName } from './index.js'; - -describe(`generators - server - jdl - ${optionName}`, () => { - [true, false].forEach(optionValue => { - describe(`with ${optionValue} value`, () => { - let state: ImportState; - - before(() => { - const importer = createImporterFromContent(`application { config { ${optionName} ${optionValue} } }`); - state = importer.import(); - }); - - it('should set expected value', () => { - expect(state.exportedApplicationsWithEntities.jhipster.config[optionName]).toBe(optionValue); - }); - }); - }); -}); diff --git a/generators/server/options/index.ts b/generators/server/options/index.ts deleted file mode 100644 index 1820b16da131..000000000000 --- a/generators/server/options/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright 2013-2024 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. - */ - -export * from './database-migration.js'; -export * from './message-broker.js'; -export * from './feign-client.js'; -export * from './sync-user-with-idp.js'; diff --git a/generators/server/options/message-broker.spec.ts b/generators/server/options/message-broker.spec.ts deleted file mode 100644 index d8ed76c310a9..000000000000 --- a/generators/server/options/message-broker.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { before, it, describe, expect } from 'esmocha'; -import { createImporterFromContent, ImportState } from '../../../jdl/jdl-importer.js'; -import optionDefinition from './message-broker.js'; -import { MESSAGE_BROKER } from './index.js'; - -describe('generators - server - jdl - messageBroker', () => { - optionDefinition.knownChoices!.forEach(optionValue => { - describe(`with ${optionValue} value`, () => { - let state: ImportState; - - before(() => { - const importer = createImporterFromContent(`application { config { ${MESSAGE_BROKER} ${optionValue} } }`); - state = importer.import(); - }); - - it('should set expected value', () => { - expect(state.exportedApplicationsWithEntities.jhipster.config[MESSAGE_BROKER]).toBe(optionValue); - }); - }); - }); -}); diff --git a/generators/server/options/message-broker.ts b/generators/server/options/message-broker.ts deleted file mode 100644 index 7b4db138cacd..000000000000 --- a/generators/server/options/message-broker.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2013-2024 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. - */ - -import { JHipsterOptionDefinition } from '../../../jdl/types/types.js'; -import { OptionWithDerivedProperties } from '../../base-application/application-options.js'; - -export const MESSAGE_BROKER = 'messageBroker'; - -export const MESSAGE_BROKER_KAFKA = 'kafka'; -export const MESSAGE_BROKER_PULSAR = 'pulsar'; -export const MESSAGE_BROKER_NO = 'no'; - -const ALPHANUMERIC_PATTERN = /^[A-Za-z][A-Za-z0-9]*$/; - -const optionDefinition: JHipsterOptionDefinition = { - name: MESSAGE_BROKER, - type: 'string', - tokenType: 'NAME', - tokenValuePattern: ALPHANUMERIC_PATTERN, - knownChoices: [MESSAGE_BROKER_NO, MESSAGE_BROKER_KAFKA, MESSAGE_BROKER_PULSAR], -}; - -export default optionDefinition; - -type MessageBrokerTypes = [typeof MESSAGE_BROKER_KAFKA, typeof MESSAGE_BROKER_PULSAR, typeof MESSAGE_BROKER_NO]; - -export type MessageBrokerApplicationType = OptionWithDerivedProperties; diff --git a/generators/server/options/sync-user-with-idp.spec.ts b/generators/server/options/sync-user-with-idp.spec.ts deleted file mode 100644 index 3e77fedbe47b..000000000000 --- a/generators/server/options/sync-user-with-idp.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { before, it, describe, expect } from 'esmocha'; -import { createImporterFromContent, ImportState } from '../../../jdl/jdl-importer.js'; -import { SYNC_USER_WITH_IDP as optionName } from './sync-user-with-idp.js'; - -describe(`generators - server - jdl - ${optionName}`, () => { - [true, false].forEach(optionValue => { - describe(`with ${optionValue} value`, () => { - let state: ImportState; - - before(() => { - const importer = createImporterFromContent(`application { config { ${optionName} ${optionValue} } }`); - state = importer.import(); - }); - - it('should set expected value', () => { - expect(state.exportedApplicationsWithEntities.jhipster.config[optionName]).toBe(optionValue); - }); - }); - }); -}); diff --git a/generators/server/options/sync-user-with-idp.ts b/generators/server/options/sync-user-with-idp.ts deleted file mode 100644 index 3994ca4336e3..000000000000 --- a/generators/server/options/sync-user-with-idp.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright 2013-2024 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. - */ - -import { JHipsterOptionDefinition } from '../../../jdl/types/types.js'; - -export const SYNC_USER_WITH_IDP = 'syncUserWithIdp'; - -export const syncUserWithIdpDefinition: JHipsterOptionDefinition = { - name: SYNC_USER_WITH_IDP, - type: 'boolean', - tokenType: 'BOOLEAN', -}; diff --git a/generators/server/resources/Dockerfile b/generators/server/resources/Dockerfile index a1d987c9a0b8..cd5856876f5f 100644 --- a/generators/server/resources/Dockerfile +++ b/generators/server/resources/Dockerfile @@ -10,20 +10,20 @@ LABEL ALIAS=jhipster-control-center FROM jhipster/consul-config-loader:v0.4.1 LABEL ALIAS=consul-config-loader -FROM postgres:16.3 +FROM postgres:17.0 LABEL ALIAS=postgresql FROM quay.io/keycloak/keycloak:25.0.1 LABEL ALIAS=keycloak -FROM mysql:9.0.0 +FROM mysql:9.1.0 -FROM mariadb:11.4.2 +FROM mariadb:11.5.2 -FROM mongo:7.0.6 +FROM mongo:8.0.3 LABEL ALIAS=mongodb -FROM couchbase/server:7.6.1 +FROM couchbase/server:7.6.3 LABEL ALIAS=couchbase FROM cassandra:5.0 @@ -31,31 +31,31 @@ FROM cassandra:5.0 FROM mcr.microsoft.com/mssql/server:2019-CU16-GDR1-ubuntu-20.04 LABEL ALIAS=mssql -FROM neo4j:5.21.2 +FROM neo4j:5.24.2 -FROM hazelcast/management-center:5.4.1 +FROM hazelcast/management-center:5.6.0 LABEL ALIAS=hazelcast -FROM memcached:1.6.29-alpine +FROM memcached:1.6.32-alpine -FROM redis:7.2.5 +FROM redis:7.4.1 -FROM confluentinc/cp-kafka:7.6.2 +FROM confluentinc/cp-kafka:7.7.1 LABEL ALIAS=kafka -FROM confluentinc/cp-zookeeper:7.6.2 +FROM confluentinc/cp-zookeeper:7.7.1 LABEL ALIAS=zookeeper -FROM apachepulsar/pulsar:3.2.3 +FROM apachepulsar/pulsar:4.0.0 LABEL ALIAS=pulsar -FROM sonarqube:10.6.0-community +FROM sonarqube:10.7.0-community LABEL ALIAS=sonar -FROM docker.io/bitnami/consul:1.19.1 +FROM docker.io/bitnami/consul:1.20.0 LABEL ALIAS=consul -FROM prom/prometheus:v2.53.1 +FROM prom/prometheus:v2.55.0 LABEL ALIAS=prometheus FROM prom/alertmanager:v0.27.0 @@ -64,7 +64,7 @@ LABEL ALIAS=prometheus-alertmanager FROM quay.io/coreos/prometheus-operator:v0.42.1 LABEL ALIAS=prometheus-operator -FROM grafana/grafana:11.1.0 +FROM grafana/grafana:11.3.0 LABEL ALIAS=grafana FROM quay.io/coreos/grafana-watcher:v0.0.8 diff --git a/generators/server/resources/gradle/libs.versions.toml b/generators/server/resources/gradle/libs.versions.toml index d259ec1574fa..6e419defb29f 100644 --- a/generators/server/resources/gradle/libs.versions.toml +++ b/generators/server/resources/gradle/libs.versions.toml @@ -3,25 +3,32 @@ spring-cloud-dependencies = { module = 'org.springframework.cloud:spring-cloud-d springdoc = { module = 'org.springdoc:springdoc-openapi-starter-webmvc-api', version = '2.6.0' } -feign-reactor-bom = { module = 'com.playtika.reactivefeign:feign-reactor-bom', version = '4.0.3' } +feign-reactor-bom = { module = 'com.playtika.reactivefeign:feign-reactor-bom', version = '4.2.1' } # Cucumber testng = { module = 'org.testng:testng', version = '7.10.2' } -cucumber-bom = { module = 'io.cucumber:cucumber-bom', version = '7.18.0' } +cucumber-bom = { module = 'io.cucumber:cucumber-bom', version = '7.20.1' } -mongock-bom = { module = 'io.mongock:mongock-bom', version = '5.4.4' } +mongock-bom = { module = 'io.mongock:mongock-bom', version = '5.5.0' } -neo4j-migrations-spring-boot-starter = { module = 'eu.michael-simons.neo4j:neo4j-migrations-spring-boot-starter', version = '2.10.3' } +neo4j-migrations-spring-boot-starter = { module = 'eu.michael-simons.neo4j:neo4j-migrations-spring-boot-starter', version = '2.13.3' } # Cassandra lz4-java = { module = 'org.lz4:lz4-java', version = '1.8.0' } +# Couchbase +couchmove = { module = 'com.github.differentway:couchmove', version = '3.4.1' } + +# jib +jib-maven-plugin = { module = 'com.google.cloud.tools:jib-maven-plugin', version = '3.4.4' } +jib-spring-boot-extension-maven = { module = 'com.google.cloud.tools:jib-spring-boot-extension-maven', version = '0.1.0' } + [plugins] gradle-git-properties = { id = 'com.gorylenko.gradle-git-properties', version = '2.4.2' } -node-gradle = { id = 'com.github.node-gradle.node', version = '7.0.2' } +node-gradle = { id = 'com.github.node-gradle.node', version = '7.1.0' } -gradle-liquibase = { id = 'org.liquibase.gradle', version = '2.2.2' } +gradle-liquibase = { id = 'org.liquibase.gradle', version = '3.0.1' } gradle-sonarqube = { id = 'org.sonarqube', version = '5.1.0.4882' } @@ -29,10 +36,10 @@ spotless-gradle-plugin = { id = 'com.diffplug.spotless', version = '6.25.0' } gradle-modernizer-plugin = { id = 'com.github.andygoossens.gradle-modernizer-plugin', version = '1.9.3' } -gradle-enterprise = { id = 'com.gradle.enterprise', version = '3.17.5' } +gradle-enterprise = { id = 'com.gradle.enterprise', version = '3.18.1' } common-custom-user-data-gradle-plugin = { id = 'com.gradle.common-custom-user-data-gradle-plugin', version = '2.0.2' } -gatling-gradle = { id = 'io.gatling.gradle', version = '3.11.5.2' } +gatling-gradle = { id = 'io.gatling.gradle', version = '3.12.0.3' } -gradle-openapi-generator = { id = 'org.openapi.generator', version = '7.7.0' } +gradle-openapi-generator = { id = 'org.openapi.generator', version = '7.9.0' } diff --git a/generators/server/resources/pom.xml b/generators/server/resources/pom.xml index 82a5747dad4e..375ddc4c25e0 100644 --- a/generators/server/resources/pom.xml +++ b/generators/server/resources/pom.xml @@ -9,38 +9,37 @@ 1.3.0 - 1.0.9.RELEASE + 1.0.10.RELEASE 1.9.4 - 3.11.5 + 3.12.0 0.2.6 - 1.5.5.Final - 1.1.1 + 1.6.2 + 1.1.2 4.7.6 - 10.17.0 + 10.19.0 1.11 - 1.15.0 - 4.9.6 + 1.15.1 + 4.10.1 9.0.1 - 3.4.3 1.0.0 0.8.12 3.1.0 - 3.4.0 + 3.6.0 3.4.0 3.13.0 3.5.0 - 3.3.1 + 3.5.1 3.4.2 - 3.7.0 + 3.10.1 3.3.1 - 3.12.1 - 3.3.1 + 3.21.0 + 3.5.1 3.4.0 2.9.0 0.0.11 - 7.7.0 + 7.9.0 1.2.1 4.0.0.4121 2.43.0 @@ -98,11 +97,6 @@ frontend-maven-plugin ${frontend-maven-plugin.version} - - com.google.cloud.tools - jib-maven-plugin - ${jib-maven-plugin.version} - com.puppycrawl.tools checkstyle diff --git a/generators/server/support/build-specification-mapper.ts b/generators/server/support/build-specification-mapper.ts index 931d27d23359..269a9a94ae16 100644 --- a/generators/server/support/build-specification-mapper.ts +++ b/generators/server/support/build-specification-mapper.ts @@ -1,4 +1,5 @@ -import { fieldTypes } from '../../../jdl/jhipster/index.js'; +import type { FieldType } from '../../../lib/application/field-types.js'; +import { fieldTypes } from '../../../lib/jhipster/index.js'; const { STRING: TYPE_STRING, @@ -17,7 +18,7 @@ const { * Return the method name which converts the filter to specification * @param {string} fieldType */ -export const getSpecificationBuildForType = (fieldType: string) => { +export const getSpecificationBuildForType = (fieldType: FieldType) => { if ( [ TYPE_INTEGER, diff --git a/generators/server/support/config.ts b/generators/server/support/config.ts index 42524dd9a4a6..e4be61c92094 100644 --- a/generators/server/support/config.ts +++ b/generators/server/support/config.ts @@ -1,15 +1,15 @@ import { mutateData, normalizePathEnd, pickFields } from '../../base/support/index.js'; import { - databaseTypes, - monitoringTypes, authenticationTypes, buildToolTypes, cacheTypes, - websocketTypes, - serviceDiscoveryTypes, + databaseTypes, + monitoringTypes, searchEngineTypes, -} from '../../../jdl/jhipster/index.js'; + serviceDiscoveryTypes, + websocketTypes, +} from '../../../lib/jhipster/index.js'; import { prepareSqlApplicationProperties } from '../../spring-data-relational/support/index.js'; import { CLIENT_DIST_DIR, @@ -20,8 +20,7 @@ import { SERVER_TEST_RES_DIR, SERVER_TEST_SRC_DIR, } from '../../generator-constants.js'; -import { MESSAGE_BROKER_KAFKA, MESSAGE_BROKER_NO, MESSAGE_BROKER_PULSAR } from '../../server/options/index.js'; -import { PlatformApplication } from '../../base-application/types.js'; +import type { PlatformApplication } from '../../base-application/types.js'; const { NO: NO_DATABASE, SQL, MONGODB, COUCHBASE, NEO4J, CASSANDRA } = databaseTypes; const { PROMETHEUS, ELK } = monitoringTypes; @@ -125,13 +124,6 @@ export const loadDerivedServerConfig = ({ application }: { application: any }) = application.searchEngineCouchbase = application.searchEngine === COUCHBASE; application.searchEngineElasticsearch = application.searchEngine === ELASTICSEARCH; - if (!application.messageBroker) { - application.messageBroker = MESSAGE_BROKER_NO; - } - application.messageBrokerKafka = application.messageBroker === MESSAGE_BROKER_KAFKA; - application.messageBrokerPulsar = application.messageBroker === MESSAGE_BROKER_PULSAR; - application.messageBrokerAny = application.messageBroker && application.messageBroker !== MESSAGE_BROKER_NO; - application.buildToolGradle = application.buildTool === GRADLE; application.buildToolMaven = application.buildTool === MAVEN; application.buildToolUnknown = !application.buildToolGradle && !application.buildToolMaven; diff --git a/generators/server/support/database.spec.ts b/generators/server/support/database.spec.ts index 26c0e0cae7b6..11c9dbc0f195 100644 --- a/generators/server/support/database.spec.ts +++ b/generators/server/support/database.spec.ts @@ -1,5 +1,5 @@ -import { it, describe, expect } from 'esmocha'; -import { databaseTypes } from '../../../jdl/jhipster/index.js'; +import { describe, expect, it } from 'esmocha'; +import { databaseTypes } from '../../../lib/jhipster/index.js'; import { getDBTypeFromDBValue, getFKConstraintName, getJoinTableName, getUXConstraintName } from './database.js'; import { hibernateSnakeCase } from './string.js'; diff --git a/generators/server/support/database.ts b/generators/server/support/database.ts index 8fae360bd3c3..f9e4a7142b57 100644 --- a/generators/server/support/database.ts +++ b/generators/server/support/database.ts @@ -18,9 +18,9 @@ */ import crypto from 'crypto'; -import { databaseTypes, fieldTypes } from '../../../jdl/jhipster/index.js'; +import { databaseTypes, fieldTypes } from '../../../lib/jhipster/index.js'; import { databaseData } from '../../spring-data-relational/support/index.js'; -import { ValidationResult } from '../../base/api.js'; +import type { ValidationResult } from '../../base/api.js'; import { hibernateSnakeCase } from './string.js'; const dbTypes = fieldTypes; diff --git a/generators/server/support/needles.spec.ts b/generators/server/support/needles.spec.ts index 91c391222fab..5ec860b76712 100644 --- a/generators/server/support/needles.spec.ts +++ b/generators/server/support/needles.spec.ts @@ -16,10 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { before, it, describe, expect } from 'esmocha'; -import { defaultHelpers as helpers, runResult } from '../../../testing/index.js'; +import { before, describe, expect, it } from 'esmocha'; +import { defaultHelpers as helpers, runResult } from '../../../lib/testing/index.js'; import { GENERATOR_SPRING_BOOT } from '../../generator-list.js'; -import type { SpringBootApplication } from '../types.js'; import { insertContentIntoApplicationProperties } from './needles.js'; describe('generator - server - support - needles', () => { @@ -36,10 +35,11 @@ describe('generator - server - support - needles', () => { describe('insertContentIntoApplicationProperties needle', () => { it('with a non existing needle', () => { - const application: SpringBootApplication = runResult.generator.sharedData.getApplication(); - expect(() => insertContentIntoApplicationProperties.call(runResult.generator, application, { foo: 'foo' })).toThrow( - /Missing required jhipster-needle application-properties-foo not found at/, - ); + const application = runResult.generator.sharedData.getApplication(); + expect(() => { + // @ts-expect-error invalid needle + insertContentIntoApplicationProperties.call(runResult.generator, application, { foo: 'foo' }); + }).toThrow(/Missing required jhipster-needle application-properties-foo not found at/); }); it('without a needle', () => { diff --git a/generators/server/support/needles.ts b/generators/server/support/needles.ts index d308fcf26848..1c9616afee99 100644 --- a/generators/server/support/needles.ts +++ b/generators/server/support/needles.ts @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import CoreGenerator from '../../base-core/index.js'; +import assert from 'assert'; +import type CoreGenerator from '../../base-core/index.js'; import { createBaseNeedle } from '../../base/support/needles.js'; -import { SpringBootApplication } from '../types.js'; export type ApplicationPropertiesNeedles = { property?: string; @@ -56,22 +56,24 @@ export type ApplicationPropertiesNeedles = { * }); * ); */ +export function insertContentIntoApplicationProperties(needles: ApplicationPropertiesNeedles); export function insertContentIntoApplicationProperties( this: CoreGenerator, - application: SpringBootApplication, + application: { javaPackageSrcDir: string }, needles: ApplicationPropertiesNeedles, ); -export function insertContentIntoApplicationProperties(this: void, needles: ApplicationPropertiesNeedles); export function insertContentIntoApplicationProperties( this: CoreGenerator | void, - application: SpringBootApplication | ApplicationPropertiesNeedles, + application: { javaPackageSrcDir: string } | ApplicationPropertiesNeedles, needles?: ApplicationPropertiesNeedles, ) { - if (this) { + if (needles) { + assert.ok(this, 'Generator context is required'); + return createBaseNeedle.call( this, { - filePath: `${(application as SpringBootApplication).javaPackageSrcDir}config/ApplicationProperties.java`, + filePath: `${(application as { javaPackageSrcDir: string }).javaPackageSrcDir}config/ApplicationProperties.java`, needlesPrefix: 'application-properties', }, needles, diff --git a/generators/server/support/prepare-entity.js b/generators/server/support/prepare-entity.ts similarity index 96% rename from generators/server/support/prepare-entity.js rename to generators/server/support/prepare-entity.ts index 82b22189f868..b3ad73184980 100644 --- a/generators/server/support/prepare-entity.js +++ b/generators/server/support/prepare-entity.ts @@ -18,9 +18,9 @@ */ import path from 'path'; -import { databaseTypes, searchEngineTypes } from '../../../jdl/jhipster/index.js'; +import { databaseTypes, searchEngineTypes } from '../../../lib/jhipster/index.js'; -import { isReservedTableName } from '../../../jdl/jhipster/reserved-keywords.js'; +import { isReservedTableName } from '../../../lib/jhipster/reserved-keywords.js'; import { mutateData, normalizePathEnd } from '../../base/support/index.js'; import { formatDocAsApiDescription, formatDocAsJavaDoc } from '../../java/support/doc.js'; import { hibernateSnakeCase } from './string.js'; @@ -109,7 +109,7 @@ export function preparePostEntityServerDerivedProperties(entity) { entity.uniqueEnums[field.fieldType] = field.fieldType; } }); - if (entity.primaryKey && entity.primaryKey.derived) { + if (entity.primaryKey?.derived) { entity.isUsingMapsId = true; entity.mapsIdAssoc = entity.relationships.find(rel => rel.id); } else { diff --git a/generators/server/support/prepare-field.js b/generators/server/support/prepare-field.ts similarity index 98% rename from generators/server/support/prepare-field.js rename to generators/server/support/prepare-field.ts index acdff7938be3..aabc4aa3364f 100644 --- a/generators/server/support/prepare-field.js +++ b/generators/server/support/prepare-field.ts @@ -19,9 +19,9 @@ import assert from 'assert'; import { snakeCase, upperFirst } from 'lodash-es'; -import { databaseTypes, entityOptions, fieldTypes, reservedKeywords } from '../../../jdl/jhipster/index.js'; +import { databaseTypes, entityOptions, fieldTypes, reservedKeywords } from '../../../lib/jhipster/index.js'; import { formatDocAsApiDescription, formatDocAsJavaDoc } from '../../java/support/doc.js'; -import { mutateData } from '../../base/support/config.js'; +import { mutateData } from '../../../lib/utils/object.js'; import { getUXConstraintName } from './database.js'; import { getJavaValueGeneratorForType } from './templates/field-values.js'; diff --git a/generators/server/support/prepare-relationship.ts b/generators/server/support/prepare-relationship.ts index e30ffc6750df..247506382732 100644 --- a/generators/server/support/prepare-relationship.ts +++ b/generators/server/support/prepare-relationship.ts @@ -1,4 +1,4 @@ -import { mutateData } from '../../base/support/config.js'; +import { mutateData } from '../../../lib/utils/object.js'; import { formatDocAsApiDescription, formatDocAsJavaDoc } from '../../java/support/doc.js'; export function prepareRelationship({ relationship }: { relationship: any; entity: any }) { diff --git a/generators/server/support/relationship.ts b/generators/server/support/relationship.ts index 0641e2734b1c..77d17d23eafa 100644 --- a/generators/server/support/relationship.ts +++ b/generators/server/support/relationship.ts @@ -17,15 +17,15 @@ * limitations under the License. */ -import { JSONEntity } from '../../../jdl/converters/types.js'; import { addOtherRelationship } from '../../base-application/support/index.js'; -import { ValidationResult } from '../../base/api.js'; -import { databaseTypes } from '../../../jdl/index.js'; +import type { ValidationResult } from '../../base/api.js'; +import { databaseTypes } from '../../../lib/jhipster/index.js'; +import type { Entity } from '../../../lib/types/application/entity.js'; +import type { Relationship } from '../../base-application/index.js'; const { NO: NO_DATABASE, SQL, NEO4J } = databaseTypes; -// eslint-disable-next-line import/prefer-default-export -export const addEntitiesOtherRelationships = (entities: JSONEntity[]): ValidationResult => { +export const addEntitiesOtherRelationships = (entities: Entity[]): ValidationResult => { const result: { warning: string[] } = { warning: [] }; for (const entity of entities.filter(entity => !entity.builtIn)) { for (const relationship of entity.relationships ?? []) { @@ -43,7 +43,7 @@ export const addEntitiesOtherRelationships = (entities: JSONEntity[]): Validatio `Ignoring '${entity.name}' definitions as it is using a built-in Entity '${relationship.otherEntityName}': 'otherEntityRelationshipName' is set with value '${relationship.otherEntityRelationshipName}' at relationship '${relationship.relationshipName}' but no back-reference was found`, ); } else { - relationship.otherRelationship = addOtherRelationship(entity, relationship.otherEntity, relationship); + relationship.otherRelationship = addOtherRelationship(entity, relationship.otherEntity as Entity, relationship) as Relationship; } } } diff --git a/generators/server/support/spring-factories.spec.ts b/generators/server/support/spring-factories.spec.ts index 23c3a35970de..60d15965585c 100644 --- a/generators/server/support/spring-factories.spec.ts +++ b/generators/server/support/spring-factories.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { addSpringFactory } from './spring-factories.js'; describe('generator - server - support - spring-factories', () => { diff --git a/generators/server/support/spring-factories.ts b/generators/server/support/spring-factories.ts index 438d6df0ce94..0213fd914dd1 100644 --- a/generators/server/support/spring-factories.ts +++ b/generators/server/support/spring-factories.ts @@ -1,6 +1,5 @@ import properties from 'dot-properties'; -// eslint-disable-next-line import/prefer-default-export export const addSpringFactory = ({ key, value }) => content => { diff --git a/generators/server/support/string.spec.ts b/generators/server/support/string.spec.ts index 4870d5d229d3..c8a1208498fe 100644 --- a/generators/server/support/string.spec.ts +++ b/generators/server/support/string.spec.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from 'esmocha'; +import { describe, expect, it } from 'esmocha'; import { hibernateSnakeCase } from './string.js'; describe('generator - server - support - string', () => { diff --git a/generators/server/support/string.ts b/generators/server/support/string.ts index e958d8870c01..919ddc5a4384 100644 --- a/generators/server/support/string.ts +++ b/generators/server/support/string.ts @@ -24,7 +24,7 @@ * @see org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy * @returns hibernate SnakeCase in JHipster preferred style */ -// eslint-disable-next-line import/prefer-default-export + export function hibernateSnakeCase(value: string): string { let res = ''; if (value) { diff --git a/generators/server/support/templates/field-values.js b/generators/server/support/templates/field-values.ts similarity index 97% rename from generators/server/support/templates/field-values.js rename to generators/server/support/templates/field-values.ts index 3439e2f35ae0..65a56a9d3460 100644 --- a/generators/server/support/templates/field-values.js +++ b/generators/server/support/templates/field-values.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { fieldTypes, databaseTypes } from '../../../../jdl/jhipster/index.js'; +import { databaseTypes, fieldTypes } from '../../../../lib/jhipster/index.js'; const dbTypes = fieldTypes; const { STRING, UUID, LONG, INTEGER } = dbTypes.CommonDBTypes; diff --git a/generators/server/support/update-languages.ts b/generators/server/support/update-languages.ts index b4d67bb034aa..71be0fbdf80f 100644 --- a/generators/server/support/update-languages.ts +++ b/generators/server/support/update-languages.ts @@ -17,17 +17,14 @@ * limitations under the License. */ -import type BaseGenerator from '../../base/index.js'; -import { type SpringBootApplication } from '../types.js'; - -type UpdateServerLanguagesTaskParam = { application: SpringBootApplication & { enableTranslation: true }; control: any }; +import { asPostWritingTask } from '../../base-application/support/task-type-inference.js'; /** * Update Languages In MailServiceIT * * @param application */ -export function updateLanguagesInMailServiceITTask(this: BaseGenerator, { application, control }: UpdateServerLanguagesTaskParam) { +export const updateLanguagesInMailServiceITTask = asPostWritingTask(function updateLanguagesInMailServiceITTask({ application, control }) { const { javaPackageTestDir, languagesDefinition } = application; const { ignoreNeedlesError: ignoreNonExisting } = control; let newContent = 'private static final String[] languages = {\n'; @@ -39,8 +36,8 @@ export function updateLanguagesInMailServiceITTask(this: BaseGenerator, { applic this.editFile(`${javaPackageTestDir}/service/MailServiceIT.java`, { ignoreNonExisting }, content => content.replace(/private.*static.*String.*languages.*\{([^}]*jhipster-needle-i18n-language-constant[^}]*)\};/g, newContent), ); -} +}); -export default function updateLanguagesTask(this: BaseGenerator, taskParam: UpdateServerLanguagesTaskParam) { +export default asPostWritingTask(function updateLanguagesTask(this, taskParam) { updateLanguagesInMailServiceITTask.call(this, taskParam); -} +}); diff --git a/generators/server/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorIT_reactive.java.ejs b/generators/server/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorIT_reactive.java.ejs deleted file mode 100644 index 9bde4032e725..000000000000 --- a/generators/server/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorIT_reactive.java.ejs +++ /dev/null @@ -1,161 +0,0 @@ -<%# - Copyright 2013-2024 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. --%> -package <%= packageName %>.web.rest.errors; - -import <%= packageName %>.IntegrationTest; -import org.hamcrest.core.AnyOf; -import org.hamcrest.core.IsEqual; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.test.context.support.WithMockUser; -<%_ if (authenticationUsesCsrf) { _%> -import org.junit.jupiter.api.BeforeEach; - -<%_ } _%> -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.test.web.reactive.server.WebTestClient; -<%_ if (authenticationUsesCsrf) { _%> - -import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf; -<%_ } _%> - -/** - * Integration tests {@link ExceptionTranslator} controller advice. - */ -@WithMockUser -@AutoConfigureWebTestClient(timeout = IntegrationTest.DEFAULT_TIMEOUT) -@IntegrationTest -class ExceptionTranslatorIT { - - @Autowired - private WebTestClient webTestClient; -<%_ if (authenticationUsesCsrf) { _%> - - @BeforeEach - public void setupCsrf() { - webTestClient = webTestClient.mutateWith(csrf()); - } -<%_ } _%> -<%_ if (!databaseTypeNo && !databaseTypeCassandra) { _%> - - @Test - void testConcurrencyFailure() { - webTestClient.get().uri("/api/exception-translator-test/concurrency-failure") - .exchange() - .expectStatus().isEqualTo(HttpStatus.CONFLICT) - .expectHeader().contentType(MediaType.APPLICATION_PROBLEM_JSON) - .expectBody() - .jsonPath("$.message").isEqualTo(ErrorConstants.ERR_CONCURRENCY_FAILURE); - } -<%_ } _%> - - @Test - void testMethodArgumentNotValid() { - webTestClient.post().uri("/api/exception-translator-test/method-argument") - .contentType(MediaType.APPLICATION_JSON) - .bodyValue("{}") - .exchange() - .expectHeader().contentType(MediaType.APPLICATION_PROBLEM_JSON) - .expectBody() - .jsonPath("$.message").isEqualTo(ErrorConstants.ERR_VALIDATION) - .jsonPath("$.fieldErrors.[0].objectName").isEqualTo("test") - .jsonPath("$.fieldErrors.[0].field").isEqualTo("test") - .jsonPath("$.fieldErrors.[0].message").isEqualTo("must not be null"); - } - - @Test - void testMissingRequestPart() { - webTestClient.get().uri("/api/exception-translator-test/missing-servlet-request-part") - .exchange() - .expectStatus().isBadRequest() - .expectHeader().contentType(MediaType.APPLICATION_PROBLEM_JSON) - .expectBody() - .jsonPath("$.message").isEqualTo("error.http.400"); - } - - @Test - void testMissingRequestParameter() { - webTestClient.get().uri("/api/exception-translator-test/missing-servlet-request-parameter") - .exchange() - .expectStatus().isBadRequest() - .expectHeader().contentType(MediaType.APPLICATION_PROBLEM_JSON) - .expectBody() - .jsonPath("$.message").isEqualTo("error.http.400"); - } - - @Test - void testAccessDenied() { - webTestClient.get().uri("/api/exception-translator-test/access-denied") - .exchange() - .expectStatus().isForbidden() - .expectHeader().contentType(MediaType.APPLICATION_PROBLEM_JSON) - .expectBody() - .jsonPath("$.message").isEqualTo("error.http.403") - .jsonPath("$.detail").isEqualTo("test access denied!"); - } - - @Test - void testUnauthorized() { - webTestClient.get().uri("/api/exception-translator-test/unauthorized") - .exchange() - .expectStatus().isUnauthorized() - .expectHeader().contentType(MediaType.APPLICATION_PROBLEM_JSON) - .expectBody() - .jsonPath("$.message").isEqualTo("error.http.401") - .jsonPath("$.path").isEqualTo("/api/exception-translator-test/unauthorized") - .jsonPath("$.detail") - .value(AnyOf.anyOf(IsEqual.equalTo("test authentication failed!"), IsEqual.equalTo("Invalid credentials"))); - } - - @Test - void testMethodNotSupported() { - webTestClient.post().uri("/api/exception-translator-test/access-denied") - .exchange() - .expectStatus().isEqualTo(HttpStatus.METHOD_NOT_ALLOWED) - .expectHeader().contentType(MediaType.APPLICATION_PROBLEM_JSON) - .expectBody() - .jsonPath("$.message").isEqualTo("error.http.405") - .jsonPath("$.detail").isEqualTo("405 METHOD_NOT_ALLOWED \"Request method 'POST' is not supported.\""); - } - - @Test - void testExceptionWithResponseStatus() { - webTestClient.get().uri("/api/exception-translator-test/response-status") - .exchange() - .expectStatus().isBadRequest() - .expectHeader().contentType(MediaType.APPLICATION_PROBLEM_JSON) - .expectBody() - .jsonPath("$.message").isEqualTo("error.http.400") - .jsonPath("$.title").isEqualTo("test response status"); - } - - @Test - void testInternalServerError() { - webTestClient.get().uri("/api/exception-translator-test/internal-server-error") - .exchange() - .expectHeader().contentType(MediaType.APPLICATION_PROBLEM_JSON) - .expectBody() - .jsonPath("$.message").isEqualTo("error.http.500") - .jsonPath("$.title").isEqualTo("Internal Server Error"); - } - -} diff --git a/generators/server/types.d.ts b/generators/server/types.d.ts index f930b7d8e130..9aa171611c4c 100644 --- a/generators/server/types.d.ts +++ b/generators/server/types.d.ts @@ -1,13 +1,13 @@ -import { JavaApplication, JavaSourceType } from '../java/types.js'; -import { GradleSourceType } from '../gradle/types.js'; -import { MavenSourceType } from '../maven/types.js'; -import { LiquibaseSourceType } from '../liquibase/types.js'; -import { SpringCacheSourceType } from '../spring-cache/types.js'; -import type { DeterministicOptionWithDerivedProperties, OptionWithDerivedProperties } from '../base-application/application-options.js'; -import { GatewayApplication } from '../spring-cloud/generators/gateway/types.ts'; -import { JavaAnnotation } from '../java/support/add-java-annotation.ts'; -import { ApplicationPropertiesNeedles } from './support/needles.ts'; -import { MessageBrokerApplicationType } from './options/message-broker.js'; +import type { PackageJson } from 'type-fest'; +import type { JavaApplication, JavaSourceType } from '../java/types.js'; +import type { GradleSourceType } from '../gradle/types.js'; +import type { MavenSourceType } from '../maven/types.js'; +import type { LiquibaseSourceType } from '../liquibase/types.js'; +import type { SpringCacheSourceType } from '../spring-cache/types.js'; +import type { OptionWithDerivedProperties } from '../base-application/application-options.js'; +import type { GatewayApplication } from '../spring-cloud/generators/gateway/types.js'; +import type { JavaAnnotation } from '../java/support/add-java-annotation.ts'; +import type { ApplicationPropertiesNeedles } from './support/needles.ts'; export type SpringEntity = { /* Generate entity's Entity */ @@ -34,6 +34,12 @@ export type SpringBootSourceType = JavaSourceType & addAllowBlockingCallsInside?({ classPath, method }: { classPath: string; method: string }): void; addApplicationPropertiesContent?(content: ApplicationPropertiesNeedles): void; addApplicationPropertiesProperty?({ propertyName, propertyType }: { propertyName: string; propertyType: string }): void; + addNativeHint?(hints: { + advanced?: string[]; + declaredConstructors?: string[]; + resources?: string[]; + publicConstructors?: string[]; + }): void; }; type CacheProviderApplication = OptionWithDerivedProperties< @@ -54,6 +60,8 @@ export type LiquibaseApplication = { liquibaseDefaultSchemaName: string; }; +/* +Deterministic option causes types to be too complex type DatabaseTypeSqlApplication = ( | ReactiveApplication | (ImperativeApplication & { @@ -64,13 +72,27 @@ type DatabaseTypeSqlApplication = ( prodDatabaseType: string; devDatabaseTypeMysql: boolean; } & LiquibaseApplication; - + */ +type DatabaseTypeSqlApplication = { + enableHibernateCache: boolean; +} & { + devDatabaseType: string; + prodDatabaseType: string; + devDatabaseTypeMysql: boolean; +} & LiquibaseApplication; +/* +Deterministic option causes types to be too complex type DatabaseTypeApplication = DeterministicOptionWithDerivedProperties< 'databaseType', ['sql', 'no', 'cassandra', 'couchbase', 'mongodb', 'neo4j'], [DatabaseTypeSqlApplication] >; +*/ +type DatabaseTypeApplication = DatabaseTypeSqlApplication & + OptionWithDerivedProperties<'databaseType', ['sql', 'no', 'cassandra', 'couchbase', 'mongodb', 'neo4j']>; +/* +Deterministic option causes types to be too complex type BuildToolApplication = DeterministicOptionWithDerivedProperties< 'buildTool', ['maven', 'gradle'], @@ -81,20 +103,28 @@ type BuildToolApplication = DeterministicOptionWithDerivedProperties< }, ] >; +*/ +type BuildToolApplication = OptionWithDerivedProperties<'buildTool', ['maven', 'gradle']> & { + enableGradleEnterprise: boolean; +}; type SearchEngine = { searchEngine: string; }; +/* +Deterministic option causes types to be too complex type ApplicationNature = (ImperativeApplication & CacheProviderApplication) | ReactiveApplication; +*/ +type ApplicationNature = { reactive: boolean } & CacheProviderApplication; export type SpringBootApplication = JavaApplication & ApplicationNature & BuildToolApplication & SearchEngine & DatabaseTypeApplication & - GatewayApplication & - MessageBrokerApplicationType & { + GatewayApplication & { + jhipsterPackageJson: PackageJson; jhipsterDependenciesVersion: string; springBootDependencies: Record; dockerContainers: Record; @@ -107,6 +137,13 @@ export type SpringBootApplication = JavaApplication & skipCheckLengthOfIdentifier: boolean; imperativeOrReactive: string; + optionalOrMono: string; + optionalOrMonoOfNullable: string; + listOrFlux: string; + optionalOrMonoClassPath: string; + wrapMono: (className: string) => string; + listOrFluxClassPath: string; + generateAuthenticationApi?: boolean; generateInMemoryUserCredentials?: boolean; diff --git a/generators/spring-boot/cleanup-oauth2.ts b/generators/spring-boot/cleanup-oauth2.ts index 81dfe4e99055..51bf13e88745 100644 --- a/generators/spring-boot/cleanup-oauth2.ts +++ b/generators/spring-boot/cleanup-oauth2.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { asWritingTask } from '../base-application/support/task-type-inference.js'; +import { asWritingTask } from '../base-application/support/index.js'; /** * Removes server files that where generated in previous JHipster versions and therefore diff --git a/generators/spring-boot/cleanup.ts b/generators/spring-boot/cleanup.ts index e65e9d56688e..9303515105f3 100644 --- a/generators/spring-boot/cleanup.ts +++ b/generators/spring-boot/cleanup.ts @@ -18,14 +18,14 @@ */ import { JAVA_DOCKER_DIR } from '../generator-constants.js'; -import { asWritingTask } from '../base-application/support/task-type-inference.js'; +import { asWritingTask } from '../base-application/support/index.js'; import cleanupOauth2 from './cleanup-oauth2.js'; /** * Removes server files that where generated in previous JHipster versions and therefore * need to be removed. */ -export default asWritingTask(function cleanupTask(this, taskParam) { +export default asWritingTask(async function cleanupTask(this, taskParam) { const { application, control } = taskParam; if (application.authenticationTypeOauth2) { cleanupOauth2.call(this, taskParam); @@ -209,7 +209,7 @@ export default asWritingTask(function cleanupTask(this, taskParam) { this.removeFile(`${application.javaPackageSrcDir}config/LocaleConfiguration.java`); } - control.cleanupFiles({ + await control.cleanupFiles({ '8.6.1': [[application.authenticationTypeOauth2!, `${application.javaPackageSrcDir}security/oauth2/JwtGrantedAuthorityConverter.java`]], }); }); diff --git a/generators/spring-boot/command.ts b/generators/spring-boot/command.ts index 13ea15eb5396..65090039953f 100644 --- a/generators/spring-boot/command.ts +++ b/generators/spring-boot/command.ts @@ -17,15 +17,17 @@ * limitations under the License. */ import chalk from 'chalk'; -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_JAVA, GENERATOR_LIQUIBASE, GENERATOR_SPRING_DATA_RELATIONAL } from '../generator-list.js'; import { createBase64Secret, createSecret } from '../base/support/secret.js'; -import { authenticationTypes, applicationTypes } from '../../jdl/index.js'; +import { applicationTypes, authenticationTypes } from '../../lib/jhipster/index.js'; const { OAUTH2, SESSION, JWT } = authenticationTypes; const { GATEWAY, MICROSERVICE } = applicationTypes; -const command: JHipsterCommandDefinition = { +const ALPHANUMERIC_PATTERN = /^[A-Za-z][A-Za-z0-9]*$/; + +const command = { options: { fakeKeytool: { description: 'Add a fake certificate store file for test purposes', @@ -46,6 +48,7 @@ const command: JHipsterCommandDefinition = { type: 'confirm', message: 'Do you want to make it reactive with Spring WebFlux?', }), + scope: 'storage', }, serverPort: { prompt: gen => ({ @@ -61,6 +64,7 @@ const command: JHipsterCommandDefinition = { gen.jhipsterConfig.serverPort = 8080 + gen.jhipsterConfig.applicationIndex; } }, + scope: 'storage', }, serviceDiscoveryType: { cli: { @@ -78,6 +82,15 @@ const command: JHipsterCommandDefinition = { { value: 'eureka', name: 'JHipster Registry (legacy, uses Eureka, provides Spring Cloud Config support)' }, { value: 'no', name: 'No service discovery' }, ], + scope: 'storage', + }, + jwtSecretKey: { + cli: { + type: String, + env: 'JHI_JWT_SECRET_KEY', + hide: true, + }, + scope: 'storage', }, authenticationType: { cli: { @@ -112,6 +125,7 @@ const command: JHipsterCommandDefinition = { gen.jhipsterConfig.jwtSecretKey = createBase64Secret(64, gen.options.reproducibleTests); } }, + scope: 'storage', }, feignClient: { description: 'Generate a feign client', @@ -125,7 +139,12 @@ const command: JHipsterCommandDefinition = { [MICROSERVICE].includes(gen.jhipsterConfigWithDefaults.applicationType) && (reactive ?? gen.jhipsterConfigWithDefaults.reactive) === false, }), + jdl: { + type: 'boolean', + tokenType: 'BOOLEAN', + }, default: false, + scope: 'storage', }, syncUserWithIdp: { description: 'Allow relationships with User for oauth2 applications', @@ -137,6 +156,10 @@ const command: JHipsterCommandDefinition = { message: 'Do you want to allow relationships with User entity?', when: ({ authenticationType }) => (authenticationType ?? gen.jhipsterConfigWithDefaults.authenticationType) === 'oauth2', }), + jdl: { + type: 'boolean', + tokenType: 'BOOLEAN', + }, configure: gen => { if (gen.jhipsterConfig.syncUserWithIdp === undefined && gen.jhipsterConfigWithDefaults.authenticationType === 'oauth2') { if (gen.isJhipsterVersionLessThan('8.1.1')) { @@ -146,6 +169,7 @@ const command: JHipsterCommandDefinition = { throw new Error('syncUserWithIdp is only supported with authenticationType oauth2'); } }, + scope: 'storage', }, defaultPackaging: { description: 'Default packaging for the application', @@ -162,8 +186,53 @@ const command: JHipsterCommandDefinition = { } }, }, + databaseType: { + cli: { + type: String, + hide: true, + }, + choices: ['sql', 'mongodb', 'couchbase', 'cassandra', 'neo4j', 'no'], + scope: 'storage', + }, + messageBroker: { + description: 'message broker', + cli: { + type: String, + }, + jdl: { + type: 'string', + tokenType: 'NAME', + tokenValuePattern: ALPHANUMERIC_PATTERN, + }, + choices: ['kafka', 'pulsar', 'no'], + scope: 'storage', + }, + databaseMigration: { + description: 'Database migration', + cli: { + type: String, + }, + jdl: { + type: 'string', + tokenType: 'NAME', + tokenValuePattern: ALPHANUMERIC_PATTERN, + }, + choices: ['liquibase'], + scope: 'storage', + }, + graalvmSupport: { + description: 'Experimental GraalVM Native support', + cli: { + type: Boolean, + }, + jdl: { + type: 'boolean', + tokenType: 'BOOLEAN', + }, + scope: 'storage', + }, }, - import: [GENERATOR_JAVA, GENERATOR_LIQUIBASE, GENERATOR_SPRING_DATA_RELATIONAL], -}; + import: [GENERATOR_JAVA, GENERATOR_LIQUIBASE, GENERATOR_SPRING_DATA_RELATIONAL, 'jhipster:spring-cloud:gateway'], +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/spring-boot/entity-cleanup.js b/generators/spring-boot/entity-cleanup.ts similarity index 75% rename from generators/spring-boot/entity-cleanup.js rename to generators/spring-boot/entity-cleanup.ts index dd84fb505d01..42a1b42920e4 100644 --- a/generators/spring-boot/entity-cleanup.js +++ b/generators/spring-boot/entity-cleanup.ts @@ -16,6 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import type { ApplicationType } from '../../lib/types/application/application.js'; +import type { Entity } from '../../lib/types/application/entity.js'; +import type CoreGenerator from '../base-core/generator.js'; + /** * Removes server files that where generated in previous JHipster versions and therefore * need to be removed. @@ -24,11 +28,13 @@ * @param {Object} application * @param {Object} entity */ -// eslint-disable-next-line import/prefer-default-export -export function cleanupOldFiles({ - application: { packageFolder, srcMainJava, srcTestJava, searchEngineElasticsearch }, - entity: { entityClass, entityAbsoluteFolder }, -}) { +export function cleanupOldFiles( + this: CoreGenerator, + { + application: { packageFolder, srcMainJava, srcTestJava, searchEngineElasticsearch }, + entity: { entityClass, entityAbsoluteFolder }, + }: { application: ApplicationType; entity: Entity }, +) { if (this.isJhipsterVersionLessThan('7.6.1')) { if (searchEngineElasticsearch) { this.removeFile(`${srcMainJava}${packageFolder}/repository/search/SortToFieldSortBuilderConverter.java`); diff --git a/generators/spring-boot/entity-files.js b/generators/spring-boot/entity-files.ts similarity index 94% rename from generators/spring-boot/entity-files.js rename to generators/spring-boot/entity-files.ts index a0e3c628fb82..1517704aa8d4 100644 --- a/generators/spring-boot/entity-files.js +++ b/generators/spring-boot/entity-files.ts @@ -19,9 +19,10 @@ import fs from 'fs'; import * as _ from 'lodash-es'; import chalk from 'chalk'; -import { moveToJavaPackageSrcDir, javaMainPackageTemplatesBlock, javaTestPackageTemplatesBlock } from '../java/support/index.js'; +import { javaMainPackageTemplatesBlock, javaTestPackageTemplatesBlock, moveToJavaPackageSrcDir } from '../java/support/index.js'; import { SERVER_TEST_SRC_DIR } from '../generator-constants.js'; -import { databaseTypes, entityOptions } from '../../jdl/jhipster/index.js'; +import { databaseTypes, entityOptions } from '../../lib/jhipster/index.js'; +import { asWritingEntitiesTask } from '../base-application/support/task-type-inference.js'; import { cleanupOldFiles } from './entity-cleanup.js'; const { COUCHBASE, MONGODB, NEO4J, SQL } = databaseTypes; @@ -195,13 +196,13 @@ export const serverFiles = { export function writeFiles() { return { - cleanupOldServerFiles({ application, entities }) { + cleanupOldServerFiles: asWritingEntitiesTask(function ({ application, entities }) { for (const entity of entities.filter(entity => !entity.skipServer)) { cleanupOldFiles.call(this, { application, entity }); } - }, + }), - async writeServerFiles({ application, entities }) { + writeServerFiles: asWritingEntitiesTask(async function ({ application, entities }) { const rootTemplatesPath = application.reactive ? ['reactive', '', '../../server/templates/', '../../java/generators/domain/templates/'] : ['', '../../server/templates/', '../../java/generators/domain/templates/']; @@ -220,6 +221,6 @@ export function writeFiles() { }); } } - }, + }), }; } diff --git a/generators/spring-boot/files.ts b/generators/spring-boot/files.ts index c30c1838b75f..df7a95786646 100644 --- a/generators/spring-boot/files.ts +++ b/generators/spring-boot/files.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { SERVER_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR, SERVER_TEST_SRC_DIR, SERVER_TEST_RES_DIR } from '../generator-constants.js'; +import { SERVER_MAIN_RES_DIR, SERVER_MAIN_SRC_DIR, SERVER_TEST_RES_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; import { addSectionsCondition, mergeSections } from '../base/support/index.js'; import { javaMainPackageTemplatesBlock, diff --git a/generators/spring-boot/generator.spec.ts b/generators/spring-boot/generator.spec.ts index db8ba27ba08b..d92a49470906 100644 --- a/generators/spring-boot/generator.spec.ts +++ b/generators/spring-boot/generator.spec.ts @@ -1,9 +1,9 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { defaultHelpers as helpers, runResult } from '../../testing/index.js'; -import { shouldSupportFeatures, testBlueprintSupport, checkEnforcements } from '../../test/support/index.js'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; +import { checkEnforcements, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/index.js'; import Generator from '../server/index.js'; import { filterBasicServerGenerators } from '../server/__test-support/index.js'; @@ -26,6 +26,7 @@ describe(`generator - ${generator}`, () => { await helpers .runJHipster(generator) .withJHipsterConfig({ authenticationType: 'jwt' }) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); @@ -39,6 +40,7 @@ describe(`generator - ${generator}`, () => { await helpers .runJHipster(generator) .withJHipsterConfig({ authenticationType: 'oauth2' }) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); diff --git a/generators/spring-boot/generator.ts b/generators/spring-boot/generator.ts index 53c37d95e7a9..c14745b3adc8 100644 --- a/generators/spring-boot/generator.ts +++ b/generators/spring-boot/generator.ts @@ -58,14 +58,15 @@ import { searchEngineTypes, testFrameworkTypes, websocketTypes, -} from '../../jdl/index.js'; +} from '../../lib/jhipster/index.js'; import { getPomVersionProperties, parseMavenPom } from '../maven/support/index.js'; +import type { FieldType } from '../../lib/application/field-types.js'; import { writeFiles as writeEntityFiles } from './entity-files.js'; import cleanupTask from './cleanup.js'; import { serverFiles } from './files.js'; import { askForOptionalItems, askForServerSideOpts, askForServerTestOpts } from './prompts.js'; -const { CAFFEINE, EHCACHE, HAZELCAST, INFINISPAN, MEMCACHED, REDIS, NO: NO_CACHE } = cacheTypes; +const { CAFFEINE, EHCACHE, HAZELCAST, INFINISPAN, MEMCACHED, REDIS } = cacheTypes; const { NO: NO_WEBSOCKET, SPRING_WEBSOCKET } = websocketTypes; const { CASSANDRA, COUCHBASE, MONGODB, NEO4J, SQL } = databaseTypes; const { MICROSERVICE, GATEWAY } = applicationTypes; @@ -103,13 +104,6 @@ export default class SpringBootGenerator extends BaseApplicationGenerator { get configuring() { return this.asConfiguringTaskGroup({ - checks() { - const config = this.jhipsterConfigWithDefaults; - if (config.enableHibernateCache && [NO_CACHE, MEMCACHED].includes(config.cacheProvider)) { - this.log.verboseInfo(`Disabling hibernate cache for cache provider ${config.cacheProvider}`); - this.jhipsterConfig.enableHibernateCache = false; - } - }, feignMigration() { const { reactive, applicationType, feignClient } = this.jhipsterConfigWithDefaults; if (feignClient) { @@ -142,12 +136,11 @@ export default class SpringBootGenerator extends BaseApplicationGenerator { const { applicationType, databaseType, + graalvmSupport, messageBroker, searchEngine, websocket, cacheProvider, - skipClient, - clientFramework, testFrameworks, feignClient, enableSwaggerCodegen, @@ -157,8 +150,8 @@ export default class SpringBootGenerator extends BaseApplicationGenerator { await this.composeWithJHipster('jhipster:java:jib'); await this.composeWithJHipster('jhipster:java:code-quality'); - if (!skipClient && clientFramework !== 'no') { - await this.composeWithJHipster('jhipster:java:node'); + if (graalvmSupport) { + await this.composeWithJHipster('jhipster:java:graalvm'); } if (enableSwaggerCodegen) { @@ -199,7 +192,7 @@ export default class SpringBootGenerator extends BaseApplicationGenerator { if (websocket === SPRING_WEBSOCKET) { await this.composeWithJHipster(GENERATOR_SPRING_WEBSOCKET); } - if ([EHCACHE, CAFFEINE, HAZELCAST, INFINISPAN, MEMCACHED, REDIS].includes(cacheProvider)) { + if ([EHCACHE, CAFFEINE, HAZELCAST, INFINISPAN, MEMCACHED, REDIS].includes(cacheProvider!)) { await this.composeWithJHipster(GENERATOR_SPRING_CACHE); } }, @@ -212,6 +205,13 @@ export default class SpringBootGenerator extends BaseApplicationGenerator { get composingComponent() { return this.asComposingComponentTaskGroup({ + async composing() { + const { clientFramework, skipClient } = this.jhipsterConfigWithDefaults; + if (!skipClient && clientFramework !== 'no') { + // When using prompts, clientFramework will only be known after composing priority. + await this.composeWithJHipster('jhipster:java:node'); + } + }, async composeLanguages() { if (this.jhipsterConfigWithDefaults.enableTranslation) { await this.composeWithJHipster(GENERATOR_LANGUAGES); @@ -345,7 +345,7 @@ public void set${javaBeanCase(propertyName)}(${propertyType} ${propertyName}) { get preparingEachEntityField() { return this.asPreparingEachEntityFieldTaskGroup({ prepareEntity({ field }) { - field.fieldJavaBuildSpecification = getSpecificationBuildForType(field.fieldType); + field.fieldJavaBuildSpecification = getSpecificationBuildForType(field.fieldType as FieldType); field.filterableField = ![TYPE_BYTES, TYPE_BYTE_BUFFER].includes(field.fieldType) && !field.transient; if (field.filterableField) { @@ -397,10 +397,11 @@ public void set${javaBeanCase(propertyName)}(${propertyType} ${propertyName}) { } }, prepareEntity({ relationship }) { - if (relationship.otherEntity.embedded) return; + const { primaryKey } = relationship.otherEntity; + if (!primaryKey) return; const { relationshipName, relationshipNameCapitalized } = relationship; - const otherEntityPkField = relationship.otherEntity.primaryKey.fields[0]; + const otherEntityPkField = primaryKey.fields[0]; mutateData(relationship, { propertyJavaFilterName: `${relationshipName}Id`, propertyJavaFilterJavaBeanName: `${relationshipNameCapitalized}Id`, @@ -453,7 +454,7 @@ public void set${javaBeanCase(propertyName)}(${propertyType} ${propertyName}) { async writeFiles({ application }) { return this.writeFiles({ sections: serverFiles, - rootTemplatesPath: ['', '../../server/templates/', '../../java/generators/domain/templates/'], + rootTemplatesPath: ['', '../../java/generators/domain/templates/'], context: application, }); }, @@ -489,29 +490,32 @@ public void set${javaBeanCase(propertyName)}(${propertyType} ${propertyName}) { application; const { serviceDiscoveryAny } = application as any; - if (application.buildToolMaven) { - source.addMavenProperty?.({ - property: 'spring-boot.version', - // eslint-disable-next-line no-template-curly-in-string - value: '${project.parent.version}', - }); - } - - source.addJavaDependencies?.([ - { groupId: 'tech.jhipster', artifactId: 'jhipster-framework', version: jhipsterDependenciesVersion! }, - ]); - - if (applicationTypeGateway || applicationTypeMicroservice || serviceDiscoveryAny || messageBrokerAny) { - source.addJavaDependencies?.([ - { - groupId: 'org.springframework.cloud', - artifactId: 'spring-cloud-dependencies', - type: 'pom', - scope: 'import', - version: javaDependencies!['spring-cloud-dependencies'], + source.addJavaDefinitions?.( + { + dependencies: [{ groupId: 'tech.jhipster', artifactId: 'jhipster-framework', version: jhipsterDependenciesVersion! }], + mavenDefinition: { + properties: [ + { + property: 'spring-boot.version', + // eslint-disable-next-line no-template-curly-in-string + value: '${project.parent.version}', + }, + ], }, - ]); - } + }, + { + condition: applicationTypeGateway || applicationTypeMicroservice || serviceDiscoveryAny || messageBrokerAny, + dependencies: [ + { + groupId: 'org.springframework.cloud', + artifactId: 'spring-cloud-dependencies', + type: 'pom', + scope: 'import', + version: javaDependencies!['spring-cloud-dependencies'], + }, + ], + }, + ); }, addSpringdoc({ application, source }) { const springdocDependency = `springdoc-openapi-starter-${application.reactive ? 'webflux' : 'webmvc'}-api`; @@ -568,6 +572,28 @@ public void set${javaBeanCase(propertyName)}(${propertyType} ${propertyName}) { ]); } }, + addSpringBootCompose({ application, source }) { + source.addLogbackMainLog!({ name: 'org.springframework.boot.docker', level: 'WARN' }); + + const dockerComposeArtifact = { groupId: 'org.springframework.boot', artifactId: 'spring-boot-docker-compose' }; + if (application.buildToolGradle) { + source.addGradleDependency!({ ...dockerComposeArtifact, scope: 'developmentOnly' }); + } else if (application.buildToolMaven) { + // Add dependency to profile due to jib issue https://github.com/GoogleContainerTools/jib-extensions/issues/158 + source.addMavenDefinition!({ + profiles: [ + { + id: 'docker-compose', + content: ` + + true + `, + }, + ], + }); + source.addMavenDependency!({ inProfile: 'docker-compose', ...dockerComposeArtifact, optional: true }); + } + }, }); } diff --git a/generators/spring-boot/prompts.js b/generators/spring-boot/prompts.ts similarity index 50% rename from generators/spring-boot/prompts.js rename to generators/spring-boot/prompts.ts index 25d70ed78ce9..59415cbc86d3 100644 --- a/generators/spring-boot/prompts.js +++ b/generators/spring-boot/prompts.ts @@ -24,28 +24,19 @@ import { applicationOptions, applicationTypes, authenticationTypes, - databaseTypes, cacheTypes, + databaseTypes, testFrameworkTypes, -} from '../../jdl/jhipster/index.js'; -import { MESSAGE_BROKER } from '../server/options/index.js'; +} from '../../lib/jhipster/index.js'; import { R2DBC_DB_OPTIONS, SQL_DB_OPTIONS } from '../server/support/database.js'; +import type CoreGenerator from '../base-core/generator.js'; const { OptionNames } = applicationOptions; const { GATEWAY, MONOLITH } = applicationTypes; const { CAFFEINE, EHCACHE, HAZELCAST, INFINISPAN, MEMCACHED, REDIS } = cacheTypes; const { OAUTH2 } = authenticationTypes; const { CASSANDRA, H2_DISK, H2_MEMORY, MONGODB, NEO4J, SQL, COUCHBASE } = databaseTypes; -const { - CACHE_PROVIDER, - DATABASE_TYPE, - DEV_DATABASE_TYPE, - PROD_DATABASE_TYPE, - SERVICE_DISCOVERY_TYPE, - WEBSOCKET, - SEARCH_ENGINE, - ENABLE_SWAGGER_CODEGEN, -} = OptionNames; +const { SERVICE_DISCOVERY_TYPE, WEBSOCKET, SEARCH_ENGINE, ENABLE_SWAGGER_CODEGEN } = OptionNames; const NO_DATABASE = databaseTypes.NO; const NO_CACHE_PROVIDER = cacheTypes.NO; const { GATLING, CUCUMBER } = testFrameworkTypes; @@ -58,7 +49,7 @@ const { GATLING, CUCUMBER } = testFrameworkTypes; * @returns {boolean} true if option is in array and is set to 'true' */ const getOptionFromArray = (array, option) => { - let optionValue = false; + let optionValue: any = false; array.forEach(value => { if (includes(value, option)) { optionValue = value.split(':')[1]; @@ -68,138 +59,140 @@ const getOptionFromArray = (array, option) => { return optionValue; }; -export async function askForServerSideOpts({ control }) { +export async function askForServerSideOpts(this: CoreGenerator, { control }) { if (control.existingProject && !this.options.askAnswered) return; - const { applicationType } = this.jhipsterConfigWithDefaults; - const prompts = [ - { - type: 'list', - name: DATABASE_TYPE, - message: `Which ${chalk.yellow('*type*')} of database would you like to use?`, - choices: answers => { - const opts = []; - if (!answers.reactive) { + const { applicationType, authenticationType, reactive } = this.jhipsterConfigWithDefaults; + + await this.prompt( + [ + { + type: 'list', + name: 'databaseType', + message: `Which ${chalk.yellow('*type*')} of database would you like to use?`, + choices: () => { + const opts: any[] = []; + if (!reactive) { + opts.push({ + value: SQL, + name: 'SQL (H2, PostgreSQL, MySQL, MariaDB, Oracle, MSSQL)', + }); + } else { + opts.push({ + value: SQL, + name: 'SQL (H2, PostgreSQL, MySQL, MariaDB, MSSQL)', + }); + } + opts.push({ + value: MONGODB, + name: 'MongoDB', + }); + if (authenticationType !== OAUTH2) { + opts.push({ + value: CASSANDRA, + name: 'Cassandra', + }); + } opts.push({ - value: SQL, - name: 'SQL (H2, PostgreSQL, MySQL, MariaDB, Oracle, MSSQL)', + value: 'couchbase', + name: '[BETA] Couchbase', }); - } else { opts.push({ - value: SQL, - name: 'SQL (H2, PostgreSQL, MySQL, MariaDB, MSSQL)', + value: NEO4J, + name: '[BETA] Neo4j', }); - } - opts.push({ - value: MONGODB, - name: 'MongoDB', - }); - if (answers.authenticationType !== OAUTH2) { opts.push({ - value: CASSANDRA, - name: 'Cassandra', + value: NO_DATABASE, + name: 'No database', }); - } - opts.push({ - value: 'couchbase', - name: '[BETA] Couchbase', - }); - opts.push({ - value: NEO4J, - name: '[BETA] Neo4j', - }); - opts.push({ - value: NO_DATABASE, - name: 'No database', - }); - return opts; + return opts; + }, + default: this.jhipsterConfigWithDefaults.databaseType, }, - default: this.jhipsterConfigWithDefaults.databaseType, - }, - { - when: response => response.databaseType === SQL, - type: 'list', - name: PROD_DATABASE_TYPE, - message: `Which ${chalk.yellow('*production*')} database would you like to use?`, - choices: answers => (answers.reactive ? R2DBC_DB_OPTIONS : SQL_DB_OPTIONS), - default: this.jhipsterConfigWithDefaults.prodDatabaseType, - }, - { - when: response => response.databaseType === SQL, - type: 'list', - name: DEV_DATABASE_TYPE, - message: `Which ${chalk.yellow('*development*')} database would you like to use?`, - choices: response => - [SQL_DB_OPTIONS.find(it => it.value === response.prodDatabaseType)].concat([ + { + when: response => response.databaseType === SQL, + type: 'list', + name: 'prodDatabaseType', + message: `Which ${chalk.yellow('*production*')} database would you like to use?`, + choices: reactive ? R2DBC_DB_OPTIONS : SQL_DB_OPTIONS, + default: this.jhipsterConfigWithDefaults.prodDatabaseType, + }, + { + when: response => response.databaseType === SQL, + type: 'list', + name: 'devDatabaseType', + message: `Which ${chalk.yellow('*development*')} database would you like to use?`, + choices: response => + [SQL_DB_OPTIONS.find(it => it.value === response.prodDatabaseType)].concat([ + { + value: H2_DISK, + name: 'H2 with disk-based persistence', + }, + { + value: H2_MEMORY, + name: 'H2 with in-memory persistence', + }, + ]) as any, + default: this.jhipsterConfigWithDefaults.devDatabaseType, + }, + { + when: !reactive, + type: 'list', + name: 'cacheProvider', + message: 'Which cache do you want to use? (Spring cache abstraction)', + choices: [ { - value: H2_DISK, - name: 'H2 with disk-based persistence', + value: EHCACHE, + name: 'Ehcache (local cache, for a single node)', }, { - value: H2_MEMORY, - name: 'H2 with in-memory persistence', + value: CAFFEINE, + name: 'Caffeine (local cache, for a single node)', }, - ]), - default: this.jhipsterConfigWithDefaults.devDatabaseType, - }, - { - when: answers => !answers.reactive, - type: 'list', - name: CACHE_PROVIDER, - message: 'Which cache do you want to use? (Spring cache abstraction)', - choices: [ - { - value: EHCACHE, - name: 'Ehcache (local cache, for a single node)', - }, - { - value: CAFFEINE, - name: 'Caffeine (local cache, for a single node)', - }, - { - value: HAZELCAST, - name: 'Hazelcast (distributed cache, for multiple nodes, supports rate-limiting for gateway applications)', - }, - { - value: INFINISPAN, - name: 'Infinispan (hybrid cache, for multiple nodes)', - }, - { - value: MEMCACHED, - name: 'Memcached (distributed cache) - Warning, when using an SQL database, this will disable the Hibernate 2nd level cache!', - }, - { - value: REDIS, - name: 'Redis (distributed cache)', - }, - { - value: NO_CACHE_PROVIDER, - name: 'No cache - Warning, when using an SQL database, this will disable the Hibernate 2nd level cache!', - }, - ], - default: this.jhipsterConfigWithDefaults.cacheProvider, - }, - { - when: answers => - ((answers.cacheProvider !== NO_CACHE_PROVIDER && answers.cacheProvider !== MEMCACHED) || applicationType === GATEWAY) && - answers.databaseType === SQL && - !answers.reactive, - type: 'confirm', - name: 'enableHibernateCache', - message: 'Do you want to use Hibernate 2nd level cache?', - default: this.jhipsterConfigWithDefaults.enableHibernateCache, - }, - ]; - - await this.prompt(prompts, this.config); + { + value: HAZELCAST, + name: 'Hazelcast (distributed cache, for multiple nodes, supports rate-limiting for gateway applications)', + }, + { + value: INFINISPAN, + name: 'Infinispan (hybrid cache, for multiple nodes)', + }, + { + value: MEMCACHED, + name: 'Memcached (distributed cache) - Warning, when using an SQL database, this will disable the Hibernate 2nd level cache!', + }, + { + value: REDIS, + name: 'Redis (distributed cache)', + }, + { + value: NO_CACHE_PROVIDER, + name: 'No cache - Warning, when using an SQL database, this will disable the Hibernate 2nd level cache!', + }, + ], + default: this.jhipsterConfigWithDefaults.cacheProvider, + }, + { + when: answers => + ((answers.cacheProvider !== NO_CACHE_PROVIDER && answers.cacheProvider !== MEMCACHED) || applicationType === GATEWAY) && + answers.databaseType === SQL && + !reactive, + type: 'confirm', + name: 'enableHibernateCache', + message: 'Do you want to use Hibernate 2nd level cache?', + default: this.jhipsterConfigWithDefaults.enableHibernateCache, + }, + ], + this.config, + ); } -export async function askForOptionalItems({ control }) { +export async function askForOptionalItems(this: CoreGenerator, { control }) { if (control.existingProject && !this.options.askAnswered) return; const { applicationType, reactive, databaseType } = this.jhipsterConfigWithDefaults; - const choices = []; + const choices: any[] = []; const defaultChoice = []; if ([SQL, MONGODB, NEO4J].includes(databaseType)) { choices.push({ @@ -234,20 +227,18 @@ export async function askForOptionalItems({ control }) { value: 'enableSwaggerCodegen:true', }); - const PROMPTS = { - type: 'checkbox', - name: 'serverSideOptions', - message: 'Which other technologies would you like to use?', - choices, - default: defaultChoice, - }; - if (choices.length > 0) { - await this.prompt(PROMPTS).then(answers => { + await this.prompt({ + type: 'checkbox', + name: 'serverSideOptions', + message: 'Which other technologies would you like to use?', + choices, + default: defaultChoice, + }).then(answers => { this.jhipsterConfig.serverSideOptions = answers.serverSideOptions; this.jhipsterConfig.websocket = getOptionFromArray(answers.serverSideOptions, WEBSOCKET); this.jhipsterConfig.searchEngine = getOptionFromArray(answers.serverSideOptions, SEARCH_ENGINE); - this.jhipsterConfig.messageBroker = getOptionFromArray(answers.serverSideOptions, MESSAGE_BROKER); + this.jhipsterConfig.messageBroker = getOptionFromArray(answers.serverSideOptions, 'messageBroker'); this.jhipsterConfig.enableSwaggerCodegen = getOptionFromArray(answers.serverSideOptions, ENABLE_SWAGGER_CODEGEN); // Only set this option if it hasn't been set in a previous question, as it's only optional for monoliths if (!this.jhipsterConfig.serviceDiscoveryType) { @@ -257,7 +248,7 @@ export async function askForOptionalItems({ control }) { } } -export async function askForServerTestOpts({ control }) { +export async function askForServerTestOpts(this: CoreGenerator, { control }) { if (control.existingProject && this.options.askAnswered !== true) return; const answers = await this.prompt([ diff --git a/generators/spring-boot/resources/spring-boot-dependencies.pom b/generators/spring-boot/resources/spring-boot-dependencies.pom index d1bf8c49834a..5ad2940a2c8d 100644 --- a/generators/spring-boot/resources/spring-boot-dependencies.pom +++ b/generators/spring-boot/resources/spring-boot-dependencies.pom @@ -3,7 +3,7 @@ 4.0.0 org.springframework.boot spring-boot-dependencies - 3.3.1 + 3.3.5 pom spring-boot-dependencies Spring Boot Dependencies @@ -25,17 +25,18 @@ https://github.com/spring-projects/spring-boot + - 6.1.2 + 6.1.3 2.0.3 2.33.0 - 1.9.22 + 1.9.22.1 3.25.3 - 4.2.1 - 3.4.0 + 4.2.2 + 3.4.2 6.0.3 3.5.0 - 1.14.17 + 1.14.19 2.6.1.Final 3.1.8 4.18.1 @@ -45,11 +46,11 @@ 3.14.0 1.6 2.12.0 - 3.6.2 + 3.6.3 1.4.0 - 2.8.0 + 2.8.2 11.5.9.0 - 1.1.5 + 1.1.6 10.16.1.1 3.10.8 8.13.4 @@ -58,13 +59,13 @@ 8.0.2 4.0.5 3.0.1 - 22.0 - 4.0.21 + 22.3 + 4.0.23 2.10.1 2.2.224 2.2 5.4.0 - 6.5.2.Final + 6.5.3.Final 8.0.1.Final 5.1.0 2.7.3 @@ -72,10 +73,10 @@ 4.1.5 5.3.1 4.4.16 - 5.2.4 - 15.0.5.Final + 5.2.5 + 15.0.10.Final 2.24 - 2.17.1 + 2.17.2 2.1.3 2.1.1 2.0.1 @@ -86,7 +87,7 @@ 1.1.4 3.1.0 6.0.0 - 3.0.0 + 3.0.2 2.0.1 3.0.2 2.1.1 @@ -98,41 +99,41 @@ 1.1.1 1.1 2.0.0 - 5.0.5.java11 + 5.0.6.java11 3.5.3.Final 2.0.6.1 5.0.2 - 3.1.7 - 4.0.5 - 12.0.10 + 3.1.9 + 4.0.8 + 12.0.14 1.16 - 3.19.10 + 3.19.14 2.9.0 2.5.1 - 1.5.1 + 1.5.3 1.3.1 4.13.2 - 5.10.2 - 3.7.0 - 1.9.24 + 5.10.5 + 3.7.1 + 1.9.25 1.8.1 1.6.3 6.3.2.RELEASE 4.27.0 2.23.1 - 1.5.6 - 1.18.32 + 1.5.11 + 1.18.34 3.3.3 3.1.0 3.7.1 3.3.2 3.13.0 3.6.1 - 3.1.2 + 3.1.3 3.4.1 3.2.5 3.4.1 - 3.1.2 + 3.1.3 3.6.1 3.4.2 3.6.3 @@ -141,64 +142,64 @@ 3.3.1 3.2.5 3.4.0 - 1.13.1 - 1.3.1 + 1.13.6 + 1.3.5 5.11.0 5.0.1 - 12.6.2.jre11 + 12.6.4.jre11 8.3.0 - 0.10.2 + 0.10.3 1.9.22 - 5.21.0 - 4.1.111.Final + 5.25.0 + 4.1.114.Final 4.12.0 1.37.0 21.9.0.0 1.2.0 - 3.1.6 - 42.7.3 + 3.1.7 + 42.7.4 1.2.1 0.16.0 - 3.2.3 - 0.5.6 + 3.2.4 + 0.5.8 2.3.2 5.1.0 1.0.0.RELEASE - 1.2.0 + 1.2.2 1.0.2.RELEASE 1.1.3 - 1.0.1.RELEASE - 1.0.5.RELEASE + 1.0.2.RELEASE + 1.0.7.RELEASE 1.1.5.RELEASE 1.0.0.RELEASE 5.21.0 0.15.0 1.0.4 - 2023.0.7 + 2023.0.11 5.4.0 1.1.3 - 3.1.8 + 3.1.9 3.0.4 4.19.1 4.13.0 - 4.10.2 - 2.0.13 + 4.10.3 + 2.0.16 2.2 - 3.1.6 - 1.3.1 + 3.1.7 + 1.3.3 5.1.2 - 2024.0.1 - 6.1.10 - 1.3.1 - 2.3.0 - 6.3.1 - 3.2.1 - 3.2.4 - 1.1.1 - 3.0.1 - 2.0.6 - 6.3.1 - 3.3.1 + 2024.0.5 + 6.1.14 + 1.3.3 + 2.3.3 + 6.3.5 + 3.2.4 + 3.2.7 + 1.1.5 + 3.0.2 + 2.0.10 + 6.3.4 + 3.3.3 4.0.11 3.45.3.0 1.19.8 @@ -206,38 +207,18 @@ 2.0.1 3.1.2.RELEASE 3.3.0 - 10.1.25 + 10.1.31 6.0.11 - 2.3.13.Final + 2.3.17.Final 2.16.2 0.58 1.6.3 1.1.0 2.9.1 - 3.0.3 + 3.0.4 - - org.apache.activemq - activemq-amqp - ${activemq.version} - - - org.apache.activemq - activemq-blueprint - ${activemq.version} - - - org.apache.activemq - activemq-broker - ${activemq.version} - - - org.apache.activemq - activemq-client - ${activemq.version} - org.apache.activemq activemq-console @@ -249,86 +230,6 @@
- - org.apache.activemq - activemq-http - ${activemq.version} - - - org.apache.activemq - activemq-jaas - ${activemq.version} - - - org.apache.activemq - activemq-jdbc-store - ${activemq.version} - - - org.apache.activemq - activemq-jms-pool - ${activemq.version} - - - org.apache.activemq - activemq-kahadb-store - ${activemq.version} - - - org.apache.activemq - activemq-karaf - ${activemq.version} - - - org.apache.activemq - activemq-log4j-appender - ${activemq.version} - - - org.apache.activemq - activemq-mqtt - ${activemq.version} - - - org.apache.activemq - activemq-openwire-generator - ${activemq.version} - - - org.apache.activemq - activemq-openwire-legacy - ${activemq.version} - - - org.apache.activemq - activemq-osgi - ${activemq.version} - - - org.apache.activemq - activemq-pool - ${activemq.version} - - - org.apache.activemq - activemq-ra - ${activemq.version} - - - org.apache.activemq - activemq-run - ${activemq.version} - - - org.apache.activemq - activemq-runtime-config - ${activemq.version} - - - org.apache.activemq - activemq-shiro - ${activemq.version} - org.apache.activemq activemq-spring @@ -340,16 +241,6 @@ - - org.apache.activemq - activemq-stomp - ${activemq.version} - - - org.apache.activemq - activemq-web - ${activemq.version} - org.eclipse.angus angus-core @@ -1666,367 +1557,367 @@ org.springframework.boot spring-boot - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-test - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-test-autoconfigure - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-testcontainers - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-actuator - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-actuator-autoconfigure - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-autoconfigure - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-autoconfigure-processor - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-buildpack-platform - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-configuration-metadata - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-configuration-processor - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-devtools - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-docker-compose - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-jarmode-tools - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-loader - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-loader-classic - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-loader-tools - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-properties-migrator - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-activemq - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-actuator - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-amqp - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-aop - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-artemis - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-batch - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-cache - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-cassandra - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-cassandra-reactive - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-couchbase - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-couchbase-reactive - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-elasticsearch - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-jdbc - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-jpa - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-ldap - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-mongodb - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-mongodb-reactive - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-r2dbc - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-redis - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-redis-reactive - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-neo4j - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-data-rest - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-freemarker - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-graphql - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-groovy-templates - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-hateoas - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-integration - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-jdbc - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-jersey - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-jetty - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-jooq - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-json - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-log4j2 - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-logging - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-mail - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-mustache - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-oauth2-authorization-server - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-oauth2-client - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-oauth2-resource-server - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-pulsar - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-pulsar-reactive - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-quartz - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-reactor-netty - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-rsocket - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-security - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-test - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-thymeleaf - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-tomcat - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-undertow - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-validation - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-web - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-webflux - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-websocket - 3.3.1 + 3.3.5 org.springframework.boot spring-boot-starter-web-services - 3.3.1 + 3.3.5 com.sun.xml.messaging.saaj @@ -2293,6 +2184,13 @@ yasson ${yasson.version} + + org.apache.activemq + activemq-bom + ${activemq.version} + pom + import + org.apache.activemq artemis-bom @@ -2725,7 +2623,7 @@ org.springframework.boot spring-boot-maven-plugin - 3.3.1 + 3.3.5 org.codehaus.mojo diff --git a/generators/server/templates/.devcontainer/Dockerfile.ejs b/generators/spring-boot/templates/.devcontainer/Dockerfile.ejs similarity index 100% rename from generators/server/templates/.devcontainer/Dockerfile.ejs rename to generators/spring-boot/templates/.devcontainer/Dockerfile.ejs diff --git a/generators/server/templates/.devcontainer/devcontainer.json.ejs b/generators/spring-boot/templates/.devcontainer/devcontainer.json.ejs similarity index 100% rename from generators/server/templates/.devcontainer/devcontainer.json.ejs rename to generators/spring-boot/templates/.devcontainer/devcontainer.json.ejs diff --git a/generators/server/templates/README.md.jhi.spring-boot.ejs b/generators/spring-boot/templates/README.md.jhi.spring-boot.ejs similarity index 93% rename from generators/server/templates/README.md.jhi.spring-boot.ejs rename to generators/spring-boot/templates/README.md.jhi.spring-boot.ejs index 21d73153143b..20910459ff5e 100644 --- a/generators/server/templates/README.md.jhi.spring-boot.ejs +++ b/generators/spring-boot/templates/README.md.jhi.spring-boot.ejs @@ -329,46 +329,52 @@ sonar.password=admin For more information, refer to the [Code quality page][]. -### Using Docker to simplify development (optional) +### Docker Compose support -You can use Docker to improve your JHipster development experience. A number of docker-compose configuration are available in the [src/main/docker](src/main/docker) folder to launch required third party services. +JHipster generates a number of Docker Compose configuration files in the [<%- dockerServicesDir %>](<%- dockerServicesDir %>) folder to launch required third party services. -<%_ if (!databaseTypeNo) { _%> -For example, to start a <%= prodDatabaseType %> database in a docker container, run: +For example, to start required services in Docker containers, run: ``` -docker compose -f src/main/docker/<%= prodDatabaseType ?? databaseType %>.yml up -d +docker compose -f <%- dockerServicesDir %>services.yml up -d ``` -To stop it and remove the container, run: +To stop and remove the containers, run: ``` -docker compose -f src/main/docker/<%= prodDatabaseType ?? databaseType %>.yml down +docker compose -f <%- dockerServicesDir %>services.yml down ``` -<%_ } _%> -You can also fully dockerize your application and all the services that it depends on. -To achieve this, first build a docker image of your app by running: +[Spring Docker Compose Integration](https://docs.spring.io/spring-boot/reference/features/dev-services.html) is enable by default. It's possible to disable it in application.yml: +```yaml +spring: + ... + docker: + compose: + enabled: false ``` + +You can also fully dockerize your application and all the services that it depends on. +To achieve this, first build a Docker image of your app by running: + +```sh npm run java:docker ``` -Or build a arm64 docker image when using an arm64 processor os like MacOS with M1 processor family running: +Or build a arm64 Docker image when using an arm64 processor os like MacOS with M1 processor family running: -``` +```sh npm run java:docker:arm64 ``` Then run: -``` +```sh docker compose -f <%- dockerServicesDir %>app.yml up -d ``` -When running Docker Desktop on MacOS Big Sur or later, consider enabling experimental `Use the new Virtualization framework` for better processing performance ([disk access performance is worse](https://github.com/docker/roadmap/issues/7)). - -For more information refer to [Using Docker and Docker-Compose][], this page also contains information on the docker-compose sub-generator (`jhipster docker-compose`), which is able to generate docker configurations for one or several JHipster applications. +For more information refer to [Using Docker and Docker-Compose][], this page also contains information on the Docker Compose sub-generator (`jhipster docker-compose`), which is able to generate Docker configurations for one or several JHipster applications. ## Continuous Integration (optional) diff --git a/generators/spring-boot/templates/_global_partials_entity_/save_template.ejs b/generators/spring-boot/templates/_global_partials_entity_/save_template.ejs index 8ad11dc9f498..0a1435e7089b 100644 --- a/generators/spring-boot/templates/_global_partials_entity_/save_template.ejs +++ b/generators/spring-boot/templates/_global_partials_entity_/save_template.ejs @@ -33,5 +33,5 @@ <%_ if (dtoMapstruct) { _%> <%- returnDirectly ? 'return' : `${dtoInstance} =` %> <%- entityInstance %>Mapper.toDto(<%- persistInstance %>); <%_ } else if (returnDirectly && searchEngineElasticsearch) { _%> - return <%- entityInstance %>; + return <%- persistInstance %>; <%_ } _%> diff --git a/generators/server/templates/build.gradle.ejs b/generators/spring-boot/templates/build.gradle.ejs similarity index 100% rename from generators/server/templates/build.gradle.ejs rename to generators/spring-boot/templates/build.gradle.ejs index 1aa987efbefb..ae1b71aa4ceb 100644 --- a/generators/server/templates/build.gradle.ejs +++ b/generators/spring-boot/templates/build.gradle.ejs @@ -246,6 +246,7 @@ if (addSpringMilestoneRepository) { _%> implementation "org.springframework.retry:spring-retry" <%_ } _%> testImplementation "org.springframework.security:spring-security-test" + // jhipster-needle-gradle-dependency - JHipster will add additional dependencies here <%_ if (reactive) { _%> OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.getCurrentOperatingSystem(); Architecture arch = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.getCurrentArchitecture(); @@ -257,7 +258,6 @@ if (addSpringMilestoneRepository) { _%> } } <%_ } _%> - // jhipster-needle-gradle-dependency - JHipster will add additional dependencies here } task cleanResources(type: Delete) { diff --git a/generators/server/templates/gradle.properties.ejs b/generators/spring-boot/templates/gradle.properties.ejs similarity index 100% rename from generators/server/templates/gradle.properties.ejs rename to generators/spring-boot/templates/gradle.properties.ejs diff --git a/generators/server/templates/gradle/profile_dev.gradle.ejs b/generators/spring-boot/templates/gradle/profile_dev.gradle.ejs similarity index 76% rename from generators/server/templates/gradle/profile_dev.gradle.ejs rename to generators/spring-boot/templates/gradle/profile_dev.gradle.ejs index 10d386e036f5..c6cffaea7d07 100644 --- a/generators/server/templates/gradle/profile_dev.gradle.ejs +++ b/generators/spring-boot/templates/gradle/profile_dev.gradle.ejs @@ -24,56 +24,12 @@ sourceSets { } } } -<%_ } _%> -<%_ if (databaseTypeSql) { _%> - -configurations { - all { - resolutionStrategy { - <%_ if (prodDatabaseDriver?.r2dbc?.version) { _%> - force "<%- prodDatabaseDriver.r2dbc.groupId %>:<%- prodDatabaseDriver.r2dbc.artifactId %>:<%- prodDatabaseDriver.r2dbc.version %>" - <%_ } _%> - <%_ if (prodDatabaseDriver?.jdbc?.version) { _%> - force "<%- prodDatabaseDriver.jdbc.groupId %>:<%- prodDatabaseDriver.jdbc.artifactId %>:<%- prodDatabaseDriver.jdbc.version %>" - <%_ } _%> - } - } -} +<%_ } _%> dependencies { developmentOnly "org.springframework.boot:spring-boot-devtools" - <%_ if (devDatabaseTypeH2Any && !reactive) { _%> - implementation "com.h2database:h2" - <%_ } _%> - <%_ if (devDatabaseTypeOracle) { _%> - implementation "com.oracle.database.jdbc:ojdbc8" - <%_ } _%> - <%_ if (devDatabaseTypeH2Any && reactive) { _%> - implementation "io.r2dbc:r2dbc-h2" - <%_ } _%> - <%_ if (devDatabaseTypeMariadb || devDatabaseTypeMssql || devDatabaseTypePostgres || devDatabaseTypeMysql) { _%> - <%_ if (reactive) { _%> - implementation "<%- prodDatabaseDriver.r2dbc.groupId %>:<%- prodDatabaseDriver.r2dbc.artifactId %>" - <%_ } _%> - implementation "<%- prodDatabaseDriver.jdbc.groupId %>:<%- prodDatabaseDriver.jdbc.artifactId %>" - <%_ } _%> - <%_ if (prodDatabaseTypeMariadb) { _%> - testImplementation "org.testcontainers:mariadb" - <%_ } _%> - <%_ if (prodDatabaseTypeMssql) { _%> - testImplementation "org.testcontainers:mssqlserver" - <%_ } _%> - <%_ if (prodDatabaseTypeMysql) { _%> - testImplementation "org.testcontainers:mysql" - <%_ } _%> - <%_ if (prodDatabaseTypeOracle) { _%> - testImplementation "org.testcontainers:oracle-xe" - <%_ } _%> - <%_ if (prodDatabaseTypePostgresql) { _%> - testImplementation "org.testcontainers:postgresql" - <%_ } _%> + // jhipster-needle-gradle-dependency - JHipster will add additional dependencies here } -<%_ } _%> ext { springProfiles = "dev" + springProfiles diff --git a/generators/server/templates/gradle/profile_prod.gradle.ejs b/generators/spring-boot/templates/gradle/profile_prod.gradle.ejs similarity index 60% rename from generators/server/templates/gradle/profile_prod.gradle.ejs rename to generators/spring-boot/templates/gradle/profile_prod.gradle.ejs index 7a730c95e673..0f533b7d98a3 100644 --- a/generators/server/templates/gradle/profile_prod.gradle.ejs +++ b/generators/spring-boot/templates/gradle/profile_prod.gradle.ejs @@ -16,55 +16,9 @@ See the License for the specific language governing permissions and limitations under the License. -%> -<%_ if (devDatabaseType !== prodDatabaseType && (devDatabaseTypeMariadb || devDatabaseTypeMssql || devDatabaseTypeMysql || devDatabaseTypePostgres)) { _%> -sourceSets { - test { - java { - exclude '<%= packageFolder %>/config/<% if (devDatabaseTypeMariadb) { %>Mariadb<% } else if (devDatabaseTypeMssql) { %>MsSql<% } else if (devDatabaseTypeMysql) { %>Mysql<% } else if (devDatabaseTypePostgres) { %>PostgreSql<% } %>TestContainer.java' - } - } -} -<%_ } _%> -<%_ if (databaseTypeSql) { _%> - -configurations { - all { - resolutionStrategy { - <%_ if (prodDatabaseDriver?.r2dbc?.version) { _%> - force "<%- prodDatabaseDriver.r2dbc.groupId %>:<%- prodDatabaseDriver.r2dbc.artifactId %>:<%- prodDatabaseDriver.r2dbc.version %>" - <%_ } _%> - <%_ if (prodDatabaseDriver?.jdbc?.version) { _%> - force "<%- prodDatabaseDriver.jdbc.groupId %>:<%- prodDatabaseDriver.jdbc.artifactId %>:<%- prodDatabaseDriver.jdbc.version %>" - <%_ } _%> - } - } -} - dependencies { - <%_ if (prodDatabaseTypeMariadb || prodDatabaseTypeMssql || prodDatabaseTypeMysql || prodDatabaseTypePostgresql) { _%> - <%_ if (reactive) { _%> - implementation "<%- prodDatabaseDriver.r2dbc.groupId %>:<%- prodDatabaseDriver.r2dbc.artifactId %>" - <%_ } _%> - implementation "<%- prodDatabaseDriver.jdbc.groupId %>:<%- prodDatabaseDriver.jdbc.artifactId %>" - <%_ } _%> - <%_ if (prodDatabaseTypeMariadb) { _%> - testImplementation "org.testcontainers:mariadb" - <%_ } _%> - <%_ if (prodDatabaseTypeMssql) { _%> - testImplementation "org.testcontainers:mssqlserver" - <%_ } _%> - <%_ if (prodDatabaseTypeMysql) { _%> - testImplementation "org.testcontainers:mysql" - <%_ } _%> - <%_ if (prodDatabaseTypeOracle) { _%> - implementation "com.oracle.database.jdbc:ojdbc8" - testImplementation "org.testcontainers:oracle-xe" - <%_ } _%> - <%_ if (prodDatabaseTypePostgresql) { _%> - testImplementation "org.testcontainers:postgresql" - <%_ } _%> + // jhipster-needle-gradle-dependency - JHipster will add additional dependencies here } -<%_ } _%> ext { springProfiles = "prod" + springProfiles diff --git a/generators/server/templates/gradle/war.gradle.ejs b/generators/spring-boot/templates/gradle/war.gradle.ejs similarity index 100% rename from generators/server/templates/gradle/war.gradle.ejs rename to generators/spring-boot/templates/gradle/war.gradle.ejs diff --git a/generators/server/templates/gradle/zipkin.gradle.ejs b/generators/spring-boot/templates/gradle/zipkin.gradle.ejs similarity index 100% rename from generators/server/templates/gradle/zipkin.gradle.ejs rename to generators/spring-boot/templates/gradle/zipkin.gradle.ejs diff --git a/generators/server/templates/micro_services_architecture.md b/generators/spring-boot/templates/micro_services_architecture.md similarity index 100% rename from generators/server/templates/micro_services_architecture.md rename to generators/spring-boot/templates/micro_services_architecture.md diff --git a/generators/server/templates/package.json.ejs b/generators/spring-boot/templates/package.json.ejs similarity index 100% rename from generators/server/templates/package.json.ejs rename to generators/spring-boot/templates/package.json.ejs diff --git a/generators/server/templates/pom.xml.ejs b/generators/spring-boot/templates/pom.xml.ejs similarity index 96% rename from generators/server/templates/pom.xml.ejs rename to generators/spring-boot/templates/pom.xml.ejs index 9c8f7cebedd4..c1142e05fa00 100644 --- a/generators/server/templates/pom.xml.ejs +++ b/generators/spring-boot/templates/pom.xml.ejs @@ -43,6 +43,7 @@ The spring-boot version should match the one managed by https://mvnrepository.com/artifact/tech.jhipster/jhipster-dependencies/${jhipster-dependencies.version} --> 3.2.5 + @ <%= JAVA_VERSION %> UTF-8 UTF-8 @@ -308,6 +309,21 @@ spring-boot:run + + + ${basedir}/<%- srcMainResources %> + true + + config/**/*.yml + + + + ${basedir}/<%- srcMainResources %> + + config/**/*.yml + + + org.apache.maven.plugins @@ -497,6 +513,13 @@ spring-boot-maven-plugin + build-info + + build-info + + + + repackage repackage @@ -618,17 +641,6 @@ - - org.springframework.boot - spring-boot-maven-plugin - - - - build-info - - - - io.github.git-commit-id git-commit-id-maven-plugin @@ -778,22 +790,6 @@ e2e - - - - org.springframework.boot - spring-boot-maven-plugin - - - repackage - - repackage - - - - - -
<%_ } _%> diff --git a/generators/server/templates/settings.gradle.ejs b/generators/spring-boot/templates/settings.gradle.ejs similarity index 88% rename from generators/server/templates/settings.gradle.ejs rename to generators/spring-boot/templates/settings.gradle.ejs index 19600935ebac..f8b7dcda1b47 100644 --- a/generators/server/templates/settings.gradle.ejs +++ b/generators/spring-boot/templates/settings.gradle.ejs @@ -26,6 +26,16 @@ pluginManagement { <%_ } _%> // jhipster-needle-gradle-plugin-management-repositories - JHipster will add additional entries here } +<%_ if (databaseMigrationLiquibase) { _%> + buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath group: 'org.liquibase', name: 'liquibase-core', version: "${liquibaseCoreVersion}" + } + } +<%_ } _%> plugins { id 'com.gorylenko.gradle-git-properties' version "${gitPropertiesPluginVersion}" <%_ if (enableGradleEnterprise) { _%> diff --git a/generators/server/templates/src/main/java/_package_/Application.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/Application.java.ejs similarity index 96% rename from generators/server/templates/src/main/java/_package_/Application.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/Application.java.ejs index 36dcaf5f7823..1935af41e6fd 100644 --- a/generators/server/templates/src/main/java/_package_/Application.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/Application.java.ejs @@ -41,8 +41,11 @@ import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collection; import java.util.Optional; +<%_ if (devDatabaseTypeH2Any) { _%> +import org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration; +<%_ } _%> -@SpringBootApplication +@SpringBootApplication(<% if (devDatabaseTypeH2Any) { %>exclude = { H2ConsoleAutoConfiguration.class }<% } %>) @EnableConfigurationProperties({<% if (databaseMigrationLiquibase) { %>LiquibaseProperties.class, <% } %>ApplicationProperties.class}) public class <%= mainClass %> { diff --git a/generators/server/templates/src/main/java/_package_/ApplicationWebXml.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/ApplicationWebXml.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/ApplicationWebXml.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/ApplicationWebXml.java.ejs diff --git a/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/repository/UserRepository.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/repository/UserRepository.java.ejs index 49e92841c785..e73bccc4ebcb 100644 --- a/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/repository/UserRepository.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/repository/UserRepository.java.ejs @@ -368,7 +368,9 @@ class UserRepositoryInternalImpl implements UserRepositoryInternal { @Override public Flux<<%= user.persistClass %>> findAllWithAuthorities(Pageable pageable) { String property = pageable.getSort().stream().map(Sort.Order::getProperty).findFirst().orElse("id"); - String direction = String.valueOf(pageable.getSort().stream().map(Sort.Order::getDirection).findFirst().orElse(Sort.DEFAULT_DIRECTION)); + String direction = String.valueOf( + pageable.getSort().stream().map(Sort.Order::getDirection).findFirst().orElse(Sort.DEFAULT_DIRECTION) + ); long page = pageable.getPageNumber(); long size = pageable.getPageSize(); @@ -381,7 +383,11 @@ class UserRepositoryInternalImpl implements UserRepositoryInternal { .all() .groupBy(t -> t.getT1().getLogin()) .flatMap(l -> l.collectList().map(t -> updateUserWithAuthorities(t.get(0).getT1(), t))) - .sort(Sort.Direction.fromString(direction) == Sort.DEFAULT_DIRECTION ? new BeanComparator<>(property) : new BeanComparator<>(property).reversed()) + .sort( + Sort.Direction.fromString(direction) == Sort.DEFAULT_DIRECTION + ? new BeanComparator<>(property) + : new BeanComparator<>(property).reversed() + ) .skip(page * size) .take(size); } diff --git a/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/UserService.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/UserService.java.ejs index e870079e423a..13ad90292eef 100644 --- a/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/UserService.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/UserService.java.ejs @@ -199,7 +199,8 @@ public class UserService { <%_ } _%> public <% if (reactive) { %>Mono<% } else { %>Optional<% } %><<%= user.persistClass %>> completePasswordReset(String newPassword, String key) { LOG.debug("Reset user password for reset key {}", key); - return userRepository.findOneByResetKey(key) + return userRepository + .findOneByResetKey(key) .filter(user -> user.getResetDate().isAfter(Instant.now().minus(1, ChronoUnit.DAYS))) <%_ if (reactive) { _%> .publishOn(Schedulers.boundedElastic()) @@ -387,7 +388,7 @@ public class UserService { <%_ if (!reactive) { _%> private boolean removeNonActivatedUser(<%= user.persistClass %> existingUser) { if (existingUser.isActivated()) { - return false; + return false; } userRepository.delete(existingUser); <%_ if (databaseTypeSql) { _%> @@ -457,7 +458,9 @@ public class UserService { user.setActivated(true); <%_ if (databaseTypeSql || databaseTypeMongodb || databaseTypeNeo4j) { _%> if (userDTO.getAuthorities() != null) { - Set authorities = userDTO.getAuthorities().stream() + Set authorities = userDTO + .getAuthorities() + .stream() .map(authorityRepository::findById) .filter(Optional::isPresent) .map(Optional::get) @@ -575,7 +578,8 @@ public class UserService { @Transactional <%_ } _%> public Mono deleteUser(String login) { - return userRepository.findOneByLogin(login) + return userRepository + .findOneByLogin(login) .flatMap(user -> userRepository.delete(user).thenReturn(user)) <%_ if (searchEngineElasticsearch) { _%> .flatMap(user -> userSearchRepository.delete(user).thenReturn(user)) @@ -917,14 +921,11 @@ public class UserService { } if (idpModifiedDate.isAfter(dbModifiedDate)) { LOG.debug("Updating user '{}' in local database", user.getLogin()); - return updateUser(user.getFirstName(), user.getLastName(), user.getEmail(), - user.getLangKey(), user.getImageUrl()); + return updateUser(user.getFirstName(), user.getLastName(), user.getEmail(), user.getLangKey(), user.getImageUrl()); } - // no last updated info, blindly update } else { LOG.debug("Updating user '{}' in local database", user.getLogin()); - return updateUser(user.getFirstName(), user.getLastName(), user.getEmail(), - user.getLangKey(), user.getImageUrl()); + return updateUser(user.getFirstName(), user.getLastName(), user.getEmail(), user.getLangKey(), user.getImageUrl()); } return Mono.empty(); }) diff --git a/generators/server/templates/src/main/java/_package_/_entityPackage_/service/dto/_dtoClass_.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/dto/_dtoClass_.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/_entityPackage_/service/dto/_dtoClass_.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/dto/_dtoClass_.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/_entityPackage_/service/mapper/EntityMapper.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/mapper/EntityMapper.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/_entityPackage_/service/mapper/EntityMapper.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/mapper/EntityMapper.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/_entityPackage_/service/mapper/_entityClass_Mapper.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/mapper/_entityClass_Mapper.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/_entityPackage_/service/mapper/_entityClass_Mapper.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/mapper/_entityClass_Mapper.java.ejs diff --git a/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/web/rest/UserResource.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/web/rest/UserResource.java.ejs index c4db9621ac62..5c59ff31644f 100644 --- a/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/web/rest/UserResource.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/web/rest/UserResource.java.ejs @@ -170,7 +170,8 @@ public class UserResource { // Lowercase the user login before comparing with database <%_ if (reactive) { _%> } - return userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()) + return userRepository + .findOneByLogin(userDTO.getLogin().toLowerCase()) .hasElement() .flatMap(loginExists -> { if (Boolean.TRUE.equals(loginExists)) { @@ -282,9 +283,15 @@ public class UserResource { return Mono.just(ResponseEntity.badRequest().build()); } - return userService.countManagedUsers() + return userService + .countManagedUsers() .map(total -> new PageImpl<>(new ArrayList<>(), pageable, total)) - .map(page -> PaginationUtil.generatePaginationHttpHeaders(ForwardedHeaderUtils.adaptFromForwardedHeaders(request.getURI(), request.getHeaders()), page)) + .map(page -> + PaginationUtil.generatePaginationHttpHeaders( + ForwardedHeaderUtils.adaptFromForwardedHeaders(request.getURI(), request.getHeaders()), + page + ) + ) .map(headers -> ResponseEntity.ok().headers(headers).body(userService.getAllManagedUsers(pageable))); <%_ } else { _%> public ResponseEntity>> getAllUsers(@org.springdoc.core.annotations.ParameterObject Pageable pageable) { diff --git a/generators/server/templates/src/main/java/_package_/aop/logging/LoggingAspect.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/aop/logging/LoggingAspect.java.ejs similarity index 97% rename from generators/server/templates/src/main/java/_package_/aop/logging/LoggingAspect.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/aop/logging/LoggingAspect.java.ejs index b6192ecbd250..b1c14094f21c 100644 --- a/generators/server/templates/src/main/java/_package_/aop/logging/LoggingAspect.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/aop/logging/LoggingAspect.java.ejs @@ -50,9 +50,11 @@ public class LoggingAspect { /** * Pointcut that matches all repositories, services and Web REST endpoints. */ - @Pointcut("within(@org.springframework.stereotype.Repository *)" + + @Pointcut( + "within(@org.springframework.stereotype.Repository *)" + " || within(@org.springframework.stereotype.Service *)" + - " || within(@org.springframework.web.bind.annotation.RestController *)") + " || within(@org.springframework.web.bind.annotation.RestController *)" + ) public void springBeanPointcut() { // Method is empty as this is just a Pointcut, the implementations are in the advices. } diff --git a/generators/server/templates/src/main/java/_package_/config/ApplicationProperties.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/ApplicationProperties.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/ApplicationProperties.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/ApplicationProperties.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/AsyncConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/AsyncConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/AsyncConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/AsyncConfiguration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/CRLFLogConverter.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/CRLFLogConverter.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/CRLFLogConverter.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/CRLFLogConverter.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/Constants.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/Constants.java.ejs similarity index 97% rename from generators/server/templates/src/main/java/_package_/config/Constants.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/Constants.java.ejs index a35b2a6041ed..3f83f4f5a4a8 100644 --- a/generators/server/templates/src/main/java/_package_/config/Constants.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/config/Constants.java.ejs @@ -36,6 +36,5 @@ public final class Constants { public static final String ID_DELIMITER = "__"; <%_ } _%> - private Constants() { - } + private Constants() {} } diff --git a/generators/server/templates/src/main/java/_package_/config/DateTimeFormatConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/DateTimeFormatConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/DateTimeFormatConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/DateTimeFormatConfiguration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/EurekaWorkaroundConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/EurekaWorkaroundConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/EurekaWorkaroundConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/EurekaWorkaroundConfiguration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/JacksonConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/JacksonConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/JacksonConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/JacksonConfiguration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/LoggingAspectConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/LoggingAspectConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/LoggingAspectConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/LoggingAspectConfiguration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/LoggingConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/LoggingConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/LoggingConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/LoggingConfiguration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/OAuth2Configuration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/OAuth2Configuration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/OAuth2Configuration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/OAuth2Configuration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/OpenApiConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/OpenApiConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/OpenApiConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/OpenApiConfiguration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/ReactorConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/ReactorConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/ReactorConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/ReactorConfiguration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs similarity index 94% rename from generators/server/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs index 5fa690b4919b..0fca34168b5d 100644 --- a/generators/server/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs @@ -51,6 +51,10 @@ import tech.jhipster.web.filter.CookieCsrfFilter; <%_ if (!skipClient) { _%> import <%= packageName %>.web.filter.SpaWebFilter; <%_ } _%> +<%_ if (applicationTypeGateway) { _%> +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +<%_ } _%> <%_ if (authenticationUsesCsrf && !applicationTypeMicroservice) { _%> import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -113,6 +117,10 @@ import <%= packageName %>.security.oauth2.CustomClaimConverter; <%_ if(!skipClient) { _%> import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter; <%_ } _%> +<%_ if (applicationTypeGateway) { _%> +import org.springframework.security.web.server.WebFilterChainProxy; +import org.springframework.security.web.server.firewall.ServerWebExchangeFirewall; +<%_ } _%> <%_ if (authenticationUsesCsrf && !applicationTypeMicroservice) { _%> import org.springframework.util.StringUtils; <%_ } _%> @@ -194,17 +202,13 @@ public class SecurityConfiguration { <%_ if (!skipClient) { _%> .requestMatchers(mvc.pattern("/index.html"), mvc.pattern("/*.js"), mvc.pattern("/*.txt"), mvc.pattern("/*.json"), mvc.pattern("/*.map"), mvc.pattern("/*.css")).permitAll() .requestMatchers(mvc.pattern("/*.ico"), mvc.pattern("/*.png"), mvc.pattern("/*.svg"), mvc.pattern("/*.webapp")).permitAll() - <%_ if (clientFrameworkVue) { _%> + <%_ if (clientBundlerVite) { _%> .requestMatchers(mvc.pattern("/assets/**")).permitAll() - <%_ if (microfrontend) { _%> - .requestMatchers(mvc.pattern("/app/**")).permitAll() - .requestMatchers(mvc.pattern("/i18n/**")).permitAll() - <%_ } _%> <%_ } else { _%> .requestMatchers(mvc.pattern("/app/**")).permitAll() .requestMatchers(mvc.pattern("/i18n/**")).permitAll() - <%_ } _%> .requestMatchers(mvc.pattern("/content/**")).permitAll() + <%_ } _%> .requestMatchers(mvc.pattern("/swagger-ui/**")).permitAll() <%_ } _%> <%_ if (authenticationTypeJwt) { _%> @@ -227,6 +231,9 @@ public class SecurityConfiguration { <%_ if (applicationTypeGateway) { _%> <%_ if (microfrontend) { _%> // microfrontend resources are loaded by webpack without authentication, they need to be public + <%_ if (clientBundlerVite) { _%> + .requestMatchers(mvc.pattern("/services/*/assets/**")).permitAll() + <%_ } _%> .requestMatchers(mvc.pattern("/services/*/*.js")).permitAll() .requestMatchers(mvc.pattern("/services/*/*.txt")).permitAll() .requestMatchers(mvc.pattern("/services/*/*.json")).permitAll() @@ -417,4 +424,20 @@ public class SecurityConfiguration { } } <%_ } _%> +<%_ if (applicationTypeGateway) { _%> + + // Fix for Spring Boot 3.3.5: https://github.com/spring-cloud/spring-cloud-gateway/issues/3568 + @Bean + BeanPostProcessor beanPostProcessor() { + return new BeanPostProcessor() { + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof WebFilterChainProxy springSecurity) { + springSecurity.setFirewall(ServerWebExchangeFirewall.INSECURE_NOOP); + } + return bean; + } + }; + } +<%_ } _%> } diff --git a/generators/server/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs similarity index 91% rename from generators/server/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs index 62fb00751d52..f5424a90b626 100644 --- a/generators/server/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs @@ -39,6 +39,10 @@ import org.springframework.boot.autoconfigure.security.SecurityProperties; <%_ if (!skipClient) { _%> import <%= packageName %>.web.filter.SpaWebFilter; <%_ } _%> +<%_ if (applicationTypeGateway) { _%> +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +<%_ } _%> import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; <%_ if (authenticationTypeOauth2) { _%> @@ -114,6 +118,10 @@ import org.springframework.security.web.server.savedrequest.NoOpServerRequestCac <%_ } _%> import org.springframework.security.web.server.util.matcher.NegatedServerWebExchangeMatcher; import org.springframework.security.web.server.util.matcher.OrServerWebExchangeMatcher; +<%_ if (applicationTypeGateway) { _%> +import org.springframework.security.web.server.WebFilterChainProxy; +import org.springframework.security.web.server.firewall.ServerWebExchangeFirewall; +<%_ } _%> <%_ if (authenticationUsesCsrf) { _%> import reactor.core.publisher.Mono; <%_ } _%> @@ -186,7 +194,9 @@ public class SecurityConfiguration { @Bean public ReactiveAuthenticationManager reactiveAuthenticationManager(ReactiveUserDetailsService userDetailsService) { - UserDetailsRepositoryReactiveAuthenticationManager authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService); + UserDetailsRepositoryReactiveAuthenticationManager authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager( + userDetailsService + ); authenticationManager.setPasswordEncoder(passwordEncoder()); return authenticationManager; } @@ -195,8 +205,7 @@ public class SecurityConfiguration { @Bean public MapReactiveUserDetailsService userDetailsService(SecurityProperties properties) { SecurityProperties.User user = properties.getUser(); - UserDetails userDetails = User - .withUsername(user.getName()) + UserDetails userDetails = User.withUsername(user.getName()) .password("{noop}" + user.getPassword()) .roles(StringUtils.toStringArray(user.getRoles())) .build(); @@ -213,19 +222,16 @@ public class SecurityConfiguration { public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http .securityMatcher(new NegatedServerWebExchangeMatcher(new OrServerWebExchangeMatcher( - <%_ if (clientFrameworkVue) { _%> pathMatchers( + <%_ if (clientBundlerVite) { _%> "/assets/**", - <%_ if (microfrontend) { _%> + <%_ } else { _%> "/app/**", "/i18n/**", "/content/**", - <%_ } _%> + <%_ } _%> "/swagger-ui/**" ) - <%_ } else { _%> - pathMatchers("/app/**", "/i18n/**", "/content/**", "/swagger-ui/**") - <%_ } _%> ))) <%_ if (!applicationTypeMicroservice) { _%> .cors(withDefaults()) @@ -285,10 +291,15 @@ public class SecurityConfiguration { <%_ if (applicationTypeGateway) { _%> <%_ if (microfrontend) { _%> // microfrontend resources are loaded by webpack without authentication, they need to be public + <%_ if (clientBundlerVite) { _%> + .pathMatchers("/services/*/assets/**").permitAll() + .pathMatchers("/services/*/*.js").permitAll() + <%_ } else { _%> .pathMatchers("/services/*/*.js").permitAll() .pathMatchers("/services/*/*.txt").permitAll() .pathMatchers("/services/*/*.json").permitAll() .pathMatchers("/services/*/*.js.map").permitAll() + <%_ } _%> <%_ } _%> .pathMatchers("/services/*/management/health/readiness").permitAll() .pathMatchers("/services/*/v3/api-docs").hasAuthority(AuthoritiesConstants.ADMIN) @@ -320,20 +331,22 @@ public class SecurityConfiguration { <%_ if (authenticationTypeOauth2) { _%> <%_ if (!applicationTypeMicroservice) { _%> private ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver( - ReactiveClientRegistrationRepository clientRegistrationRepository) { - DefaultServerOAuth2AuthorizationRequestResolver authorizationRequestResolver = - new DefaultServerOAuth2AuthorizationRequestResolver(clientRegistrationRepository); + ReactiveClientRegistrationRepository clientRegistrationRepository + ) { + DefaultServerOAuth2AuthorizationRequestResolver authorizationRequestResolver = new DefaultServerOAuth2AuthorizationRequestResolver( + clientRegistrationRepository + ); if (this.issuerUri.contains("auth0.com")) { authorizationRequestResolver.setAuthorizationRequestCustomizer(authorizationRequestCustomizer()); } - return authorizationRequestResolver; + return authorizationRequestResolver; } private Consumer authorizationRequestCustomizer() { - return customizer -> customizer - .authorizationRequestUri(uriBuilder -> - uriBuilder.queryParam("audience", jHipsterProperties.getSecurity().getOauth2().getAudience()) - .build()); + return customizer -> + customizer.authorizationRequestUri(uriBuilder -> + uriBuilder.queryParam("audience", jHipsterProperties.getSecurity().getOauth2().getAudience()).build() + ); } <%_ } _%> @@ -409,8 +422,7 @@ public class SecurityConfiguration { private ReactiveJwtDecoder createJwtDecoder(String issuerUri, String jwkSetUri, String userInfoUri) { NimbusReactiveJwtDecoder jwtDecoder = new NimbusReactiveJwtDecoder(jwkSetUri); - OAuth2TokenValidator audienceValidator = new AudienceValidator( - jHipsterProperties.getSecurity().getOauth2().getAudience()); + OAuth2TokenValidator audienceValidator = new AudienceValidator(jHipsterProperties.getSecurity().getOauth2().getAudience()); OAuth2TokenValidator withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri); OAuth2TokenValidator withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator); @@ -419,8 +431,7 @@ public class SecurityConfiguration { return new ReactiveJwtDecoder() { @Override public Mono decode(String token) throws JwtException { - return jwtDecoder.decode(token) - .flatMap(jwt -> enrich(token, jwt)); + return jwtDecoder.decode(token).flatMap(jwt -> enrich(token, jwt)); } private Mono enrich(String token, Jwt jwt) { @@ -429,17 +440,15 @@ public class SecurityConfiguration { return Mono.just(jwt); } // Get user info from `users` cache if present - return Optional.ofNullable(users.getIfPresent(jwt.getSubject())) - // Retrieve user info from OAuth provider if not already loaded - .orElseGet(() -> WebClient.create() + return Optional.ofNullable(users.getIfPresent(jwt.getSubject())).orElseGet(() -> // Retrieve user info from OAuth provider if not already loaded + WebClient.create() .get() .uri(userInfoUri) .headers(headers -> headers.setBearerAuth(token)) .retrieve() .bodyToMono(new ParameterizedTypeReference>() {}) .map(userInfo -> - Jwt - .withTokenValue(jwt.getTokenValue()) + Jwt.withTokenValue(jwt.getTokenValue()) .subject(jwt.getSubject()) .audience(jwt.getAudience()) .headers(headers -> headers.putAll(jwt.getHeaders())) @@ -464,7 +473,7 @@ public class SecurityConfiguration { ) // Put user info into the `users` cache .doOnNext(newJwt -> users.put(jwt.getSubject(), Mono.just(newJwt))) - ); + ); } }; } @@ -481,4 +490,20 @@ public class SecurityConfiguration { return Mono.empty(); } <%_ } _%> +<%_ if (applicationTypeGateway) { _%> + + // Fix for Spring Boot 3.3.5: https://github.com/spring-cloud/spring-cloud-gateway/issues/3568 + @Bean + BeanPostProcessor beanPostProcessor() { + return new BeanPostProcessor() { + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof WebFilterChainProxy springSecurity) { + springSecurity.setFirewall(ServerWebExchangeFirewall.INSECURE_NOOP); + } + return bean; + } + }; + } +<%_ } _%> } diff --git a/generators/server/templates/src/main/java/_package_/config/SecurityInMemoryConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityInMemoryConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/SecurityInMemoryConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/SecurityInMemoryConfiguration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/SecurityJwtConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityJwtConfiguration.java.ejs similarity index 99% rename from generators/server/templates/src/main/java/_package_/config/SecurityJwtConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/SecurityJwtConfiguration.java.ejs index 0b7693d2d46b..97713022d533 100644 --- a/generators/server/templates/src/main/java/_package_/config/SecurityJwtConfiguration.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityJwtConfiguration.java.ejs @@ -60,7 +60,7 @@ public class SecurityJwtConfiguration { if (e.getMessage().contains("Jwt expired at")) { metersService.trackTokenExpired(); } else if (e.getMessage().contains("Failed to validate the token")) { - metersService.trackTokenInvalidSignature(); + metersService.trackTokenInvalidSignature(); } else if ( e.getMessage().contains("Invalid JWT serialization:") || e.getMessage().contains("Invalid unsecured/JWS/JWE header:") diff --git a/generators/server/templates/src/main/java/_package_/config/StaticResourcesWebConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/StaticResourcesWebConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/config/StaticResourcesWebConfiguration.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/StaticResourcesWebConfiguration.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/config/WebConfigurer.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/WebConfigurer.java.ejs similarity index 92% rename from generators/server/templates/src/main/java/_package_/config/WebConfigurer.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/config/WebConfigurer.java.ejs index b5d3f5d40373..7abe376d965c 100644 --- a/generators/server/templates/src/main/java/_package_/config/WebConfigurer.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/config/WebConfigurer.java.ejs @@ -26,6 +26,7 @@ import tech.jhipster.config.JHipsterConstants; <%_ } _%> import tech.jhipster.config.JHipsterProperties; <%_ if (devDatabaseTypeH2Any) { _%> +import tech.jhipster.config.ApplicationProperties; import tech.jhipster.config.h2.H2ConfigurationHelper; <%_ } _%> <%_ if (!skipClient && reactive) { _%> @@ -102,14 +103,15 @@ public class WebConfigurer implements <% if (!reactive) { %>ServletContextInitia <%_ } _%> private final JHipsterProperties jHipsterProperties; - public WebConfigurer(<% if (!reactive || (devDatabaseTypeH2Any && reactive)) { %>Environment env, <% } %>JHipsterProperties jHipsterProperties) { + public WebConfigurer(<% if (!reactive || devDatabaseTypeH2Any) { %>Environment env, <% } %>JHipsterProperties jHipsterProperties) { <%_ if (!reactive) { _%> this.env = env; <%_ } _%> this.jHipsterProperties = jHipsterProperties; <%_ if (devDatabaseTypeH2Any && reactive) { _%> - if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT))) { + if (h2ConsoleIsEnabled(env)) { try { + LOG.info("Initialize H2 console"); H2ConfigurationHelper.initH2Console(); } catch (Exception e) { // Console may already be running on another app or after a refresh. @@ -118,8 +120,6 @@ public class WebConfigurer implements <% if (!reactive) { %>ServletContextInitia } <%_ } _%> } - - <%_ if (!reactive) { _%> @Override @@ -129,7 +129,7 @@ public class WebConfigurer implements <% if (!reactive) { %>ServletContextInitia } <%_ if (devDatabaseTypeH2Any) { _%> - if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT))) { + if (h2ConsoleIsEnabled(env)) { initH2Console(servletContext); } <%_ } _%> @@ -170,7 +170,6 @@ public class WebConfigurer implements <% if (!reactive) { %>ServletContextInitia } return extractedPath.substring(0, extractionEndIndex); } - <%_ } _%> <%_ } _%> @@ -178,7 +177,7 @@ public class WebConfigurer implements <% if (!reactive) { %>ServletContextInitia public <% if (reactive) { %>CorsConfigurationSource corsConfigurationSource()<% } else { %>CorsFilter corsFilter()<% } %> { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = jHipsterProperties.getCors(); - if (!CollectionUtils.isEmpty(config.getAllowedOrigins()) || ! CollectionUtils.isEmpty(config.getAllowedOriginPatterns())) { + if (!CollectionUtils.isEmpty(config.getAllowedOrigins()) || !CollectionUtils.isEmpty(config.getAllowedOriginPatterns())) { LOG.debug("Registering CORS filter"); source.registerCorsConfiguration("/api/**", config); source.registerCorsConfiguration("/management/**", config); @@ -230,14 +229,20 @@ public class WebConfigurer implements <% if (!reactive) { %>ServletContextInitia } <%_ } _%> <%_ } _%> -<%_ if (devDatabaseTypeH2Any && !reactive) { _%> +<%_ if (devDatabaseTypeH2Any) { _%> + + private boolean h2ConsoleIsEnabled(Environment env) { + return env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) && "true".equals(env.getProperty("spring.h2.console.enabled")); + } + <%_ if (!reactive) { _%> /** * Initializes H2 console. */ private void initH2Console(ServletContext servletContext) { - LOG.debug("Initialize H2 console"); + LOG.info("Initialize H2 console"); H2ConfigurationHelper.initH2Console(servletContext); } + <%_ } _%> <%_ } _%> } diff --git a/generators/server/templates/src/main/java/_package_/domain/AbstractAuditingEntity.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/domain/AbstractAuditingEntity.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/domain/AbstractAuditingEntity.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/domain/AbstractAuditingEntity.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/domain/PersistentToken.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/domain/PersistentToken.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/domain/PersistentToken.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/domain/PersistentToken.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/domain/User.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/domain/User.java.ejs similarity index 99% rename from generators/server/templates/src/main/java/_package_/domain/User.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/domain/User.java.ejs index 31b62df864cd..6e4dcc4a34cf 100644 --- a/generators/server/templates/src/main/java/_package_/domain/User.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/domain/User.java.ejs @@ -41,7 +41,6 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; <%_ } _%> <%_ if (databaseTypeSql && reactive) { _%> import org.springframework.data.annotation.Id; -import org.springframework.data.annotation.Transient; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Table; <%_ if (requiresPersistableImplementation) { _%> @@ -395,7 +394,7 @@ public class <%= user.persistClass %><% if (generateSpringAuditor) { %> extends @BatchSize(size = 20) <%_ } _%> <%_ if (databaseTypeSql && reactive) { _%> - @Transient + @org.springframework.data.annotation.Transient <%_ } _%> <%_ if (databaseTypeSql || databaseTypeMongodb || databaseTypeNeo4j) { _%> private Set authorities = new HashSet<>(); @@ -413,7 +412,7 @@ public class <%= user.persistClass %><% if (generateSpringAuditor) { %> extends <%_ } _%> <%_ if (databaseTypeSql && reactive && requiresPersistableImplementation) { _%> - @Transient + @org.springframework.data.annotation.Transient private boolean isPersisted; <%_ } _%> diff --git a/generators/server/templates/src/main/java/_package_/management/SecurityMetersService.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/management/SecurityMetersService.java.ejs similarity index 96% rename from generators/server/templates/src/main/java/_package_/management/SecurityMetersService.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/management/SecurityMetersService.java.ejs index 4d06fb7aac7b..b022316a8a2f 100644 --- a/generators/server/templates/src/main/java/_package_/management/SecurityMetersService.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/management/SecurityMetersService.java.ejs @@ -27,7 +27,8 @@ import io.micrometer.core.instrument.MeterRegistry; public class SecurityMetersService { public static final String INVALID_TOKENS_METER_NAME = "security.authentication.invalid-tokens"; - public static final String INVALID_TOKENS_METER_DESCRIPTION = "Indicates validation error count of the tokens presented by the clients."; + public static final String INVALID_TOKENS_METER_DESCRIPTION = + "Indicates validation error count of the tokens presented by the clients."; public static final String INVALID_TOKENS_METER_BASE_UNIT = "errors"; public static final String INVALID_TOKENS_METER_CAUSE_DIMENSION = "cause"; diff --git a/generators/server/templates/src/main/java/_package_/repository/PersistentTokenRepository.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/repository/PersistentTokenRepository.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/repository/PersistentTokenRepository.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/repository/PersistentTokenRepository.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/security/AuthoritiesConstants.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/security/AuthoritiesConstants.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/security/AuthoritiesConstants.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/security/AuthoritiesConstants.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/security/DomainUserDetailsService.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/security/DomainUserDetailsService.java.ejs similarity index 98% rename from generators/server/templates/src/main/java/_package_/security/DomainUserDetailsService.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/security/DomainUserDetailsService.java.ejs index d83964ef1894..07e2504e409e 100644 --- a/generators/server/templates/src/main/java/_package_/security/DomainUserDetailsService.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/security/DomainUserDetailsService.java.ejs @@ -93,8 +93,6 @@ public class DomainUserDetailsService implements <% if (reactive) { %>Reactive<% .map(Authority::getName)<% } %> .map(SimpleGrantedAuthority::new) .toList(); - return new org.springframework.security.core.userdetails.User(user.getLogin(), - user.getPassword(), - grantedAuthorities); + return new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(), grantedAuthorities); } } diff --git a/generators/server/templates/src/main/java/_package_/security/PersistentTokenRememberMeServices.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/security/PersistentTokenRememberMeServices.java.ejs similarity index 98% rename from generators/server/templates/src/main/java/_package_/security/PersistentTokenRememberMeServices.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/security/PersistentTokenRememberMeServices.java.ejs index cd593704c402..de0894f4a1de 100644 --- a/generators/server/templates/src/main/java/_package_/security/PersistentTokenRememberMeServices.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/security/PersistentTokenRememberMeServices.java.ejs @@ -153,9 +153,7 @@ public class PersistentTokenRememberMeServices extends AbstractRememberMeService } @Override - protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication - successfulAuthentication) { - + protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) { String login = successfulAuthentication.getName(); LOG.debug("Creating new persistent login for user {}", login); @@ -225,8 +223,9 @@ public class PersistentTokenRememberMeServices extends AbstractRememberMeService */ private PersistentToken getPersistentToken(String[] cookieTokens) { if (cookieTokens.length != 2) { - throw new InvalidCookieException("Cookie token did not contain " + 2 + - " tokens, but contained '" + Arrays.asList(cookieTokens) + "'"); + throw new InvalidCookieException( + "Cookie token did not contain " + 2 + " tokens, but contained '" + Arrays.asList(cookieTokens) + "'" + ); } String presentedSeries = cookieTokens[0]; String presentedToken = cookieTokens[1]; diff --git a/generators/server/templates/src/main/java/_package_/security/SecurityUtils.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/security/SecurityUtils.java.ejs similarity index 94% rename from generators/server/templates/src/main/java/_package_/security/SecurityUtils.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/security/SecurityUtils.java.ejs index 56b5d79ca71e..15549cb33aba 100644 --- a/generators/server/templates/src/main/java/_package_/security/SecurityUtils.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/security/SecurityUtils.java.ejs @@ -79,8 +79,7 @@ public final class SecurityUtils { public static final String AUTHORITIES_KEY = "auth"; <%_ } _%> - private SecurityUtils() { - } + private SecurityUtils() {} /** * Get the login of the current user. @@ -109,7 +108,7 @@ public final class SecurityUtils { <%_ } _%> <%_ if (authenticationTypeOauth2) { _%> } else if (authentication instanceof JwtAuthenticationToken) { - return (String) ((JwtAuthenticationToken)authentication).getToken().getClaims().get("preferred_username"); + return (String) ((JwtAuthenticationToken) authentication).getToken().getClaims().get("preferred_username"); } else if (authentication.getPrincipal() instanceof DefaultOidcUser) { Map attributes = ((DefaultOidcUser) authentication.getPrincipal()).getAttributes(); if (attributes.containsKey("preferred_username")) { @@ -174,9 +173,11 @@ public final class SecurityUtils { return ReactiveSecurityContextHolder.getContext() .map(SecurityContext::getAuthentication) .map(Authentication::getAuthorities) - .map(authorityList -> authorityList.stream() - .map(GrantedAuthority::getAuthority) - .anyMatch(authority -> Arrays.asList(authorities).contains(authority)) + .map(authorityList -> + authorityList + .stream() + .map(GrantedAuthority::getAuthority) + .anyMatch(authority -> Arrays.asList(authorities).contains(authority)) ); <%_ } else { _%> Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); @@ -231,16 +232,14 @@ public final class SecurityUtils { @SuppressWarnings("unchecked") private static Collection getRolesFromClaims(Map claims) { - return (Collection) claims.getOrDefault("groups", - claims.getOrDefault("roles", - claims.getOrDefault(CLAIMS_NAMESPACE + "roles", new ArrayList<>()))); + return (Collection) claims.getOrDefault( + "groups", + claims.getOrDefault("roles", claims.getOrDefault(CLAIMS_NAMESPACE + "roles", new ArrayList<>())) + ); } private static List mapRolesToGrantedAuthorities(Collection roles) { - return roles.stream() - .filter(role -> role.startsWith("ROLE_")) - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); + return roles.stream().filter(role -> role.startsWith("ROLE_")).map(SimpleGrantedAuthority::new).collect(Collectors.toList()); } <%_ } _%> <%_ if (generateAuthenticationApi && ((authenticationTypeOauth2 && !syncUserWithIdp) || (authenticationTypeJwt && skipUserManagement))) { _%> diff --git a/generators/server/templates/src/main/java/_package_/security/SpringSecurityAuditorAware.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/security/SpringSecurityAuditorAware.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/security/SpringSecurityAuditorAware.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/security/SpringSecurityAuditorAware.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/security/UserNotActivatedException.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/security/UserNotActivatedException.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/security/UserNotActivatedException.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/security/UserNotActivatedException.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/security/oauth2/AudienceValidator.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/security/oauth2/AudienceValidator.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/security/oauth2/AudienceValidator.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/security/oauth2/AudienceValidator.java.ejs index 6f1f3b774ccb..7bbcafcc58e6 100644 --- a/generators/server/templates/src/main/java/_package_/security/oauth2/AudienceValidator.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/security/oauth2/AudienceValidator.java.ejs @@ -27,8 +27,8 @@ import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.util.Assert; import java.util.List; - public class AudienceValidator implements OAuth2TokenValidator { + private static final Logger LOG = LoggerFactory.getLogger(AudienceValidator.class); private final OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null); diff --git a/generators/server/templates/src/main/java/_package_/security/oauth2/CustomClaimConverter.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/security/oauth2/CustomClaimConverter.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/security/oauth2/CustomClaimConverter.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/security/oauth2/CustomClaimConverter.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/service/EmailAlreadyUsedException.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/service/EmailAlreadyUsedException.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/service/EmailAlreadyUsedException.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/service/EmailAlreadyUsedException.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/service/InvalidPasswordException.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/service/InvalidPasswordException.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/service/InvalidPasswordException.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/service/InvalidPasswordException.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/service/MailService.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/service/MailService.java.ejs similarity index 96% rename from generators/server/templates/src/main/java/_package_/service/MailService.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/service/MailService.java.ejs index 21879b927f14..60a017b6a538 100644 --- a/generators/server/templates/src/main/java/_package_/service/MailService.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/service/MailService.java.ejs @@ -97,8 +97,14 @@ public class MailService { } private void sendEmailSync(String to, String subject, String content, boolean isMultipart, boolean isHtml) { - LOG.debug("Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}", - isMultipart, isHtml, to, subject, content); + LOG.debug( + "Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}", + isMultipart, + isHtml, + to, + subject, + content + ); // Prepare message using a Spring helper MimeMessage mimeMessage = javaMailSender.createMimeMessage(); diff --git a/generators/server/templates/src/main/java/_package_/service/UsernameAlreadyUsedException.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/service/UsernameAlreadyUsedException.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/service/UsernameAlreadyUsedException.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/service/UsernameAlreadyUsedException.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/service/dto/AdminUserDTO.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/service/dto/AdminUserDTO.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/service/dto/AdminUserDTO.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/service/dto/AdminUserDTO.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/service/dto/PasswordChangeDTO.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/service/dto/PasswordChangeDTO.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/service/dto/PasswordChangeDTO.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/service/dto/PasswordChangeDTO.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/service/dto/UserDTO.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/service/dto/UserDTO.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/service/dto/UserDTO.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/service/dto/UserDTO.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/service/mapper/UserMapper.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/service/mapper/UserMapper.java.ejs similarity index 95% rename from generators/server/templates/src/main/java/_package_/service/mapper/UserMapper.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/service/mapper/UserMapper.java.ejs index 0ff8f79de5c4..37ec631039c4 100644 --- a/generators/server/templates/src/main/java/_package_/service/mapper/UserMapper.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/service/mapper/UserMapper.java.ejs @@ -110,11 +110,14 @@ public class UserMapper { Set authorities = new HashSet<>(); if (authoritiesAsString != null) { - authorities = authoritiesAsString.stream().map(string -> { - Authority auth = new Authority(); - auth.setName(string); - return auth; - }).collect(Collectors.toSet()); + authorities = authoritiesAsString + .stream() + .map(string -> { + Authority auth = new Authority(); + auth.setName(string); + return auth; + }) + .collect(Collectors.toSet()); } return authorities; diff --git a/generators/server/templates/src/main/java/_package_/web/filter/OAuth2ReactiveRefreshTokensWebFilter.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/filter/OAuth2ReactiveRefreshTokensWebFilter.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/filter/OAuth2ReactiveRefreshTokensWebFilter.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/filter/OAuth2ReactiveRefreshTokensWebFilter.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/filter/OAuth2RefreshTokensWebFilter.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/filter/OAuth2RefreshTokensWebFilter.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/filter/OAuth2RefreshTokensWebFilter.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/filter/OAuth2RefreshTokensWebFilter.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/filter/SpaWebFilter_imperative.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/filter/SpaWebFilter_imperative.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/filter/SpaWebFilter_imperative.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/filter/SpaWebFilter_imperative.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/filter/SpaWebFilter_reactive.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/filter/SpaWebFilter_reactive.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/filter/SpaWebFilter_reactive.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/filter/SpaWebFilter_reactive.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/AccountResource.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/AccountResource.java.ejs similarity index 92% rename from generators/server/templates/src/main/java/_package_/web/rest/AccountResource.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/AccountResource.java.ejs index 3f4c271fb47c..0b731c84b1dc 100644 --- a/generators/server/templates/src/main/java/_package_/web/rest/AccountResource.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/web/rest/AccountResource.java.ejs @@ -18,13 +18,13 @@ -%> package <%= packageName %>.web.rest; - <%_ if (authenticationTypeSession && !reactive) { _%> +<%_ if (authenticationTypeSession && !reactive) { _%> import <%= packageName %>.domain.PersistentToken; import <%= packageName %>.repository.PersistentTokenRepository; - <%_ } _%> - <%_ if (!reactive) { _%> +<%_ } _%> +<%_ if (!reactive) { _%> import <%= user.entityAbsoluteClass %>; - <%_ } _%> +<%_ } _%> import <%= packageName %>.repository.UserRepository; import <%= packageName %>.security.SecurityUtils; import <%= packageName %>.service.MailService; @@ -35,31 +35,24 @@ import <%= packageName %>.web.rest.errors.*; import <%= packageName %>.web.rest.vm.KeyAndPasswordVM; import <%= packageName %>.web.rest.vm.ManagedUserVM; +import java.security.Principal; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; - <%_ if (reactive) { _%> -import org.springframework.web.server.ServerWebExchange; +<%_ if (reactive) { _%> +import java.util.Objects; import reactor.core.publisher.Mono; - <%_ } _%> - - <%_ if (!reactive && !authenticationTypeJwt) { _%> -import jakarta.servlet.http.HttpServletRequest; - <%_ } _%> +<%_ } else { _%> +import java.util.*; +<%_ } _%> import jakarta.validation.Valid; - <%_ if (authenticationTypeSession && !reactive) { _%> +<%_ if (authenticationTypeSession && !reactive) { _%> import java.nio.charset.StandardCharsets; import java.net.URLDecoder; - <%_ } _%> - <%_ if (reactive) { _%> -import java.security.Principal; -import java.util.Objects; - <%_ } _%> - <%_ if (!reactive) { _%> -import java.util.*; - <%_ } _%> +<%_ } _%> /** * REST controller for managing the current user's account. @@ -144,19 +137,13 @@ public class AccountResource { /** * {@code GET /authenticate} : check if the user is authenticated, and return its login. * - * @param request the HTTP request. + * @param principal the authentication principal. * @return the login if the user is authenticated. */ - @GetMapping("/authenticate") - <%_ if (reactive) { _%> - public Mono isAuthenticated(ServerWebExchange request) { - LOG.debug("REST request to check if the current user is authenticated"); - return request.getPrincipal().map(Principal::getName); - <%_ } else { _%> - public String isAuthenticated(HttpServletRequest request) { + @GetMapping(value = "/authenticate", produces = MediaType.TEXT_PLAIN_VALUE) + public String isAuthenticated(Principal principal) { LOG.debug("REST request to check if the current user is authenticated"); - return request.getRemoteUser(); - <%_ } _%> + return principal == null ? null : principal.getName(); } <%_ } _%> @@ -167,7 +154,7 @@ public class AccountResource { * @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be returned. */ @GetMapping("/account") - public <% if (reactive) { %>Mono<<%= user.adminUserDto %>><% } else { %><%= user.adminUserDto %><% } %> getAccount() { + public <%- wrapMono(user.adminUserDto) %> getAccount() { return userService.getUserWithAuthorities() .map(<%= user.adminUserDto %>::new) <%_ if (reactive) { _%> @@ -291,7 +278,8 @@ public class AccountResource { @PostMapping(path = "/account/reset-password/init") <%_ if (reactive) { _%> public Mono requestPasswordReset(@RequestBody String mail) { - return userService.requestPasswordReset(mail) + return userService + .requestPasswordReset(mail) .doOnSuccess(user -> { if (Objects.nonNull(user)) { mailService.sendPasswordResetMail(user); @@ -342,8 +330,10 @@ public class AccountResource { } private static boolean isPasswordLengthInvalid(String password) { - return StringUtils.isEmpty(password) || + return ( + StringUtils.isEmpty(password) || password.length() < ManagedUserVM.PASSWORD_MIN_LENGTH || - password.length() > ManagedUserVM.PASSWORD_MAX_LENGTH; + password.length() > ManagedUserVM.PASSWORD_MAX_LENGTH + ); } } diff --git a/generators/server/templates/src/main/java/_package_/web/rest/AccountResource_oauth2.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/AccountResource_oauth2.java.ejs similarity index 77% rename from generators/server/templates/src/main/java/_package_/web/rest/AccountResource_oauth2.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/AccountResource_oauth2.java.ejs index 21969efd3729..3bfead1f79df 100644 --- a/generators/server/templates/src/main/java/_package_/web/rest/AccountResource_oauth2.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/web/rest/AccountResource_oauth2.java.ejs @@ -18,27 +18,21 @@ -%> package <%= packageName %>.web.rest; -<%_ if (reactive) { _%> -import <%= packageName %>.security.SecurityUtils; -<%_ } _%> import <%= packageName %>.service.UserService; import <%= packageName %>.service.dto.<%= user.adminUserDto %>; +import java.security.Principal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; <%_ if (reactive) { _%> -import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; -<%_ } else { _%> -import jakarta.servlet.http.HttpServletRequest; <%_ } _%> -import java.security.Principal; - /** * REST controller for managing the current user's account. */ @@ -71,7 +65,7 @@ public class AccountResource { * @throws AccountResourceException {@code 500 (Internal Server Error)} if the user couldn't be returned. */ @GetMapping("/account") - public <% if (reactive) { %>Mono<<%= user.adminUserDto %>><% } else { %><%= user.adminUserDto %><% } %> getAccount(Principal principal) { + public <%- wrapMono(user.adminUserDto) %> getAccount(Principal principal) { if (principal instanceof AbstractAuthenticationToken) { return userService.getUserFromAuthentication((AbstractAuthenticationToken) principal); } else { @@ -82,18 +76,12 @@ public class AccountResource { /** * {@code GET /authenticate} : check if the user is authenticated, and return its login. * - * @param request the HTTP request. + * @param principal the authentication principal. * @return the login if the user is authenticated. */ - @GetMapping("/authenticate") -<%_ if (reactive) { _%> - public Mono isAuthenticated(ServerWebExchange request) { + @GetMapping(value = "/authenticate", produces = MediaType.TEXT_PLAIN_VALUE) + public String isAuthenticated(Principal principal) { LOG.debug("REST request to check if the current user is authenticated"); - return request.getPrincipal().map(Principal::getName); -<%_ } else { _%> - public String isAuthenticated(HttpServletRequest request) { - LOG.debug("REST request to check if the current user is authenticated"); - return request.getRemoteUser(); -<%_ } _%> + return principal == null ? null : principal.getName(); } } diff --git a/generators/server/templates/src/main/java/_package_/web/rest/AccountResource_skipUserManagement.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/AccountResource_skipUserManagement.java.ejs similarity index 92% rename from generators/server/templates/src/main/java/_package_/web/rest/AccountResource_skipUserManagement.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/AccountResource_skipUserManagement.java.ejs index b5c8750c8e45..a8525ef35ef2 100644 --- a/generators/server/templates/src/main/java/_package_/web/rest/AccountResource_skipUserManagement.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/web/rest/AccountResource_skipUserManagement.java.ejs @@ -23,26 +23,19 @@ import <%= packageName %>.security.SecurityUtils; import <%= packageName %>.domain.Authority; <%_ } _%> + +import java.security.Principal; <%_ if (reactive) { _%> import reactor.core.publisher.Mono; -<%_ } else { _%> -import jakarta.servlet.http.HttpServletRequest; <%_ } _%> - <%_ if (authenticationTypeOauth2) { _%> import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; - <%_ if (reactive) { _%> -import org.springframework.web.server.ServerWebExchange; - <%_ } _%> <%_ } _%> <%_ if (authenticationTypeOauth2 || authenticationTypeJwt) { _%> -import java.security.Principal; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.authentication.AbstractAuthenticationToken; <%_ } else { _%> <%_ if (reactive) { _%> -import java.security.Principal; -import org.springframework.web.server.ServerWebExchange; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.userdetails.UserDetails; @@ -55,6 +48,7 @@ import org.springframework.security.core.context.SecurityContextHolder; import com.fasterxml.jackson.annotation.JsonAnyGetter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; import org.springframework.security.core.GrantedAuthority; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -147,19 +141,13 @@ public class AccountResource { /** * {@code GET /authenticate} : check if the user is authenticated, and return its login. * - * @param request the HTTP request. + * @param principal the authentication principal. * @return the login if the user is authenticated. */ - @GetMapping("/authenticate") - <%_ if (reactive) { _%> - public Mono isAuthenticated(ServerWebExchange request) { + @GetMapping(value = "/authenticate", produces = MediaType.TEXT_PLAIN_VALUE) + public String isAuthenticated(Principal principal) { LOG.debug("REST request to check if the current user is authenticated"); - return request.getPrincipal().map(Principal::getName); - <%_ } else { _%> - public String isAuthenticated(HttpServletRequest request) { - LOG.debug("REST request to check if the current user is authenticated"); - return request.getRemoteUser(); - <%_ } _%> + return principal == null ? null : principal.getName(); } <%_ } _%> diff --git a/generators/server/templates/src/main/java/_package_/web/rest/AuthInfoResource.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/AuthInfoResource.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/AuthInfoResource.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/AuthInfoResource.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/AuthenticateController.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/AuthenticateController.java.ejs similarity index 87% rename from generators/server/templates/src/main/java/_package_/web/rest/AuthenticateController.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/AuthenticateController.java.ejs index 73d029eb53fd..9c8c94892876 100644 --- a/generators/server/templates/src/main/java/_package_/web/rest/AuthenticateController.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/web/rest/AuthenticateController.java.ejs @@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -43,13 +44,11 @@ import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.JwtEncoder; import org.springframework.security.oauth2.jwt.JwtEncoderParameters; import org.springframework.web.bind.annotation.*; -<%_ if (reactive) { _%> import java.security.Principal; +<%_ if (reactive) { _%> import reactor.core.publisher.Mono; -import org.springframework.web.server.ServerWebExchange; import org.springframework.security.authentication.ReactiveAuthenticationManager; <%_ } else { _%> -import jakarta.servlet.http.HttpServletRequest; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.context.SecurityContextHolder; <%_ } _%> @@ -82,11 +81,10 @@ public class AuthenticateController { @PostMapping("/authenticate") public Mono> authorize(@Valid @RequestBody Mono loginVM) { return loginVM - .flatMap( - login -> - authenticationManager - .authenticate(new UsernamePasswordAuthenticationToken(login.getUsername(), login.getPassword())) - .flatMap(auth -> Mono.fromCallable(() -> this.createToken(auth, login.isRememberMe()))) + .flatMap(login -> + authenticationManager + .authenticate(new UsernamePasswordAuthenticationToken(login.getUsername(), login.getPassword())) + .flatMap(auth -> Mono.fromCallable(() -> this.createToken(auth, login.isRememberMe()))) ) .map(jwt -> { HttpHeaders httpHeaders = new HttpHeaders(); @@ -121,19 +119,13 @@ public class AuthenticateController { /** * {@code GET /authenticate} : check if the user is authenticated, and return its login. * - * @param request the HTTP request. + * @param principal the authentication principal. * @return the login if the user is authenticated. */ - @GetMapping("/authenticate") -<%_ if (reactive) { _%> - public Mono isAuthenticated(ServerWebExchange request) { + @GetMapping(value = "/authenticate", produces = MediaType.TEXT_PLAIN_VALUE) + public String isAuthenticated(Principal principal) { LOG.debug("REST request to check if the current user is authenticated"); - return request.getPrincipal().map(Principal::getName); -<%_ } else { _%> - public String isAuthenticated(HttpServletRequest request) { - LOG.debug("REST request to check if the current user is authenticated"); - return request.getRemoteUser(); -<%_ } _%> + return principal == null ? null : principal.getName(); } public String createToken(Authentication authentication, boolean rememberMe) { diff --git a/generators/server/templates/src/main/java/_package_/web/rest/LogoutResource_imperative.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_imperative.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/LogoutResource_imperative.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_imperative.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/LogoutResource_reactive.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_reactive.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/LogoutResource_reactive.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_reactive.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/errors/BadRequestAlertException.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/BadRequestAlertException.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/errors/BadRequestAlertException.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/BadRequestAlertException.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/errors/EmailAlreadyUsedException.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/EmailAlreadyUsedException.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/errors/EmailAlreadyUsedException.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/EmailAlreadyUsedException.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/errors/ErrorConstants.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/ErrorConstants.java.ejs similarity index 97% rename from generators/server/templates/src/main/java/_package_/web/rest/errors/ErrorConstants.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/ErrorConstants.java.ejs index c459ec0b070a..b683c32e9457 100644 --- a/generators/server/templates/src/main/java/_package_/web/rest/errors/ErrorConstants.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/ErrorConstants.java.ejs @@ -35,6 +35,5 @@ public final class ErrorConstants { public static final URI LOGIN_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/login-already-used"); <%_ } _%> - private ErrorConstants() { - } + private ErrorConstants() {} } diff --git a/generators/server/templates/src/main/java/_package_/web/rest/errors/ExceptionTranslator.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/ExceptionTranslator.java.ejs similarity index 94% rename from generators/server/templates/src/main/java/_package_/web/rest/errors/ExceptionTranslator.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/ExceptionTranslator.java.ejs index a44f55f7e1c0..184f2884d37d 100644 --- a/generators/server/templates/src/main/java/_package_/web/rest/errors/ExceptionTranslator.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/ExceptionTranslator.java.ejs @@ -180,12 +180,12 @@ _%> String title = extractTitle(err, problem.getStatus()); String problemTitle = problem.getTitle(); if (problemTitle == null || !problemTitle.equals(title)) { - problem.setTitle(title); + problem.setTitle(title); } if (problem.getDetail() == null) { // higher precedence to cause - problem.setDetail(getCustomizedErrorDetails(err)); + problem.setDetail(getCustomizedErrorDetails(err)); } Map problemProperties = problem.getProperties(); @@ -240,17 +240,13 @@ _%> // Let the ErrorResponse take this responsibility if (throwable instanceof ErrorResponse err) return HttpStatus.valueOf(err.getBody().getStatus()); - return Optional - .ofNullable(getMappedStatus(throwable)) - .orElse(Optional - .ofNullable(resolveResponseStatus(throwable)) - .map(ResponseStatus::value) - .orElse(HttpStatus.INTERNAL_SERVER_ERROR)); + return Optional.ofNullable(getMappedStatus(throwable)).orElse( + Optional.ofNullable(resolveResponseStatus(throwable)).map(ResponseStatus::value).orElse(HttpStatus.INTERNAL_SERVER_ERROR) + ); } private ResponseStatus extractResponseStatus(final Throwable throwable) { - return Optional.ofNullable(resolveResponseStatus(throwable)) - .orElse(null); + return Optional.ofNullable(resolveResponseStatus(throwable)).orElse(null); } private ResponseStatus resolveResponseStatus(final Throwable type) { @@ -259,8 +255,7 @@ _%> } private URI getMappedType(Throwable err) { - if(err instanceof MethodArgumentNotValidException) - return ErrorConstants.CONSTRAINT_VIOLATION_TYPE; + if (err instanceof MethodArgumentNotValidException) return ErrorConstants.CONSTRAINT_VIOLATION_TYPE; return ErrorConstants.DEFAULT_TYPE; } @@ -281,8 +276,7 @@ _%> } private String getCustomizedTitle(Throwable err) { - if(err instanceof MethodArgumentNotValidException) - return "Method argument not valid"; + if (err instanceof MethodArgumentNotValidException) return "Method argument not valid"; return null; } @@ -317,9 +311,15 @@ _%> } private HttpHeaders buildHeaders(Throwable err) { - return err instanceof BadRequestAlertException badRequestAlertException ? - HeaderUtil.createFailureAlert(applicationName, true, badRequestAlertException.getEntityName(), - badRequestAlertException.getErrorKey(), badRequestAlertException.getMessage()) : null; + return err instanceof BadRequestAlertException badRequestAlertException + ? HeaderUtil.createFailureAlert( + applicationName, + true, + badRequestAlertException.getEntityName(), + badRequestAlertException.getErrorKey(), + badRequestAlertException.getMessage() + ) + : null; } <%_ if (reactive) { _%> private HttpHeaders updateContentType(HttpHeaders headers) { diff --git a/generators/server/templates/src/main/java/_package_/web/rest/errors/FieldErrorVM.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/FieldErrorVM.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/errors/FieldErrorVM.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/FieldErrorVM.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/errors/InvalidPasswordException.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/InvalidPasswordException.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/errors/InvalidPasswordException.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/InvalidPasswordException.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/errors/LoginAlreadyUsedException.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/LoginAlreadyUsedException.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/errors/LoginAlreadyUsedException.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/errors/LoginAlreadyUsedException.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/vm/KeyAndPasswordVM.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/vm/KeyAndPasswordVM.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/vm/KeyAndPasswordVM.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/vm/KeyAndPasswordVM.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/vm/LoginVM.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/vm/LoginVM.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/vm/LoginVM.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/vm/LoginVM.java.ejs diff --git a/generators/server/templates/src/main/java/_package_/web/rest/vm/ManagedUserVM.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/vm/ManagedUserVM.java.ejs similarity index 100% rename from generators/server/templates/src/main/java/_package_/web/rest/vm/ManagedUserVM.java.ejs rename to generators/spring-boot/templates/src/main/java/_package_/web/rest/vm/ManagedUserVM.java.ejs diff --git a/generators/server/templates/src/main/resources/banner-no-color.txt b/generators/spring-boot/templates/src/main/resources/banner-no-color.txt similarity index 100% rename from generators/server/templates/src/main/resources/banner-no-color.txt rename to generators/spring-boot/templates/src/main/resources/banner-no-color.txt diff --git a/generators/server/templates/src/main/resources/banner.txt b/generators/spring-boot/templates/src/main/resources/banner.txt similarity index 100% rename from generators/server/templates/src/main/resources/banner.txt rename to generators/spring-boot/templates/src/main/resources/banner.txt diff --git a/generators/server/templates/src/main/resources/banner_react.txt b/generators/spring-boot/templates/src/main/resources/banner_react.txt similarity index 100% rename from generators/server/templates/src/main/resources/banner_react.txt rename to generators/spring-boot/templates/src/main/resources/banner_react.txt diff --git a/generators/server/templates/src/main/resources/banner_vue.txt b/generators/spring-boot/templates/src/main/resources/banner_vue.txt similarity index 100% rename from generators/server/templates/src/main/resources/banner_vue.txt rename to generators/spring-boot/templates/src/main/resources/banner_vue.txt diff --git a/generators/server/templates/src/main/resources/config/application-dev.yml.ejs b/generators/spring-boot/templates/src/main/resources/config/application-dev.yml.ejs similarity index 96% rename from generators/server/templates/src/main/resources/config/application-dev.yml.ejs rename to generators/spring-boot/templates/src/main/resources/config/application-dev.yml.ejs index a991975404b3..fa5dce97ca53 100644 --- a/generators/server/templates/src/main/resources/config/application-dev.yml.ejs +++ b/generators/spring-boot/templates/src/main/resources/config/application-dev.yml.ejs @@ -87,6 +87,13 @@ spring: additional-exclude: static/**<% if (devDatabaseTypeH2Any) { %>,.h2.server.properties<% } %> livereload: enabled: false # we use Webpack dev server + BrowserSync for livereload +<%_ if (devDatabaseTypeH2Any && 'dockerServices' in locals && dockerServices && dockerServices.length > 1) { _%> + docker: + compose: + enabled: <%- authenticationTypeOauth2 || messageBrokerAny || serviceDiscoveryAny || cacheProviderRedis %> + profiles: + active: dev +<%_ } _%> jackson: serialization: indent-output: true @@ -148,8 +155,12 @@ spring: <%_ if (devDatabaseTypeH2Any) { _%> h2: console: - # disable spring boot built-in h2-console since we start it manually with correct configuration - enabled: false + # JHipster uses a custom h2-console initializer + <%_ if (graalvmSupport) { _%> + enabled: '@spring.h2.console.enabled@' + <%_ } else { _%> + enabled: true + <%_ } _%> <%_ } _%> <%_ if (databaseTypeMongodb) { _%> data: diff --git a/generators/server/templates/src/main/resources/config/application-prod.yml.ejs b/generators/spring-boot/templates/src/main/resources/config/application-prod.yml.ejs similarity index 100% rename from generators/server/templates/src/main/resources/config/application-prod.yml.ejs rename to generators/spring-boot/templates/src/main/resources/config/application-prod.yml.ejs diff --git a/generators/server/templates/src/main/resources/config/application-tls.yml.ejs b/generators/spring-boot/templates/src/main/resources/config/application-tls.yml.ejs similarity index 100% rename from generators/server/templates/src/main/resources/config/application-tls.yml.ejs rename to generators/spring-boot/templates/src/main/resources/config/application-tls.yml.ejs diff --git a/generators/server/templates/src/main/resources/config/application.yml.ejs b/generators/spring-boot/templates/src/main/resources/config/application.yml.ejs similarity index 97% rename from generators/server/templates/src/main/resources/config/application.yml.ejs rename to generators/spring-boot/templates/src/main/resources/config/application.yml.ejs index 01fad331516d..f2c49128b53a 100644 --- a/generators/server/templates/src/main/resources/config/application.yml.ejs +++ b/generators/spring-boot/templates/src/main/resources/config/application.yml.ejs @@ -161,6 +161,8 @@ management: repository: autotime: enabled: true + tags: + application: ${spring.application.name} <%_ if (databaseTypeMongodb) { _%> mongock: @@ -266,6 +268,17 @@ spring: content-type: text/plain group: <%= dasherizedBaseName %> <%_ } _%> +<%_ } _%> +<%_ if ('dockerServices' in locals && dockerServices && dockerServices.length > 1) { _%> + docker: + compose: + enabled: true + lifecycle-management: start-only + <%_ if (applicationTypeMicroservice) { _%> + file: <%- dockerServicesDir %><%- databaseTypeSql ? prodDatabaseType : databaseType %>.yml + <%_ } else { _%> + file: <%- dockerServicesDir %>services.yml + <%_ } _%> <%_ } _%> profiles: # The commented value for `active` can be replaced with valid Spring profiles to load. diff --git a/generators/server/templates/src/main/resources/config/bootstrap-prod.yml.ejs b/generators/spring-boot/templates/src/main/resources/config/bootstrap-prod.yml.ejs similarity index 100% rename from generators/server/templates/src/main/resources/config/bootstrap-prod.yml.ejs rename to generators/spring-boot/templates/src/main/resources/config/bootstrap-prod.yml.ejs diff --git a/generators/server/templates/src/main/resources/config/bootstrap.yml.ejs b/generators/spring-boot/templates/src/main/resources/config/bootstrap.yml.ejs similarity index 90% rename from generators/server/templates/src/main/resources/config/bootstrap.yml.ejs rename to generators/spring-boot/templates/src/main/resources/config/bootstrap.yml.ejs index 0de7ea411745..b89fd57317b5 100644 --- a/generators/server/templates/src/main/resources/config/bootstrap.yml.ejs +++ b/generators/spring-boot/templates/src/main/resources/config/bootstrap.yml.ejs @@ -59,4 +59,13 @@ spring: profile: dev # profile(s) of the property source label: main # toggle to switch to a different version of the configuration as stored in git # it can be set to any label, branch or commit of the configuration source Git repository +<%_ } _%> + docker: + compose: + enabled: true + lifecycle-management: start-only +<%_ if (applicationTypeMicroservice) { _%> + file: <%- dockerServicesDir %><%- databaseTypeSql ? prodDatabaseType : databaseType %>.yml +<%_ } else { _%> + file: <%- dockerServicesDir %>services.yml <%_ } _%> diff --git a/generators/server/templates/src/main/resources/i18n/messages.properties.ejs b/generators/spring-boot/templates/src/main/resources/i18n/messages.properties.ejs similarity index 100% rename from generators/server/templates/src/main/resources/i18n/messages.properties.ejs rename to generators/spring-boot/templates/src/main/resources/i18n/messages.properties.ejs diff --git a/generators/server/templates/src/main/resources/logback-spring.xml.ejs b/generators/spring-boot/templates/src/main/resources/logback-spring.xml.ejs similarity index 97% rename from generators/server/templates/src/main/resources/logback-spring.xml.ejs rename to generators/spring-boot/templates/src/main/resources/logback-spring.xml.ejs index c543fd443832..4bda6373aca7 100644 --- a/generators/server/templates/src/main/resources/logback-spring.xml.ejs +++ b/generators/spring-boot/templates/src/main/resources/logback-spring.xml.ejs @@ -169,6 +169,9 @@ + + + true diff --git a/generators/server/templates/src/main/resources/static/index_microservices.html.ejs b/generators/spring-boot/templates/src/main/resources/static/index_microservices.html.ejs similarity index 100% rename from generators/server/templates/src/main/resources/static/index_microservices.html.ejs rename to generators/spring-boot/templates/src/main/resources/static/index_microservices.html.ejs diff --git a/generators/server/templates/src/main/resources/templates/error.html.ejs b/generators/spring-boot/templates/src/main/resources/templates/error.html.ejs similarity index 100% rename from generators/server/templates/src/main/resources/templates/error.html.ejs rename to generators/spring-boot/templates/src/main/resources/templates/error.html.ejs diff --git a/generators/server/templates/src/main/resources/templates/mail/activationEmail.html.ejs b/generators/spring-boot/templates/src/main/resources/templates/mail/activationEmail.html.ejs similarity index 100% rename from generators/server/templates/src/main/resources/templates/mail/activationEmail.html.ejs rename to generators/spring-boot/templates/src/main/resources/templates/mail/activationEmail.html.ejs diff --git a/generators/server/templates/src/main/resources/templates/mail/creationEmail.html.ejs b/generators/spring-boot/templates/src/main/resources/templates/mail/creationEmail.html.ejs similarity index 100% rename from generators/server/templates/src/main/resources/templates/mail/creationEmail.html.ejs rename to generators/spring-boot/templates/src/main/resources/templates/mail/creationEmail.html.ejs diff --git a/generators/server/templates/src/main/resources/templates/mail/passwordResetEmail.html.ejs b/generators/spring-boot/templates/src/main/resources/templates/mail/passwordResetEmail.html.ejs similarity index 100% rename from generators/server/templates/src/main/resources/templates/mail/passwordResetEmail.html.ejs rename to generators/spring-boot/templates/src/main/resources/templates/mail/passwordResetEmail.html.ejs diff --git a/generators/server/templates/src/test/java/_package_/IntegrationTest.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/IntegrationTest.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/IntegrationTest.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/IntegrationTest.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/TechnicalStructureTest.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/TechnicalStructureTest.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/TechnicalStructureTest.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/TechnicalStructureTest.java.ejs diff --git a/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/service/UserServiceIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/service/UserServiceIT.java.ejs index 9f5188226d47..a991adf903cb 100644 --- a/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/service/UserServiceIT.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/service/UserServiceIT.java.ejs @@ -547,7 +547,11 @@ class UserServiceIT { private OAuth2AuthenticationToken createMockOAuth2AuthenticationToken(Map userDetails) { Collection authorities = Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); - UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities); + UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken( + "anonymous", + "anonymous", + authorities + ); usernamePasswordAuthenticationToken.setDetails(userDetails); OAuth2User user = new DefaultOAuth2User(authorities, userDetails, "sub"); diff --git a/generators/server/templates/src/test/java/_package_/_entityPackage_/service/dto/_dtoClass_Test.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/service/dto/_dtoClass_Test.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/_entityPackage_/service/dto/_dtoClass_Test.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/service/dto/_dtoClass_Test.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/_entityPackage_/service/mapper/_entityClass_MapperTest.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/service/mapper/_entityClass_MapperTest.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/_entityPackage_/service/mapper/_entityClass_MapperTest.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/service/mapper/_entityClass_MapperTest.java.ejs diff --git a/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/PublicUserResourceIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/PublicUserResourceIT.java.ejs index b845922e078d..404a8143e018 100644 --- a/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/PublicUserResourceIT.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/PublicUserResourceIT.java.ejs @@ -75,9 +75,6 @@ import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Mono; <%_ } _%> -<%_ if (databaseTypeSql && !reactive) { _%> -import jakarta.persistence.EntityManager; -<%_ } _%> <%_ if (databaseTypeCassandra || databaseTypeCouchbase) { _%> import java.util.stream.Stream; <%_ } _%> @@ -130,11 +127,6 @@ class PublicUserResourceIT { @Autowired private UserSearchRepository mockUserSearchRepository; <%_ } _%> -<%_ if (databaseTypeSql) { _%> - - @Autowired - private EntityManager em; -<%_ } _%> <%_ if (cacheProviderAny) { _%> @Autowired @@ -168,7 +160,7 @@ class PublicUserResourceIT { <%_ } _%> @BeforeEach public void initTest() { - user = UserResourceIT.initTestUser(<% if (databaseTypeSql) { %>em<% } %>); + user = UserResourceIT.initTestUser(); } @AfterEach diff --git a/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/UserResourceIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/UserResourceIT.java.ejs index ce6b9ba026c6..e845f16e570c 100644 --- a/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/UserResourceIT.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/UserResourceIT.java.ejs @@ -226,7 +226,7 @@ class UserResourceIT { * This is a static method, as tests for other entities might also need it, * if they test an entity which has a required relationship to the User entity. */ - public static <%= user.persistClass %> createEntity(<% if (databaseTypeSql) { %>EntityManager em<% } %>) { + public static <%= user.persistClass %> createEntity() { <%= user.persistClass %> persistUser = new <%= user.persistClass %>(); <%_ if (databaseTypeCassandra || (authenticationTypeOauth2 && !databaseTypeCouchbase)) { _%> persistUser.setId(UUID.randomUUID().toString()); @@ -260,8 +260,8 @@ class UserResourceIT { /** * Setups the database with one user. */ - public static <%= user.persistClass %> initTestUser(<% if (databaseTypeSql) { %>EntityManager em<% } _%>) { - <%= user.persistClass %> persistUser = createEntity(<% if (databaseTypeSql ) { %>em<% } _%>); + public static <%= user.persistClass %> initTestUser() { + <%= user.persistClass %> persistUser = createEntity(); <%_ if (databaseTypeSql) { _%> persistUser.setLogin(DEFAULT_LOGIN); persistUser.setEmail(DEFAULT_EMAIL); @@ -271,7 +271,7 @@ class UserResourceIT { @BeforeEach public void initTest() { - user = initTestUser(<% if (databaseTypeSql) { %>em<% } _%>); + user = initTestUser(); } @AfterEach @@ -460,7 +460,7 @@ class UserResourceIT { userDTO.setLogin("anotherlogin"); userDTO.setFirstName(DEFAULT_FIRSTNAME); userDTO.setLastName(DEFAULT_LASTNAME); - userDTO.setEmail(DEFAULT_EMAIL);// this email should already be used + userDTO.setEmail(DEFAULT_EMAIL); // this email should already be used userDTO.setActivated(true); <%_ if (!databaseTypeCassandra) { _%> userDTO.setImageUrl(DEFAULT_IMAGEURL); @@ -759,7 +759,7 @@ class UserResourceIT { userDTO.setLogin(updatedUser.getLogin()); userDTO.setFirstName(updatedUser.getFirstName()); userDTO.setLastName(updatedUser.getLastName()); - userDTO.setEmail("jhipster@localhost");// this email should already be used by anotherUser + userDTO.setEmail("jhipster@localhost"); // this email should already be used by anotherUser userDTO.setActivated(updatedUser.isActivated()); <%_ if (!databaseTypeCassandra) { _%> userDTO.setImageUrl(updatedUser.getImageUrl()); @@ -826,7 +826,7 @@ class UserResourceIT { <%= user.adminUserDto %> userDTO = new <%= user.adminUserDto %>(); userDTO.setId(updatedUser.getId()); - userDTO.setLogin("jhipster");// this login should already be used by anotherUser + userDTO.setLogin("jhipster"); // this login should already be used by anotherUser userDTO.setFirstName(updatedUser.getFirstName()); userDTO.setLastName(updatedUser.getLastName()); userDTO.setEmail(updatedUser.getEmail()); diff --git a/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/_entityClass_ResourceIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/_entityClass_ResourceIT.java.ejs index c9e272fafaa3..d0924e51658b 100644 --- a/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/_entityClass_ResourceIT.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/_entityClass_ResourceIT.java.ejs @@ -329,24 +329,25 @@ if (field.fieldTypeString || field.blobContentTypeText) { // Generate Strings, using pattern try { const patternRegExp = new RegExp(field.fieldValidateRulesPattern); - const randExp = field.createRandexp(); // set infinite repetitions max range if (!patternRegExp.test(sampleTextString.replace(/\\"/g, '"').replace(/\\\\/g, '\\'))) { - sampleTextString = randExp.gen().replace(/\\/g, '\\\\').replace(/"/g, '\\"'); + const value = field.generateFakeDataFromPattern(); + sampleTextString = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); } if (!patternRegExp.test(updatedTextString.replace(/\\"/g, '"').replace(/\\\\/g, '\\'))) { - updatedTextString = randExp.gen().replace(/\\/g, '\\\\').replace(/"/g, '\\"'); + const value = field.generateFakeDataFromPattern(); + updatedTextString = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); } } catch (error) { - log(this.chalkRed('Error generating test value for entity "' + entityClass + + this.log.warn('Error generating test value for entity "' + entityClass + '" field "' + field.fieldName + '" with pattern "' + field.fieldValidateRulesPattern + - '", generating default values for this field. Detailed error message: "' + error.message + '".')); + '", generating default values for this field. Detailed error message: "' + error.message + '".'); } if (sampleTextString === updatedTextString) { updatedTextString = updatedTextString + "B"; - log(this.chalkRed('Randomly generated first and second test values for entity "' + entityClass + + this.log.warn('Randomly generated first and second test values for entity "' + entityClass + '" field "' + field.fieldName + '" with pattern "' + field.fieldValidateRulesPattern + - '" in file "' + entityClass + 'ResourceIT" where equal, added symbol "B" to second value.')); + '" in file "' + entityClass + 'ResourceIT" where equal, added symbol "B" to second value.'); } } _%> @@ -516,42 +517,51 @@ filterTestableRelationships.filter(rel => !rel.otherEntity.builtInUser).forEach( <%_ }); }_%> <%_ ['DEFAULT_', 'UPDATED_'].forEach((fieldStatus) => { _%> +<%_ const createInstance = fieldStatus === 'UPDATED_' ? `updated${persistClass}` : persistInstance; _%> /** * Create an <% if (fieldStatus === 'UPDATED_') { %>updated <% } %>entity for this test. * * This is a static method, as tests for other entities might also need it, * if they test an entity which requires the current entity. */ - public static <%= persistClass %> create<% if (fieldStatus === 'UPDATED_') { _%>Updated<%_ } %>Entity(<% if (databaseTypeSql) { %>EntityManager em<% } %>) { + public static <%= persistClass %> create<% if (fieldStatus === 'UPDATED_') { _%>Updated<%_ } %>Entity(<% if (databaseTypeSql && anyRelationshipIsRequired) { %>EntityManager em<% } %>) { <%_ if (fluentMethods) { _%> - <%= persistClass %> <%= persistInstance %> = new <%= persistClass %>() + <% if (!anyRelationshipIsRequired) { %>return <% } else { %><%= persistClass %> <%= createInstance %> = <% } %>new <%= persistClass %>() <%_ if (reactive && databaseTypeSql && primaryKey.typeUUID && !isUsingMapsId) { _%> .<%= primaryKey.name %>(UUID.randomUUID()) <%_ } _%> <%_ if (primaryKey.typeString && !isUsingMapsId && !primaryKey.autoGenerate) { _%> .<%= primaryKey.name %>(UUID.randomUUID().toString()) <%_ } _%> - <% for (field of fieldsToTest) { %> - .<%= field.fieldName %>(<%= fieldStatus + field.fieldNameUnderscored.toUpperCase() %>)<% if (field.fieldTypeBinary && !field.blobContentTypeText) { %> - .<%= field.fieldName %>ContentType(<%= fieldStatus + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE)<% } %><% } %>; + <%_ for (field of fieldsToTest) { _%> + .<%= field.fieldName %>(<%= fieldStatus + field.fieldNameUnderscored.toUpperCase() %>) + <%_ if (field.fieldTypeBinary && !field.blobContentTypeText) { _%> + .<%= field.fieldName %>ContentType(<%= fieldStatus + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE) + <%_ } _%> + <%_ } _%>; + <%_ if (!anyRelationshipIsRequired) { _%> + } + <%_ return; _%> + <%_ } _%> <%_ } else { _%> - <%= persistClass %> <%= persistInstance %> = new <%= persistClass %>(); + <%= persistClass %> <%= createInstance %> = new <%= persistClass %>(); <%_ if (reactive && databaseTypeSql && primaryKey.typeUUID && !isUsingMapsId) { _%> - <%= persistInstance %>.set<%= primaryKey.fields[0].fieldInJavaBeanMethod %>(UUID.randomUUID()); + <%= createInstance %>.set<%= primaryKey.fields[0].fieldInJavaBeanMethod %>(UUID.randomUUID()); <%_ } _%> <%_ if (primaryKey.typeString && !isUsingMapsId && !primaryKey.autoGenerate) { _%> - <%= persistInstance %>.set<%= primaryKey.fields[0].fieldInJavaBeanMethod %>(UUID.randomUUID().toString()); + <%= createInstance %>.set<%= primaryKey.fields[0].fieldInJavaBeanMethod %>(UUID.randomUUID().toString()); <%_ } _%> <%_ for (field of fieldsToTest) { _%> - <%= persistInstance %>.set<%= field.fieldInJavaBeanMethod %>(<%= fieldStatus + field.fieldNameUnderscored.toUpperCase() %>); + <%= createInstance %>.set<%= field.fieldInJavaBeanMethod %>(<%= fieldStatus + field.fieldNameUnderscored.toUpperCase() %>); <%_ if (field.fieldTypeBinary && !field.blobContentTypeText) { _%> - <%= persistInstance %>.set<%= field.fieldInJavaBeanMethod %>ContentType(<%= fieldStatus + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE); + <%= createInstance %>.set<%= field.fieldInJavaBeanMethod %>ContentType(<%= fieldStatus + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE); <%_ } _%> <%_ } _%> <%_ } _%> <%_ const alreadyGeneratedEntities = []; for (relationship of persistableRelationships) { + const otherEntity = relationship.otherEntity; const relationshipValidate = relationship.relationshipValidate; const otherEntityName = relationship.otherEntityName; const otherEntityNameCapitalized = relationship.otherEntityNameCapitalized; @@ -562,7 +572,7 @@ filterTestableRelationships.filter(rel => !rel.otherEntity.builtInUser).forEach( // Add required entity <%_ if (alreadyGeneratedEntities.indexOf(otherEntityName) == -1) { _%> <%_ if (relationship.otherEntityUser) { /* TODO or other entity has no unique fields */ _%> - <%= relationship.otherEntity.persistClass %> <%= otherEntityName %> = <%= createEntityPrefix %><%= otherEntityNameCapitalized %>ResourceIT.createEntity(<% if (databaseTypeSql) { %>em<% } %>)<%= createEntityPostfix %>; + <%= relationship.otherEntity.persistClass %> <%= otherEntityName %> = <%= createEntityPrefix %><%= otherEntityNameCapitalized %>ResourceIT.createEntity(<% if (databaseTypeSql && otherEntity.anyRelationshipIsRequired) { %>em<% } %>)<%= createEntityPostfix %>; <%_ if (databaseTypeSql && !reactive) { _%> em.persist(<%= otherEntityName %>); em.flush(); @@ -576,7 +586,7 @@ filterTestableRelationships.filter(rel => !rel.otherEntity.builtInUser).forEach( <%_ if (!isUsingMapsId || fieldStatus !== "UPDATED_") { _%> if (TestUtil.findAll(em, <%= relationship.otherEntity.persistClass %>.class).isEmpty()) { <%_ } _%> - <%= otherEntityName %> = <%= createEntityPrefix %><%= otherEntityNameCapitalized %>ResourceIT.create<% if (fieldStatus === 'UPDATED_') { %>Updated<% } %>Entity(em)<%= createEntityPostfix %>; + <%= otherEntityName %> = <%= createEntityPrefix %><%= otherEntityNameCapitalized %>ResourceIT.create<% if (fieldStatus === 'UPDATED_') { %>Updated<% } %>Entity(<% if (relationship.otherEntity.anyRelationshipIsRequired) { %>em<% } %>)<%= createEntityPostfix %>; em.persist(<%= otherEntityName %>); em.flush(); <%_ if (!isUsingMapsId || fieldStatus !== "UPDATED_") { _%> @@ -585,7 +595,7 @@ filterTestableRelationships.filter(rel => !rel.otherEntity.builtInUser).forEach( } <%_ } _%> <%_ } else { _%> - <%= otherEntityName %> = <%= createEntityPrefix %><%= otherEntityNameCapitalized %>ResourceIT.create<% if (fieldStatus === 'UPDATED_') { %>Updated<% } %>Entity(<% if (databaseType === 'sql') { %>em<% } %>)<%= createEntityPostfix %>; + <%= otherEntityName %> = <%= createEntityPrefix %><%= otherEntityNameCapitalized %>ResourceIT.create<% if (fieldStatus === 'UPDATED_') { %>Updated<% } %>Entity(<% if (databaseType === 'sql' && otherEntity.anyRelationshipIsRequired) { %>em<% } %>)<%= createEntityPostfix %>; <%_ } _%> <%_ if (databaseTypeMongodb) { _%> <%= otherEntityName %>.set<%= primaryKey.nameCapitalized %>("fixed-id-for-tests"); @@ -593,14 +603,14 @@ filterTestableRelationships.filter(rel => !rel.otherEntity.builtInUser).forEach( <%_ } _%> <%_ } _%> <%_ if (relationship.relationshipManyToMany || relationship.relationshipOneToMany) { _%> - <%= persistInstance %>.get<%= relationshipNameCapitalizedPlural %>().add(<%= otherEntityName %>); + <%= createInstance %>.get<%= relationshipNameCapitalizedPlural %>().add(<%= otherEntityName %>); <%_ } else { _%> - <%= persistInstance %>.set<%= relationshipNameCapitalized %>(<%= otherEntityName %>); + <%= createInstance %>.set<%= relationshipNameCapitalized %>(<%= otherEntityName %>); <%_ } _%> <%_ alreadyGeneratedEntities.push(otherEntityName) _%> <%_ } _%> <%_ } _%> - return <%= persistInstance %>; + return <%= createInstance %>; } <%_ }); _%> @@ -636,7 +646,7 @@ _%> <%_ } _%> @BeforeEach public void initTest() { - <%= persistInstance %> = createEntity(<% if (databaseTypeSql) { %>em<% } %>); + <%= persistInstance %> = createEntity(<% if (databaseTypeSql && anyRelationshipIsRequired) { %>em<% } %>); } @AfterEach @@ -789,13 +799,14 @@ _%> int searchDatabaseSizeBefore = IterableUtil.sizeOf(<%= entityInstance %>SearchRepository.findAll()<%= callListBlock %>); <%_ } _%> <%_ for (relationship of relationships) { + const otherEntity = relationship.otherEntity; const otherEntityName = relationship.otherEntityName; const otherEntityNameCapitalized = relationship.otherEntityNameCapitalized; const mapsIdUse = relationship.id; if (mapsIdUse) { _%> // Add a new parent entity <%_ if (alreadyGeneratedEntities.indexOf(otherEntityName) == -1) { _%> - <%= relationship.otherEntity.persistClass %> <%= otherEntityName %> = <%= otherEntityNameCapitalized %>ResourceIT.create<% if (!relationship.otherEntityUser) { _%>Updated<%_ } %>Entity(<% if (databaseTypeSql) { %>em<% } %>); + <%= relationship.otherEntity.persistClass %> <%= otherEntityName %> = <%= otherEntityNameCapitalized %>ResourceIT.create<% if (!relationship.otherEntityUser) { _%>Updated<%_ } %>Entity(<% if (databaseTypeSql && otherEntity.anyRelationshipIsRequired) { %>em<% } %>); <%_ if (databaseTypeSql && !reactive) { _%> em.persist(<%= otherEntityName %>); em.flush(); @@ -1232,12 +1243,12 @@ _%> <%= relationship.otherEntity.persistClass %> <%= relationship.relationshipFieldName %>; if (TestUtil.findAll(em, <%= relationship.otherEntity.persistClass %>.class).isEmpty()) { <%= entityInstance %>Repository.saveAndFlush(<%= persistInstance %>); - <%= relationship.relationshipFieldName %> = <%= createEntityPrefix %><%= relationship.otherEntityNameCapitalized %>ResourceIT.createEntity(em); + <%= relationship.relationshipFieldName %> = <%= createEntityPrefix %><%= relationship.otherEntityNameCapitalized %>ResourceIT.createEntity(<% if (relationship.otherEntity.anyRelationshipIsRequired) { %>em<% } %>); } else { <%= relationship.relationshipFieldName %> = TestUtil.findAll(em, <%= relationship.otherEntity.persistClass %>.class).get(0); } <%_ } else { _%> - <%= relationship.otherEntity.persistClass %> <%= relationship.relationshipFieldName %> = <%= relationship.otherEntityNameCapitalized %>ResourceIT.createEntity(em); + <%= relationship.otherEntity.persistClass %> <%= relationship.relationshipFieldName %> = <%= relationship.otherEntityNameCapitalized %>ResourceIT.createEntity(<% if (relationship.otherEntity.anyRelationshipIsRequired) { %>em<% } %>); <%_ } _%> <%_ if(reactive) { _%> <%= relationship.otherEntity.persistInstance %>Repository.<%= saveMethod %>(<%= relationship.relationshipFieldName %>)<%= callBlock %>; @@ -1889,7 +1900,7 @@ _%> } protected void assertSameRepositoryCount(long countBefore) { - assertThat(countBefore).isEqualTo(getRepositoryCount()); + assertThat(countBefore).isEqualTo(getRepositoryCount()); } protected <%- persistClass %> getPersisted<%- persistClass %>(<%- persistClass %> <%- entityInstance %>) { diff --git a/generators/server/templates/src/test/java/_package_/config/AsyncSyncConfiguration.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/config/AsyncSyncConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/config/AsyncSyncConfiguration.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/config/AsyncSyncConfiguration.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/config/CRLFLogConverterTest.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/config/CRLFLogConverterTest.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/config/CRLFLogConverterTest.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/config/CRLFLogConverterTest.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/config/JHipsterBlockHoundIntegration.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/config/JHipsterBlockHoundIntegration.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/config/JHipsterBlockHoundIntegration.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/config/JHipsterBlockHoundIntegration.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/config/SpringBootTestClassOrderer.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/config/SpringBootTestClassOrderer.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/config/SpringBootTestClassOrderer.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/config/SpringBootTestClassOrderer.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/config/StaticResourcesWebConfigurerTest.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/config/StaticResourcesWebConfigurerTest.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/config/StaticResourcesWebConfigurerTest.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/config/StaticResourcesWebConfigurerTest.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/config/TestContainersSpringContextCustomizerFactory.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/config/TestContainersSpringContextCustomizerFactory.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/config/TestContainersSpringContextCustomizerFactory.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/config/TestContainersSpringContextCustomizerFactory.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/config/TestSecurityConfiguration.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/config/TestSecurityConfiguration.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/config/TestSecurityConfiguration.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/config/TestSecurityConfiguration.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/config/WebConfigurerTest.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/config/WebConfigurerTest.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/config/WebConfigurerTest.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/config/WebConfigurerTest.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/config/WebConfigurerTestController.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/config/WebConfigurerTestController.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/config/WebConfigurerTestController.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/config/WebConfigurerTestController.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/management/SecurityMetersServiceTests.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/management/SecurityMetersServiceTests.java.ejs similarity index 99% rename from generators/server/templates/src/test/java/_package_/management/SecurityMetersServiceTests.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/management/SecurityMetersServiceTests.java.ejs index 31dbad76fdd6..f84bb9c67919 100644 --- a/generators/server/templates/src/test/java/_package_/management/SecurityMetersServiceTests.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/management/SecurityMetersServiceTests.java.ejs @@ -18,16 +18,14 @@ -%> package <%= packageName %>.management; +import static org.assertj.core.api.Assertions.assertThat; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import java.util.Collection; -import static org.assertj.core.api.Assertions.assertThat; - class SecurityMetersServiceTests { private static final String INVALID_TOKENS_METER_EXPECTED_NAME = "security.authentication.invalid-tokens"; diff --git a/generators/server/templates/src/test/java/_package_/security/DomainUserDetailsServiceIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/security/DomainUserDetailsServiceIT.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/security/DomainUserDetailsServiceIT.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/security/DomainUserDetailsServiceIT.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_imperative.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_imperative.java.ejs similarity index 96% rename from generators/server/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_imperative.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_imperative.java.ejs index a385cd5ba420..254c98c8568a 100644 --- a/generators/server/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_imperative.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_imperative.java.ejs @@ -91,12 +91,14 @@ class SecurityUtilsUnitTest { Map claims = new HashMap<>(); claims.put("groups", Arrays.asList(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)); - List expectedAuthorities = Arrays.asList(new SimpleGrantedAuthority(AuthoritiesConstants.ADMIN), new SimpleGrantedAuthority(AuthoritiesConstants.USER)); + List expectedAuthorities = Arrays.asList( + new SimpleGrantedAuthority(AuthoritiesConstants.ADMIN), + new SimpleGrantedAuthority(AuthoritiesConstants.USER) + ); List authorities = SecurityUtils.extractAuthorityFromClaims(claims); - assertThat(authorities).isNotNull().isNotEmpty().hasSize(2) - .containsAll(expectedAuthorities); + assertThat(authorities).isNotNull().isNotEmpty().hasSize(2).containsAll(expectedAuthorities); } @Test @@ -104,7 +106,10 @@ class SecurityUtilsUnitTest { Map claims = new HashMap<>(); claims.put(SecurityUtils.CLAIMS_NAMESPACE + "roles", Arrays.asList(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)); - List expectedAuthorities = Arrays.asList(new SimpleGrantedAuthority(AuthoritiesConstants.ADMIN), new SimpleGrantedAuthority(AuthoritiesConstants.USER)); + List expectedAuthorities = Arrays.asList( + new SimpleGrantedAuthority(AuthoritiesConstants.ADMIN), + new SimpleGrantedAuthority(AuthoritiesConstants.USER) + ); List authorities = SecurityUtils.extractAuthorityFromClaims(claims); diff --git a/generators/server/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_reactive.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_reactive.java.ejs similarity index 90% rename from generators/server/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_reactive.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_reactive.java.ejs index 30daf3c349e8..7f6f34fd0f96 100644 --- a/generators/server/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_reactive.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/security/SecurityUtilsUnitTest_reactive.java.ejs @@ -48,11 +48,7 @@ class SecurityUtilsUnitTest { @Test void testgetCurrentUserLogin() { String login = SecurityUtils.getCurrentUserLogin() - .contextWrite( - ReactiveSecurityContextHolder.withAuthentication( - new UsernamePasswordAuthenticationToken("admin", "admin") - ) - ) + .contextWrite(ReactiveSecurityContextHolder.withAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin"))) .block(); assertThat(login).isEqualTo("admin"); } @@ -61,11 +57,7 @@ class SecurityUtilsUnitTest { @Test void testgetCurrentUserJWT() { String jwt = SecurityUtils.getCurrentUserJWT() - .contextWrite( - ReactiveSecurityContextHolder.withAuthentication( - new UsernamePasswordAuthenticationToken("admin", "token") - ) - ) + .contextWrite(ReactiveSecurityContextHolder.withAuthentication(new UsernamePasswordAuthenticationToken("admin", "token"))) .block(); assertThat(jwt).isEqualTo("token"); } @@ -74,11 +66,7 @@ class SecurityUtilsUnitTest { @Test void testIsAuthenticated() { Boolean isAuthenticated = SecurityUtils.isAuthenticated() - .contextWrite( - ReactiveSecurityContextHolder.withAuthentication( - new UsernamePasswordAuthenticationToken("admin", "admin") - ) - ) + .contextWrite(ReactiveSecurityContextHolder.withAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin"))) .block(); assertThat(isAuthenticated).isTrue(); } diff --git a/generators/server/templates/src/test/java/_package_/security/jwt/AuthenticationIntegrationTest.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/security/jwt/AuthenticationIntegrationTest.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/security/jwt/AuthenticationIntegrationTest.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/security/jwt/AuthenticationIntegrationTest.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/security/jwt/JwtAuthenticationTestUtils.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/security/jwt/JwtAuthenticationTestUtils.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/security/jwt/JwtAuthenticationTestUtils.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/security/jwt/JwtAuthenticationTestUtils.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/security/jwt/TestAuthenticationResource.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/security/jwt/TestAuthenticationResource.java.ejs similarity index 78% rename from generators/server/templates/src/test/java/_package_/security/jwt/TestAuthenticationResource.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/security/jwt/TestAuthenticationResource.java.ejs index c3aed5b1f010..dd79577de29e 100644 --- a/generators/server/templates/src/test/java/_package_/security/jwt/TestAuthenticationResource.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/security/jwt/TestAuthenticationResource.java.ejs @@ -1,5 +1,6 @@ package <%= packageName %>.security.jwt; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; /** @@ -14,7 +15,7 @@ public class TestAuthenticationResource { * * @return ok. */ - @GetMapping("/authenticate") + @GetMapping(value = "/authenticate", produces = MediaType.TEXT_PLAIN_VALUE) public String isAuthenticated() { return "ok"; } diff --git a/generators/server/templates/src/test/java/_package_/security/jwt/TokenAuthenticationIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/security/jwt/TokenAuthenticationIT.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/security/jwt/TokenAuthenticationIT.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/security/jwt/TokenAuthenticationIT.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/security/jwt/TokenAuthenticationSecurityMetersIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/security/jwt/TokenAuthenticationSecurityMetersIT.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/security/jwt/TokenAuthenticationSecurityMetersIT.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/security/jwt/TokenAuthenticationSecurityMetersIT.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/security/oauth2/AudienceValidatorTest.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/security/oauth2/AudienceValidatorTest.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/security/oauth2/AudienceValidatorTest.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/security/oauth2/AudienceValidatorTest.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/security/oauth2/CustomClaimConverterIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/security/oauth2/CustomClaimConverterIT.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/security/oauth2/CustomClaimConverterIT.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/security/oauth2/CustomClaimConverterIT.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/service/MailServiceIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/service/MailServiceIT.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/service/MailServiceIT.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/service/MailServiceIT.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/service/mapper/UserMapperTest.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/service/mapper/UserMapperTest.java.ejs similarity index 96% rename from generators/server/templates/src/test/java/_package_/service/mapper/UserMapperTest.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/service/mapper/UserMapperTest.java.ejs index fea1a4b9ef7e..a42f866ab60d 100644 --- a/generators/server/templates/src/test/java/_package_/service/mapper/UserMapperTest.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/service/mapper/UserMapperTest.java.ejs @@ -153,9 +153,7 @@ class UserMapperTest { List<<%= user.dtoClass %>> userDTOS = userMapper.usersToUserDTOs(users); - assertThat(userDTOS) - .isNotEmpty() - .size().isEqualTo(1); + assertThat(userDTOS).isNotEmpty().size().isEqualTo(1); } @Test @@ -166,9 +164,7 @@ class UserMapperTest { List<<%= user.persistClass %>> users = userMapper.userDTOsToUsers(usersDto); - assertThat(users) - .isNotEmpty() - .size().isEqualTo(1); + assertThat(users).isNotEmpty().size().isEqualTo(1); } @Test @@ -182,9 +178,7 @@ class UserMapperTest { List<<%= user.persistClass %>> users = userMapper.userDTOsToUsers(usersDto); - assertThat(users) - .isNotEmpty() - .size().isEqualTo(1); + assertThat(users).isNotEmpty().size().isEqualTo(1); assertThat(users.get(0).getAuthorities()).isNotNull(); assertThat(users.get(0).getAuthorities()).isNotEmpty(); <%_ if (databaseTypeSql || databaseTypeMongodb) { _%> @@ -204,9 +198,7 @@ class UserMapperTest { List<<%= user.persistClass %>> users = userMapper.userDTOsToUsers(usersDto); - assertThat(users) - .isNotEmpty() - .size().isEqualTo(1); + assertThat(users).isNotEmpty().size().isEqualTo(1); assertThat(users.get(0).getAuthorities()).isNotNull(); assertThat(users.get(0).getAuthorities()).isEmpty(); } diff --git a/generators/server/templates/src/test/java/_package_/test/util/OAuth2TestUtil.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/test/util/OAuth2TestUtil.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/test/util/OAuth2TestUtil.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/test/util/OAuth2TestUtil.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/web/filter/SpaWebFilterIT_imperative.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/filter/SpaWebFilterIT_imperative.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/web/filter/SpaWebFilterIT_imperative.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/filter/SpaWebFilterIT_imperative.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/web/filter/SpaWebFilterIT_reactive.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/filter/SpaWebFilterIT_reactive.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/web/filter/SpaWebFilterIT_reactive.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/filter/SpaWebFilterIT_reactive.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/web/filter/SpaWebFilterTestController_reactive.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/filter/SpaWebFilterTestController_reactive.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/web/filter/SpaWebFilterTestController_reactive.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/filter/SpaWebFilterTestController_reactive.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/rest/AccountResourceIT.java.ejs similarity index 98% rename from generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/rest/AccountResourceIT.java.ejs index 7733528d5fb3..41a763744ec4 100644 --- a/generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/web/rest/AccountResourceIT.java.ejs @@ -174,14 +174,14 @@ class AccountResourceIT { <%_ if (reactive) { _%> void testNonAuthenticatedUser() { accountWebTestClient.get().uri("/api/authenticate") - .accept(MediaType.APPLICATION_JSON) + .accept(MediaType.TEXT_PLAIN) .exchange() .expectStatus().isOk() .expectBody().isEmpty(); <%_ } else { _%> void testNonAuthenticatedUser() throws Exception { - restAccountMockMvc.perform(get("/api/authenticate") - .accept(MediaType.APPLICATION_JSON)) + restAccountMockMvc + .perform(get("/api/authenticate").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string("")); <%_ } _%> @@ -193,15 +193,14 @@ class AccountResourceIT { void testAuthenticatedUser() { accountWebTestClient .get().uri("/api/authenticate") - .accept(MediaType.APPLICATION_JSON) + .accept(MediaType.TEXT_PLAIN) .exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo(TEST_USER_LOGIN); <%_ } else { _%> void testAuthenticatedUser() throws Exception { - restAccountMockMvc.perform(get("/api/authenticate") - .with(request -> request) - .accept(MediaType.APPLICATION_JSON)) + restAccountMockMvc + .perform(get("/api/authenticate").with(request -> request).accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string(TEST_USER_LOGIN)); <%_ } _%> @@ -324,7 +323,7 @@ class AccountResourceIT { <%_ } _%> void testRegisterInvalidLogin() throws Exception { ManagedUserVM invalidUser = new ManagedUserVM(); - invalidUser.setLogin("funky-log(n");// <-- invalid + invalidUser.setLogin("funky-log(n"); // <-- invalid invalidUser.setPassword("password"); invalidUser.setFirstName("Funky"); invalidUser.setLastName("One"); @@ -360,9 +359,9 @@ class AccountResourceIT { static Stream invalidUsers() { return Stream.of( - createInvalidUser("bob", "password", "Bob", "Green", "invalid", true),// <-- invalid - createInvalidUser("bob", "123", "Bob", "Green", "bob@example.com", true),// password with only 3 digits - createInvalidUser("bob", null, "Bob", "Green", "bob@example.com", true)// invalid null password + createInvalidUser("bob", "password", "Bob", "Green", "invalid", true), // <-- invalid + createInvalidUser("bob", "123", "Bob", "Green", "bob@example.com", true), // password with only 3 digits + createInvalidUser("bob", null, "Bob", "Green", "bob@example.com", true) // invalid null password ); } @@ -391,7 +390,14 @@ class AccountResourceIT { assertThat(user).isEmpty(); } - private static ManagedUserVM createInvalidUser(String login, String password, String firstName, String lastName, String email, boolean activated) { + private static ManagedUserVM createInvalidUser( + String login, + String password, + String firstName, + String lastName, + String email, + boolean activated + ) { ManagedUserVM invalidUser = new ManagedUserVM(); invalidUser.setLogin(login); invalidUser.setPassword(password); @@ -1201,7 +1207,8 @@ class AccountResourceIT { token.setUserAgent("Test agent"); persistentTokenRepository.save<% if (databaseTypeSql && !reactive) { %>AndFlush<% } %>(token); - restAccountMockMvc.perform(get("/api/account/sessions")) + restAccountMockMvc + .perform(get("/api/account/sessions")) .andExpect(status().isOk()) .andExpect(jsonPath("$.[*].series").value(hasItem(token.getSeries()))) .andExpect(jsonPath("$.[*].ipAddress").value(hasItem(token.getIpAddress()))) diff --git a/generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT_oauth2.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/rest/AccountResourceIT_oauth2.java.ejs similarity index 97% rename from generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT_oauth2.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/rest/AccountResourceIT_oauth2.java.ejs index acea88f2e112..805b52fcbb30 100644 --- a/generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT_oauth2.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/web/rest/AccountResourceIT_oauth2.java.ejs @@ -185,13 +185,13 @@ class AccountResourceIT { void testNonAuthenticatedUser() <% if (!reactive) { %>throws Exception <% } %>{ <%_ if (reactive) { _%> webTestClient.get().uri("/api/authenticate") - .accept(MediaType.APPLICATION_JSON) + .accept(MediaType.TEXT_PLAIN) .exchange() .expectStatus().isOk() .expectBody().isEmpty(); <%_ } else { _%> restAccountMockMvc.perform(get("/api/authenticate") - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string("")); <%_ } _%> @@ -203,14 +203,14 @@ class AccountResourceIT { <%_ if (reactive) { _%> webTestClient .get().uri("/api/authenticate") - .accept(MediaType.APPLICATION_JSON) + .accept(MediaType.TEXT_PLAIN) .exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo(TEST_USER_LOGIN); <%_ } else { _%> restAccountMockMvc.perform(get("/api/authenticate") .with(request -> request) - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string(TEST_USER_LOGIN)); <%_ } _%> diff --git a/generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT_skipUserManagement.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/rest/AccountResourceIT_skipUserManagement.java.ejs similarity index 96% rename from generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT_skipUserManagement.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/rest/AccountResourceIT_skipUserManagement.java.ejs index c2bcbc27eba1..46ccb1c54867 100644 --- a/generators/server/templates/src/test/java/_package_/web/rest/AccountResourceIT_skipUserManagement.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/web/rest/AccountResourceIT_skipUserManagement.java.ejs @@ -116,13 +116,13 @@ class AccountResourceIT { void testNonAuthenticatedUser() <% if (!reactive) { %>throws Exception <% } %>{ <%_ if (reactive) { _%> accountWebTestClient.get().uri("/api/authenticate") - .accept(MediaType.APPLICATION_JSON) + .accept(MediaType.TEXT_PLAIN) .exchange() .expectStatus().isOk() .expectBody().isEmpty(); <%_ } else { _%> restAccountMockMvc.perform(get("/api/authenticate") - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string("")); <%_ } _%> @@ -134,14 +134,14 @@ class AccountResourceIT { <%_ if (reactive) { _%> accountWebTestClient .get().uri("/api/authenticate") - .accept(MediaType.APPLICATION_JSON) + .accept(MediaType.TEXT_PLAIN) .exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo(TEST_USER_LOGIN); <%_ } else { _%> restAccountMockMvc.perform(get("/api/authenticate") .with(request -> request) - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string(TEST_USER_LOGIN)); <%_ } _%> diff --git a/generators/server/templates/src/test/java/_package_/web/rest/AuthenticateControllerIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/rest/AuthenticateControllerIT.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/web/rest/AuthenticateControllerIT.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/rest/AuthenticateControllerIT.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/web/rest/LogoutResourceIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/rest/LogoutResourceIT.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/web/rest/LogoutResourceIT.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/rest/LogoutResourceIT.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/web/rest/TestUtil.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/rest/TestUtil.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/web/rest/TestUtil.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/rest/TestUtil.java.ejs diff --git a/generators/server/templates/src/test/java/_package_/web/rest/WithUnauthenticatedMockUser.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/rest/WithUnauthenticatedMockUser.java.ejs similarity index 97% rename from generators/server/templates/src/test/java/_package_/web/rest/WithUnauthenticatedMockUser.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/rest/WithUnauthenticatedMockUser.java.ejs index e463ec569bf2..0d5abfb494b8 100644 --- a/generators/server/templates/src/test/java/_package_/web/rest/WithUnauthenticatedMockUser.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/web/rest/WithUnauthenticatedMockUser.java.ejs @@ -28,12 +28,12 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -@Target({ElementType.METHOD, ElementType.TYPE}) +@Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @WithSecurityContext(factory = WithUnauthenticatedMockUser.Factory.class) public @interface WithUnauthenticatedMockUser { - class Factory implements WithSecurityContextFactory { + @Override public SecurityContext createSecurityContext(WithUnauthenticatedMockUser annotation) { return SecurityContextHolder.createEmptyContext(); diff --git a/generators/server/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorIT_imperative.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorIT_imperative.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorIT_imperative.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorIT_imperative.java.ejs diff --git a/generators/spring-boot/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorIT_reactive.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorIT_reactive.java.ejs new file mode 100644 index 000000000000..a25b51087232 --- /dev/null +++ b/generators/spring-boot/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorIT_reactive.java.ejs @@ -0,0 +1,212 @@ +<%# + Copyright 2013-2024 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. +-%> +package <%= packageName %>.web.rest.errors; + +import <%= packageName %>.IntegrationTest; +import org.hamcrest.core.AnyOf; +import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; +<%_ if (authenticationUsesCsrf) { _%> +import org.junit.jupiter.api.BeforeEach; + +<%_ } _%> +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.web.reactive.server.WebTestClient; +<%_ if (authenticationUsesCsrf) { _%> + +import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf; +<%_ } _%> + +/** + * Integration tests {@link ExceptionTranslator} controller advice. + */ +@WithMockUser +@AutoConfigureWebTestClient(timeout = IntegrationTest.DEFAULT_TIMEOUT) +@IntegrationTest +class ExceptionTranslatorIT { + + @Autowired + private WebTestClient webTestClient; +<%_ if (authenticationUsesCsrf) { _%> + + @BeforeEach + public void setupCsrf() { + webTestClient = webTestClient.mutateWith(csrf()); + } +<%_ } _%> +<%_ if (!databaseTypeNo && !databaseTypeCassandra) { _%> + + @Test + void testConcurrencyFailure() { + webTestClient + .get() + .uri("/api/exception-translator-test/concurrency-failure") + .exchange() + .expectStatus() + .isEqualTo(HttpStatus.CONFLICT) + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .jsonPath("$.message") + .isEqualTo(ErrorConstants.ERR_CONCURRENCY_FAILURE); + } +<%_ } _%> + + @Test + void testMethodArgumentNotValid() { + webTestClient + .post() + .uri("/api/exception-translator-test/method-argument") + .contentType(MediaType.APPLICATION_JSON) + .bodyValue("{}") + .exchange() + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .jsonPath("$.message") + .isEqualTo(ErrorConstants.ERR_VALIDATION) + .jsonPath("$.fieldErrors.[0].objectName") + .isEqualTo("test") + .jsonPath("$.fieldErrors.[0].field") + .isEqualTo("test") + .jsonPath("$.fieldErrors.[0].message") + .isEqualTo("must not be null"); + } + + @Test + void testMissingRequestPart() { + webTestClient + .get() + .uri("/api/exception-translator-test/missing-servlet-request-part") + .exchange() + .expectStatus() + .isBadRequest() + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .jsonPath("$.message") + .isEqualTo("error.http.400"); + } + + @Test + void testMissingRequestParameter() { + webTestClient + .get() + .uri("/api/exception-translator-test/missing-servlet-request-parameter") + .exchange() + .expectStatus() + .isBadRequest() + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .jsonPath("$.message") + .isEqualTo("error.http.400"); + } + + @Test + void testAccessDenied() { + webTestClient + .get() + .uri("/api/exception-translator-test/access-denied") + .exchange() + .expectStatus() + .isForbidden() + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .jsonPath("$.message") + .isEqualTo("error.http.403") + .jsonPath("$.detail") + .isEqualTo("test access denied!"); + } + + @Test + void testUnauthorized() { + webTestClient + .get() + .uri("/api/exception-translator-test/unauthorized") + .exchange() + .expectStatus() + .isUnauthorized() + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .jsonPath("$.message") + .isEqualTo("error.http.401") + .jsonPath("$.path") + .isEqualTo("/api/exception-translator-test/unauthorized") + .jsonPath("$.detail") + .value(AnyOf.anyOf(IsEqual.equalTo("test authentication failed!"), IsEqual.equalTo("Invalid credentials"))); + } + + @Test + void testMethodNotSupported() { + webTestClient + .post() + .uri("/api/exception-translator-test/access-denied") + .exchange() + .expectStatus() + .isEqualTo(HttpStatus.METHOD_NOT_ALLOWED) + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .jsonPath("$.message") + .isEqualTo("error.http.405") + .jsonPath("$.detail") + .isEqualTo("405 METHOD_NOT_ALLOWED \"Request method 'POST' is not supported.\""); + } + + @Test + void testExceptionWithResponseStatus() { + webTestClient + .get() + .uri("/api/exception-translator-test/response-status") + .exchange() + .expectStatus() + .isBadRequest() + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .jsonPath("$.message") + .isEqualTo("error.http.400") + .jsonPath("$.title") + .isEqualTo("test response status"); + } + + @Test + void testInternalServerError() { + webTestClient + .get() + .uri("/api/exception-translator-test/internal-server-error") + .exchange() + .expectHeader() + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .expectBody() + .jsonPath("$.message") + .isEqualTo("error.http.500") + .jsonPath("$.title") + .isEqualTo("Internal Server Error"); + } + +} diff --git a/generators/server/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorTestController.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorTestController.java.ejs similarity index 100% rename from generators/server/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorTestController.java.ejs rename to generators/spring-boot/templates/src/test/java/_package_/web/rest/errors/ExceptionTranslatorTestController.java.ejs diff --git a/generators/server/templates/src/test/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration.ejs b/generators/spring-boot/templates/src/test/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration.ejs similarity index 100% rename from generators/server/templates/src/test/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration.ejs rename to generators/spring-boot/templates/src/test/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration.ejs diff --git a/generators/server/templates/src/test/resources/config/application.yml.ejs b/generators/spring-boot/templates/src/test/resources/config/application.yml.ejs similarity index 100% rename from generators/server/templates/src/test/resources/config/application.yml.ejs rename to generators/spring-boot/templates/src/test/resources/config/application.yml.ejs diff --git a/generators/server/templates/src/test/resources/config/bootstrap.yml.ejs b/generators/spring-boot/templates/src/test/resources/config/bootstrap.yml.ejs similarity index 100% rename from generators/server/templates/src/test/resources/config/bootstrap.yml.ejs rename to generators/spring-boot/templates/src/test/resources/config/bootstrap.yml.ejs diff --git a/generators/server/templates/src/test/resources/i18n/messages_en.properties.ejs b/generators/spring-boot/templates/src/test/resources/i18n/messages_en.properties.ejs similarity index 100% rename from generators/server/templates/src/test/resources/i18n/messages_en.properties.ejs rename to generators/spring-boot/templates/src/test/resources/i18n/messages_en.properties.ejs diff --git a/generators/server/templates/src/test/resources/junit-platform.properties.ejs b/generators/spring-boot/templates/src/test/resources/junit-platform.properties.ejs similarity index 100% rename from generators/server/templates/src/test/resources/junit-platform.properties.ejs rename to generators/spring-boot/templates/src/test/resources/junit-platform.properties.ejs diff --git a/generators/server/templates/src/test/resources/logback.xml.ejs b/generators/spring-boot/templates/src/test/resources/logback.xml.ejs similarity index 100% rename from generators/server/templates/src/test/resources/logback.xml.ejs rename to generators/spring-boot/templates/src/test/resources/logback.xml.ejs diff --git a/generators/server/templates/src/test/resources/templates/mail/activationEmail.html.ejs b/generators/spring-boot/templates/src/test/resources/templates/mail/activationEmail.html.ejs similarity index 100% rename from generators/server/templates/src/test/resources/templates/mail/activationEmail.html.ejs rename to generators/spring-boot/templates/src/test/resources/templates/mail/activationEmail.html.ejs diff --git a/generators/server/templates/src/test/resources/templates/mail/creationEmail.html.ejs b/generators/spring-boot/templates/src/test/resources/templates/mail/creationEmail.html.ejs similarity index 100% rename from generators/server/templates/src/test/resources/templates/mail/creationEmail.html.ejs rename to generators/spring-boot/templates/src/test/resources/templates/mail/creationEmail.html.ejs diff --git a/generators/server/templates/src/test/resources/templates/mail/passwordResetEmail.html.ejs b/generators/spring-boot/templates/src/test/resources/templates/mail/passwordResetEmail.html.ejs similarity index 100% rename from generators/server/templates/src/test/resources/templates/mail/passwordResetEmail.html.ejs rename to generators/spring-boot/templates/src/test/resources/templates/mail/passwordResetEmail.html.ejs diff --git a/generators/server/templates/src/test/resources/templates/mail/testEmail.html.ejs b/generators/spring-boot/templates/src/test/resources/templates/mail/testEmail.html.ejs similarity index 100% rename from generators/server/templates/src/test/resources/templates/mail/testEmail.html.ejs rename to generators/spring-boot/templates/src/test/resources/templates/mail/testEmail.html.ejs diff --git a/generators/spring-cache/__snapshots__/generator.spec.ts.snap b/generators/spring-cache/__snapshots__/generator.spec.ts.snap index d4d4e6579556..b93bc8679095 100644 --- a/generators/spring-cache/__snapshots__/generator.spec.ts.snap +++ b/generators/spring-cache/__snapshots__/generator.spec.ts.snap @@ -39,37 +39,46 @@ exports[`generator - spring-cache caffeine-gradle should match source calls 1`] "id": "jhipster.spring-cache-conventions", }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "cache-api", - "groupId": "javax.cache", - }, - { - "artifactId": "jcache", - "groupId": "com.github.ben-manes.caffeine", - }, - { - "artifactId": "caffeine", - "groupId": "com.github.ben-manes.caffeine", - }, - { - "artifactId": "config", - "groupId": "com.typesafe", - "version": "'TYPESAFE-VERSION'", - }, - { - "artifactId": "hibernate-jcache", - "groupId": "org.hibernate.orm", - }, - ], - "versions": [], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "cache-api", + "groupId": "javax.cache", + }, + { + "artifactId": "jcache", + "groupId": "com.github.ben-manes.caffeine", + }, + { + "artifactId": "caffeine", + "groupId": "com.github.ben-manes.caffeine", + }, + { + "artifactId": "config", + "groupId": "com.typesafe", + "version": "'TYPESAFE-VERSION'", + }, + ], + }, + { + "condition": true, + "dependencies": [ + { + "artifactId": "hibernate-jcache", + "groupId": "org.hibernate.orm", + }, + ], + }, + ], ], } `; @@ -93,37 +102,46 @@ exports[`generator - spring-cache caffeine-maven should match source calls 1`] = "relationships": [], }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "cache-api", - "groupId": "javax.cache", - }, - { - "artifactId": "jcache", - "groupId": "com.github.ben-manes.caffeine", - }, - { - "artifactId": "caffeine", - "groupId": "com.github.ben-manes.caffeine", - }, - { - "artifactId": "config", - "groupId": "com.typesafe", - "version": "'TYPESAFE-VERSION'", - }, - { - "artifactId": "hibernate-jcache", - "groupId": "org.hibernate.orm", - }, - ], - "versions": [], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "cache-api", + "groupId": "javax.cache", + }, + { + "artifactId": "jcache", + "groupId": "com.github.ben-manes.caffeine", + }, + { + "artifactId": "caffeine", + "groupId": "com.github.ben-manes.caffeine", + }, + { + "artifactId": "config", + "groupId": "com.typesafe", + "version": "'TYPESAFE-VERSION'", + }, + ], + }, + { + "condition": true, + "dependencies": [ + { + "artifactId": "hibernate-jcache", + "groupId": "org.hibernate.orm", + }, + ], + }, + ], ], } `; @@ -155,29 +173,38 @@ exports[`generator - spring-cache ehcache-gradle should match source calls 1`] = "id": "jhipster.spring-cache-conventions", }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "cache-api", - "groupId": "javax.cache", - }, - { - "artifactId": "ehcache", - "classifier": "jakarta", - "groupId": "org.ehcache", - }, - { - "artifactId": "hibernate-jcache", - "groupId": "org.hibernate.orm", - }, - ], - "versions": [], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "cache-api", + "groupId": "javax.cache", + }, + { + "artifactId": "ehcache", + "classifier": "jakarta", + "groupId": "org.ehcache", + }, + ], + }, + { + "condition": true, + "dependencies": [ + { + "artifactId": "hibernate-jcache", + "groupId": "org.hibernate.orm", + }, + ], + }, + ], ], } `; @@ -201,29 +228,38 @@ exports[`generator - spring-cache ehcache-maven should match source calls 1`] = "relationships": [], }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "cache-api", - "groupId": "javax.cache", - }, - { - "artifactId": "ehcache", - "classifier": "jakarta", - "groupId": "org.ehcache", - }, - { - "artifactId": "hibernate-jcache", - "groupId": "org.hibernate.orm", - }, - ], - "versions": [], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "cache-api", + "groupId": "javax.cache", + }, + { + "artifactId": "ehcache", + "classifier": "jakarta", + "groupId": "org.ehcache", + }, + ], + }, + { + "condition": true, + "dependencies": [ + { + "artifactId": "hibernate-jcache", + "groupId": "org.hibernate.orm", + }, + ], + }, + ], ], } `; @@ -275,30 +311,39 @@ exports[`generator - spring-cache hazelcast-gradle should match source calls 1`] "id": "jhipster.spring-cache-conventions", }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "cache-api", - "groupId": "javax.cache", - }, - { - "artifactId": "hazelcast-spring", - "groupId": "com.hazelcast", - "version": "'HAZELCAST-SPRING-VERSION'", - }, - { - "artifactId": "hazelcast-hibernate53", - "groupId": "com.hazelcast", - "version": "'HAZELCAST-HIBERNATE-53-VERSION'", - }, - ], - "versions": [], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "cache-api", + "groupId": "javax.cache", + }, + { + "artifactId": "hazelcast-spring", + "groupId": "com.hazelcast", + "version": "'HAZELCAST-SPRING-VERSION'", + }, + ], + }, + { + "condition": true, + "dependencies": [ + { + "artifactId": "hazelcast-hibernate53", + "groupId": "com.hazelcast", + "version": "'HAZELCAST-HIBERNATE-53-VERSION'", + }, + ], + }, + ], ], } `; @@ -322,30 +367,39 @@ exports[`generator - spring-cache hazelcast-maven should match source calls 1`] "relationships": [], }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "cache-api", - "groupId": "javax.cache", - }, - { - "artifactId": "hazelcast-spring", - "groupId": "com.hazelcast", - "version": "'HAZELCAST-SPRING-VERSION'", - }, - { - "artifactId": "hazelcast-hibernate53", - "groupId": "com.hazelcast", - "version": "'HAZELCAST-HIBERNATE-53-VERSION'", - }, - ], - "versions": [], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "cache-api", + "groupId": "javax.cache", + }, + { + "artifactId": "hazelcast-spring", + "groupId": "com.hazelcast", + "version": "'HAZELCAST-SPRING-VERSION'", + }, + ], + }, + { + "condition": true, + "dependencies": [ + { + "artifactId": "hazelcast-hibernate53", + "groupId": "com.hazelcast", + "version": "'HAZELCAST-HIBERNATE-53-VERSION'", + }, + ], + }, + ], ], } `; @@ -380,41 +434,48 @@ exports[`generator - spring-cache infinispan-gradle should match source calls 1` "id": "jhipster.spring-cache-conventions", }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "cache-api", - "groupId": "javax.cache", - }, - { - "artifactId": "infinispan-hibernate-cache-v62", - "groupId": "org.infinispan", - }, - { - "artifactId": "infinispan-spring-boot3-starter-embedded", - "groupId": "org.infinispan", - }, - { - "artifactId": "infinispan-commons", - "groupId": "org.infinispan", - }, - { - "artifactId": "infinispan-core", - "groupId": "org.infinispan", - }, - { - "artifactId": "infinispan-component-annotations", - "groupId": "org.infinispan", - "scope": "compile", - }, - ], - "versions": [], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "cache-api", + "groupId": "javax.cache", + }, + { + "artifactId": "infinispan-hibernate-cache-v62", + "groupId": "org.infinispan", + }, + { + "artifactId": "infinispan-spring-boot3-starter-embedded", + "groupId": "org.infinispan", + }, + { + "artifactId": "infinispan-commons", + "groupId": "org.infinispan", + }, + { + "artifactId": "infinispan-core", + "groupId": "org.infinispan", + }, + { + "artifactId": "infinispan-component-annotations", + "groupId": "org.infinispan", + "scope": "compile", + }, + ], + }, + { + "condition": false, + }, + ], ], } `; @@ -441,41 +502,48 @@ exports[`generator - spring-cache infinispan-maven should match source calls 1`] "relationships": [], }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "cache-api", - "groupId": "javax.cache", - }, - { - "artifactId": "infinispan-hibernate-cache-v62", - "groupId": "org.infinispan", - }, - { - "artifactId": "infinispan-spring-boot3-starter-embedded", - "groupId": "org.infinispan", - }, - { - "artifactId": "infinispan-commons", - "groupId": "org.infinispan", - }, - { - "artifactId": "infinispan-core", - "groupId": "org.infinispan", - }, - { - "artifactId": "infinispan-component-annotations", - "groupId": "org.infinispan", - "scope": "compile", - }, - ], - "versions": [], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "cache-api", + "groupId": "javax.cache", + }, + { + "artifactId": "infinispan-hibernate-cache-v62", + "groupId": "org.infinispan", + }, + { + "artifactId": "infinispan-spring-boot3-starter-embedded", + "groupId": "org.infinispan", + }, + { + "artifactId": "infinispan-commons", + "groupId": "org.infinispan", + }, + { + "artifactId": "infinispan-core", + "groupId": "org.infinispan", + }, + { + "artifactId": "infinispan-component-annotations", + "groupId": "org.infinispan", + "scope": "compile", + }, + ], + }, + { + "condition": false, + }, + ], ], } `; @@ -507,40 +575,48 @@ exports[`generator - spring-cache memcached-gradle should match source calls 1`] "id": "jhipster.spring-cache-conventions", }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "cache-api", - "groupId": "javax.cache", - }, - { - "artifactId": "spring-cache", - "groupId": "com.google.code.simple-spring-memcached", - "versionRef": "xmemcached-provider", - }, - { - "artifactId": "xmemcached-provider", - "groupId": "com.google.code.simple-spring-memcached", - "versionRef": "xmemcached-provider", - }, - { - "artifactId": "xmemcached", - "groupId": "com.googlecode.xmemcached", - "version": "'XMEMCACHED-VERSION'", - }, - ], - "versions": [ - { - "name": "xmemcached-provider", - "version": "'XMEMCACHED-PROVIDER-VERSION'", - }, - ], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "cache-api", + "groupId": "javax.cache", + }, + { + "artifactId": "spring-cache", + "groupId": "com.google.code.simple-spring-memcached", + "versionRef": "xmemcached-provider", + }, + { + "artifactId": "xmemcached-provider", + "groupId": "com.google.code.simple-spring-memcached", + "versionRef": "xmemcached-provider", + }, + { + "artifactId": "xmemcached", + "groupId": "com.googlecode.xmemcached", + "version": "'XMEMCACHED-VERSION'", + }, + ], + "versions": [ + { + "name": "xmemcached-provider", + "version": "'XMEMCACHED-PROVIDER-VERSION'", + }, + ], + }, + { + "condition": false, + }, + ], ], } `; @@ -564,40 +640,48 @@ exports[`generator - spring-cache memcached-maven should match source calls 1`] "relationships": [], }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "cache-api", - "groupId": "javax.cache", - }, - { - "artifactId": "spring-cache", - "groupId": "com.google.code.simple-spring-memcached", - "versionRef": "xmemcached-provider", - }, - { - "artifactId": "xmemcached-provider", - "groupId": "com.google.code.simple-spring-memcached", - "versionRef": "xmemcached-provider", - }, - { - "artifactId": "xmemcached", - "groupId": "com.googlecode.xmemcached", - "version": "'XMEMCACHED-VERSION'", - }, - ], - "versions": [ - { - "name": "xmemcached-provider", - "version": "'XMEMCACHED-PROVIDER-VERSION'", - }, - ], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "cache-api", + "groupId": "javax.cache", + }, + { + "artifactId": "spring-cache", + "groupId": "com.google.code.simple-spring-memcached", + "versionRef": "xmemcached-provider", + }, + { + "artifactId": "xmemcached-provider", + "groupId": "com.google.code.simple-spring-memcached", + "versionRef": "xmemcached-provider", + }, + { + "artifactId": "xmemcached", + "groupId": "com.googlecode.xmemcached", + "version": "'XMEMCACHED-VERSION'", + }, + ], + "versions": [ + { + "name": "xmemcached-provider", + "version": "'XMEMCACHED-PROVIDER-VERSION'", + }, + ], + }, + { + "condition": false, + }, + ], ], } `; @@ -638,35 +722,44 @@ exports[`generator - spring-cache redis-gradle should match source calls 1`] = ` "id": "jhipster.spring-cache-conventions", }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "junit-jupiter", - "groupId": "org.testcontainers", - "scope": "test", - }, - { - "artifactId": "testcontainers", - "groupId": "org.testcontainers", - "scope": "test", - }, - { - "artifactId": "redisson", - "groupId": "org.redisson", - "version": "'REDISSON-VERSION'", - }, - { - "artifactId": "hibernate-jcache", - "groupId": "org.hibernate.orm", - }, - ], - "versions": [], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "junit-jupiter", + "groupId": "org.testcontainers", + "scope": "test", + }, + { + "artifactId": "testcontainers", + "groupId": "org.testcontainers", + "scope": "test", + }, + { + "artifactId": "redisson", + "groupId": "org.redisson", + "version": "'REDISSON-VERSION'", + }, + ], + }, + { + "condition": true, + "dependencies": [ + { + "artifactId": "hibernate-jcache", + "groupId": "org.hibernate.orm", + }, + ], + }, + ], ], "addTestSpringFactory": [ { @@ -705,35 +798,44 @@ exports[`generator - spring-cache redis-maven should match source calls 1`] = ` "relationships": [], }, ], - "addJavaDefinition": [ - { - "dependencies": [ - { - "artifactId": "spring-boot-starter-cache", - "groupId": "org.springframework.boot", - }, - { - "artifactId": "junit-jupiter", - "groupId": "org.testcontainers", - "scope": "test", - }, - { - "artifactId": "testcontainers", - "groupId": "org.testcontainers", - "scope": "test", - }, - { - "artifactId": "redisson", - "groupId": "org.redisson", - "version": "'REDISSON-VERSION'", - }, - { - "artifactId": "hibernate-jcache", - "groupId": "org.hibernate.orm", - }, - ], - "versions": [], - }, + "addJavaDefinitions": [ + [ + { + "gradleFile": "buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle", + }, + { + "dependencies": [ + { + "artifactId": "spring-boot-starter-cache", + "groupId": "org.springframework.boot", + }, + { + "artifactId": "junit-jupiter", + "groupId": "org.testcontainers", + "scope": "test", + }, + { + "artifactId": "testcontainers", + "groupId": "org.testcontainers", + "scope": "test", + }, + { + "artifactId": "redisson", + "groupId": "org.redisson", + "version": "'REDISSON-VERSION'", + }, + ], + }, + { + "condition": true, + "dependencies": [ + { + "artifactId": "hibernate-jcache", + "groupId": "org.hibernate.orm", + }, + ], + }, + ], ], "addTestSpringFactory": [ { diff --git a/generators/spring-cache/files.ts b/generators/spring-cache/files.ts index a0ae79046d9f..704beebe574b 100644 --- a/generators/spring-cache/files.ts +++ b/generators/spring-cache/files.ts @@ -17,11 +17,11 @@ * limitations under the License. */ import { moveToJavaPackageSrcDir, moveToJavaPackageTestDir } from '../java/support/index.js'; -import { SERVER_MAIN_SRC_DIR, SERVER_TEST_SRC_DIR, GRADLE_BUILD_SRC_MAIN_DIR } from '../generator-constants.js'; -import { WriteFileSection } from '../base/api.js'; -import Generator from './generator.js'; +import { GRADLE_BUILD_SRC_MAIN_DIR, SERVER_MAIN_SRC_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; +import type { WriteFileSection } from '../base/api.js'; +import type Generator from './generator.js'; -const files: WriteFileSection = { +const files: WriteFileSection = { cacheFiles: [ { condition: data => data.buildToolGradle, diff --git a/generators/spring-cache/generator.spec.ts b/generators/spring-cache/generator.spec.ts index acf2a8370f38..4857599499fd 100644 --- a/generators/spring-cache/generator.spec.ts +++ b/generators/spring-cache/generator.spec.ts @@ -1,13 +1,13 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { fromMatrix, defaultHelpers as helpers, result } from '../../testing/index.js'; +import { fromMatrix, defaultHelpers as helpers, result } from '../../lib/testing/index.js'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; import { GENERATOR_SPRING_CACHE } from '../generator-list.js'; -import { cacheTypes, buildToolTypes } from '../../jdl/jhipster/index.js'; +import { buildToolTypes, cacheTypes } from '../../lib/jhipster/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); diff --git a/generators/spring-cache/generator.ts b/generators/spring-cache/generator.ts index bd6a8a48e9b5..b4f792419eb1 100644 --- a/generators/spring-cache/generator.ts +++ b/generators/spring-cache/generator.ts @@ -18,7 +18,6 @@ */ import BaseApplicationGenerator from '../base-application/index.js'; import { createNeedleCallback } from '../base/support/needles.js'; -import { JavaDependency, JavaDependencyVersion } from '../java/types.js'; import writeTask from './files.js'; import cleanupTask from './cleanup.js'; import { getCacheProviderMavenDefinition } from './internal/dependencies.js'; @@ -34,8 +33,32 @@ export default class SpringCacheGenerator extends BaseApplicationGenerator { } } + get configuring() { + return this.asConfiguringTaskGroup({ + configure() { + const { databaseType, reactive, cacheProvider } = this.jhipsterConfigWithDefaults; + if (this.jhipsterConfig.enableHibernateCache && (reactive || databaseType !== 'sql')) { + this.log.verboseInfo(`Disabling hibernate cache for ${reactive ? 'reactive application' : 'non-SQL databases'}`); + this.jhipsterConfig.enableHibernateCache = undefined; + } + if (reactive && cacheProvider !== 'no') { + this.log.error(`Cache provider is not supported in reactive application`); + } + }, + }); + } + + get [BaseApplicationGenerator.CONFIGURING]() { + return this.delegateTasksToBlueprint(() => this.configuring); + } + get preparing() { return this.asPreparingTaskGroup({ + cancel() { + if (this.jhipsterConfigWithDefaults.cacheProvider === 'no') { + this.cancelCancellableTasks(); + } + }, loadDependabot({ application }) { this.loadJavaDependenciesFromGradleCatalog(application.javaDependencies!, true); }, @@ -137,18 +160,20 @@ export default class SpringCacheGenerator extends BaseApplicationGenerator { const { javaDependencies } = application; const { cacheProvider, enableHibernateCache } = application as any; - const dependencies: JavaDependency[] = [{ groupId: 'org.springframework.boot', artifactId: 'spring-boot-starter-cache' }]; - const versions: JavaDependencyVersion[] = []; const definition = getCacheProviderMavenDefinition(cacheProvider, javaDependencies); - versions.push(...(definition.base.versions ?? [])); - dependencies.push(...definition.base.dependencies!); - if (enableHibernateCache && definition.hibernateCache) { - versions.push(...(definition.hibernateCache.versions ?? [])); - dependencies.push(...definition.hibernateCache.dependencies!); - } - source.addJavaDefinition?.( - { dependencies, versions }, + source.addJavaDefinitions?.( { gradleFile: 'buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle' }, + { + ...definition.base, + dependencies: [ + { groupId: 'org.springframework.boot', artifactId: 'spring-boot-starter-cache' }, + ...definition.base.dependencies, + ], + }, + { + condition: Boolean(enableHibernateCache && definition.hibernateCache), + ...definition.hibernateCache, + }, ); }, }); @@ -164,8 +189,8 @@ export default class SpringCacheGenerator extends BaseApplicationGenerator { if (application.databaseTypeSql) { for (const entity of entities.filter(entity => !entity.skipServer && !entity.builtInUser)) { source.addEntityToCache?.({ - entityAbsoluteClass: (entity as any).entityAbsoluteClass, - relationships: entity.relationships, + entityAbsoluteClass: entity.entityAbsoluteClass, + relationships: entity.relationships as any, }); } } diff --git a/generators/spring-cache/internal/dependencies.ts b/generators/spring-cache/internal/dependencies.ts index 66b72ad48df6..63b28a508ddb 100644 --- a/generators/spring-cache/internal/dependencies.ts +++ b/generators/spring-cache/internal/dependencies.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { JavaDependency, JavaDependencyVersion } from '../../java/types.js'; +import type { JavaDependency, JavaDependencyVersion } from '../../java/types.js'; const javaxCacheApi = { groupId: 'javax.cache', @@ -35,7 +35,6 @@ type CacheProviderDependencies = { hibernateCache?: CacheProviderDefinition; }; -// eslint-disable-next-line import/prefer-default-export export const getCacheProviderMavenDefinition: ( cacheProvider: string, javaDependencies: Record, diff --git a/generators/spring-cache/needles.spec.ts b/generators/spring-cache/needles.spec.ts index 5398a33dea5f..7116e6f4253d 100644 --- a/generators/spring-cache/needles.spec.ts +++ b/generators/spring-cache/needles.spec.ts @@ -1,10 +1,9 @@ -import { before, it, describe } from 'esmocha'; -import { defaultHelpers as helpers, result as runResult } from '../../testing/index.js'; +import { before, describe, it } from 'esmocha'; +import { defaultHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; import BaseApplicationGenerator from '../base-application/index.js'; import { SERVER_MAIN_SRC_DIR } from '../generator-constants.js'; import { GENERATOR_SPRING_CACHE } from '../generator-list.js'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any const mockBlueprintSubGen: any = class extends BaseApplicationGenerator { constructor(args, opts, features) { super(args, opts, features); @@ -34,7 +33,7 @@ describe('needle API server cache: JHipster server generator with blueprint', () await helpers .runJHipster(GENERATOR_SPRING_CACHE) .withOptions({ - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }) .withJHipsterConfig({ cacheProvider: 'ehcache', @@ -69,7 +68,7 @@ describe('needle API server cache: JHipster server generator with blueprint', () await helpers .runJHipster(GENERATOR_SPRING_CACHE) .withOptions({ - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }) .withJHipsterConfig({ cacheProvider: 'caffeine', @@ -104,7 +103,7 @@ describe('needle API server cache: JHipster server generator with blueprint', () await helpers .runJHipster(GENERATOR_SPRING_CACHE) .withOptions({ - blueprint: 'myblueprint', + blueprint: ['myblueprint'], }) .withJHipsterConfig({ cacheProvider: 'redis', diff --git a/generators/spring-cache/resources/gradle/libs.versions.toml b/generators/spring-cache/resources/gradle/libs.versions.toml index f37637393e65..1dbc59e204da 100644 --- a/generators/spring-cache/resources/gradle/libs.versions.toml +++ b/generators/spring-cache/resources/gradle/libs.versions.toml @@ -5,11 +5,11 @@ typesafe = { module = 'com.typesafe:config', version = '1.4.3' } # hazelcast hazelcast-hibernate53 = { module = 'com.hazelcast:hazelcast-hibernate53', version = '5.2.0' } -hazelcast-spring = { module = 'com.hazelcast:hazelcast-spring', version = '5.4.0' } +hazelcast-spring = { module = 'com.hazelcast:hazelcast-spring', version = '5.5.0' } # memcached xmemcached-provider = { module = 'com.google.code.simple-spring-memcached:xmemcached-provider', version = '4.1.3' } xmemcached = { module = 'com.googlecode.xmemcached:xmemcached', version = '2.4.8' } -redisson = { module = 'org.redisson:redisson', version = '3.33.0' } +redisson = { module = 'org.redisson:redisson', version = '3.37.0' } diff --git a/generators/spring-cache/templates/src/main/java/_package_/config/CacheConfiguration.java.ejs b/generators/spring-cache/templates/src/main/java/_package_/config/CacheConfiguration.java.ejs index 34b7a0893f77..875db25f9ad7 100644 --- a/generators/spring-cache/templates/src/main/java/_package_/config/CacheConfiguration.java.ejs +++ b/generators/spring-cache/templates/src/main/java/_package_/config/CacheConfiguration.java.ejs @@ -310,8 +310,9 @@ public class CacheConfiguration { LOG.debug("Configuring Hazelcast clustering for instanceId: {}", serviceId); // In development, everything goes through 127.0.0.1, with a different port if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT))) { - LOG.debug("Application is running with the \"dev\" profile, Hazelcast " + - "cluster will only work with localhost instances"); + LOG.debug( + "Application is running with the \"dev\" profile, Hazelcast " + "cluster will only work with localhost instances" + ); config.getNetworkConfig().setPort(serverProperties.getPort() + 5701); config.getNetworkConfig().getJoin().getTcpIpConfig().setEnabled(true); diff --git a/generators/spring-cloud-stream/generator-pulsar.spec.ts b/generators/spring-cloud-stream/generator-pulsar.spec.ts index 2e7fbba64019..a28402731397 100644 --- a/generators/spring-cloud-stream/generator-pulsar.spec.ts +++ b/generators/spring-cloud-stream/generator-pulsar.spec.ts @@ -16,14 +16,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, after, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { buildSamplesFromMatrix, buildServerMatrix, defaultHelpers as helpers } from '../../testing/index.js'; -import { messageBrokerTypes } from '../../jdl/jhipster/index.js'; +import { buildSamplesFromMatrix, buildServerMatrix, defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; +import { messageBrokerTypes } from '../../lib/jhipster/index.js'; import Generator from './index.js'; const { PULSAR } = messageBrokerTypes; @@ -32,7 +32,6 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorFile = join(__dirname, 'index.ts'); const commonConfig = { messageBroker: PULSAR }; @@ -47,14 +46,10 @@ describe(`generator - ${generator}`, () => { Object.entries(testSamples).forEach(([name, config]) => { describe(name, () => { - let runResult; - before(async () => { - runResult = await helpers.run(generatorFile).withJHipsterConfig(config); + await helpers.runJHipster(generator).withJHipsterConfig(config); }); - after(() => runResult.cleanup()); - it('should match generated files snapshot', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); }); diff --git a/generators/spring-cloud-stream/generator.spec.ts b/generators/spring-cloud-stream/generator.spec.ts index 0a469fb493bd..85b916e8b588 100644 --- a/generators/spring-cloud-stream/generator.spec.ts +++ b/generators/spring-cloud-stream/generator.spec.ts @@ -16,14 +16,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, after, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { buildSamplesFromMatrix, buildServerMatrix, defaultHelpers as helpers } from '../../testing/index.js'; -import { messageBrokerTypes } from '../../jdl/jhipster/index.js'; +import { buildSamplesFromMatrix, buildServerMatrix, defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; +import { messageBrokerTypes } from '../../lib/jhipster/index.js'; import Generator from './index.js'; const { KAFKA } = messageBrokerTypes; @@ -32,7 +32,6 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorFile = join(__dirname, 'index.ts'); const commonConfig = { messageBroker: KAFKA }; @@ -47,14 +46,10 @@ describe(`generator - ${generator}`, () => { Object.entries(testSamples).forEach(([name, config]) => { describe(name, () => { - let runResult; - before(async () => { - runResult = await helpers.run(generatorFile).withJHipsterConfig(config); + await helpers.runJHipster(generator).withJHipsterConfig(config).withMockedSource(); }); - after(() => runResult.cleanup()); - it('should match generated files snapshot', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); }); diff --git a/generators/spring-cloud-stream/generators/kafka/files.ts b/generators/spring-cloud-stream/generators/kafka/files.ts index db420fcb5028..22ca4bcce597 100644 --- a/generators/spring-cloud-stream/generators/kafka/files.ts +++ b/generators/spring-cloud-stream/generators/kafka/files.ts @@ -16,11 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { WriteFileSection } from '../../../base/api.js'; -import { SERVER_MAIN_SRC_DIR, SERVER_TEST_SRC_DIR, GRADLE_BUILD_SRC_MAIN_DIR } from '../../../generator-constants.js'; +import type { WriteFileSection } from '../../../base/api.js'; +import { GRADLE_BUILD_SRC_MAIN_DIR, SERVER_MAIN_SRC_DIR, SERVER_TEST_SRC_DIR } from '../../../generator-constants.js'; import { moveToJavaPackageSrcDir, moveToJavaPackageTestDir } from '../../../server/support/index.js'; -export const kafkaFiles: WriteFileSection = { +export const kafkaFiles: WriteFileSection = { config: [ { condition: data => data.buildToolGradle, diff --git a/generators/spring-cloud-stream/generators/kafka/generator.ts b/generators/spring-cloud-stream/generators/kafka/generator.ts index 5c5341ff80bf..20f5cda493e8 100644 --- a/generators/spring-cloud-stream/generators/kafka/generator.ts +++ b/generators/spring-cloud-stream/generators/kafka/generator.ts @@ -100,6 +100,9 @@ export default class KafkaGenerator extends BaseApplicationGenerator { ]); } }, + addLog({ source }) { + source.addLogbackMainLog!({ name: 'org.apache.kafka', level: 'WARN' }); + }, }); } diff --git a/generators/spring-cloud-stream/generators/pulsar/files.ts b/generators/spring-cloud-stream/generators/pulsar/files.ts index 6c6572e15cb7..4124956e6c49 100644 --- a/generators/spring-cloud-stream/generators/pulsar/files.ts +++ b/generators/spring-cloud-stream/generators/pulsar/files.ts @@ -16,11 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { WriteFileSection } from '../../../base/api.js'; -import { SERVER_TEST_SRC_DIR, GRADLE_BUILD_SRC_MAIN_DIR } from '../../../generator-constants.js'; +import type { WriteFileSection } from '../../../base/api.js'; +import { GRADLE_BUILD_SRC_MAIN_DIR, SERVER_TEST_SRC_DIR } from '../../../generator-constants.js'; import { moveToJavaPackageTestDir } from '../../../java/support/index.js'; -export const pulsarFiles: WriteFileSection = { +export const pulsarFiles: WriteFileSection = { config: [ { condition: data => data.buildToolGradle, diff --git a/generators/spring-cloud/generators/gateway/__snapshots__/generator.spec.ts.snap b/generators/spring-cloud/generators/gateway/__snapshots__/generator.spec.ts.snap index b0bbddf98867..b946a0b24026 100644 --- a/generators/spring-cloud/generators/gateway/__snapshots__/generator.spec.ts.snap +++ b/generators/spring-cloud/generators/gateway/__snapshots__/generator.spec.ts.snap @@ -72,5 +72,11 @@ exports[`generator - spring-cloud:gateway with serviceDiscovery option should ma "src/main/java/com/mycompany/myapp/security/jwt/JWTRelayGatewayFilterFactory.java": { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/web/rest/GatewayResource.java": { + "stateCleared": "modified", + }, + "src/main/java/com/mycompany/myapp/web/rest/vm/RouteVM.java": { + "stateCleared": "modified", + }, } `; diff --git a/generators/spring-cloud/generators/gateway/command.ts b/generators/spring-cloud/generators/gateway/command.ts index fd2d2eef8626..4c94b58c4f82 100644 --- a/generators/spring-cloud/generators/gateway/command.ts +++ b/generators/spring-cloud/generators/gateway/command.ts @@ -16,20 +16,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { JHipsterCommandDefinition } from '../../../base/api.js'; +import type { JHipsterCommandDefinition } from '../../../../lib/command/index.js'; -const command: JHipsterCommandDefinition = { +const command = { configs: { routes: { description: 'Manually configured gateway routes', cli: { - type: String, + type: Array, hide: true, }, + jdl: { + tokenType: 'quotedList', + type: 'quotedList', + tokenValuePattern: /^"[A-Za-z][A-Za-z0-9_]*(?::[A-Za-z][A-Za-z0-9_]+(?::[0-9]+)?)?"$/, + }, scope: 'storage', }, }, import: [], -}; +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/spring-cloud/generators/gateway/generator.spec.ts b/generators/spring-cloud/generators/gateway/generator.spec.ts index fcf2f0c290e5..d081b027be99 100644 --- a/generators/spring-cloud/generators/gateway/generator.spec.ts +++ b/generators/spring-cloud/generators/gateway/generator.spec.ts @@ -18,10 +18,10 @@ */ import { basename, dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; import Generator from './index.js'; const __filename = fileURLToPath(import.meta.url); @@ -47,9 +47,11 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ + "jhipster:bootstrap", "jhipster:java:build-tool", + "jhipster:project-name", ] `); }); @@ -62,7 +64,7 @@ describe(`generator - ${generator}`, () => { .withMockedJHipsterGenerators() .withMockedSource() .withSharedApplication({}) - .withJHipsterConfig({ serviceDiscovery: 'consul' }); + .withJHipsterConfig({ serviceDiscoveryType: 'consul' }); }); it('should match files snapshot', () => { @@ -74,9 +76,11 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ + "jhipster:bootstrap", "jhipster:java:build-tool", + "jhipster:project-name", ] `); }); @@ -115,9 +119,11 @@ describe(`generator - ${generator}`, () => { }); it('should compose with generators', () => { - expect(result.composedMockedGenerators).toMatchInlineSnapshot(` + expect(result.getComposedGenerators()).toMatchInlineSnapshot(` [ + "jhipster:bootstrap", "jhipster:java:build-tool", + "jhipster:project-name", ] `); }); diff --git a/generators/spring-cloud/generators/gateway/generator.ts b/generators/spring-cloud/generators/gateway/generator.ts index d95dbac395c1..285692171d29 100644 --- a/generators/spring-cloud/generators/gateway/generator.ts +++ b/generators/spring-cloud/generators/gateway/generator.ts @@ -70,8 +70,8 @@ export default class GatewayGenerator extends BaseApplicationGenerator { get writing() { return this.asWritingTaskGroup({ - cleanup({ control, application }) { - control.cleanupFiles({ + async cleanup({ control, application }) { + await control.cleanupFiles({ '8.6.1': [ [ application.reactive && (application as any).serviceDiscoveryAny, diff --git a/generators/spring-cloud/generators/gateway/jdl/jdl-routes-option.spec.ts b/generators/spring-cloud/generators/gateway/jdl/jdl-routes-option.spec.ts index 1709e34bd669..66cfd95278ad 100644 --- a/generators/spring-cloud/generators/gateway/jdl/jdl-routes-option.spec.ts +++ b/generators/spring-cloud/generators/gateway/jdl/jdl-routes-option.spec.ts @@ -1,6 +1,7 @@ -import { before, it, describe, expect } from 'esmocha'; -import { createImporterFromContent, ImportState } from '../../../../../jdl/jdl-importer.js'; -import { convertSingleContentToJDL } from '../../../../../jdl/converters/json-to-jdl-converter.js'; +import { before, describe, expect, it } from 'esmocha'; +import type { ImportState } from '../../../../../lib/jdl/jdl-importer.js'; +import { createImporterFromContent } from '../../../../../lib/jdl/jdl-importer.js'; +import { convertSingleContentToJDL } from '../../../../../lib/jdl/converters/json-to-jdl-converter.js'; const optionName = 'routes'; diff --git a/generators/spring-cloud/generators/gateway/jdl/jdl-routes-option.ts b/generators/spring-cloud/generators/gateway/jdl/jdl-routes-option.ts deleted file mode 100644 index 0e8dae8fe16a..000000000000 --- a/generators/spring-cloud/generators/gateway/jdl/jdl-routes-option.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { JHipsterOptionDefinition } from '../../../../../jdl/types/types.js'; - -export const jdlRoutesOptions: JHipsterOptionDefinition = { - name: 'routes', - tokenType: 'quotedList', - type: 'quotedList', - tokenValuePattern: /^"[A-Za-z][A-Za-z0-9_]*(?::[A-Za-z][A-Za-z0-9_]+(?::[0-9]+)?)?"$/, -}; diff --git a/generators/spring-cloud/generators/gateway/types.d.ts b/generators/spring-cloud/generators/gateway/types.d.ts index f6c7b0e93071..3f2b0391fc11 100644 --- a/generators/spring-cloud/generators/gateway/types.d.ts +++ b/generators/spring-cloud/generators/gateway/types.d.ts @@ -1,5 +1,5 @@ export type GatewayApplication = { gatewayServicesApiAvailable?: boolean; - gatewayRoutes?: Array<{ route: string; host: string; serverPort: string }>; + gatewayRoutes?: { route: string; host: string; serverPort: string }[]; routes?: string[]; }; diff --git a/generators/spring-data-cassandra/cleanup.js b/generators/spring-data-cassandra/cleanup.ts similarity index 91% rename from generators/spring-data-cassandra/cleanup.js rename to generators/spring-data-cassandra/cleanup.ts index 415fed0f32a3..74e19e7ac1e0 100644 --- a/generators/spring-data-cassandra/cleanup.js +++ b/generators/spring-data-cassandra/cleanup.ts @@ -1,3 +1,5 @@ +import { asWritingTask } from '../base-application/support/task-type-inference.js'; + /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,7 +18,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export default function cleanupCassandraFilesTask({ application }) { +export default asWritingTask(function cleanupCassandraFilesTask({ application }) { if (this.isJhipsterVersionLessThan('4.3.0')) { this.removeFile(`${application.javaPackageSrcDir}config/cassandra/CustomZonedDateTimeCodec.java`); } @@ -35,4 +37,4 @@ export default function cleanupCassandraFilesTask({ application }) { if (this.isJhipsterVersionLessThan('7.10.0')) { this.removeFile(`${application.javaPackageTestDir}config/TestContainersSpringContextCustomizerFactory.java`); } -} +}); diff --git a/generators/spring-data-cassandra/database-changelog.spec.ts b/generators/spring-data-cassandra/database-changelog.spec.ts index 76edb24994ce..e95de5aa2f03 100644 --- a/generators/spring-data-cassandra/database-changelog.spec.ts +++ b/generators/spring-data-cassandra/database-changelog.spec.ts @@ -1,5 +1,5 @@ -import { before, it, describe } from 'esmocha'; -import { dryRunHelpers as helpers } from '../../testing/index.js'; +import { before, describe, it } from 'esmocha'; +import { defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { SERVER_MAIN_RES_DIR } from '../generator-constants.js'; import { GENERATOR_SPRING_DATA_CASSANDRA } from '../generator-list.js'; @@ -9,9 +9,8 @@ const entityFoo = { name: 'Foo', changelogDate: '20160926101210' }; describe('generator - app - database changelogs', () => { describe('when regenerating the application', () => { describe('with cassandra database', () => { - let runResult; before(async () => { - runResult = await helpers + await helpers .runJHipster(GENERATOR_SPRING_DATA_CASSANDRA) .withJHipsterConfig({ databaseType: 'cassandra' }, [entityFoo]) .withOptions({ force: true, skipClient: true }); diff --git a/generators/spring-data-cassandra/entity-files.js b/generators/spring-data-cassandra/entity-files.ts similarity index 90% rename from generators/spring-data-cassandra/entity-files.js rename to generators/spring-data-cassandra/entity-files.ts index e1c7f4c39327..7abc40aac3d9 100644 --- a/generators/spring-data-cassandra/entity-files.js +++ b/generators/spring-data-cassandra/entity-files.ts @@ -16,6 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { asWritingEntitiesTask } from '../base-application/support/task-type-inference.js'; import { SERVER_MAIN_RES_DIR } from '../generator-constants.js'; import { javaMainPackageTemplatesBlock } from '../server/support/index.js'; @@ -54,11 +55,11 @@ export const entityFiles = { export function cleanupCassandraEntityFilesTask() {} -export default async function writeEntityCassandraFiles({ application, entities }) { +export default asWritingEntitiesTask(async function writeEntityCassandraFiles({ application, entities }) { for (const entity of entities.filter(entity => !entity.skipServer)) { await this.writeFiles({ sections: entity.builtIn ? { domainFiles } : entityFiles, context: { ...application, ...entity }, }); } -} +}); diff --git a/generators/spring-data-cassandra/files.js b/generators/spring-data-cassandra/files.ts similarity index 90% rename from generators/spring-data-cassandra/files.js rename to generators/spring-data-cassandra/files.ts index cf432c14bafb..015fdb6624ac 100644 --- a/generators/spring-data-cassandra/files.js +++ b/generators/spring-data-cassandra/files.ts @@ -16,7 +16,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { SERVER_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; +import { asWritingTask } from '../base-application/support/task-type-inference.js'; +import { SERVER_MAIN_RES_DIR, SERVER_MAIN_SRC_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; import { moveToJavaPackageSrcDir, moveToJavaPackageTestDir } from '../server/support/index.js'; export const cassandraFiles = { @@ -63,9 +64,9 @@ export const cassandraFiles = { ], }; -export default async function writeCassandraFilesTask({ application }) { +export default asWritingTask(async function writeCassandraFilesTask({ application }) { await this.writeFiles({ sections: cassandraFiles, context: application, }); -} +}); diff --git a/generators/spring-data-cassandra/generator.spec.ts b/generators/spring-data-cassandra/generator.spec.ts index eb93dd421bec..2430b4d7e123 100644 --- a/generators/spring-data-cassandra/generator.spec.ts +++ b/generators/spring-data-cassandra/generator.spec.ts @@ -18,18 +18,18 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { buildServerSamples, entitiesSimple as entities, defaultHelpers as helpers, runResult } from '../../testing/index.js'; +import { buildServerSamples, entitiesSimple as entities, defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; import Generator from '../server/index.js'; -import { databaseTypes } from '../../jdl/jhipster/index.js'; +import { databaseTypes } from '../../lib/jhipster/index.js'; import { filterBasicServerGenerators, - shouldComposeWithSpringCloudStream, shouldComposeWithLiquibase, + shouldComposeWithSpringCloudStream, } from '../server/__test-support/index.js'; const __filename = fileURLToPath(import.meta.url); @@ -72,6 +72,7 @@ describe(`generator - ${databaseType}`, () => { await helpers .runJHipster('server') .withJHipsterConfig(sampleConfig, entities) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ except: ['jhipster:spring-data-cassandra'], filter: filterBasicServerGenerators, diff --git a/generators/spring-data-cassandra/generator.js b/generators/spring-data-cassandra/generator.ts similarity index 97% rename from generators/spring-data-cassandra/generator.js rename to generators/spring-data-cassandra/generator.ts index e507923234d9..fd6563151a77 100644 --- a/generators/spring-data-cassandra/generator.js +++ b/generators/spring-data-cassandra/generator.ts @@ -18,7 +18,7 @@ */ import BaseApplicationGenerator from '../base-application/index.js'; -import { PaginationTypes } from '../../jdl/jhipster/entity-options.js'; +import { PaginationTypes } from '../../lib/jhipster/entity-options.js'; import writeCassandraFilesTask from './files.js'; import cleanupCassandraFilesTask from './cleanup.js'; import writeCassandraEntityFilesTask, { cleanupCassandraEntityFilesTask } from './entity-files.js'; @@ -94,7 +94,7 @@ export default class CassandraGenerator extends BaseApplicationGenerator { { groupId: 'org.apache.cassandra', artifactId: 'java-driver-mapper-runtime' }, { groupId: 'commons-codec', artifactId: 'commons-codec' }, { groupId: 'org.springframework.boot', artifactId: cassandraStarter }, - { groupId: 'org.lz4', artifactId: 'lz4-java', version: javaDependencies['lz4-java'] }, + { groupId: 'org.lz4', artifactId: 'lz4-java', version: javaDependencies!['lz4-java'] }, { scope: 'test', groupId: 'org.testcontainers', artifactId: 'junit-jupiter' }, { scope: 'test', groupId: 'org.testcontainers', artifactId: 'testcontainers' }, { scope: 'test', groupId: 'org.testcontainers', artifactId: 'cassandra' }, diff --git a/generators/spring-data-couchbase/entity-files.js b/generators/spring-data-couchbase/entity-files.ts similarity index 89% rename from generators/spring-data-couchbase/entity-files.js rename to generators/spring-data-couchbase/entity-files.ts index e8914dfa2089..85e08ebe50fc 100644 --- a/generators/spring-data-couchbase/entity-files.js +++ b/generators/spring-data-couchbase/entity-files.ts @@ -16,6 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { asWritingEntitiesTask } from '../base-application/support/task-type-inference.js'; import { SERVER_MAIN_RES_DIR } from '../generator-constants.js'; import { javaMainPackageTemplatesBlock } from '../server/support/index.js'; @@ -63,7 +64,7 @@ export const entityFiles = { repositoryFiles, }; -export function cleanupCouchbaseEntityFilesTask({ application, entities }) { +export const cleanupCouchbaseEntityFilesTask = asWritingEntitiesTask(function ({ application, entities }) { for (const entity of entities.filter(entity => !entity.builtIn && !entity.skipServer)) { if (this.isJhipsterVersionLessThan('7.6.1')) { this.removeFile( @@ -71,13 +72,13 @@ export function cleanupCouchbaseEntityFilesTask({ application, entities }) { ); } } -} +}); -export default async function writeEntityCouchbaseFiles({ application, entities }) { +export default asWritingEntitiesTask(async function writeEntityCouchbaseFiles({ application, entities }) { for (const entity of entities.filter(entity => !entity.skipServer)) { await this.writeFiles({ sections: entityFiles, context: { ...application, ...entity }, }); } -} +}); diff --git a/generators/spring-data-couchbase/files.js b/generators/spring-data-couchbase/files.ts similarity index 92% rename from generators/spring-data-couchbase/files.js rename to generators/spring-data-couchbase/files.ts index d40f1da65da0..4d3919482fff 100644 --- a/generators/spring-data-couchbase/files.js +++ b/generators/spring-data-couchbase/files.ts @@ -16,7 +16,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { SERVER_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; +import { asWritingTask } from '../base-application/support/task-type-inference.js'; +import { SERVER_MAIN_RES_DIR, SERVER_MAIN_SRC_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; import { moveToJavaPackageSrcDir, moveToJavaPackageTestDir } from '../server/support/index.js'; export const couchbaseFiles = { @@ -71,7 +72,7 @@ export const couchbaseFiles = { ], }; -export function cleanupCouchbaseFilesTask({ application }) { +export const cleanupCouchbaseFilesTask = asWritingTask(function cleanupCouchbaseFilesTask({ application }) { if (this.isJhipsterVersionLessThan('7.1.1')) { this.removeFile(`${application.javaPackageSrcDir}repository/CustomReactiveCouchbaseRepository.java `); this.removeFile(`${application.javaPackageSrcDir}config/DatabaseConfigurationIT.java`); @@ -92,11 +93,11 @@ export function cleanupCouchbaseFilesTask({ application }) { this.removeFile(`${application.srcMainResources}config/couchmove/changelog/V0.1__initial_setup/user__admin.json`); this.removeFile(`${application.srcMainResources}config/couchmove/changelog/V0.1__initial_setup/user__user.json`); } -} +}); -export default async function writeCouchbaseFilesTask({ application }) { +export default asWritingTask(async function writeCouchbaseFilesTask({ application }) { await this.writeFiles({ sections: couchbaseFiles, context: application, }); -} +}); diff --git a/generators/spring-data-couchbase/generator.spec.ts b/generators/spring-data-couchbase/generator.spec.ts index fdb3ee4a686e..445b62438605 100644 --- a/generators/spring-data-couchbase/generator.spec.ts +++ b/generators/spring-data-couchbase/generator.spec.ts @@ -18,24 +18,24 @@ */ import { basename, dirname, join } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { + buildSamplesFromMatrix, buildServerMatrix, - extendMatrix, entitiesSimple as entities, - buildSamplesFromMatrix, + extendMatrix, defaultHelpers as helpers, runResult, -} from '../../testing/index.js'; +} from '../../lib/testing/index.js'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { databaseTypes } from '../../jdl/jhipster/index.js'; +import { databaseTypes } from '../../lib/jhipster/index.js'; import { filterBasicServerGenerators, - shouldComposeWithSpringCloudStream, shouldComposeWithLiquibase, + shouldComposeWithSpringCloudStream, } from '../server/__test-support/index.js'; import Generator from './generator.js'; @@ -85,6 +85,7 @@ describe(`generator - ${databaseType}`, () => { await helpers .runJHipster('server') .withJHipsterConfig(sampleConfig, entities) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ except: ['jhipster:spring-data-couchbase'], filter: filterBasicServerGenerators, diff --git a/generators/spring-data-couchbase/generator.js b/generators/spring-data-couchbase/generator.ts similarity index 95% rename from generators/spring-data-couchbase/generator.js rename to generators/spring-data-couchbase/generator.ts index 3b5e0b4b000a..3c4910cb4f0b 100644 --- a/generators/spring-data-couchbase/generator.js +++ b/generators/spring-data-couchbase/generator.ts @@ -57,17 +57,17 @@ export default class CouchbaseGenerator extends BaseApplicationGenerator { get postWriting() { return this.asPostWritingTaskGroup({ addTestSpringFactory({ source, application }) { - source.addTestSpringFactory({ + source.addTestSpringFactory!({ key: 'org.springframework.test.context.ContextCustomizerFactory', value: `${application.packageName}.config.TestContainersSpringContextCustomizerFactory`, }); }, addDependencies({ application, source }) { - const { reactive } = application; + const { reactive, javaDependencies } = application; source.addJavaDependencies?.([ { groupId: 'commons-codec', artifactId: 'commons-codec' }, { groupId: 'com.couchbase.client', artifactId: 'java-client' }, - { groupId: 'com.github.differentway', artifactId: 'couchmove' }, + { groupId: 'com.github.differentway', artifactId: 'couchmove', version: javaDependencies!.couchmove }, { groupId: 'org.springframework.boot', artifactId: `spring-boot-starter-data-couchbase${reactive ? '-reactive' : ''}` }, { scope: 'test', groupId: 'org.testcontainers', artifactId: 'junit-jupiter' }, { scope: 'test', groupId: 'org.testcontainers', artifactId: 'testcontainers' }, diff --git a/generators/spring-data-elasticsearch/__test-support/elastic-search-matcher.ts b/generators/spring-data-elasticsearch/__test-support/elastic-search-matcher.ts index 54298a9c73f7..23c7646730b9 100644 --- a/generators/spring-data-elasticsearch/__test-support/elastic-search-matcher.ts +++ b/generators/spring-data-elasticsearch/__test-support/elastic-search-matcher.ts @@ -1,14 +1,14 @@ -import type { RunResult } from 'yeoman-test'; +import { it } from 'esmocha'; -import { SERVER_MAIN_SRC_DIR, JAVA_DOCKER_DIR } from '../../generator-constants.js'; -import { matchWrittenConfig, matchWrittenFiles } from '../../../testing/index.js'; +import { JAVA_DOCKER_DIR, SERVER_MAIN_SRC_DIR } from '../../generator-constants.js'; +import { matchWrittenConfig, matchWrittenFiles, runResult } from '../../../lib/testing/index.js'; const expectedElasticsearchFiles = () => { return [`${JAVA_DOCKER_DIR}elasticsearch.yml`]; }; -const expectedElasticsearchUserFiles = (resultGetter: () => RunResult) => { - const application = (resultGetter() as any).generator.sharedData.getApplication(); +const expectedElasticsearchUserFiles = () => { + const application = runResult.generator.sharedData.getApplication(); return application.generateBuiltInUserEntity ? [`${SERVER_MAIN_SRC_DIR}${application.packageFolder}/repository/search/UserSearchRepository.java`] : []; @@ -20,14 +20,14 @@ const desiredConfig = { }, }; -export const matchElasticSearchDocker = (resultGetter: () => RunResult, shouldMatch: boolean) => { - matchWrittenFiles('elasticsearch', resultGetter, expectedElasticsearchFiles, shouldMatch); +export const matchElasticSearchDocker = (shouldMatch: boolean) => { + it(...matchWrittenFiles('elasticsearch', expectedElasticsearchFiles, shouldMatch)); }; -export const matchElasticSearch = (resultGetter: () => RunResult, shouldMatch: boolean) => { - matchWrittenConfig('elasticsearch', resultGetter, desiredConfig, shouldMatch); +export const matchElasticSearch = (shouldMatch: boolean) => { + it(...matchWrittenConfig('elasticsearch', desiredConfig, shouldMatch)); }; -export const matchElasticSearchUser = (resultGetter: () => RunResult, shouldMatch: boolean) => { - matchWrittenFiles('elasticsearch user', resultGetter, () => expectedElasticsearchUserFiles(resultGetter), shouldMatch); +export const matchElasticSearchUser = (shouldMatch: boolean) => { + it(...matchWrittenFiles('elasticsearch user', () => expectedElasticsearchUserFiles(), shouldMatch)); }; diff --git a/generators/spring-data-elasticsearch/cleanup.js b/generators/spring-data-elasticsearch/cleanup.ts similarity index 90% rename from generators/spring-data-elasticsearch/cleanup.js rename to generators/spring-data-elasticsearch/cleanup.ts index 18be902d4dde..ee49d1a7e69f 100644 --- a/generators/spring-data-elasticsearch/cleanup.js +++ b/generators/spring-data-elasticsearch/cleanup.ts @@ -1,3 +1,5 @@ +import { asWritingTask } from '../base-application/support/task-type-inference.js'; + /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,7 +18,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export default function cleanupElasticsearchFilesTask({ application }) { +export default asWritingTask(function cleanupElasticsearchFilesTask({ application }) { if (this.isJhipsterVersionLessThan('4.0.0')) { this.removeFile(`${application.javaPackageSrcDir}config/ElasticSearchConfiguration.java`); } @@ -36,4 +38,4 @@ export default function cleanupElasticsearchFilesTask({ application }) { this.removeFile(`${application.javaPackageTestDir}config/ElasticsearchReactiveTestConfiguration.java`); } } -} +}); diff --git a/generators/spring-data-elasticsearch/entity-files.js b/generators/spring-data-elasticsearch/entity-files.ts similarity index 85% rename from generators/spring-data-elasticsearch/entity-files.js rename to generators/spring-data-elasticsearch/entity-files.ts index 68a762872b4b..27e7389ab72a 100644 --- a/generators/spring-data-elasticsearch/entity-files.js +++ b/generators/spring-data-elasticsearch/entity-files.ts @@ -16,6 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { asWritingEntitiesTask } from '../base-application/support/task-type-inference.js'; import { javaMainPackageTemplatesBlock } from '../server/support/index.js'; export const entityFiles = { @@ -35,11 +36,11 @@ export const entityFiles = { export function cleanupElasticsearchEntityFilesTask() {} -export default async function writeEntityElasticsearchFiles({ application, entities }) { - for (const entity of entities.filter(entity => !entity.skipServer && entity.searchEngineElasticsearch)) { +export default asWritingEntitiesTask(async function writeEntityElasticsearchFiles({ application, entities }) { + for (const entity of entities.filter(entity => !entity.skipServer && (entity as any).searchEngineElasticsearch)) { await this.writeFiles({ sections: entityFiles, context: { ...application, ...entity }, }); } -} +}); diff --git a/generators/spring-data-elasticsearch/files.js b/generators/spring-data-elasticsearch/files.ts similarity index 91% rename from generators/spring-data-elasticsearch/files.js rename to generators/spring-data-elasticsearch/files.ts index 4d0d6a5fee36..8e1a144346da 100644 --- a/generators/spring-data-elasticsearch/files.js +++ b/generators/spring-data-elasticsearch/files.ts @@ -16,6 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { asWritingTask } from '../base-application/support/task-type-inference.js'; import { SERVER_MAIN_SRC_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; import { moveToJavaPackageSrcDir, moveToJavaPackageTestDir } from '../server/support/index.js'; @@ -49,9 +50,9 @@ export const files = { ], }; -export default async function writeElasticsearchFilesTask({ application }) { +export default asWritingTask(async function writeElasticsearchFilesTask({ application }) { await this.writeFiles({ sections: files, context: application, }); -} +}); diff --git a/generators/spring-data-elasticsearch/generator.spec.ts b/generators/spring-data-elasticsearch/generator.spec.ts index f2c65a309f55..6561cb4abd5c 100644 --- a/generators/spring-data-elasticsearch/generator.spec.ts +++ b/generators/spring-data-elasticsearch/generator.spec.ts @@ -18,19 +18,19 @@ */ import { basename, dirname, join } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { + buildSamplesFromMatrix, buildServerMatrix, - extendMatrix, entitiesServerSamples as entities, - buildSamplesFromMatrix, + extendMatrix, defaultHelpers as helpers, runResult, -} from '../../testing/index.js'; +} from '../../lib/testing/index.js'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { databaseTypes, searchEngineTypes, authenticationTypes, applicationTypes } from '../../jdl/jhipster/index.js'; +import { applicationTypes, authenticationTypes, databaseTypes, searchEngineTypes } from '../../lib/jhipster/index.js'; import { filterBasicServerGenerators, shouldComposeWithSpringCloudStream } from '../server/__test-support/index.js'; import Generator from './generator.js'; import { matchElasticSearch, matchElasticSearchUser } from './__test-support/elastic-search-matcher.js'; @@ -87,6 +87,7 @@ describe('generator - elasticsearch', () => { await helpers .runJHipster('server') .withJHipsterConfig(sampleConfig, entities) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ except: ['jhipster:spring-data-elasticsearch'], filter: filterBasicServerGenerators, @@ -94,10 +95,10 @@ describe('generator - elasticsearch', () => { }); it('should compose with jhipster:common', () => { - expect(runResult.mockedGenerators['jhipster:common'].callCount).toBe(1); + runResult.assertGeneratorComposedOnce('jhipster:common'); }); it(`should ${enableTranslation ? '' : 'not '}compose with jhipster:languages`, () => { - expect(runResult.mockedGenerators['jhipster:languages'].callCount).toBe(enableTranslation ? 1 : 0); + expect(runResult.getGeneratorComposeCount('jhipster:languages')).toBe(enableTranslation ? 1 : 0); }); it('should match generated files snapshot', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); @@ -105,9 +106,8 @@ describe('generator - elasticsearch', () => { describe('searchEngine', () => { const elasticsearch = sampleConfig.searchEngine === ELASTICSEARCH; - matchElasticSearch(() => runResult, elasticsearch); + matchElasticSearch(elasticsearch); matchElasticSearchUser( - () => runResult, elasticsearch && (sampleConfig.authenticationType === OAUTH2 || (sampleConfig.applicationType !== MICROSERVICE && !sampleConfig.skipUserManagement)), diff --git a/generators/spring-data-elasticsearch/generator.js b/generators/spring-data-elasticsearch/generator.ts similarity index 98% rename from generators/spring-data-elasticsearch/generator.js rename to generators/spring-data-elasticsearch/generator.ts index 6cc09667c841..22ba3c244243 100644 --- a/generators/spring-data-elasticsearch/generator.js +++ b/generators/spring-data-elasticsearch/generator.ts @@ -73,7 +73,7 @@ export default class ElasticsearchGenerator extends BaseApplicationGenerator { get postWriting() { return this.asPostWritingTaskGroup({ addTestSpringFactory({ source, application }) { - source.addTestSpringFactory({ + source.addTestSpringFactory!({ key: 'org.springframework.test.context.ContextCustomizerFactory', value: `${application.packageName}.config.TestContainersSpringContextCustomizerFactory`, }); diff --git a/generators/spring-data-mongodb/cleanup.js b/generators/spring-data-mongodb/cleanup.ts similarity index 86% rename from generators/spring-data-mongodb/cleanup.js rename to generators/spring-data-mongodb/cleanup.ts index 7d32cad2c144..10cbaf5a8b79 100644 --- a/generators/spring-data-mongodb/cleanup.js +++ b/generators/spring-data-mongodb/cleanup.ts @@ -1,3 +1,5 @@ +import { asWritingTask } from '../base-application/support/task-type-inference.js'; + /** * Copyright 2013-2024 the original author or authors from the JHipster project. * @@ -16,11 +18,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export default function cleanupMongodbFilesTask({ application }) { +export default asWritingTask(function cleanupMongodbFilesTask({ application }) { if (this.isJhipsterVersionLessThan('3.10.0')) { this.removeFile(`${application.javaPackageSrcDir}config/CloudMongoDbConfiguration.java`); } if (this.isJhipsterVersionLessThan('7.7.1')) { this.removeFile(`${application.javaPackageTestDir}MongoDbTestContainerExtension.java`); } -} +}); diff --git a/generators/spring-data-mongodb/entity-files.js b/generators/spring-data-mongodb/entity-files.ts similarity index 89% rename from generators/spring-data-mongodb/entity-files.js rename to generators/spring-data-mongodb/entity-files.ts index 2ade22b013b1..214a9e2db72c 100644 --- a/generators/spring-data-mongodb/entity-files.js +++ b/generators/spring-data-mongodb/entity-files.ts @@ -16,6 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { asWritingEntitiesTask } from '../base-application/support/task-type-inference.js'; import { javaMainPackageTemplatesBlock } from '../server/support/index.js'; const domainFiles = [ @@ -46,11 +47,11 @@ export const entityFiles = { export function cleanupMongodbEntityFilesTask() {} -export default async function writeEntityMongodbFiles({ application, entities }) { +export default asWritingEntitiesTask(async function writeEntityMongodbFiles({ application, entities }) { for (const entity of entities.filter(entity => !entity.skipServer)) { await this.writeFiles({ sections: entityFiles, context: { ...application, ...entity }, }); } -} +}); diff --git a/generators/spring-data-mongodb/files.js b/generators/spring-data-mongodb/files.ts similarity index 90% rename from generators/spring-data-mongodb/files.js rename to generators/spring-data-mongodb/files.ts index ccb787dfc00b..a541487b9b37 100644 --- a/generators/spring-data-mongodb/files.js +++ b/generators/spring-data-mongodb/files.ts @@ -16,6 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { asWritingTask } from '../base-application/support/task-type-inference.js'; import { SERVER_MAIN_SRC_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; import { moveToJavaPackageSrcDir, moveToJavaPackageTestDir } from '../server/support/index.js'; @@ -40,9 +41,9 @@ export const mongoDbFiles = { ], }; -export default async function writeMongodbFilesTask({ application }) { +export default asWritingTask(async function writeMongodbFilesTask({ application }) { await this.writeFiles({ sections: mongoDbFiles, context: application, }); -} +}); diff --git a/generators/spring-data-mongodb/generator.spec.ts b/generators/spring-data-mongodb/generator.spec.ts index a8f276b43296..6784808a7123 100644 --- a/generators/spring-data-mongodb/generator.spec.ts +++ b/generators/spring-data-mongodb/generator.spec.ts @@ -18,7 +18,7 @@ */ import { basename, dirname, join } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { @@ -27,15 +27,15 @@ import { entitiesSimple as entities, defaultHelpers as helpers, runResult, -} from '../../testing/index.js'; +} from '../../lib/testing/index.js'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; import Generator from '../server/index.js'; -import { databaseTypes } from '../../jdl/jhipster/index.js'; +import { databaseTypes } from '../../lib/jhipster/index.js'; import { filterBasicServerGenerators, - shouldComposeWithSpringCloudStream, shouldComposeWithLiquibase, + shouldComposeWithSpringCloudStream, } from '../server/__test-support/index.js'; const __filename = fileURLToPath(import.meta.url); @@ -80,6 +80,7 @@ describe(`generator - ${databaseType}`, () => { await helpers .runJHipster('server') .withJHipsterConfig(sampleConfig, entities) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ except: ['jhipster:spring-data-mongodb'], filter: filterBasicServerGenerators, diff --git a/generators/spring-data-mongodb/generator.js b/generators/spring-data-mongodb/generator.ts similarity index 94% rename from generators/spring-data-mongodb/generator.js rename to generators/spring-data-mongodb/generator.ts index 59a77df1cf2c..22d66145d9df 100644 --- a/generators/spring-data-mongodb/generator.js +++ b/generators/spring-data-mongodb/generator.ts @@ -58,7 +58,7 @@ export default class MongoDBGenerator extends BaseApplicationGenerator { get postWriting() { return this.asPostWritingTaskGroup({ addTestSpringFactory({ source, application }) { - source.addTestSpringFactory({ + source.addTestSpringFactory!({ key: 'org.springframework.test.context.ContextCustomizerFactory', value: `${application.packageName}.config.TestContainersSpringContextCustomizerFactory`, }); @@ -66,7 +66,7 @@ export default class MongoDBGenerator extends BaseApplicationGenerator { addDependencies({ application, source }) { const { reactive, javaDependencies } = application; source.addJavaDependencies?.([ - { groupId: 'io.mongock', artifactId: 'mongock-bom', type: 'pom', version: javaDependencies['mongock-bom'], scope: 'import' }, + { groupId: 'io.mongock', artifactId: 'mongock-bom', type: 'pom', version: javaDependencies!['mongock-bom'], scope: 'import' }, { groupId: 'io.mongock', artifactId: 'mongock-springboot-v3' }, { groupId: 'org.springframework.boot', artifactId: `spring-boot-starter-data-mongodb${reactive ? '-reactive' : ''}` }, { groupId: 'io.mongock', artifactId: reactive ? 'mongodb-reactive-driver' : 'mongodb-springdata-v4-driver' }, @@ -87,7 +87,7 @@ export default class MongoDBGenerator extends BaseApplicationGenerator { blockhound({ application, source }) { const { reactive } = application; if (reactive) { - source.addAllowBlockingCallsInside({ classPath: 'com.mongodb.internal.Locks', method: 'checkedWithLock' }); + source.addAllowBlockingCallsInside!({ classPath: 'com.mongodb.internal.Locks', method: 'checkedWithLock' }); } }, }); diff --git a/generators/spring-data-neo4j/entity-files.ts b/generators/spring-data-neo4j/entity-files.ts index 8cbed6591ecc..d8df8f1a5cdf 100644 --- a/generators/spring-data-neo4j/entity-files.ts +++ b/generators/spring-data-neo4j/entity-files.ts @@ -17,7 +17,7 @@ * limitations under the License. */ import { javaMainPackageTemplatesBlock } from '../server/support/index.js'; -import Generator from './generator.js'; +import type Generator from './generator.js'; const domainFiles = [ { diff --git a/generators/spring-data-neo4j/files.ts b/generators/spring-data-neo4j/files.ts index b34b2fd33326..f46c392f77ad 100644 --- a/generators/spring-data-neo4j/files.ts +++ b/generators/spring-data-neo4j/files.ts @@ -17,8 +17,8 @@ * limitations under the License. */ import { moveToJavaPackageSrcDir, moveToJavaPackageTestDir } from '../server/support/index.js'; -import { SERVER_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; -import Generator from './generator.js'; +import { SERVER_MAIN_RES_DIR, SERVER_MAIN_SRC_DIR, SERVER_TEST_SRC_DIR } from '../generator-constants.js'; +import type Generator from './generator.js'; export const neo4jFiles = { serverResource: [ diff --git a/generators/spring-data-neo4j/generator.spec.ts b/generators/spring-data-neo4j/generator.spec.ts index 6db56dfaeeec..706755e7e8a2 100644 --- a/generators/spring-data-neo4j/generator.spec.ts +++ b/generators/spring-data-neo4j/generator.spec.ts @@ -1,21 +1,21 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { buildSamplesFromMatrix, buildServerMatrix, entitiesSimple as entities, defaultHelpers as helpers, runResult, -} from '../../testing/index.js'; +} from '../../lib/testing/index.js'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; import Generator from '../server/index.js'; -import { databaseTypes } from '../../jdl/jhipster/index.js'; +import { databaseTypes } from '../../lib/jhipster/index.js'; import { filterBasicServerGenerators, - shouldComposeWithSpringCloudStream, shouldComposeWithLiquibase, + shouldComposeWithSpringCloudStream, } from '../server/__test-support/index.js'; import { GENERATOR_SERVER } from '../generator-list.js'; @@ -59,6 +59,7 @@ describe(`generator - ${databaseType}`, () => { await helpers .runJHipster('server') .withJHipsterConfig(sampleConfig, entities) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ except: ['jhipster:spring-data-neo4j'], filter: filterBasicServerGenerators, diff --git a/generators/spring-data-neo4j/generator.ts b/generators/spring-data-neo4j/generator.ts index 1d551c3ad6aa..624a2569ff89 100644 --- a/generators/spring-data-neo4j/generator.ts +++ b/generators/spring-data-neo4j/generator.ts @@ -147,21 +147,26 @@ export default class Neo4jGenerator extends BaseApplicationGenerator { }); }, addDependencies({ application, source }) { - source.addJavaDependencies?.([ - { groupId: 'org.springframework.boot', artifactId: 'spring-boot-starter-data-neo4j' }, - { scope: 'test', groupId: 'org.testcontainers', artifactId: 'junit-jupiter' }, - { scope: 'test', groupId: 'org.testcontainers', artifactId: 'testcontainers' }, - { scope: 'test', groupId: 'org.testcontainers', artifactId: 'neo4j' }, - ]); - if (!application.databaseMigrationLiquibase) { - source.addJavaDependencies?.([ - { - groupId: 'eu.michael-simons.neo4j', - artifactId: 'neo4j-migrations-spring-boot-starter', - version: application.javaDependencies!['neo4j-migrations-spring-boot-starter'], - }, - ]); - } + source.addJavaDefinitions?.( + { + dependencies: [ + { groupId: 'org.springframework.boot', artifactId: 'spring-boot-starter-data-neo4j' }, + { scope: 'test', groupId: 'org.testcontainers', artifactId: 'junit-jupiter' }, + { scope: 'test', groupId: 'org.testcontainers', artifactId: 'testcontainers' }, + { scope: 'test', groupId: 'org.testcontainers', artifactId: 'neo4j' }, + ], + }, + { + condition: !application.databaseMigrationLiquibase, + dependencies: [ + { + groupId: 'eu.michael-simons.neo4j', + artifactId: 'neo4j-migrations-spring-boot-starter', + version: application.javaDependencies!['neo4j-migrations-spring-boot-starter'], + }, + ], + }, + ); }, }); } diff --git a/generators/spring-data-neo4j/templates/src/main/java/_package_/config/DatabaseConfiguration.java_neo4j.ejs b/generators/spring-data-neo4j/templates/src/main/java/_package_/config/DatabaseConfiguration.java_neo4j.ejs index 8020a2c8aa3d..8b6beba3e0b2 100644 --- a/generators/spring-data-neo4j/templates/src/main/java/_package_/config/DatabaseConfiguration.java_neo4j.ejs +++ b/generators/spring-data-neo4j/templates/src/main/java/_package_/config/DatabaseConfiguration.java_neo4j.ejs @@ -27,6 +27,7 @@ import org.springframework.data.elasticsearch.repository.config.Enable<% if (rea <%_ } _%> import org.springframework.data.neo4j.repository.config.Enable<% if (reactive) { %>Reactive<% } %>Neo4jRepositories; +import org.springframework.data.neo4j.repository.<% if (reactive) { %>Reactive<% } %>Neo4jRepository; <%_ if (reactive) { _%> import org.neo4j.driver.Driver; diff --git a/generators/spring-data-relational/command.ts b/generators/spring-data-relational/command.ts index 4ae0459bcdad..f519e0854b61 100644 --- a/generators/spring-data-relational/command.ts +++ b/generators/spring-data-relational/command.ts @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; -const command: JHipsterCommandDefinition = { +const command = { options: { devDatabaseType: { description: 'Development database', @@ -26,6 +26,16 @@ const command: JHipsterCommandDefinition = { scope: 'storage', }, }, -}; + configs: { + prodDatabaseType: { + cli: { + type: String, + hide: true, + }, + choices: ['postgresql', 'mysql', 'mariadb', 'oracle', 'mssql'], + scope: 'storage', + }, + }, +} as const satisfies JHipsterCommandDefinition; export default command; diff --git a/generators/spring-data-relational/entity-files.js b/generators/spring-data-relational/entity-files.ts similarity index 95% rename from generators/spring-data-relational/entity-files.js rename to generators/spring-data-relational/entity-files.ts index fcf7785415ed..7147d7dbcb63 100644 --- a/generators/spring-data-relational/entity-files.js +++ b/generators/spring-data-relational/entity-files.ts @@ -16,6 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { asWritingEntitiesTask } from '../base-application/support/task-type-inference.js'; import { javaMainPackageTemplatesBlock } from '../java/support/index.js'; const domainFiles = [ @@ -88,7 +89,7 @@ const sqlFiles = { export function cleanupEntitiesTask() {} -export default async function writeEntitiesTask({ application, entities }) { +export default asWritingEntitiesTask(async function writeEntitiesTask({ application, entities }) { for (const entity of entities.filter(entity => !entity.skipServer)) { if (entity.builtInUser) { await this.writeFiles({ @@ -108,4 +109,4 @@ export default async function writeEntitiesTask({ application, entities }) { }); } } -} +}); diff --git a/generators/spring-data-relational/files.js b/generators/spring-data-relational/files.ts similarity index 90% rename from generators/spring-data-relational/files.js rename to generators/spring-data-relational/files.ts index cd157ec26389..a6e34953e379 100644 --- a/generators/spring-data-relational/files.js +++ b/generators/spring-data-relational/files.ts @@ -16,12 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { mergeSections, addSectionsCondition } from '../base/support/index.js'; +import { asWritingTask } from '../base-application/support/index.js'; +import { addSectionsCondition, mergeSections } from '../base/support/index.js'; import { javaMainPackageTemplatesBlock, + javaMainResourceTemplatesBlock, javaTestPackageTemplatesBlock, javaTestResourceTemplatesBlock, - javaMainResourceTemplatesBlock, } from '../java/support/index.js'; export const sqlFiles = { @@ -71,6 +72,12 @@ export const sqlFiles = { templates: ['config/application-testprod.yml'], }, ], + graalvm: [ + javaMainPackageTemplatesBlock({ + condition: ctx => !ctx.reactive && ctx.graalvmSupport, + templates: ['config/JacksonNativeConfiguration.java'], + }), + ], }; export const h2Files = { @@ -127,9 +134,9 @@ export const serverFiles = mergeSections( addSectionsCondition(postgresFiles, context => context.prodDatabaseTypePostgresql), ); -export default async function writeSqlFiles({ application }) { +export default asWritingTask(async function writeSqlFiles({ application }) { await this.writeFiles({ sections: serverFiles, context: application, }); -} +}); diff --git a/generators/spring-data-relational/generator.spec.ts b/generators/spring-data-relational/generator.spec.ts index 2472c3789b23..99837ebf89ac 100644 --- a/generators/spring-data-relational/generator.spec.ts +++ b/generators/spring-data-relational/generator.spec.ts @@ -1,24 +1,24 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { + buildSamplesFromMatrix, buildServerMatrix, - extendMatrix, extendFilteredMatrix, - buildSamplesFromMatrix, + extendMatrix, defaultHelpers as helpers, runResult, -} from '../../testing/index.js'; +} from '../../lib/testing/index.js'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; import Generator from '../server/index.js'; -import { databaseTypes, cacheTypes } from '../../jdl/jhipster/index.js'; +import { cacheTypes, databaseTypes } from '../../lib/jhipster/index.js'; import { filterBasicServerGenerators, - shouldComposeWithSpringCloudStream, shouldComposeWithLiquibase, + shouldComposeWithSpringCloudStream, } from '../server/__test-support/index.js'; import { GENERATOR_SERVER } from '../generator-list.js'; @@ -93,6 +93,7 @@ describe(`generator - ${databaseType}`, () => { await helpers .runJHipster('server') .withJHipsterConfig(sampleConfig) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ except: ['jhipster:spring-data-relational'], filter: filterBasicServerGenerators, @@ -100,13 +101,13 @@ describe(`generator - ${databaseType}`, () => { }); it('should compose with jhipster:common', () => { - expect(runResult.mockedGenerators['jhipster:common'].callCount).toBe(1); + runResult.assertGeneratorComposedOnce('jhipster:common'); }); it(`should ${enableTranslation ? '' : 'not '}compose with jhipster:languages`, () => { - expect(runResult.mockedGenerators['jhipster:languages'].callCount).toBe(enableTranslation ? 1 : 0); + expect(runResult.getGeneratorComposeCount('jhipster:languages')).toBe(enableTranslation ? 1 : 0); }); it('should compose with jhipster:liquibase', () => { - expect(runResult.mockedGenerators['jhipster:liquibase'].callCount).toBe(1); + runResult.assertGeneratorComposedOnce('jhipster:liquibase'); }); it('should match generated files snapshot', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); diff --git a/generators/spring-data-relational/generator.ts b/generators/spring-data-relational/generator.ts index 87f03a52cf4d..043e0271f5e6 100644 --- a/generators/spring-data-relational/generator.ts +++ b/generators/spring-data-relational/generator.ts @@ -17,20 +17,25 @@ * limitations under the License. */ +import assert from 'assert'; import BaseApplicationGenerator from '../base-application/index.js'; import { GENERATOR_LIQUIBASE } from '../generator-list.js'; -import { isReservedTableName } from '../../jdl/jhipster/reserved-keywords.js'; -import { databaseTypes } from '../../jdl/jhipster/index.js'; -import { GeneratorDefinition as SpringBootGeneratorDefinition } from '../server/index.js'; +import { isReservedTableName } from '../../lib/jhipster/reserved-keywords.js'; +import { databaseTypes } from '../../lib/jhipster/index.js'; import writeTask from './files.js'; import cleanupTask from './cleanup.js'; import writeEntitiesTask, { cleanupEntitiesTask } from './entity-files.js'; import { getDBCExtraOption, getJdbcUrl, getR2dbcUrl } from './support/index.js'; -import { getDatabaseDriverForDatabase, getDatabaseTypeMavenDefinition, getH2MavenDefinition } from './internal/dependencies.js'; +import { + getDatabaseDriverForDatabase, + getDatabaseTypeMavenDefinition, + getH2MavenDefinition, + javaSqlDatabaseArtifacts, +} from './internal/dependencies.js'; const { SQL } = databaseTypes; -export default class SqlGenerator extends BaseApplicationGenerator { +export default class SqlGenerator extends BaseApplicationGenerator { async beforeQueue() { if (!this.fromBlueprint) { await this.composeWithBlueprints(); @@ -60,7 +65,7 @@ export default class SqlGenerator extends BaseApplicationGenerator this.postWriting); } + get postWritingEntities() { + return this.asPostWritingEntitiesTaskGroup({ + async jsonFilter({ application, entities, source }) { + if (application.reactive || !application.graalvmSupport) return; + for (const entity of entities.filter(({ builtIn, builtInUser, embedded }) => builtInUser || (!builtIn && !embedded))) { + source.editJavaFile!(`${application.srcMainJava}/${entity.entityAbsoluteFolder}/domain/${entity.entityClass}.java`, { + annotations: [ + { + package: 'com.fasterxml.jackson.annotation', + annotation: 'JsonFilter', + parameters: () => '"lazyPropertyFilter"', + }, + ], + }); + } + }, + }); + } + + get [BaseApplicationGenerator.POST_WRITING_ENTITIES]() { + return this.delegateTasksToBlueprint(() => this.postWritingEntities); + } + /** * @private * Returns the JDBC URL for a databaseType diff --git a/generators/spring-data-relational/internal/dependencies.ts b/generators/spring-data-relational/internal/dependencies.ts index 97f5786e9148..2d6c935d8cf6 100644 --- a/generators/spring-data-relational/internal/dependencies.ts +++ b/generators/spring-data-relational/internal/dependencies.ts @@ -17,7 +17,8 @@ * limitations under the License. */ -import { MavenDefinition, MavenPlugin } from '../../maven/types.js'; +import type { JavaDependency } from '../../java/types.js'; +import type { MavenDefinition, MavenPlugin } from '../../maven/types.js'; type DatabaseTypeDependencies = { jdbc: MavenDefinition; @@ -31,31 +32,42 @@ const testcontainerFileForDB = { postgresql: 'PostgreSqlTestContainer.java', }; -type JavaDependency = { groupId: string; artifactId: string; version?: string }; -export type DatabaseArtifact = { jdbc: JavaDependency; r2dbc: JavaDependency }; +export type DatabaseArtifact = { jdbc: JavaDependency; r2dbc?: JavaDependency; testContainer?: JavaDependency }; -const databaseArtifactForDB: Record = { +export const javaSqlDatabaseArtifacts = { mariadb: { jdbc: { groupId: 'org.mariadb.jdbc', artifactId: 'mariadb-java-client' }, // maria-r2dbc driver is failing. // r2dbc: { groupId: 'org.mariadb', artifactId: 'r2dbc-mariadb' }, r2dbc: { groupId: 'io.asyncer', artifactId: 'r2dbc-mysql' }, + testContainer: { groupId: 'org.testcontainers', artifactId: 'mariadb', scope: 'test' }, }, mssql: { jdbc: { groupId: 'com.microsoft.sqlserver', artifactId: 'mssql-jdbc' }, r2dbc: { groupId: 'io.r2dbc', artifactId: 'r2dbc-mssql' }, + testContainer: { groupId: 'org.testcontainers', artifactId: 'mssqlserver', scope: 'test' }, }, mysql: { jdbc: { groupId: 'com.mysql', artifactId: 'mysql-connector-j' }, r2dbc: { groupId: 'io.asyncer', artifactId: 'r2dbc-mysql' }, + testContainer: { groupId: 'org.testcontainers', artifactId: 'mysql', scope: 'test' }, }, postgresql: { jdbc: { groupId: 'org.postgresql', artifactId: 'postgresql' }, r2dbc: { groupId: 'org.postgresql', artifactId: 'r2dbc-postgresql' }, + testContainer: { groupId: 'org.testcontainers', artifactId: 'postgresql', scope: 'test' }, }, -}; + oracle: { + jdbc: { groupId: 'com.oracle.database.jdbc', artifactId: 'ojdbc8' }, + testContainer: { groupId: 'org.testcontainers', artifactId: 'oracle-xe', scope: 'test' }, + }, + h2: { + jdbc: { groupId: 'com.h2database', artifactId: 'h2' }, + r2dbc: { groupId: 'io.r2dbc', artifactId: 'r2dbc-h2' }, + }, +} as const satisfies Record; -export const getDatabaseDriverForDatabase = (databaseType: string) => databaseArtifactForDB[databaseType]; +export const getDatabaseDriverForDatabase = (databaseType: string) => javaSqlDatabaseArtifacts[databaseType]; export const getH2MavenDefinition = ({ prodDatabaseType, @@ -84,16 +96,15 @@ export const getH2MavenDefinition = ({ return { jdbc: { - dependencies: [{ inProfile: 'dev', groupId: 'com.h2database', artifactId: 'h2' }], + dependencies: [{ inProfile: 'dev', ...javaSqlDatabaseArtifacts.h2.jdbc }], plugins: excludeContainerPlugin, }, r2dbc: { - dependencies: [{ inProfile: 'dev', groupId: 'io.r2dbc', artifactId: 'r2dbc-h2' }], + dependencies: [{ inProfile: 'dev', ...javaSqlDatabaseArtifacts.h2.r2dbc }], }, }; }; -// eslint-disable-next-line import/prefer-default-export export const getDatabaseTypeMavenDefinition: ( databaseType: string, options: { inProfile?: string; javaDependencies: Record }, @@ -102,41 +113,41 @@ export const getDatabaseTypeMavenDefinition: ( mariadb: { jdbc: { dependencies: [ - { inProfile, ...databaseArtifactForDB.mariadb.jdbc }, - { groupId: 'org.testcontainers', artifactId: 'mariadb', scope: 'test' }, + { inProfile, ...javaSqlDatabaseArtifacts.mariadb.jdbc }, + { inProfile, ...javaSqlDatabaseArtifacts.mariadb.testContainer }, ], }, r2dbc: { - dependencies: [{ inProfile, ...databaseArtifactForDB.mariadb.r2dbc }], + dependencies: [{ inProfile, ...javaSqlDatabaseArtifacts.mariadb.r2dbc }], }, }, mssql: { jdbc: { dependencies: [ - { inProfile, ...databaseArtifactForDB.mssql.jdbc }, - { groupId: 'org.testcontainers', artifactId: 'mssqlserver', scope: 'test' }, + { inProfile, ...javaSqlDatabaseArtifacts.mssql.jdbc }, + { inProfile, ...javaSqlDatabaseArtifacts.mssql.testContainer }, ], }, r2dbc: { - dependencies: [{ inProfile, ...databaseArtifactForDB.mssql.r2dbc }], + dependencies: [{ inProfile, ...javaSqlDatabaseArtifacts.mssql.r2dbc }], }, }, mysql: { jdbc: { dependencies: [ - { inProfile, ...databaseArtifactForDB.mysql.jdbc }, - { groupId: 'org.testcontainers', artifactId: 'mysql', scope: 'test' }, + { inProfile, ...javaSqlDatabaseArtifacts.mysql.jdbc }, + { inProfile, ...javaSqlDatabaseArtifacts.mysql.testContainer }, ], }, r2dbc: { - dependencies: [{ inProfile, ...databaseArtifactForDB.mysql.r2dbc }], + dependencies: [{ inProfile, ...javaSqlDatabaseArtifacts.mysql.r2dbc }], }, }, oracle: { jdbc: { dependencies: [ - { inProfile, groupId: 'com.oracle.database.jdbc', artifactId: 'ojdbc8' }, - { groupId: 'org.testcontainers', artifactId: 'oracle-xe', scope: 'test' }, + { inProfile, ...javaSqlDatabaseArtifacts.oracle.jdbc }, + { inProfile, ...javaSqlDatabaseArtifacts.oracle.testContainer }, ], }, r2dbc: {}, @@ -144,12 +155,12 @@ export const getDatabaseTypeMavenDefinition: ( postgresql: { jdbc: { dependencies: [ - { inProfile, ...databaseArtifactForDB.postgresql.jdbc }, - { groupId: 'org.testcontainers', artifactId: 'postgresql', scope: 'test' }, + { inProfile, ...javaSqlDatabaseArtifacts.postgresql.jdbc }, + { inProfile, ...javaSqlDatabaseArtifacts.postgresql.testContainer }, ], }, r2dbc: { - dependencies: [{ inProfile, ...databaseArtifactForDB.postgresql.r2dbc }], + dependencies: [{ inProfile, ...javaSqlDatabaseArtifacts.postgresql.r2dbc }], }, }, }; diff --git a/generators/spring-data-relational/sql-entities.spec.ts b/generators/spring-data-relational/sql-entities.spec.ts index e91f926598a3..07514dc89aba 100644 --- a/generators/spring-data-relational/sql-entities.spec.ts +++ b/generators/spring-data-relational/sql-entities.spec.ts @@ -1,16 +1,16 @@ -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { + buildSamplesFromMatrix, buildServerMatrix, - extendMatrix, - extendFilteredMatrix, entitiesServerSamples as entities, - buildSamplesFromMatrix, + extendFilteredMatrix, + extendMatrix, defaultHelpers as helpers, runResult, -} from '../../testing/index.js'; +} from '../../lib/testing/index.js'; import { filterBasicServerGenerators } from '../server/__test-support/index.js'; -import { databaseTypes, cacheTypes } from '../../jdl/jhipster/index.js'; +import { cacheTypes, databaseTypes } from '../../lib/jhipster/index.js'; import { GENERATOR_SERVER } from '../generator-list.js'; const { SQL: databaseType, H2_DISK, H2_MEMORY, POSTGRESQL, MARIADB, MYSQL, MSSQL, ORACLE } = databaseTypes; @@ -80,13 +80,13 @@ describe(`generator - ${databaseType} - entities`, () => { }); it('should compose with jhipster:common', () => { - expect(runResult.mockedGenerators['jhipster:common'].callCount).toBe(1); + runResult.assertGeneratorComposedOnce('jhipster:common'); }); it(`should ${enableTranslation ? '' : 'not '}compose with jhipster:languages`, () => { - expect(runResult.mockedGenerators['jhipster:languages'].callCount).toBe(enableTranslation ? 1 : 0); + expect(runResult.getGeneratorComposeCount('jhipster:languages')).toBe(enableTranslation ? 1 : 0); }); it('should compose with jhipster:liquibase', () => { - expect(runResult.mockedGenerators['jhipster:liquibase'].callCount).toBe(1); + runResult.assertGeneratorComposedOnce('jhipster:liquibase'); }); it('should match generated files snapshot', () => { expect(runResult.getStateSnapshot()).toMatchSnapshot(); diff --git a/generators/spring-data-relational/support/application-properties.ts b/generators/spring-data-relational/support/application-properties.ts index 232c4ad10b07..ec228e755a49 100644 --- a/generators/spring-data-relational/support/application-properties.ts +++ b/generators/spring-data-relational/support/application-properties.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { databaseTypes } from '../../../jdl/jhipster/index.js'; +import { databaseTypes } from '../../../lib/jhipster/index.js'; import { getDatabaseData } from './database-data.js'; import { getJdbcUrl, getR2dbcUrl } from './database-url.js'; diff --git a/generators/spring-data-relational/support/database-data.ts b/generators/spring-data-relational/support/database-data.ts index 66ca34e665bd..118b05ddcb91 100644 --- a/generators/spring-data-relational/support/database-data.ts +++ b/generators/spring-data-relational/support/database-data.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { databaseTypes } from '../../../jdl/jhipster/index.js'; +import { databaseTypes } from '../../../lib/jhipster/index.js'; export type DatabaseData = { name: string; @@ -151,6 +151,9 @@ const databaseData: Record = { jdbcDriver: 'org.postgresql.Driver', hibernateDialect: 'org.hibernate.dialect.PostgreSQLDialect', port: ':5432/', + // Password is required by Spring Boot v3.3.x, can be removed for v3.4.x, see https://github.com/spring-projects/spring-boot/pull/41511 + // Use a strong password to avoid being flagged by SonarQube + defaultPassword: 'password', constraintNameMaxLength: 63, tableNameMaxLength: 63, diff --git a/generators/spring-data-relational/support/database-url.spec.ts b/generators/spring-data-relational/support/database-url.spec.ts index c4ffc1667fee..4fb98eba9816 100644 --- a/generators/spring-data-relational/support/database-url.spec.ts +++ b/generators/spring-data-relational/support/database-url.spec.ts @@ -1,5 +1,5 @@ -import { it, describe, expect } from 'esmocha'; -import { databaseTypes } from '../../../jdl/jhipster/index.js'; +import { describe, expect, it } from 'esmocha'; +import { databaseTypes } from '../../../lib/jhipster/index.js'; import { getJdbcUrl, getR2dbcUrl } from './database-url.js'; const { H2_MEMORY, H2_DISK, MARIADB, MSSQL, MYSQL, ORACLE, POSTGRESQL } = databaseTypes; diff --git a/generators/spring-data-relational/support/database-url.ts b/generators/spring-data-relational/support/database-url.ts index acb997f6f8a0..cd7cac385a10 100644 --- a/generators/spring-data-relational/support/database-url.ts +++ b/generators/spring-data-relational/support/database-url.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { databaseTypes } from '../../../jdl/jhipster/index.js'; +import { databaseTypes } from '../../../lib/jhipster/index.js'; import databaseData, { type getData } from './database-data.js'; const { ORACLE, MYSQL, POSTGRESQL, MARIADB, MSSQL, H2_DISK, H2_MEMORY } = databaseTypes; diff --git a/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.spring_data_persistable.ejs b/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.spring_data_persistable.ejs index 5186a2a8d178..78019cb9abc8 100644 --- a/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.spring_data_persistable.ejs +++ b/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.spring_data_persistable.ejs @@ -36,7 +36,10 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; <&_ } -&> <&_ if (fragment.classAdditionalFieldsSection) { -&> + @org.springframework.data.annotation.Transient +<%_ if (!reactive) { _%> @Transient +<%_ } _%> private boolean isPersisted; <&_ } -&> @@ -48,7 +51,10 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; } <%_ } -%> + @org.springframework.data.annotation.Transient +<%_ if (!reactive) { _%> @Transient +<%_ } _%> @Override public boolean isNew() { return !this.isPersisted; diff --git a/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.spring_data_reactive.ejs b/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.spring_data_reactive.ejs index 7655cae15704..704ee5018be1 100644 --- a/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.spring_data_reactive.ejs +++ b/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.spring_data_reactive.ejs @@ -22,7 +22,6 @@ -%> <&_ if (fragment.importSection) { -&> import org.springframework.data.annotation.Id; -import org.springframework.data.annotation.Transient; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Table; <&_ } -&> @@ -55,7 +54,7 @@ import org.springframework.data.relational.core.mapping.Table; <%_ for (const relationship of relationships) { _%> <&_ if (fragment.relationship<%- relationship.relationshipNameCapitalized %>AnnotationSection) { -&> - @Transient + @org.springframework.data.annotation.Transient <&_ } -&> <%_ } -%> diff --git a/generators/spring-data-relational/templates/src/main/java/_package_/config/DatabaseConfiguration.java.ejs b/generators/spring-data-relational/templates/src/main/java/_package_/config/DatabaseConfiguration.java.ejs index 7c90b2d65e26..e1508b1132d8 100644 --- a/generators/spring-data-relational/templates/src/main/java/_package_/config/DatabaseConfiguration.java.ejs +++ b/generators/spring-data-relational/templates/src/main/java/_package_/config/DatabaseConfiguration.java.ejs @@ -43,6 +43,10 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.data.elasticsearch.repository.config.Enable<% if (reactive) { %>Reactive<% } %>ElasticsearchRepositories; <%_ } _%> <%_ if (devDatabaseTypeH2Any) { _%> +import java.sql.SQLException; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.autoconfigure.h2.H2ConsoleProperties; import org.springframework.core.env.Environment; <%_ } _%> <%_ if (reactive) { _%> @@ -64,9 +68,6 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; <%_ } _%> import org.springframework.transaction.annotation.EnableTransactionManagement; -<%_ if (devDatabaseTypeH2Any) { _%> -import java.sql.SQLException; -<%_ } _%> <%_ if (reactive) { _%> import java.time.Duration; import java.time.Instant; @@ -94,6 +95,9 @@ import java.util.UUID; <%_ if (searchEngineElasticsearch) { _%> @Enable<% if (reactive) { %>Reactive<% } %>ElasticsearchRepositories("<%= packageName %>.repository.search") <%_ } _%> +<%_ if (devDatabaseTypeH2Any) { _%> +@EnableConfigurationProperties(H2ConsoleProperties.class) +<%_ } _%> public class DatabaseConfiguration { <%_ if (devDatabaseTypeH2Any) { _%> @@ -113,6 +117,7 @@ public class DatabaseConfiguration { */ @Bean(initMethod = "start", destroyMethod = "stop") @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) + @ConditionalOnProperty(prefix = "spring.h2.console", name = "enabled", havingValue = "true") public Object h2TCPServer() throws SQLException { String port = getValidPortForH2(); LOG.debug("H2 database is available on port {}", port); diff --git a/generators/spring-data-relational/templates/src/main/java/_package_/config/JacksonNativeConfiguration.java.ejs b/generators/spring-data-relational/templates/src/main/java/_package_/config/JacksonNativeConfiguration.java.ejs new file mode 100644 index 000000000000..fb95ea646401 --- /dev/null +++ b/generators/spring-data-relational/templates/src/main/java/_package_/config/JacksonNativeConfiguration.java.ejs @@ -0,0 +1,98 @@ +package <%=packageName%>.config; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; +import com.fasterxml.jackson.databind.ser.PropertyFilter; +import com.fasterxml.jackson.databind.ser.PropertyWriter; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; +import jakarta.persistence.Basic; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.FetchType; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.lang.annotation.Annotation; +import java.util.function.Function; +import org.hibernate.Hibernate; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JacksonNativeConfiguration { + + /* + * Filter to allow Jackson serializer to detect lazy-loaded properties when using hibernate-enhance-maven-plugin + * see: https://github.com/FasterXML/jackson-datatype-hibernate/issues/148#issuecomment-1383923857 + */ + @Bean + public Jackson2ObjectMapperBuilderCustomizer customizeJackson() { + return builder -> { + String filterName = "lazyPropertyFilter"; + builder.filters(new SimpleFilterProvider().addFilter(filterName, new LazyPropertyFilter())); + }; + } + + <%- // Thanks to @hurelhuyag for contributing the LazyPropertyFilter source. %> + private class LazyPropertyFilter implements PropertyFilter { + + public static boolean isPropertyInitialized(BeanPropertyWriter prop, Object bean) throws Exception { + return ( + Hibernate.isPropertyInitialized(bean, prop.getName()) && + isInitialized(prop, bean, ManyToOne.class, ManyToOne::fetch) && + isInitialized(prop, bean, ElementCollection.class, ElementCollection::fetch) && + isInitialized(prop, bean, OneToMany.class, OneToMany::fetch) && + isInitialized(prop, bean, Basic.class, Basic::fetch) + ); + } + + public static boolean isInitialized( + BeanPropertyWriter prop, + Object bean, + Class type, + Function fetch + ) throws Exception { + var ann = prop.getAnnotation(type); + if (ann == null) { + return true; + } + var fetchType = fetch.apply(ann); + if (fetchType == FetchType.EAGER) { + return true; + } + var value = prop.get(bean); + return Hibernate.isInitialized(value); + } + + @Override + public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider prov, PropertyWriter writer) throws Exception { + var initialized = isPropertyInitialized((BeanPropertyWriter) writer, pojo); + if (initialized) { + writer.serializeAsField(pojo, gen, prov); + } else if (!gen.canOmitFields()) { // since 2.3 + writer.serializeAsOmittedField(pojo, gen, prov); + } + } + + @Override + public void serializeAsElement(Object elementValue, JsonGenerator gen, SerializerProvider prov, PropertyWriter writer) { + throw new RuntimeException("LazyPropertyFilter.serializeAsElement() currently unsupported"); + } + + @SuppressWarnings("deprecation") + @Override + public void depositSchemaProperty(PropertyWriter writer, ObjectNode propertiesNode, SerializerProvider provider) + throws JsonMappingException { + writer.depositSchemaProperty(propertiesNode, provider); + } + + @Override + public void depositSchemaProperty(PropertyWriter writer, JsonObjectFormatVisitor objectVisitor, SerializerProvider provider) + throws JsonMappingException { + writer.depositSchemaProperty(objectVisitor, provider); + } + } +} \ No newline at end of file diff --git a/generators/spring-data-relational/templates/src/main/resources/.h2.server.properties.ejs b/generators/spring-data-relational/templates/src/main/resources/.h2.server.properties.ejs index 6e279c3f89dd..dd767bab8fa3 100644 --- a/generators/spring-data-relational/templates/src/main/resources/.h2.server.properties.ejs +++ b/generators/spring-data-relational/templates/src/main/resources/.h2.server.properties.ejs @@ -1,6 +1,6 @@ #H2 Server Properties <%_ if (devDatabaseTypeH2Memory) { _%> -0=JHipster H2 (Memory)|org.h2.Driver|jdbc\:h2\:mem\:<%= lowercaseBaseName %>|<%= baseName %> +0=JHipster H2 (Memory)|org.h2.Driver|jdbc\:h2\:mem\:<%= baseName %>|<%= baseName %> <%_ } _%> <%_ if (devDatabaseTypeH2Disk) { _%> 0=JHipster H2 (Disk)|org.h2.Driver|jdbc\:h2\:file\:./<%= temporaryDir %>h2db/db/<%= lowercaseBaseName %>|<%= baseName %> diff --git a/generators/spring-data-relational/templates/src/test/java/_package_/config/SqlTestContainersSpringContextCustomizerFactory.java.ejs b/generators/spring-data-relational/templates/src/test/java/_package_/config/SqlTestContainersSpringContextCustomizerFactory.java.ejs index a1bfbe4a864d..e57a066a89bc 100644 --- a/generators/spring-data-relational/templates/src/test/java/_package_/config/SqlTestContainersSpringContextCustomizerFactory.java.ejs +++ b/generators/spring-data-relational/templates/src/test/java/_package_/config/SqlTestContainersSpringContextCustomizerFactory.java.ejs @@ -49,8 +49,7 @@ public class SqlTestContainersSpringContextCustomizerFactory implements ContextC public ContextCustomizer createContextCustomizer(Class testClass, List configAttributes) { return new ContextCustomizer() { @Override - public void customizeContext(ConfigurableApplicationContext context, - MergedContextConfiguration mergedConfig) { + public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) { ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); TestPropertyValues testValues = TestPropertyValues.empty(); EmbeddedSQL sqlAnnotation = AnnotatedElementUtils.findMergedAnnotation(testClass, EmbeddedSQL.class); diff --git a/generators/spring-websocket/files.ts b/generators/spring-websocket/files.ts index 046cd3c30f60..8e5cf40067eb 100644 --- a/generators/spring-websocket/files.ts +++ b/generators/spring-websocket/files.ts @@ -18,11 +18,10 @@ */ import { moveToJavaPackageSrcDir } from '../server/support/index.js'; import { SERVER_MAIN_SRC_DIR } from '../generator-constants.js'; -import { WriteFileSection } from '../base/api.js'; -import { SpringBootApplication } from '../server/types.js'; -import Generator from './generator.js'; +import type { WriteFileSection } from '../base/api.js'; +import type Generator from './generator.js'; -const files: WriteFileSection = { +const files: WriteFileSection = { websocketFiles: [ { path: `${SERVER_MAIN_SRC_DIR}_package_/`, diff --git a/generators/spring-websocket/generator.spec.ts b/generators/spring-websocket/generator.spec.ts index 25f9e2cc0a48..a4a79fb2733f 100644 --- a/generators/spring-websocket/generator.spec.ts +++ b/generators/spring-websocket/generator.spec.ts @@ -1,10 +1,10 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; import { shouldSupportFeatures, testBlueprintSupport } from '../../test/support/tests.js'; -import { defaultHelpers as helpers, result } from '../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../lib/testing/index.js'; import { GENERATOR_SPRING_WEBSOCKET } from '../generator-list.js'; import Generator from './index.js'; diff --git a/generators/type-utils.ts b/generators/type-utils.ts new file mode 100644 index 000000000000..dc539b2e5e9e --- /dev/null +++ b/generators/type-utils.ts @@ -0,0 +1,27 @@ +/** + * Copyright 2013-2024 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. + */ +import type { JHipsterCommandDefinition } from '../lib/command/index.js'; + +/** + * Type inferring function to create a JHipster command definition. + * + * @param {JHipsterCommandDefinition} command + * @returns {JHipsterCommandDefinition} + */ +export const asCommand = (command: JHipsterCommandDefinition): JHipsterCommandDefinition => command; diff --git a/generators/upgrade/command.ts b/generators/upgrade/command.ts index 75c5870dd6e2..edae9bd606d3 100644 --- a/generators/upgrade/command.ts +++ b/generators/upgrade/command.ts @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JHipsterCommandDefinition } from '../base/api.js'; +import type { JHipsterCommandDefinition } from '../../lib/command/index.js'; import { GENERATOR_APP } from '../generator-list.js'; const command: JHipsterCommandDefinition = { diff --git a/generators/upgrade/generator.spec.js b/generators/upgrade/generator.spec.ts similarity index 93% rename from generators/upgrade/generator.spec.js rename to generators/upgrade/generator.spec.ts index 512092a9d8cd..0f9357dac9c3 100644 --- a/generators/upgrade/generator.spec.js +++ b/generators/upgrade/generator.spec.ts @@ -18,12 +18,12 @@ */ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { it, describe, expect, before, fn } from 'esmocha'; +import { before, describe, expect, fn, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import git from 'simple-git'; +import { simpleGit } from 'simple-git'; import { shouldSupportFeatures } from '../../test/support/tests.js'; -import { basicHelpers as helpers, result } from '../../testing/index.js'; +import { defaultHelpers as helpers, result } from '../../lib/testing/index.js'; import { UPGRADE_BRANCH } from './support/index.js'; import Generator from './index.js'; @@ -68,7 +68,7 @@ describe(`generator - ${generator}`, () => { }) .commitFiles() .onEnvironment(async ctx => { - await git(ctx.cwd).init().add('package.json').commit('project'); + await simpleGit(ctx.cwd).init().add('package.json').commit('project'); }), ).rejects.toThrow('local changes found.'); }); @@ -82,7 +82,7 @@ describe(`generator - ${generator}`, () => { }) .commitFiles() .onEnvironment(async ctx => { - await git(ctx.cwd).init().add('.').commit('project', ['--no-verify']).checkoutLocalBranch(UPGRADE_BRANCH); + await simpleGit(ctx.cwd).init().add('.').commit('project', ['--no-verify']).checkoutLocalBranch(UPGRADE_BRANCH); }), ).rejects.toThrow('You are on the upgrade branch, please switch to another branch before upgrading.'); }); @@ -137,7 +137,7 @@ describe(`generator - ${generator}`, () => { .runJHipster(generator) .withJHipsterConfig() .withSpawnMock({ - registerSinonDefaults: false, + registerNodeMockDefaults: false, stub: fn(), }) .withFiles({ @@ -165,7 +165,7 @@ describe(`generator - ${generator}`, () => { .runJHipster(generator) .withJHipsterConfig() .withSpawnMock({ - registerSinonDefaults: false, + registerNodeMockDefaults: false, stub: fn(), }) .withFiles({ diff --git a/generators/upgrade/generator.js b/generators/upgrade/generator.ts similarity index 98% rename from generators/upgrade/generator.js rename to generators/upgrade/generator.ts index df56b82fcb10..f464cc2cb77e 100644 --- a/generators/upgrade/generator.js +++ b/generators/upgrade/generator.ts @@ -49,8 +49,9 @@ export default class UpgradeGenerator extends BaseGenerator { actualApplicationBranch; silent; applyConfig; - spawnStdio = 'inherit'; + spawnStdio: 'inherit' | 'ignore' | 'pipe' | 'overlapped' = 'inherit'; executable; + verbose!: boolean; async beforeQueue() { if (!this.fromBlueprint) { @@ -176,7 +177,7 @@ export default class UpgradeGenerator extends BaseGenerator { // Make sure the node_modules is up to date await this.spawnCommand('npm install', { stdio: this.spawnStdio }); - const customCliOptions = []; + const customCliOptions: string[] = []; if (this.getPackageJsonVersion() === '7.9.4') { customCliOptions.push('--with-entities'); } @@ -322,7 +323,7 @@ export default class UpgradeGenerator extends BaseGenerator { const generatorOptions = { ...inheritedOptions, ...DEFAULT_NON_INTERATIVE_OPTIONS }; // We should not reuse sharedData at non interactive runs - delete generatorOptions.sharedData; + delete (generatorOptions as any).sharedData; const envBuilder = await this.createEnvBuilder(envOptions); const env = envBuilder.getEnvironment(); diff --git a/generators/upgrade/upgrade.spec.ts b/generators/upgrade/upgrade.spec.ts index 8061a0ed7bc4..3a2234985270 100644 --- a/generators/upgrade/upgrade.spec.ts +++ b/generators/upgrade/upgrade.spec.ts @@ -1,18 +1,14 @@ -import path, { dirname } from 'path'; -import { fileURLToPath } from 'url'; +import path from 'path'; import { mkdirSync, writeFileSync } from 'fs'; import { escapeRegExp } from 'lodash-es'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { execaCommandSync } from 'execa'; import { packageJson } from '../../lib/index.js'; import { GENERATOR_APP, GENERATOR_UPGRADE } from '../generator-list.js'; -import { basicHelpers as helpers, getGenerator, result as runResult } from '../../testing/index.js'; +import { basicHelpers as helpers, result as runResult } from '../../lib/testing/index.js'; const writeJsonSync = (file, content) => writeFileSync(file, JSON.stringify(content, null, 2)); -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - describe('generator - upgrade', function () { describe('default application', () => { before(async () => { @@ -23,12 +19,11 @@ describe('generator - upgrade', function () { skipServer: true, baseName: 'upgradeTest', }) - .withOptions({ useVersionPlaceholders: false }); - await runResult - .create(getGenerator(GENERATOR_UPGRADE)) + .withOptions({ skipGit: false, useVersionPlaceholders: false }); + await helpers + .runJHipsterInApplication(GENERATOR_UPGRADE) .withSpawnMock() - .withOptions({ useVersionPlaceholders: false } as any) - .run(); + .withOptions({ useVersionPlaceholders: false } as any); }); it('generated git commits to match snapshot', () => { @@ -72,27 +67,22 @@ Initial version of upgradeTest generated by generator-jhipster@undefined" writeJsonSync(path.join(fakeBlueprintModuleDir, 'package.json'), packagejs); // Create an fake generator, otherwise env.lookup doesn't find it. writeFileSync(path.join(fakeBlueprintModuleDir, 'generators', 'fake', 'index.js'), ''); - return helpers - .create(path.join(__dirname, '../generators/app/index.js'), { tmpdir: false }) + await helpers + .runJHipster('app', { tmpdir: false }) .withJHipsterConfig({ skipClient: true, skipServer: true, baseName: 'upgradeTest', }) .withOptions({ + skipGit: false, blueprints: blueprintName, - }) - .run() - .then(() => { - return helpers - .create(path.join(__dirname, '../generators/upgrade/index.js'), { tmpdir: false }) - .withOptions({ - force: true, - silent: false, - targetVersion: packageJson.version, - }) - .run(); }); + await helpers.runJHipsterInApplication('upgrade').withOptions({ + force: true, + silent: false, + targetVersion: packageJson.version, + }); }); it('generated git commits to match snapshot', () => { diff --git a/generators/vue/__snapshots__/generator.spec.ts.snap b/generators/vue/__snapshots__/generator.spec.ts.snap index a434261f6ce6..978209a6225e 100644 --- a/generators/vue/__snapshots__/generator.spec.ts.snap +++ b/generators/vue/__snapshots__/generator.spec.ts.snap @@ -17,13 +17,10 @@ exports[`generator - vue gateway-jwt-skipUserManagement(true)-withAdminUi(false) ".yo-rc.json": { "stateCleared": "modified", }, - "clientRoot/.eslintignore": { - "stateCleared": "modified", - }, - "clientRoot/.eslintrc.cjs": { + "clientRoot/.postcssrc.js": { "stateCleared": "modified", }, - "clientRoot/.postcssrc.js": { + "clientRoot/eslint.config.mjs": { "stateCleared": "modified", }, "clientRoot/package.json": { @@ -452,6 +449,9 @@ exports[`generator - vue gateway-jwt-skipUserManagement(true)-withAdminUi(false) "clientRoot/vitest.config.mts": { "stateCleared": "modified", }, + "package.json": { + "stateCleared": "modified", + }, } `; @@ -472,13 +472,10 @@ exports[`generator - vue gateway-oauth2-withAdminUi(true)-skipJhipsterDependenci ".yo-rc.json": { "stateCleared": "modified", }, - "clientRoot/.eslintignore": { - "stateCleared": "modified", - }, - "clientRoot/.eslintrc.cjs": { + "clientRoot/.postcssrc.js": { "stateCleared": "modified", }, - "clientRoot/.postcssrc.js": { + "clientRoot/eslint.config.mjs": { "stateCleared": "modified", }, "clientRoot/package.json": { @@ -979,6 +976,9 @@ exports[`generator - vue gateway-oauth2-withAdminUi(true)-skipJhipsterDependenci "clientRoot/vitest.config.mts": { "stateCleared": "modified", }, + "package.json": { + "stateCleared": "modified", + }, } `; @@ -999,13 +999,13 @@ exports[`generator - vue microservice-jwt-skipUserManagement(false)-withAdminUi( ".yo-rc.json": { "stateCleared": "modified", }, - "clientRoot/.eslintignore": { + "clientRoot/.postcssrc.js": { "stateCleared": "modified", }, - "clientRoot/.eslintrc.cjs": { + "clientRoot/eslint.config.mjs": { "stateCleared": "modified", }, - "clientRoot/.postcssrc.js": { + "clientRoot/module-federation.config.cjs": { "stateCleared": "modified", }, "clientRoot/package.json": { @@ -1458,17 +1458,14 @@ exports[`generator - vue microservice-jwt-skipUserManagement(false)-withAdminUi( "clientRoot/webpack/webpack.prod.js": { "stateCleared": "modified", }, + "package.json": { + "stateCleared": "modified", + }, } `; exports[`generator - vue microservice-oauth2-withAdminUi(true)-skipJhipsterDependencies(true)-enableTranslation(true)--websocket(false) should match generated files snapshot 1`] = ` { - ".eslintignore": { - "stateCleared": "modified", - }, - ".eslintrc.cjs": { - "stateCleared": "modified", - }, ".jhipster/EntityWithCustomId.json": { "stateCleared": "modified", }, @@ -1487,6 +1484,12 @@ exports[`generator - vue microservice-oauth2-withAdminUi(true)-skipJhipsterDepen ".yo-rc.json": { "stateCleared": "modified", }, + "eslint.config.mjs": { + "stateCleared": "modified", + }, + "module-federation.config.cjs": { + "stateCleared": "modified", + }, "package.json": { "stateCleared": "modified", }, @@ -1942,12 +1945,6 @@ exports[`generator - vue microservice-oauth2-withAdminUi(true)-skipJhipsterDepen exports[`generator - vue monolith-jwt-skipUserManagement(false)-withAdminUi(true)-skipJhipsterDependencies(true)-enableTranslation(true)--websocket(true) should match generated files snapshot 1`] = ` { - ".eslintignore": { - "stateCleared": "modified", - }, - ".eslintrc.cjs": { - "stateCleared": "modified", - }, ".jhipster/EntityWithCustomId.json": { "stateCleared": "modified", }, @@ -1966,6 +1963,9 @@ exports[`generator - vue monolith-jwt-skipUserManagement(false)-withAdminUi(true ".yo-rc.json": { "stateCleared": "modified", }, + "eslint.config.mjs": { + "stateCleared": "modified", + }, "package.json": { "stateCleared": "modified", }, @@ -2556,12 +2556,6 @@ exports[`generator - vue monolith-jwt-skipUserManagement(false)-withAdminUi(true exports[`generator - vue monolith-oauth2-withAdminUi(false)-skipJhipsterDependencies(false)-enableTranslation(false)-websocket(false) should match generated files snapshot 1`] = ` { - ".eslintignore": { - "stateCleared": "modified", - }, - ".eslintrc.cjs": { - "stateCleared": "modified", - }, ".jhipster/EntityWithCustomId.json": { "stateCleared": "modified", }, @@ -2580,6 +2574,9 @@ exports[`generator - vue monolith-oauth2-withAdminUi(false)-skipJhipsterDependen ".yo-rc.json": { "stateCleared": "modified", }, + "eslint.config.mjs": { + "stateCleared": "modified", + }, "package.json": { "stateCleared": "modified", }, @@ -2990,12 +2987,6 @@ exports[`generator - vue monolith-oauth2-withAdminUi(false)-skipJhipsterDependen exports[`generator - vue monolith-session-skipUserManagement(true)-withAdminUi(false)-skipJhipsterDependencies(false)-enableTranslation(false)-websocket(true) should match generated files snapshot 1`] = ` { - ".eslintignore": { - "stateCleared": "modified", - }, - ".eslintrc.cjs": { - "stateCleared": "modified", - }, ".jhipster/EntityWithCustomId.json": { "stateCleared": "modified", }, @@ -3014,6 +3005,9 @@ exports[`generator - vue monolith-session-skipUserManagement(true)-withAdminUi(f ".yo-rc.json": { "stateCleared": "modified", }, + "eslint.config.mjs": { + "stateCleared": "modified", + }, "package.json": { "stateCleared": "modified", }, diff --git a/generators/vue/cleanup.js b/generators/vue/cleanup.ts similarity index 97% rename from generators/vue/cleanup.js rename to generators/vue/cleanup.ts index db9ca64fe4c8..87a87e4b9b92 100644 --- a/generators/vue/cleanup.js +++ b/generators/vue/cleanup.ts @@ -17,11 +17,13 @@ * limitations under the License. */ +import { asWritingTask } from '../base-application/support/task-type-inference.js'; + /** * Removes files that where generated in previous JHipster versions and therefore * need to be removed. */ -export default function cleanupOldFilesTask({ application } = {}) { +export default asWritingTask(function cleanupOldFilesTask({ application }) { if (this.isJhipsterVersionLessThan('7.0.0-beta.0')) { this.removeFile(`${application.clientSrcDir}app/admin/audits/audits.component.ts`); this.removeFile(`${application.clientSrcDir}app/admin/audits/audits.service.ts`); @@ -106,4 +108,4 @@ export default function cleanupOldFilesTask({ application } = {}) { this.removeFile('vite.config.ts'); this.removeFile('vitest.config.ts'); } -} +}); diff --git a/generators/vue/entity-files-vue.js b/generators/vue/entity-files-vue.ts similarity index 81% rename from generators/vue/entity-files-vue.js rename to generators/vue/entity-files-vue.ts index f5aded49014c..df21f9861e0a 100644 --- a/generators/vue/entity-files-vue.js +++ b/generators/vue/entity-files-vue.ts @@ -16,6 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { asPostWritingEntitiesTask, asWritingEntitiesTask } from '../base-application/support/index.js'; import { clientApplicationTemplatesBlock } from '../client/support/index.js'; export const entityFiles = { @@ -50,7 +51,7 @@ export const entityFiles = { ], }; -export async function writeEntityFiles({ control, application, entities }) { +export const writeEntityFiles = asWritingEntitiesTask(async function writeEntityFiles({ control, application, entities }) { for (const entity of (control.filterEntitiesAndPropertiesForClient ?? (entities => entities))(entities).filter( entity => !entity.skipClient && !entity.builtInUser, )) { @@ -59,9 +60,9 @@ export async function writeEntityFiles({ control, application, entities }) { context: { ...application, ...entity }, }); } -} +}); -export async function postWriteEntityFiles({ control, application, entities }) { +export const postWriteEntityFiles = asPostWritingEntitiesTask(async function postWriteEntityFiles({ control, application, entities }) { for (const entity of (control.filterEntitiesForClient ?? (entities => entities))(entities).filter(entity => !entity.builtInUser)) { if (!entity.embedded) { const { enableTranslation } = application; @@ -76,10 +77,10 @@ export async function postWriteEntityFiles({ control, application, entities }) { readOnly, entityClassPlural, i18nKeyPrefix, - pageTitle = enableTranslation ? `${i18nKeyPrefix}.home.title` : entityClassPlural, } = entity; + const pageTitle = ((entity as any).pageTitle ?? enableTranslation) ? `${i18nKeyPrefix}.home.title` : entityClassPlural; - this.addEntityToModule( + (this as any).addEntityToModule( entityInstance, entityClass, entityAngularName, @@ -90,12 +91,17 @@ export async function postWriteEntityFiles({ control, application, entities }) { readOnly, pageTitle, ); - this.addEntityToMenu(entity.entityPage, application.enableTranslation, entity.entityTranslationKeyMenu, entity.entityClassHumanized); + (this as any).addEntityToMenu( + entity.entityPage, + application.enableTranslation, + entity.entityTranslationKeyMenu, + entity.entityClassHumanized, + ); } } -} +}); -export function cleanupEntitiesFiles({ control, application, entities }) { +export const cleanupEntitiesFiles = asWritingEntitiesTask(function cleanupEntitiesFiles({ control, application, entities }) { for (const entity of (control.filterEntitiesForClient ?? (entities => entities))(entities).filter(entity => !entity.builtInUser)) { const { entityFolderName, entityFileName } = entity; if (this.isJhipsterVersionLessThan('8.0.0-beta.3')) { @@ -105,4 +111,4 @@ export function cleanupEntitiesFiles({ control, application, entities }) { this.removeFile(`${application.clientTestDir}/spec/app/entities/${entityFolderName}/${entityFileName}.service.spec.ts`); } } -} +}); diff --git a/generators/vue/files-vue.js b/generators/vue/files-vue.ts similarity index 94% rename from generators/vue/files-vue.js rename to generators/vue/files-vue.ts index 41eb2b2a774a..dcf63b6c2ce7 100644 --- a/generators/vue/files-vue.js +++ b/generators/vue/files-vue.ts @@ -17,19 +17,20 @@ * limitations under the License. */ +import { asWritingEntitiesTask, asWritingTask } from '../base-application/support/index.js'; import { clientApplicationTemplatesBlock, clientRootTemplatesBlock, clientSrcTemplatesBlock } from '../client/support/files.js'; export const vueFiles = { common: [ clientRootTemplatesBlock({ templates: [ + '.postcssrc.js', + { sourceFile: 'eslint.config.js.jhi.vue', destinationFile: ctx => `${ctx.eslintConfigFile}.jhi.vue` }, 'package.json', 'tsconfig.json', 'tsconfig.app.json', 'tsconfig.node.json', 'tsconfig.vitest.json', - '.postcssrc.js', - '.eslintrc.cjs', 'vite.config.mts', 'vitest.config.mts', ], @@ -38,13 +39,16 @@ export const vueFiles = { microfrontend: [ clientRootTemplatesBlock({ condition: generator => generator.microfrontend, + templates: ['module-federation.config.cjs'], + }), + clientRootTemplatesBlock({ + condition: ctx => ctx.microfrontend && ctx.clientBundlerWebpack, templates: [ 'webpack/config.js', 'webpack/webpack.common.js', 'webpack/webpack.dev.js', 'webpack/webpack.prod.js', 'webpack/vue.utils.js', - 'webpack/webpack.microfrontend.js.jhi.vue', ], }), { @@ -294,14 +298,14 @@ export const entitiesFiles = { ], }; -export async function writeFiles({ application }) { +export const writeFiles = asWritingTask(async function writeFiles({ application }) { await this.writeFiles({ sections: vueFiles, context: application, }); -} +}); -export async function writeEntitiesFiles({ application, entities }) { +export const writeEntitiesFiles = asWritingEntitiesTask(async function writeEntitiesFiles({ application, entities }) { entities = entities.filter(entity => !entity.skipClient && !entity.builtInUser); await this.writeFiles({ sections: entitiesFiles, @@ -310,4 +314,4 @@ export async function writeEntitiesFiles({ application, entities }) { entities, }, }); -} +}); diff --git a/generators/vue/generator.spec.ts b/generators/vue/generator.spec.ts index b2b035ec8c6e..77ef9c93d759 100644 --- a/generators/vue/generator.spec.ts +++ b/generators/vue/generator.spec.ts @@ -1,12 +1,12 @@ -import { basename, dirname, join } from 'path'; +import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { before, it, describe, expect } from 'esmocha'; +import { before, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; -import { buildClientSamples, entitiesClientSamples as entities, defaultHelpers as helpers, runResult } from '../../testing/index.js'; -import { shouldSupportFeatures, testBlueprintSupport, checkEnforcements } from '../../test/support/index.js'; +import { buildClientSamples, entitiesClientSamples as entities, defaultHelpers as helpers, runResult } from '../../lib/testing/index.js'; +import { checkEnforcements, shouldSupportFeatures, testBlueprintSupport } from '../../test/support/index.js'; -import { clientFrameworkTypes } from '../../jdl/jhipster/index.js'; +import { clientFrameworkTypes } from '../../lib/jhipster/index.js'; import { CLIENT_MAIN_SRC_DIR } from '../generator-constants.js'; import { GENERATOR_VUE } from '../generator-list.js'; import Generator from './index.js'; @@ -15,7 +15,6 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const generator = basename(__dirname); -const generatorFile = join(__dirname, 'index.ts'); const { VUE: clientFramework } = clientFrameworkTypes; const commonConfig = { clientFramework, nativeLanguage: 'en', languages: ['fr', 'en'] }; @@ -68,7 +67,7 @@ describe(`generator - ${clientFramework}`, () => { describe(name, () => { before(async () => { await helpers - .run(generatorFile) + .runJHipster(generator) .withJHipsterConfig(sampleConfig, entities) .withControl({ getWebappTranslation: () => 'translations' }) .withSharedApplication({ gatewayServicesApiAvailable: sampleConfig.applicationType === 'gateway' }) diff --git a/generators/vue/generator.js b/generators/vue/generator.ts similarity index 65% rename from generators/vue/generator.js rename to generators/vue/generator.ts index d2e78e361225..04cca3fb6b3c 100644 --- a/generators/vue/generator.js +++ b/generators/vue/generator.ts @@ -16,25 +16,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { relative } from 'path'; +import assert from 'node:assert'; import chalk from 'chalk'; import { isFileStateModified } from 'mem-fs-editor/state'; import { camelCase, startCase } from 'lodash-es'; import BaseApplicationGenerator from '../base-application/index.js'; -import { fieldTypes, clientFrameworkTypes } from '../../jdl/jhipster/index.js'; -import { GENERATOR_VUE, GENERATOR_CLIENT, GENERATOR_LANGUAGES } from '../generator-list.js'; +import { clientFrameworkTypes, fieldTypes } from '../../lib/jhipster/index.js'; +import { GENERATOR_CLIENT, GENERATOR_LANGUAGES, GENERATOR_VUE } from '../generator-list.js'; import { + generateEntityClientImports as formatEntityClientImports, generateEntityClientEnumImports as getClientEnumImportsFormat, generateEntityClientFields as getHydratedEntityClientFields, - generateEntityClientImports as formatEntityClientImports, - generateTestEntityId as getTestEntityId, getTypescriptKeyType as getTSKeyType, + generateTestEntityId as getTestEntityId, } from '../client/support/index.js'; import { createNeedleCallback } from '../base/support/index.js'; -import { writeEntityFiles, postWriteEntityFiles, cleanupEntitiesFiles } from './entity-files-vue.js'; +import { writeEslintClientRootConfigFile } from '../javascript/generators/eslint/support/tasks.js'; +import { cleanupEntitiesFiles, postWriteEntityFiles, writeEntityFiles } from './entity-files-vue.js'; import cleanupOldFilesTask from './cleanup.js'; -import { writeFiles, writeEntitiesFiles } from './files-vue.js'; +import { writeEntitiesFiles, writeFiles } from './files-vue.js'; import { convertTranslationsSupport, isTranslatedVueFile, translateVueFilesTransform } from './support/index.js'; const { CommonDBTypes } = fieldTypes; @@ -61,6 +62,12 @@ export default class VueGenerator extends BaseApplicationGenerator { this.fetchFromInstalledJHipster(GENERATOR_VUE, 'resources', 'package.json'), ); }, + applicationDefauts({ applicationDefaults }) { + applicationDefaults({ + __override__: true, + typescriptEslint: true, + }); + }, }); } @@ -70,16 +77,21 @@ export default class VueGenerator extends BaseApplicationGenerator { get preparing() { return this.asPreparingTaskGroup({ + applicationDefauts({ applicationDefaults }) { + applicationDefaults({ + __override__: true, + eslintConfigFile: app => `eslint.config.${app.packageJsonType === 'module' ? 'js' : 'mjs'}`, + clientWebappDir: app => `${app.clientSrcDir}app/`, + webappEnumerationsDir: app => `${app.clientWebappDir}shared/model/enumerations/`, + }); + }, prepareForTemplates({ application, source }) { - application.clientWebappDir = `${application.clientSrcDir}app/`; - application.webappEnumerationsDir = `${application.clientWebappDir}shared/model/enumerations/`; - application.clientSpecDir = `${application.clientTestDir}spec/`; - - // Can be dropped if tests are moved near implementation - application.applicationRootRelativeToClientTestDir = `${relative(application.clientSpecDir, '.')}/`; - application.clientSrcDirRelativeToClientTestDir = `${relative(application.clientSpecDir, application.clientWebappDir)}/`; + application.addPrettierExtensions?.(['html', 'vue', 'css', 'scss']); source.addWebpackConfig = args => { + if (!application.clientBundlerWebpack) { + throw new Error('This application is not webpack based'); + } const webpackPath = `${application.clientRootDir}webpack/webpack.common.js`; const ignoreNonExisting = this.sharedData.getControl().ignoreNeedlesError && 'Webpack configuration file not found'; this.editFile( @@ -99,24 +111,14 @@ export default class VueGenerator extends BaseApplicationGenerator { return this.delegateTasksToBlueprint(() => this.preparing); } - get preparingEachEntity() { - return this.asPreparingEachEntityTaskGroup({ - prepareEntityForTemplates({ entity }) { - // Can be dropped if tests are moved near implementation - entity.relativeToEntityFolderName = relative(entity.entityFolderName, '.'); - }, - }); - } - - get [BaseApplicationGenerator.PREPARING_EACH_ENTITY]() { - return this.delegateTasksToBlueprint(() => this.preparingEachEntity); - } - get default() { return this.asDefaultTaskGroup({ async queueTranslateTransform({ control, application }) { const { enableTranslation, clientSrcDir } = application; const { getWebappTranslation } = control; + + assert.ok(getWebappTranslation, 'getWebappTranslation is required'); + this.queueTransformStream( { name: 'translating vue application', @@ -146,7 +148,13 @@ export default class VueGenerator extends BaseApplicationGenerator { get writing() { return this.asWritingTaskGroup({ + async cleanup({ control }) { + await control.cleanupFiles({ + '8.6.1': ['.eslintrc.json', '.eslintignore'], + }); + }, cleanupOldFilesTask, + writeEslintClientRootConfigFile, writeFiles, }); } @@ -169,13 +177,88 @@ export default class VueGenerator extends BaseApplicationGenerator { get postWriting() { return this.asPostWritingTaskGroup({ + addPackageJsonScripts({ application }) { + const { clientBundlerVite, clientBundlerWebpack, clientPackageManager, prettierExtensions } = application; + if (clientBundlerVite) { + this.packageJson.merge({ + scripts: { + 'webapp:build:dev': `${clientPackageManager} run vite-build`, + 'webapp:build:prod': `${clientPackageManager} run vite-build`, + 'webapp:dev': `${clientPackageManager} run vite-serve`, + 'webapp:serve': `${clientPackageManager} run vite-serve`, + 'vite-serve': 'vite', + 'vite-build': 'vite build', + }, + }); + } else if (clientBundlerWebpack) { + this.packageJson.merge({ + scripts: { + 'prettier:check': `prettier --check "{,src/**/,webpack/,.blueprint/**/}*.{${prettierExtensions}}"`, + 'prettier:format': `prettier --write "{,src/**/,webpack/,.blueprint/**/}*.{${prettierExtensions}}"`, + 'webapp:build:dev': `${clientPackageManager} run webpack -- --mode development --env stats=minimal`, + 'webapp:build:prod': `${clientPackageManager} run webpack -- --mode production --env stats=minimal`, + 'webapp:dev': `${clientPackageManager} run webpack-dev-server -- --mode development --env stats=normal`, + 'webpack-dev-server': 'webpack serve --config webpack/webpack.common.js', + webpack: 'webpack --config webpack/webpack.common.js', + }, + }); + } + }, + addMicrofrontendDependencies({ application }) { + const { applicationTypeGateway, clientBundlerVite, clientBundlerWebpack, enableTranslation, microfrontend } = application; + if (!microfrontend) return; + if (clientBundlerVite) { + this.packageJson.merge({ + devDependencies: { + '@originjs/vite-plugin-federation': '1.3.6', + }, + }); + } else if (clientBundlerWebpack) { + if (applicationTypeGateway) { + this.packageJson.merge({ + devDependencies: { + '@module-federation/utilities': null, + }, + }); + } + this.packageJson.merge({ + devDependencies: { + '@module-federation/enhanced': null, + 'browser-sync-webpack-plugin': null, + 'copy-webpack-plugin': null, + 'css-loader': null, + 'css-minimizer-webpack-plugin': null, + 'html-webpack-plugin': null, + 'mini-css-extract-plugin': null, + 'postcss-loader': null, + 'sass-loader': null, + 'terser-webpack-plugin': null, + 'ts-loader': null, + 'vue-loader': null, + 'vue-style-loader': null, + webpack: null, + 'webpack-bundle-analyzer': null, + 'webpack-cli': null, + 'webpack-dev-server': null, + 'webpack-merge': null, + 'workbox-webpack-plugin': null, + ...(enableTranslation + ? { + 'folder-hash': null, + 'merge-jsons-webpack-plugin': null, + } + : {}), + }, + }); + } + }, addIndexAsset({ source, application }) { - if (application.microfrontend) return; - source.addExternalResourceToRoot({ + if (!application.clientBundlerVite) return; + source.addExternalResourceToRoot!({ resource: '', comment: 'Workaround https://github.com/axios/axios/issues/5622', }); - source.addExternalResourceToRoot({ + source.addExternalResourceToRoot!({ resource: ``, comment: 'Load vue main', }); @@ -247,17 +330,7 @@ export default class VueGenerator extends BaseApplicationGenerator { * @param {boolean} readOnly - If the entity is read-only or not * @param {string} pageTitle - The translation key or the text for the page title in the browser */ - addEntityToModule( - entityInstance = this.entityInstance, - entityClass = this.entityClass, - entityName = this.entityAngularName, - entityFolderName = this.entityFolderName, - entityFileName = this.entityFileName, - _entityUrl = this.entityUrl, - _microserviceName = this.microserviceName, - readOnly = this.readOnly, - _pageTitle = this.enableTranslation ? `${this.i18nKeyPrefix}.home.title` : this.entityClassPlural, - ) { + addEntityToModule(entityInstance, entityClass, entityName, entityFolderName, entityFileName, _entityUrl, _microserviceName, readOnly?) { this.needleApi.clientVue.addEntityToRouterImport(entityName, entityFileName, entityFolderName, readOnly); this.needleApi.clientVue.addEntityToRouter(entityInstance, entityName, entityFileName, readOnly); this.needleApi.clientVue.addEntityServiceToEntitiesComponentImport(entityName, entityClass, entityFileName, entityFolderName); diff --git a/generators/vue/resources/package.json b/generators/vue/resources/package.json index 61b36e9d4821..83bfc7cca195 100644 --- a/generators/vue/resources/package.json +++ b/generators/vue/resources/package.json @@ -6,70 +6,70 @@ "@stomp/rx-stomp": "2.0.0", "@vuelidate/core": "2.0.3", "@vuelidate/validators": "2.0.4", - "@vueuse/core": "10.11.0", - "axios": "1.7.2", + "@vueuse/core": "11.1.0", + "axios": "1.7.7", "bootstrap": "4.6.2", "bootstrap-vue": "2.23.1", "bootswatch": "4.6.2", "deepmerge": "4.3.1", "js-cookie": "3.0.5", - "pinia": "2.1.7", + "pinia": "2.2.5", "rxjs": "7.8.1", "sockjs-client": "1.6.1", - "vue": "3.4.21", - "vue-i18n": "9.13.1", - "vue-router": "4.4.0" + "vue": "3.5.12", + "vue-i18n": "10.0.4", + "vue-router": "4.4.5" }, "devDependencies": { - "@module-federation/utilities": "3.0.3-0", - "@pinia/testing": "0.1.3", - "@rushstack/eslint-patch": "1.10.3", + "@eslint/js": "9.13.0", + "@module-federation/enhanced": "0.6.13", + "@module-federation/utilities": "3.1.19", + "@pinia/testing": "0.1.6", "@tsconfig/node18": "18.2.4", "@types/node": "20.11.25", "@types/sinon": "17.0.3", - "@vitejs/plugin-vue": "5.0.5", - "@vue/eslint-config-prettier": "9.0.0", - "@vue/eslint-config-typescript": "13.0.0", + "@vitejs/plugin-vue": "5.1.4", "@vue/test-utils": "2.4.6", "@vue/tsconfig": "0.5.1", - "autoprefixer": "10.4.19", - "axios-mock-adapter": "1.22.0", + "autoprefixer": "10.4.20", + "axios-mock-adapter": "2.1.0", "browser-sync-webpack-plugin": "2.3.0", "copy-webpack-plugin": "12.0.2", "css-loader": "7.1.2", "css-minimizer-webpack-plugin": "7.0.0", - "eslint": "8.57.0", + "eslint": "9.13.0", "eslint-plugin-prettier": "5.2.1", - "eslint-plugin-vue": "9.27.0", + "eslint-plugin-vue": "9.30.0", "flush-promises": "1.0.2", "folder-hash": "4.0.4", "happy-dom": "14.12.3", - "html-webpack-plugin": "5.6.0", + "html-webpack-plugin": "5.6.3", "merge-jsons-webpack-plugin": "2.0.1", - "mini-css-extract-plugin": "2.9.0", + "mini-css-extract-plugin": "2.9.1", "numeral": "2.0.6", "postcss-import": "16.1.0", "postcss-loader": "8.1.1", "postcss-url": "10.1.3", "rimraf": "5.0.8", - "sass": "1.77.8", - "sass-loader": "14.2.1", - "sinon": "18.0.0", + "sass": "1.64.2", + "sass-loader": "16.0.2", + "sinon": "19.0.2", "terser-webpack-plugin": "5.3.10", "ts-loader": "9.5.1", - "typescript": "5.5.3", - "vite": "5.3.4", - "vite-plugin-static-copy": "1.0.6", - "vitest": "2.0.3", + "typescript": "5.6.3", + "typescript-eslint": "8.12.2", + "vite": "5.4.10", + "vite-plugin-static-copy": "2.0.0", + "vitest": "2.1.4", "vitest-sonar-reporter": "2.0.0", "vue-loader": "17.4.2", "vue-style-loader": "4.1.3", - "vue-tsc": "2.0.26", - "webpack": "5.93.0", + "vue-tsc": "2.1.8", + "webpack": "5.95.0", "webpack-bundle-analyzer": "4.10.2", "webpack-cli": "5.1.4", - "webpack-dev-server": "5.0.4", + "webpack-dev-server": "5.1.0", "webpack-merge": "6.0.1", - "workbox-webpack-plugin": "7.1.0" + "workbox-webpack-plugin": "7.3.0" } } diff --git a/generators/vue/support/index.ts b/generators/vue/support/index.ts index caec84a41b1b..b0c67885abbf 100644 --- a/generators/vue/support/index.ts +++ b/generators/vue/support/index.ts @@ -17,7 +17,6 @@ * limitations under the License. */ export { default as convertTranslationsSupport } from './convert-translation.js'; -export * from './needles.js'; export * from './translate-vue.js'; export { default as translateVueFilesTransform } from './translate-vue.js'; export { default as updateLanguagesTask } from './update-languages.js'; diff --git a/generators/vue/support/translate-vue.spec.ts b/generators/vue/support/translate-vue.spec.ts index 5719ebbe05b6..26a7f50a7cd9 100644 --- a/generators/vue/support/translate-vue.spec.ts +++ b/generators/vue/support/translate-vue.spec.ts @@ -17,33 +17,33 @@ * limitations under the License. */ import { inspect } from 'node:util'; -import { it, describe, expect } from 'esmocha'; -import { replaceTranslationTags, replaceTranslations, removeDeclarations } from './translate-vue.js'; +import { describe, expect, it } from 'esmocha'; +import { removeDeclarations, replaceTranslationTags, replaceTranslations } from './translate-vue.js'; const FULL_BODY = ` Your user account has been activated. Please Did you forget your password? - + - + @@ -162,8 +162,8 @@ getWebappTranslation('msg', { exp: '{{ foo }}', num: 1, str: 'a' })
@@ -183,26 +183,26 @@ getWebappTranslation('msg', { exp: '{{ foo }}', num: 1, str: 'a' }) - + - + diff --git a/generators/vue/support/translate-vue.ts b/generators/vue/support/translate-vue.ts index 40dcfcc7e55c..cef43430177a 100644 --- a/generators/vue/support/translate-vue.ts +++ b/generators/vue/support/translate-vue.ts @@ -18,12 +18,12 @@ */ import { passthrough } from '@yeoman/transform'; import { Minimatch } from 'minimatch'; -import CoreGenerator from '../../base-core/index.js'; +import type CoreGenerator from '../../base-core/index.js'; type GetWebappTranslation = (s: string, data?: Record) => string; function replaceTranslationAttributes({ content, getWebappTranslation }: { content: string; getWebappTranslation: GetWebappTranslation }) { - return content.replaceAll(/v-bind:(?(?:placeholder|title|label))="(?t\$\([^"]+\))"/g, (_complete, ...args) => { + return content.replaceAll(/:(?(?:placeholder|title|label))="(?t\$\([^"]+\))"/g, (_complete, ...args) => { const groups: Record = args.pop(); if (groups.translate.includes('+')) { return ''; diff --git a/generators/vue/support/update-languages.ts b/generators/vue/support/update-languages.ts index fdf3eb45c3d5..5f515134dd78 100644 --- a/generators/vue/support/update-languages.ts +++ b/generators/vue/support/update-languages.ts @@ -87,7 +87,7 @@ function updateLanguagesInWebpackTask(this: BaseGenerator, { application, contro export default function updateLanguagesTask(this: BaseGenerator, taskParam: UpdateClientLanguagesTaskParam) { updateLanguagesInPipeTask.call(this, taskParam); updateLanguagesInConfigTask.call(this, taskParam); - if (taskParam.application.microfrontend) { + if (taskParam.application.clientBundlerWebpack) { updateLanguagesInWebpackTask.call(this, taskParam); } updateLanguagesInDayjsConfigurationTask.call(this, taskParam, { diff --git a/generators/vue/templates/.eslintrc.cjs.ejs b/generators/vue/templates/.eslintrc.cjs.ejs deleted file mode 100644 index 626929dee1aa..000000000000 --- a/generators/vue/templates/.eslintrc.cjs.ejs +++ /dev/null @@ -1,65 +0,0 @@ -<%# - Copyright 2013-2024 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-env node */ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - root: true, - extends: [ - 'plugin:vue/vue3-essential', - 'eslint:recommended', - '@vue/eslint-config-typescript', - '@vue/eslint-config-prettier/skip-formatting', - ], -<%_ if (cypressTests) { _%> - overrides: [ - { - files: [ - '<%= clientTestDir %>cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', - ], - 'extends': [ - 'plugin:cypress/recommended', - ], - }, - ], -<%_ } _%> - parser: 'vue-eslint-parser', - parserOptions: { - parser: '@typescript-eslint/parser', - ecmaVersion: 'latest', - }, - rules: { - 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', - 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', - 'vue/multi-word-component-names': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unused-vars': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-empty-function': 'off', - '@typescript-eslint/ban-ts-comment': 'off', - '@typescript-eslint/no-var-requires': 'off', - '@typescript-eslint/consistent-type-imports': 'error', - 'vue/no-v-text-v-html-on-component': [ - 'error', - { 'allow': ['router-link', 'b-alert', 'b-badge', 'b-button', 'b-link'] }, - ], - 'vue/no-reserved-component-names': 'off', - }, - ignorePatterns: ['<%= this.relativeDir(clientRootDir, temporaryDir) %>'], -}; diff --git a/generators/vue/templates/eslint.config.js.jhi.vue.ejs b/generators/vue/templates/eslint.config.js.jhi.vue.ejs new file mode 100644 index 000000000000..7a5a36fa442b --- /dev/null +++ b/generators/vue/templates/eslint.config.js.jhi.vue.ejs @@ -0,0 +1,74 @@ +<%# + Copyright 2013-2024 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. +-%> +<&_ if (fragment.importsSection) { -&> +import js from '@eslint/js'; +import vue from 'eslint-plugin-vue'; + +<&_ } -&> +<&_ if (fragment.configSection) { -&> + { ignores: ['<%- this.relativeDir(clientRootDir, clientDistDir) %>', '<%- temporaryDir %>'] }, + js.configs.recommended, + ...tseslint.configs.recommended.map(config => + config.name === 'typescript-eslint/base' ? config : { ...config, files: [ '**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts' ] }, + ), + { + files: ['**/*.{js,cjs,mjs}'], + rules: { + 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + }, + }, + ...vue.configs['flat/recommended'], + { + files: ['**/*.vue'], + languageOptions: { + parserOptions: { parser: '@typescript-eslint/parser' }, + globals: { ...globals.browser }, + }, + }, + { + files: ['<%- this.relativeDir(clientRootDir, clientSrcDir) %>**/*.vue', '<%- this.relativeDir(clientRootDir, clientSrcDir) %>**/*.ts'], + languageOptions: { + globals: { ...globals.browser }, + }, + rules: { + 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'vue/multi-word-component-names': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/consistent-type-imports': 'error', + 'vue/no-v-text-v-html-on-component': [ + 'error', + { 'allow': ['router-link', 'b-alert', 'b-badge', 'b-button', 'b-link'] }, + ], + 'vue/no-reserved-component-names': 'off', + 'vue/attributes-order': 'off', + }, + }, + { + files: ['<%- this.relativeDir(clientRootDir, clientSrcDir) %>**/*.spec.ts'], + rules: { + '@typescript-eslint/no-empty-function': 'off', + }, + }, +<&_ } -&> diff --git a/generators/vue/templates/module-federation.config.cjs.ejs b/generators/vue/templates/module-federation.config.cjs.ejs new file mode 100644 index 000000000000..a7d7eff0ef7a --- /dev/null +++ b/generators/vue/templates/module-federation.config.cjs.ejs @@ -0,0 +1,55 @@ +<%# + Copyright 2013-2024 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 packageJson = require('./package.json'); + +// Microfrontend api, should match across gateway and microservices. +const apiVersion = '0.0.1'; + +const sharedDefaults = { singleton: true, strictVersion: true, requiredVersion: apiVersion }; +const shareMappings = (...mappings) => Object.fromEntries(mappings.map(map => [map, { ...sharedDefaults, version: apiVersion }])); + +const shareDependencies = ({ skipList = [] } = {}) => + Object.fromEntries( + Object.entries(packageJson.dependencies) + .filter(([dependency]) => !skipList.includes(dependency)) + .map(([dependency, version]) => [dependency, { ...sharedDefaults, version, requiredVersion: version }]), + ); + +/** @type {import('@module-federation/runtime').Options} */ +module.exports = { + name: '<%= lowercaseBaseName %>', +<%_ if (applicationTypeMicroservice) { _%> + exposes: { + './entities-router': './<%- this.relativeDir(clientRootDir, clientSrcDir) %>app/router/entities.ts', + './entities-menu': './<%- this.relativeDir(clientRootDir, clientSrcDir) %>app/entities/entities-menu.vue', + }, +<%_ } _%> + filename: 'remoteEntry.js', + shareScope: 'default', + shared: { + ...shareDependencies(), + ...shareMappings( + '@/shared/security/authority', + '@/shared/alert/alert.service', + '@/locale/translation.service', + ), + }, + dts: false, + manifest: false, +}; diff --git a/generators/vue/templates/package.json.ejs b/generators/vue/templates/package.json.ejs index 11146b19f44d..4e25b34c897e 100644 --- a/generators/vue/templates/package.json.ejs +++ b/generators/vue/templates/package.json.ejs @@ -55,43 +55,13 @@ "vue-router": "<%= nodeDependencies['vue-router'] %>" }, "devDependencies": { -<%_ if (applicationTypeGateway && microfrontend) { _%> - "@module-federation/utilities": "<%= nodeDependencies['@module-federation/utilities'] %>", -<%_ } _%> -<%_ if (microfrontend) { _%> - "@originjs/vite-plugin-federation": "1.3.3", - "browser-sync-webpack-plugin": "<%= nodeDependencies['browser-sync-webpack-plugin'] %>", - "copy-webpack-plugin": "<%= nodeDependencies['copy-webpack-plugin'] %>", - "css-loader": "<%= nodeDependencies['css-loader'] %>", - "css-minimizer-webpack-plugin": "<%= nodeDependencies['css-minimizer-webpack-plugin'] %>", - "html-webpack-plugin": "<%= nodeDependencies['html-webpack-plugin'] %>", - <%_ if (enableTranslation) { _%> - "folder-hash": "<%= nodeDependencies['folder-hash'] %>", - "merge-jsons-webpack-plugin": "<%= nodeDependencies['merge-jsons-webpack-plugin'] %>", - <%_ } _%> - "mini-css-extract-plugin": "<%= nodeDependencies['mini-css-extract-plugin'] %>", - "postcss-loader": "<%= nodeDependencies['postcss-loader'] %>", - "sass-loader": "<%= nodeDependencies['sass-loader'] %>", - "terser-webpack-plugin": "<%= nodeDependencies['terser-webpack-plugin'] %>", - "ts-loader": "<%= nodeDependencies['ts-loader'] %>", - "vue-loader": "<%= nodeDependencies['vue-loader'] %>", - "vue-style-loader": "<%= nodeDependencies['vue-style-loader'] %>", - "webpack": "<%= nodeDependencies['webpack'] %>", - "webpack-bundle-analyzer": "<%= nodeDependencies['webpack-bundle-analyzer'] %>", - "webpack-cli": "<%= nodeDependencies['webpack-cli'] %>", - "webpack-dev-server": "<%= nodeDependencies['webpack-dev-server'] %>", - "webpack-merge": "<%= nodeDependencies['webpack-merge'] %>", - "workbox-webpack-plugin": "<%= nodeDependencies['workbox-webpack-plugin'] %>", -<%_ } _%> + "@eslint/js": null, "@pinia/testing": "<%= nodeDependencies['@pinia/testing'] %>", - "@rushstack/eslint-patch": "<%= nodeDependencies['@rushstack/eslint-patch'] %>", "@types/node": "<%= nodeDependencies['@types/node'] %>", "@types/sinon": "<%= nodeDependencies['@types/sinon'] %>", "@tsconfig/node18": null, "@vitejs/plugin-vue": "<%= nodeDependencies['@vitejs/plugin-vue'] %>", "@vitest/coverage-v8": "<%= nodeDependencies.vitest %>", - "@vue/eslint-config-prettier": "<%= nodeDependencies['@vue/eslint-config-prettier'] %>", - "@vue/eslint-config-typescript": "<%= nodeDependencies['@vue/eslint-config-typescript'] %>", "@vue/test-utils": "<%= nodeDependencies['@vue/test-utils'] %>", "@vue/tsconfig": null, "axios-mock-adapter": "<%= nodeDependencies['axios-mock-adapter'] %>", @@ -109,64 +79,43 @@ "sinon": "<%= nodeDependencies['sinon'] %>", "swagger-ui-dist": "<%= nodeDependencies['swagger-ui-dist'] %>", "eslint": "<%= nodeDependencies['eslint'] %>", + "eslint-config-prettier": null, "eslint-plugin-prettier": "<%= nodeDependencies['eslint-plugin-prettier'] %>", "eslint-plugin-vue": "<%= nodeDependencies['eslint-plugin-vue'] %>", "typescript": "<%= nodeDependencies['typescript'] %>", + "typescript-eslint": null, "vite": null, "vitest": "<%= nodeDependencies.vitest %>", "vite-plugin-static-copy": null, "vitest-sonar-reporter": "<%= nodeDependencies['vitest-sonar-reporter'] %>" }, "engines": { - "node": ">=<%= nodeVersion %>", - "npm": ">= 6.14.4" + "node": ">=<%= nodeVersion %>" }, "config": { "default_environment": "prod" }, "scripts": { -<%_ if (microfrontend) { %> - "prettier:check": "prettier --check \"{,src/**/,webpack/,.blueprint/**/}*.{<%= prettierExtensions %>}\"", - "prettier:format": "prettier --write \"{,src/**/,webpack/,.blueprint/**/}*.{<%= prettierExtensions %>}\"", -<%_ } else { %> - "prettier:check": "prettier --check \"{,src/**/,.blueprint/**/}*.{<%= prettierExtensions %>}\"", - "prettier:format": "prettier --write \"{,src/**/,.blueprint/**/}*.{<%= prettierExtensions %>}\"", -<%_ } %> - "lint": "eslint . --ext .ts,.vue ", - "lint:fix": "eslint . --ext .ts,.vue --fix", + "build": "<%= clientPackageManager %> run webapp:prod --", + "build-watch": "concurrently 'npm run webapp:build:dev -- --watch'<% if(!skipServer) { %> npm:backend:start<% } %>", "cleanup": "rimraf <%= this.relativeDir(clientRootDir, temporaryDir) %>", "clean-www": "rimraf <%= this.relativeDir(clientRootDir, clientDistDir) %>", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "prettier:check": "prettier --check \"{,src/**/,.blueprint/**/}*.{<%= prettierExtensions %>}\"", + "prettier:format": "prettier --write \"{,src/**/,.blueprint/**/}*.{<%= prettierExtensions %>}\"", + "serve": "<%= clientPackageManager %> run start --", "start": "<%= clientPackageManager %> run webapp:dev --", "start-tls": "<%= clientPackageManager %> run webapp:dev -- --env.tls", - "serve": "<%= clientPackageManager %> run start --", - "build": "<%= clientPackageManager %> run webapp:prod --", - "build-watch": "concurrently 'npm run webapp:build:dev -- --watch'<% if(!skipServer) { %> npm:backend:start<% } %>", - "vitest-run": "vitest --run --coverage", - "vitest": "vitest", "pretest": "<%= clientPackageManager %> run lint", "test": "<%= clientPackageManager %> run vitest-run --", "test:watch": "<%= clientPackageManager %> run vitest", + "vitest-run": "vitest --run --coverage", + "vitest": "vitest", "watch": "concurrently npm:start<% if(!skipServer) { %> npm:backend:start<% } %>", "webapp:build": "<%= clientPackageManager %> run clean-www && <%= clientPackageManager %> run webapp:build:dev --", -<%_ if (microfrontend) { %> - "webapp:build:dev": "<%= clientPackageManager %> run webpack -- --mode development --env stats=minimal", - "webapp:build:prod": "<%= clientPackageManager %> run webpack -- --mode production --env stats=minimal", - "webapp:dev": "<%= clientPackageManager %> run webpack-dev-server -- --mode development --env stats=normal", -<%_ } else { %> - "webapp:build:dev": "<%= clientPackageManager %> run vite-build", - "webapp:build:prod": "<%= clientPackageManager %> run vite-build", - "webapp:dev": "<%= clientPackageManager %> run vite-serve", - "webapp:serve": "<%= clientPackageManager %> run vite-serve", -<%_ } %> "webapp:prod": "<%= clientPackageManager %> run clean-www && <%= clientPackageManager %> run webapp:build:prod --", - "webapp:test": "<%= clientPackageManager %> run test --", -<%_ if (microfrontend) { %> - "webpack-dev-server": "webpack serve --config webpack/webpack.common.js", - "webpack": "webpack --config webpack/webpack.common.js" -<%_ } else { %> - "vite-serve": "vite", - "vite-build": "vite build" -<%_ } %> + "webapp:test": "<%= clientPackageManager %> run test --" }, "browserslist": [ "> 1%", diff --git a/generators/vue/templates/src/main/webapp/app/account/account.service.ts.ejs b/generators/vue/templates/src/main/webapp/app/account/account.service.ts.ejs index 237229c3c47d..8f03c33666a2 100644 --- a/generators/vue/templates/src/main/webapp/app/account/account.service.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/account.service.ts.ejs @@ -18,7 +18,7 @@ export default class AccountService { const res = await axios.get('management/info'); if (res.data && res.data.activeProfiles) { this.store.setRibbonOnProfiles(res.data['display-ribbon-on-profiles']); - this.store.setActiveProfiles(res.data['activeProfiles']); + this.store.setActiveProfiles(res.data.activeProfiles); } return true; } catch (error) { diff --git a/generators/vue/templates/src/main/webapp/app/account/activate/activate.vue.ejs b/generators/vue/templates/src/main/webapp/app/account/activate/activate.vue.ejs index 77e8ce22ff67..d34170165871 100644 --- a/generators/vue/templates/src/main/webapp/app/account/activate/activate.vue.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/activate/activate.vue.ejs @@ -5,7 +5,7 @@

Activation

Your user could not be activated. Please use the registration form to sign up. diff --git a/generators/vue/templates/src/main/webapp/app/account/change-password/change-password.vue.ejs b/generators/vue/templates/src/main/webapp/app/account/change-password/change-password.vue.ejs index dcf4a5bf7a4a..bfb9215d6dab 100644 --- a/generators/vue/templates/src/main/webapp/app/account/change-password/change-password.vue.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/change-password/change-password.vue.ejs @@ -20,7 +20,7 @@ The password and its confirmation do not match!
-
+
{ loginForm.password = 'pwd'; loginForm.rememberMe = true; const jwtSecret = 'jwt-secret'; - axiosStub.post.resolves({ headers: { authorization: 'Bearer ' + jwtSecret } }); + axiosStub.post.resolves({ headers: { authorization: `Bearer ${jwtSecret}` } }); // WHEN loginForm.doLogin(); await loginForm.$nextTick(); // THEN - expect(axiosStub.post.calledWith('api/authenticate', { - username: 'login', - password: 'pwd', - rememberMe: true - })).toBeTruthy(); + expect( + axiosStub.post.calledWith('api/authenticate', { + username: 'login', + password: 'pwd', + rememberMe: true, + }), + ).toBeTruthy(); expect(loginForm.authenticationError).toBeFalsy(); expect(localStorage.getItem('<%=jhiPrefixDashed %>-authenticationToken')).toEqual(jwtSecret); @@ -113,18 +115,20 @@ describe('LoginForm Component', () => { loginForm.password = 'pwd'; loginForm.rememberMe = false; const jwtSecret = 'jwt-secret'; - axiosStub.post.resolves({ headers: { authorization: 'Bearer ' + jwtSecret } }); + axiosStub.post.resolves({ headers: { authorization: `Bearer ${jwtSecret}` } }); // WHEN loginForm.doLogin(); await loginForm.$nextTick(); // THEN - expect(axiosStub.post.calledWith('api/authenticate', { - username: 'login', - password: 'pwd', - rememberMe: false - })).toBeTruthy(); + expect( + axiosStub.post.calledWith('api/authenticate', { + username: 'login', + password: 'pwd', + rememberMe: false, + }), + ).toBeTruthy(); expect(loginForm.authenticationError).toBeFalsy(); expect(sessionStorage.getItem('<%=jhiPrefixDashed %>-authenticationToken')).toEqual(jwtSecret); @@ -163,9 +167,11 @@ describe('LoginForm Component', () => { await loginForm.$nextTick(); // THEN - expect(axiosStub.post.calledWith('api/authentication', - 'username=login&password=pwd&remember-me=true&submit=Login', - { "headers": { "Content-Type": "application/x-www-form-urlencoded" } })).toBeTruthy(); + expect( + axiosStub.post.calledWith('api/authentication', 'username=login&password=pwd&remember-me=true&submit=Login', { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + }), + ).toBeTruthy(); expect(loginForm.authenticationError).toBeFalsy(); }); diff --git a/generators/vue/templates/src/main/webapp/app/account/login-form/login-form.component.ts.ejs b/generators/vue/templates/src/main/webapp/app/account/login-form/login-form.component.ts.ejs index 02b388eb04d0..337697956942 100644 --- a/generators/vue/templates/src/main/webapp/app/account/login-form/login-form.component.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/login-form/login-form.component.ts.ejs @@ -43,8 +43,8 @@ export default defineComponent({ try { await axios.post('api/authentication', data, { headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - } + 'Content-Type': 'application/x-www-form-urlencoded', + }, }); <%_ } _%> diff --git a/generators/vue/templates/src/main/webapp/app/account/login-form/login-form.vue.ejs b/generators/vue/templates/src/main/webapp/app/account/login-form/login-form.vue.ejs index db7b673d2bdf..7403f7e291d8 100644 --- a/generators/vue/templates/src/main/webapp/app/account/login-form/login-form.vue.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/login-form/login-form.vue.ejs @@ -7,25 +7,25 @@
- - + + - + @@ -42,8 +42,12 @@ <%_ if (generateUserManagement) { _%>
- Did you forget your password?Did you forget your password?
diff --git a/generators/vue/templates/src/main/webapp/app/account/login.service.spec.ts.ejs b/generators/vue/templates/src/main/webapp/app/account/login.service.spec.ts.ejs index 803270f49f40..3cbb71448794 100644 --- a/generators/vue/templates/src/main/webapp/app/account/login.service.spec.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/login.service.spec.ts.ejs @@ -18,7 +18,7 @@ describe('Login Service test suite', () => { <%_ if (authenticationTypeOauth2) { _%> it('should build url for login', () => { - const loc = {href: '', hostname: 'localhost', pathname: '/'}; + const loc = { href: '', hostname: 'localhost', pathname: '/' }; loginService.login(loc); diff --git a/generators/vue/templates/src/main/webapp/app/account/login.service.ts.ejs b/generators/vue/templates/src/main/webapp/app/account/login.service.ts.ejs index e6d448fdc9ff..a9e8e8251a86 100644 --- a/generators/vue/templates/src/main/webapp/app/account/login.service.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/login.service.ts.ejs @@ -32,7 +32,7 @@ export default class LoginService { contextPath = contextPath.substring(0, contextPath.indexOf('forbidden')); } if (!contextPath.endsWith('/')) { - contextPath = contextPath + '/'; + contextPath = `${contextPath}/`; } // If you have configured multiple OIDC providers, then, you can update this URL to /login. // It will show a Spring Security generated login page with links to configured OIDC providers. @@ -41,7 +41,7 @@ export default class LoginService { <%_ } _%> <%_ if (!authenticationTypeJwt) { _%> - public logout() : AxiosPromise { + public logout(): AxiosPromise { return axios.post('api/logout'); } <%_ } _%> diff --git a/generators/vue/templates/src/main/webapp/app/account/register/register.component.spec.ts.ejs b/generators/vue/templates/src/main/webapp/app/account/register/register.component.spec.ts.ejs index 65f809aeeedc..145372a363cd 100644 --- a/generators/vue/templates/src/main/webapp/app/account/register/register.component.spec.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/register/register.component.spec.ts.ejs @@ -72,7 +72,7 @@ describe('Register Component', () => { langKey: '<%= nativeLanguage %>', login: 'jhi', password: 'jhipster', - }) + }), ).toBeTruthy(); expect(register.success).toBe(true); expect(register.error).toBe(null); diff --git a/generators/vue/templates/src/main/webapp/app/account/register/register.vue.ejs b/generators/vue/templates/src/main/webapp/app/account/register/register.vue.ejs index 44eca9c2f5de..ebdfa903b447 100644 --- a/generators/vue/templates/src/main/webapp/app/account/register/register.vue.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/register/register.vue.ejs @@ -23,7 +23,7 @@
- +
@@ -84,7 +84,7 @@ maxlength="254" email required - v-bind:placeholder="t$('global.form[\'email.placeholder\']')" + :placeholder="t$('global.form[\'email.placeholder\']')" data-cy="email" />
@@ -130,7 +130,7 @@ minlength="4" maxlength="50" required - v-bind:placeholder="t$('global.form[\'newpassword.placeholder\']')" + :placeholder="t$('global.form[\'newpassword.placeholder\']')" data-cy="firstPassword" />
@@ -171,7 +171,7 @@ minlength="4" maxlength="50" required - v-bind:placeholder="t$('global.form[\'confirmpassword.placeholder\']')" + :placeholder="t$('global.form[\'confirmpassword.placeholder\']')" data-cy="secondPassword" />
@@ -209,7 +209,7 @@

If you want to - sign insign in, you can try the default accounts:
- Administrator (login="admin" and password="admin")
- User (login="user" and password="user").
Your password had been reset. Please - sign in + sign in

The password and its confirmation do not match!

@@ -27,7 +27,7 @@
- +
Check your email for details on how to reset your password.

- +
{ this.error = null; this.success = 'OK'; diff --git a/generators/vue/templates/src/main/webapp/app/account/sessions/sessions.vue.ejs b/generators/vue/templates/src/main/webapp/app/account/sessions/sessions.vue.ejs index 461a36504429..93c5b759df5e 100644 --- a/generators/vue/templates/src/main/webapp/app/account/sessions/sessions.vue.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/sessions/sessions.vue.ejs @@ -30,7 +30,7 @@ {{ session.userAgent }} {{ session.tokenDate }} - diff --git a/generators/vue/templates/src/main/webapp/app/account/settings/settings.vue.ejs b/generators/vue/templates/src/main/webapp/app/account/settings/settings.vue.ejs index 43e766ad6ad2..a5a3cd2060f6 100644 --- a/generators/vue/templates/src/main/webapp/app/account/settings/settings.vue.ejs +++ b/generators/vue/templates/src/main/webapp/app/account/settings/settings.vue.ejs @@ -16,75 +16,132 @@ Settings saved!
-