Gradle Effective Implementation Guide Review
 
Maybe it’s just the Kindle version, but none of the tables/source code figures have reference numbers (like Table 2, Figure 8, etc.) associated with them, so it is difficult to reference them.
 
Chapter 1
Default Gradle tasks:
“We haven’t defined any property ourselves in the build script…” -> properties
 
Task name abbreviation:
“In our first build we only have one task, so the command gradleh should …” -> gradle h
Got lumped together as a single word
 
Changing the build file and directory:
“hello-world $ gradle --build-file -q helloWorld” -> gradle --build-file hello.build -q helloWorld
The name of the hello.build file is missing from the command line
 
Gradle daemon:
Does not mention use of gradle.properties for a project or for a user to be able to set the daemon property value.  Maybe it will be referenced later, but it doesn’t show up now as even an option.  There are issues with doing it as part of the project properties (such as not wanting the CI build to run it that way), but setting it as part of the user’s gradle.properties is often valid.
 
Task Tree:
“The Filter button…”  “The Toggle filter button…”
There is no image reference that points directly to these buttons.  A small image showing the tooltip help displayed would be very useful at this point.
 
Setup:
“…Debug, Info, Lifecycle, and Error…”  The Error log level…”
There is no error log level selectable.  Just the Quiet level.
 
Chapter 2
Writing a build script:
The first example with project.description is simple to follow, but the second example might cause confusion as it says you can leave out the project variable, but then it is used as project.getDescription()  because of the use within the task closure which now delegates to the task object first.  This might be the place to introduce GStrings for Groovy string usage of “${project.description}” instead (or call out the scoping of default references, so it is clear that within a task block, the implicit Task object is used to resolve properties)
 
Since the next sectionDefining tasks” has examples with with GStrings, and no explanations about what that really means, it would be useful to have a concrete example spelled out either in chapter 1 or at the beginning of chapter 2.  The GString information found in the “Build scripts are Groovy code” is probably the part that could be easily moved to the beginning of the chapter.
 
Build scripts are Groovy code:
“This means we can use all the Groovy’s…”  -> of
 
Grouping tasks together:
“A task group is a set of tasks tha belong…” -> that
 
Using task rules:
“But we can ao define…” -> also
 
Adding additional properties to tasks:
Simple.message -> simple.ext.message
This makes use of the deprecated dynamic properties pattern, instead of using the .ext notation for ExtraPropertiesExtension.
 
Skipping tasks that are up-to-date:
Might be some confusion on inputs.property ‘version’, project.version and how inputs.files ‘input/input1.xml’, ‘input/input2.xml’ is used later since there hasn’t been any discussion on how Groovy handles method arguments, since the signatures of the property() and files() methods aren’t explicitly listed.
 
Chapter 3
Locating files:
“We can use closure to define the file or directory” -> “…can use a closure…”
 
Very nice on the PathValidation.  I’ve never actually utilized that capability.
 
Using file collections:
Comment for ‘filterFiles’ task has “// Filter for files smaller than 5KB”, but the actual operation is checking to see if the file ends with ‘txt’.  The final comment “// smallFiles now contains 2 files:”  also would need to be fixed, as only ‘INSTALL.txt’ should be part of the collection.  Of course, the collection probably shouldn’t be called smallFiles any more.
 
Working with file trees:
“def projectFiles = fileTree()”
Using Gradle 1.1 and Gradle 1.2, results in an exception, as it is trying to match FileOperations#fileTree(Closure), #fileTree(Object), #fileTree(Map), or #fileTree(Object, Closure).  There either never has been, or no longer is, a no-argument method for fileTree.  Also, the closure only method is deprecated.  fileTree(file(‘.’)) might be what is desired.
 
Archiving files:
Could also in this section mention the archivesBaseName project property that affects the baseName of all archives for a project unless explicitly overridden.
 
Defining custom properties in script:
It seems that custom should have printed out three times in the “gradle sP” show properties output.
 
Using logging:
Logging level table has “Import information messages” -> Important?
 
Might be a good place to mention that even though “quiet” is technically not an error, it will get logged when the --quiet level is specified on the gradle command line.  Confusing, since the help output says the -q flag will “Log errors only.”
 
 
Chapter 4
Creating a new source set:
There is a table with many of the properties, but unexpectedly, compileClasspath and runtimeClasspath are absent, and then compileClasspath is used as part of a later example.
 
