Рекомендуется выполнять сборку Gradle с помощью утилиты Gradle Wrapper (далее коротко просто "Wrapper"). Wrapper это скрипт, который берет декларируемую версию Gradle и перед сборкой загрузит её при необходимости. В результате разработчики могут быстро получить рабочий компилируемый проект Gradle без исследования руководства по инсталляции, что экономит время и деньги вашей компании.
Рис. 1. Рабочий процесс Wrapper.
В двух словах вы получаете следующие преимущества:
· Стандартизирует проект на данной версии Gradle, что позволяет создавать более надежные и устойчивые сборки. · Предоставление новой версии Gradle различным пользователям и средам разработки (например, IDE или серверам непрерывной интеграции) осуществляется так же просто, как и изменение определения Wrapper.
Так как же это работает? Для пользователя обычно существует три различных рабочих процесса:
· Вы настраиваете новый проект Gradle, и хотите добавить к нему Wrapper. · Вы хотите запустить проект с помощью Wrapper, который уже предоставлен для проекта. · Вы хотите обновить Wrapper для новой версии Gradle.
В последующих секциях описывается более подробно каждый из этих случаев.
[Добавление Gradle Wrapper]
Генерация файлов Wrapper требует установленную на вашем компьютере Gradle runtime, как это описано в разделе установки Gradle [2]. К счастью, создание начальных файлов Wrapper является однократным процессом.
Каждая сборка Gradle поставляется со встроенной задачей (task), которая называется wrapper. При перечислении задач можно найти задачу, указанную в группе "Задачи установки построения". Выполнение задачи обертки создает необходимые файлы обертки в каталоге проекта. Эту задачу можно найти в группе "Build Setup tasks", если вывести список задач. Выполнение задачи wrapper генерирует необходимые файлы Wrapper в каталоге проекта.
{spoiler tutle=Получение списка задач Gradle opened=0}
Запуск команды gradle tasks выдаст список основных задач выбранного проекта. Этот отчет покажет задачи по умолчанию (default tasks) для проекта, если они существуют, и описание для каждой задачи.
По умолчанию отчет этой команды покажет только те задачи, которые были назначены группе задач. Вы можете получить больше информации в списке задач, используя опцию --all.
Если нужна более конкретная информация, то можно отобразить только задачи из определенной группы, используя опцию --group.
$ gradle tasks --group="build setup"
Подробное описание интерфейса командной строки Gradle см. в [3].
{/spoiler}
Запуск задачи Wrapper:
$ gradle wrapper
> Task :wrapper
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
Замечание: чтобы сделать файлы Wrapper доступными для других разработчиков и сред выполнения, необходимо добавить их в репозиторий системы управления версиями. Размер всех файлов Wrapper, включая JAR-файл, очень мал. Подразумевается добавление также и JAR-файла в систему управления версиями. Некоторые организации не разрешают проектам передавать двоичные файлы в систему управления версиями. Однако на данный момент альтернативных вариантов нет.
Информация о дистрибутиве Gradle сохраняется в файле свойств Wrapper: gradle/wrapper/gradle-wrapper.properties.
· На сервере организуется хостинг дистрибутива Gradle. · Устанавливается тип дистрибутива Gradle. По умолчанию это дистрибутив bin, который содержит только runtime-код, но не образец кода и документацию. · Версия Gradle используется для выполнения сборки. По умолчанию задача wrapper берет точно ту же версию Gradle, которая использовалась для генерации файлов Wrapper.
Опционально устанавливается таймаут в миллисекундах, когда загружается дистрибутив gradle.
gradle/wrapper/gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
Все эти аспекты конфигурируются в момент генерации файлов Wrapper с помощью следующих опций командной строки.
--gradle-version
Версия Gradle используется для загрузки и выполнения Wrapper. Разрешены следующие метки (labels):
· latest · release-candidate · nightly · release-nightly
--distribution-type
Тип дистрибутива Gradle, используемый для Wrapper. Доступные опции bin и all. ПО умолчанию используется bin.
--gradle-distribution-url
Полный URL, указывающий на ZIP-файл дистрибутива Gradle. Использование этой опции делает опции --gradle-version и --distribution-type устаревшими, поскольку URL уже содержит эту информацию. Опция --gradle-distribution-url очень важна, если вы хотите реализовать хостинг дистрибутива Gradle в внутри сетевой инфраструктуры компании.
--gradle-distribution-sha256-sum
Хэш-сумма SHA256, используемая для верификации загруженного дистрибутива Gradle.
--network-timeout
Таймаут сети, используемый при загрузке дистрибутива gradle, в мс. Значение по умолчанию 10000.
Пример установки опций для задачи Wrapper. Для иллюстрации использования опций командной строки предположим следующий случай. Вы хотите генерировать Wrapper версии 8.1.1 , и используете дистрибутив all, чтобы позволить вашей IDE функцию code-completion для навигации по исходному коду Gradle. Эти требования реализуются следующей командной строкой:
$ gradle wrapper --gradle-version 8.1.1 --distribution-type all
> Task :wrapper
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
Результат этой команды вы найдете в файле свойств Wrapper.
Пример генерации URL дистрибутива:
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip
Давайте взглянем на следующую структуру проекта для иллюстрации ожидаемых файлов Wrapper. На Kotlin она будет выглядеть так (на Groovy будет то же самое, просто у файлы build.gradle.kts и settings.gradle.kts будут без суффикса .kts):
. ├── a-subproject │ └── build.gradle.kts ├── settings.gradle.kts ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew └── gradlew.bat
Проект Gradle обычно предоставляет файл settings.gradle(.kts) и по одному файлу build.gradle(.kts) для каждого субпроекта. Файлы Wrapper находятся рядом в каталоге gradle и корневом каталоге проекта. В следующем списке объясняется их назначение.
gradle-wrapper.jar JAR-файл Wrapper, содержащий код для загрузки дистрибутива Gradle.
gradle-wrapper.properties Файл свойств, отвечающий за конфигурирование runtime-поведение Wrapper, например определение версии Gradle, совместимой с этой версией Wrapper. Обратите внимание, что более общие настройки, такие как конфигурирование Wrapper для использования прокси, должны переходить в другой файл настроек.
gradlew, gradlew.bat Шелл-скрипт и командный файл Windows для выполнения сборки с помощью Wrapper.
Можно выполнить построение с помощью обертки без установки среды выполнения Gradle. Если проект, с которым вы работаете, не содержит эти файлы Wrapper, их необходимо сгенерировать.
[Использование Gradle Wrapper]
Рекомендуется всегда выполнять сборку с помощью Wrapper, чтобы гарантировать управляемое и стандартизированное выполнение сборки. Использование Wrapper выглядит почти как сборка с инсталляцией Gradle. В зависимости от операционной системы вы можете запустить либо gradlew, либо gradlew.bat вместо команды gradle. Следующий вывод консоли демонстрирует использование Wrapper на Windows для проекта, основанного на Java.
$ gradlew.bat build
Downloading https://services.gradle.org/distributions/gradle-5.0-all.zip
.....................................................................................
Unzipping C:\Documents and Settings\имяпользователя\.gradle\wrapper\dists\gradle-5.0-all\
ac27o8rbd0ic8ih41or9l32mv\gradle-5.0-all.zip to C:\Documents and Settings\имяпользователя\
.gradle\wrapper\dists\gradle-5.0-al\ac27o8rbd0ic8ih41or9l32mv
Set executable permissions for: C:\Documents and Settings\имяпользователя\.gradle\wrapper\
dists\gradle-5.0-all\ac27o8rbd0ic8ih41or9l32mv\gradle-5.0\bin\gradle
BUILD SUCCESSFUL in 12s
1 actionable task: 1 executed
В случае, когда на машине нет дистрибутива Gradle, скрипт Wrapper загрузит его и сохранит в локальной файловой системе. Любые последующие сборки будут выполняться с использованием локального дистрибутива, пока не поменяется URL дистрибутива в свойствах Gradle.
Замечание: шелл-скрипт Wrapper и командный файл Windows находится в корневой директории сборки Gradle для одиночного проекта или проекта со множеством субпроектов (multi-project). Вам понадобится обращаться к правильному пути к этим файлам в случае, если хотите их выполнить сборку из подкаталога, где находится субпроект, например gradlew tasks.
[Обновление Gradle Wrapper]
Обычно проекты стараются держать свежими, чтобы обновлять версию Gradle и пользоваться добавленными нововведениями и улучшениями. Один из способов обновить версию Gradle - вручную поменять свойство distributionUrl в файле gradle-wrapper.properties, где находятся свойства Wrapper. Лучшая и рекомендуемая опция - запустить задачу Wrapper (wrapper task) и предоставить целевую версию Gradle, как это было описано выше в разделе "Добавление Gradle Wrapper". Использование wrapper task гарантирует, что для проекта применятся любые оптимизации, сделанные для шелл-скрипта Wrapper или командного файла, вместе со специальной, соответствующей версией Gradle. Как обычно, следует сделать фиксацию (commit) изменений в файлах обертки системы управления версиями.
Обратите внимание, что однократный запуск wrapper task обновит только gradle-wrapper.properties only, но оставит не измененным сам Wrapper в файле gradle-wrapper.jar. Это обычно нормально, поскольку новые версии Gradle могут быть запущены даже со старыми файлами Wrapper. Если вы все же хотите, чтобы все файлы Wrapper были полностью обновлены, вам потребуется запустить wrapper task второй раз.
Используйте Gradle wrapper task для генерации Wrapper, указав версию. По умолчанию используется текущая версия. Когда обновили wrapper, можете проверить, та ли версия была установлена, что вы ожидали, с помощью запуска команды ./gradlew --version.
Пример обновления Wrapper на последнюю версию:
$ ./gradlew wrapper --gradle-version lates
BUILD SUCCESSFUL in 4s
1 actionable task: 1 executed
Пример обновления Wrapper на определенную версию:
$ ./gradlew wrapper --gradle-version 8.1.1
BUILD SUCCESSFUL in 4s
1 actionable task: 1 executed
[Настройка под себя Gradle Wrapper]
Большинство пользователей Gradle вполне удовлетворены runtime-поведением Wrapper, установленном по умолчанию. Однако политики организаций, ограничения безопасности или пользовательские предпочтения могут потребовать углубиться в настройку Wrapper. К счастью, встроенная задаче wrapper предоставляет множество опций для подстройки runtime-поведения по вашим нуждам. Большинство опций конфигурации доступны из нижележащего типа задачи Wrapper [4].
Предположим, что вы устали определять -all для типа дистрибутива в командной строке каждый раз при обновлении Wrapper. Вы можете сэкономить для себя несколько клавиатурных нажатий путем переконфигурирования wrapper task.
Пример 1. Кастомизация Wrapper task, файл build.gradle.kts для Kotlin [7]:
tasks.wrapper {
distributionType = Wrapper.DistributionType.ALL
}
Файл build.gradle для Groovy:
tasks.named('wrapper') {
distributionType = Wrapper.DistributionType.ALL
}
С запущенной конфигурацией ./gradlew wrapper --gradle-version 8.1.1 достаточно предоставить значение distributionUrl в файле свойств Wrapper, который запросит дистрибутив -all.
Сгенерированный URL дистрибутива:
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip
См. документацию по API для получения более подробного описания доступных опций конфигурации. Вы также можете различные примеры конфигурирования Wrapper в дистрибутиве Gradle.
Аутентифицированная загрузка дистрибутива Gradle. Gradle Wrapper может загрузить дистрибутивы Gradle с серверов, используя HTTP Basic Authentication. Это позволит вам организовать хостинг дистрибутива Gradle на приватном защищенном сервере. Вы можете указать username и password двумя разными способами в зависимости от вашего варианта использования: в виде системных свойств, или путем прямого встраивания в distributionUrl. Параметр учетной записи в свойствах системы имеют преимущество над встроенным в distributionUrl.
Предупреждение безопасности: HTTP Basic Authentication должна использоваться только с HTTPS URL, но не с незащищенными HTTP. При Basic Authentication, данные учетной записи пользователя посылаются открытым текстом.
Использование системных свойств может быть реализовано в файле свойств .gradle/gradle.properties, находящегося в домашней директории пользователя, либо другими способами, см. раздел "Gradle properties" документации [5].
Указание логина и пароля для HTTP Basic Authentication, используя системные свойства:
systemProp.gradle.wrapperUser=username
systemProp.gradle.wrapperPassword=password
Встраивание логина и пароля в distributionUrl файла gradle/wrapper/gradle-wrapper.properties также работает. Имейте в виду, что этот файл попадает в фиксацию вашей системы управления версиями. Таким образом, в этом файле вы предоставляете другим пользователям данные учетной записи, так что distributionUrl следует использовать только в контролируемом рабочем окружении.
Указание логина и пароля для HTTP Basic Authentication в distributionUrl:
distributionUrl=https://username:password@somehost/path/to/gradle-distribution.zip
Это может использоваться совместно с прокси, с аутентификацией или без. См. раздел "Accessing the web via a proxy" документации [5] для дополнительной информации, как конфигурировать Wrapper для использования прокси.
Верификация загруженного дистрибутива Gradle. Gradle Wrapper позволяет выполнить проверку загруженного дистрибутива Gradle с помощью сравнения контрольной суммы хэша SHA-256. Это повышает безопасность против целевых атак типа man-in-the-middle, отключая злоумышленнику доступ к загруженному дистрибутиву Gradle.
Для разрешения этой фичи загрузите файл .sha256, связанный с дистрибутивом Gradle, который вы хотите проверить.
Загрузка файла SHA-256. Вы можете загрузить .sha256 из стабильного релиза, или release candidate и nightly-релизов. Формат этого файла - однострочный текст, который содержит хэш SHA-256 соответствующего zip-файла.
Вы можете также обратиться к списку контрольных сумм дистрибутива Gradle [6].
Конфигурирование верификации по контрольной сумме. Добавьте загруженную контрольную сумму хэша в gradle-wrapper.properties, используя свойство distributionSha256Sum, или используйте опцию --gradle-distribution-sha256-sum в командной строке.
Пример установки свойства distributionSha256Sum в файле gradle-wrapper.properties:
distributionSha256Sum=371cb9fbebbe9880d147f59bab36d61eee122854ef8c9ee1ecf12b82368bcf10
Gradle сообщит об ошибке сборки в случае, когда сконфигурированная контрольная сумма не совпадет с контрольной суммой, найденной на сервере хостинга дистрибутива. Checksum Verification выполняется, если сконфигурированный дистрибутив Wrapper пока еще не загружен.
Замечание: задача Wrapper остановится с ошибкой, если gradle-wrapper.properties содержит distributionSha256Sum, однако конфигурация задачи не определяет сумму. Выполнение задачи Wrapper сохраняет конфигурацию distributionSha256Sum, когда версия Gradle не поменялась.
[Проверка целостности Gradle Wrapper JAR]
Wrapper JAR это двоичный файл, который будет выполнен на компьютерах разработчиков и серверах сборки. Как и для всех таких файлов, перед их выполнением необходимо убедиться в том, что они заслуживают доверия. Поскольку Wrapper JAR обычно проверяется в системе контроля версий проекта, существует потенциальная возможность атаки злоумышленника для замены оригинального JAR модифицированным, путем отправки запроса извлечения из репозитория (pull request), который казалось бы только обновляет версию Gradle.
Для верификации целостности Wrapper JAR в Gradle создано GitHub Action, которое автоматически проверяет бинарники Wrapper JAR в pull-запросах по списку известных корректных контрольных сумм. Gradle также публикует контрольные суммы всех релизов (кроме версий от 3.3 до 4.0.2, которые не генерируют воспроизводимые бинарники JAR), так что вы можете вручную проверить целостность Wrapper JAR.
Автоматическая верификация Gradle Wrapper JAR на GitHub. GitHub Action выпущена в релиз отдельно от Gradle, поэтому см. его документацию по применению для своего проекта.
Верификация Gradle Wrapper JAR вручную. Вы можете сами проверить контрольную сумму Wrapper JAR, чтобы убедиться, что его бинарник не был взломан, запустив следующие команды на популярных операционных системах.
Linux:
$ cd gradle/wrapper
$ curl --location --output gradle-wrapper.jar.sha256 \
https://services.gradle.org/distributions/gradle-8.1.1-wrapper.jar.sha256
$ echo " gradle-wrapper.jar" >> gradle-wrapper.jar.sha256
$ sha256sum --check gradle-wrapper.jar.sha256
gradle-wrapper.jar: OK
macOS:
$ cd gradle/wrapper
$ curl --location --output gradle-wrapper.jar.sha256 \
https://services.gradle.org/distributions/gradle-8.1.1-wrapper.jar.sha256
$ echo " gradle-wrapper.jar" >> gradle-wrapper.jar.sha256
$ shasum --check gradle-wrapper.jar.sha256
gradle-wrapper.jar: OK
Windows (с использованием PowerShell):
> $expected = Invoke-RestMethod -Uri https://services.gradle.org/distributions/gradle-8.1.1-wrapper.jar.sha256
> $actual = (Get-FileHash gradle\wrapper\gradle-wrapper.jar -Algorithm SHA256).Hash.ToLower()
> @{$true = 'OK: Checksum match'; $false = "ERROR!`nExpected: $expected`nActual: $actual"}[$actual -eq $expected]
OK: Checksum match
Если контрольная сумма не совпала, то возможно wrapper task не была выполнена с обновленным дистрибутивом Gradle. Таким образом, вы должны сначала проверить, соответствует ли фактическая контрольная сумма одной из разных версий Gradle. Ниже приведены команды на основных операционных системах для генерации актуальной контрольной суммы Wrapper JAR.
Linux:
$ sha256sum gradle/wrapper/gradle-wrapper.jar
d81e0f23ade952b35e55333dd5f1821585e887c6d24305aeea2fbc8dad564b95 gradle/wrapper/gradle-wrapper.jar
macOS:
$ shasum --algorithm=256 gradle/wrapper/gradle-wrapper.jar
d81e0f23ade952b35e55333dd5f1821585e887c6d24305aeea2fbc8dad564b95 gradle/wrapper/gradle-wrapper.jar
Windows (с использованием PowerShell):
> (Get-FileHash gradle\wrapper\gradle-wrapper.jar -Algorithm SHA256).Hash.ToLower()
d81e0f23ade952b35e55333dd5f1821585e887c6d24305aeea2fbc8dad564b95
Сверьте сгенерированную контрольную сумму со списком [6]. Если она есть в списке, то вы проверили целостность Wrapper JAR. Если версия Gradle, которая сгенерировала Wrapper JAR, не совпадает с версией в gradle/wrapper/gradle-wrapper.properties, то можно безопасно снова запустить wrapper task для обновления Wrapper JAR.
Если контрольная сумма не перечислена на странице [6], то релиз Wrapper JAR может быть из milestone, release candidate, nightly build, либо может быть сгенерирован версиями Gradle от 3.3 до 4.0.2. Вам следует попытаться выяснить, как был сгенерирован Wrapper JAR, и если не удалось убедиться, что была правильная генерация, то следует считать его ненадежным. Если вы считаете, что Wrapper JAR был скомпроментирован, то сообщите об этом команде разработчиков Gradle отправкой письма на security@gradle.com.
[Ссылки]
1. The Gradle Wrapper site:docs.gradle.org. 2. Installing Gradle site:docs.gradle.org. 3. Command-Line Interface site:docs.gradle.org. 4. Wrapper task to build your project with Gradle, without having to install Gradle. 5. Gradle Build Environment site:docs.gradle.org. 6. Gradle distribution and wrapper JAR checksum reference site:gradle.org. 7. Kotlin: что это такое? |