217

From Gradle's documentation:

The scripts generated by this task are intended to be committed to your version control system. This task also generates a small gradle-wrapper.jar bootstrap JAR file and properties file which should also be committed to your VCS. The scripts delegates to this JAR.

From: What should NOT be under source control?

I think generated files should not be in the VCS.

When are gradlew and gradle/gradle-wrapper.jar needed?

Why not store a gradle version in the build.gradle file?

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
farmer1992
  • 7,816
  • 3
  • 30
  • 26
  • 1
    What might be an interesting side discussion, given the answers below, is the usefulness of these files if you're using some form of continuous integration tool. Which ones will check for grade-wrapper and use it if it's there? – lilbyrdie Jun 01 '15 at 16:19

6 Answers6

178

Because the whole point of the gradle wrapper is to be able, without having ever installed gradle, and without even knowing how it works, where to download it from, which version, to clone the project from the VCS, to execute the gradlew script it contains, and to build the project without any additional step.

If all you had was a gradle version number in a build.gradle file, you would need a README explaining everyone that gradle version X must be downloaded from URL Y and installed, and you would have to do it every time the version is incremented.

mernst
  • 7,437
  • 30
  • 45
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 144
    That's stupid. gradle-wrapper.jar shouldn't be needed on the VCS. Gradle should be able to download any version once you installed a first one, if needed. The toolchain has nothing to do on a VCS… I understand your answer is right, and it's Gradle's design. But this design is absurd. – Marc Plano-Lesay Dec 07 '13 at 13:10
  • 33
    The point is to be able to download gradle **without having installed gradle** before. What's the problem in having a 50KB-large file in the VCS? – JB Nizet Dec 07 '13 at 13:55
  • 90
    The problem is that it's not a part of the project. It's a tool you use to build the project. You won't store the JDK in VCS, would you? Nor GCC for a C application? So why would you store a Gradle part? If a developer is unable to read and install Gradle himself, that's another problem. – Marc Plano-Lesay Dec 07 '13 at 14:00
  • 14
    The build file is also not part of the project. It's also only used to build the project. The README that nobody reads and which has to explain which version of Maven/Gradle you have to install to build the project is also not part of the project. It's only used to build the project. The problem is not in being unable to install Gradle. The problem is to have to answer to bug reports from developers having installed Gradle 1.8 and who can't build the project because it's supposed to be built with Gradle 1.9. – JB Nizet Dec 07 '13 at 14:32
  • 35
    The problem is also that you can't remember, 2 years after it has been released, which version of Gradle was used to build the v1.0 version of your software, that you have to hotfix for a customer which is still using this 1.0 version and can't upgrade. The gradle wrapper solves that: you clone the 1.0 tag from the VCS, build it using gradlew, and it uses the gradle version that was used 2 years ago to build the 1.0 version. – JB Nizet Dec 07 '13 at 14:34
  • 48
    I agree that the Gradle version to be used needs to be indicated somewhere in the project. But Gradle is an *external* tool, nothing comparable with a README or anything you listed. Gradle should be able to fetch the corresponding version itself, without having to store a jar on the VCS. – Marc Plano-Lesay Dec 07 '13 at 14:54
  • 6
    How could gradle do anything if gradle is not even installed? Anyway, nobody forces you to use the wrapper. If you prefer specifying which gradle version to install, where to download it from, how to configure it, and redo that and change environment variables each time you switch your environment or branch, you can. – JB Nizet Dec 07 '13 at 14:59
  • 6
    What I mean is that you should be able, having any Gradle version installed, to download/install automatically a specific version if needed, without having to store anything on the VCS excepted the Gradle version number. Having to store it on the VCS when Gradle could do this by itself… – Marc Plano-Lesay Dec 07 '13 at 15:01
  • 29
    This was an interesting conversation to read. In my experience the gradle wrapper works very well and eases project import and configuration a lot. Sometimes, by having it under source control you can avoid a lot of other files that would be required to setup a project (for example in Android Studio). Although I understand why @Kernald thinks it's "stupid", if you think about it, at the end of the day most of the repos include several pieces that are not "part of the project" but still very handy. And sometimes it's important to be less theoretically perfect and more pragmatic. – cprcrack Oct 12 '14 at 02:49
  • 7
    One comment above mentioned that you wouldn't put the JDK in version control. I think that's where we need a definition of "project", too. What most people are referring to as a project here is actually just the source code part of the project on a single platform. In very controlled world, like in some enterprise and government world, one might actually find it very desirable to keep all external references and tools in internal source control for a very reliable level of reproduction of all builds. Having correct tools for this is critical, whether it's a build tool or image processor. – lilbyrdie Jun 01 '15 at 16:13
  • 2
    It's so simple... If you like the wrapper, use it and commit it to VCS. If not, don't use it or don't commit it!!! Gradle works without it, if you have it installed. – Italo Borssatto Jan 25 '16 at 22:38
  • 7
    _What's the problem in having a 50KB-large file in the VCS?_ One problem is that full copies of the file are kept each time the file is changed. When the file is large it’ll drastically increase the size of the repository (and therefore time and size of clones) over time assuming the file is updated. With a shared Git environment (i.e. in an enterprise) with hundreds and thousands of Git repositories, this would slowly have a detrimental effect to performance and would provoke the need for additional scaling earlier than necessary. – Jesse Nov 20 '16 at 04:07
  • 1
    1) The file isn't large 2) If you don'T want to use wrapper and keep gradle to be purely an external build tools, then DO IT. I don't get why everyone is freaking out, wrapper is an _opportunity_ to simplify the setup by storing a little file in VCS, but you don't have to use it. Gradle can also work like Maven or Ant, from local installation, but then every contributor has to install the build tool themselves. – xeruf Oct 07 '18 at 13:22
  • The Gradle project itself, which very frequently updates its wrapper, [has updated over 270 times with a max footprint of 14 MB](https://github.com/gradle/gradle/issues/6632#issuecomment-418805607). I wouldn't consider that a lot of space, especially when a commenter determines that Git compression [performs well on binaries, too](https://github.com/gradle/gradle/issues/6632#issuecomment-418988402). IMO the Gradle wrapper is a pragmatic approach for achieving more hermetic builds. If you could easily (and with no cost) have all of your dependencies in the source tree, wouldn't you? – mkobit Nov 20 '18 at 22:41
  • The Gradle Wrapper is **NOT** Gradle. – Gi0rgi0s May 07 '19 at 17:10
  • 6
    The solution is this: The `gradlew` script detects the version of the gradle JAR (as specified in a value in `settings.gradle`) isn't present, downloads it then executes it. The JAR is stored in the `.gradle` directory (rather than `gradle`) and `.gradle` is in `.gitignore`. Alternately, the script could detect if Docker is installed, and use a gradle image (which also means the local machine wouldn't even need Java installed). CI ppl rejoice! The only tooling extra that needed to be in the source code repo would be the fairly straightforward shell-only wrapper script, not the binary. – delitescere Oct 09 '19 at 04:21
  • 1
    Now I know why I never use Gradle. – 6infinity8 Dec 21 '21 at 12:14
  • 2
    One thing I don't get is why the gradle wrapper isn't just a script that uses curl to download any binaries it needs, why it has to have a jar binary to bootstrap itself. Sure, that would mean depending on curl, but Windows has a curl and Linux usually has it installed, and it would be far more palitable to checkin to the repository a few extra lines of script than an actual .jar binary. – xpusostomos Jan 22 '22 at 20:37
  • 2
    If the gradle wrapper functionality lived in a shell script, not a jar, this wouldn't even be a discussion. Everyone would happily commit the little shell script to VCS. – Andrew Feb 20 '22 at 04:41
97

Because the whole point of the Gradle wrapper is to be able, without having ever installed Gradle

Same argument goes for the JDK, do you want to commit that also? Do you also commit all your dependency libraries?

The dependencies should be upgraded continuously as new versions are released to get security and other bug fixes, and because if you get to far behind it can be a very time consuming task to get up to date again.

If the Gradle wrapper is incremented for every new release, and it is committed, the repo will grow very large. The problem is obvious when working with distributed VCS where a clone will download all versions of everything.

and without even knowing how it works

Create a build script that downloads the wrapper and uses it to build. Everyone does not need to know how the script works, they need to agree that the project is build by executing it.

where to download it from, which version

task wrapper(type: Wrapper) {
  gradleVersion = 'X.X' 
}

for Gradle version >= 5:

wrapper {
  gradleVersion = 'X.X' 
}

and then

gradle wrapper

to download the correct version.

to clone the project from the VCS, to execute the gradlew script it contains, and to build the project without any additional step.

Solved by the steps above. Downloading the Gradle wrapper is not different from downloading any other dependency. The script could be smart enough to check for any current Gradle wrapper and only download it if there is a new version.

If the developer has never used Gradle before and maybe doesn't know the project is built with Gradle, then it is more obvious to run a build.sh compared to running gradlew build.

If all you had was a gradle version number in a build.gradle file, you would need a README explaining everyone that gradle version X must be downloaded from URL Y an installed,

No, you would not need a README. You could have one, but we are developers and we should automate as much as possible. Creating a script is better.

and you would have to do it every time the version is incremented.

