Проектування баз даних

Пакування та розповсюдження JavaFX-додатків

Від вихідного коду до готового інсталятора: створення Fat JAR, використання jpackage для генерації нативних інсталяторів під Windows, macOS та Linux, публікація релізів у GitHub Releases.

Пакування та розповсюдження JavaFX-додатків

Вступ: Від середовища розробника до рук користувача

Уявіть ситуацію, з якою стикається кожен розробник після завершення основного етапу розробки. Додаток запускається бездоганно з командного рядка, усі тести проходять успішно, інтерфейс виглядає саме так, як задумано. Настає момент, коли потрібно передати результат роботи замовнику або кінцевому користувачеві. І тут виникає закономірне питання: як запустити цей додаток на комп'ютері, де не встановлено ні JDK, ні IntelliJ IDEA, ні Maven?

Це питання є ключовим у промисловій розробці програмного забезпечення. Процес перетворення вихідного коду на готовий до розповсюдження продукт називається релізною інженерією (release engineering). Для Java-екосистеми цей процес має свою специфіку, зумовлену особливостями платформи JVM.

Проблема класичного JAR. Стандартний JAR-файл (Java ARchive), який генерують Maven або Gradle, містить лише скомпільований байт-код вашого проєкту. Він не включає ні сторонні бібліотеки (AtlantaFX, Google Guice, HikariCP), ні модулі JavaFX, ні саму JVM. Спроба запустити такий файл командою java -jar audiobook.jar на чистій машині завершиться помилкою ClassNotFoundException при першому ж зверненні до будь-якої зовнішньої залежності.

Еволюція підходів до розповсюдження. Протягом двох десятиліть розвитку Java-екосистеми сформувалося кілька підходів до вирішення цієї проблеми:

Fat JAR / Uber JAR

Усі залежності упаковуються в один великий JAR-файл. Простий підхід, але вимагає встановленої JVM на цільовій машині.

jlink: Custom Runtime Image

Створення мінімального образу JVM, що містить лише необхідні модулі. Зменшує розмір дистрибутиву, але вимагає модульності проєкту.

jpackage: Нативний інсталятор

Генерація платформо-специфічного інсталятора (.exe, .msi, .dmg, .deb, .rpm), що включає всі залежності та вбудовану JVM. Найкращий досвід для кінцевого користувача.

У цій статті ми послідовно пройдемо всі три рівні пакування — від простого Fat JAR до повноцінного нативного інсталятора — та навчимося публікувати релізи у GitHub Releases для зручного розповсюдження серед користувачів.


Частина I. Fat JAR: Перший крок до самодостатнього артефакту

Що таке Fat JAR і чому він так називається

Fat JAR (також відомий як Uber JAR або Shaded JAR) — це JAR-архів, що містить не лише байт-код власного проєкту, а й байт-код усіх його транзитивних залежностей. Назва "fat" (жирний) є красномовною: якщо звичайний JAR платформи аудіокниг може важити 50–100 КБ, то Fat JAR з усіма бібліотеками (AtlantaFX, Guice, HikariCP, H2) зважитиме 30–50 МБ. Це, безумовно, збільшує розмір артефакту, проте забезпечує головне: єдину точку входу у вигляді одного файлу.

Fat JAR не вирішує проблему JVM. Щоб запустити Fat JAR, на цільовій машині все одно має бути встановлена сумісна Java Runtime Environment (JRE). Цю проблему повністю вирішує лише jpackage, розглянутий у наступному розділі. Fat JAR є зручним проміжним рішенням — для передачі між розробниками, розгортання на серверах, де JRE вже наявна, або як будівельний блок для jpackage.

Налаштування Maven: плагін maven-shade-plugin

Maven не надає вбудованої підтримки Fat JAR. Для цього використовується maven-shade-plugin — один із найпопулярніших плагінів Maven-екосистеми, що дозволяє "затінити" (shade) всі залежності в єдиний архів.

