Skip to content

Commit

Permalink
feat: update gradle plugin clean tasks (#18756)
Browse files Browse the repository at this point in the history
* feat: update gradle plugin clean tasks

Updates Vaadin Gradle plugin to clean in same way as Maven plugin cleans. Moved  CleanFrontendMojo logic to CleanFrontendUtil in shared flow-plugin-base.
Updated VaadinCleanTask and VaadinBuildFrontendTask.
Added cleanFrontendFiles property to Gradle plugin.

Fixes: #18556

* test: added tests

* chore: use local stub jar

...instead of using real hilla endpoint. Also removed webpack.generated.js from the task description and javadoc.

* chore: extract Options to CleanOptions

* docs: added javadoc
  • Loading branch information
tltv authored Feb 22, 2024
1 parent 11830c9 commit 2064933
Show file tree
Hide file tree
Showing 13 changed files with 602 additions and 351 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,11 @@ public void logDebug(CharSequence debugMessage) {
getLog().debug(debugMessage);
}

@Override
public void logDebug(CharSequence debugMessage, Throwable e) {
getLog().debug(debugMessage, e);
}

@Override
public void logInfo(CharSequence infoMessage) {
getLog().info(infoMessage);
Expand All @@ -318,14 +323,19 @@ public void logWarn(CharSequence warning) {
getLog().warn(warning);
}

@Override
public void logError(CharSequence error) {
getLog().error(error);
}

@Override
public void logWarn(CharSequence warning, Throwable e) {
getLog().warn(warning, e);
}

@Override
public void logError(CharSequence warning, Throwable e) {
getLog().error(warning, e);
public void logError(CharSequence error, Throwable e) {
getLog().error(error, e);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import java.io.File
*/
abstract class AbstractGradleTest {

val flowVersion = System.getenv("vaadin.version").takeUnless { it.isNullOrEmpty() } ?: "24.3-SNAPSHOT"
val flowVersion = System.getenv("vaadin.version").takeUnless { it.isNullOrEmpty() } ?: "24.4-SNAPSHOT"
val slf4jVersion = "2.0.3"

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ import java.io.File
import kotlin.test.assertContains
import kotlin.test.expect
import com.vaadin.flow.server.InitParameters
import com.vaadin.flow.server.frontend.FrontendUtils
import elemental.json.JsonObject
import elemental.json.impl.JsonUtil
import org.gradle.api.JavaVersion
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.TaskOutcome
import org.junit.Before
import org.junit.Test
import java.nio.file.Files
import java.nio.file.StandardCopyOption


/**
* The most basic tests. If these fail, the plugin is completely broken and all
Expand Down Expand Up @@ -149,29 +152,15 @@ class VaadinSmokeTest : AbstractGradleTest() {
@Test
fun vaadinCleanDoesntDeletePnpmFiles() {
val pnpmLockYaml = testProject.newFile("pnpm-lock.yaml")
val pnpmFileJs = testProject.newFile("pnpmfile.js")
val pnpmFileCjs = testProject.newFile(".pnpmfile.cjs")
val webpackConfigJs = testProject.newFile("webpack.config.js")
testProject.build("vaadinClean")
expect(false) { pnpmLockYaml.exists() }
expect(false) { pnpmFileJs.exists() }
expect(false) { pnpmFileCjs.exists() }
// don't delete webpack.config.js: https://github.com/vaadin/vaadin-gradle-plugin/pull/74#discussion_r444457296
expect(true) { webpackConfigJs.exists() }
}

/**
* Tests that VaadinClean task removes TS-related files.
*/
@Test
fun vaadinCleanDeletesTsFiles() {
val tsconfigJson = testProject.newFile("tsconfig.json")
val typesDTs = testProject.newFile("types.d.ts")
testProject.build("vaadinClean")
expect(false) { tsconfigJson.exists() }
expect(false) { typesDTs.exists() }
}

/**
* Tests that VaadinClean task removes default fronted/generated directory
*/
Expand Down Expand Up @@ -246,6 +235,58 @@ class VaadinSmokeTest : AbstractGradleTest() {
expect(false) { generatedTsFolder.exists() }
}

@Test
fun vaadinCleanShouldRemoveNodeModulesAndPackageLock() {
val nodeModules: File = testProject.newFolder(FrontendUtils.NODE_MODULES)
val packageLock: File = testProject.newFile("package-lock.json")
expect(true) { nodeModules.exists() }
expect(true) { packageLock.exists() }
testProject.build("vaadinClean")
expect(false) { nodeModules.exists() }
expect(false) { packageLock.exists() }
}

@Test
fun vaadinCleanShouldNotRemoveNodeModulesAndPackageLockWithHilla() {
testProject.buildFile.writeText("""
plugins {
id 'war'
id 'com.vaadin'
}
repositories {
mavenLocal()
mavenCentral()
maven { url = 'https://maven.vaadin.com/vaadin-prereleases' }
flatDir {
dirs("libs")
}
}
dependencies {
implementation("com.vaadin:flow:$flowVersion")
implementation name:'hilla-endpoint-stub'
providedCompile("jakarta.servlet:jakarta.servlet-api:6.0.0")
implementation("org.slf4j:slf4j-simple:$slf4jVersion")
}
vaadin {
nodeAutoUpdate = true // test the vaadin{} block by changing some innocent property with limited side-effect
}
""")
testProject.newFolder("libs")
// hilla-endpoint-stub.jar contains only stub for com.vaadin.hilla.EndpointController.class
val hillaEndpointJar: File = testProject.newFile("libs/hilla-endpoint-stub.jar")
Files.copy(
File(javaClass.classLoader.getResource("hilla-endpoint-stub.jar").path).toPath(),
hillaEndpointJar.toPath(), StandardCopyOption.REPLACE_EXISTING)
enableHilla()
val nodeModules: File = testProject.newFolder(FrontendUtils.NODE_MODULES)
val packageLock: File = testProject.newFile("package-lock.json")
expect(true) { nodeModules.exists() }
expect(true) { packageLock.exists() }
testProject.build("vaadinClean")
expect(true) { nodeModules.exists() }
expect(true) { packageLock.exists() }
}

/**
* Tests that build works with a custom frontend directory
*/
Expand Down Expand Up @@ -360,4 +401,9 @@ class VaadinSmokeTest : AbstractGradleTest() {
)
}
}

private fun enableHilla() {
testProject.newFolder("frontend")
testProject.newFile("frontend/index.ts")
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ internal class GradlePluginAdapter(
project.logger.debug(debugMessage.toString())
}

override fun logDebug(debugMessage: CharSequence, throwable: Throwable?) {
project.logger.debug(debugMessage.toString(), throwable)
}

override fun logInfo(infoMessage: CharSequence) {
project.logger.info(infoMessage.toString())
}
Expand All @@ -118,6 +122,10 @@ internal class GradlePluginAdapter(
project.logger.warn(warningMessage.toString(), throwable)
}

override fun logError(errorMessage: CharSequence) {
project.logger.error(errorMessage.toString())
}

override fun logError(warning: CharSequence, e: Throwable?) {
project.logger.error(warning.toString(), e)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,18 @@ public open class VaadinBuildFrontendTask : DefaultTask() {
*
* @return `true` to remove created files, `false` to keep the files
*/
protected open fun cleanFrontendFiles(): Boolean = true
protected open fun cleanFrontendFiles(): Boolean {
val adapter = GradlePluginAdapter(project, config, false)
if (FrontendUtils.isHillaUsed(adapter.frontendDirectory(),
adapter.classFinder)) {
/*
* Override this to not clean generated frontend files after the
* build. For Hilla, the generated files can still be useful for
* developers after the build. For example, a developer can use
* {@code vite.generated.ts} to run tests with vitest in CI.
*/
return false
}
return config.cleanFrontendFiles.get()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
*/
package com.vaadin.gradle

import com.vaadin.flow.plugin.base.CleanFrontendUtil
import com.vaadin.flow.plugin.base.CleanOptions
import com.vaadin.flow.server.frontend.FrontendUtils
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import com.vaadin.flow.server.Constants

/**
* Cleans everything Vaadin-related. Useful if npm fails to run after Vaadin
Expand All @@ -28,11 +30,7 @@ import com.vaadin.flow.server.Constants
* * `node_modules`
* * `package.json`
* * `package-lock.json`
* * `webpack.generated.js`
* * `package-lock.yaml` (used by Vaadin 14.2+ pnpm)
* * `pnpm-file.js` (used by Vaadin 14.2+ pnpm)
* * `tsconfig.json` (used by Vaadin 15+)
* * `types.d.ts` (used by Vaadin 15+)
*
* Doesn't delete `webpack.config.js` since it is intended to contain
* user-specific code. See https://github.com/vaadin/vaadin-gradle-plugin/issues/43
Expand All @@ -48,28 +46,16 @@ public open class VaadinCleanTask : DefaultTask() {

init {
group = "Vaadin"
description = "Cleans the project completely and removes 'generated' folders, node_modules, src/main/bundles/, webpack.generated.js, " +
"vite.generated.js, tsconfig.json, types.d.ts, pnpm-lock.yaml, pnpmfile.js, .pnpmfile.cjs and package-lock.json"
description = "Cleans the project completely and removes 'generated' folders, node_modules, src/main/bundles/, " +
"vite.generated.js, pnpm-lock.yaml, .pnpmfile.cjs and package-lock.json"

dependsOn("clean")
}

@TaskAction
public fun clean() {
project.delete(
config.generatedTsFolder,
config.frontendDirectory.get().resolve("generated").absolutePath,
"${project.projectDir}/node_modules",
"${project.projectDir}/${Constants.BUNDLE_LOCATION}",
"${project.projectDir}/src/main/dev-bundle/",
"${project.projectDir}/package-lock.json",
"${project.projectDir}/webpack.generated.js",
"${project.projectDir}/vite.generated.js",
"${project.projectDir}/.pnpmfile.cjs",
"${project.projectDir}/pnpm-lock.yaml", // used by Vaadin 14.2+ pnpm
"${project.projectDir}/pnpmfile.js", // used by Vaadin 14.2+ pnpm
"${project.projectDir}/tsconfig.json", // used by Vaadin 15+
"${project.projectDir}/types.d.ts" // used by Vaadin 15+
)
CleanFrontendUtil.runCleaning(
GradlePluginAdapter(project, config, false),
CleanOptions())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ public abstract class VaadinFlowPluginExtension {

public abstract val reactEnable: Property<Boolean>

public abstract val cleanFrontendFiles: Property<Boolean>

public fun filterClasspath(@DelegatesTo(value = ClasspathFilter::class, strategy = Closure.DELEGATE_FIRST) block: Closure<*>) {
block.delegate = classpathFilter
block.resolveStrategy = Closure.DELEGATE_FIRST
Expand Down Expand Up @@ -419,6 +421,8 @@ internal class PluginEffectiveConfiguration(
.convention(FrontendUtils.isReactRouterRequired(frontendDirectory.get()))
.overrideWithSystemProperty(InitParameters.REACT_ENABLE)

var cleanFrontendFiles: Property<Boolean> = extension.cleanFrontendFiles
.convention(true)
/**
* Finds the value of a boolean property. It searches in gradle and system properties.
*
Expand Down Expand Up @@ -466,7 +470,8 @@ internal class PluginEffectiveConfiguration(
"skipDevBundleBuild=${skipDevBundleBuild.get()}, " +
"alwaysExecutePrepareFrontend=${alwaysExecutePrepareFrontend.get()}, " +
"frontendHotdeploy=${frontendHotdeploy.get()}," +
"reactEnable=${reactEnable.get()}" +
"reactEnable=${reactEnable.get()}," +
"cleanFrontendFiles=${cleanFrontendFiles.get()}" +
")"
companion object {
internal fun get(project: Project): PluginEffectiveConfiguration =
Expand Down
Loading

0 comments on commit 2064933

Please sign in to comment.