If the developers agree that the correct process is to:

  1. Clone repo
  2. Run build script

Then there upgrading to latest Gradle wrapper is no problem. If the version is incremented since last run, the script could download the new version.

mauris
  • 42,982
  • 15
  • 99
  • 131
Tomas Bjerre
  • 3,270
  • 22
  • 27
  • 3
    "The dependencies should be upgraded continuously." Yes, in a forward looking direction. No, in a backward looking direction. To reproduce an old build, you need to have specific versions of the dependencies. Gradle makes some types of projects faster and easier to deal with. It would be a mess in an organization that needed reproduction and auditing. – lilbyrdie Jun 01 '15 at 16:16
  • 6
    Not really sure what you mean. But if you have `build.gradle` in version control and in it you have: `task wrapper(type: Wrapper) { gradleVersion = 'X.X' }` Then `gradle wrapper` will download the wrapper that was used, and you can reproduce the old build. – Tomas Bjerre Jan 07 '16 at 15:27
  • 1
    Was referring to your line about the dependencies, not the gradle version. Sure, you want your libraries to have all the latest security and bug fixes but NOT when you're trying to reproduce an old build, maybe for auditing or legal purposes. You want your libraries and build process to be able to produce a binary identical output, if at all possible. As with a library dependency, there's no guarantee that a specific version would be available at the time of building... be it 2 weeks from now or 2 decades from now. So yes, it is the same as libraries and SDKs, for some projects. – lilbyrdie Jan 07 '16 at 16:50
  • 1
    @lilbyrdie since the dependencies are versioned and those versions are specified in the build file (gradle in this case), presumably when doing an older build you'd have the older build file and this get the right (older) dependencies. You're seeming to raise an issue that I'm honestly not able to follow. – sofend Dec 20 '16 at 18:29
  • 4
    I think the wrapper is there primarily for historic reason. In the beginning everyone is using Maven, and nobody has Gradle installed. It would be difficult to persuade co-worker to install unknown intrusive dependencies, so the wrapper helps them bootstrap. Nowadays everyone has Gradle already, and the wrapper becomes redundant. – Franklin Yu Nov 22 '17 at 15:56
  • 4
    Are you suggesting to execute `gradle wrapper` after clone on every build? This basically makes wrapper useless, because its whole point is that you _do not have to install Gradle locally to build the project_! – xeruf Oct 07 '18 at 13:24
  • 1
    _"Same argument goes for the JDK, do you want to commit that also? Do you also commit all your dependencie libraries?"_ You haven't provided any reasoning against doing this. Having everything under source control provides for a hermetic and reproducible build at all times, compared to relying on external services you can't always rely on. Why wouldn't you want that? The pragmatic approach for most developers and tools today does end up somewhere in the middle, but there are plenty of reasons to be able to have a hermetic build by checking in binaries. – mkobit Nov 20 '18 at 22:48
  • This answers makes more sense than the answer with highest upvotes. – Manu Manjunath Jan 02 '19 at 06:39
  • @mkobit Seriously, if your team checks in JDK then of course Gradle wrapper should be checked in. – Franklin Yu Feb 27 '19 at 21:15
  • 3
    Since Gradle 5, it should be `wrapper` instead of `task wrapper(type: Wrapper)`. See [this answer](https://stackoverflow.com/questions/53709282/cannot-add-task-wrapper-as-a-task-with-that-name-already-exists/54741656#54741656) for details. – Franklin Yu Feb 27 '19 at 22:30
  • @FranklinYu Yess, a version of installed gradle can be different from the syntax used in the build.gradle as you can see how wrapper syntax changed. `gradle wrapper` wont work with all versions of gradle and that is why gradlew script is needed in the first place to serve as a wrapper over all versions of gradle. – Mukul Anand Jul 08 '20 at 07:14
51

I would like to recommend a simple approach.

In your project's README, document that an installation step is required, namely:

gradle wrapper --gradle-version 3.3

This works with Gradle 2.4 or higher. This creates a wrapper without requiring a dedicated task to be added to "build.gradle".

With this option, ignore (do not check in) these files/folders for version control:

  • ./gradle
  • gradlew
  • gradlew.bat

The key benefit is that you don't have to check-in a downloaded file to source control. It costs one extra step on installation. I think it is worth it.

David J.
  • 31,569
  • 22
  • 122
  • 174
  • 28
    why would you need wrapper then? The whole idea of wrapper is that you can build project without having gradle on your system. – edio Nov 21 '17 at 21:06
  • 6
    Nice solution. No binaries in git and still an ability to use `gradlew`. @edio you will need it to download and use a *specific* version of gradle. – Kirill Mar 18 '18 at 21:59
  • 1
    I like this solution. @edio the reason why the wrapper is still needed is because running gradle and running gradlew will not necessarily result in the same build. You use gradle (possibly some random version) to install the project-specific gradlew, then use that to build. – Max Sep 14 '21 at 17:23
  • "Don't do X" is not an answer to the question "Why should I do X?" // SO being SO at its finest – Arthur Khazbs Jun 25 '22 at 20:48
  • Can you share any popular repos using this approach? – theonlygusti Jun 18 '23 at 23:02
12

According to Gradle docs, adding gradle-wrapper.jar to VCS is expected as making Gradle Wrapper available to developers is part of the Gradle approach:

To make the Wrapper files available to other developers and execution environments you’ll need to check them into version control. All Wrapper files including the JAR file are very small in size. Adding the JAR file to version control is expected. Some organizations do not allow projects to submit binary files to version control. At the moment there are no alternative options to the approach.

Arthur Khazbs
  • 705
  • 8
  • 19
  • 4
    Unfortunately, this sentence ("Adding the JAR file to version control is expected.") doesn't help much; only saying "X is expected" is not persuasive. There are many ways to make code available to developers; there is no need to assume all code must be in available in the project-at-hand's VCS. Many organizations have in-house artifact servers, for example. / On another note, the Q&A discussion here on SO is more substantive -- people are *digging in* to the rationale. – David J. Sep 17 '21 at 13:53
6

What is the "project"?

Maybe there is a technical definition of this idiom that excludes build scripts. But if we accept this definition, then we must say your "project" is not all the things that you need to versioned!

But if we say "your project" is everything you have done. Then we can say you must include it and only it into VCS.

This is very theoretical and maybe not practical in case of our development works. So we change it to "your project is every file (or folder) you need to editing them directly".

"directly" means "not indirectly" and "indirectly" means by editing another file and then an effect will be reflected into this file.

So we reach the same that OP said (and is said here):

I think Generated files should not be in the VCS.

Yes. Because you haven't created them. So they are not part of "your project" according to the second definition.


What is the result about these files:

  • build.gradle: Yes. We need to edit it. Our works should be versioned.

    Note: There is no difference where you edit it. Whether in your text editor environment or in Project Structure GUI environment. Anyway you doing it directly!

  • gradle-wrapper.properties: Yes. We need to at least determine Gradle version in this file.

  • gradle-wrapper.jar and gradlew[.bat]: I haven't created or edited them in any of my development works, till this moment! So the answer is "No". If you have done so, the answer is "Yes" about you at that work (and about the same file you edited).


The important note about the latest case is the user who clones your repo, needs to execute this command on repo's <root-directory> to auto-generate wrapper files:

> gradle wrapper --gradle-version=$v --distribution-type=$distType

$v and $distType are determined from gradle-wrapper.properties:

distributionUrl=https\://services.gradle.org/distributions/gradle-{$v}-{$distType}.zip

See https://gradle.org/install/ for more information.

gradle executable is bin/gradle[.bat] in local distribution. It's not required that local distribution be same as that determined in the repo. After wrapper files created then gradlew[.bat] can download determined Gradle distribution automatically (if not exists locally). Then he/she probably must regenerate wrapper files using new gradle executable (in downloaded distribution) using above instructions.


Note: In the above instructions, supposed the user has at least one Gradle distribution locally (e.g. ~/.gradle/wrapper/dists/gradle-4.10-bin/bg6py687nqv2mbe6e1hdtk57h/gradle-4.10). It covers almost all real cases. But what happens if the user hasn't any distribution already?

He/She can download it manually using the URL in .properties file. But if he/she doesn't locate it in the path that the wrapper expected, the wrapper will download it again! The expected path is completely predictable but is out of the subject (see here for the most complex part).

There are also some easier (but dirty) ways. For example, he/she can copy wrapper files (except .properties file) from any other local/remote repository to his/her repository and then run gradlew on his/her repository. It will automatically download the suitable distribution.

Mir-Ismaili
  • 13,974
  • 8
  • 82
  • 100
5

Old question, fresh answer. If you don't upgrade gradle often (most of us don't), it's better to commit it to VCS. And the main reason for me is to increase the build speed on the CI server. Nowadays, most of the projects are getting built and installed by CI servers, different server instance every time.

If you don't commit it, CI server will download a jar for every build and it significantly increases a build time. There are other ways to handle this problem, but I find this one the easiest to maintain.

smgn
  • 59
  • 1
  • 3
  • 5
    Modern pipelines have to have build caches. No need to pollute VCS with reproducible binaries. On other hand `gradle/gradle-wrapper.jar` is not frequently changed even across major Gradle releases. – gavenkoa Jan 19 '21 at 15:00