pom.xml
<build>
    <plugins>
        <!-- Компілятор: вказуємо версію Java -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.13.0</version>
            <configuration>
                <source>21</source>
                <target>21</target>
            </configuration>
        </plugin>

        <!-- Fat JAR: упаковуємо всі залежності в один архів -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.5.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <!-- Головний клас: точка входу додатку -->
                        <transformers>
                            <transformer implementation=
                                "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>dev.kostyl.audiobook.Launcher</mainClass>
                            </transformer>
                            <!-- Об'єднання META-INF/services (важливо для Guice) -->
                            <transformer implementation=
                                "org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                        </transformers>
                        <!-- Виключення підписів з JAR-файлів залежностей -->
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.SF</exclude>
                                    <exclude>META-INF/*.DSA</exclude>
                                    <exclude>META-INF/*.RSA</exclude>
                                </excludes>
                            </filter>
                        </filters>
                        <!-- Назва вихідного файлу -->
                        <outputFile>
                            ${project.build.directory}/${project.artifactId}-fat.jar
                        </outputFile>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Клас Launcher замість App. JavaFX-додатки мають специфіку: якщо головний клас безпосередньо успадковується від javafx.application.Application, запуск через java -jar завершується помилкою java.lang.reflect.InvocationTargetException. Це пов'язано з тим, що JavaFX-модулі не завантажуються автоматично через classpath. Рішення — створити клас-обгортку Launcher, що не успадковується від Application, і саме його вказувати як mainClass.
Launcher.java
package dev.kostyl.audiobook;

/**
 * Клас-обгортка для запуску JavaFX-додатку через Fat JAR.
 * Не успадковується від Application — це критично для коректного
 * завантаження класів через classpath (не module-path).
 */
public class Launcher {
    public static void main(String[] args) {
        AudiobookApp.main(args); // Делегуємо до реального Application
    }
}

Тепер зберіть проєкт та перевірте результат:

# Збірка Fat JAR
mvn clean package

# Результат у директорії target/
ls -lh target/audiobook-app-fat.jar
# → -rw-r--r-- 1 user staff 42M audiobook-app-fat.jar

# Запуск Fat JAR
java -jar target/audiobook-app-fat.jar

Частина II. jpackage: Нативний інсталятор із вбудованою JVM

Концептуальна основа: що таке jpackage

jpackage — це інструмент командного рядка, що з'явився у складі JDK 16 як стабільна функція (до цього він існував у вигляді інкубаційного модуля з JDK 14). Його призначення — генерація нативних інсталяторів для desktop-додатків на Java, що не вимагають попередньої установки JVM на цільовій машині.

Принцип роботи jpackage полягає у наступному: інструмент бере ваш Fat JAR (або директорію з класами), додає до нього урізаний образ JRE (створений за допомогою jlink), іконку програми, метадані (назва, версія, виробник) та упаковує все це у формат, звичний для кожної операційної системи:

Операційна системаФормат інсталятораРезультат
Windows.msi або .exe (NSIS)Стандартний Windows Installer
macOS.dmg або .pkgОбраз диска або пакет macOS
Linux (Debian/Ubuntu).debПакет Debian
Linux (RHEL/Fedora).rpmПакет RPM
Крос-компіляція неможлива.jpackage генерує інсталятор лише для тієї операційної системи, на якій він запускається. Щоб створити інсталятори для Windows, macOS та Linux одночасно, необхідно використовувати CI/CD-систему (наприклад, GitHub Actions) з окремими runner-агентами для кожної платформи. Саме цей підхід ми розглянемо у розділі про GitHub Actions.

Передумови: що потрібно перед запуском jpackage

Перш ніж розпочати генерацію інсталятора, переконайтеся, що виконані такі умови:

Крок 1: JDK 17+ із підтримкою jpackage

jpackage є частиною JDK 14+. Перевірте наявність інструменту:

jpackage --version
# → 21.0.3

Якщо команда не знайдена — переконайтеся, що JAVA_HOME вказує на повний JDK (не JRE), та що директорія $JAVA_HOME/bin присутня у PATH.

