Постобработка и уведомления о результате сборки

Рейтинг: 67.6% · 8 голосов
Подробный курс по Jenkins и CI/CD: установка и настройка, плагины и Configuration as Code, конвейеры (pipeline) и Jenkinsfile, declarative и scripted, агенты, Docker и Kubernetes, общие библиотеки на Groovy, безопасность и credentials, интеграции (SonarQube, артефакты), траблшутинг. Актуально на 2026.
Ответить
Аватара пользователя
Andrey_CICD
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Постобработка и уведомления о результате сборки

Сообщение Andrey_CICD »

Оглавление курса (47)
  1. Что такое Jenkins и зачем нужен CI/CD
  2. Jenkins в 2026: версии, экосистема и сравнение с GitLab CI и GitHub Actions
  3. Архитектура Jenkins: контроллер, агенты, узлы и исполнители
  4. Установка Jenkins: пакеты, Docker и Kubernetes
  5. Первичная настройка Jenkins: мастер, плагины, пользователи
  6. Плагины Jenkins: установка, обновление и ключевой набор
  7. Configuration as Code (JCasC): настройка Jenkins декларативно
  8. Конвейеры Jenkins и Jenkinsfile: pipeline as code
  9. Scripted против Declarative: два синтаксиса конвейера
  10. Структура конвейера: node, stage, steps и первый pipeline
  11. Генератор сниппетов, запуск конвейера и Replay
  12. Типы заданий Jenkins: Freestyle, Pipeline, Multibranch и Organization
  13. Декларативный конвейер: структура pipeline, agent, stages
  14. agent, environment и переменные в конвейере
  15. tools, options, parameters и triggers в декларативном конвейере
  16. stages, parallel и matrix: организация этапов
  17. Условное выполнение when и блок post
  18. Триггеры сборки: webhook от GitHub, SCM polling и расписание
  19. Параметры сборки и пользовательский ввод
  20. Управление потоком: timeout, retry, sleep и waitUntil
  21. Параллелизм и блокировки: parallel, lock, milestone
  22. Постобработка и уведомления о результате сборки (вы здесь)
  23. Groovy для Jenkins: основы скриптового конвейера
  24. Скриптовый конвейер: логика, циклы и функции
  25. Общие библиотеки Jenkins: Shared Libraries
  26. Подключение и загрузка общих библиотек
  27. Шаги оболочки: sh, bat, powershell и коды возврата
  28. Переменные среды, withEnv и рабочие пространства
  29. Работа с файлами, артефактами и отпечатками
  30. Сборка проектов в конвейере: Maven, Gradle, npm
  31. Качество кода: SonarQube и покрытие тестами
  32. Управление артефактами: публикация в Nexus и Artifactory
  33. Docker в Jenkins: образы как агенты сборки
  34. Сборка и публикация Docker-образов из конвейера
  35. Jenkins в Kubernetes: динамические pod-агенты
  36. Развёртывание в Kubernetes из конвейера
  37. Безопасность Jenkins: аутентификация и матрица прав
  38. Учётные данные Jenkins: credentials в конвейере
  39. Безопасность сценариев: Groovy sandbox и Vault
  40. Уведомления и отчёты: email, Slack, Telegram, HTML
  41. Blue Ocean и интерфейс Jenkins в 2026
  42. Автоматизация Jenkins: CLI, REST API и script console
  43. Поиск и устранение неисправностей: читаем логи конвейера
  44. Типичные ошибки конвейера: сериализация и неутверждённый код
  45. Эксплуатация Jenkins: бэкап, обновление, масштабирование
  46. Конвертация и миграция: от Freestyle к Jenkinsfile
  47. Итог: сквозной CI/CD конвейер и Jenkins против альтернатив в 2026
Сборка прошла - и тишина. Артефакты остались валяться в workspace, отчёт о тестах никто не открыл, а о том, что ночной билд развалился, команда узнаёт утром по сломанному деплою. Знакомо? Конвейер, который только собирает, но ничего не делает после, - это половина работы. Настоящая ценность CI начинается там, где сборка уже закончилась: убрать за собой мусор, сохранить нужное, разложить отчёты и громко сказать людям, что произошло. Этим занимается блок post - постобработка результата.

В этом уроке разберём, как устроена секция post в declarative pipeline, какие у неё условия (always, success, failure и компания), как гарантированно чистить workspace через cleanWs, публиковать результаты тестов через junit, архивировать артефакты и слать jenkins уведомления так, чтобы они доходили только когда надо.

Зачем нужен блок post и как он работает

Главная идея: шаги внутри stages выполняются, только пока всё хорошо. Упал тест, свалился sh с ненулевым кодом - и остаток pipeline просто не запускается. А что если именно при падении нужно отправить алёрт и собрать логи? Если писать это обычными шагами в конце, до них дело не дойдёт. Любой jenkins build может оборваться в середине, и постобработка должна сработать в любом случае.

