Integrating Reports

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Integrating Reports

hans_d
Administrator
I would like to start discussing how to integrate reports into Gradle.

I see two kind of reports:

1.) Reports which belong to the domain of a certain task and possibly  
depend on the execution of this task. For example junit reports and  
cobertura or emma are related to the test task.
2.) Reports which do not belong to a certain task. For example  
checkstyle.

How to implement 1.):

a.)For any test related report task the test task may provide 2  
properties. For example enableJunitReport and junitReport. The first  
is a boolean, the second is an instance of the JUnitReport task. But  
this instance has not been added to the project tasks yet. The test  
task registers a project.addAfterEvaluateListener(). This listener  
checks the value of for example enableJunitReports. If it is true, it  
adds its JUnitReport task instance to the project task.

b.) An alternative implementation would be to for the test task, to  
just provide one property, the JUnitReport task. This task is  
directly added to the project tasks. If a user does not want it, it  
can be disabled, via setting the enabled property any task has to  
false. The disadvantage of this approach is, that the JUnitReport  
task is added to the task execution graph and makes it bigger and  
harder to read (e.g. by using gradle -t) without any purpose. Setting  
enabled to false just prevents that any action gets executed. It is  
the same as setting a skip property.

c.) Another option is do things as in b.) but to change the behavior  
of the 'enabled' property of tasks. If a task is not enabled, it is  
not added to the task execution graph. If another task has a  
dependsOn relation to a disabled task an exception is thrown. An  
possibly alternative to an exception would be not to add the  
dependsOn task as well.

How to implement 2.):
We could provide a reports tasks which bundles all independent  
reports. It has the same role as the test task for test associated  
tasks. We have the same option a,b,c for implementing the association  
between the report task and its reports.


Right now I would add the reports task to the Java plugin and we have  
to add all the necessary libs to the gradle libs folder. In another  
thread we have discussed that we want to do things differently once  
we have our new plugin system.

- Hans

--
Hans Dockter
Gradle Project lead
http://www.gradle.org





---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Integrating Reports

dportello
I don't have any direct feed back for these options, though I would like to add. Sometimes when running Corbortura or Emma, it should be run against the entire application project and sub-projects, not on individual projects. part of my hacked-up grails build was to have a reporting phase of the build.

On Fri, Aug 29, 2008 at 10:01 AM, Hans Dockter <[hidden email]> wrote:
I would like to start discussing how to integrate reports into Gradle.

I see two kind of reports:

1.) Reports which belong to the domain of a certain task and possibly depend on the execution of this task. For example junit reports and cobertura or emma are related to the test task.
2.) Reports which do not belong to a certain task. For example checkstyle.

How to implement 1.):

a.)For any test related report task the test task may provide 2 properties. For example enableJunitReport and junitReport. The first is a boolean, the second is an instance of the JUnitReport task. But this instance has not been added to the project tasks yet. The test task registers a project.addAfterEvaluateListener(). This listener checks the value of for example enableJunitReports. If it is true, it adds its JUnitReport task instance to the project task.

b.) An alternative implementation would be to for the test task, to just provide one property, the JUnitReport task. This task is directly added to the project tasks. If a user does not want it, it can be disabled, via setting the enabled property any task has to false. The disadvantage of this approach is, that the JUnitReport task is added to the task execution graph and makes it bigger and harder to read (e.g. by using gradle -t) without any purpose. Setting enabled to false just prevents that any action gets executed. It is the same as setting a skip property.

c.) Another option is do things as in b.) but to change the behavior of the 'enabled' property of tasks. If a task is not enabled, it is not added to the task execution graph. If another task has a dependsOn relation to a disabled task an exception is thrown. An possibly alternative to an exception would be not to add the dependsOn task as well.

How to implement 2.):
We could provide a reports tasks which bundles all independent reports. It has the same role as the test task for test associated tasks. We have the same option a,b,c for implementing the association between the report task and its reports.


Right now I would add the reports task to the Java plugin and we have to add all the necessary libs to the gradle libs folder. In another thread we have discussed that we want to do things differently once we have our new plugin system.

- Hans

--
Hans Dockter
Gradle Project lead
http://www.gradle.org





---------------------------------------------------------------------
To unsubscribe from this list, please visit:

  http://xircles.codehaus.org/manage_email



Reply | Threaded
Open this post in threaded view
|

Re: Integrating Reports

dportello
sorry, I meant Gant, not Grails... too many G* projects on the brain.