Крок 2: Інструменти платформи (лише для Windows)

Для генерації .msi-інсталятора на Windows необхідно встановити WiX Toolset — набір інструментів для компіляції MSI-пакетів.

!IMPORTANTjpackage вимагає виключно WiX Toolset версії 3.x (версії 4.x та 5.x не підтримуються утилітою автоматично). Тому необхідно встановлювати саме версію 3.

Для встановлення WiX Toolset v3 скористайтеся одним із пакетних менеджерів для Windows:

Для Scoop спочатку потрібно підключити репозиторій версій, оскільки WiX 3 є застарілою гілкою:

# Додавання бакету версій
scoop bucket add versions

# Встановлення версії 3 WiX Toolset
scoop install versions/wixtoolset3

Chocolatey за замовчуванням встановлює стабільну гілку WiX Toolset v3:

choco install wixtoolset --yes

Утиліта Winget (Windows Package Manager) дозволяє встановити пакет за його унікальним ідентифікатором:

winget install -e --id WiXToolset.WiXToolset

::

Після встановлення переконайтеся, що шлях до утиліт WiX (зокрема до папки bin, де знаходяться candle.exe та light.exe) додано до системної змінної PATH. Перезапустіть термінал та перевірте наявність інструменту:

# Перевірка наявності WiX
candle.exe --version
# → Windows Installer XML Toolset Compiler version 3.14.0.8606

Для генерації .exe (NSIS-інсталятора) встановіть NSIS з nsis.sourceforge.io.

Крок 3: Зібраний Fat JAR

jpackage вимагає вхідний JAR-файл. Використовуйте Fat JAR, створений у попередньому розділі:

# Maven
mvn clean package
# Gradle
./gradlew shadowJar

::

Структура проєкту перед пакуванням

Для зручності рекомендується розмістити всі ресурси для пакування в окремій директорії packaging/:

audiobook-app/
├── src/
├── target/
│   └── audiobook-app-fat.jar       ← зібраний Fat JAR
├── packaging/
│   ├── windows/
│   │   ├── audiobook.ico           ← іконка для Windows (.ico)
│   │   └── license.rtf             ← ліцензія для MSI-діалогу
│   ├── macos/
│   │   └── audiobook.icns          ← іконка для macOS (.icns)
│   └── linux/
│       └── audiobook.png           ← іконка для Linux (.png, 128×128)
└── pom.xml

Генерація інсталятора для Windows (.msi)

Наведена команда виконується на Windows-машині (або у Windows runner у GitHub Actions):

!WARNINGПроблема з кирилицею у метаданих на Windows WiX Toolset v3 за замовчуванням використовує західноєвропейську кодову сторінку (наприклад, 1252). Якщо значення параметрів --description, --vendor чи --name містять кириличні символи, WiX не зможе скомпілювати інсталятор і поверне помилку виду: light.exe : error LGHT0311 : A string was provided with characters that are not available in the specified database code page '1252'.

Рекомендація: Завжди вказуйте опис програми (--description) та інші метадані виключно англійською мовою. Якщо використання кирилиці є критичним, вам доведеться примусово задавати кодову сторінку за допомогою параметра --win-codepage 1251, проте англомовний варіант є найбільш надійним та сумісним.

jpackage ^
  --type msi ^
  --name "Audiobook Platform" ^
  --app-version "1.0.0" ^
  --vendor "Kostyl Dev" ^
  --description "Audiobook Management Platform" ^
  --input target/ ^
  --main-jar audiobook-app-fat.jar ^
  --main-class dev.kostyl.audiobook.Launcher ^
  --icon packaging/windows/audiobook.ico ^
  --dest dist/ ^
  --win-dir-chooser ^
  --win-menu ^
  --win-shortcut ^
  --win-menu-group "Kostyl Dev"