Combined with the clean<Pattern> and classes, people might be surprised that cleanClasses never really does anything since compileJava and compileApiJava really “own” the generated classes.
 
Setting the main compileClasspath might be a good place to mention that compileClasspath being a FileCollection can add or remove other FileCollections, which can be obtained via Project.files()
 
Good example with ‘integration-test’ having to be in quotes.
 
Working with properties:
JavaVersion.VERSION_1_6 is a Gradle-specific thing, but it is not mentioned as such anywhere.
 
Assembling archives:
I’m not sure of the proper answer, but for something like ‘api’, it seems like classifier = ‘api’ might be considered another viable approach for adjusting the name of a constructed jar, although in this case, since it’s supposed to be a different module, appendix is probably correct.  Both appendix and classifier are part of the AbstractArchiveTask class.
 
The last example shows jar tvf build/libs/sample-api.jar, but just before that, it refers to the file now being named gradle-sample-api-1.0.jar.  Now, without a clean in between, both would still live there, but it’s a little confusing.
 
Chapter 5
Dependency configuration:
Probably should spell out the four configurations explicitly, as people might not realize that archives and default are added as part of the “base” plugin.
 
Adding Maven repositories:
Technically the maven pattern includes an optional (-[classifier]) after revision.
 
“and use those properties in our build fil:” -> file:
 
Adding Ivy repositories:
The last example adds the same artifactPattern twice.  Not sure if that was desired, or if one was supposed to be different, to just show how you add multiple patterns.
 
Adding a local directory repository:
This is a special case where just using “../something” actually works, because the directories are explicitly evaluated as Project.files(), but that should probably be mentioned to the reader, since everywhere else the pattern is to apply file() or files() before assigning a directory or file, because it will not be relative to the project directory otherwise.
 
Using external module dependencies:
If there isn’t a desire to add variables to the project explicitly, users can just use def springVersion = ‘’ and def springGroup = ‘’, since that also is still allowed, and keeps the scope local.
 
“We must also use this notation when a repository doesn’t have a module descriptor file and we want to get the artifact.  We must add an @ symbol before the extension of the artifact.”  This is not quite correct, as it will prefer to find the descriptor file (ivy or maven), but it will still directly grab the artifact if it can find it.
 
“In the following sample build file, we set the transitive property on the runtime configuration”.  Then the example uses “configurations.compile.transitive = false”.
 
Adding optional ANT tasks:
“…and use the optional ANT tak.” -> task
 
System.console() still does not work with the gradle daemon running, so this might be a good place for a potential warning, and mention to use --no-daemon until sometime in the future when it works as expected.
 
Chapter 6
Testing:
While the correct code is utilized within the book, if someone was attempting to follow and still had the api with ReadWelcomeMessage interface, the tests would have failed because it wasn’t part of the test runtime classpath.
 
Using TestNG for testing:
Might be valuable to explain to reader that junit is only left as a compile dependency because of the previous junit code, otherwise there would not be any need for it.
 
Logging test output:
testLogging.exceptionFormat ‘full’ is so incredibly useful, and possibly should be considered for the default in the future.
 
Running an application as task:
main = ‘gradle.sample.SampleApp’
classpath sourceSets.main.runtimeClasspath
This might be a good opportunity to explain that the first one is setting a property, and the second on is adding something to a property.  People get very confused as to when they should use ‘=’ versus not.
 
Uploading to a Maven repository:
That ‘file:./maven’ directory is relative to wherever gradle is invoked, and is likely not the intended effect.  It should either be an absolute path, or probably generated from file().
 
For the scp example there is the configuration = configurations.mavenScp line.  Digging through the javadoc and groovydoc, DSL, and the user guide, there is exactly one example of that field, int Example 46.4 Upload of file via SSH.  It is good that there is another example in this book.
 
Multiple artifacts:
Another one of those cases where sometimes it will auto-wire up the dependencies and other times not.  Maybe there is some easy to follow convention to figure out when that will happen.
 
Signing artifacts:
The signing plugin is interesting, in that unless there is a signing {} block in the build file, it does not actually add any tasks.  This can be confusing if someone just applies the plugin and then runs gradle tasks --all.
 
The $gradle signArchives output clearly shows that :jar comes before :signArchives, so the preceding statement “We can invoke the signArchives tasks to sign our JAR artifact or use the jar task, which is automatically dependent on the signArchives task” seems contradictory.
 
