Перейти к основному содержимому

Gradle Groovy DSL — первая сборка

Разработчику

Gradle Groovy DSL — первая сборка

Gradle — система сборки для JVM (и не только) — компиляция, тесты, упаковка JAR, запуск приложения. Сценарий описывают в build.gradle (язык Groovy) или build.gradle.kts (Kotlin).

Android и многие enterprise-репозитории до сих пор используют Groovy DSL. Строка implementation 'group:artifact:version' внутри dependencies { } — это вызов метода, который Gradle добавляет через делегирование замыканий, а не "магический" синтаксис.

Java-аналог на Kotlin DSL: Gradle — практический старт. Maven: структура и сборки Java. Тесты Spock: Spock — первая спецификация. CI: Jenkinsfile.


Что получится

Проект hello-groovy-gradle: ./gradlew build, JAR, unit-тест. Понимание блоков plugins, repositories, dependencies, tasks.

./gradlew build

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew build и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Термины

ТерминПростыми словами
ПроектКорень с build.gradle или подпапка в multi-module
Плагин (plugin)Набор готовых задач (java, application)
Задача (task)Единица работы: compileJava, test, build
Конфигурацияimplementation, testImplementation — "роль" зависимости
Wrapper (gradlew)Скрипт, который скачивает фиксированную версию Gradle
Maven CentralПубличный репозиторий JAR-файлов
ToolchainGradle сам подберёт JDK нужной версии

Groovy DSL и Kotlin DSL

Groovy build.gradleKotlin build.gradle.kts
Исторически в AndroidНовые модули часто на KTS
Больше примеров в сетиСтроже подсказки IDE
Один и тот же Gradle "под капотом"Один и тот же Gradle

Логика одинакова; меняется только синтаксис файла.


Создание проекта

mkdir hello-groovy-gradle && cd hello-groovy-gradle
gradle init

Разбор:

  • mkdir ... && cd ... — создаёт каталог проекта и переходит в него (одна строка в shell).
  • gradle init — мастер Gradle — предложит тип проекта (application), язык (Java), DSL скрипта (Groovy).
  • После мастера появятся build.gradle, settings.gradle, wrapper — их коммитят в Git.
  • Глобальный gradle нужен только для init; дальше команда — ./gradlew.
  • Без wrapper коллеги и CI получат другую версию Gradle и "плавающие" сборки.

Минимальный build.gradle вручную (если не используете gradle init):

Код ITЗагрузка примера кода…

Разбор:

  • plugins { id 'java' } — подключает компиляцию src/main/java, тесты, задачу jar.
  • repositories { mavenCentral() } — откуда Gradle скачивает JAR-зависимости.
  • implementation — библиотека для основного кода; groovy на classpath компиляции и runtime.
  • tasks.named('test') { useJUnitPlatform() } — тесты через JUnit 5 (нужно для JUnit и Spock 2.x).
  • Для запуска main добавьте плагин application и блок application { mainClass = '...' } (см. полный пример ниже).

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с mkdir hello-groovy-gradle && cd hello-groovy-gradle и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

В мастере выберите — application, Java, Groovy build script, JUnit Jupiter.

Появятся:

ФайлНазначение
gradlew, gradlew.batWrapper для Unix/Windows
gradle/wrapper/gradle-wrapper.propertiesВерсия Gradle
settings.gradleИмя и список подпроектов
build.gradleСценарий сборки

settings.gradle

rootProject.name = 'hello-groovy-gradle'

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с rootProject.name = 'hello-groovy-gradle' и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Имя корневого проекта влияет на имя JAR и отображение в IDE. В multi-module сюда добавляют include 'api', 'service'.


build.gradle — разбор по блокам