On Fri, Aug 29, 2008 at 10:48 AM, Dennis Portello <[hidden email]> wrote:
I don't have any direct feed back for these options, though I would like to add. Sometimes when running Corbortura or Emma, it should be run against the entire application project and sub-projects, not on individual projects. part of my hacked-up grails build was to have a reporting phase of the build.


On Fri, Aug 29, 2008 at 10:01 AM, Hans Dockter <[hidden email]> wrote:
I would like to start discussing how to integrate reports into Gradle.

I see two kind of reports:

1.) Reports which belong to the domain of a certain task and possibly depend on the execution of this task. For example junit reports and cobertura or emma are related to the test task.
2.) Reports which do not belong to a certain task. For example checkstyle.

How to implement 1.):

a.)For any test related report task the test task may provide 2 properties. For example enableJunitReport and junitReport. The first is a boolean, the second is an instance of the JUnitReport task. But this instance has not been added to the project tasks yet. The test task registers a project.addAfterEvaluateListener(). This listener checks the value of for example enableJunitReports. If it is true, it adds its JUnitReport task instance to the project task.

b.) An alternative implementation would be to for the test task, to just provide one property, the JUnitReport task. This task is directly added to the project tasks. If a user does not want it, it can be disabled, via setting the enabled property any task has to false. The disadvantage of this approach is, that the JUnitReport task is added to the task execution graph and makes it bigger and harder to read (e.g. by using gradle -t) without any purpose. Setting enabled to false just prevents that any action gets executed. It is the same as setting a skip property.

c.) Another option is do things as in b.) but to change the behavior of the 'enabled' property of tasks. If a task is not enabled, it is not added to the task execution graph. If another task has a dependsOn relation to a disabled task an exception is thrown. An possibly alternative to an exception would be not to add the dependsOn task as well.

How to implement 2.):
We could provide a reports tasks which bundles all independent reports. It has the same role as the test task for test associated tasks. We have the same option a,b,c for implementing the association between the report task and its reports.


Right now I would add the reports task to the Java plugin and we have to add all the necessary libs to the gradle libs folder. In another thread we have discussed that we want to do things differently once we have our new plugin system.

- Hans

--
Hans Dockter
Gradle Project lead
http://www.gradle.org





---------------------------------------------------------------------
To unsubscribe from this list, please visit:

  http://xircles.codehaus.org/manage_email




Reply | Threaded
Open this post in threaded view
|

Re: Integrating Reports

Adam Murdoch-2
In reply to this post by hans_d


Hans Dockter wrote:
> I would like to start discussing how to integrate reports into Gradle.
>
> I see two kind of reports:
>
> 1.) Reports which belong to the domain of a certain task and possibly
> depend on the execution of this task. For example junit reports and
> cobertura or emma are related to the test task.

Some things I'd like to be able to do with these kinds of reports:

Generally, these reports really only depend on the output of the task,
rather than the execution as such. For example, I can run the junit
report if I have some test result xml files, regardless of how they got
there (they may have been generated in a previous build, or maybe run on
a bunch of different machines, etc). Ditto the cobertura and emma
reports. So, sometimes I'd like to be able to run the reports without
running the associated task.

In the case of reporting on tests, I'd like to be able to replace how
the testing actually gets run, but leave all the reporting in place. The
'how to run the tests' and the 'what to do with the results' should be
fairly independent things.

For test coverage reports, for a given build, I only want to use one out
of the available ones at any given time, so I'd like to have a simple
way to choose which one (if any). When a coverage report is to be
included in the build, it needs to instrument the classes to be used for
testing, and so the report (or something) is going to need a way to
modify the inputs to the test task.

For these kind of reports, I'd like the report to be generated whenever
the associated task is included in the build, and to be generated
regardless of whether the task succeeds or fails, or any of the other
reports succeed or fail.

Finally, I'd want to be able to decorate the tests with my own reports.

> 2.) Reports which do not belong to a certain task. For example
> checkstyle.
>

Would a report that summaries the build fit into this category? For
example, a report which summaries all the reports for the build.  Or a
report which summaries the timing for each task. I'd like to be able to
add a report like this, and have it be generated whenever the build does
a certain type of thing (generates a report, runs a task, etc)

