Hans Dockter wrote:
> Hi,
>
> one thing I find inconvenient with Gradle multi-project builds at
the
> moment, is that dependent projects are rebuild although it would not
> be necessary.
>
> Let's look at an example:
>
> root
> - commons
> - webservice (has a compile dependency on commons)
>
> Let's look at some use cases
>
> 1.)
> webservice> gradle compile
>
> current:
> does compile, test and uploadLibsInternal on commons
> does compile on webservice
>
> should do: if commons hasn't been touched an existing jar of commons
> should be used. If commons has been touched or no jar does exists,
the
> commons-jar should be build, but without being tested.
>
... [show rest of quote]
Part of the problem here is that uploadLibsInternal does not really
depend on test, but we add this as an artificial dependency to
overlay a
lifecycle over the tasks. Perhaps separating real dependencies
(artifact
dependencies?) from lifecycle would help here. Then, Gradle could
consider real dependencies in other projects and ignore lifecycle
dependencies.
> 2.)
> webservice> gradle test
>
> current: like above except that webservice is tested
> should do: If commons hasn't been touched an existing jar of commons
> should be used. If commons has been touched or no jar does exists,
the
> commons-jar should be build with being tested.
>
Should commons be tested?
I think this is the same question as to whether commons should be
cleaned or not by 'gradle clean'. Sometimes yes and sometime no.
Sometimes I want the task to be run for the current project and all
the
projects it depends on. And sometimes I want the task to be run only
for
the current project. Running 'gradle test' isn't really expressive
enough - it doesn't declare my intentions.
Right.
One solution is to select one behaviour as the default, and provide
some
way to override this from the command-line. A few options:
- Use command-line options to express this, such as: gradle --
recursive test
This is a simple and straight forward way of doing things.
- Use synthetic task names to express this, such as: gradle
recursive-test, where Gradle generates the 'recursive-test' task from
the 'test' task. This could be implemented by a plugin.
This way you could not express that the current project should not be
cleaned, but the dependent projects.
- Use task name pattern matching, such as gradle *:test
I would spare us another command option. But we would have to come up
with some syntax for 'no-rebuild'. I'm not sure.
Here is an idea for implementing things. After http://jira.codehaus.org/browse/GRADLE-183
is implemented, we have a publish<ConfigurationName>task (I call it
the publish task in the rest of the posting). Each project has 0..n of
those tasks. Neither the publish task nor the archive tasks will
depend on test. I think this publish tasks is nice place for
implementing this behavior.
We could offer:
gradle compile -R -no-rebuild // This would disable all the publish
tasks of the dependency projects
gradle compile -R clean,test // Adds dependsOn for clean and test on
the publish tasks of the dependency projects
gradle compile // Chooses a default behavior. We can decide which one.
I think right now it would make sense to choose 'rebuild without
additional stuff'. If our build becomes smarter in avoiding
unnecessary stuff, we might add the test task to the default behavior.
A publish task could also come with a property like
defaultDependsOnTasks. This would overwrite the default behavior if
nothing is specified with the recursive option.
I think for 0.6 we should go with simple tasks names for the recursive
option. In a future release we could provide patterns to be more
selective, e.g.: gradle compile -R *core*:test (only test project
dependencies with a core in there name).
The issue for this is: http://jira.codehaus.org/browse/GRADLE-220
<snip>
- Hans
--
Hans Dockter
Gradle Project lead
http://www.gradle.org