Java, CI/CD Makefile сборка

В данном разделе рассмотрен пример CI/CD сборки java проекта через Makefile.

Смотрите также раздел CI/CD сборки Maven проекта.

💡

Для проверки данного примера подготовлена ветка makefile-build в репозитории gitverse_tutorials/CICD_building_projects (opens in a new tab).

Подготовительные действия

  1. Создайте репозиторий, например, CICD_building_projects.

  2. Обновите список доступных пакетов:

sudo apt update
  1. Установите JDK-пакет по умолчанию, который включает в себя компилятор Java:
sudo apt install default-jdk

Проверьте, что компилятор установлен:

javac -version
  1. Скачайте раннер и сделайте его исполняемым:
  chmod +x act_runner
  1. Установите docker.

  2. Включите CI/CD в настройках вашего репозитория.

Пример:

Main.java

Создайте файл Main.java с кодом:

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Проверьте, что программа исполняется

Запустите файл Main.java без предварительной компиляции, используя интерпретатор Java (java).

Пример успешного выполнения:

$ java Main.java
Hello, World!

Makefile

Создайте Makefile, который содержит инструкции для сборки проекта или программы с помощью утилиты make:

# Define compiler
CC = javac

# Define target directory
TARGET_DIR = target

# Define target
TARGET = $(TARGET_DIR)/Main

all: $(TARGET)

$(TARGET): Main.java
  mkdir -p $(TARGET_DIR)
  $(CC) -d $(TARGET_DIR) Main.java

clean:
  rm -rf $(TARGET_DIR)

В Makefile обычно определяются зависимости между различными частями проекта и команды для их сборки. Утилита make использует Makefile для автоматизации процесса компиляции и сборки программного обеспечения.

Структура Makefile

  1. CC = javac — определяет переменную CC и устанавливает ее значение равным javac, что указывает на компилятор Java.
  2. TARGET_DIR = target — здесь определяется переменная TARGET_DIR и устанавливается в значение target, указывающее на директорию, где будут храниться скомпилированные файлы.
  3. TARGET = $(TARGET_DIR)/Main — определяет переменную TARGET, которая представляет собой путь к главному исполняемому файлу Main.
  4. all: $(TARGET) — это цель all, которая зависит от цели $(TARGET), что означает, что при запуске make all будет собран целевой файл Main.
  5. $(TARGET): Main.java — указывает, что цель $(TARGET) зависит от файла Main.java.
  6. mkdir -p $(TARGET_DIR) — создает директорию $(TARGET_DIR) с ключом -p, который создает все промежуточные директории в пути, если они отсутствуют.
  7. $(CC) -d $(TARGET_DIR) Main.java — использует переменную CC (компилятор javac) для компиляции файла Main.java и помещает скомпилированный файл в директорию $(TARGET_DIR).
  8. clean: rm -rf $(TARGET_DIR) — удаляет директорию $(TARGET_DIR) и все ее содержимое рекурсивно.

Проверьте, что Makefile исполняется

Пример:

$ make
javac Main.java

В результате должен появиться файл Main.class.

Когда вы выполнили команду make, она вызвала правило all, которое зависит от цели $(TARGET), в данном случае Main. Это правило указывает, что для создания цели Main необходимо выполнить команду javac Main.java, которая компилирует файл Main.java с использованием Java компилятора (javac). Таким образом, при выполнении make была автоматически вызвана команда компиляции Java файла.

Проверьте скомпилированный файл

Пример успешного выполнения:

$ java Main
Hello, World!

Когда вы выполняете java Main, Java ВМ ожидает, что имя класса будет указано после слова java, без расширения файла. Таким образом, Main будет рассматриваться как имя класса для запуска.

С другой стороны, когда вы используете java Main.java, вы указываете Java ВМ запустить файл Main.java, который не является допустимым способом для запуска Java программы. Java ВМ ожидает имя класса, а не имени файла .java.

javaMakefileBuildDemo.yaml

name: Сборка проекта через Makefile
on:
  push:
jobs:
  build-test:
    name: javaMakefileBuildDemo
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3  # Checkout the repository code
 
      - name: Install jdk
        run: |
          apt-get update
          apt-get -y install default-jdk
 
      - name: build project through Makefile
        run: |
          make
 
      - name: Set Git user email
        run: |
          git config --local user.email "author@gitverse.com"
 
      - name: Set Git user name
        run: |
          git config --local user.name "author"
 
      - name: Create new makefile-build-branch
        run: |
          git checkout -b makefile-build-branch 
          git add .
          git commit -m "a project through Makefile is built"
 
      - name: Push to remote branch
        run: |
          git push -u origin makefile-build-branch --force

