DEV-NOTES|Gradle: Reading Eclipses codeformatter xml file

This little code snippet transforms the code formatter XML description file into a properties structure which could be applied to the JDT properties later on.

def initializeFormatter() {
  def formatterDefinitions = new XmlSlurper.parse("$rootDir/misc/codeformatter.xml")
  assert formatterDefinitions instanceof GPathResult

  def Properties props = new Properties()

  formatterDefinitions.'**'.findAll{ node ->
    node.name() == 'setting'
  }*.each { n ->
    props.put(n.@id.text(), n.@value.text()
  }

  return props
}

DEV-NOTES|Gradle: Injecting project version and Jenkins build number into project resources

Gradles project model provides a consistent way of expressing a version of an artifact. The following task uses the version number and makes it accessible to application code. Furthermore it adds the number of the build given by the Jenkins CI server.

/**
 * Read the version number from gradle (multi-) project definition
 * and add the build number from Jenkins-ci if available, otherwise use "IDE"
 */
task injectVersion << {
    def lineSep = System.getProperty("line.separator", "n")

    def file = file("$sourceSets.main.output.resourcesDir/version.properties")
    file.newWriter().withWriter { w ->
        w << "version=" << rootProject.version << lineSep
        w << "buildNumber=" << (System.getenv("BUILD_NUMBER") as String ?: "IDE") << lineSep
    }
}

// the inject version task requires the output folders to be already created
injectVersion.mustRunAfter processResources

// the version properties file have to be added to the classpath resource
classes.dependsOn injectVersion

It is worth to notice that the inject version task relies on the existence of the resource output directory from the „main“ source set. Therefore it is not allowed to run before the processResources has been completed and it depends on the classes task.

Someone might consider extending the processResources task putting the version.properties file creation into the doLast step like:

processResources.doLast {
    def lineSep = System.getProperty("line.separator", "n")

    def file = file("$sourceSets.main.output.resourcesDir/version.properties")
   file.newWriter().withWriter { w ->
        w << "version=" << rootProject.version << lineSep
        w << "buildNumber=" << (System.getenv("BUILD_NUMBER") as String ?: "IDE") << lineSep
    }
}

This works well except for changing numbers without cleaning, because gradle could not decide whether the build number has changed or is still unchanged during its configuration phase.


References

DEV-NOTES|Gradle: Use gradle wrapper with self-signed / organization local certificates

Automated provisioning of the required build environment is one of the great promises by gradle. Using gradle wrapper allows the rapid workspace setup for a new developer or on a new machine.

In organizations there are sometimes restrictions in accessing public networks and it local hosting becomes inevitable. The actual example is based on the idea hosting the gradle distribution inside the local document management system which is accessible using https only.

# gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

distributionUrl=https://provisioning-url/gradle-2.2-bin.zip

Unfortunately the server identity is assured by a self-signed resp. signed by a local authority certificate. Running the gradle wrapper screws up yielding the following exception:

&lt;br /&gt;&gt; gradlew tasks
Downloading https://provisioning-url/gradle-2.2-bin.zip

Exception in thread &quot;main&quot; java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:78)
        at org.gradle.wrapper.Install.createDist(Install.java:44)
        at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:126)
        at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:58)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
        at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java
:185)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1300)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
        at org.gradle.wrapper.Download.downloadInternal(Download.java:56)
        at org.gradle.wrapper.Download.download(Download.java:42)
        at org.gradle.wrapper.Install$1.call(Install.java:57)
        at org.gradle.wrapper.Install$1.call(Install.java:44)
        at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:65)
        ... 3 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
        at sun.security.validator.Validator.validate(Validator.java:260)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323)
        ... 19 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
        ... 25 more

The problem is that the HTTPS connection could not be validated because there is no trusted certificate for the provisioning url available.

The solution is to enhance the truststore with the certificate or the authority used in the provisioning url:

#create or copy an existing truststore eq. form jdk
&gt; cp $JAVA_HOME/jre/lib/security/cacerts certs.jks
# import your certifiact into certs.jks
&gt; keytool -importcert -file self-signed.pem -keystore certs.jks

and tell gradlew to use this truststore instead of the original one. Gradles behavior can be adjusted by modifying the gradle.properties file in the root directory of your gradle project (for more information see „The Build Environment“ from the user guide).

# gradle.properties
systemProp.javax.net.ssl.trustStore=certs.jks
# could set password as well
# javax.net.ssl.trustStorePassword=changeit

Calling gradlew again should kick off downloading the gradle distribution and running your tasks like a charm.


Update 27/10/2016

Changed password property to match the truststore. Thanks to Thomas for his advice.

Deliver code coverage indices for Scala using Gradle and SCCT

This post is a kind of follow up post to Gradle rocking Scala Specs2 tests. After setting up the build supporting Specs2 tests we could take it a step further to provide information about the code coverage of the tests.

SCCT is a code coverage tool for Scala. One benefit of SCCT is that the output format is compliant, to the widely known Cobertura so it could easily integrated into Jenkins for example. „Deliver code coverage indices for Scala using Gradle and SCCT“ weiterlesen

Gradle rocking scala specs2 tests

In preparation of the upcoming Coursera course „Reactive Programming“ I just want to refresh my Scala skills by porting the Coursera Downloader from Python to Scala.

Setting up the initial build with Gradle is quite easy using the Scala Plugin. Looking around for some testing framework I have chosen Specs2 . Running Gradle after building some simple unit tests shows up that the tests are not executed at all. The build passes without running one single tests. Even declaring the tests to be processed by a JUnit4 runner did not want show up a single tests result. So I came up with the following simple solution. I add a new specs2 task to my Gradle build using the specs2 file runner:

/**
 * Run Spec2 tests
 */
task specs(type: JavaExec, dependsOn: testClasses) {
    main = 'org.specs2.files'
    args = ['console']
    classpath sourceSets.main.runtimeClasspath
    classpath sourceSets.test.runtimeClasspath
    classpath configurations.testRuntime
    classpath configurations.runtime
}

The file runner will select all files matching .*Spec in the test source directory which default (src/test/scala) nicely conforms the default project setup. If necessary it could be adjusted by setting the specs2.srcTestDir system property. For more information on the Specs2 Runners refer to the Specs2 documentation.

Now you have only to hook in the test step execution which could be easily achieved by extending the test task to depend on the specs2 tasks as well:

/*
 * and  add them to the default test set
 */
test.dependsOn specs

Running the test target of the Gradle build once again shows up the execution of the specs2 target and all tests and specifications.

Update(09/04/2014)

Marino Borra points out that he could run the specs tests successfully with the default gradle test task by simply adding the @RunWith(classOf[JUnitRunner]) annotation.