Delegating test and test-only

172 views
Skip to first unread message

Derek Wyatt

unread,
Mar 14, 2012, 9:10:38 PM3/14/12
to simple-b...@googlegroups.com
Hi,

I've successfully built a plugin that helps me write a book. I've defined a book:compile such that the standard compile happens first, then the book compile. This is ideal because code gets inserted into the book and it would be nice if it succeeds first.

Now, I'd like to take that to the next level and ensure that the tests also succeed before building the book.

What I wanted to do was extend my config from (Compile, Test) instead of just (Compile). I'm not getting things "for free" and so I need to know what to do next.

The basic idea is at https://github.com/derekwyatt/sbt-book-compiler

What I tried to do was change it so that:

val BookConfig = config("book") extend(Compile, Test)

and then change it so that we start the configuration as:

inConfig(BookConfig)(Defaults.defaultConfigs ++ Seq(

test <<= (test in Test),
testOnly <<= (testOnly in Test)
))

But, while that seems to do the test compile, it doesn't seem to run the tests (I'm using book:test-only) and it also no longer triggers my book compile when a book file changes.

Does anyone know how to extend what I've got to handle tests as well?

Thanks a lot,
Derek

signature.asc

Derek Wyatt

unread,
Mar 14, 2012, 9:19:37 PM3/14/12
to simple-b...@googlegroups.com
Scratch some of this :) I was being stupid about the tests - they run… what I'm still missing is getting the compile to still trigger as well.

I'd like to have the book compile trigger when a book file changes even when I'm running ~test or ~test-only.

I've tried rewiring it with:

test <<= (test in Test) dependsOn compile

This passes the compiler but it doesn't do anything at runtime.

testOnly <<= (testOnly in Test) dependsOn compile

This fails to pass the compiler because testOnly is an InputTask and doesn't have 'dependsOn' as a method.

Whatever pointers people can send my way would be greatly appreciated.

signature.asc

Mark Harrah

unread,
Mar 15, 2012, 6:25:50 PM3/15/12
to simple-b...@googlegroups.com
On Wed, 14 Mar 2012 21:19:37 -0400
Derek Wyatt <de...@derekwyatt.org> wrote:

> Scratch some of this :) I was being stupid about the tests - they run… what I'm still missing is getting the compile to still trigger as well.
>
> I'd like to have the book compile trigger when a book file changes even when I'm running ~test or ~test-only.
>
> I've tried rewiring it with:
>
> test <<= (test in Test) dependsOn compile
>
> This passes the compiler but it doesn't do anything at runtime.
>
> testOnly <<= (testOnly in Test) dependsOn compile

It would probably help to see a reproducible test case, a sample session, and output. It is hard to tell if you want the *:compile (which is what is being referenced) or some other compile, like test:compile or compile:compile.

> This fails to pass the compiler because testOnly is an InputTask and doesn't have 'dependsOn' as a method.

Right, this is only available in 0.12.0-M1 and later.

-Mark

Derek Wyatt

unread,
Mar 15, 2012, 6:59:33 PM3/15/12
to simple-b...@googlegroups.com
Thanks Mark,

On 2012-03-15, at 6:25 PM, Mark Harrah wrote:
> On Wed, 14 Mar 2012 21:19:37 -0400
> Derek Wyatt <de...@derekwyatt.org> wrote:
>
>> Scratch some of this :) I was being stupid about the tests - they run… what I'm still missing is getting the compile to still trigger as well.
>>
>> I'd like to have the book compile trigger when a book file changes even when I'm running ~test or ~test-only.
>>
>> I've tried rewiring it with:
>>
>> test <<= (test in Test) dependsOn compile
>>
>> This passes the compiler but it doesn't do anything at runtime.
>>
>> testOnly <<= (testOnly in Test) dependsOn compile
>
> It would probably help to see a reproducible test case, a sample session, and output. It is hard to tell if you want the *:compile (which is what is being referenced) or some other compile, like test:compile or compile:compile.

(Sorry about the lack of info in the email… the github link would have filled you in, but I should have put it in the email to make it easier on you)

The bottom line is that I fixed the first one. It was always in an inConfig() block so it was working… the failure was elsewhere.