Секция post решает ровно это. Она объявляется на уровне всего pipeline или внутри отдельного stage и выполняется ПОСЛЕ основной работы - независимо от того, успех там или провал. По сути это аналог try/finally из обычного программирования: что бы ни случилось в теле, finally отработает. В scripted-конвейере так и пишут руками, через try/catch/finally, - к этому вернёмся ниже. В declarative за тебя это делает движок: ты просто описываешь, что и при каком исходе делать.

Внутри post живут не произвольные шаги, а условные блоки. Вот полный набор на 2026 год:
  • always - выполняется всегда, при любом статусе. Сюда кладут очистку и то, что нужно сделать безусловно.
  • success - только если сборка зелёная.
  • failure - только если сборка упала (статус FAILURE). Главный кандидат для жёстких алёртов.
  • unstable - сборка "нестабильна": обычно это упавшие тесты или нарушения качества кода, помеченные жёлтым.
  • aborted - сборку прервали (обычно вручную или по таймауту).
  • unsuccessful - всё, что НЕ success: объединяет failure, unstable и aborted.
  • changed - статус отличается от предыдущего запуска (был success, стал failure - или наоборот).
  • fixed - починилось: текущая сборка успешна, а предыдущая была failure или unstable.
  • regression - регрессия: текущая упала/нестабильна/прервана, а предыдущая была успешной. Самый ценный сигнал - "только что сломали".
  • cleanup - выполняется в самом конце, ПОСЛЕ всех остальных условий, всегда. Финальная уборка.
Запомни порядок: сначала отрабатывает always, затем подходящие по статусу условия (success или failure и т.п.), а cleanup - гарантированно последним. Поэтому окончательную очистку логично вешать именно на cleanup, а не на always: к моменту always другие блоки ещё могут что-то писать в workspace.

Изображение

Практика: junit, archiveArtifacts и уведомления в post

Соберём типовой declarative pipeline, который собирает Java-проект, гоняет тесты и аккуратно завершается. Обрати внимание, как jenkins post-секция распределяет действия по исходам.

Код: Выделить всё

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                sh './gradlew clean assemble'
            }
        }
        stage('Test') {
            steps {
                sh './gradlew test'
            }
        }
    }

    post {
        always {
            // публикуем отчёты JUnit в любом случае - даже если тесты упали
            junit testResults: '**/build/test-results/**/*.xml', allowEmptyResults: true
        }
        success {
            // артефакты сохраняем только у зелёной сборки
            archiveArtifacts artifacts: 'build/libs/*.jar', fingerprint: true
            echo 'Сборка успешна, артефакты заархивированы'
        }
        failure {
            // jenkins post failure - сюда вешаем алёрт
            mail to: 'team@example.com',
                 subject: "СБОРКА УПАЛА: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
                 body: "Смотри лог: ${env.BUILD_URL}console"
        }
        unstable {
            echo 'Тесты красные - сборка нестабильна'
        }
        cleanup {
            cleanWs()
        }
    }
}
Что здесь важно. Шаг junit мы ставим в always - иначе при падении тестов отчёт не опубликуется, а именно он-то и нужен в этот момент. archiveArtifacts имеет смысл только при success: незачем хранить jar от сломанной сборки. Жёсткое jenkins post failure уведомление уходит только при реальном падении, чтобы не спамить команду на каждый запуск. А cleanWs() висит в cleanup - чтобы уборка прошла после того, как junit и archiveArtifacts прочитали свои файлы из workspace.

Про уведомления: шаг mail - встроенный, без плагинов, но примитивный. На практике в 2026-м чаще используют slackSend (плагин Slack Notification), Telegram-интеграции или общую функцию-обёртку. Удобный приём - вынести логику в одну функцию notify и дёргать её из разных условий:

Код: Выделить всё

        failure {
            script {
                notify('danger', "Упала: ${env.JOB_NAME} #${env.BUILD_NUMBER}")
            }
        }
        fixed {
            script {
                notify('good', "Починилась: ${env.JOB_NAME} #${env.BUILD_NUMBER}")
            }
        }
Где notify - твоя функция (например, из shared library), внутри которой и slackSend, и логика выбора канала. Связка failure + fixed даёт классический паттерн: пришёл алёрт "сломалось", через какое-то время - "починилось". Без шума на каждой зелёной сборке.

Отдельно про статус. Внутри post часто нужно знать, чем всё закончилось. Текущий результат лежит в currentBuild.result (значения SUCCESS, FAILURE, UNSTABLE, ABORTED или null, если ещё не задан). Можно и принудительно пометить сборку:

Код: Выделить всё

        always {
            script {
                if (currentBuild.result == 'UNSTABLE') {
                    echo 'Есть красные тесты, но билд не валим'
                }
                echo "Итоговый статус: ${currentBuild.currentResult}"
            }
        }
Поле currentBuild.currentResult удобнее: оно никогда не null и отдаёт текущий вычисленный статус. Запомни разницу: result может быть пустым в начале, currentResult - нет.

Постобработка в scripted: try/catch/finally вручную