> How to implement 1.):
>
> a.)For any test related report task the test task may provide 2
> properties. For example enableJunitReport and junitReport. The first
> is a boolean, the second is an instance of the JUnitReport task. But
> this instance has not been added to the project tasks yet. The test
> task registers a project.addAfterEvaluateListener(). This listener
> checks the value of for example enableJunitReports. If it is true, it
> adds its JUnitReport task instance to the project task.
>
> b.) An alternative implementation would be to for the test task, to
> just provide one property, the JUnitReport task. This task is directly
> added to the project tasks. If a user does not want it, it can be
> disabled, via setting the enabled property any task has to false. The
> disadvantage of this approach is, that the JUnitReport task is added
> to the task execution graph and makes it bigger and harder to read
> (e.g. by using gradle -t) without any purpose. Setting enabled to
> false just prevents that any action gets executed. It is the same as
> setting a skip property.
>
> c.) Another option is do things as in b.) but to change the behavior
> of the 'enabled' property of tasks. If a task is not enabled, it is
> not added to the task execution graph. If another task has a dependsOn
> relation to a disabled task an exception is thrown. An possibly
> alternative to an exception would be not to add the dependsOn task as
> well.
>

I don't think that the Test task should know about which reports could
be generated from its output. Instead, I think we should go with
independent reusable chunks of behaviour as Tasks, let the plugins
provide the domain model and do the wiring, with some stuff in the core
to let us express the things we need.

So, I think we should, for the short term:

- Implement each report as a Task.  We should also add a Report
interface to provide some generic config and meta-info.
- Split a JunitReport task out of the Test task
- Add a way to declare that a task must be included in the execution
graph if a given other task (or matching set of tasks) is included in
the execution graph.
- Use the enabled flag and/or skip properties to include/exclude the report.
- Change the java plugin to always add the junitReport and a coverage
task (we just pick one of coberatura or emma)
- Add the jars required for the above tasks to gradle home lib directory.

There'd still be some things to tidy-up, but we can figure that out later:
- Better ways of including/excluding reports. This isn't a problem
specific to reports - any sizable build has tasks that are wired up for
a 'full' build, but which are optional in some cases (eg the docs and
tests when running gradle's 'install' task)
- Better ways of bundling/downloading/locating the dependencies for the
reports. Again, this isn't specific to reports - each plugin and group
of tasks is going to need a number of dependencies which we don't want
to include in the core distribution.

> How to implement 2.):
> We could provide a reports tasks which bundles all independent reports.

This is a good idea.



Adam

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Integrating Reports

hans_d
Administrator

On Aug 30, 2008, at 7:10 AM, Adam Murdoch wrote:

>
>
> Hans Dockter wrote:
>> I would like to start discussing how to integrate reports into  
>> Gradle.
>>
>> I see two kind of reports:
>>
>> 1.) Reports which belong to the domain of a certain task and  
>> possibly depend on the execution of this task. For example junit  
>> reports and cobertura or emma are related to the test task.
>
> Some things I'd like to be able to do with these kinds of reports:
>
> Generally, these reports really only depend on the output of the  
> task, rather than the execution as such. For example, I can run the  
> junit report if I have some test result xml files, regardless of  
> how they got there (they may have been generated in a previous  
> build, or maybe run on a bunch of different machines, etc). Ditto  
> the cobertura and emma reports. So, sometimes I'd like to be able  
> to run the reports without running the associated task.
>
> In the case of reporting on tests, I'd like to be able to replace  
> how the testing actually gets run, but leave all the reporting in  
> place. The 'how to run the tests' and the 'what to do with the  
> results' should be fairly independent things.

Agreed.

>
> For test coverage reports, for a given build, I only want to use  
> one out of the available ones at any given time, so I'd like to  
> have a simple way to choose which one (if any). When a coverage  
> report is to be included in the build, it needs to instrument the  
> classes to be used for testing, and so the report (or something) is  
> going to need a way to modify the inputs to the test task.
>
> For these kind of reports, I'd like the report to be generated  
> whenever the associated task is included in the build, and to be  
> generated regardless of whether the task succeeds or fails, or any  
> of the other reports succeed or fail.
>
> Finally, I'd want to be able to decorate the tests with my own  
> reports.
>
>> 2.) Reports which do not belong to a certain task. For example  
>> checkstyle.
>>
>
> Would a report that summaries the build fit into this category? For  
> example, a report which summaries all the reports for the build.  
> Or a report which summaries the timing for each task. I'd like to  
> be able to add a report like this, and have it be generated  
> whenever the build does a certain type of thing (generates a  
> report, runs a task, etc)

I'd say it fits into this category. Anyway, it is good idea for a  
report.

