doFirst and doLast allow you to perform custom actions before and after the task itself is executed.
The timeline is something like:
Your build.gradle is executed and the task copyScriptsToBuild is created/registered.
If the task is created the code inside the { and } is executed.
If it is only registered this step delayed.
Gradle calculates which tasks should be executed and executes the code inside the { and } for tasks which have only been registered, and are now created. (Note that Gradle can skip this part for tasks which are not needed.)
Then tasks are started. (if possible in parallel but usually tasks depend on each other):
call doFirst of the task
perform the task action
call doLast of the task
As the copy-task (step 2) is executed before doLast (step 3) your first code sample would configure the task after it had already completed.
It might be possible to configure the task in doFirst but in any case you should not configure your task during the execution step.
You second code sample is the correct way. You are configuring the Copy task during the configuration phase.
An example where I use the doFirst function: the swagger codegen task creates code, but doesn’t empty the target directory. I now delete all files in the target directory in the doFirst function.
You could also output debug statements in doFirst and doLast
Disclaimer: this is my understanding. I hope it’s correct. Please correct any mistakes
Additional edit: from "$rootDir/AppScripts" and into "$buildDir/output/bin" do not perform any actions.
Those code lines only configure the Copy task!
Note that Gradle can skip this part for tasks which are not needed.
If the task would have been registered, that would be correct.
In the shown example though eager API is used that does not leverage task configuration avoidance.
So in the shown case the configuration code is always executed.
call doFirst of the task
perform the task action
call doLast of the task
plural for the 1 and 3, you can register multiple doFirst and doLast actions
As the copy-task (step 2) is executed before doLast (step 3) your first code sample would configure the task after it had already completed.
It might be possible to configure the task in doFirst
I don’t think it is possible in doFirst because before doFirst is executed the inputs and outputs are checked and Gradle will see that there are no inputs and don’t even start to execute the task.
but in any case you should not configure your task during the execution step.
very true and important especially for upcoming configuration cache.
But also for up-to-date checking (and caching for cacheable tasks).