--type
string
Тип вихідного пакету: msi, exe, dmg, pkg, deb, rpm, app-image.
--name
string
Назва програми, що відображається у меню «Пуск» та панелі керування.
--app-version
string
Версія програми у форматі major.minor.patch. Відображається у «Установка та видалення програм».
--input
string
Директорія, що містить --main-jar. Усі файли з неї потраплять у дистрибутив.
--win-dir-chooser
boolean
Додає у діалог інсталятора крок вибору директорії встановлення.
--win-menu
boolean
Створює ярлик у меню «Пуск».
--win-shortcut
boolean
Створює ярлик на робочому столі.
jpackage — Windows MSI
PS C:\audiobook-app> jpackage --type msi --name "Audiobook Platform" ...
WARNING: Using incubator modules: jdk.incubator.jpackage
Checking WiX toolset installation...
OK: WiX 3.14.0.8606 found at C:\Program Files\WiX Toolset v3.14\bin
Building application image...
Generating MSI installer...
SUCCESS: Installer created: dist\Audiobook Platform-1.0.0.msi (87 MB)

Результатом є файл dist/Audiobook Platform-1.0.0.msi, що є повноцінним Windows-інсталятором з майстром встановлення.

Генерація інсталятора для macOS (.dmg)

На macOS-машині:

jpackage \
  --type dmg \
  --name "Audiobook Platform" \
  --app-version "1.0.0" \
  --vendor "Kostyl Dev" \
  --input target/ \
  --main-jar audiobook-app-fat.jar \
  --main-class dev.kostyl.audiobook.Launcher \
  --icon packaging/macos/audiobook.icns \
  --dest dist/ \
  --mac-package-name "audiobook-platform" \
  --mac-package-identifier "dev.kostyl.audiobook"
Підпис коду (Code Signing) для macOS. Якщо ви плануєте розповсюджувати програму через App Store або не хочете, щоб macOS Gatekeeper блокував запуск, необхідно підписати інсталятор сертифікатом Apple Developer Certificate. Для цього додайте параметр --mac-sign та вкажіть --mac-signing-key-user-name "Developer Name (TEAMID)". Процес потребує Apple Developer Program ($99/рік). Для навчальних проєктів підпис не є обов'язковим — користувачі можуть запустити програму через Ctrl+Click → Відкрити.

Генерація пакету для Linux (.deb)

На Linux-машині (Debian/Ubuntu):

jpackage \
  --type deb \
  --name "audiobook-platform" \
  --app-version "1.0.0" \
  --vendor "Kostyl Dev" \
  --input target/ \
  --main-jar audiobook-app-fat.jar \
  --main-class dev.kostyl.audiobook.Launcher \
  --icon packaging/linux/audiobook.png \
  --dest dist/ \
  --linux-package-name "audiobook-platform" \
  --linux-app-category "Education" \
  --linux-shortcut

Частина III. Автоматизація: jpackage-maven-plugin та GitHub Actions

Інтеграція jpackage у збірку Maven

Виконання jpackage вручну з командного рядка є зручним для налагодження, але незручним для регулярних релізів. Плагін jpackage-maven-plugin від проєкту io.github.fvarrui дозволяє описати всі параметри пакування безпосередньо у pom.xml та запускати пакування однією командою.

pom.xml
<plugin>
    <groupId>io.github.fvarrui</groupId>
    <artifactId>javapackager</artifactId>
    <version>1.7.6</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>package</goal>
            </goals>
            <configuration>
                <mainClass>dev.kostyl.audiobook.Launcher</mainClass>
                <bundleJre>true</bundleJre>
                <generateInstaller>true</generateInstaller>
                <administratorRequired>false</administratorRequired>
                <platform>auto</platform>
                <name>Audiobook Platform</name>
                <version>1.0.0</version>
                <organizationName>Kostyl Dev</organizationName>
                <organizationUrl>https://kostyl.dev</organizationUrl>
                <iconFile>packaging/app-icon</iconFile><!-- без розширення: плагін підбирає .ico/.icns/.png -->
                <outputDirectory>dist</outputDirectory>
                <winConfig>
                    <createDesktopIconLink>true</createDesktopIconLink>
                    <createStartMenuIconLink>true</createStartMenuIconLink>
                    <menuGroupName>Kostyl Dev</menuGroupName>
                    <generateInstaller>true</generateInstaller>
                    <installerType>msi</installerType>
                </winConfig>
                <macConfig>
                    <generateDmg>true</generateDmg>
                </macConfig>
                <linuxConfig>
                    <generateDeb>true</generateDeb>
                    <generateRpm>false</generateRpm>
                </linuxConfig>
            </configuration>
        </execution>
    </executions>
