CI/CD для Java: продвинутые настройки GitHub Actions

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: от базовых пайплайнов к промышленным решениям

Базовый 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

Преимущества:

  • Значительное сокращение общего времени пайплайна.
  • Чёткое разделение ответственности между джобами.
  • Возможность скачать отчёты о те

Блоги

Рекомендаций по книгам