Код ITЗагрузка примера кода…

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с plugins { и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Таблица блоков

БлокНазначение
plugins { id 'java' }Задачи компиляции, тестов, JAR
plugins { id 'application' }Задача run с точкой входа
group / versionКоординаты артефакта (Maven-style)
repositories { mavenCentral() }Откуда скачивать зависимости
dependencies { ... }Список библиотек по конфигурациям
application { mainClass = ... }Класс с public static void main
java { toolchain { ... } }Сборка под JDK 17 без ручного JAVA_HOME
tasks.named('test') { useJUnitPlatform() }JUnit 5 вместо устаревшего JUnit 4

Конфигурации зависимостей

КонфигурацияКуда попадает JAR
implementationТолько ваш модуль при компиляции и runtime
testImplementationТолько тесты (src/test)
api (в библиотеках)Пробрасывается потребителям модуля

Правило для новичка: production-код → implementation, тестовые библиотеки (JUnit, Spock) → testImplementation.

Строка 'org.apache.groovy:groovy:4.0.21'координата Maven: group:artifact:version.

Почему implementation '...' работает внутри { } — см. делегирование DSL.


Структура каталогов (Java)

src/main/java/ — production
src/test/java/ — JUnit
src/test/groovy/ — Spock (если подключили)

Разбор:

  • Фрагмент на text показывает рабочий пример: начинается с src/main/java/ — production и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

src/main/java/com/example/App.java:

package com.example;

public class App {
public static void main(String[] args) {
System.out.println("Hello from Gradle Groovy DSL");
}
}

Разбор:

  • Фрагмент на java показывает рабочий пример: начинается с package com.example; и задает контекст выполнения.
  • Конструкция class описывает структуру объекта: поля хранят состояние, а методы инкапсулируют поведение.
  • Вызовы методов и объявления функций задают основной шаг логики: входные значения передаются в метод и сразу обрабатываются.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Пакет com.example должен совпадать с путём папок.


Команды

./gradlew tasks # список задач
./gradlew compileJava # только компиляция main
./gradlew test # компиляция + тесты
./gradlew run # запуск main (плагин application)
./gradlew build # compile + test + jar

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew tasks # список задач и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Wrapper: gradlew фиксирует версию Gradle из gradle-wrapper.properties. В CI и у коллег не нужно ставить Gradle глобально — коммитьте wrapper в Git.

Windows: gradlew.bat вместо ./gradlew.


Своя задача (task)

tasks.register('hello') {
group = 'custom'
description = 'Печать приветствия'
doLast {
println "Gradle task hello"
}
}

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с tasks.register('hello') { и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.
ЧастьСмысл
tasks.register('hello')Ленивая регистрация задачи
group / descriptionОтображение в ./gradlew tasks
doLast { }Closure: выполнится в конце задачи
./gradlew hello

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew hello и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Встроенные задачи плагина java устроены так же: цепочка doFirst / doLast и зависимости между задачами (test зависит от compileTestJava).


Подключение Spock

dependencies {
testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0'
testImplementation 'org.apache.groovy:groovy:4.0.21'
}

test {
useJUnitPlatform()
}

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с dependencies { и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Тесты в src/test/groovy — см. Spock — первая спецификация.


Multi-module (набросок)

settings.gradle:

rootProject.name = 'parent'
include 'api', 'service'

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с rootProject.name = 'parent' и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

У api/ и service/ свой build.gradle. Зависимость модуля на модуль:

dependencies {
implementation project(':api')
}

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с dependencies { и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Сборка всего дерева: ./gradlew build из корня.

./gradlew build

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew build и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Частые ошибки

СимптомПричина
Could not find method implementation()Не применён плагин java
Unsupported class file major versionToolchain ниже версии байткода зависимости
gradlew не найден в CIЗапускают gradle без wrapper — добавьте wrapper в репо
Тесты не запускаютсяНет useJUnitPlatform() для JUnit 5

Что попробовать

  1. Добавить Spock и один CalcSpec.
  2. Spring Boot plugin — сравнить с Первая программа на Spring Framework.
  3. Переписать скрипт в Kotlin DSL — Gradle — практический старт.
  4. Подключить Jenkins с ./gradlew test.
./gradlew test

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew test и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Дальше

Spock · Jenkinsfile · делегирование DSL


Реальный workflow команды с Gradle

Типичный ежедневный цикл:

  1. Локально запускаем ./gradlew test.
  2. Перед пушем делаем ./gradlew build.
  3. В CI повторяем тот же wrapper-командой.
  4. Для релиза добавляем версионирование и публикацию.
./gradlew clean test build

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew clean test build и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Одинаковые команды локально и в CI снижают число "у меня работает" случаев.


Производительность сборки

Для ускорения больших проектов применяют:

  • org.gradle.caching=true в gradle.properties;
  • org.gradle.parallel=true для независимых модулей;
  • remote build cache в CI;
  • разделение модулей, чтобы изменения в одном модуле не пересобирали все дерево.
org.gradle.caching=true
org.gradle.parallel=true

Разбор:

  • Фрагмент на properties показывает рабочий пример: начинается с org.gradle.caching=true и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Оптимизацию проверяют через build scan и время критичных задач (compileJava, test).


Мини-памятка по качеству build.gradle

  • Плагины и версии вынесены в единый каталог версий или convention plugins.
  • Зависимости группируются по назначению.
  • Кастомные задачи имеют group и description.
  • Wrapper хранится в репозитории и обновляется осознанно.

Связанные материалы — Jenkins Pipeline, Spock, Groovy и Java.


Сквозной кейс — build.gradle для каталога

Сборка каталога книг в едином файле:

Код ITЗагрузка примера кода…

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с plugins { и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Дальше тот же сценарий везде:

  • локально ./gradlew test;
  • в Jenkins тот же wrapper;
  • отчеты подхватываются через junit.

Этот шаг закрывает сквозной маршрут "модель → логика → БД → тесты → CI".