Declarative post - это сахар над тем, что в scripted-конвейере пишется руками. Если по теме нужна динамика (генерация stage в цикле, сложная логика), берут scripted, и тогда постобработку оборачивают сам:

Код: Выделить всё

node {
    try {
        stage('Build') {
            sh './gradlew clean assemble'
        }
        stage('Test') {
            sh './gradlew test'
        }
        currentBuild.result = 'SUCCESS'
    } catch (err) {
        currentBuild.result = 'FAILURE'
        throw err          // пробрасываем, чтобы сборка честно покраснела
    } finally {
        junit '**/build/test-results/**/*.xml'
        // jenkins cleanup - гарантированная очистка в finally
        cleanWs()
    }
}
Видно один в один: try - это тело stages, catch ловит падение и красит сборку, а finally - аналог always плюс cleanup. cleanWs() в finally гарантирует, что мусор уберётся, даже если всё рухнуло. Это и есть та самая гарантированная очистка, ради которой declarative-движок и придумал свой post. Понимая эту механику, ты не запутаешься, читая чужой scripted-код.

Типичные грабли
  • junit в success вместо always. Тесты упали, статус FAILURE, блок success не сработал - и отчёта о тестах нет именно тогда, когда он нужнее всего. Всегда публикуй результаты в always.
  • cleanWs() в always, а не в cleanup. Очистка может снести файлы раньше, чем archiveArtifacts или junit успеют их прочитать. Уборку - в cleanup, он последний.
  • cleanWs() требует плагин. Шаг даёт Workspace Cleanup Plugin. Без него получишь "No such DSL method 'cleanWs'". Поставь плагин или, в простом случае, используй deleteDir() внутри блока (он чистит текущую директорию).
  • Алёрты на каждый запуск. Если уведомление висит в always, команда быстро научится его игнорировать. Шли в failure/regression, а "ожило" - через fixed.
  • archiveArtifacts с allowEmptyArchive по умолчанию false. Если артефакта нет (а при падении его и не будет), шаг сам уронит сборку. Либо держи его в success, либо ставь allowEmptyArchive: true.
  • Путаница result и currentResult. currentBuild.result бывает null. Для проверок в post надёжнее currentBuild.currentResult.
Мини-лаба

Повтори руками, чтобы прочувствовать механику:
  • Возьми любой проект с тестами. Напиши declarative pipeline со стадиями Build и Test.
  • Добавь post с блоками always (junit), success (archiveArtifacts), failure (echo или mail) и cleanup (cleanWs).
  • Запусти зелёным - убедись, что артефакт заархивирован, а failure не сработал.
  • Сломай тест намеренно. Перезапусти. Проверь: отчёт junit опубликован (always отработал), failure сработал, success - нет.
  • Почини тест и запусти снова - проверь, как ведёт себя fixed (если добавишь этот блок).
  • Перепиши тот же конвейер в scripted с try/catch/finally и сравни поведение.
Контрольные вопросы
  • Чем отличается блок always от cleanup и почему очистку лучше вешать на cleanup?
  • В какой блок post поставить шаг junit, чтобы отчёт о тестах публиковался даже при их падении, и почему?
  • Какому конструкту обычного языка соответствует declarative post и как это выглядит в scripted-конвейере?
  • В чём разница между currentBuild.result и currentBuild.currentResult и какое поле надёжнее в post?
Итог

Секция post - это твой finally для всего конвейера: она отрабатывает при любом исходе и раскладывает действия по условиям от always до cleanup. Базовый рабочий набор прост: junit в always, archiveArtifacts в success, уведомление в failure (и fixed для "ожило"), а cleanWs - в cleanup, чтобы уборка была гарантированной и последней. Понимаешь, что под капотом это try/catch/finally, - значит, разберёшь и declarative, и scripted. Дальше будет проще: на этом фундаменте строятся и матрицы окружений, и параллельные стадии.
👍3 ❤️3 🔥3 😄 🤔
Аватара пользователя
keilkb
Сообщения: 1
Зарегистрирован: 28 май 2026, 17:08

Re: Постобработка и уведомления о результате сборки

Сообщение keilkb »

Спасибо, наконец дошло почему junit надо в always а не в success. У меня как раз отчёты пропадали ровно когда тесты падали, теперь понятно.
👍2 ❤️2 🔥 😄 🤔
Аватара пользователя
marc27
Сообщения: 1
Зарегистрирован: 31 май 2026, 05:56

Re: Постобработка и уведомления о результате сборки

Сообщение marc27 »

А cleanWs у меня ругался No such DSL method, оказалось плагин Workspace Cleanup не стоял. Добавлю в заметку, может кому пригодится.
👍 ❤️1 🔥1 😄 🤔
Ответить
← Предыдущая глава
Параллелизм и блокировки: parallel, lock, milestone
Следующая глава →
Groovy для Jenkins: основы скриптового конвейера

Все главы курса «Jenkins: конвейеры CI/CD от основ до продакшена»

Поделиться темой: ✈ Telegram VK

Вернуться в «Jenkins: конвейеры CI/CD от основ до продакшена»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость