Java, CI/CD Makefile сборка
В данном разделе рассмотрен пример CI/CD сборки java проекта через Makefile.
Смотрите также раздел CI/CD сборки Maven проекта.
Для проверки данного примера подготовлена ветка makefile-build в репозитории gitverse_tutorials/CICD_building_projects (opens in a new tab).
Подготовительные действия
-
Создайте репозиторий, например, CICD_building_projects.
-
Обновите список доступных пакетов:
sudo apt update
- Установите JDK-пакет по умолчанию, который включает в себя компилятор Java:
sudo apt install default-jdk
Проверьте, что компилятор установлен:
javac -version
- Скачайте раннер и сделайте его исполняемым:
chmod +x act_runner
-
Включите 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
CC = javac
— определяет переменную CC и устанавливает ее значение равнымjavac
, что указывает на компилятор Java.TARGET_DIR = target
— здесь определяется переменнаяTARGET_DIR
и устанавливается в значениеtarget
, указывающее на директорию, где будут храниться скомпилированные файлы.TARGET = $(TARGET_DIR)/Main
— определяет переменнуюTARGET
, которая представляет собой путь к главному исполняемому файлу Main.all: $(TARGET)
— это цельall
, которая зависит от цели$(TARGET)
, что означает, что при запускеmake all
будет собран целевой файл Main.$(TARGET): Main.java
— указывает, что цель$(TARGET)
зависит от файла Main.java.mkdir -p $(TARGET_DIR)
— создает директорию$(TARGET_DIR)
с ключом -p, который создает все промежуточные директории в пути, если они отсутствуют.$(CC) -d $(TARGET_DIR) Main.java
— использует переменнуюCC
(компилятор javac) для компиляции файла Main.java и помещает скомпилированный файл в директорию$(TARGET_DIR)
.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
.