>
>> How to implement 1.):
>>
>> a.)For any test related report task the test task may provide 2  
>> properties. For example enableJunitReport and junitReport. The  
>> first is a boolean, the second is an instance of the JUnitReport  
>> task. But this instance has not been added to the project tasks  
>> yet. The test task registers a project.addAfterEvaluateListener().  
>> This listener checks the value of for example enableJunitReports.  
>> If it is true, it adds its JUnitReport task instance to the  
>> project task.
>>
>> b.) An alternative implementation would be to for the test task,  
>> to just provide one property, the JUnitReport task. This task is  
>> directly added to the project tasks. If a user does not want it,  
>> it can be disabled, via setting the enabled property any task has  
>> to false. The disadvantage of this approach is, that the  
>> JUnitReport task is added to the task execution graph and makes it  
>> bigger and harder to read (e.g. by using gradle -t) without any  
>> purpose. Setting enabled to false just prevents that any action  
>> gets executed. It is the same as setting a skip property.
>>
>> c.) Another option is do things as in b.) but to change the  
>> behavior of the 'enabled' property of tasks. If a task is not  
>> enabled, it is not added to the task execution graph. If another  
>> task has a dependsOn relation to a disabled task an exception is  
>> thrown. An possibly alternative to an exception would be not to  
>> add the dependsOn task as well.
>>
>
> I don't think that the Test task should know about which reports  
> could be generated from its output. Instead, I think we should go  
> with independent reusable chunks of behaviour as Tasks, let the  
> plugins provide the domain model and do the wiring, with some stuff  
> in the core to let us express the things we need.

I agree.

>
> So, I think we should, for the short term:
>
> - Implement each report as a Task.  We should also add a Report  
> interface to provide some generic config and meta-info.
> - Split a JunitReport task out of the Test task
> - Add a way to declare that a task must be included in the  
> execution graph if a given other task (or matching set of tasks) is  
> included in the execution graph.

Here is how I understand this requirement:

With the current dependsOn declaration we can only define  
prerequisites of a task. Something I have always liked were the  
postGoal's of Maven 1. We could offer a method to a task like  
'postRequisite' which takes tasks as an argument. This tasks need to  
be executed after the source task has been executed. The question is  
how to fit this into a directed acyclic graph. My rough idea is to  
create dependsOn relations from the postRequisite tasks to the source  
task. If the build is started with: 'gradle sourceTask' we need to  
translate this into an execution of the postRequisite tasks. If a  
task has postRequisite its name is rather an alias for the  
postRequisite tasks.


> - Use the enabled flag and/or skip properties to include/exclude  
> the report.
> - Change the java plugin to always add the junitReport and a  
> coverage task (we just pick one of coberatura or emma)

With the above terminology junitReport and coverage would be  
postRequisites of the test task, right? (I don't think that  
postRequisite is a very good name, but for now I don't know anything  
better).

> - Add the jars required for the above tasks to gradle home lib  
> directory.
>
> There'd still be some things to tidy-up, but we can figure that out  
> later:
> - Better ways of including/excluding reports. This isn't a problem  
> specific to reports - any sizable build has tasks that are wired up  
> for a 'full' build, but which are optional in some cases (eg the  
> docs and tests when running gradle's 'install' task)
> - Better ways of bundling/downloading/locating the dependencies for  
> the reports. Again, this isn't specific to reports - each plugin  
> and group of tasks is going to need a number of dependencies which  
> we don't want to include in the core distribution.

This is important as we have discussed in another thread.

>
>> How to implement 2.):
>> We could provide a reports tasks which bundles all independent  
>> reports.
>
> This is a good idea.

We might change this to: 'which bundles all reports'.

- Hans

--
Hans Dockter
Gradle Project lead
http://www.gradle.org





---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Integrating Reports

Adam Murdoch-2


Hans Dockter wrote:

>
> On Aug 30, 2008, at 7:10 AM, Adam Murdoch wrote:
>>
>> So, I think we should, for the short term:
>>
>> - Implement each report as a Task.  We should also add a Report
>> interface to provide some generic config and meta-info.
>> - Split a JunitReport task out of the Test task
>> - Add a way to declare that a task must be included in the execution
>> graph if a given other task (or matching set of tasks) is included in
>> the execution graph.
>
> Here is how I understand this requirement:
>
> With the current dependsOn declaration we can only define
> prerequisites of a task. Something I have always liked were the
> postGoal's of Maven 1. We could offer a method to a task like
> 'postRequisite' which takes tasks as an argument. This tasks need to
> be executed after the source task has been executed.

Pretty much. It's a kind of like a finally handler for the source task,
which is itself a task. We could call these tasks finally handler tasks,
and the method doFinally(). Regardless of its name, I think it should
work like dependsOn() - you can use a task path or Task object or
collections of these things (and TaskActions? and Closures?).

