Gradle и maven enforcer

Written by elwood

Те, кто плотно пользуются мавном, наверняка знают и активно используют плагин maven enforcer. Если включить проверку DependencyConvergence, то плагин будет проверять проект на отсутствие конфликтов между версиями используемых артефактов:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>1.0.1</version>
    <executions>
        <execution>
            <id>enforce</id>
            <configuration>
                <rules>
                    <DependencyConvergence />
                </rules>
            </configuration>
            <goals>
                <goal>enforce</goal>
            </goals>
        </execution>
    </executions>
</plugin>

У него есть ещё проверки, но самая важная именно эта. Например, в проекте используется log4j версии 1.2, а какая-то библиотека в одной из транзитивных зависимостей ссылается на log4j 1.1, то enforcer ругнётся во время сборки. После этого программист увидит проблему и пойдёт чинить. Как правило, для решения траблы достаточно замаскировать часть транзитивных зависимостей с помощью exclude. Если же этого не сделать, а отключить enforcer, то в билд попадут обе зависимости: и log4j:1.2, и log4j:1.1, что не очень хорошо, так как то, какая версия будет реально использована, зависит лишь от порядка его нахождения в classpath.

В gradle же по умолчанию работает следующая схема. Если есть конфликт, то будет использована крайняя версия артефакта, и дублей в результирующем билде не будет. И — черт возьми — в 99% случаев это именно то, что надо ! Но душа взывает к возможности полного контроля за ситуацией. Хочется, чтобы при появлении конфликтующей зависимости программист сразу об этом узнал и на всякий случай проверил ещё раз руками. Если у вас такая же параноя — вы можете установить другой режим разрешения конфликтов (благо грейдл это позволяет):

configurations.all {
   resolutionStrategy {
      // Fail eagerly on version conflict (includes transitive dependencies)
      // e.g. multiple different versions of the same dependency (group and name are equal)
      failOnVersionConflict()
   }
}

Всё, теперь сборка будет фейлиться при появлении конфликтов. Разрешать эти конфликты вам придётся самостоятельно, опять же с помощью exclude’ов, либо пользуясь force-установкой версий артефактов (см. документацию).

Единственный минус этой схемы по сравнению с maven enforcer в том, что enforcer вываливает все конфликты сразу, а gradle будет фейлиться на каждом конфликте по одному 🙂 В общем, занятие чистить руками конфликты это минимум на полчаса ковыряний с gradle :dependencies.

А вообще, режим градла по умолчанию очень разумный, в принципе, можно ничего и не трогать, всё будет работать (почти всегда).