</plugin>

Тепер запустити повний цикл збірки та пакування можна однією командою:

mvn clean package
# → target/audiobook-app-fat.jar     (Fat JAR)
# → dist/Audiobook Platform-1.0.0.msi  (Windows)  або
# → dist/Audiobook Platform-1.0.0.dmg  (macOS)    або
# → dist/audiobook-platform_1.0.0.deb  (Linux)

GitHub Actions: Збірка інсталяторів для всіх платформ

Найпрофесійніший підхід — автоматична збірка інсталяторів для всіх трьох платформ при кожному новому тегу релізу. GitHub Actions надає безкоштовні runner-агенти для Windows, macOS та Ubuntu.

Створіть файл .github/workflows/release.yml у репозиторії:

.github/workflows/release.yml
name: Release — Build Installers

# Запускається при пуші тегу виду v1.0.0, v2.3.1 тощо
on:
  push:
    tags:
      - 'v*.*.*'

jobs:
  build-installers:
    # Матриця: три паралельних завдання для трьох ОС
    strategy:
      matrix:
        os: [windows-latest, macos-latest, ubuntu-latest]
    
    runs-on: ${{ matrix.os }}
    
    steps:
      # 1. Клонування репозиторію
      - name: Checkout repository
        uses: actions/checkout@v4

      # 2. Встановлення JDK 25 (включає jpackage)
      - name: Set up JDK 25
        uses: actions/setup-java@v4
        with:
          java-version: '25'
          distribution: 'temurin'
          cache: maven

      # 3. Встановлення WiX Toolset (лише для Windows)
      - name: Install WiX Toolset (Windows only)
        if: matrix.os == 'windows-latest'
        run: |
          choco install wixtoolset --yes

      # 4. Встановлення інструментів збірки RPM (лише для Linux)
      - name: Install RPM packaging tools (Linux only)
        if: matrix.os == 'ubuntu-latest'
        run: |
          sudo apt-get update
          sudo apt-get install -y rpm

      # 5. Збірка Fat JAR
      - name: Build Fat JAR
        run: mvn clean package -DskipTests

      # 6. Підготовка директорії вхідних файлів для jpackage
      - name: Prepare jpackage input
        run: |
          mkdir -p jpackage-input
          cp target/audiobook-app-fat.jar jpackage-input/

      # 7. Визначення версії з тегу (v1.0.0 → 1.0.0)
      - name: Extract version from tag
        id: version
        shell: bash
        run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT

      # 8. Генерація нативного інсталятора через jpackage
      - name: Package installer (Windows)
        if: matrix.os == 'windows-latest'
        shell: pwsh
        run: |
          jpackage `
            --type msi `
            --name "Audiobook Platform" `
            --app-version "${{ steps.version.outputs.VERSION }}" `
            --vendor "Kostyl Dev" `
            --input jpackage-input/ `
            --main-jar audiobook-app-fat.jar `
            --main-class dev.kostyl.audiobook.Launcher `
            --icon packaging/windows/audiobook.ico `
            --dest dist/ `
            --win-dir-chooser `
            --win-menu `
            --win-shortcut

      - name: Package installer (macOS)
        if: matrix.os == 'macos-latest'
        run: |
          jpackage \
            --type dmg \
            --name "Audiobook Platform" \
            --app-version "${{ steps.version.outputs.VERSION }}" \
            --vendor "Kostyl Dev" \
            --input jpackage-input/ \
            --main-jar audiobook-app-fat.jar \
            --main-class dev.kostyl.audiobook.Launcher \
            --icon packaging/macos/audiobook.icns \
            --dest dist/

      - name: Package installer (Linux DEB & RPM)
        if: matrix.os == 'ubuntu-latest'
        run: |
          # Створення DEB-пакета для Debian/Ubuntu
          jpackage \
            --type deb \
            --name "audiobook-platform" \
            --app-version "${{ steps.version.outputs.VERSION }}" \
            --vendor "Kostyl Dev" \
            --input jpackage-input/ \
            --main-jar audiobook-app-fat.jar \
            --main-class dev.kostyl.audiobook.Launcher \
            --icon packaging/linux/audiobook.png \
            --dest dist/ \
            --linux-shortcut

          # Створення RPM-пакета для RedHat/Fedora/CentOS
          jpackage \
            --type rpm \
            --name "audiobook-platform" \
            --app-version "${{ steps.version.outputs.VERSION }}" \
            --vendor "Kostyl Dev" \
            --input jpackage-input/ \
            --main-jar audiobook-app-fat.jar \
            --main-class dev.kostyl.audiobook.Launcher \
            --icon packaging/linux/audiobook.png \
            --dest dist/ \
            --linux-shortcut

          # Копіювання Fat JAR у директорію dist, щоб він також потрапив у реліз
          cp target/audiobook-app-fat.jar dist/

      # 9. Збереження артефактів для наступного завдання
      - name: Upload installer artifact
        uses: actions/upload-artifact@v4
        with:
          name: installer-${{ matrix.os }}
          path: dist/
          retention-days: 1

  # Окреме завдання: публікація GitHub Release
  publish-release:
    needs: build-installers
    runs-on: ubuntu-latest
    permissions:
      contents: write

    steps:
      - name: Download all installer artifacts
        uses: actions/download-artifact@v4
        with:
          path: installers/
          merge-multiple: true

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          name: "Audiobook Platform ${{ github.ref_name }}"
          body: |
            ## Що нового у ${{ github.ref_name }}

            Опис змін цього релізу.

            ## Завантаження

            | Операційна система / Платформа | Файл |
            |---|---|
            | Windows 10/11 | `*.msi` |
            | macOS 12+ | `*.dmg` |
            | Ubuntu/Debian | `*.deb` |
            | RedHat/Fedora | `*.rpm` |
            | Будь-яка (з встановленою JRE) | `*.jar` |
          files: installers/**
          draft: false
          prerelease: false

Частина IV. Публікація у GitHub Releases

Принцип GitHub Releases

GitHub Releases — це механізм GitHub для публікації версіонованих випусків програмного забезпечення. Кожен реліз прив'язується до конкретного git-тегу та може містити довільну кількість файлів-артефактів: інсталяторів, архівів із вихідним кодом, документації.

На відміну від звичайного коміту, реліз має:

  • Версійний тег (наприклад, v1.0.0) — незмінний покажчик у git-історії.
  • Назву та опис — що змінилося, які нові можливості з'явилися, які помилки виправлено.
  • Бінарні файли — безпосередньо файли для завантаження кінцевими користувачами.

Публікація релізу вручну через git і GitHub CLI

Якщо ви не використовуєте GitHub Actions, реліз можна опублікувати в кілька кроків.

Крок 1. Переконайтеся, що всі зміни закоміченні та ви знаходитесь на гілці main:

git status
# → On branch main, nothing to commit, working tree clean

git log --oneline -3
# → a1b2c3d Фінальна версія платформи аудіокниг
# → 9f8e7d6 Виправлення валідації форм
# → 5c4b3a2 Інтеграція AtlantaFX

Крок 2. Створіть анотований тег для нового релізу:

# Синтаксис: git tag -a <тег> -m "<повідомлення>"
git tag -a v1.0.0 -m "Перший стабільний реліз Audiobook Platform"

# Перевірка: переглянути всі теги
git tag -l
# → v1.0.0

# Переглянути деталі тегу
git show v1.0.0
Різниця між легким та анотованим тегом.git tag v1.0.0 (без -a) створює легкий тег — простий покажчик на коміт. git tag -a v1.0.0 -m "..." створює анотований тег — окремий git-об'єкт із автором, датою та повідомленням. Для релізів завжди слід використовувати анотовані теги: вони несуть більше семантики та краще відображаються в інтерфейсі GitHub.

Крок 3. Запушіть тег до віддаленого репозиторію:

# Пуш конкретного тегу
git push origin v1.0.0

# АБО пуш усіх локальних тегів одночасно
git push origin --tags
git push — tag
$ git push origin v1.0.0
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 190 bytes | 190.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/arakviel/audiobook-platform.git
* [new tag] v1.0.0 → v1.0.0

Крок 4. Після пуші тегу, якщо ви налаштували GitHub Actions із файлом release.yml, workflow запуститься автоматично. Якщо ж публікуєте вручну — використайте GitHub CLI:

# Встановлення GitHub CLI (якщо ще не встановлено)
# macOS: brew install gh
# Windows: choco install gh
# Linux: sudo apt install gh

# Автентифікація
gh auth login

# Публікація релізу з файлами
gh release create v1.0.0 \
  dist/*.msi \
  dist/*.dmg \
  dist/*.deb \
  --title "Audiobook Platform v1.0.0" \
  --notes "## Перший реліз

Платформа для управління та прослуховування аудіокниг.

### Що включено
- Повний CRUD для аудіокниг
- MVVM-архітектура з Guice
- Сучасний інтерфейс на AtlantaFX
- Інтеграція з H2 базою даних"

Крок 5. Переконайтеся, що реліз опублікований:

# Перегляд усіх релізів у репозиторії
gh release list

# → TITLE                           TAG       PUBLISHED
# → Audiobook Platform v1.0.0       v1.0.0    about 1 minute ago

# Відкрити реліз у браузері
gh release view v1.0.0 --web

Semantic Versioning: угода щодо нумерації версій

Щоб версії релізів несли змістовну інформацію для користувачів та інших розробників, дотримуйтеся стандарту Semantic Versioning (SemVer) у форматі MAJOR.MINOR.PATCH:


Підсумок: Повний релізний цикл

Нижче наведено зведений огляд повного шляху від вихідного коду до рук користувача:

Розробка та коміти

Розробіть функціональність, покрийте тестами, закомітьте зміни. Дотримуйтесь конвенції Conventional Commits для структурованих повідомлень комітів.

Оновлення версії у pom.xml

mvn versions:set -DnewVersion=1.0.0

Збірка Fat JAR

mvn clean package
# → target/audiobook-app-fat.jar

Генерація нативного інсталятора

# Запускається на відповідній платформі або через GitHub Actions
jpackage --type msi ... --dest dist/

Тегування та публікація

git tag -a v1.0.0 -m "Реліз v1.0.0"
git push origin v1.0.0
# GitHub Actions автоматично збирає інсталятори та публікує реліз

Fat JAR

Коли використовувати: Розгортання на серверах, передача між розробниками, як вхідний артефакт для jpackage.

Команда: mvn clean package або ./gradlew shadowJar

jpackage

Коли використовувати: Розповсюдження кінцевим користувачам, створення інсталяторів для всіх ОС.

Команда: jpackage --type msi|dmg|deb ...

GitHub Releases

Коли використовувати: Публічне розповсюдження, версіонування, централізоване сховище артефактів.

Команда: git tag -a v1.0.0 && git push origin v1.0.0

Найпростіший старт. Якщо ви лише починаєте знайомство з релізною інженерією, реалізуйте кроки послідовно: спочатку налаштуйте Fat JAR та переконайтеся, що він запускається на іншому комп'ютері. Потім додайте jpackage для своєї поточної ОС. Нарешті, налаштуйте GitHub Actions для автоматизації збірки на всіх трьох платформах. Кожен крок є самодостатнім і надає цінність незалежно від наступних.
Copyright © 2026