From 960bc7462cbc4add1180d7df90b56238789d91fb Mon Sep 17 00:00:00 2001 From: Marco Collovati Date: Fri, 5 Jul 2024 13:58:14 +0200 Subject: [PATCH] feat: add application identifier to build info (#19669) * feat: add application identifier to build info Gets or computes an application identifier during production build and store it into flow-build-info.json * make applicationIdentifier available through application and deployment configuration * fix test --- .../flow/plugin/maven/BuildDevBundleMojo.java | 46 +++---- .../com/vaadin/gradle/MiscMultiModuleTest.kt | 112 +++++++++++++++++ .../com/vaadin/gradle/MiscSingleModuleTest.kt | 14 +++ .../com/vaadin/gradle/VaadinSmokeTest.kt | 13 ++ .../com/vaadin/gradle/GradlePluginAdapter.kt | 2 + .../gradle/PrepareFrontendInputProperties.kt | 3 + .../gradle/VaadinFlowPluginExtension.kt | 40 ++++-- .../kotlin/com/vaadin/gradle/VaadinUtils.kt | 25 +++- .../plugin/maven/FlowModeAbstractMojo.java | 37 ++++-- .../plugin/maven/BuildFrontendMojoTest.java | 117 +++++++++++++----- .../flow/plugin/base/BuildFrontendUtil.java | 17 +-- .../flow/plugin/base/PluginAdapterBase.java | 13 +- .../plugin/base/BuildFrontendUtilTest.java | 86 ++++++++++--- .../vaadin/flow/server/InitParameters.java | 6 + .../startup/AbstractConfigurationFactory.java | 9 +- .../DeploymentConfigurationFactoryTest.java | 20 +-- 16 files changed, 449 insertions(+), 111 deletions(-) diff --git a/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildDevBundleMojo.java b/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildDevBundleMojo.java index ff08a2ad1f5..d636d79ef97 100644 --- a/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildDevBundleMojo.java +++ b/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildDevBundleMojo.java @@ -15,10 +15,6 @@ */ package com.vaadin.flow.plugin.maven; -import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; -import static com.vaadin.flow.server.Constants.VAADIN_WEBAPP_RESOURCES; -import static com.vaadin.flow.server.frontend.FrontendUtils.FRONTEND; - import java.io.File; import java.io.IOException; import java.net.URI; @@ -31,32 +27,34 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.plugins.annotations.ResolutionScope; -import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.DependencyResolutionRequiredException; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.project.MavenProject; - -import com.vaadin.flow.plugin.base.BuildFrontendUtil; -import com.vaadin.flow.plugin.base.PluginAdapterBase; -import com.vaadin.flow.server.InitParameters; -import com.vaadin.flow.server.frontend.FrontendTools; -import com.vaadin.flow.server.frontend.installer.NodeInstaller; -import com.vaadin.flow.server.frontend.installer.Platform; -import com.vaadin.flow.server.frontend.scanner.ClassFinder; - import com.vaadin.flow.component.dependency.JavaScript; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.dependency.NpmPackage; +import com.vaadin.flow.plugin.base.BuildFrontendUtil; +import com.vaadin.flow.plugin.base.PluginAdapterBase; import com.vaadin.flow.plugin.base.PluginAdapterBuild; import com.vaadin.flow.server.Constants; import com.vaadin.flow.server.ExecutionFailedException; +import com.vaadin.flow.server.InitParameters; +import com.vaadin.flow.server.frontend.FrontendTools; import com.vaadin.flow.server.frontend.FrontendUtils; +import com.vaadin.flow.server.frontend.installer.NodeInstaller; +import com.vaadin.flow.server.frontend.installer.Platform; +import com.vaadin.flow.server.frontend.scanner.ClassFinder; import com.vaadin.flow.theme.Theme; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DependencyResolutionRequiredException; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; + +import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; +import static com.vaadin.flow.server.Constants.VAADIN_WEBAPP_RESOURCES; +import static com.vaadin.flow.server.frontend.FrontendUtils.FRONTEND; /** * Goal that builds the dev frontend bundle to be used in Express Build mode. @@ -459,4 +457,8 @@ public boolean isReactEnabled() { return reactEnable; } + @Override + public String applicationIdentifier() { + return project.getGroupId() + ":" + project.getArtifactId(); + } } diff --git a/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/MiscMultiModuleTest.kt b/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/MiscMultiModuleTest.kt index 1923016b27a..0bec936766e 100644 --- a/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/MiscMultiModuleTest.kt +++ b/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/MiscMultiModuleTest.kt @@ -16,8 +16,13 @@ package com.vaadin.gradle +import com.vaadin.flow.server.InitParameters +import elemental.json.Json import org.gradle.testkit.runner.BuildResult import org.junit.Test +import java.io.File +import java.nio.file.Files +import kotlin.io.path.writeText import kotlin.test.expect class MiscMultiModuleTest : AbstractGradleTest() { @@ -110,5 +115,112 @@ class MiscMultiModuleTest : AbstractGradleTest() { expect(null) { b.task(":lib:vaadinBuildFrontend") } expect(null) { b.task(":vaadinPrepareFrontend") } expect(null) { b.task(":vaadinBuildFrontend") } + + val tokenFile = File(testProject.dir, "web/build/resources/main/META-INF/VAADIN/config/flow-build-info.json") + val tokenFileContent = Json.parse(tokenFile.readText()) + expect("web") { tokenFileContent.getString(InitParameters.APPLICATION_IDENTIFIER) } + } + + @Test + fun `vaadinBuildFrontend application identifier from custom project name`() { + testProject.settingsFile.writeText(""" + include 'lib', 'web' + project(':web').name = 'MY_APP_ID' + """.trimIndent()) + testProject.buildFile.writeText(""" + plugins { + id 'java' + id 'com.vaadin' apply false + } + allprojects { + repositories { + mavenLocal() + mavenCentral() + maven { url = 'https://maven.vaadin.com/vaadin-prereleases' } + } + } + project(':lib') { + apply plugin: 'java' + } + """.trimIndent()) + testProject.newFolder("lib") + val webFolder = testProject.newFolder("web") + val webBuildFile = Files.createFile(webFolder.toPath().resolve("build.gradle")) + webBuildFile.writeText(""" + apply plugin: 'war' + apply plugin: 'com.vaadin' + + dependencies { + implementation project(':lib') + implementation("com.vaadin:flow:$flowVersion") + } + + vaadin { + nodeAutoUpdate = true // test the vaadin{} block by changing some innocent property with limited side-effect + } + """.trimIndent()) + + val b: BuildResult = testProject.build("-Pvaadin.productionMode", "vaadinBuildFrontend", checkTasksSuccessful = false) + b.expectTaskSucceded("MY_APP_ID:vaadinPrepareFrontend") + b.expectTaskSucceded("MY_APP_ID:vaadinBuildFrontend") + expect(null) { b.task(":lib:vaadinPrepareFrontend") } + expect(null) { b.task(":lib:vaadinBuildFrontend") } + expect(null) { b.task(":vaadinPrepareFrontend") } + expect(null) { b.task(":vaadinBuildFrontend") } + + val tokenFile = File(testProject.dir, "web/build/resources/main/META-INF/VAADIN/config/flow-build-info.json") + val tokenFileContent = Json.parse(tokenFile.readText()) + expect("MY_APP_ID") { tokenFileContent.getString(InitParameters.APPLICATION_IDENTIFIER) } + } + + @Test + fun `vaadinBuildFrontend application identifier from plugin configuration`() { + testProject.settingsFile.writeText("include 'lib', 'web'") + testProject.buildFile.writeText(""" + plugins { + id 'java' + id 'com.vaadin' apply false + } + allprojects { + repositories { + mavenLocal() + mavenCentral() + maven { url = 'https://maven.vaadin.com/vaadin-prereleases' } + } + } + project(':lib') { + apply plugin: 'java' + } + """.trimIndent()) + testProject.newFolder("lib") + val webFolder = testProject.newFolder("web") + val webBuildFile = Files.createFile(webFolder.toPath().resolve("build.gradle")) + webBuildFile.writeText(""" + apply plugin: 'war' + apply plugin: 'com.vaadin' + + dependencies { + implementation project(':lib') + implementation("com.vaadin:flow:$flowVersion") + } + + vaadin { + nodeAutoUpdate = true // test the vaadin{} block by changing some innocent property with limited side-effect + applicationIdentifier = 'MY_APP_ID' + } + """.trimIndent()) + + val b: BuildResult = testProject.build("-Pvaadin.productionMode", "vaadinBuildFrontend", checkTasksSuccessful = false) + b.expectTaskSucceded("web:vaadinPrepareFrontend") + b.expectTaskSucceded("web:vaadinBuildFrontend") + expect(null) { b.task(":lib:vaadinPrepareFrontend") } + expect(null) { b.task(":lib:vaadinBuildFrontend") } + expect(null) { b.task(":vaadinPrepareFrontend") } + expect(null) { b.task(":vaadinBuildFrontend") } + + val tokenFile = File(testProject.dir, "web/build/resources/main/META-INF/VAADIN/config/flow-build-info.json") + val tokenFileContent = Json.parse(tokenFile.readText()) + expect("MY_APP_ID") { tokenFileContent.getString(InitParameters.APPLICATION_IDENTIFIER) } } + } diff --git a/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/MiscSingleModuleTest.kt b/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/MiscSingleModuleTest.kt index 3aab2b1056e..451acef7648 100644 --- a/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/MiscSingleModuleTest.kt +++ b/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/MiscSingleModuleTest.kt @@ -16,6 +16,8 @@ package com.vaadin.gradle +import com.vaadin.flow.server.InitParameters +import elemental.json.Json import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.TaskOutcome import org.junit.Test @@ -66,6 +68,18 @@ class MiscSingleModuleTest : AbstractGradleTest() { @Test fun testWarProjectProductionMode() { doTestWarProjectProductionMode() + val tokenFile = File(testProject.dir, "build/resources/main/META-INF/VAADIN/config/flow-build-info.json") + val tokenFileContent = Json.parse(tokenFile.readText()) + expect(testProject.dir.name) { tokenFileContent.getString(InitParameters.APPLICATION_IDENTIFIER) } + } + + @Test + fun testWarProjectProductionModeWithCustomName() { + testProject.settingsFile.writeText("rootProject.name = 'my-test-project'") + doTestWarProjectProductionMode() + val tokenFile = File(testProject.dir, "build/resources/main/META-INF/VAADIN/config/flow-build-info.json") + val tokenFileContent = Json.parse(tokenFile.readText()) + expect("my-test-project") { tokenFileContent.getString(InitParameters.APPLICATION_IDENTIFIER) } } /** diff --git a/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/VaadinSmokeTest.kt b/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/VaadinSmokeTest.kt index 86229a185a2..8dbecd53f40 100644 --- a/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/VaadinSmokeTest.kt +++ b/flow-plugins/flow-gradle-plugin/src/functionalTest/kotlin/com/vaadin/gradle/VaadinSmokeTest.kt @@ -101,6 +101,19 @@ class VaadinSmokeTest : AbstractGradleTest() { val tokenFile = File(testProject.dir, "build/resources/main/META-INF/VAADIN/config/flow-build-info.json") val buildInfo: JsonObject = JsonUtil.parse(tokenFile.readText()) expect(true, buildInfo.toJson()) { buildInfo.getBoolean(InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE) } + expect(testProject.dir.name, buildInfo.toJson()) { buildInfo.getString(InitParameters.APPLICATION_IDENTIFIER) } + } + + @Test + fun testBuildFrontendInProductionMode_customApplicationIdentifier() { + val result: BuildResult = testProject.build("-Pvaadin.applicationIdentifier=MY_APP_ID", "-Pvaadin.productionMode", "vaadinBuildFrontend", debug = true) + // vaadinBuildFrontend depends on vaadinPrepareFrontend + // let's explicitly check that vaadinPrepareFrontend has been run + result.expectTaskSucceded("vaadinPrepareFrontend") + + val tokenFile = File(testProject.dir, "build/resources/main/META-INF/VAADIN/config/flow-build-info.json") + val buildInfo: JsonObject = JsonUtil.parse(tokenFile.readText()) + expect("MY_APP_ID", buildInfo.toJson()) { buildInfo.getString(InitParameters.APPLICATION_IDENTIFIER) } } @Test diff --git a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/GradlePluginAdapter.kt b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/GradlePluginAdapter.kt index b685a0c6530..9797440fb99 100644 --- a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/GradlePluginAdapter.kt +++ b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/GradlePluginAdapter.kt @@ -214,4 +214,6 @@ internal class GradlePluginAdapter( override fun isPrepareFrontendCacheDisabled(): Boolean = config.alwaysExecutePrepareFrontend.get() override fun isReactEnabled(): Boolean = config.reactEnable.get() + + override fun applicationIdentifier(): String = config.applicationIdentifier.get() } diff --git a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/PrepareFrontendInputProperties.kt b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/PrepareFrontendInputProperties.kt index 2675d0cd05a..da0f141d446 100644 --- a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/PrepareFrontendInputProperties.kt +++ b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/PrepareFrontendInputProperties.kt @@ -139,6 +139,9 @@ internal class PrepareFrontendInputProperties(private val config: PluginEffectiv @Input public fun getReactEnable(): Provider = config.reactEnable + @Input + public fun getApplicationIdentifier(): Provider = config.applicationIdentifier + @Input @Optional public fun getNodeExecutablePath(): Provider = tools diff --git a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt index b95b14e9adb..bee4c9e93d6 100644 --- a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt +++ b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt @@ -278,6 +278,8 @@ public abstract class VaadinFlowPluginExtension @Inject constructor(private val public abstract val cleanFrontendFiles: Property + public abstract val applicationIdentifier: Property + public fun filterClasspath(@DelegatesTo(value = ClasspathFilter::class, strategy = Closure.DELEGATE_FIRST) block: Closure<*>) { block.delegate = classpathFilter block.resolveStrategy = Closure.DELEGATE_FIRST @@ -302,7 +304,7 @@ public class PluginEffectiveConfiguration( ) { public val productionMode: Provider = extension.productionMode .convention(false) - .overrideWithSystemProperty("vaadin.productionMode") + .overrideWithSystemPropertyFlag("vaadin.productionMode") public val sourceSetName: Property = extension.sourceSetName .convention("main") @@ -333,22 +335,22 @@ public class PluginEffectiveConfiguration( public val pnpmEnable: Provider = extension.pnpmEnable .convention(Constants.ENABLE_PNPM_DEFAULT) - .overrideWithSystemProperty(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM) + .overrideWithSystemPropertyFlag(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM) public val bunEnable: Provider = extension.bunEnable .convention(Constants.ENABLE_BUN_DEFAULT) - .overrideWithSystemProperty(InitParameters.SERVLET_PARAMETER_ENABLE_BUN) + .overrideWithSystemPropertyFlag(InitParameters.SERVLET_PARAMETER_ENABLE_BUN) public val useGlobalPnpm: Provider = extension.useGlobalPnpm .convention(Constants.GLOBAL_PNPM_DEFAULT) - .overrideWithSystemProperty(InitParameters.SERVLET_PARAMETER_GLOBAL_PNPM) + .overrideWithSystemPropertyFlag(InitParameters.SERVLET_PARAMETER_GLOBAL_PNPM) public val requireHomeNodeExec: Property = extension.requireHomeNodeExec .convention(false) public val eagerServerLoad: Provider = extension.eagerServerLoad .convention(false) - .overrideWithSystemProperty("vaadin.eagerServerLoad") + .overrideWithSystemPropertyFlag("vaadin.eagerServerLoad") public val applicationProperties: Property = extension.applicationProperties .convention(File(project.projectDir, "src/main/resources/application.properties")) @@ -405,43 +407,59 @@ public class PluginEffectiveConfiguration( public val frontendHotdeploy: Provider = extension.frontendHotdeploy .convention(FrontendUtils.isHillaUsed(BuildFrontendUtil.getFrontendDirectory(GradlePluginAdapter(project, this, true)))) - .overrideWithSystemProperty(InitParameters.FRONTEND_HOTDEPLOY) + .overrideWithSystemPropertyFlag(InitParameters.FRONTEND_HOTDEPLOY) public val ciBuild: Provider = extension.ciBuild .convention(false) - .overrideWithSystemProperty(InitParameters.CI_BUILD) + .overrideWithSystemPropertyFlag(InitParameters.CI_BUILD) public val skipDevBundleBuild: Property = extension.skipDevBundleBuild .convention(false) public val forceProductionBuild: Provider = extension.forceProductionBuild .convention(false) - .overrideWithSystemProperty(InitParameters.FORCE_PRODUCTION_BUILD) + .overrideWithSystemPropertyFlag(InitParameters.FORCE_PRODUCTION_BUILD) public val alwaysExecutePrepareFrontend: Property = extension.alwaysExecutePrepareFrontend .convention(false) public val reactEnable: Provider = extension.reactEnable .convention(FrontendUtils.isReactRouterRequired(BuildFrontendUtil.getFrontendDirectory(GradlePluginAdapter(project, this, true)))) - .overrideWithSystemProperty(InitParameters.REACT_ENABLE) + .overrideWithSystemPropertyFlag(InitParameters.REACT_ENABLE) public val cleanFrontendFiles: Property = extension.cleanFrontendFiles .convention(true) + + public val applicationIdentifier: Provider = extension.applicationIdentifier.convention(project.name) + .overrideWithSystemProperty("vaadin.${InitParameters.APPLICATION_IDENTIFIER}") + /** * Finds the value of a boolean property. It searches in gradle and system properties. * - * If the property is defined in both gradle and system properties, then the gradle property is taken. + * If the property is defined in both gradle and system properties, then the system property is taken. * * @param propertyName the property name * @return a new provider of the value, which either takes the original value if the system/gradle property is not present, * `true` if it's defined or if it's set to "true" and `false` otherwise. */ - private fun Provider.overrideWithSystemProperty(propertyName: String) : Provider = map { originalValue -> + private fun Provider.overrideWithSystemPropertyFlag(propertyName: String) : Provider = map { originalValue -> project.getBooleanProperty(propertyName) ?: originalValue } + /** + * Finds the value of a string property. It searches in gradle and system properties. + * + * If the property is defined in both gradle and system properties, then the system property is taken. + * + * @param propertyName the property name + * @return a new provider of the value, which either takes the original value if the system/gradle property is not present. + */ + private fun Provider.overrideWithSystemProperty(propertyName: String) : Provider = map { originalValue -> + project.getStringProperty(propertyName) ?: originalValue + } override fun toString(): String = "PluginEffectiveConfiguration(" + "productionMode=${productionMode.get()}, " + + "applicationIdentifier=${applicationIdentifier.get()}, " + "webpackOutputDirectory=${webpackOutputDirectory.get()}, " + "npmFolder=${npmFolder.get()}, " + "frontendDirectory=${frontendDirectory.get()}, " + diff --git a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinUtils.kt b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinUtils.kt index 53a62108abe..5bd489d7e17 100644 --- a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinUtils.kt +++ b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinUtils.kt @@ -37,7 +37,7 @@ import kotlin.contracts.contract /** * Finds the value of a boolean property. It searches in gradle and system properties. * - * If the property is defined in both gradle and system properties, then the gradle property is taken. + * If the property is defined in both gradle and system properties, then the system property is taken. * * @param propertyName the property name * @@ -60,6 +60,29 @@ public fun Project.getBooleanProperty(propertyName: String) : Boolean? { return null } +/** + * Finds the value of a string property. It searches in gradle and system properties. + * + * If the property is defined in both gradle and system properties, then the system property is taken. + * + * @param propertyName the property name + * + * @return the value of the property or `null` if the property is not present. + */ +public fun Project.getStringProperty(propertyName: String) : String? { + if (System.getProperty(propertyName) != null) { + val value: String = System.getProperty(propertyName) + logger.info("Set $propertyName to $value because of System property $propertyName='$value'") + return value + } + if (project.hasProperty(propertyName)) { + val value: String = project.property(propertyName) as String + logger.info("Set $propertyName to $value because of Gradle project property $propertyName='$value'") + return value + } + return null +} + /** * Allows Kotlin-based gradle scripts to be configured via the `vaadin{}` DSL block: * ``` diff --git a/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java b/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java index fa50c77183a..865bd99633a 100644 --- a/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java +++ b/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java @@ -15,11 +15,6 @@ */ package com.vaadin.flow.plugin.maven; -import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; -import static com.vaadin.flow.server.Constants.VAADIN_WEBAPP_RESOURCES; -import static com.vaadin.flow.server.frontend.FrontendUtils.FRONTEND; -import static com.vaadin.flow.server.frontend.FrontendUtils.GENERATED; - import java.io.File; import java.net.URI; import java.net.URISyntaxException; @@ -31,12 +26,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.DependencyResolutionRequiredException; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.MavenProject; - import com.vaadin.flow.plugin.base.BuildFrontendUtil; import com.vaadin.flow.plugin.base.PluginAdapterBase; import com.vaadin.flow.server.Constants; @@ -46,6 +35,16 @@ import com.vaadin.flow.server.frontend.installer.NodeInstaller; import com.vaadin.flow.server.frontend.installer.Platform; import com.vaadin.flow.server.frontend.scanner.ClassFinder; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DependencyResolutionRequiredException; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; + +import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; +import static com.vaadin.flow.server.Constants.VAADIN_WEBAPP_RESOURCES; +import static com.vaadin.flow.server.frontend.FrontendUtils.FRONTEND; +import static com.vaadin.flow.server.frontend.FrontendUtils.GENERATED; /** * The base class of Flow Mojos in order to compute correctly the modes. @@ -232,6 +231,14 @@ public abstract class FlowModeAbstractMojo extends AbstractMojo @Parameter(property = InitParameters.REACT_ENABLE, defaultValue = "${null}") private Boolean reactEnable; + /** + * Identifier for the application. + *

+ * If not specified, defaults to '{@literal groupId:artifactId}'. + */ + @Parameter(property = InitParameters.APPLICATION_IDENTIFIER) + private String applicationIdentifier; + /** * Generates a List of ClasspathElements (Run and CompileTime) from a * MavenProject. @@ -522,4 +529,12 @@ public boolean isReactEnabled() { File frontendDirectory = BuildFrontendUtil.getFrontendDirectory(this); return FrontendUtils.isReactRouterRequired(frontendDirectory); } + + @Override + public String applicationIdentifier() { + if (applicationIdentifier != null && !applicationIdentifier.isBlank()) { + return applicationIdentifier; + } + return project.getGroupId() + ":" + project.getArtifactId(); + } } diff --git a/flow-plugins/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/maven/BuildFrontendMojoTest.java b/flow-plugins/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/maven/BuildFrontendMojoTest.java index d1208542243..88ac8c5a902 100644 --- a/flow-plugins/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/maven/BuildFrontendMojoTest.java +++ b/flow-plugins/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/maven/BuildFrontendMojoTest.java @@ -34,6 +34,18 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.vaadin.flow.di.Lookup; +import com.vaadin.flow.plugin.TestUtils; +import com.vaadin.flow.server.Constants; +import com.vaadin.flow.server.InitParameters; +import com.vaadin.flow.server.frontend.EndpointGeneratorTaskFactory; +import com.vaadin.flow.server.frontend.FrontendTools; +import com.vaadin.flow.server.frontend.FrontendUtils; +import com.vaadin.flow.server.frontend.installer.NodeInstaller; +import com.vaadin.flow.server.frontend.scanner.ClassFinder; +import elemental.json.Json; +import elemental.json.JsonObject; +import elemental.json.impl.JsonUtil; import org.apache.maven.model.Build; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; @@ -49,34 +61,23 @@ import org.junit.rules.TemporaryFolder; import org.mockito.Mockito; -import com.vaadin.flow.di.Lookup; -import com.vaadin.flow.plugin.TestUtils; -import com.vaadin.flow.server.Constants; -import com.vaadin.flow.server.InitParameters; -import com.vaadin.flow.server.frontend.EndpointGeneratorTaskFactory; -import com.vaadin.flow.server.frontend.FrontendTools; -import com.vaadin.flow.server.frontend.FrontendUtils; -import com.vaadin.flow.server.frontend.installer.NodeInstaller; -import com.vaadin.flow.server.frontend.scanner.ClassFinder; +import static java.io.File.pathSeparator; -import elemental.json.Json; -import elemental.json.JsonObject; -import elemental.json.impl.JsonUtil; import static com.vaadin.flow.server.Constants.PACKAGE_JSON; import static com.vaadin.flow.server.Constants.TARGET; import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; import static com.vaadin.flow.server.Constants.VAADIN_WEBAPP_RESOURCES; +import static com.vaadin.flow.server.InitParameters.APPLICATION_IDENTIFIER; import static com.vaadin.flow.server.InitParameters.FRONTEND_HOTDEPLOY; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_FRONTEND_DIR; +import static com.vaadin.flow.server.frontend.FrontendUtils.FRONTEND_FOLDER_ALIAS; import static com.vaadin.flow.server.frontend.FrontendUtils.IMPORTS_D_TS_NAME; import static com.vaadin.flow.server.frontend.FrontendUtils.IMPORTS_NAME; import static com.vaadin.flow.server.frontend.FrontendUtils.NODE_MODULES; import static com.vaadin.flow.server.frontend.FrontendUtils.TOKEN_FILE; import static com.vaadin.flow.server.frontend.FrontendUtils.VITE_CONFIG; import static com.vaadin.flow.server.frontend.FrontendUtils.VITE_GENERATED_CONFIG; -import static com.vaadin.flow.server.frontend.FrontendUtils.FRONTEND_FOLDER_ALIAS; -import static java.io.File.pathSeparator; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -109,19 +110,6 @@ public class BuildFrontendMojoTest { public void setup() throws Exception { projectBase = temporaryFolder.getRoot(); - MavenProject project = Mockito.mock(MavenProject.class); - Mockito.when(project.getRuntimeClasspathElements()) - .thenReturn(getClassPath(projectBase.toPath())); - - List packages = Arrays - .stream(System.getProperty("java.class.path") - .split(File.pathSeparatorChar + "")) - .collect(Collectors.toList()); - Mockito.when(project.getRuntimeClasspathElements()) - .thenReturn(packages); - Mockito.when(project.getCompileClasspathElements()) - .thenReturn(Collections.emptyList()); - tokenFile = new File(temporaryFolder.getRoot(), VAADIN_SERVLET_RESOURCES + TOKEN_FILE); @@ -161,7 +149,6 @@ public void setup() throws Exception { "frontendResourcesDirectory", projectFrontendResourcesDirectory); - ReflectionUtils.setVariableValueInObject(mojo, "project", project); ReflectionUtils.setVariableValueInObject(mojo, "webpackOutputDirectory", webpackOutputDirectory); ReflectionUtils.setVariableValueInObject(mojo, @@ -196,8 +183,9 @@ public void setup() throws Exception { Paths.get(projectBase.toString(), "target").toString()); ReflectionUtils.setVariableValueInObject(mojo, "postinstallPackages", Collections.emptyList()); - Mockito.when(mojo.getJarFiles()).thenReturn( - Set.of(jarResourcesSource.getParentFile().getParentFile())); + Mockito.doReturn( + Set.of(jarResourcesSource.getParentFile().getParentFile())) + .when(mojo).getJarFiles(); setProject(mojo, npmFolder); @@ -235,6 +223,8 @@ static void setProject(AbstractMojo mojo, File baseFolder) Build buildMock = mock(Build.class); when(buildMock.getFinalName()).thenReturn("finalName"); MavenProject project = mock(MavenProject.class); + Mockito.when(project.getGroupId()).thenReturn("com.vaadin.testing"); + Mockito.when(project.getArtifactId()).thenReturn("my-application"); when(project.getBasedir()).thenReturn(baseFolder); when(project.getBuild()).thenReturn(buildMock); when(project.getRuntimeClasspathElements()) @@ -514,6 +504,73 @@ public void existingTokenFile_parametersShouldBeRemoved() InitParameters.SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE)); } + @Test + public void existingTokenFile_defaultApplicationIdentifierWritten() + throws IOException, MojoExecutionException, MojoFailureException { + String expectedAppId = "com.vaadin.testing:my-application"; + + JsonObject initialBuildInfo = Json.createObject(); + initialBuildInfo.put(SERVLET_PARAMETER_PRODUCTION_MODE, false); + initialBuildInfo.put(Constants.NPM_TOKEN, "npm"); + initialBuildInfo.put(Constants.FRONTEND_TOKEN, "src/main/frontend"); + + initialBuildInfo.put(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, + true); + initialBuildInfo.put(InitParameters.REQUIRE_HOME_NODE_EXECUTABLE, true); + initialBuildInfo.put( + InitParameters.SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE, true); + initialBuildInfo.put(InitParameters.CI_BUILD, true); + + org.apache.commons.io.FileUtils.forceMkdir(tokenFile.getParentFile()); + org.apache.commons.io.FileUtils.write(tokenFile, + JsonUtil.stringify(initialBuildInfo, 2) + "\n", "UTF-8"); + + mojo.execute(); + Assert.assertTrue("No token file could be found", tokenFile.exists()); + + String json = org.apache.commons.io.FileUtils + .readFileToString(tokenFile, "UTF-8"); + JsonObject buildInfo = JsonUtil.parse(json); + Assert.assertEquals( + "Custom application identifier not written on token file", + expectedAppId, buildInfo.getString(APPLICATION_IDENTIFIER)); + } + + @Test + public void existingTokenFile_customApplicationIdentifierWritten() + throws IOException, MojoExecutionException, MojoFailureException, + IllegalAccessException { + String appId = "MY-APP-ID"; + ReflectionUtils.setVariableValueInObject(mojo, "applicationIdentifier", + appId); + + JsonObject initialBuildInfo = Json.createObject(); + initialBuildInfo.put(SERVLET_PARAMETER_PRODUCTION_MODE, false); + initialBuildInfo.put(Constants.NPM_TOKEN, "npm"); + initialBuildInfo.put(Constants.FRONTEND_TOKEN, "src/main/frontend"); + + initialBuildInfo.put(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, + true); + initialBuildInfo.put(InitParameters.REQUIRE_HOME_NODE_EXECUTABLE, true); + initialBuildInfo.put( + InitParameters.SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE, true); + initialBuildInfo.put(InitParameters.CI_BUILD, true); + + org.apache.commons.io.FileUtils.forceMkdir(tokenFile.getParentFile()); + org.apache.commons.io.FileUtils.write(tokenFile, + JsonUtil.stringify(initialBuildInfo, 2) + "\n", "UTF-8"); + + mojo.execute(); + Assert.assertTrue("No token file could be found", tokenFile.exists()); + + String json = org.apache.commons.io.FileUtils + .readFileToString(tokenFile, "UTF-8"); + JsonObject buildInfo = JsonUtil.parse(json); + Assert.assertEquals( + "Custom application identifier not written on token file", + appId, buildInfo.getString(APPLICATION_IDENTIFIER)); + } + @Test public void noTokenFile_noTokenFileShouldBeCreated() throws MojoExecutionException, MojoFailureException { diff --git a/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java b/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java index 27a3898c39b..41eb102f5e0 100644 --- a/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java +++ b/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java @@ -34,13 +34,6 @@ import java.util.jar.JarFile; import java.util.jar.Manifest; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.zeroturnaround.exec.InvalidExitValueException; -import org.zeroturnaround.exec.ProcessExecutor; - import com.vaadin.flow.di.Lookup; import com.vaadin.flow.server.Constants; import com.vaadin.flow.server.ExecutionFailedException; @@ -59,10 +52,15 @@ import com.vaadin.pro.licensechecker.BuildType; import com.vaadin.pro.licensechecker.LicenseChecker; import com.vaadin.pro.licensechecker.Product; - import elemental.json.Json; import elemental.json.JsonObject; import elemental.json.impl.JsonUtil; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zeroturnaround.exec.InvalidExitValueException; +import org.zeroturnaround.exec.ProcessExecutor; import static com.vaadin.flow.server.Constants.CONNECT_APPLICATION_PROPERTIES_TOKEN; import static com.vaadin.flow.server.Constants.CONNECT_JAVA_SOURCE_FOLDER_TOKEN; @@ -72,6 +70,7 @@ import static com.vaadin.flow.server.Constants.JAVA_RESOURCE_FOLDER_TOKEN; import static com.vaadin.flow.server.Constants.NPM_TOKEN; import static com.vaadin.flow.server.Constants.PROJECT_FRONTEND_GENERATED_DIR_TOKEN; +import static com.vaadin.flow.server.InitParameters.APPLICATION_IDENTIFIER; import static com.vaadin.flow.server.InitParameters.FRONTEND_HOTDEPLOY; import static com.vaadin.flow.server.InitParameters.NODE_DOWNLOAD_ROOT; import static com.vaadin.flow.server.InitParameters.NODE_VERSION; @@ -730,6 +729,8 @@ public static void updateBuildFile(PluginAdapterBuild adapter) { buildInfo.remove(Constants.PROJECT_FRONTEND_GENERATED_DIR_TOKEN); buildInfo.remove(InitParameters.BUILD_FOLDER); buildInfo.put(SERVLET_PARAMETER_PRODUCTION_MODE, true); + buildInfo.put(APPLICATION_IDENTIFIER, + adapter.applicationIdentifier()); FileUtils.write(tokenFile, JsonUtil.stringify(buildInfo, 2) + "\n", StandardCharsets.UTF_8.name()); diff --git a/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/PluginAdapterBase.java b/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/PluginAdapterBase.java index e0a187cb10e..bb695477e9d 100644 --- a/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/PluginAdapterBase.java +++ b/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/PluginAdapterBase.java @@ -30,7 +30,6 @@ /** * Gives access to plugin-specific implementations and configurations. - * */ public interface PluginAdapterBase { @@ -326,4 +325,16 @@ default Lookup createLookup(ClassFinder classFinder) { * router and excluding React dependencies */ boolean isReactEnabled(); + + /** + * Gets the application identifier. + *

+ * The application identifier is usually computed against project unique + * information, such as {@literal groupId} and {@literal artifactId}, but it + * can be any kind of not blank string. + * + * @return application identifier, never {@literal null} nor + * {@literal blank}. + */ + String applicationIdentifier(); } diff --git a/flow-plugins/flow-plugin-base/src/test/java/com/vaadin/flow/plugin/base/BuildFrontendUtilTest.java b/flow-plugins/flow-plugin-base/src/test/java/com/vaadin/flow/plugin/base/BuildFrontendUtilTest.java index 96fd5b519a0..461a3727479 100644 --- a/flow-plugins/flow-plugin-base/src/test/java/com/vaadin/flow/plugin/base/BuildFrontendUtilTest.java +++ b/flow-plugins/flow-plugin-base/src/test/java/com/vaadin/flow/plugin/base/BuildFrontendUtilTest.java @@ -10,6 +10,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -18,22 +19,10 @@ import java.util.Set; import java.util.stream.Collectors; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.mockito.ArgumentMatchers; -import org.mockito.InOrder; -import org.mockito.MockedConstruction; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - import com.vaadin.flow.di.Lookup; import com.vaadin.flow.server.Constants; import com.vaadin.flow.server.ExecutionFailedException; +import com.vaadin.flow.server.InitParameters; import com.vaadin.flow.server.frontend.EndpointGeneratorTaskFactory; import com.vaadin.flow.server.frontend.FrontendTools; import com.vaadin.flow.server.frontend.FrontendUtils; @@ -46,9 +35,20 @@ import com.vaadin.flow.server.frontend.scanner.FrontendDependenciesScanner; import com.vaadin.flow.utils.LookupImpl; import com.vaadin.pro.licensechecker.Product; - import elemental.json.Json; import elemental.json.JsonObject; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.mockito.ArgumentMatchers; +import org.mockito.InOrder; +import org.mockito.MockedConstruction; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import static com.vaadin.flow.server.frontend.FrontendUtils.TOKEN_FILE; @@ -75,6 +75,7 @@ public void setup() throws Exception { .thenReturn(new File(baseDir, "src/main/frontend/generated")); Mockito.when(adapter.projectBaseDirectory()) .thenReturn(tmpDir.getRoot().toPath()); + Mockito.when(adapter.applicationIdentifier()).thenReturn("TEST_APP_ID"); ClassFinder classFinder = Mockito.mock(ClassFinder.class); Mockito.when(classFinder.loadClass(ArgumentMatchers.anyString())).then( i -> getClass().getClassLoader().loadClass(i.getArgument(0))); @@ -301,6 +302,63 @@ public void prepareFrontend_shouldCleanUnusedGeneratedFiles() } + @Test + public void updateBuildFile_tokenFileNotExisting_doNothing() + throws Exception { + fillAdapter(); + + BuildFrontendUtil.updateBuildFile(adapter); + File tokenFile = new File(resourceOutput, TOKEN_FILE); + Assert.assertFalse("Token file should not have been created", + tokenFile.exists()); + } + + @Test + public void updateBuildFile_tokenExisting_developmentEntriesRemoved() + throws Exception { + fillAdapter(); + + BuildFrontendUtil.propagateBuildInfo(adapter); + + File tokenFile = new File(resourceOutput, TOKEN_FILE); + Assert.assertTrue("Token file should have been created", + tokenFile.exists()); + JsonObject buildInfoJsonDev = Json + .parse(Files.readString(tokenFile.toPath())); + + BuildFrontendUtil.updateBuildFile(adapter); + Assert.assertTrue("Token file should still exist", tokenFile.exists()); + JsonObject buildInfoJsonProd = Json + .parse(Files.readString(tokenFile.toPath())); + + Set removedKeys = Arrays.stream(buildInfoJsonDev.keys()) + .filter(key -> !buildInfoJsonProd.hasKey(key)) + .collect(Collectors.toSet()); + Assert.assertFalse( + "Development entries have not been removed from token file", + removedKeys.isEmpty()); + } + + @Test + public void updateBuildFile_tokenExisting_applicationIdentifierAdded() + throws Exception { + fillAdapter(); + + BuildFrontendUtil.propagateBuildInfo(adapter); + + File tokenFile = new File(resourceOutput, TOKEN_FILE); + Assert.assertTrue("Token file should have been created", + tokenFile.exists()); + + BuildFrontendUtil.updateBuildFile(adapter); + Assert.assertTrue("Token file should still exist", tokenFile.exists()); + JsonObject buildInfoJsonProd = Json + .parse(Files.readString(tokenFile.toPath())); + Assert.assertEquals("Wrong application identifier in token file", + "TEST_APP_ID", buildInfoJsonProd + .getString(InitParameters.APPLICATION_IDENTIFIER)); + } + private void fillAdapter() throws URISyntaxException { Mockito.when(adapter.nodeDownloadRoot()) .thenReturn(URI.create("http://something/node/")); diff --git a/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java b/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java index f8a93f7c69e..a9889197a45 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java @@ -279,4 +279,10 @@ public class InitParameters implements Serializable { * Time is given in minutes. */ public static final String LAUNCH_BROWSER_DELAY = "launch-browser-delay"; + + /** + * Configuration name for setting the application identifier. + */ + public static final String APPLICATION_IDENTIFIER = "applicationIdentifier"; + } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java index 0816c581ad4..51ccfc28fc9 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java @@ -24,14 +24,12 @@ import java.util.Map; import java.util.function.Function; -import org.apache.commons.io.FileUtils; - import com.vaadin.flow.internal.UsageStatistics; import com.vaadin.flow.server.Constants; import com.vaadin.flow.server.InitParameters; import com.vaadin.flow.server.frontend.FrontendUtils; - import elemental.json.JsonObject; +import org.apache.commons.io.FileUtils; import static com.vaadin.flow.server.Constants.CONNECT_APPLICATION_PROPERTIES_TOKEN; import static com.vaadin.flow.server.Constants.CONNECT_JAVA_SOURCE_FOLDER_TOKEN; @@ -45,6 +43,7 @@ import static com.vaadin.flow.server.Constants.NPM_TOKEN; import static com.vaadin.flow.server.Constants.PROJECT_FRONTEND_GENERATED_DIR_TOKEN; import static com.vaadin.flow.server.Constants.VAADIN_PREFIX; +import static com.vaadin.flow.server.InitParameters.APPLICATION_IDENTIFIER; import static com.vaadin.flow.server.InitParameters.BUILD_FOLDER; import static com.vaadin.flow.server.InitParameters.FRONTEND_HOTDEPLOY; import static com.vaadin.flow.server.InitParameters.NODE_DOWNLOAD_ROOT; @@ -171,6 +170,10 @@ protected Map getConfigParametersUsingTokenData( params.put(REACT_ENABLE, String.valueOf(buildInfo.getBoolean(REACT_ENABLE))); } + if (buildInfo.hasKey(APPLICATION_IDENTIFIER)) { + params.put(APPLICATION_IDENTIFIER, + buildInfo.getString(APPLICATION_IDENTIFIER)); + } setDevModePropertiesUsingTokenData(params, buildInfo); return params; diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java index ae03aff2d07..f239e6d6bce 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java @@ -2,13 +2,13 @@ import jakarta.servlet.ServletConfig; import jakarta.servlet.ServletContext; - import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -19,8 +19,13 @@ import java.util.Map; import java.util.Properties; import java.util.Set; -import java.util.ArrayList; +import com.vaadin.flow.component.UI; +import com.vaadin.flow.di.Lookup; +import com.vaadin.flow.di.ResourceProvider; +import com.vaadin.flow.function.DeploymentConfiguration; +import com.vaadin.flow.server.frontend.FrontendUtils; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.AfterClass; @@ -33,19 +38,13 @@ import org.junit.rules.TemporaryFolder; import org.mockito.Mockito; -import com.vaadin.flow.component.UI; -import com.vaadin.flow.di.Lookup; -import com.vaadin.flow.di.ResourceProvider; -import com.vaadin.flow.function.DeploymentConfiguration; -import com.vaadin.flow.server.frontend.FrontendUtils; -import com.vaadin.flow.server.startup.ApplicationConfiguration; +import static java.util.Collections.emptyMap; import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; import static com.vaadin.flow.server.frontend.FrontendUtils.PARAM_TOKEN_FILE; import static com.vaadin.flow.server.frontend.FrontendUtils.TOKEN_FILE; import static com.vaadin.flow.server.startup.AbstractConfigurationFactory.DEV_FOLDER_MISSING_MESSAGE; -import static java.util.Collections.emptyMap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -326,7 +325,8 @@ public void createInitParameters_valuesAreTakenFromservletConfigAndTokenFile_val InitParameters.SERVLET_PARAMETER_DEVMODE_VITE_OPTIONS, InitParameters.COMPILED_WEB_COMPONENTS_PATH, InitParameters.NODE_VERSION, InitParameters.NODE_DOWNLOAD_ROOT, - InitParameters.BUILD_FOLDER)); + InitParameters.BUILD_FOLDER, + InitParameters.APPLICATION_IDENTIFIER)); Field[] initParamFields = InitParameters.class.getDeclaredFields(); String mockTokenJsonString = generateJsonStringFromFields( initParamFields, stringParams);