Another option is that you flip this around and attach the dependency to
the postrequisite task, using, say, a dependsOn() with a condition, such
that the dependency is included only when the condition is met. In this
case, the condition would be whether the source task is scheduled to be
executed.

I'd like to make the dependencies between tasks into real objects with
an interface (TaskDependency, say) which anyone can implement to
describe different types of dependencies.  We would have some standard
implementations: prerequisite tasks, finally tasks, error handler tasks,
project dependencies, all tasks which generate reports, all tasks which
match a closure, all tasks in the same project, all tasks with a given
name in all subprojects ... you get the idea. Not sure how this
interface would look yet.

> The question is how to fit this into a directed acyclic graph. My
> rough idea is to create dependsOn relations from the postRequisite
> tasks to the source task. If the build is started with: 'gradle
> sourceTask' we need to translate this into an execution of the
> postRequisite tasks. If a task has postRequisite its name is rather an
> alias for the postRequisite tasks.
>

I think all of the above stuff boils down to 3 primitive dependencies
between tasks:
1) taskA should execute if taskB successfully executes
2) taskA should execute if taskB executes and fails
3) taskA should execute if taskB executes at all, regardless of success
or failure

Building the DAG would involve converting from TaskDependency objects to
the above primitives (somehow).

sourceTask.doFinally(finallyTask) should result in a dependency of type
3, from finallyTask to sourceTask if sourceTask is scheduled to be
executed - regardless of how we decided to schedule it (from the
command-line, because of a depends-on, because it is a finally task of
some other task, etc).

>> - Use the enabled flag and/or skip properties to include/exclude the
>> report.
>> - Change the java plugin to always add the junitReport and a coverage
>> task (we just pick one of coberatura or emma)
>
> With the above terminology junitReport and coverage would be
> postRequisites of the test task, right?
>

Yes. And, for example, the 'all reports' task would be a postRequisite
of the junitReport and the coverage report.

>>> How to implement 2.):
>>> We could provide a reports tasks which bundles all independent reports.
>>
>> This is a good idea.
>
> We might change this to: 'which bundles all reports'.
>

That's what I read :)


Adam

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Integrating Reports

hans_d
Administrator

On Sep 1, 2008, at 12:44 PM, Adam Murdoch wrote:

>
>
> Hans Dockter wrote:
>>
>> On Aug 30, 2008, at 7:10 AM, Adam Murdoch wrote:
>>>
>>> So, I think we should, for the short term:
>>>
>>> - Implement each report as a Task.  We should also add a Report  
>>> interface to provide some generic config and meta-info.
>>> - Split a JunitReport task out of the Test task
>>> - Add a way to declare that a task must be included in the  
>>> execution graph if a given other task (or matching set of tasks)  
>>> is included in the execution graph.
>>
>> Here is how I understand this requirement:
>>
>> With the current dependsOn declaration we can only define  
>> prerequisites of a task. Something I have always liked were the  
>> postGoal's of Maven 1. We could offer a method to a task like  
>> 'postRequisite' which takes tasks as an argument. This tasks need  
>> to be executed after the source task has been executed.
>
> Pretty much. It's a kind of like a finally handler for the source  
> task, which is itself a task. We could call these tasks finally  
> handler tasks, and the method doFinally(). Regardless of its name,  
> I think it should work like dependsOn() - you can use a task path  
> or Task object or collections of these things (and TaskActions? and  
> Closures?).
>
> Another option is that you flip this around and attach the  
> dependency to the postrequisite task, using, say, a dependsOn()  
> with a condition, such that the dependency is included only when  
> the condition is met. In this case, the condition would be whether  
> the source task is scheduled to be executed.
>
> I'd like to make the dependencies between tasks into real objects  
> with an interface (TaskDependency, say) which anyone can implement  
> to describe different types of dependencies.  We would have some  
> standard implementations: prerequisite tasks, finally tasks, error  
> handler tasks, project dependencies, all tasks which generate  
> reports, all tasks which match a closure, all tasks in the same  
> project, all tasks with a given name in all subprojects ... you get  
> the idea. Not sure how this interface would look yet.

Introducing a task dependency is I think a very good idea.

>
>> The question is how to fit this into a directed acyclic graph. My  
>> rough idea is to create dependsOn relations from the postRequisite  
>> tasks to the source task. If the build is started with: 'gradle  
>> sourceTask' we need to translate this into an execution of the  
>> postRequisite tasks. If a task has postRequisite its name is  
>> rather an alias for the postRequisite tasks.
>>
>
> I think all of the above stuff boils down to 3 primitive  
> dependencies between tasks:
> 1) taskA should execute if taskB successfully executes
> 2) taskA should execute if taskB executes and fails
> 3) taskA should execute if taskB executes at all, regardless of  
> success or failure
>
> Building the DAG would involve converting from TaskDependency  
> objects to the above primitives (somehow).

