diff --git a/.blueprint/cli/commands.mts b/.blueprint/cli/commands.mts index 11c9d371cf6b..25b3c9d02974 100644 --- a/.blueprint/cli/commands.mts +++ 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/github-build-matrix/command.ts b/.blueprint/github-build-matrix/command.ts new file mode 100644 index 000000000000..7f9be6ca2d6a --- /dev/null +++ b/.blueprint/github-build-matrix/command.ts @@ -0,0 +1,14 @@ +import type { JHipsterCommandDefinition } from '../../generators/index.js'; + +export default { + configs: { + workflow: { + description: 'Workflow', + argument: { + type: String, + }, + scope: 'generator', + choices: ['testcontainers'], + }, + }, +} as const satisfies JHipsterCommandDefinition; diff --git a/.blueprint/github-build-matrix/generator.ts b/.blueprint/github-build-matrix/generator.ts new file mode 100644 index 000000000000..ed1d8ffd18b5 --- /dev/null +++ b/.blueprint/github-build-matrix/generator.ts @@ -0,0 +1,22 @@ +import BaseGenerator from '../../generators/base/index.js'; +import { setGithubTaskOutput } from '../../lib/testing/index.js'; +import { convertToGitHubMatrix } from './support/github-ci-matrix.js'; +import { dockerComposeMatrix } from './samples/docker-compose-integration.js'; + +export default class extends BaseGenerator { + workflow; + + constructor(args, opts, features) { + super(args, opts, { queueCommandTasks: true, ...features, jhipsterBootstrap: false }); + } + + get [BaseGenerator.WRITING]() { + return this.asWritingTaskGroup({ + async buildMatrix() { + if (this.workflow === 'docker-compose-integration') { + setGithubTaskOutput('matrix', JSON.stringify(convertToGitHubMatrix(dockerComposeMatrix), null, 2)); + } + }, + }); + } +} 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/docker-compose-integration.ts b/.blueprint/github-build-matrix/samples/docker-compose-integration.ts new file mode 100644 index 000000000000..36cb21371508 --- /dev/null +++ b/.blueprint/github-build-matrix/samples/docker-compose-integration.ts @@ -0,0 +1,44 @@ +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 const dockerComposeMatrix = 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), + }, + ]), +); 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/github-ci-matrix.ts b/.blueprint/github-build-matrix/support/github-ci-matrix.ts new file mode 100644 index 000000000000..f4ab656f3f2b --- /dev/null +++ b/.blueprint/github-build-matrix/support/github-ci-matrix.ts @@ -0,0 +1,38 @@ +import { RECOMMENDED_JAVA_VERSION, RECOMMENDED_NODE_VERSION } from '../../../generators/index.js'; + +type GitHubMatrix = { + os: string; + 'node-version': string; + 'java-version': string; + 'default-environment': string; + 'job-name': string; + args: string; +}; + +type GitHubMatrixOutput = { + include: GitHubMatrix[]; +}; + +export const defaultEnvironment = { + os: 'ubuntu-latest', + 'node-version': RECOMMENDED_NODE_VERSION, + 'java-version': RECOMMENDED_JAVA_VERSION, + 'default-environment': 'prod', +}; + +export const defaultEnvironmentMatrix = { + os: ['ubuntu-latest'], + 'node-version': [RECOMMENDED_NODE_VERSION], + 'java-version': [RECOMMENDED_JAVA_VERSION], + 'default-environment': ['prod'], +}; + +export const convertToGitHubMatrix = (matrix: Record): GitHubMatrixOutput => { + return { + include: Object.entries(matrix).map(([key, value]) => ({ + 'job-name': key, + ...defaultEnvironment, + ...value, + })), + }; +}; 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/.github/workflows/docker-compose-integration.yml b/.github/workflows/docker-compose-integration.yml new file mode 100644 index 000000000000..ca1175f8ae40 --- /dev/null +++ b/.github/workflows/docker-compose-integration.yml @@ -0,0 +1,109 @@ +# +# 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: + - '*' +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 + 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 d8eba2295701..9d6155ff7f01 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 diff --git a/generators/app/__snapshots__/generator.spec.ts.snap b/generators/app/__snapshots__/generator.spec.ts.snap index dcfecaf595ac..1e26fd49d446 100644 --- a/generators/app/__snapshots__/generator.spec.ts.snap +++ b/generators/app/__snapshots__/generator.spec.ts.snap @@ -24,7 +24,7 @@ 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 --prettier-tab-width Default tab width for prettier @@ -287,7 +287,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` "defaultPackaging": "jar", "devDatabaseExtraOptions": "", "devDatabaseName": "jhipster", - "devDatabasePassword": "", + "devDatabasePassword": "password", "devDatabaseType": "postgresql", "devDatabaseTypeH2Any": false, "devDatabaseTypeH2Disk": false, @@ -741,7 +741,7 @@ exports[`generator - app with default config should match snapshot 1`] = ` }, "prodDatabaseExtraOptions": "", "prodDatabaseName": "jhipster", - "prodDatabasePassword": "", + "prodDatabasePassword": "password", "prodDatabaseType": "postgresql", "prodDatabaseTypeMariadb": false, "prodDatabaseTypeMssql": false, @@ -901,7 +901,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` "defaultPackaging": "jar", "devDatabaseExtraOptions": "", "devDatabaseName": "jhipster", - "devDatabasePassword": "", + "devDatabasePassword": "password", "devDatabaseType": "postgresql", "devDatabaseTypeH2Any": false, "devDatabaseTypeH2Disk": false, @@ -1351,7 +1351,7 @@ exports[`generator - app with gateway should match snapshot 1`] = ` }, "prodDatabaseExtraOptions": "", "prodDatabaseName": "jhipster", - "prodDatabasePassword": "", + "prodDatabasePassword": "password", "prodDatabaseType": "postgresql", "prodDatabaseTypeMariadb": false, "prodDatabaseTypeMssql": false, @@ -1510,7 +1510,7 @@ exports[`generator - app with microservice should match snapshot 1`] = ` "defaultPackaging": "jar", "devDatabaseExtraOptions": "", "devDatabaseName": "jhipster", - "devDatabasePassword": "", + "devDatabasePassword": "password", "devDatabaseType": "postgresql", "devDatabaseTypeH2Any": false, "devDatabaseTypeH2Disk": false, @@ -1907,7 +1907,7 @@ exports[`generator - app with microservice should match snapshot 1`] = ` }, "prodDatabaseExtraOptions": "", "prodDatabaseName": "jhipster", - "prodDatabasePassword": "", + "prodDatabasePassword": "password", "prodDatabaseType": "postgresql", "prodDatabaseTypeMariadb": false, "prodDatabaseTypeMssql": false, 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/bootstrap-application-base/command.ts b/generators/bootstrap-application-base/command.ts index 5020591ae9c7..3733cecbe1e7 100644 --- a/generators/bootstrap-application-base/command.ts +++ b/generators/bootstrap-application-base/command.ts @@ -29,6 +29,7 @@ const command = { skipJhipsterDependencies: { description: "Don't write jhipster dependencies to package.json.", type: Boolean, + env: 'JHI_SKIP_JHIPSTER_DEPENDENCIES', scope: 'storage', }, creationTimestamp: { diff --git a/generators/client/command.ts b/generators/client/command.ts index ad34b083ad74..b52503537712 100644 --- a/generators/client/command.ts +++ b/generators/client/command.ts @@ -105,6 +105,10 @@ const command = { }, 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', diff --git a/generators/common/__snapshots__/generator.spec.ts.snap b/generators/common/__snapshots__/generator.spec.ts.snap index 5cd1490c00db..2e8f2e914f95 100644 --- a/generators/common/__snapshots__/generator.spec.ts.snap +++ b/generators/common/__snapshots__/generator.spec.ts.snap @@ -152,8 +152,12 @@ 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,UndocumentedApi +# 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/**/* diff --git a/generators/common/templates/sonar-project.properties.ejs b/generators/common/templates/sonar-project.properties.ejs index dc2a531618f4..d571fb5912f5 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,\ <%_ } _%> @@ -55,19 +58,24 @@ sonar.issue.ignore.multicriteria=\ <%_ } _%> S4684,S5145,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.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.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.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.ruleKey=java:S4684 diff --git a/generators/docker-compose/__snapshots__/docker-compose.spec.ts.snap b/generators/docker-compose/__snapshots__/docker-compose.spec.ts.snap index 0d81629621a4..7f14394a0e93 100644 --- a/generators/docker-compose/__snapshots__/docker-compose.spec.ts.snap +++ b/generators/docker-compose/__snapshots__/docker-compose.spec.ts.snap @@ -371,6 +371,8 @@ jhipster: interval: 5s timeout: 25s retries: 20 + labels: + org.springframework.boot.ignore: true consul: image: consul-placeholder @@ -647,7 +649,7 @@ jhipster: image: postgresql-placeholder environment: - POSTGRES_USER=mspsql - - POSTGRES_PASSWORD= + - POSTGRES_PASSWORD=password - POSTGRES_HOST_AUTH_METHOD=trust healthcheck: test: @@ -736,6 +738,7 @@ 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: @@ -1040,7 +1043,7 @@ jhipster: image: postgresql-placeholder environment: - POSTGRES_USER=mspsql - - POSTGRES_PASSWORD= + - POSTGRES_PASSWORD=password - POSTGRES_HOST_AUTH_METHOD=trust healthcheck: test: @@ -1142,6 +1145,7 @@ 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: @@ -1457,7 +1461,7 @@ jhipster: image: postgresql-placeholder environment: - POSTGRES_USER=mspsql - - POSTGRES_PASSWORD= + - POSTGRES_PASSWORD=password - POSTGRES_HOST_AUTH_METHOD=trust healthcheck: test: @@ -1792,7 +1796,7 @@ jhipster: image: postgresql-placeholder environment: - POSTGRES_USER=mspsql - - POSTGRES_PASSWORD= + - POSTGRES_PASSWORD=password - POSTGRES_HOST_AUTH_METHOD=trust healthcheck: test: @@ -1884,6 +1888,7 @@ 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: diff --git a/generators/docker/__test-support/service-discovery-matcher.ts b/generators/docker/__test-support/service-discovery-matcher.ts index c5634e16c79c..416e24f51188 100644 --- a/generators/docker/__test-support/service-discovery-matcher.ts +++ b/generators/docker/__test-support/service-discovery-matcher.ts @@ -1,3 +1,4 @@ +import { it } from 'esmocha'; import type { RunResult } from 'yeoman-test'; import { JAVA_DOCKER_DIR } from '../../generator-constants.js'; @@ -32,11 +33,11 @@ const desiredConsulConfig = { }; export const matchEureka = (resultGetter: () => RunResult, shouldMatch: boolean) => { - matchWrittenFiles('eureka', resultGetter, expectedEurekaFiles, shouldMatch); - matchWrittenConfig('eureka', resultGetter, desiredEurekaConfig, shouldMatch); + it(...matchWrittenFiles('eureka', expectedEurekaFiles, shouldMatch, resultGetter())); + it(...matchWrittenConfig('eureka', desiredEurekaConfig, shouldMatch, resultGetter())); }; export const matchConsul = (resultGetter: () => RunResult, shouldMatch: boolean) => { - matchWrittenFiles('consul', resultGetter, expectedConsulFiles, shouldMatch); - matchWrittenConfig('consul', resultGetter, desiredConsulConfig, shouldMatch); + it(...matchWrittenFiles('consul', expectedConsulFiles, shouldMatch, resultGetter())); + it(...matchWrittenConfig('consul', desiredConsulConfig, shouldMatch, resultGetter())); }; diff --git a/generators/docker/generator.ts b/generators/docker/generator.ts index 1daf922d0801..664d62264c67 100644 --- a/generators/docker/generator.ts +++ b/generators/docker/generator.ts @@ -120,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: { @@ -179,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/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..de486ddf550a 100644 --- a/generators/docker/templates/docker/keycloak.yml.ejs +++ b/generators/docker/templates/docker/keycloak.yml.ejs @@ -45,3 +45,7 @@ services: timeout: 5s retries: 40 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/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/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/jdl/__snapshots__/generator.spec.ts.snap b/generators/jdl/__snapshots__/generator.spec.ts.snap index 85eb87aa9bf3..1f27ae27a0ad 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) @@ -188,7 +188,7 @@ 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 diff --git a/generators/jdl/command.ts b/generators/jdl/command.ts index de1afb3144f1..e5887da2cc8a 100644 --- a/generators/jdl/command.ts +++ b/generators/jdl/command.ts @@ -44,6 +44,7 @@ const command = { 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', diff --git a/generators/liquibase/incremental-liquibase.spec.ts b/generators/liquibase/incremental-liquibase.spec.ts index 5f27ba442d84..3baed9a5b803 100644 --- a/generators/liquibase/incremental-liquibase.spec.ts +++ b/generators/liquibase/incremental-liquibase.spec.ts @@ -4,6 +4,8 @@ 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'; +const exceptSourceMethods = ['addLiquibaseChangelog', 'addLiquibaseIncrementalChangelog', 'addLiquibaseConstraintsChangelog']; + const incrementalFiles = [ `${SERVER_MAIN_RES_DIR}config/liquibase/master.xml`, `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/00000000000000_initial_schema.xml`, @@ -180,7 +182,10 @@ describe('generator - app - --incremental-changelog', function () { this.timeout(45000); describe('when creating a new application', () => { before(async () => { - await helpers.runJHipster('server').withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + await helpers + .runJHipster('server') + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); }); it('should create application', () => { @@ -198,6 +203,7 @@ describe('generator - app - --incremental-changelog', function () { await helpers .runJHipster('server') .withJHipsterConfig({ incrementalChangelog: true }) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .doInDir(cwd => { incrementalFiles.forEach(filePath => { @@ -230,6 +236,7 @@ describe('generator - app - --incremental-changelog', function () { before(async () => { await helpers .runJHipster('server') + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withJHipsterConfig({ incrementalChangelog: true }) .withOptions({ recreateInitialChangelog: true }) @@ -263,7 +270,10 @@ describe('generator - app - --incremental-changelog', function () { describe('regenerating the application', () => { before(async () => { - await helpers.runJDL(jdlApplicationWithRelationshipToUser).withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + await helpers + .runJDL(jdlApplicationWithRelationshipToUser) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); await runResult.create('jhipster:jdl').withOptions({ inline: jdlApplicationWithRelationshipToUser, creationTimestamp: '2020-01-02', @@ -321,6 +331,7 @@ entity Customer { } `, ) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-02', @@ -381,6 +392,7 @@ entity Customer { } `, ) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-02', @@ -441,6 +453,7 @@ entity Customer { } `, ) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-02', @@ -501,6 +514,7 @@ entity Customer { } `, ) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-02', @@ -544,10 +558,14 @@ entity Customer { describe('when adding a relationship', () => { before(async () => { - await helpers.runJDL(jdlApplicationWithEntities).withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + await helpers + .runJDL(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); await helpers .runJDLInApplication(jdlApplicationWithEntitiesAndRelationship) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-02', @@ -591,10 +609,14 @@ entity Customer { describe('when adding a many-to-many relationship', () => { before(async () => { - await helpers.runJDL(jdlApplicationWithEntities).withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + await helpers + .runJDL(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); await helpers .runJDLInApplication(jdlApplicationWithEntitiesAndAddedNewMnyToManyRelationship) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-02', @@ -651,10 +673,14 @@ entity Customer { describe('when adding a relationship with on handlers', () => { before(async () => { - await helpers.runJDL(jdlApplicationWithEntities).withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + 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', @@ -707,10 +733,14 @@ entity Customer { }); describe('when modifying a relationship with on handlers, only at these handlers', () => { before(async () => { - await helpers.runJDL(jdlApplicationWithEntities).withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + 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', @@ -718,6 +748,7 @@ entity Customer { await helpers .runJDLInApplication(jdlApplicationWithEntitiesAndRelationshipsWithChangedOnHandlers) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-03', @@ -805,10 +836,14 @@ entity Customer { describe('when modifying an existing relationship', () => { before(async () => { - await helpers.runJDL(jdlApplicationWithEntities).withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + 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', @@ -816,6 +851,7 @@ entity Customer { await helpers .runJDLInApplication(jdlApplicationWithEntitiesAndRelationshipsWithChangedOnHandlersAndChangedNaming) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-03', @@ -915,6 +951,7 @@ entity Customer { before(async () => { await helpers .runJDL(jdlApplicationWithEntitiesAndRelationshipsWithOnHandlers) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); }); @@ -963,10 +1000,14 @@ entity Customer { describe('when removing a relationship', () => { before(async () => { - await helpers.runJDL(jdlApplicationWithEntitiesAndRelationship).withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + await helpers + .runJDL(jdlApplicationWithEntitiesAndRelationship) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); await helpers .runJDLInApplication(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-02', @@ -1013,10 +1054,14 @@ entity Customer { describe('when modifying fields and relationships at the same time in different entities', () => { before(async () => { - await helpers.runJDL(jdlApplicationWithEntities).withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + await helpers + .runJDL(jdlApplicationWithEntities) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); await helpers .runJDLInApplication(jdlApplicationWithChangedEntitiesAndRelationship) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-02', @@ -1132,10 +1177,14 @@ entity Customer { describe('when modifying default values, fields with default values and relationships', () => { before(async () => { - await helpers.runJDL(jdlApplicationWithEntitiesWithDefaultValues).withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + await helpers + .runJDL(jdlApplicationWithEntitiesWithDefaultValues) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); await helpers .runJDLInApplication(jdlApplicationWithEntitiesWithChangedDefaultValuesAndNewRelationship) + .withMockedSource({ except: exceptSourceMethods }) .withMockedJHipsterGenerators({ except: exceptMockedGenerators }) .withOptions({ creationTimestamp: '2020-01-02', @@ -1192,7 +1241,10 @@ entity Customer { ].forEach(eachEntityConfig => { describe(`testing ${eachEntityConfig.bytesFields ? 'with' : 'without'} byte fields`, () => { before(async () => { - await helpers.runJDL(eachEntityConfig.entity).withMockedJHipsterGenerators({ except: exceptMockedGenerators }); + await helpers + .runJDL(eachEntityConfig.entity) + .withMockedSource({ except: exceptSourceMethods }) + .withMockedJHipsterGenerators({ except: exceptMockedGenerators }); }); it('should create entity config file', () => { diff --git a/generators/maven/types.d.ts b/generators/maven/types.d.ts index d35b10743c67..edb29424ed40 100644 --- a/generators/maven/types.d.ts +++ b/generators/maven/types.d.ts @@ -43,6 +43,7 @@ export type MavenDependency = MavenArtifact & { type?: string; scope?: string; classifier?: string; + optional?: boolean; additionalContent?: string; }; diff --git a/generators/server/__snapshots__/generator.spec.ts.snap b/generators/server/__snapshots__/generator.spec.ts.snap index 45d21d555a06..28811ab52b30 100644 --- a/generators/server/__snapshots__/generator.spec.ts.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/generator.spec.ts b/generators/server/generator.spec.ts index ed02e4f93418..fae936a53c82 100644 --- a/generators/server/generator.spec.ts +++ b/generators/server/generator.spec.ts @@ -52,6 +52,7 @@ describe(`generator - ${generator}`, () => { messageBroker: 'no', }) .withSkipWritingPriorities() + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); @@ -66,6 +67,7 @@ describe(`generator - ${generator}`, () => { messageBroker: 'kafka', }) .withSkipWritingPriorities() + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); shouldComposeWithSpringCloudStream(true, () => runResult); @@ -79,6 +81,7 @@ describe(`generator - ${generator}`, () => { messageBroker: 'pulsar', }) .withSkipWritingPriorities() + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); shouldComposeWithSpringCloudStream(true, () => runResult); @@ -94,6 +97,7 @@ describe(`generator - ${generator}`, () => { databaseType: 'no', authenticationType: 'jwt', }) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); @@ -111,6 +115,7 @@ describe(`generator - ${generator}`, () => { databaseType: 'no', authenticationType: 'session', }) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); @@ -128,6 +133,7 @@ describe(`generator - ${generator}`, () => { databaseType: 'no', authenticationType: 'oauth2', }) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); @@ -146,6 +152,7 @@ describe(`generator - ${generator}`, () => { databaseType: 'couchbase', }) .withSkipWritingPriorities() + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ filter: filterBasicServerGenerators }); }); shouldComposeWithCouchbase(true, () => runResult); @@ -155,15 +162,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.ts b/generators/server/generator.ts index 4d4362a2429a..e45daf6ac75f 100644 --- a/generators/server/generator.ts +++ b/generators/server/generator.ts @@ -522,7 +522,7 @@ Hibernate JPA 2 Metamodel does not work with Bean Validation 2 for LOB fields, s }, 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); const applicationEndpoint = application.applicationTypeMicroservice @@ -536,9 +536,10 @@ Hibernate JPA 2 Metamodel does not work with Bean Validation 2 for LOB fields, s 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"`, }); } }, diff --git a/generators/spring-boot/generator.spec.ts b/generators/spring-boot/generator.spec.ts index c6bc95abfc2f..d92a49470906 100644 --- a/generators/spring-boot/generator.spec.ts +++ b/generators/spring-boot/generator.spec.ts @@ -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 85ed61330654..4334d43537e7 100644 --- a/generators/spring-boot/generator.ts +++ b/generators/spring-boot/generator.ts @@ -573,6 +573,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/templates/pom.xml.ejs b/generators/spring-boot/templates/pom.xml.ejs index ec9f3ee08971..c1142e05fa00 100644 --- a/generators/spring-boot/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 diff --git a/generators/spring-boot/templates/src/main/resources/config/application-dev.yml.ejs b/generators/spring-boot/templates/src/main/resources/config/application-dev.yml.ejs index a991975404b3..8bf2eae20e9e 100644 --- a/generators/spring-boot/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,12 @@ spring: additional-exclude: static/**<% if (devDatabaseTypeH2Any) { %>,.h2.server.properties<% } %> livereload: enabled: false # we use Webpack dev server + BrowserSync for livereload +<%_ if (devDatabaseTypeH2Any) { _%> + docker: + compose: + profiles: + active: dev +<%_ } _%> jackson: serialization: indent-output: true diff --git a/generators/spring-boot/templates/src/main/resources/config/application.yml.ejs b/generators/spring-boot/templates/src/main/resources/config/application.yml.ejs index 7fd46697b125..6e136c5b6677 100644 --- a/generators/spring-boot/templates/src/main/resources/config/application.yml.ejs +++ b/generators/spring-boot/templates/src/main/resources/config/application.yml.ejs @@ -268,6 +268,15 @@ spring: content-type: text/plain group: <%= dasherizedBaseName %> <%_ } _%> +<%_ } _%> + 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/spring-boot/templates/src/main/resources/config/bootstrap.yml.ejs b/generators/spring-boot/templates/src/main/resources/config/bootstrap.yml.ejs index 0de7ea411745..b89fd57317b5 100644 --- a/generators/spring-boot/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/spring-cloud-stream/generator.spec.ts b/generators/spring-cloud-stream/generator.spec.ts index d6f85f587311..a668c6d21fa5 100644 --- a/generators/spring-cloud-stream/generator.spec.ts +++ b/generators/spring-cloud-stream/generator.spec.ts @@ -16,7 +16,7 @@ * 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, describe, expect, it } from 'esmocha'; import { snakeCase } from 'lodash-es'; @@ -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 }; @@ -50,7 +49,7 @@ describe(`generator - ${generator}`, () => { let runResult; before(async () => { - runResult = await helpers.run(generatorFile).withJHipsterConfig(config); + runResult = await helpers.runJHipster(generator).withJHipsterConfig(config).withMockedSource(); }); it('should match generated files snapshot', () => { 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-data-cassandra/generator.spec.ts b/generators/spring-data-cassandra/generator.spec.ts index c54947a4bffb..2430b4d7e123 100644 --- a/generators/spring-data-cassandra/generator.spec.ts +++ b/generators/spring-data-cassandra/generator.spec.ts @@ -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-couchbase/generator.spec.ts b/generators/spring-data-couchbase/generator.spec.ts index 6f72952005a7..445b62438605 100644 --- a/generators/spring-data-couchbase/generator.spec.ts +++ b/generators/spring-data-couchbase/generator.spec.ts @@ -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-elasticsearch/__test-support/elastic-search-matcher.ts b/generators/spring-data-elasticsearch/__test-support/elastic-search-matcher.ts index 5a604def0dc1..637e458f8fe7 100644 --- a/generators/spring-data-elasticsearch/__test-support/elastic-search-matcher.ts +++ b/generators/spring-data-elasticsearch/__test-support/elastic-search-matcher.ts @@ -1,3 +1,4 @@ +import { it } from 'esmocha'; import type { RunResult } from 'yeoman-test'; import { JAVA_DOCKER_DIR, SERVER_MAIN_SRC_DIR } from '../../generator-constants.js'; @@ -21,13 +22,13 @@ const desiredConfig = { }; export const matchElasticSearchDocker = (resultGetter: () => RunResult, shouldMatch: boolean) => { - matchWrittenFiles('elasticsearch', resultGetter, expectedElasticsearchFiles, shouldMatch); + it(...matchWrittenFiles('elasticsearch', expectedElasticsearchFiles, shouldMatch, resultGetter())); }; export const matchElasticSearch = (resultGetter: () => RunResult, shouldMatch: boolean) => { - matchWrittenConfig('elasticsearch', resultGetter, desiredConfig, shouldMatch); + it(...matchWrittenConfig('elasticsearch', desiredConfig, shouldMatch, resultGetter())); }; export const matchElasticSearchUser = (resultGetter: () => RunResult, shouldMatch: boolean) => { - matchWrittenFiles('elasticsearch user', resultGetter, () => expectedElasticsearchUserFiles(resultGetter), shouldMatch); + it(...matchWrittenFiles('elasticsearch user', () => expectedElasticsearchUserFiles(resultGetter), shouldMatch, resultGetter())); }; diff --git a/generators/spring-data-elasticsearch/generator.spec.ts b/generators/spring-data-elasticsearch/generator.spec.ts index 46130cabd98f..98d3c1d5930b 100644 --- a/generators/spring-data-elasticsearch/generator.spec.ts +++ b/generators/spring-data-elasticsearch/generator.spec.ts @@ -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, diff --git a/generators/spring-data-mongodb/generator.spec.ts b/generators/spring-data-mongodb/generator.spec.ts index 250cca1b5094..6784808a7123 100644 --- a/generators/spring-data-mongodb/generator.spec.ts +++ b/generators/spring-data-mongodb/generator.spec.ts @@ -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-neo4j/generator.spec.ts b/generators/spring-data-neo4j/generator.spec.ts index 5b11aea0a446..706755e7e8a2 100644 --- a/generators/spring-data-neo4j/generator.spec.ts +++ b/generators/spring-data-neo4j/generator.spec.ts @@ -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/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/generator.spec.ts b/generators/spring-data-relational/generator.spec.ts index 02bc35c25dbb..99837ebf89ac 100644 --- a/generators/spring-data-relational/generator.spec.ts +++ b/generators/spring-data-relational/generator.spec.ts @@ -93,6 +93,7 @@ describe(`generator - ${databaseType}`, () => { await helpers .runJHipster('server') .withJHipsterConfig(sampleConfig) + .withMockedSource({ except: ['addTestSpringFactory'] }) .withMockedJHipsterGenerators({ except: ['jhipster:spring-data-relational'], filter: filterBasicServerGenerators, diff --git a/generators/spring-data-relational/support/database-data.ts b/generators/spring-data-relational/support/database-data.ts index 3b80f3963125..118b05ddcb91 100644 --- a/generators/spring-data-relational/support/database-data.ts +++ b/generators/spring-data-relational/support/database-data.ts @@ -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/lib/testing/helpers.ts b/lib/testing/helpers.ts index 57a6622b84a8..f9cef0d09988 100644 --- a/lib/testing/helpers.ts +++ b/lib/testing/helpers.ts @@ -1,4 +1,5 @@ import { basename, dirname, join } from 'path'; +import { mock } from 'node:test'; import { merge, set, snakeCase } from 'lodash-es'; import type { RunContextSettings, RunResult } from 'yeoman-test'; import { RunContext, YeomanTest, result } from 'yeoman-test'; @@ -56,19 +57,32 @@ const composedGeneratorsToCheck = allGenerators const defaultSharedApplication = Object.fromEntries(['CLIENT_WEBPACK_DIR'].map(key => [key, undefined])); -let defaultMockFactory; +let defaultMockFactory: (original?: any) => any; +let defaultAccumulateMockArgs: (mocks: Record) => Record; -export const defineDefaults = async ({ mockFactory }: { mockFactory?: any } = {}) => { +export const defineDefaults = async ({ + mockFactory, + accumulateMockArgs, +}: { mockFactory?: any; accumulateMockArgs?: (mock: Record) => Record } = {}) => { if (mockFactory) { defaultMockFactory = mockFactory; } else if (!defaultMockFactory) { try { - const { esmocha } = await import('esmocha'); - defaultMockFactory = esmocha.fn; + defaultMockFactory = (...args) => mock.fn(...args); } catch { throw new Error('loadMockFactory should be called before using mock'); } } + if (!defaultAccumulateMockArgs) { + defaultAccumulateMockArgs = + accumulateMockArgs ?? + ((mocks = {}) => + Object.fromEntries( + Object.entries(mocks) + .filter(([_name, fn]) => fn.mock) + .map(([name, fn]) => [name, fn.mock.calls.map(call => (call.arguments.length > 1 ? call.arguments : call.arguments[0]))]), + )); + } }; const createFiles = (workspaceFolder: string, configuration: Record, entities?: BaseEntity[]) => { @@ -222,7 +236,8 @@ class JHipsterRunContext extends RunContext { .commitFiles(); } - withMockedSource(): this { + withMockedSource(options: { except?: string[] } = {}): this { + const { except = [] } = options; this.sharedSource = new Proxy( {}, { @@ -232,7 +247,13 @@ class JHipsterRunContext extends RunContext { } return target[name]; }, - set() { + set(target, property, value) { + if (except.includes(property as string)) { + if (target[property]) { + throw new Error(`Cannot set ${property as string} mock`); + } + target[property] = defaultMockFactory(value); + } return true; }, }, @@ -308,22 +329,33 @@ plugins { async run(): Promise> { const runResult = (await super.run()) as unknown as JHipsterRunResult; if (this.sharedSource) { - const sourceCallsArg = Object.fromEntries( - Object.entries(this.sharedSource).map(([name, fn]) => [name, fn.mock.calls.map(args => (args.length > 1 ? args : args[0]))]), + // Convert big objects to an identifier to avoid big snapshot and serialization issues. + const cleanupArguments = (args: any[] | any[][]) => + args.map(arg => { + if (Array.isArray(arg)) { + return cleanupArguments(arg); + } + const { application, relationships, entities, entity } = arg; + if (application) { + arg = { ...arg, application: `Application[${application.baseName}]` }; + } + if (entity) { + arg = { ...arg, entity: `Entity[${entity.name}]` }; + } + for (const key of ['control', 'entities', 'source'].filter(key => arg[key])) { + arg = { ...arg, [key]: `TaskParameter[${key}]` }; + } + if (relationships) { + arg = { ...arg, relationships: relationships.map(rel => `Relationship[${rel.relationshipName}]`) }; + } + if (entities) { + arg = { ...arg, entities: entities.map(entity => `Entity[${entity.name}]`) }; + } + return arg; + }); + runResult.sourceCallsArg = Object.fromEntries( + Object.entries(defaultAccumulateMockArgs(this.sharedSource)).map(([name, args]) => [name, cleanupArguments(args)]), ); - if (sourceCallsArg.addEntitiesToClient) { - sourceCallsArg.addEntitiesToClient = sourceCallsArg.addEntitiesToClient.map(({ application, entities }) => ({ - application: `Application[${application.baseName}]`, - entities: entities.map(entity => `Entity[${entity.name}]`), - })); - } - if (sourceCallsArg.addEntityToCache) { - sourceCallsArg.addEntityToCache = sourceCallsArg.addEntityToCache.map(({ relationships, ...fields }) => ({ - ...fields, - relationships: relationships.map(rel => `Relationship[${rel.relationshipName}]`), - })); - } - runResult.sourceCallsArg = sourceCallsArg; } runResult.composedMockedGenerators = composedGeneratorsToCheck.filter(gen => runResult.mockedGenerators[gen]?.mock.callCount() > 0); diff --git a/lib/testing/support/matcher.ts b/lib/testing/support/matcher.ts index 7b85e4feac14..bff607c3c1fe 100644 --- a/lib/testing/support/matcher.ts +++ b/lib/testing/support/matcher.ts @@ -1,29 +1,40 @@ -import type { RunResult } from 'yeoman-test'; +import { result } from 'yeoman-test'; +/** + * Requires a global `it` function to be available. + * + * @example + * it(..matchWrittenFiles('eureka', () => ['file'], true)); + */ export const matchWrittenFiles = ( title: string, - resultGetter: () => RunResult, expectedFilesGetter: () => string[], shouldMatch: boolean, -) => { - const testTitle = shouldMatch ? `writes ${title} files` : `doesn't write ${title} files`; - it(testTitle, () => { - const expectedFiles = expectedFilesGetter(); + runResult = result, +): [string, () => void] => [ + shouldMatch ? `writes ${title} files` : `doesn't write ${title} files`, + () => { if (shouldMatch) { - resultGetter().assertFile(expectedFiles); + runResult.assertFile(expectedFilesGetter()); } else { - resultGetter().assertNoFile(expectedFiles); + runResult.assertNoFile(expectedFilesGetter()); } - }); -}; + }, +]; -export const matchWrittenConfig = (title: string, resultGetter: () => RunResult, config: any, shouldMatch: boolean) => { - const testTitle = shouldMatch ? `writes ${title} config` : `doesn't write ${title} config`; - it(testTitle, () => { +/** + * Requires a global `it` function to be available. + * + * @example + * it(..matchWrittenFiles('eureka', { 'generator-jhipster': { config: true } }, true)); + */ +export const matchWrittenConfig = (title: string, config: any, shouldMatch: boolean, runResult = result): [string, () => void] => [ + shouldMatch ? `writes ${title} config` : `doesn't write ${title} config`, + () => { if (shouldMatch) { - resultGetter().assertJsonFileContent('.yo-rc.json', config); + runResult.assertJsonFileContent('.yo-rc.json', config); } else { - resultGetter().assertNoJsonFileContent('.yo-rc.json', config); + runResult.assertNoJsonFileContent('.yo-rc.json', config); } - }); -}; + }, +];