Good templates for a project wizard

I would like to ask your opinion on what script should a good wizard generate. The main reason for having a wizard is to educate users unfamiliar to Gradle. So I expect the generated projects to embrace current best practices. That is, created so that in the future it will be easy for them to leverage the improvements in Gradle (e.g.: parallel processing of scripts).

Currently, in the NetBeans IDE, I have two kinds of project wizards: for standalone projects and for multi-module projects.

Standalone project

The wizard generates a build.gradle and an empty settings.gradle file. This is a basic project for those not planning to use subprojects.

Multi-module project

Actually there are two wizards for this. The first wizard creates the root project and the second allows to add a subproject to it.

which is to be applied to each subproject. - Subproject: The wizard adds a single build.gradle

and checks if the parent folder contains the previously mentioned .gradle files.

Hey,

Thanks a lot of all the efforts to improve NetBeans support!

Some feedback (those are just brainstorming ideas - feel free to disband them at will)

  1. It might be worth having a ‘sample’ java project. E.g with junit testCompile dependency, with some commons lib as compile dependency, with a sample class, a sample unit test, with configured ‘group’, and ‘version’ properties. Following this pattern, you can a sample web app, too.

  2. I would not add the empty settings.gradle. If they are empty, they are not really needed. In case of a single-module project, settings.gradle can have a “rootProject.name=‘foo’” assignment only. This is pretty cool because it makes the project name consistent even if project is checked out to different folder on different environments. 3. I’m not sure I like the ‘parent.gradle’ script applied in every child. Why is it needed? It feels unconventional. Gradle is very good at injecting configuration from the root project to all the children (allprojects{} subprojects{} blocks). 4. It would be cool if the multi project build was somewhat realistic. For example one child project could be a java library that is consumed by a different child project that is a web application.

For more inspiration, take a look at existing 3rd party Gradle plugins that provide the ‘project templates’ feature.

Sooner or later we’ll have a top level support for generation of project templates. We can also provide this functionality via the tooling api. Before that, you’re on your own :slight_smile:

Hope that helps!

Thank you for answering. I will check these project templates.

It might be worth having a ‘sample’ java project.

Despite that I said, the wizards are mostly for educational purposes. I do want them to be useable in practice. That is, it is unlikely that I can guess the libraries a user will use (it would feel like Visual Studio adding a “Class1.cs” to new projects, who knows you might just need one? :)). Except perhaps for JUnit but I already added that one. That said, it truly wouldn’t hurt to at least add commented dependencies.

I would not add the empty settings.gradle. If they are empty, they are not really needed.

I add an empty settings.gradle, so Gradle stops looking for settings.gradle file in a parent directory. To avoid possible issues, if the user had a settings.gradle in a parent directory by accident.

I’m not sure I like the ‘parent.gradle’ script applied in every child. Why is it needed?

When I first saw Gradle the “subprojects” method in the root script was quite confusing. It was obvious that subprojects had a build.gradle (I didn’t know at that time, that they can be renamed). So, when I tried to understand the script of a project, I just didn’t know where to look for, it is not at all obvious, while “apply from” is. Also, almost every build script I have seen depends on the fact that the build.gradle of the root project is executed before its child project. This isn’t necessarily what I expect, I expected the subproject’s script to execute first when I execute gradle from that dir. Other than these, aren’t future plans to disallow one project to configure other projects?

It would be cool if the multi project build was somewhat realistic.

Currently when you create a new root project no subproject is added, you have to add as many subprojects as you one separately in another project wizard window. Though obviously, it would be reasonable to add at least a single subproject.

Sooner or later we’ll have a top level support for generation of project templates. We can also provide this functionality via the tooling api.

That would be nice, making it available through the Tooling API is certainly desirable for me.

That said, it truly wouldn’t hurt to at least add commented dependencies.

I would not advise adding any commented out build script logic as it is not really testable. The idea with the ‘commons-lang’ dependency is more to show how to declare the dependency and that it can be useable in java code. It’s just feedback - it’s up to you how the sample project works :slight_smile:

I add an empty settings.gradle, so Gradle stops looking for settings.gradle file in a parent directory.

Ok, good point. Consider adding the rootProject.name = ‘foo’ thing.

Other than these, aren’t future plans to disallow one project to configure other projects?

That’s correct but we will still have to make the core concepts like allprojects {} and subprojects {} working.

If every single child project applies some common stuff, the most natural place for this common stuff is ‘allprojects’ and ‘subprojects’. That’s how most Gradle builds out there work, that’s what the user guide and gradle books teach, etc. I don’t intend to change your mind - please do whatever you like with my feedback.

Thanks again for the NB plugin :slight_smile:

I would not advise adding any commented out build script logic as it is not really testable.

I’m really ashamed of it but the plugin does not have automated tests :(, so I manually test everything anyway. I hope though that sometime in the future I will add some (at least to those parts I’m able).

Consider adding the rootProject.name = ‘foo’ thing.

I absolutely forgot about this altough it does not affect the IDE.

That’s correct but we will still have to make the core concepts like allprojects {} and subprojects {} working.

Despite being at disadvantage, I will bet against you in this one :). That is, I don’t think it is feasible to keep common initalization here without serious hacks in the specification of these methods. I will keep using “apply from”, since that is something I believe will likely work. Speaking of which, there is one thing in the current build script: The root project is referenced to find the directory where the common script code is stored. Is there a better way to access a directory for common scripts of the project?

Is there a better way to access a directory for common scripts of the project?

What you do is fine. The only thing I would change is use rootProject.file method as it feels more natural.

Hope that helps!

Thank you, somehow I didn’t notice Project.file.

I don’t think it is feasible to keep common initalization here without serious hacks in the specification of these methods.

It’s the idiomatic approach, it works well, and everybody is using it. Hence my vote for using it in the NB plugin template as well. It’s too early to speculate how things might change in the future.

It seems it is two against one :slight_smile: But there is one problem to solve if I add it: I currently base the “run” and “debug” method on a property of the project “mainClass” which is defined before applying the script. How can I do this with “subprojects” or “allprojects”?

My first question would be if it’s desirable to bake all sorts of features into the build script templates that Gradle doesn’t provide out-of-the-box. Many builds won’t need these features, and some of the features might be better implemented as custom plugins (‘apply from:’ or ‘apply plugin:’).

If you do want to implement such features right in the build script, you have the usual choices: ‘evaluationDependsOnChildren’, ‘gradle.projectsEvaluated’, convention mapping, etc. But often this is best hidden away in a plugin.

Some other suggestions:

  • Omit semicolons at end of line. * Rather than adding a task based on whether the user sets some property, it’s more customary to have the user apply a custom plugin (‘apply from:’ or ‘apply plugin:’) in exactly those subprojects that need the task/feature.

My first question would be if it’s desirable to bake all sorts of features into the build script templates that Gradle doesn’t provide out-of-the-box.

I want to add features to the script which is often needed because I don’t expect “veteran” Gradle users to use the wizard because they probably have their own idea how the build script should look like. So I added Maven related things, so that newcomers (maybe it is their first time seeing Gradle and might not even read any doc before) can see that it is doable. Since Maven is the most used build tool in the Java world, I think most user want to see that they can install (upload would be preferable though) Maven artifacts.

As for the tasks added: “run” and “debug” is necessary because NB will execute these tasks when running or debugging a project. Users need to see that this is the way NB expects it.

The task “createFolders” might be dubious because the wizard will create these directories anyway. But I though I might add a task where it is clear that Java code can be added just like that.

Omit semicolons at end of line.

Is this something preferred in Groovy? I mean, I have no Groovy background and since I was using languages where they are necessary, it just felt missing to me. Though, with this reasoning, I could have added every parentheses as well (and semicolons after the methods taking closures as well).

Personally, I’d keep things rather minimal, and wouldn’t make too many assumptions about the background of users (don’t forget Ant). Otherwise you risk ending up with all sorts of build code pieces that aren’t used, or not adequate for the user’s needs.

As for the tasks added: “run” and “debug” is necessary because NB will execute these tasks when running or debugging a project. Users need to see that this is the way NB expects it.

I see. Will the user ever have to touch this code, or use it directly (when running a Gradle build outside of NB)? If not, it might be best to move this code out of the build script and into an init script that NB passes along when it invokes the build.

Is this something preferred in Groovy?

Yes, idiomatic Groovy omits semicolons wherever possible.

… wouldn’t make too many assumptions about the background of users (don’t forget Ant) …

To be honest, I did not plan to add these project wizards, I added them to an explicit request. The requestor wanted a simple head start in Gradle, so this was in response to satisfy this request. Most likely the wizard is not good for more advanced users but they are not the target audience. I want to add a more advanced wizard as soon as Gradle adds some kind of explicit support to it. I don’t really plan to add many specialized wizards because it is too much (boring) work for a questionable gain.

… it might be best to move this code out of the build script and into an init script …

I didn’t know about init scripts but it seems appropriate to me. Actually, I had been thinking about filing an rfe to be able to further customize the build script. I should have run “gradle --help” :slight_smile:

I have adjusted the templates according to the recommendations. I have tried to implement the init script as fail-safe as reasonably possible. That is, normally it shouldn’t prevent loading otherwise correct projects.

The new snapshot of the script templates are here:

Multi-project build

  • settings.gradle - build.gradle - common.gradle This is the file replacing “parent.gradle” and the code is not embedded in the build.gradle of the root project, so that the wizard can make a sanity check if the parent folder contains a proper root project before adding a subproject. Regardless, the file is applied in the build.gradle of the root project (via the ‘subprojects’ method). - build.gradle of subprojects

Single project