Using the War plugin:
Good to mention that the jar file not built by default, but there are many use cases where producing a jar and a war are needed, so might have wished to show how that is done.  Granted that causes issues when applying the ear plugin, but that could addressed as well in the book.
 
Chapter 7
Executing tasks by project path:
How a settings.gradle file is found is based upon what is in the Gradle User Guide, but it is missing the predicate “If you execute Gradle from within a project that has no settings.gradle file, Gradle does the following”.  Both would probably be easier to understand if the first step was stated simply to look for a settings.gradle in the current directory, and then apply the following four steps as usual.
 
Step 3 is either missing the “If no settings.gradle” or “If settings.gradle is not found”, as right now it states that if a settings.gradle is found, that it will run a single project build.
 
Definining projects:
“master maki $” and just “$” are used for command prompts, where in the previous multi-project examples, it is always  the current directory preceding the $.
 
Filtering projects:
afterEvaluate() is definitely one of the least understood capabilities, so it is good to have it included where it is absolutely necessary.  Might even been more powerful to have shown that it didn’t work first, and then add afterEvaluate next.
 
Defining configuration dependencies:
Excellent example of why to use evaluationDependsOn.
 
Using partial builds:
current projet -> project
 
Using the Jetty plugin:
It isn’t clear how modifying the reload and scanIntervalSeconds properties provides value to the user since any changes to the source code do not automatically get recompiled and re-deployed due to anything related to this plugin. 
 
Chapter 8
Mixed Languages:
Could have used the term “incubating” with the C++ plugin (although at the majority of the time of writing for this book, it would have still been called experimental).
 
Using the Groovy plugin:
Good explanation of why not to use “localGroovy” for normal development, but that it makes sense for plugin development.
 
Might have been useful to say where the Gradle build file was placed in the directory hierarchy.  By now, the reader probably knows, but someone that skipped to this section might think it belongs in src/main/groovy or src/main/groovy/gradle/sample since they are the only two directories referenced.
 
“When our Java code uses Groovy classes, and vice versa, we can use the joint compilation feature.  We must make sure both the Java and Groovy source files are in the src/main/groovy directory.”  This is correct and misleading at the same time.  Only the java classes that depend upon groovy classes and directly/indirectly dependent java classes on those classes need to be included in the main Groovy sourceset.  It’s the “vice versa” that isn’t really necessary, as you could have all the groovy code depend upon all of the java code, and putting the java code into src/main/groovy would not be necessary unless at least one java class depended upon a groovy class.  (Part of the confusion is also because joint compilation is treated differently with the scala plugin examined next)
 
Using the Scala plugin:
“The source files must be in the src/main/scala directory”.  This is the default directory, but like most everything else within Gradle, it can be easily changed.
 
“The compile tasks support both Java and Scala source files with joint compilation.  We can place our Java source files in say the src/main/java directory of our project and the Scala source files in the src/main/scala directory.  The compiler will compile both types of files.”  This is not correct, as just like for groovy, anything in src/main/java will by default be compiled by the Java compiler during the compileJava task.  You’d have to either stuff all of the java code into src/main/scala, or do something like “sourceSets.main.scala.srcDir “src/main/java”    sourceSets.main.java.srcDirs = []” to get joint compilation without having to co-mingle the java and scala code (the same pattern is applicable to the groovy plugin as well).
 
There is a useful example of how to create a dynamic map property with the name “scala”, but without any supporting text, it at first seems like a required way to specify scala information.
 
Good usage of from() for the jar task based upon the outputs of a user added sourceSet.
 
Chapter 9
Maintaining Code Quality:
“either our code has no common coding problems or calculates the complexity of the code.”  Not quite sure what this sentence fragment is meant to convey.  Maybe the removal of “either our code” and replacing the semi-colon with a comma would make sense.
 
Using the Checkstyle plugin:
Good to include an example configuration, since there still isn’t a default one.  Also relevant to mention that access to a repository is necessary to get checkstyle dependencies – might have been even better to list the exact dependencies.
 
First example showing an apply block.  While it generally doesn’t decrease typing much, and uses two extra lines, it’s a very good thing for a reader to absorb to help understand the different ways gradle allows configuration within build files.
 
Example using tabWidth doesn’t actually show how the checkstyle.xml file should actually look.  It would be something like <property name=”tabWidth” value=”${tabWidth}” default=”4”/> as part of the TreeWalker module.  Also, instead of configProperties = [tabWidth: 10] it would be much better if it were [‘tabWidth’: 10], especially since many checkstyle examples use variable names like checkstyle.javadoc.severity, or other names with dots in them that will not expand properly unless quoted.
 
