groovy.com.cedarsolutions.gradle.CedarGwtOnGaePlugin.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cedar-build Show documentation
Show all versions of cedar-build Show documentation
Gradle plugins and other functionality for use with a standardized build process.
// vim: set ft=groovy ts=4 sw=4:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// *
// * C E D A R
// * S O L U T I O N S "Software done right."
// * S O F T W A R E
// *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// *
// * Copyright (c) 2013-2015 Kenneth J. Pronovici.
// * All rights reserved.
// *
// * This program is free software; you can redistribute it and/or
// * modify it under the terms of the Apache License, Version 2.0.
// * See LICENSE for more information about the licensing terms.
// *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// *
// * Author : Kenneth J. Pronovici
// * Language : Gradle (>= 2.5)
// * Project : Secret Santa Exchange
// *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package com.cedarsolutions.gradle
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.WarPlugin
import com.google.appengine.AppEnginePlugin
/**
* The cedarGwtOnGae plugin.
* @author Kenneth J. Pronovici
*/
class CedarGwtOnGaePlugin implements Plugin {
/** Apply the plugin. */
void apply(Project project) {
project.plugins.apply(JavaPlugin)
project.plugins.apply(WarPlugin)
project.plugins.apply(AppEnginePlugin)
project.extensions.create("cedarGwtOnGae", CedarGwtOnGaePluginExtension, project)
project.extensions.create("cedarCucumber", CedarCucumberPluginExtension, project)
project.convention.plugins.cedarGwtOnGae = new CedarGwtOnGaePluginConvention(project)
project.convention.plugins.cedarCucumber = new CedarCucumberPluginConvention(project)
applyCedarGwtOnGae(project)
applyCedarCucumber(project)
applyProjectTestSuites(project)
}
/** Apply cedarGwtOnGae. */
void applyCedarGwtOnGae(Project project) {
// We need to download the SDK before the classpath can be generated properly.
project.tasks.compileJava.dependsOn(project.tasks.appengineDownloadSdk)
// Tell the GAE plugin to download the SDK
project.convention.appengine.downloadSdk = true
// Set up the war plugin
project.webAppDirName = "war" // for some reason, I can't pull this out into cedarGwtOnGae configuration (?)
project.war {
// The gradle build should not get any of the files generated by Eclipse
excludes += [ "*.JUnit/**",
"*.JUnit",
"WEB-INF/deploy/**/*",
"WEB-INF/deploy",
"WEB-INF/classes/**/*",
"WEB-INF/classes",
"WEB-INF/lib/**/*",
"WEB-INF/lib",
"WEB-INF/appengine-generated/**/*",
"WEB-INF/appengine-generated", ]
}
// Compile GWT into the exploded war directory
project.task("buildApplication", dependsOn: project.tasks.appengineExplodeApp) << {
project.cedarGwtOnGae.validateGwtConfig()
def warDir = project.appengineExplodeApp.explodedAppDirectory.getPath()
def moduleDir = project.file(warDir + "/" + project.cedarGwtOnGae.getAppModuleName()).canonicalPath
def classesDir = project.file(warDir + "/WEB-INF/classes").canonicalPath
def libDir = project.file(warDir + "/WEB-INF/lib").canonicalPath
def compilerClass = "com.google.gwt.dev.Compiler"
project.file(moduleDir).deleteDir() // It's proved difficult to exclude this via project.war.excludes
// Run the GWT compiler
project.ant.java(classname : compilerClass, fork : "true", failonerror : "true") {
jvmarg(value: "-Xmx" + project.cedarGwtOnGae.getGwtCompilerMemory())
arg(value : "-war")
arg(value : warDir)
arg(value : project.cedarGwtOnGae.getAppEntryPoint())
classpath() {
pathelement(path: project.configurations.providedRuntime.asPath)
fileset(dir: libDir, includes : "*.jar")
pathelement(location: classesDir)
project.sourceSets.main.java.srcDirs.each { dir ->
pathelement(location: dir)
}
}
}
// Save off application Javascript so we can work around server boot behavior later
project.convention.plugins.cedarGwtOnGae.archiveApplicationJavascript()
}
// Start the development mode server
project.task("startDevmode") << {
project.convention.plugins.cedarGwtOnGae.bootDevmode()
}
// Stop the development mode server
project.task("stopDevmode") << {
project.convention.plugins.cedarGwtOnGae.killDevmode()
}
// Reboot the development mode server
project.task("rebootDevmode") << {
project.convention.plugins.cedarGwtOnGae.rebootDevmode()
}
}
/** Apply cedarCucumber. */
void applyCedarCucumber(Project project) {
// Install all of the Cucumber-related tooling
project.task("installCucumber") << {
project.convention.plugins.cedarCucumber.installCucumber()
}
// Uninstall all of the Cucumber-related tooling
project.task("uninstallCucumber") << {
project.convention.plugins.cedarCucumber.uninstallCucumber()
}
// Reinstall all of the Cucumber-related tooling
project.task("reinstallCucumber", dependsOn: [project.tasks.uninstallCucumber, project.tasks.installCucumber]) << {
}
// If they invoke both, uninstall and then reinstall
project.tasks.installCucumber.mustRunAfter project.tasks.uninstallCucumber
// Verify the configured cucumber install is ok.
project.task("verifyCucumber") << {
project.convention.plugins.cedarCucumber.verifyCucumberInstall()
}
// Run the Cucumber tests, assuming the devmode server is already up
// Note that you have to manually build the application and boot devmode for this to work
project.task("runCucumber", dependsOn: project.tasks.verifyCucumber) << {
project.convention.plugins.cedarCucumber.execCucumber("single-pass", null, null).assertNormalExitValue()
}
// Run the Cucumber tests, including a reboot of the server
// Note that you have to manually build the application for this to work
project.task("runCucumberWithReboot", dependsOn: project.tasks.verifyCucumber) << {
project.convention.plugins.cedarGwtOnGae.rebootDevmode()
project.convention.plugins.cedarCucumber.execCucumber("single-pass", null, null).assertNormalExitValue()
}
// Run the Cucumber tests, restricting by name containing a substring, assuming the devmode server is already up
// Note that you have to manually build the application and boot devmode for this to work
// This does not depend on verifyCucumber because that step is really slow with JRuby and this is a time-saving task.
project.task("runCucumberByName") << {
def name = null
project.convention.plugins.cedarBuild.getInput("Configure Cucumber", "Test Name", false, { input -> name = input})
project.convention.plugins.cedarCucumber.execCucumber("single-pass", name, null).assertNormalExitValue()
}
// Run the Cucumber tests for a specific feature file, assuming the devmode server is already up
// Note that you have to manually build the application and boot devmode for this to work
// This does not depend on verifyCucumber because that step is really slow with JRuby and this is a time-saving task.
project.task("runCucumberByFeature") << {
def feature = null
project.convention.plugins.cedarBuild.getInput("Configure Cucumber", "Feature Path", false, { input -> feature = input})
project.convention.plugins.cedarCucumber.execCucumber("single-pass", null, feature).assertNormalExitValue()
}
}
/** Apply projectTestSuites. */
void applyProjectTestSuites(Project project) {
// Run unit tests, assumed to be found in a class suites/UnitTestSuite.
// The caller that applies this plugin still has responsibility for making sure the suite gets compiled.
project.task("unittest", type: com.cedarsolutions.gradle.TestTask) {
// these configuration values are set when the task is created
workingDir = project.projectDir
scanForTestClasses = false
enableAssertions = false
outputs.upToDateWhen { false }
include "suites/UnitTestSuite.class"
// these configuration values are set immediately before the test is executed
deferredConfig {
// Note: it's important to add onto the JVM args rather than replace them.
// Otherwise, important arguments like the Jacoco coverage agent don't get included as expected.
setMaxHeapSize(project.cedarGwtOnGae.getUnitTestMemory())
setJvmArgs(getJvmArgs() + [ "-XX:MaxPermSize=" + project.cedarGwtOnGae.getUnitTestPermgen(), ])
}
}
// Run GWT client tests, assumed to be found in a class suites/ClientTestSuite.
// The caller that applies this plugin still has responsibility for making sure the suite gets compiled.
project.task("clienttest", type: com.cedarsolutions.gradle.TestTask) {
// these configuration values are set when the task is created
workingDir = project.projectDir
scanForTestClasses = false
scanForTestClasses = false
enableAssertions = false
outputs.upToDateWhen { false }
systemProperty "gwt.args", "-out www-test -logLevel ERROR"
systemProperty "java.awt.headless", "true" // required on Linux to avoid deferred binding errors
include "suites/ClientTestSuite.class"
// these configuration values are set immediately before the test is executed
deferredConfig {
// Here, we *do* replace the JVM args, because this is apparently the only way
// to disable Jacoco on a test task. Replacing the JVM arguments discards
// the -javaagent that Gradle adds into the list. This is a big hammer approach,
// but it's clear from looking at the Gradle code that there's no way to configure
// the plugin to run for some test tasks and ignore others. Poor design.
setMaxHeapSize(project.cedarGwtOnGae.getClientTestMemory())
setJvmArgs([ "-XX:MaxPermSize=" + project.cedarGwtOnGae.getClientTestPermgen(), ])
}
// delete the cache directories before running the suite
beforeSuite { descriptor ->
if (descriptor.className == "suites.ClientTestSuite") {
def wwwTest = project.file(workingDir.canonicalPath + "/www-test")
def gwtCache = project.file(workingDir.canonicalPath + "/gwt-unitCache")
wwwTest.deleteDir()
gwtCache.deleteDir()
}
}
// delete the cache directories after running the suite
afterSuite { descriptor ->
if (descriptor.className == "suites.ClientTestSuite") {
def wwwTest = project.file(workingDir.canonicalPath + "/www-test")
def gwtCache = project.file(workingDir.canonicalPath + "/gwt-unitCache")
wwwTest.deleteDir()
gwtCache.deleteDir()
}
}
}
// Run the acceptance tests, including a build of the application
project.task("acceptancetest", dependsOn: [ project.tasks.buildApplication, project.tasks.verifyCucumber ]) << {
// This runs Cucumber in a two-pass mode: the first pass runs all
// of the tests and builds a list of the ones that failed, and the
// second pass re-runs only the failed tests. This is designed to
// deal a little more robustly with the intermittent, non-deterministic
// test failures that pop-up with some regularity as the test suite
// gets larger.
//
// This is not a perfect solution. Arguably, we'd rather have an
// explanation for why the tests fail in the first place. However,
// since the acceptance test suite is mostly supposed to be a smoke
// test, we're going to live with it. The goal with these tests is
// to give us some confidence that the application is pretty much
// working, and that goal is better served by ignoring tests that
// work on retry vs. being overly noisly about failures that
// "magically" go away when someone tries them again.
// First pass
project.convention.plugins.cedarGwtOnGae.rebootDevmode()
project.convention.plugins.cedarCucumber.execCucumber("first-pass", null, null)
// Second pass
project.convention.plugins.cedarGwtOnGae.rebootDevmode()
def result = project.convention.plugins.cedarCucumber.execCucumber("second-pass", null, null)
project.convention.plugins.cedarGwtOnGae.killDevmode()
result.assertNormalExitValue()
}
// Effectively disable the standard test runner by making it look for a bogus class.
project.tasks.test.include("**/bogus.class")
// Redefine the test runner in terms of the unit and client test suites.
project.tasks.test.dependsOn(project.tasks.clienttest, project.tasks.unittest)
// Define the order of tests if there are multiple called at the same time
project.tasks.clienttest.mustRunAfter project.tasks.unittest
project.tasks.acceptancetest.mustRunAfter project.tasks.clienttest
// Define a task that runs all of the tests
project.task("alltest", dependsOn: [ project.tasks.unittest, project.tasks.clienttest, project.tasks.acceptancetest ]);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy