Unparalleled Command-Line Usability

(Hans Dockter) #1

summary: Smart Bash Completion, Command Line Task Parameters (completable) instead of magic properties, Command Line Plugins, Even better reporting status: Discussions are happening and we will iteratively add features in this area after 1.0. code: planned

Today’s Gradle already contains very rich information about your project, including the structure of multi-project builds, the purpose of and tasks for each project and so on. Today’s Gradle provides a reasonable command-line interface for interacting with that project knowledege, but we are committed that it go much, much further.

The Gradle command line should, from the first moment of use, guide the user through what is possible in the Gradle build, providing help at every turn, exposing interesting information when appropriate, and hiding needless details at the same time.

For us, the command line is the ultimate proving ground for tool usability. If you get it right at the command line, you have every opportunity to get it right in the GUI or IDE, but the opposite is not necessarily the case. Following in the footsteps of projects like Roo and Git, we are currently in progress making Gradle’s command-line interface world-class.

We think this is important not just because a polished UI looks and feels great, but because the very nature of interacting with a build tool demands this kind of experience. Most users, most of the time, interact with the build as what we’ll call a ‘build operator’. They are a Java developer who wants to compile and test the sources, generate project documentation, and so on. The need not, and should not have to think about, look at, or modify build script internals in order to satisfy those core use cases. It should not be a matter of tribal knowledge, documentation, or previous experience that they know (remember) how to operate the build. Rather, they should have a friendly interface that can tell them what’s possible, and help them through their daily workflow.

As a related aside, those that create and maintain the build, we’ll call ‘build masters’. Of course, in practice, the roles of ‘build operator’ and ‘build master’ may be played by the same individual people, but it is nevertheless important to distinguish the user roles from the user. The build master is also naturally a power-user of this CLI, but spends much of their time interacting with the Gradle DSL and APIs to implement requirements in the build script(s).

Build systems need not be overly rigid. To constrains what’s possible in the name of ‘build homogeny’ would indeed be nice if it weren’t for the pesky reality that not all builds are the same, and that build heterogeny is the reality and rule, not the exception. There are many specific standars in an enterprise that need to be explicitly modelled. In practice, too many constraints forces the users to make what would be explicit concepts implicit. This makes the build harder to operate.

The proper solution to the apparent homogeny (consistency) vs. heterogeny (flexibility) problem is to provide build operators with a helpful UI. If build A differs from build B, this is not a problem if they each present to me a clear understanding of what I can do and why I would care.

What will this UI look like? It will be fiercely minimalistic yet always friendly, offering to tell you more about what you specifically care about. It will be in color by default, with an option to disable. We think color makes a tremendous difference at the command line, and again defer to Git and Roo as all the proof necessary. Gradle will provide advanced bash-completion scripts capable of staying up-to-date with the dynamic nature of individual gradle builds. Unlike Git, Gradle’s bash-completion support will be a first-class member of the Gradle ecosystem; something that can be installed by default / on demand and in a hands-free fashion.

(Merlyn Albery-Speyer) #2

One usability issue is the potential disconnect between the user’s Gradle version and the one specified for the Gradle wrapper. IMO it’s preferable for the wrapper version could supersede the user’s Gradle version.

(Adam Murdoch) #3

@merlyn that’s exactly the plan.

(Davide Cavestro) #4

I’d like to have a way to inform the CLI user about the configuration switches/options supported by the local build logic (as happens adding descriptions to tasks).

I quote here an interesting comment Adam left some time ago on the old forums:

give the build author some way to declare the >human tweakable configuration for the build. Then, the UI (command-line, >GUI, IDE, CI server) can provide some way to: >- tell the user what configuration is available >- validate the values that the user has provided >- persist the user’s configuration (if required) >- report on the config that was used to build some given artifacts

taken from http://gradle.1045684.n5.nabble.com/Proposal-Custom-command-line-arguments-tp1437272p1437275.html Are you planning to support even these scenarios? That would be great!

(Warren Muller) #5


What we have done is to create all our custom build tasks in plugins. Each plugin has an ext object. In our build.gradle we include these in the buildScript and apply them where applicable (some in the root only some in allprojects, some in specific projects only). We then apply a project level override say config.gradle - which can be set in each project but mostly in the root project. This is where users can override any plugin config at a project level that affects everyone. Lastly we apply a usersettings.gradle which is a user specific/personal override to the plugin values. this was we have a tiered approach to override properties but its more than just a .properties file, its logic too that any user can utilise if they know how. We have a ‘Common’ plugin that provides some utility functionality. It too has ext. properties. So we have in each ext obj for each plugin a method called showProperties which explicitly shows all properties in a proper format for that plugin extension. The common plugin then has a task called showProperties which ‘finds’ all custom plugin extension objects and using introspection looks to see if there is a method called showProperties and executes this. The result is sorted before output to console. So ‘gradle properties’ shows all gradle properties and ‘gradle showProperties’ shows all our custom configuration sorted by plugin ext obj name which we can grep. So that covers most of what you you request. Validation is done on the fly as the task is executed, but of course any invalid settings or overrides that are not appropriate will fail first before the task is executed.

(Davide Cavestro) #6

Thanks Warren, you depicted a very powerful solution.

I’ve not tried yet, but I was just wondering if gradle CLI parser could somewhat be more friendly in a scenario where I use groovy CLIBuilder from a gradle script in order to automatically populate project properties (or whatever machinery used to propagate user config).

I thought about CLIBuilder cause it would easily improve CLI user experience producing comfortable usage/validation messages.

I guess currently I have to wrap that script-local arguments as a single property value in order to pass them to gradle, something like

./gradlew -Pscriptargs="–arg1 --arg2" [gradle cli options] while it could be easier if we could do

./gradlew [gradle cli options] --scriptargs --arg1 --arg2

Just my two cents

(Matias Bjarland) #7

I would like to chime in with a related idea which we are thinking of implementing for our internal build logic. We would like to have something similar to git where you can type “git help log” and get an extensive help page on the “log” command. I.e. live, in-line, context sensitive help on the available commands which in gradle-world translates to tasks.

So you could type something along the lines of:

gradle help myCustomTaskName

and have gradle produce a print out with a help page for the task in question. Essentially a man page, but probably with a more terse format suitable for in-line display on the command line. Some things that this page could contain are:

  • A description of what the task does * A list of the available settings for the task. Essentially this is what the DSL reference does in html.

  • A display of the actual configured settings currently active for that task (if this is feasible). * An example task usage.

  • Potentially links to online dsl references or user guides (either gradleware or third party) with more information on the usage of this task. * The runtime task dependencies. These can and often do differ from the dependencies declared using “dependsOn”. Build scripts have the power to use expressions like:

tasks.withType(Test) { it.dependsOn someTask }

where the actual configuration of the task can live in one build file and the withType call in an entirely different one. This makes it hard to have transparency into what the actual dependencies of the task are. Something like the above would solve this.

…etc. I think you get the picture.

This could be implemented in a number of ways, but shooting from the hip perhaps either different “self documenting” base class for tasks or a couple of annotations together with javadoc extraction ala dsl reference would work.