Steve Appling wrote:
I have been trying to make use of the new onlyIf method to optimize
our large build. OnlyIf seemed liked a very useful approach in the
abstract, but is proving to be more of a challenge in a real project.
It was useful for a few tasks (like jar.onlyIf { compile.didWork ||
processResources.didWork }), but not for some of the more expensive
ones. The Test task, in particular, has been frustrating.
I tried the somewhat too simple:
test.onlyIf { compile.didWork || testCompile.didWork ||
processTestResources.didWork }
This does exactly what it says, it only runs the tests if new code was
compiled or the test resources changed and this seemed great at first
glance. When I tried this on our real project, however, I was
disappointed. What this will do is to cause the test task for a
module to be run only once. If it fails and the developer does not
correct it, then the next time the build is run the test will be
skipped. This gives the false impression that everything is correct
when it is not. To be useful, I think this also needs some type of
state information about whether the tests passed last time, but this
is getting more complicated than I originally envisioned.
A general solution to this problem is going to have to remember whether
a task has completed or failed to execute. It is also going to have to
consider the output artifacts of the task (and do a better job with the
input artifacts). I think it is reasonable for Gradle to maintain this
state, provided we do so in a general-purpose way.
For example, this is something that the OptimisationHelper could expose,
that the onlyIf clause can make use of if it cares:
test.onlyIf { compile.didWork || ... || !completedSuccessfully }
I find that I am fighting hard to stop running the test task before
making the jar. While the current dependency chain may seem fine for
a single project build, it becomes frustratingly slow for a really big
system. With older versions of Gradle, I always had to run gradle twice:
gradle -Dskip.test :currentProject:libs
gradle :currentProject:test
The addition of the "-a" option was very helpful with this, so that in
normal daily development we just do:
gradle -a :currentProject:test
This works pretty well. There are some types of dependencies that -a
doesn't skip, so there are some cases where a little more work is done
than needed, but in general this works good. For our continuous build
server, though, we still have a problem. We want to have build
configurations for each project that make a clean build, but only run
the tests for their project. This is back to my original problem
where I need to invoke gradle twice. This is not cleanly handled and
we find that we have to make a custom gradle runner :(.
Thanks for sticking with my rant so far - I'll get to the point.
Why must jar depend on test? This seems like an attempt by the build
tool to enforce test driven development. The "do it my way" mentality
is one thing that many people did not like about Maven. At the very
least, this should be an easily configured option - prehaps parameters
to the Java plugin?. I think that I suggested before that the
usePlugin method might also take a map so you could do:
usePlugin('java', testJars:true)
While I understand the ideal or testing a jar every time, in practice
it often makes it hard to work with in a multi-project system. I
don't want the building of the jars I depend on to be coupled to the
testing of other projects. I want to be able to run "gradle clean
:currentProject:test" to only run the test for the project that I
specified, but still build all the dependencies. This accomplishes
many of the desires I specified earlier for command line syntax
changes, but in a much more straightforward way.
I don't like the fact that jar depends on test, either. It belongs
somewhere else. We now have a similar problem with the checkstyle and
codenarc tasks, because jar also depends on them (for want of somewhere
else to put them).
I think we need some way to tell Gradle whether or not you want tested
(and checked) artifacts.
A simple option is to add a lifecycle task, called, say 'build' and move
the lifecycle dependencies from 'jar' to 'build', so we end up with
something like:
jar -> compile, processResources
libs -> (all jars and wars)
dists -> (all zips and tars)
check -> (all code quality checks)
build -> (all archives), test, check
This way, 'gradle clean test' will test only the current project. A
downside to this approach is that there's no way to get the existing
behaviour (ie test this project and all projects it depends on).
Another option would be to use implicit tasks for tested vs non-tested
artifacts, something like:
tested<TaskName> dependsOn <TaskName>, (test, check for this project and
all projects it depends on).
Adam
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email