Skip to content

Commit

Permalink
Add skip install feature (#825)
Browse files Browse the repository at this point in the history
* Add support for skip install feature for dev mode

* Use latest common snapshot

* Add more exclude tasks

* Fix test

* More test fixes

* One code fix and correct formatting

* Add comments and fix task exclusions

* Remove yaml changes and one code change

* attempt to fix test case timing issue
  • Loading branch information
cherylking authored Aug 21, 2023
1 parent 96ec0a0 commit 0f51fc5
Show file tree
Hide file tree
Showing 16 changed files with 371 additions and 46 deletions.
1 change: 1 addition & 0 deletions docs/libertyDev.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ The following are optional command line parameters supported by this task.
| serverStartTimeout | Maximum time to wait (in seconds) to verify that the server has started. The value must be an integer greater than or equal to 0. The default value is `90` seconds. | No |
| verifyAppStartTimeout | Maximum time to wait (in seconds) to verify that the application has started or updated before running tests. The value must be an integer greater than or equal to 0. The default value is `30` seconds. | No |
| generateFeatures | If set to `true`, when a Java file, server configuration file, or build file is changed, generate features required by the application in the source configuration directory. The default value is `false`. | No |
| skipInstallFeature | If set to `true`, the `installFeature` task will be skipped when `dev` mode is started on an already existing Liberty runtime installation. It will also be skipped when `dev` mode is running and a restart of the server is triggered either directly by the user or by application changes. The `installFeature` task will be invoked though when `dev` mode is running and a change to the configured features is detected. The default value is `false`. | No |

### Properties

Expand Down
88 changes: 77 additions & 11 deletions src/main/groovy/io/openliberty/tools/gradle/tasks/DevTask.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class DevTask extends AbstractFeatureTask {
private static final boolean DEFAULT_SKIP_DEFAULT_PORTS = false;
private static final boolean DEFAULT_KEEP_TEMP_DOCKERFILE = false;
private static final boolean DEFAULT_GENERATE_FEATURES = false;
private static final boolean DEFAULT_SKIP_INSTALL_FEATURE = false;

// Debug port for BuildLauncher tasks launched from DevTask as parent JVM
// (parent defaults to '5005')
Expand Down Expand Up @@ -267,11 +268,21 @@ class DevTask extends AbstractFeatureTask {
@Input
Boolean generateFeatures;

// Need to use a string value to allow someone to specify --generateFeatures=false, if not explicitly set defaults to true
@Option(option = 'generateFeatures', description = 'If true, scan the application binary files to determine which Liberty features should be used. The default value is false.')
void setGenerateFeatures(String generateFeatures) {
this.generateFeatures = Boolean.parseBoolean(generateFeatures);
}
// Need to use a string value to allow someone to specify --generateFeatures=false, if not explicitly set defaults to true
@Option(option = 'generateFeatures', description = 'If true, scan the application binary files to determine which Liberty features should be used. The default value is false.')
void setGenerateFeatures(String generateFeatures) {
this.generateFeatures = Boolean.parseBoolean(generateFeatures);
}

@Optional
@Input
Boolean skipInstallFeature;

// Need to use a string value to allow someone to specify --skipInstallFeature=true, if not explicitly set defaults to false
@Option(option = 'skipInstallFeature', description = 'If set to true, the installFeature task will be skipped when dev mode is started on an already existing Liberty runtime installation. It will also be skipped when dev mode is running and a restart of the server is triggered either directly by the user or by application changes. The installFeature task will be invoked though when dev mode is running and a change to the configured features is detected. The default value is false.')
void setSkipInstallFeature(String skipInstallFeature) {
this.skipInstallFeature = Boolean.parseBoolean(skipInstallFeature);
}

@Optional
@Input
Expand Down Expand Up @@ -302,14 +313,14 @@ class DevTask extends AbstractFeatureTask {

DevTaskUtil(File buildDir, File installDirectory, File userDirectory, File serverDirectory, File sourceDirectory, File testSourceDirectory,
File configDirectory, File projectDirectory, List<File> resourceDirs,
boolean hotTests, boolean skipTests, String artifactId, int serverStartTimeout,
boolean hotTests, boolean skipTests, boolean skipInstallFeature, String artifactId, int serverStartTimeout,
int verifyAppStartTimeout, int appUpdateTimeout, double compileWait,
boolean libertyDebug, boolean pollingTest, boolean container, File dockerfile, File dockerBuildContext,
String dockerRunOpts, int dockerBuildTimeout, boolean skipDefaultPorts, boolean keepTempDockerfile,
String mavenCacheLocation, String packagingType, File buildFile, boolean generateFeatures
) throws IOException {
super(buildDir, serverDirectory, sourceDirectory, testSourceDirectory, configDirectory, projectDirectory, /* multi module project directory */ projectDirectory,
resourceDirs, hotTests, skipTests, false /* skipUTs */, false /* skipITs */, artifactId, serverStartTimeout,
resourceDirs, hotTests, skipTests, false /* skipUTs */, false /* skipITs */, skipInstallFeature, artifactId, serverStartTimeout,
verifyAppStartTimeout, appUpdateTimeout, ((long) (compileWait * 1000L)), libertyDebug,
true /* useBuildRecompile */, true /* gradle */, pollingTest, container, dockerfile, dockerBuildContext, dockerRunOpts, dockerBuildTimeout, skipDefaultPorts,
null /* compileOptions not needed since useBuildRecompile is true */, keepTempDockerfile, mavenCacheLocation, null /* multi module upstream projects */,
Expand Down Expand Up @@ -842,6 +853,10 @@ class DevTask extends AbstractFeatureTask {
if (container) {
gradleBuildLauncher.addArguments(CONTAINER_PROPERTY_ARG);
}
if (skipInstallFeature) {
gradleBuildLauncher.addArguments("--exclude-task", "libertyCreate"); // deploy dependsOn libertyCreate which is finalizedBy installFeature
gradleBuildLauncher.addArguments("--exclude-task", "installFeature");
}
runGradleTask(gradleBuildLauncher, 'deploy');
} catch (BuildException e) {
throw new PluginExecutionException(e);
Expand Down Expand Up @@ -897,6 +912,10 @@ class DevTask extends AbstractFeatureTask {
}
}

/**
* This method is only called from DevUtil.restartServer() which explicitly calls libertyCreate() before calling this method. We need to explicitly
* exclude the libertyCreate task.
**/
@Override
public void libertyDeploy() {
ProjectConnection gradleConnection = initGradleProjectConnection();
Expand All @@ -907,6 +926,9 @@ class DevTask extends AbstractFeatureTask {
// Skip installFeature since it is not needed here in container mode.
// Container mode should call installFeature separately with the containerName parameter where needed.
gradleBuildLauncher.addArguments("--exclude-task", "installFeature");
} else if (skipInstallFeature) {
gradleBuildLauncher.addArguments("--exclude-task", "libertyCreate"); // deploy dependsOn libertyCreate which is finalizedBy installFeature
gradleBuildLauncher.addArguments("--exclude-task", "installFeature");
}
runGradleTask(gradleBuildLauncher, 'deploy');
} catch (BuildException e) {
Expand All @@ -916,6 +938,10 @@ class DevTask extends AbstractFeatureTask {
}
}

/*
* This method is only called from common DevUtil.restartServer() method. The installLiberty task should not need to be called, and must be
* explicitly excluded since libertyCreate dependsOn installLiberty.
*/
@Override
public void libertyCreate() {
if (container) {
Expand All @@ -928,6 +954,10 @@ class DevTask extends AbstractFeatureTask {

gradleBuildLauncher.addArguments('--rerun-tasks');
addLibertyRuntimeProperties(gradleBuildLauncher);
gradleBuildLauncher.addArguments("--exclude-task", "installLiberty");
if (skipInstallFeature) {
gradleBuildLauncher.addArguments("--exclude-task", "installFeature");
}
try {
runGradleTask(gradleBuildLauncher, 'libertyCreate');
} catch (BuildException e) {
Expand Down Expand Up @@ -1042,6 +1072,10 @@ class DevTask extends AbstractFeatureTask {
generateFeatures = DEFAULT_GENERATE_FEATURES;
}

if (skipInstallFeature == null) {
skipInstallFeature = DEFAULT_SKIP_INSTALL_FEATURE;
}

processContainerParams();
}

Expand Down Expand Up @@ -1097,7 +1131,7 @@ class DevTask extends AbstractFeatureTask {
// Instantiate util before any child gradle tasks launched so it can help find available port if needed
this.util = new DevTaskUtil(project.buildDir, serverInstallDir, getUserDir(project, serverInstallDir),
serverDirectory, sourceDirectory, testSourceDirectory, configDirectory, project.getRootDir(),
resourceDirs, hotTests.booleanValue(), skipTests.booleanValue(), artifactId, serverStartTimeout.intValue(),
resourceDirs, hotTests.booleanValue(), skipTests.booleanValue(), skipInstallFeature.booleanValue(), artifactId, serverStartTimeout.intValue(),
verifyAppStartTimeout.intValue(), verifyAppStartTimeout.intValue(), compileWait.doubleValue(),
libertyDebug.booleanValue(), pollingTest.booleanValue(), container.booleanValue(), dockerfile, dockerBuildContext, dockerRunOpts,
dockerBuildTimeout, skipDefaultPorts.booleanValue(), keepTempDockerfile.booleanValue(), localMavenRepoForFeatureUtility,
Expand Down Expand Up @@ -1150,11 +1184,43 @@ class DevTask extends AbstractFeatureTask {
}
}
if (!container) {
boolean isNewInstallation = true;
// Check to see if Liberty was already installed and set flag accordingly.
if (serverInstallDir != null) {
try {
File installDirectoryCanonicalFile = serverInstallDir.getCanonicalFile();
// Quick check to see if a Liberty installation exists at the installDirectory
File file = new File(installDirectoryCanonicalFile, "lib/ws-launch.jar");
if (file.exists()) {
isNewInstallation = false;
logger.info("Dev mode is using an existing installation.");
}
} catch (IOException e) {
}
}

// if skipInstallFeature is set to true, skip installFeature task unless it is a new installation
if (skipInstallFeature) {
logger.debug("skipInstallFeature flag is set to true");
}

if (!isNewInstallation) {
logger.info("Skipping installLiberty task for existing installation.")
// will this cause an issue when changing the runtime? Customer would be forced to cleanup first?
gradleBuildLauncher.addArguments("--exclude-task", "installLiberty"); // skip installing Liberty at startup since it was already installed
if (skipInstallFeature) {
logger.info("Skipping installFeature task due to skipInstallFeature configuration.")
gradleBuildLauncher.addArguments("--exclude-task", "installFeature"); // skip installing features at startup since flag was set
}
}
addLibertyRuntimeProperties(gradleBuildLauncher);
runGradleTask(gradleBuildLauncher, 'libertyCreate');
// suppress extra install feature warnings (one would have shown up already from the libertyCreate task on the line above)
gradleBuildLauncher.addArguments("-D" + DevUtil.SKIP_BETA_INSTALL_WARNING + "=" + Boolean.TRUE.toString());
runInstallFeatureTask(gradleBuildLauncher, null);

if (!skipInstallFeature || isNewInstallation) {
// suppress extra install feature warnings (one would have shown up already from the libertyCreate task on the line above)
gradleBuildLauncher.addArguments("-D" + DevUtil.SKIP_BETA_INSTALL_WARNING + "=" + Boolean.TRUE.toString());
runInstallFeatureTask(gradleBuildLauncher, null);
}
} else {
// skip creating the server and installing features and just propagate the option to 'deploy'
createServerDirectories();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class InstallLibertyTask extends AbstractLibertyTask {
protected String detachedCoords
protected String detachedConfigFilePath
// default to install the latest Open Liberty kernel from Maven Central repository
protected String defaultRuntime = "io.openliberty:openliberty-kernel:[19.0.0.9,)"
protected String defaultRuntime = "io.openliberty:openliberty-kernel:[23.0.0.3,)"

InstallLibertyTask() {
configure({
Expand Down
48 changes: 28 additions & 20 deletions src/test/groovy/io/openliberty/tools/gradle/BaseDevTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@ import java.nio.file.Files;
import java.nio.file.Path;

class BaseDevTest extends AbstractIntegrationTest {
static final String projectName = "basic-dev-project";

static File resourceDir = new File("build/resources/test/dev-test/" + projectName);
static File buildDir = new File(integTestDir, "dev-test/" + projectName + System.currentTimeMillis()); // append timestamp in case previous build was not deleted
static File buildDir;
static String buildFilename = "build.gradle";
final String RUNNING_INSTALL_FEATURE = "Task :installFeature";
final String RUNNING_GENERATE_FEATURES = "Task :generateFeatures";
final String REGENERATE_FEATURES = "Regenerated the following features:";
final String GENERATE_FEATURES = "Generated the following features:";
Expand All @@ -56,13 +54,22 @@ class BaseDevTest extends AbstractIntegrationTest {
// the correct file. Use logFile for "compilation was successful"
// and errFile for "compilation had errors" or Liberty messages like
// "CWWKF0011I" or "The server installed the following features".
static File logFile = new File(buildDir, "output.log");
static File errFile = new File(buildDir, "stderr.log");
static File logFile;
static File errFile;

static Process process;

protected static void runDevMode() throws IOException, InterruptedException, FileNotFoundException {
System.out.println("Starting dev mode...");
startProcess("--generateFeatures=true", true);
protected static void runDevMode(File buildDirectory) throws IOException, InterruptedException, FileNotFoundException {
runDevMode("--generateFeatures=true", buildDirectory)
}

protected static void runDevMode(String params, File buildDirectory) throws IOException, InterruptedException, FileNotFoundException {
buildDir = buildDirectory;
logFile = new File(buildDir, "output.log");
errFile = new File(buildDir, "stderr.log");

System.out.println("Starting dev mode with params..."+params);
startProcess(params, true);
System.out.println("Started dev mode");
}

Expand Down Expand Up @@ -145,13 +152,18 @@ class BaseDevTest extends AbstractIntegrationTest {
throws InterruptedException, FileNotFoundException {
int waited = 0;
int sleep = 10;
int foundOccurrences = 0;
while (waited <= timeout) {
Thread.sleep(sleep);
waited += sleep;
if (countOccurrences(message, file) == occurrences) {
foundOccurrences = countOccurrences(message, file)
if (foundOccurrences == occurrences) {
return true;
}
}

System.out.println("Log message found "+foundOccurrences+" times, expected to find it "+occurrences+" times.");

return false;
}

Expand Down Expand Up @@ -200,7 +212,7 @@ class BaseDevTest extends AbstractIntegrationTest {
// a file has been changed between two instants of time. The problem is that the
// method has a resolution of just 2000ms on Windows FAT and 1000ms on MacOS HFS+.
protected static void waitLongEnough() throws InterruptedException {
Thread.sleep(2001);
Thread.sleep(3001); // make sure we wait long enough
}

private static boolean readFile(String str, File file) throws FileNotFoundException {
Expand Down Expand Up @@ -269,15 +281,8 @@ class BaseDevTest extends AbstractIntegrationTest {
protected static void cleanUpAfterClass(boolean isDevMode) throws Exception {
stopProcess(isDevMode);
if (buildDir != null && buildDir.exists()) {
// FileUtils.deleteDirectory(buildDir);
FileUtils.deleteQuietly(buildDir); // try this method that does not throw an exception
}
if (logFile != null && logFile.exists()) {
assertTrue(logFile.delete());
}
if (errFile != null && errFile.exists()) {
assertTrue(errFile.delete());
}
}

private static void stopProcess(boolean isDevMode) throws IOException, InterruptedException, FileNotFoundException {
Expand All @@ -289,8 +294,11 @@ class BaseDevTest extends AbstractIntegrationTest {
} else {
process.destroy(); // stop run
}
writer.flush();
writer.close();
try {
writer.close(); // close automatically does a flush
} catch (IOException e) {
System.out.println("Received IOException on writer.close()" + e.getMessage());
}

// test that dev mode has stopped running
assertTrue(verifyLogMessage(100000, "CWWKE0036I", errFile, ++serverStoppedOccurrences));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ import java.nio.file.Files;
import java.nio.file.Path;

class DevRecompileTest extends BaseDevTest {
static final String projectName = "basic-dev-project";

static File resourceDir = new File("build/resources/test/dev-test/" + projectName);
static File buildDir = new File(integTestDir, "dev-test/" + projectName + System.currentTimeMillis()); // append timestamp in case previous build was not deleted

@BeforeClass
public static void setup() throws IOException, InterruptedException, FileNotFoundException {
createDir(buildDir);
createTestProject(buildDir, resourceDir, buildFilename);
runDevMode();
runDevMode(buildDir);
}

@Test
Expand Down
Loading

0 comments on commit 0f51fc5

Please sign in to comment.