May be I'm missing something. But I think the domain is more  
complicated then that (leaving aside conditional tasks). Let's look  
at test, testCompile and testReport. How would the relationship  
between test and testCompile be modeled with the above? If I execute  
testCompile, I don't want test to be executed.

gradle testCompile // should execute only testCompile
gradle test // should execute testCompile before and testReport after
gradle testReport // should execute test before. In this case this is  
equivalent to 'gradle test'. But it is a possible operation.

One way to solve this would be to have only one primitive dependency  
in a DAG, which is dependsOn (as it is now).

test dependsOn testCompile
testReport dependsOn test

Additionally we have to modify our execution logic. Instead of  
executing a task, we execute its finally tasks. They have a dependsOn  
relation to its source task. This means the source task is executed  
first and afterwards the finally tasks. Only if there are no finally  
task, the task is executed directly.

- Hans

--
Hans Dockter
Gradle Project lead
http://www.gradle.org





---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Integrating Reports

Adam Murdoch-2


Hans Dockter wrote:

>
>>> The question is how to fit this into a directed acyclic graph. My
>>> rough idea is to create dependsOn relations from the postRequisite
>>> tasks to the source task. If the build is started with: 'gradle
>>> sourceTask' we need to translate this into an execution of the
>>> postRequisite tasks. If a task has postRequisite its name is rather
>>> an alias for the postRequisite tasks.
>>>
>>
>> I think all of the above stuff boils down to 3 primitive dependencies
>> between tasks:
>> 1) taskA should execute if taskB successfully executes
>> 2) taskA should execute if taskB executes and fails
>> 3) taskA should execute if taskB executes at all, regardless of
>> success or failure
>>
>> Building the DAG would involve converting from TaskDependency objects
>> to the above primitives (somehow).
>
> May be I'm missing something. But I think the domain is more
> complicated then that (leaving aside conditional tasks).

I didn't explain this too well. It feels to me like there are 2 levels
of dependency relationships here. The first level is made up of
high-level, domain specific dependencies. Dependencies such as, taskA
depends on all Report tasks. Or taskB must be executed if taskA fails.
Or 'clean' and all its dependencies must be executed before 'assemble'
and all its dependencies. And so on.

These would be represented as TaskDependency implementations attached to
Tasks.

The second level is made up of a small number of types of low level,
general purpose dependencies. Namely the 3 I described earlier.

There would be represented as edges in the DAG.

The process of assembling the DAG would involve evaluating each of the
appropriate TaskDependency instances and adding edges to the DAG. Build
execution would then proceed as it currently does, traversing the edges,
except it would traverse some edges conditionally.

> Let's look at test, testCompile and testReport. How would the
> relationship between test and testCompile be modeled with the above?
> If I execute testCompile, I don't want test to be executed.
>
> gradle testCompile // should execute only testCompile
> gradle test // should execute testCompile before and testReport after
> gradle testReport // should execute test before.

Should it? Or should it just generate the report for whatever results
are already there?

Here's another use for a finally task in a build I have: We have a
number of ci builds, each of which builds an expensive artifact and
uploads it. Currently we have a bunch of artificial tasks to make sure
that upload executes after whichever assemble tasks are being run, but
that upload does not depend on any of the assemble tasks. Finally tasks
would simplify this, as the upload task is a finally task for each of
the assemble tasks. However, if I run the upload task, I don't want any
of the assemble tasks to run, I simply want to upload whatever's already
been assembled.

I guess this discussion demonstrates the usefulness of having
TaskDependency objects. If we choose one behaviour, and I don't like it,
then I can write my own TaskDependency implementation to do what I like.


Adam

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Integrating Reports

hans_d
Administrator

On Sep 12, 2008, at 12:28 AM, Adam Murdoch wrote:

>
>
> Hans Dockter wrote:
>>
>>>> The question is how to fit this into a directed acyclic graph.  
>>>> My rough idea is to create dependsOn relations from the  
>>>> postRequisite tasks to the source task. If the build is started  
>>>> with: 'gradle sourceTask' we need to translate this into an  
>>>> execution of the postRequisite tasks. If a task has  
>>>> postRequisite its name is rather an alias for the postRequisite  
>>>> tasks.
>>>>
>>>
>>> I think all of the above stuff boils down to 3 primitive  
>>> dependencies between tasks:
>>> 1) taskA should execute if taskB successfully executes
>>> 2) taskA should execute if taskB executes and fails
>>> 3) taskA should execute if taskB executes at all, regardless of  
>>> success or failure
>>>
>>> Building the DAG would involve converting from TaskDependency  
>>> objects to the above primitives (somehow).
>>
>> May be I'm missing something. But I think the domain is more  
>> complicated then that (leaving aside conditional tasks).
>
> I didn't explain this too well. It feels to me like there are 2  
> levels of dependency relationships here. The first level is made up  
> of high-level, domain specific dependencies. Dependencies such as,  
> taskA depends on all Report tasks. Or taskB must be executed if  
> taskA fails. Or 'clean' and all its dependencies must be executed  
> before 'assemble' and all its dependencies. And so on.
>
> These would be represented as TaskDependency implementations  
> attached to Tasks.

First of all, I'm definitely in favor of a TaskDependency object. And  
I also share the notion of high level domain specific dependencies  
and low level DAG dependencies.

Domain wise I see another two categories. There are lifecycle  
dependencies and execution dependencies. For example the jar task has  
a lifecycle dependency on the test task. The jar task does not care  
if the test task is skipped. The jar task uses the dependency only to  
establish its point of execution in the build. The test task on the  
other hand has an execution dependency on testCompile. I know that  
this view is a bit fuzzy and has a couple of border cases. Right now  
we can only skip a particular task. I think there are use case where  
you want to skip a subset of the graph if a certain task is skipped.  
Right now we simulate this by adding for example the skip.test  
property as a skip property to testResources. But this is not a very  
nice solution.

>
> The second level is made up of a small number of types of low  
> level, general purpose dependencies. Namely the 3 I described earlier.

I'm still not sure if I understand the way you describe the low level  
dependencies.

You say: taskA should execute if taskB executes

This means:
gradle taskB, executes first taskB then taskA
gradle taskA, executes only taskA

Which is different to the dependsOn relation we use right now (and is  
used this way by almost every other build tool out there).

>
> There would be represented as edges in the DAG.
>
> The process of assembling the DAG would involve evaluating each of  
> the appropriate TaskDependency instances and adding edges to the  
> DAG. Build execution would then proceed as it currently does,  
> traversing the edges, except it would traverse some edges  
> conditionally.

I don't think the way we currently execute the DAG will be enough for  
what we want to achieve. I've tried to explain this is my earlier  
email. Before I get into this again, I would like to get on the same  
page with you regarding the low level dependencies (see above).

>
>> Let's look at test, testCompile and testReport. How would the  
>> relationship between test and testCompile be modeled with the  
>> above? If I execute testCompile, I don't want test to be executed.
>>
>> gradle testCompile // should execute only testCompile
>> gradle test // should execute testCompile before and testReport after
>> gradle testReport // should execute test before.
>
> Should it? Or should it just generate the report for whatever  
> results are already there?

In this case you are right. It was just an example. You might replace  
testReport with some task that really depends on test. It's obviously  
a trivial example and my question was how to implement this with low  
level dependencies as described above.

>
> Here's another use for a finally task in a build I have: We have a  
> number of ci builds, each of which builds an expensive artifact and  
> uploads it. Currently we have a bunch of artificial tasks to make  
> sure that upload executes after whichever assemble tasks are being  
> run, but that upload does not depend on any of the assemble tasks.  
> Finally tasks would simplify this, as the upload task is a finally  
> task for each of the assemble tasks. However, if I run the upload  
> task, I don't want any of the assemble tasks to run, I simply want  
> to upload whatever's already been assembled.

This is an interesting use case.

>
> I guess this discussion demonstrates the usefulness of having  
> TaskDependency objects. If we choose one behaviour, and I don't  
> like it, then I can write my own TaskDependency implementation to  
> do what I like.

Yes. Another improvement for making the impossible possible ;)

- Hans

--
Hans Dockter
Gradle Project lead
http://www.gradle.org





---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Integrating Reports

Adam Murdoch-2


Hans Dockter wrote:

>
> On Sep 12, 2008, at 12:28 AM, Adam Murdoch wrote:
>
>>
>>
>> Hans Dockter wrote:
>>>
>>>>> The question is how to fit this into a directed acyclic graph. My
>>>>> rough idea is to create dependsOn relations from the postRequisite
>>>>> tasks to the source task. If the build is started with: 'gradle
>>>>> sourceTask' we need to translate this into an execution of the
>>>>> postRequisite tasks. If a task has postRequisite its name is
>>>>> rather an alias for the postRequisite tasks.
>>>>>
>>>>
>>>> I think all of the above stuff boils down to 3 primitive
>>>> dependencies between tasks:
>>>> 1) taskA should execute if taskB successfully executes
>>>> 2) taskA should execute if taskB executes and fails
>>>> 3) taskA should execute if taskB executes at all, regardless of
>>>> success or failure
>>>>
>>>> Building the DAG would involve converting from TaskDependency
>>>> objects to the above primitives (somehow).
>>>
>>> May be I'm missing something. But I think the domain is more
>>> complicated then that (leaving aside conditional tasks).
>>
>> I didn't explain this too well. It feels to me like there are 2
>> levels of dependency relationships here. The first level is made up
>> of high-level, domain specific dependencies. Dependencies such as,
>> taskA depends on all Report tasks. Or taskB must be executed if taskA
>> fails. Or 'clean' and all its dependencies must be executed before
>> 'assemble' and all its dependencies. And so on.
>>
>> These would be represented as TaskDependency implementations attached
>> to Tasks.
>
> First of all, I'm definitely in favor of a TaskDependency object. And
> I also share the notion of high level domain specific dependencies and
> low level DAG dependencies.
>
> Domain wise I see another two categories. There are lifecycle
> dependencies and execution dependencies. For example the jar task has
> a lifecycle dependency on the test task. The jar task does not care if
> the test task is skipped. The jar task uses the dependency only to
> establish its point of execution in the build. The test task on the
> other hand has an execution dependency on testCompile. I know that
> this view is a bit fuzzy and has a couple of border cases. Right now
> we can only skip a particular task. I think there are use case where
> you want to skip a subset of the graph if a certain task is skipped.
> Right now we simulate this by adding for example the skip.test
> property as a skip property to testResources. But this is not a very
> nice solution.
>

I really like the idea of using the dependency type to exclude and
include things from a build. I'm not sure about the categories, or how
you might declare this. One option would be to allow a condition to be
attached to a dependency, something like:

taskA.dependsOn('taskA', 'taskB').when { buildType == 'full' }

or

taskA.dependsOn { buildType == 'full' ? 'otherTask' : null }

Another option (not necessarily mutually exclusive) would be to allow a
type to be specified for a dependency, and allow the dependency type to
be skipped using something from the command-line.

Another option would be to introduce the concept of a build type (or
build), which would be declared in the build file, and which would
progammatically modify the task graph in some way, such as
including/excluding tasks and dependencies, and executing tasks in a
particular sequence (eg run clean, then run assemble).  Some examples
from gradle's build would be the developerBuild, or a quickInstallBuild
which would run clean and install but skip docs and tests (and
checkstyle when we add it, etc).

>>
>> The second level is made up of a small number of types of low level,
>> general purpose dependencies. Namely the 3 I described earlier.
>
> I'm still not sure if I understand the way you describe the low level
> dependencies.
>
> You say: taskA should execute if taskB executes
>

This is taskA dependsOn taskB, expressed from the point of view of the
thing that executes the tasks. I should have used dependsOn to express
this, as it's clearer.

The point is really that we take the high-level graph, where a task can
have incoming and outgoing polymorphic dependencies, and compile it down
to a low-level graph, containing simple dependencies which point in 1
direction only.

So, with a project declaring that taskA dependsOn taskB and taskB
doFinally taskC, we get:

gradle taskB -> execute {taskB, taskC} with taskC dependsOn taskB
gradle taskA -> execute {taskA, taskB, taskC} with taskA dependsOn taskB
and taskC dependsOnTaskB
gradle taskC -> execute {taskC}

>>
>> There would be represented as edges in the DAG.
>>
>> The process of assembling the DAG would involve evaluating each of
>> the appropriate TaskDependency instances and adding edges to the DAG.
>> Build execution would then proceed as it currently does, traversing
>> the edges, except it would traverse some edges conditionally.
>
> I don't think the way we currently execute the DAG will be enough for
> what we want to achieve. I've tried to explain this is my earlier
> email. Before I get into this again, I would like to get on the same
> page with you regarding the low level dependencies (see above).
>

I think we're both saying the same thing. I think a soluation is to add
a state enum (on success, on failure, always) to the low level
dependencies we execute, and change the execution algorithm to traverse
a dependency A dependsOn B only when B has executed with the required
state. Currently we have an implicit on 'success state' for all our
dependencies.


Adam

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email