Рубрики
Без рубрики

Stack to the Future – Как я перенес автоматическую сборку с Maven на Gradle.

Введение Когда меня познакомили с игровым проектом, я ухватился за возможность попробовать… Помеченный java, gradle, maven.

Когда меня познакомили с проектом Gameplay , я ухватился за возможность попытаться исправить некоторые проблемы в нем и просто заняться внесением вклада в проект с открытым исходным кодом, который действительно приносил пользу.

Одна проблема: я не мог его построить

В проекте была система сборки Maven, и все зависело от нее. Начиная со сборки и тестирования и заканчивая выпусками, все было написано в огромных XML-файлах, что (по моему скромному мнению) затрудняет чтение и понимание. Существовала огромная зависимость от разработчика, работающего над проектом, имеющего библиотеки JavaFX в своем глобальном пути к классу. Не только это, но и проект был построен на Java 8 с устаревшей версией JavaFX (т.Е. той, которая включена в более старые исправления Oracle Java 8).

Это не была устойчивая среда разработки, поэтому я решил, что моим первым вкладом будет использование возможностей Gradle для упрощения сборки, а также новых функций и поддержки OpenJDK 11 и OpenJFX 11. Намерение состояло в том, чтобы позволить любому разработчику клонировать проект и запускать его практически без каких-либо настроек. Эта статья представляет собой руководство о том, как я этого добился, и никоим образом не является окончательным руководством по миграции.

Первым шагом в этой задаче было заставить gradle выполнять большую часть тяжелой работы. Выполнив команду gradle init в каталоге с проектом Maven, вы можете получить Gradle для создания сценариев-оболочек, файлов свойств и файла build.gradle для эквивалентного pom.xml файл в корневом и внутреннем проектах.

Вот мой новый корневой build.gradle файл:

/*
 * This file was generated by the Gradle 'init' task.
 */

allprojects {
    group = 'com.github.schwabdidier'
    version = '1.6.2-SNAPSHOT'
}

subprojects {
    apply plugin: 'java'
    apply plugin: 'maven-publish'

    repositories {
        mavenLocal()
        maven {
            url = 'http://jcenter.bintray.com'
        }

        maven {
            url = 'https://jitpack.io'
        }

        maven {
            url = 'http://repo.maven.apache.org/maven2'
        }

        maven {
            url = 'https://raw.github.com/agomezmoron/screen-recorder/mvn-repo'
        }
    }

    dependencies {
        compileOnly 'com.google.code.findbugs:findbugs:3.0.1'
    }

    sourceCompatibility = '1.8'

    publishing {
        publications {
            maven(MavenPublication) {
                from(components.java)
            }
        }
    }

    tasks.withType(JavaCompile) {
        options.encoding = 'UTF-8'
    }
}

А вот один из файлов подпроекта build.gradle :

/*
 * This file was generated by the Gradle 'init' task.
 */

dependencies {
    compile 'com.github.agomezmoron:screen-recorder:0.0.3'
    compile project(':gazeplay-commons')
    compile project(':gazeplay-data')
    ...
}

Однако чего это не делает, так это переноса плагинов Maven. В частности, чтобы заставить сборку работать, мне пришлось добавить плагины для обработки аннотаций javafx и lombok в корневой каталог build.gradle . Также требовалась отчетность по лицензии, поэтому я включил и это.

plugins {
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.8'
    id 'io.freefair.lombok' version '4.0.1'
    id 'com.github.hierynomus.license-report' version '0.15.0'
}

Последними шагами для того, чтобы заставить сборку работать, было рекурсивное добавление плагинов в каждый подпроект и настройка их по мере необходимости.

Удобно, что инициализация Gradle уже предоставила мне блок subproject и мне просто нужно было добавить к нему эту конфигурацию;

subprojects {
    apply plugin: 'java'
    apply plugin: 'maven-publish'
    apply plugin: 'org.openjfx.javafxplugin'
    apply plugin: 'io.freefair.lombok'
    apply plugin: 'com.github.hierynomus.license-report'

    javafx {
        version = "11.0.2"
        modules = [ 'javafx.controls', 'javafx.swing', 'javafx.media', 'javafx.web' ]
    }
   ...
}

Примечание: На этом этапе я установил свой JAVA_HOME так, чтобы он указывал на мою локальную установку AdoptOpenJDK 11. Поскольку для этого требуется модульная версия OpenJFX, мне пришлось просмотреть весь импорт проекта и определить, какие модули включить. Это не было имитировано в Maven POM, поскольку для этого просто нужно было импортировать элементы управления JavaFX.

Несколько обновлений библиотеки, замена устаревших API-интерфейсов и некоторая документация позже, Несколько обновлений библиотеки, замена устаревших API-интерфейсов и некоторая документация позже,