Using the PMD plugin:
Output from $ gradle check shows :pmdMain, :pmdTest, and :pmdUtil coming before compileJava, which is plausible (because it works on source code), but not what happens when actually executing the command.
 
configure(tasks.withType(Pmd)) is a very useful pattern shown in the example to disable html reporting.
 
Example for adding custom ruleSetFiles doesn’t have listed what a valid ruleset file looks like, which would be useful.
 
Makes it clear that toolVersion is used across the plugins to set the version desired.
 
Using the FindBugs plugin:
Good example of applying ignoreFailures to all Findbugs tasks or just the desired one.
 
“We can also configure the plugin that an HTML report generates.” -> “We can also configure the plugin so that an HTML report is generated.”
 
“If we want to use FindBugs plugins, we can define them as dependencies.  The FindBugs plugin adds a findbugsPlugins dependency configuration.  We can assign plugin dependencies to this configuration, and the findbugs tasks will use these plugins to analyze the code.”  This is quite confusing, because it isn’t clear what is a plugin, as it seems to be referring to the rules of FindBugs as plugins or possibly the dependencies themselves.
 
Using the JDepend plugin:
It was shown in the FindBugs example, but is in the text, that only one kind of report can be generated (at least at the time of the book writing).  Although, sometimes it is text vs xml, instead of xml vs html.  At some point, gradle likely should have a way to do unified output, and support more than one output type at a time.
 
Using the CodeNarc plugin:
Unlike the other plugins, the example shows text and xml both enabled, but the content implies that the output can be XML or text file formats.  The CodeNarc plugin actually allows for the creation of html, text and xml altogether.
 
Using the Sonar plugin:
“The task can analyze not only class files, but also test results, so we can make sure the build task is executed before the sonarAnalyze task, to add a dependency on the build task to the sonarAnalyze task.” -> “… by adding a dependency…”
 
Summary:
Not strictly necessary, but each project can either be analyzed as a Java or a Groovy project, but not both at the same time.
 
Chapter 10
Creating a custom task in the build file:
Not clear why the example with “prefix = ‘Running Gradle’” assignment does not contain the @Optional annotation for prefix shown in the previous example.
 
Creating a task in the project source directory:
Good explanation as to why the import statements are necessary in the buildSrc directory.  Also, useful to note the need to qualify package to class and/or use import statement.
 
“The buildSrc directory can even be a multi-project build.”  I believe this intending to describe that it can be part of a multi-project build, not that it can contain a multi-project build.
 
Writing tests:
Should explicitly call out that test class for example belongs in “buildSrc/src/test/groovy/sample” directory.
 
Valuable comment in test example about having to create task object via project method.
 
“In our build.gradle file in the build directory, we must add a Maven repository and the dependency on the JUnit libraries by using the following lines of code:”  Technically, the JUnit libraries do not need to come from a Maven repository, just some repository.
 
Creating a task in a standalone project:
“Gradle implicitly added the Groovy plugin and dependencies on the Gradle API and Groovy for us when the build.gradle file is in the buildSrc directory.”  This is very valuable information when dealing with the magic of the buildSrc directory.
 
The dependencies section is quite interesting, as it seems like there probably should be a gradleTestApi() to make it easier to write plugin-type things.
 
Creating a plugin in the project source directory:
Demonstrates the use of a project extension class, but doesn’t describe why that is being done.
 
Chapter 11
Creating a sample project:
The “$ git add .” command could have unintended consequences, especially if the build directory gets included accidentally.  Not really a gradle issue though.
 
Configuring artifacts and test results:
The test report XMLs pattern is listed as “build/test-results/*.xml”.  This generally should be “**/build/test-results/*.xml” to capture the output from multi-project builds.
 
Chapter 12
Customizing with XML manipulation:
There are several other instances of usage, but it probably should be explained why “.@” is being utilized to directly access variables, especially with the spread operator “*.@”  used for “classpathXml.classpathentry.findAll { it.@kind == ‘con’ }*.@exported = ‘true’”
 
Comprehensive examples of dealing with merge customization to deal with Eclipse and IntelliJ location expectations.
 
Running Gradle in Eclipse:
“We can install the SprintSource Tool Suite” -> “SpringSource”
 

-Spencer