{"id":573,"date":"2019-01-26T08:14:25","date_gmt":"2019-01-26T13:14:25","guid":{"rendered":"http:\/\/jebware.com\/blog\/?p=573"},"modified":"2020-06-05T11:10:01","modified_gmt":"2020-06-05T16:10:01","slug":"save-time-and-reduce-risk-with-gradles-includegroup","status":"publish","type":"post","link":"https:\/\/jebware.com\/blog\/?p=573","title":{"rendered":"Save time and reduce risk with Gradle\u2019s includeGroup"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">With the recently released version 5.1, Gradle has added a great, subtle new feature that lets you specify which dependencies should be pulled from which repositories. &nbsp;To explain what this is, let\u2019s start with the default behavior. In your Gradle file, you probably have multiple repositories defined, like this:<\/span><\/p>\n<p><a href=\"http:\/\/jebware.com\/blog\/wp-content\/uploads\/2019\/01\/normal-repos.png\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-574\" src=\"http:\/\/jebware.com\/blog\/wp-content\/uploads\/2019\/01\/normal-repos.png\" alt=\"\" width=\"336\" height=\"313\"><\/a><span style=\"font-weight: 400;\">When Gradle needs to find a dependency, it will search each of those repositories, in the order they are declared. &nbsp;So when it goes to download, for example, [com.android.support.constraint:constraint-layout:1.1.3], it will first check the Google repo, which has that artifact, so it\u2019s done. &nbsp;But then let\u2019s say you want RxJava: [io.reactivex.rxjava2:rxjava:2.1.9]. Gradle checks for it in the Google repo, but Google responds with a HTTP 404 error, so Gradle moves on to the next repository, which is JCenter. &nbsp;And on and on, for each dependency in your build.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This can lead to a couple of problems:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">There\u2019s a performance problem. &nbsp;Since you have to check each repository in order for each dependency, there are a lot of requests that return a 404, and you waste time and resources. &nbsp;Wouldn\u2019t it be nice if we could tell Gradle \u201coh, I know RxJava is on JCenter, so don\u2019t bother checking the Google repository\u201d?<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">If a repository that\u2019s first in the list gives a bad response (like the time JCenter responded to Google artifacts with an HTTP 409 error). Gradle will give up, and not check other repositories. &nbsp;This will break your build, and leads to a lot of advice like \u201cmake sure you list the Google repository first!\u201d<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">You\u2019re vulnerable to a spoofing attack. &nbsp;If you have a dependency that\u2019s in your last repository (fabric in the example above), but a malicious actor uploads a library with the same group and artifact names to JCenter, for example, Gradle will download the JAR from JCenter since it\u2019s higher in the list, and you\u2019ll never know the difference. &nbsp;JCenter doesn\u2019t do much to verify that you are who you say you are, so this type of attack is a real risk.<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">So how do we resolve this? &nbsp;<a href=\"https:\/\/docs.gradle.org\/5.1.1\/release-notes.html#repository-to-dependency-matching\">Gradle 5.1 adds a new API so you can specify which groups to include or exclude in a repository<\/a>. &nbsp;A quick note about what I mean by groups: it\u2019s the bit before the first colon in a Gradle coordinate.<\/span><\/p>\n<p><a href=\"http:\/\/jebware.com\/blog\/wp-content\/uploads\/2019\/01\/coordinates-annotated.png\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-575\" src=\"http:\/\/jebware.com\/blog\/wp-content\/uploads\/2019\/01\/coordinates-annotated.png\" alt=\"\" width=\"569\" height=\"138\"><\/a><\/p>\n<p><span style=\"font-weight: 400;\">So in practice, your build.gradle might now look something like this &#8211; note that you can match groups exactly or with a regular expression:<\/span><\/p>\n<p><script src=\"https:\/\/gist.github.com\/jebware\/506a4442d98f0da736732ca5d23d877d.js\"><\/script><\/p>\n<p><span style=\"font-weight: 400;\">Now, when Gradle goes to download constraint layout, it will match the regex on the google repo, and Gradle will never attempt to download it from another repository. &nbsp;Likewise, even though the Google maven repository is listed first, Gradle won\u2019t attempt to download RxJava from it, because it\u2019s not listed in the include groups.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">If you want to test this, try running a Gradle task with \u201c&#8211;refresh-dependencies\u201d, which will force Gradle to try to download all of your dependencies again. &nbsp;If you get an error like this one then you know you still need to work on your configuration.<\/span><\/p>\n<pre><span style=\"font-weight: 400;\">&gt; Could not resolve all files for configuration ':app:debugCompileClasspath'.<\/span>\n<span style=\"font-weight: 400;\"> &nbsp;&nbsp;&gt; Could not find io.reactivex.rxjava2:rxjava:2.2.2.<\/span><\/pre>\n<p><span style=\"font-weight: 400;\">The important thing to know about includes and excludes is that the behavior is defined per repository.<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">If you list an include &#8211; Gradle will only try to download the included groups for this repository.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">If you list an exclude &#8211; Gradle will try any groups <em>except<\/em>&nbsp;the excluded groups for this repository.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">If you list includes and excludes &#8211; Gradle will download only groups that are included <em>and not<\/em>&nbsp;excluded.<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">There\u2019s one non-obvious thing that I want to really emphasize, though: &nbsp;If you specify includeGroups on repo but don\u2019t specify any groups on a second repo, like the screenshot below, Gradle will still try to download com.google artifacts from both of these repositories. &nbsp;The options you declare for one repository <em>don\u2019t affect other repositories<\/em>.<\/span><\/p>\n<p><a href=\"http:\/\/jebware.com\/blog\/wp-content\/uploads\/2019\/01\/good-and-bad-annotated.png\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-576\" src=\"http:\/\/jebware.com\/blog\/wp-content\/uploads\/2019\/01\/good-and-bad-annotated.png\" alt=\"\" width=\"597\" height=\"457\"><\/a><\/p>\n<p><span style=\"font-weight: 400;\">This leads to my last, but perhaps most important piece of advice: whitelist every group. &nbsp;The best way I can see to use this is to include <em>every<\/em>&nbsp;group in the appropriate repository, and make sure every listed repository has an includeGroup declared. &nbsp;This will force Gradle to download each dependency from the <em>right<\/em> repository <em>only<\/em>.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>With the recently released version 5.1, Gradle has added a great, subtle new feature that lets you specify which dependencies should be pulled from which repositories. &nbsp;To explain what this is, let\u2019s start with the default behavior. In your Gradle file, you probably have multiple repositories defined, like this: When Gradle needs to find a &hellip; <a href=\"https:\/\/jebware.com\/blog\/?p=573\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Save time and reduce risk with Gradle\u2019s includeGroup&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_mi_skip_tracking":false,"twitterCardType":"summary_large_image","cardImageID":0,"cardImage":"http:\/\/jebware.com\/blog\/wp-content\/uploads\/2019\/01\/good-and-bad-annotated.png","cardTitle":"","cardDesc":"","cardImageAlt":"","cardPlayer":"","cardPlayerWidth":0,"cardPlayerHeight":0,"cardPlayerStream":"","cardPlayerCodec":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/jebware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/573"}],"collection":[{"href":"https:\/\/jebware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jebware.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jebware.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jebware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=573"}],"version-history":[{"count":4,"href":"https:\/\/jebware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/573\/revisions"}],"predecessor-version":[{"id":624,"href":"https:\/\/jebware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/573\/revisions\/624"}],"wp:attachment":[{"href":"https:\/\/jebware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=573"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jebware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=573"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jebware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=573"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}