Структура javaMakefileBuildDemo.yaml:

  • name: Сборка проекта через Makefile — название работы (job), которая отвечает за сборку проекта через Makefile.
  • on: push: — этот job будет запускаться при каждом push'е в репозиторий.
  • jobs: build-test: — начало описания работы с именем build-test.
    • name: javaMakefileBuildDemo — название этой конкретной задачи сборки проекта через Makefile.
    • runs-on: ubuntu-latest — указание о том, что задача будет выполняться на последней версии Ubuntu.
    • steps: — начало списка шагов, необходимых для выполнения этой задачи.
      • - uses: actions/checkout@v3 — используется для клонирования кода репозитория.
      • - name: Install jdk— название шага, устанавливающего JDK.
      • run: | — начало блока команд для выполнения.
        • apt-get update — обновление пакетов.
        • apt-get -y install default-jdk — установка JDK.
      • - name: build project through Makefile — название шага, собирающего проект через Makefile.
        • run: | — начало блока команд для выполнения.
          • make — вызов команды make для сборки проекта.
      • - name: Set Git user email — название шага, устанавливающего email пользователя Git.
        • run: | — начало блока команд для выполнения.
          • git config --local user.email "author@gitverse.com" — установка email пользователя Git.
      • - name: Set Git user name — название шага, устанавливающего имя пользователя Git.
        • run: | — начало блока команд для выполнения.
          • git config --local user.name "author" — установка имени пользователя Git.
      • - name: Create new makefile-build-branch — название шага, создающего новую ветку для сборки через Makefile.
        • run: |: Начало блока команд для выполнения.
          • git branch -d makefile-build-branch — удаление ветки локально
          • git checkout -b makefile-build-branch — создание новой ветки.
          • git add . — добавление изменений для коммита.
          • git commit -m "a project through Makefile is built" — коммит изменений с сообщением.
      • - name: Push to remote branch — название шага, отправляющего изменения на удаленную ветку.
        • run: | — начало блока команд для выполнения.
          • git push -u origin makefile-build-branch --force — отправка изменений на удаленную ветку.

CI/CD Сборка

Получите токен раннера

Создайте токен раннера в профиле репозитория во вкладке Настройки > Раннеры > Добавить раннер > пиктограмма копирования раннера.

Пример:

Зарегистрируйте раннер

$ sudo ./act_runner register
INFO Registering runner, arch=amd64, os=linux, version=40a6fce.
INFO Enter the runner token:
qbTVGAj5pZrLtYTjAR3SSHoWu3Qy6dgBkSkyJAwo
INFO Enter the runner name (if set empty, use hostname: DESKTOP-VOTMM9Q):
makefile-build-demo
INFO Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-20.04:docker://node:16-bullseye,ubuntu-18.04:docker://node:16-buster,linux_arm:host):
 
INFO Registering runner, name=makefile-build-demo, instance=https://gitverse.ru/sc, labels=[ubuntu-latest:docker://node:16-bullseye ubuntu-22.04:docker://node:16-bullseye ubuntu-20.04:docker://node:16-bullseye ubuntu-18.04:docker://node:16-buster].
DEBU Successfully pinged the GitVerse instance server
INFO Runner registered successfully.

Пример:

Сохраните и отправьте изменения в удаленный репозиторий

git add .
git commit -m "ваш комментарий"
git push -u origin makefile-build

Запустите раннер

sudo ./act_runner daemon

Раннер сработает на ранее отправленное изменение (событие push) и через некоторое время отправит в репозиторий новую ветку makefile-build-branch с собранным проектом.

Пример:

Проверка сборки

Через некоторое время раннер выполнит задачи.

Пример:

Пример:

После успешной сборки обновите ваш локальный репозиторий, сохраните изменения в текущей ветке (если они были сделаны) и перейдите в ветку makefile-build-branch:

git pull
git add .
git commit -m "ваш комментарий"
git switch makefile-build-branch

Запустите проект:

$ java /target/Main
Hello, World!

Когда вы используете java Main, Java виртуальная машина ожидает, что имя класса будет указано после слова java, без расширения файла. Таким образом, Main будет рассматриваться как имя класса для запуска.

С другой стороны, когда вы используете java Main.java, вы указываете Java виртуальной машине запустить файл Main.java, который не является допустимым способом для запуска Java-программы. Таким образом Java виртуальная машина ожидает имя класса, а имя файла .java.