Я мог бы протестировать работу конфигурации Gradle, запустив gradlew run для запуска приложения из командной строки. Игры прошли так, как ожидалось, и я мог перейти к следующему этапу.

Одной из ключевых целей этой задачи была возможность связывать релизы для пользователей приложения в виде запускаемого К счастью, Gradle распознал все мои зависимости и добавил их банки в папку lib , когда я запустил distZip задача из дистрибутива плагина . Чего не смог сделать launch jar , так это НАЙТИ какую-либо из зависимостей!

Чтобы исправить это, мне пришлось настроить конфигурацию манифеста jar, чтобы добавить как Основной класс для запуска, так и путь к классу для всех зависимостей среды выполнения.

jar {
    manifest {
        attributes (
            "Main-Class": 'net.gazeplay.GazePlayLauncher',
            "Class-Path": configurations.runtime.collect { it.getName() }.join(' ')
        )
    }
}

Путем сбора используя все время выполнения конфигурации и ит просматривая их все, я мог бы getName и соедините

Теперь, запустив созданный gazeplay-project-1.6.2-SNAPSHOT.jar фактически загрузил бы другие банки в путь к классу и позволил бы запускать игры!

Задача Индивидуальной Упаковки

Поскольку упаковка приложения для выпуска требовала нескольких шагов, я решил создать свою собственную пользовательскую задачу в новом файле .gradle .

import org.apache.tools.ant.filters.ReplaceTokens

task packageApp(dependsOn: ['assembleDist', 'downloadLicenses', 'scriptsForRelease']) {
    tasks.findByName('assembleDist').mustRunAfter('downloadLicenses')
    tasks.findByName('assembleDist').mustRunAfter('scriptsForRelease')
}

task scriptsForRelease(type: Copy) {
    from "${rootDir}/gazeplay-dist/src/main/bin"
    into "${rootDir}/build/scripts"
    filter(
        ReplaceTokens, tokens: [VERSION: project.version, NAME: project.name]
    )

    outputs.upToDateWhen { false } // Forces the task to rerun every time, without requiring a clean.
}

Задача package App загружает все лицензии для зависимостей, выполняет scripts For Release task для замены переменных среды для версии и имени проекта, а затем упаковывает все это в Zip и Tar-архив.

Плагин для выпуска Gradle

По умолчанию Gradle не включает прямой эквивалент maven-release-plugin/|, который проект использовал до этого момента. Плагин release предназначен для обеспечения того, чтобы все файлы были зафиксированы и отправлены в master, а затем помечали фиксацию номером версии в проекте. Наконец, он увеличивает эту версию и снова фиксирует все, готовое к дальнейшей разработке.

Для этого проекта я выбрал самую популярную итерацию плагина Gradle; плагин Researchgate Release . Все, что было необходимо для настройки плагина, – это указать, что задача package App была выполнена до запуска релиза; перед выпуском Build.dependsOn packageApp .

Главной особенностью JDK 9 стало внедрение модульных JDK и JRE. Это, конечно, распространено в OpenJDK 11 и является ключом к созданию пользовательского JRE для распространения вместе с приложением. Чтобы сделать это, я решил использовать плагин Badass Runtime Plugin , который оборачивает команду jlink задачей Gradle. Определив точные модули, необходимые приложению для запуска, можно сгенерировать JRE в качестве задачи сборки с включенной задачей jre .

Вот фрагмент модулей, включенных в созданный JRE:

ext.jreModules=['java.base',\
  'java.compiler',\
  'java.datatransfer',\
  'java.desktop',\
  'java.instrument',\
  'java.logging',\
  'java.management',\
  'java.management.rmi',\
  'java.naming',\
...

Все, что осталось сделать, это настроить плагин времени выполнения следующим образом:

runtime {
    options = ['--compress', '2', '--no-header-files', '--no-man-pages']
    modules = jreModules
    jreDir = file("gazeplay-dist/src/jre")
}

Параметры команды j link указаны для того, чтобы папка была как можно меньше, а каталог установлен так, чтобы он соответствовал месту расположения JRE 1.8, для согласованности с существующим проектом.

Возможно, это был не самый гламурный проект, но я многое узнал о Gradle, пользовательских задачах и сторонних плагинах. Кроме того, я не эксперт по пользовательским заказам или модульности Java 9+, но этот проект дал мне шаг вперед, необходимый для того, чтобы начать расследование и узнать об этом больше. В конце концов, я надеюсь, что эта статья поможет кому-то решить эту маленькую досадную проблему, которая у них есть, или просто будет интересным чтением для тех, кто проходит через тот же процесс.

Для получения более подробной информации обо всем, что я обсуждал здесь, не стесняйтесь проверить PR со всем кодом.

Оригинал: “https://dev.to/tohaker/stack-to-the-future-how-i-migrated-an-automated-build-from-maven-to-gradle-2b6m”