What I'm still having trouble wrapping my head around is defining stuff like this:

val compileTestCompile = TaskKey[sbt.inc.Analysis]("compile-test-compile")

inConfig(BookConfig)(…
compileTestCompile <<= compile dependsOn ((test in Test) dependsOn (compile in Compile))
)

The goal of that is to compile the main code, then test it, then compile my book. But, whenever I write a book src file or a scala src file, all that happens is that my tests run. No compiles of any kind take place.

There's a lot about SBT that I don't yet understand - I'm getting there, but I'm clueless on this one.

>> This fails to pass the compiler because testOnly is an InputTask and doesn't have 'dependsOn' as a method.
>
> Right, this is only available in 0.12.0-M1 and later.

Ah, awesome. Thanks again. I'll try to upgrade to the latest and greatest as soon as I can.

Cheers,
Derek

>
> -Mark
>
>> Whatever pointers people can send my way would be greatly appreciated.
>>
>> On 2012-03-14, at 9:10 PM, Derek Wyatt wrote:
>>
>>> Hi,
>>>
>>> I've successfully built a plugin that helps me write a book. I've defined a book:compile such that the standard compile happens first, then the book compile. This is ideal because code gets inserted into the book and it would be nice if it succeeds first.
>>>
>>> Now, I'd like to take that to the next level and ensure that the tests also succeed before building the book.
>>>
>>> What I wanted to do was extend my config from (Compile, Test) instead of just (Compile). I'm not getting things "for free" and so I need to know what to do next.
>>>
>>> The basic idea is at https://github.com/derekwyatt/sbt-book-compiler
>>>
>>> What I tried to do was change it so that:
>>>
>>> val BookConfig = config("book") extend(Compile, Test)
>>>
>>> and then change it so that we start the configuration as:
>>>
>>> inConfig(BookConfig)(Defaults.defaultConfigs ++ Seq(
>>> …
>>> test <<= (test in Test),
>>> testOnly <<= (testOnly in Test)
>>> ))
>>>
>>> But, while that seems to do the test compile, it doesn't seem to run the tests (I'm using book:test-only) and it also no longer triggers my book compile when a book file changes.
>>>
>>> Does anyone know how to extend what I've got to handle tests as well?
>>>
>>> Thanks a lot,
>>> Derek
>>
>

> --
> You received this message because you are subscribed to the Google Groups "simple-build-tool" group.
> To post to this group, send email to simple-b...@googlegroups.com.
> To unsubscribe from this group, send email to simple-build-t...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/simple-build-tool?hl=en.
>

signature.asc

Mark Harrah

unread,
Mar 15, 2012, 8:12:55 PM3/15/12
to simple-b...@googlegroups.com
On Thu, 15 Mar 2012 18:59:33 -0400
Derek Wyatt <de...@derekwyatt.org> wrote:

> Thanks Mark,
>
> On 2012-03-15, at 6:25 PM, Mark Harrah wrote:
> > On Wed, 14 Mar 2012 21:19:37 -0400
> > Derek Wyatt <de...@derekwyatt.org> wrote:
> >
> >> Scratch some of this :) I was being stupid about the tests - they run… what I'm still missing is getting the compile to still trigger as well.
> >>
> >> I'd like to have the book compile trigger when a book file changes even when I'm running ~test or ~test-only.
> >>
> >> I've tried rewiring it with:
> >>
> >> test <<= (test in Test) dependsOn compile
> >>
> >> This passes the compiler but it doesn't do anything at runtime.
> >>
> >> testOnly <<= (testOnly in Test) dependsOn compile
> >
> > It would probably help to see a reproducible test case, a sample session, and output. It is hard to tell if you want the *:compile (which is what is being referenced) or some other compile, like test:compile or compile:compile.
>
> (Sorry about the lack of info in the email… the github link would have filled you in, but I should have put it in the email to make it easier on you)

Ah, sorry I missed that. A link is fine and often better (more readable).

> The bottom line is that I fixed the first one. It was always in an inConfig() block so it was working… the failure was elsewhere.
>
> What I'm still having trouble wrapping my head around is defining stuff like this:
>
> val compileTestCompile = TaskKey[sbt.inc.Analysis]("compile-test-compile")
> …
> inConfig(BookConfig)(…
> compileTestCompile <<= compile dependsOn ((test in Test) dependsOn (compile in Compile))
> )
>
> The goal of that is to compile the main code, then test it, then compile my book. But, whenever I write a book src file or a scala src file, all that happens is that my tests run. No compiles of any kind take place.

First, remember that you are defining a dependency graph. There isn't really an imperative notion of saying "do x, then y, then z". It is more declarative, like:

z is a task that depends on y
y is a task that depends on x

and sbt ensures x runs before y and y runs before z. Also, note that (test in Test) is already using the result of (compile in Compile). So, if you want to run tests before compiling the book, have (compile in BookConfig) depend on (test in Test) where you define (compile in BookConfig).

Generally, don't use dependsOn if the task model doesn't make sense yet. I think the way it reads it conveys the wrong semantics in this situation and should perhaps be deprecated or come with a warning.

-Mark

Derek Wyatt

unread,
Mar 15, 2012, 9:12:05 PM3/15/12
to simple-b...@googlegroups.com
OK, 0.12.0-M2 definitely lets me do (test in Test) dependsOn, which is awesome.  Thx.

I've updated the code on github. Things now work pretty well, so thanks.  There's a commented line there that I can't get to work due to some tough typing on the testOnly:

[error]  found   : sbt.InputKey[Unit]
[error]  required: sbt.Scoped.AnyInitTask
[error]     testOnlyThenCompile <<= bookCompile dependsOn (testOnly in Test)

But, if you're telling me that using dependsOn is a bad idea (or not-so-great idea) then maybe I'm pushing it too far.  However, I don't see a way to do this without dependsOn… what should I go look at to see an alternative?  I'm more than happy to do something better, so if you've got a better way for me to go then that'll be cool.

Thanks again,
Derek
signature.asc

Mark Harrah

unread,
Mar 19, 2012, 7:08:37 PM3/19/12
to simple-b...@googlegroups.com
On Thu, 15 Mar 2012 21:12:05 -0400
Derek Wyatt <de...@derekwyatt.org> wrote:

First, testOnly is an InputTask[Unit], which is basically a function of String => Task[Unit] and you can't depend on it. You could depend on 'test'. Perhaps you don't want that because you want different options than the usual test?

dependsOn is bad because it probably doesn't do what you think it does. Do you require testOnly to run before bookCompile or do you just want both of them to run?

-Mark

Derek Wyatt

unread,
Mar 19, 2012, 7:15:46 PM3/19/12
to simple-b...@googlegroups.com
>> I've updated the code on github. Things now work pretty well, so thanks. There's a commented line there that I can't get to work due to some tough typing on the testOnly:
>>
>> [error] found : sbt.InputKey[Unit]
>> [error] required: sbt.Scoped.AnyInitTask
>> [error] testOnlyThenCompile <<= bookCompile dependsOn (testOnly in Test)
>>
>> But, if you're telling me that using dependsOn is a bad idea (or not-so-great idea) then maybe I'm pushing it too far. However, I don't see a way to do this without dependsOn… what should I go look at to see an alternative? I'm more than happy to do something better, so if you've got a better way for me to go then that'll be cool.
>
> First, testOnly is an InputTask[Unit], which is basically a function of String => Task[Unit] and you can't depend on it. You could depend on 'test'. Perhaps you don't want that because you want different options than the usual test?

Yeah, I get that… I guess from my point of view (and this is just a dumb-user point of view - underscored), it's a "task". The mechanics of it are the next level down, and it would be nice if I could ignore it :) I'll answer the next question next...

> dependsOn is bad because it probably doesn't do what you think it does. Do you require testOnly to run before bookCompile or do you just want both of them to run?

Yeah, again this is just a dumb user perspective… I'm starting to think I want to do something backwards. I'd like to compile the book, but compile it after I've compiled and tested the code that the book is based on. For the purposes of "easy" operation, it would be awesome to have that "test" be either "test" or "test-only". From the user perspective, they're just tests.

Now, it's not at all critical - I'm working just fine having the book compile run before the test-only. It's no big deal. It would just be nice if "test" and "test-only" were indistinguishable at this level. They're just things that run and I'd like to string those things together in a particular order, dumping out early if there's a failure.

signature.asc

Mark Harrah

unread,
Mar 19, 2012, 7:45:54 PM3/19/12
to simple-b...@googlegroups.com
On Mon, 19 Mar 2012 19:15:46 -0400
Derek Wyatt <de...@derekwyatt.org> wrote:

> >> I've updated the code on github. Things now work pretty well, so thanks. There's a commented line there that I can't get to work due to some tough typing on the testOnly:
> >>
> >> [error] found : sbt.InputKey[Unit]
> >> [error] required: sbt.Scoped.AnyInitTask
> >> [error] testOnlyThenCompile <<= bookCompile dependsOn (testOnly in Test)
> >>
> >> But, if you're telling me that using dependsOn is a bad idea (or not-so-great idea) then maybe I'm pushing it too far. However, I don't see a way to do this without dependsOn… what should I go look at to see an alternative? I'm more than happy to do something better, so if you've got a better way for me to go then that'll be cool.
> >
> > First, testOnly is an InputTask[Unit], which is basically a function of String => Task[Unit] and you can't depend on it. You could depend on 'test'. Perhaps you don't want that because you want different options than the usual test?
>
> Yeah, I get that… I guess from my point of view (and this is just a dumb-user point of view - underscored), it's a "task". The mechanics of it are the next level down, and it would be nice if I could ignore it :) I'll answer the next question next...

The distinction is important, although I think I understand what you are trying to do now. You want to define an input task 'test-only-then-compile' that passes its arguments to test-only and runs book-compile?

-Mark

Derek Wyatt

unread,
Mar 19, 2012, 7:47:55 PM3/19/12
to simple-b...@googlegroups.com

On 2012-03-19, at 7:45 PM, Mark Harrah wrote:

> On Mon, 19 Mar 2012 19:15:46 -0400
> Derek Wyatt <de...@derekwyatt.org> wrote:
>
>>>> I've updated the code on github. Things now work pretty well, so thanks. There's a commented line there that I can't get to work due to some tough typing on the testOnly:
>>>>
>>>> [error] found : sbt.InputKey[Unit]
>>>> [error] required: sbt.Scoped.AnyInitTask
>>>> [error] testOnlyThenCompile <<= bookCompile dependsOn (testOnly in Test)
>>>>
>>>> But, if you're telling me that using dependsOn is a bad idea (or not-so-great idea) then maybe I'm pushing it too far. However, I don't see a way to do this without dependsOn… what should I go look at to see an alternative? I'm more than happy to do something better, so if you've got a better way for me to go then that'll be cool.
>>>
>>> First, testOnly is an InputTask[Unit], which is basically a function of String => Task[Unit] and you can't depend on it. You could depend on 'test'. Perhaps you don't want that because you want different options than the usual test?
>>
>> Yeah, I get that… I guess from my point of view (and this is just a dumb-user point of view - underscored), it's a "task". The mechanics of it are the next level down, and it would be nice if I could ignore it :) I'll answer the next question next...
>
> The distinction is important, although I think I understand what you are trying to do now. You want to define an input task 'test-only-then-compile' that passes its arguments to test-only and runs book-compile?

Yup, that's it. I haven't taken the time to figure out how to do that yet.. if you wanna help, go for it, but if you want to leave me to my own meagre devices, that's totally understood. :)

/Derek

signature.asc

Mark Harrah

unread,
Mar 19, 2012, 7:58:09 PM3/19/12
to simple-b...@googlegroups.com
On Mon, 19 Mar 2012 19:47:55 -0400
Derek Wyatt <de...@derekwyatt.org> wrote:

>
> On 2012-03-19, at 7:45 PM, Mark Harrah wrote:
>
> > On Mon, 19 Mar 2012 19:15:46 -0400
> > Derek Wyatt <de...@derekwyatt.org> wrote:
> >
> >>>> I've updated the code on github. Things now work pretty well, so thanks. There's a commented line there that I can't get to work due to some tough typing on the testOnly:
> >>>>
> >>>> [error] found : sbt.InputKey[Unit]
> >>>> [error] required: sbt.Scoped.AnyInitTask
> >>>> [error] testOnlyThenCompile <<= bookCompile dependsOn (testOnly in Test)
> >>>>
> >>>> But, if you're telling me that using dependsOn is a bad idea (or not-so-great idea) then maybe I'm pushing it too far. However, I don't see a way to do this without dependsOn… what should I go look at to see an alternative? I'm more than happy to do something better, so if you've got a better way for me to go then that'll be cool.
> >>>
> >>> First, testOnly is an InputTask[Unit], which is basically a function of String => Task[Unit] and you can't depend on it. You could depend on 'test'. Perhaps you don't want that because you want different options than the usual test?
> >>
> >> Yeah, I get that… I guess from my point of view (and this is just a dumb-user point of view - underscored), it's a "task". The mechanics of it are the next level down, and it would be nice if I could ignore it :) I'll answer the next question next...
> >
> > The distinction is important, although I think I understand what you are trying to do now. You want to define an input task 'test-only-then-compile' that passes its arguments to test-only and runs book-compile?
>
> Yup, that's it. I haven't taken the time to figure out how to do that yet.. if you wanna help, go for it, but if you want to leave me to my own meagre devices, that's totally understood. :)

Ah, ok. That is a reasonable thing to want to do. However, InputTasks aren't easy to manipulate/combine. It would probably be a waste of time to try to make this work without changes to sbt, so if you open a bug, I'll take a look. I don't know that I'll get to a fix too soon, but I can probably post a workaround that uses commands.

-Mark

Derek Wyatt

unread,
Mar 19, 2012, 7:59:31 PM3/19/12
to simple-b...@googlegroups.com

On 2012-03-19, at 7:58 PM, Mark Harrah wrote:

> On Mon, 19 Mar 2012 19:47:55 -0400
> Derek Wyatt <de...@derekwyatt.org> wrote:
>
>>
>> On 2012-03-19, at 7:45 PM, Mark Harrah wrote:
>>
>>> On Mon, 19 Mar 2012 19:15:46 -0400
>>> Derek Wyatt <de...@derekwyatt.org> wrote:
>>>
>>>>>> I've updated the code on github. Things now work pretty well, so thanks. There's a commented line there that I can't get to work due to some tough typing on the testOnly:
>>>>>>
>>>>>> [error] found : sbt.InputKey[Unit]
>>>>>> [error] required: sbt.Scoped.AnyInitTask
>>>>>> [error] testOnlyThenCompile <<= bookCompile dependsOn (testOnly in Test)
>>>>>>
>>>>>> But, if you're telling me that using dependsOn is a bad idea (or not-so-great idea) then maybe I'm pushing it too far. However, I don't see a way to do this without dependsOn… what should I go look at to see an alternative? I'm more than happy to do something better, so if you've got a better way for me to go then that'll be cool.
>>>>>
>>>>> First, testOnly is an InputTask[Unit], which is basically a function of String => Task[Unit] and you can't depend on it. You could depend on 'test'. Perhaps you don't want that because you want different options than the usual test?
>>>>
>>>> Yeah, I get that… I guess from my point of view (and this is just a dumb-user point of view - underscored), it's a "task". The mechanics of it are the next level down, and it would be nice if I could ignore it :) I'll answer the next question next...
>>>
>>> The distinction is important, although I think I understand what you are trying to do now. You want to define an input task 'test-only-then-compile' that passes its arguments to test-only and runs book-compile?
>>
>> Yup, that's it. I haven't taken the time to figure out how to do that yet.. if you wanna help, go for it, but if you want to leave me to my own meagre devices, that's totally understood. :)
>
> Ah, ok. That is a reasonable thing to want to do. However, InputTasks aren't easy to manipulate/combine. It would probably be a waste of time to try to make this work without changes to sbt, so if you open a bug, I'll take a look. I don't know that I'll get to a fix too soon, but I can probably post a workaround that uses commands.

Will do. Thanks Mark.

signature.asc
Reply all
Reply to author
Forward
0 new messages