Введение: от базовых пайплайнов к промышленным решениям
Базовый CI/CD пайплайн для Java проекта — это хорошо. Но в реальной разработке, когда проект разрастается до десятков модулей, а команда состоит из нескольких разработчиков, простой `mvn clean test` перестаёт отвечать требованиям. Возникают вопросы: как ускорить сборку? Как тестировать на разных версиях JDK? Как организовать параллельный запуск тестов? Как автоматически публиковать артефакты в Docker Hub?
В этой статье мы разберём продвинутые техники настройки GitHub Actions для Java проектов. Вы узнаете, как превратить ваш пайплайн из линейной последовательности шагов в мощную, параллельную и оптимизированную систему непрерывной интеграции и доставки.
1. Матричные сборки: тестирование на нескольких JDK и ОС
Одна из ключевых задач CI — гарантировать, что ваш Java-код работает на всех поддерживаемых платформах. Ручной запуск тестов на Windows, macOS и Linux с разными версиями JDK (11, 17, 21) — непозволительная роскошь. GitHub Actions предлагает элегантное решение: матричные сборки (matrix builds).
Как это работает
Вы определяете матрицу параметров (версии JDK, операционные системы), и GitHub автоматически создаёт отдельный джоб для каждой комбинации. Все они запускаются параллельно.
Пример конфигурации
name: Java CI Matrix
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
java: [11, 17, 21]
exclude:
- os: windows-latest
java: 21 # Исключаем JDK 21 на Windows, если он не поддерживается
fail-fast: false # Не останавливать остальные джобы при ошибке в одном
steps:
- uses: actions/checkout@v4
- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
- name: Build with Maven
run: mvn -B clean verify --file pom.xml
Ключевые моменты:
strategy.matrix— определяет комбинации параметров.exclude— позволяет исключить заведомо нерабочие или ненужные комбинации.fail-fast: false— если один джоб упал, остальные продолжат работу. Это даёт полную картину совместимости.
2. Кэширование зависимостей: ускоряем сборку в 2-3 раза
Каждый запуск пайплайна начинается с чистого окружения. Maven или Gradle заново скачивают все зависимости из репозиториев. Это может занимать 3-5 минут. Кэширование решает эту проблему, сохраняя папку ~/.m2/repository (для Maven) или ~/.gradle/caches (для Gradle) между запусками.
GitHub Actions предоставляет встроенное действие actions/cache. Ключ кэша формируется на основе файла с зависимостями (pom.xml). Если файл не менялся — кэш восстанавливается мгновенно.
Пример для Maven
steps:
- uses: actions/checkout@v4
- name: Cache Maven dependencies
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Maven
run: mvn -B clean verify --file pom.xml
Важно: Кэширование должно идти до шага сборки. Ключ hashFiles('**/pom.xml') гарантирует, что кэш будет обновлён только при изменении зависимостей.
3. Параллельное выполнение тестов и артефакты сборки
Когда ваш проект содержит сотни или тысячи тестов, их последовательное выполнение может занять десятки минут. GitHub Actions позволяет разбить тесты на несколько параллельных джобов, а затем объединить результаты.
Стратегия "разделяй и властвуй"
Мы можем запускать модульные и интеграционные тесты в разных джобах, а также собирать JAR-артефакты отдельно.
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Run unit tests
run: mvn -B test -Dtest=*Test
- name: Upload unit test results
if: always()
uses: actions/upload-artifact@v4
with:
name: unit-test-results
path: target/surefire-reports/
integration-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Run integration tests
run: mvn -B verify -Dtest=*IntegrationTest
- name: Upload integration test results
if: always()
uses: actions/upload-artifact@v4
with:
name: integration-test-results
path: target/failsafe-reports/
build-jar:
needs: [unit-tests, integration-tests] # Ждём завершения обоих джобов
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build JAR
run: mvn -B package -DskipTests
- name: Upload JAR artifact
uses: actions/upload-artifact@v4
with:
name: myapp-jar
path: target/*.jar
Преимущества:
- Значительное сокращение общего времени пайплайна.
- Чёткое разделение ответственности между джобами.
- Возможность скачать отчёты о те