Так, например, мне лень писать длинный pipeline (вообще писать руками pipeline лень). И мне не нравится идея гонять туда — сюда файлик, в который придётся писать параметры, для чего городить огород из лишнего кода.
Кстати, может кто-то из читателей этой статьи сможет объяснить, почему нужно выполнять все операции (сборка дистрибутива, его тестирование и т. д.) на той же машине, где расположен Jenkins? Я вот так не считаю и моя архитектура построена так, что Jenkins нужен для запуска задач, а вот они (задачи) выполняются на отведённых под эти вещи машинах. Но это лирика и желание пообщаться и поделиться опытом.
Сама статья о другом: как сохранить параметры и параметризовать регулярную Job'у удобно и штатно?
Давайте представим гипотетическую ситуацию, когда вам нужно сделать регулярный запуск некоторого набора тестов по расписанию.
Вы уже сделали некоторою Job'у, с использованием плагина Active Choices и теперь вы молодцы и можете запускать руками нужный набор.
Но как теперь объединить обе этих функции, чтобы получить выгоду от обоих подходов?
Не буду рассказывать всех тех вариантов, которые мне пришлось услышать или попробовать, а сразу перейду к самой сути. Решение моё лишь частично, так как реализация была найдена на Medium. Я же решил поделиться им с сообществом, чтобы больше людей перестали костылить и делать глупости.
Целевая картина в нашем случае будет выглядеть так: есть Job'а для управления набором сценариев, которая используется, когда этот самый набор нужно отредактировать, и есть регулярная Job'а, которая будет использовать и регулярно запускать нужный набор.
Первое, что нужно сделать — это создать пару переменных: одна для хранения «эталонного набора» и вторая для непосредственного хранения целевого набора. Для этого переходим по меню Jenkins «Настроить Jenkins — > Конфигурация системы — > Глобальные настройки»:
Создатели Jenkins позаботились о своих пользователях и нам только остаётся добавить две переменные, как показано на изображении выше.
Когда переменные созданы, нужно установить плагин Active Choices, если ещё не установлен. Он нам ещё пригодится.
Создадим задачу со свободной конфигурацией. Укажем, что сборка параметризованная, установив checkbox «Это — параметризованная сборка». И добавим параметр типа «Active Choices Reactive Parameter».
Назовём этот параметр «first_param», для примера.
Добавим следующий код, как показано на изображении выше:
import jenkins.model.*
//получаем конкретный instance
instance = Jenkins.get()
//получаем доступ к глобальным переменным
globalNodeProperties = instance.getGlobalNodeProperties()
myParam = 'Not Set'
globalNodeProperties.each {
envVars = it.getEnvVars()
if (envVars.get('my_env') != null) {
myParam = envVars.get('my_env');
}
}
def scriptList = [];
def a = myParam.trim().replaceAll(~/^\[|\]$/, '').split(',').collect{ it.trim()}
scriptList.addAll(a)
return scriptList.flatten()
На выходе код отдаёт одномерный массив.
Я предпочитаю заполнять блок fallback, как показано ниже:
«Choice Type» предлагаю выбрать самостоятельно. В моём случае это «Checkboxes». " Referenced parameters" оставляем пустым.
Теперь нужно создать ещё один параметр. В моём примере это second_param.
В секцию «Groovy script» добавим следующее:
//импорт библиотек для работы
import hudson.EnvVars;
import hudson.slaves.EnvironmentVariablesNodeProperty;
import hudson.slaves.NodeProperty;
import hudson.slaves.NodePropertyDescriptor;
import hudson.util.DescribableList;
import jenkins.model.Jenkins;
//функция для создания или обновления переменных
public createGlobalEnvironmentVariables(String key, String value){
Jenkins instance = Jenkins.getInstance();
DescribableList<NodeProperty<?>, NodePropertyDescriptor> globalNodeProperties = instance.getGlobalNodeProperties();
List<EnvironmentVariablesNodeProperty> envVarsNodePropertyList = globalNodeProperties.getAll(EnvironmentVariablesNodeProperty.class);
EnvironmentVariablesNodeProperty newEnvVarsNodeProperty = null;
EnvVars envVars = null;
if ( envVarsNodePropertyList == null || envVarsNodePropertyList.size() == 0 ) {
newEnvVarsNodeProperty = new hudson.slaves.EnvironmentVariablesNodeProperty();
globalNodeProperties.add(newEnvVarsNodeProperty);
envVars = newEnvVarsNodeProperty.getEnvVars();
} else {
envVars = envVarsNodePropertyList.get(0).getEnvVars();
}
envVars.put(key, value)
instance.save()
}
//конвертирование массива в строку
List<String> list = Arrays.asList(second_param);
String stringRepresentationOfList = String.join(",", list);
//следующая строка создаёт или обновляет глобальную переменную 'Var1'
createGlobalEnvironmentVariables('Var1',stringRepresentationOfList)
В блок «Groovy Script» добавляем код:
return['error']
или что-то более читаемое.
«Choice Type» ставим любой, поскольку эта переменная нам фактически нужна только для выполнения Groovy кода для записи глобальной перемернной. Наверняка можно обойтись и без неё, но так было проще и быстрее.
В «Referenced parameters» записываем название предыдущей переменной second_param, чтобы связать два блока.
Жмём сохранить — et voila!
Для проверки давайте посмотрим, какие исходные значения глобальных переменный у нас сейчас записаны, для чего проходим «Настроить Jenkins — > Конфигурация системы — > Глобальные настройки»:
Теперь возвращаемся к нашей Job'е и нажимаем «Собрать с параметрами». Выбираем, для примера, только один пункт:
Жмём «Собрать» и снова проверяем глобальные переменные:
Как видим, всё работает.
Использование же глобальной переменной до крайности простое. И в своей регулярной Job'е вы можете обратиться к ней, как обычно:
Из нюансов, вынужден отметить, что нажимать кнопку «Собрать» вовсе необязательно, так как перезапись глобальной переменной происходит всякий раз, когда вы выбираете один из пунктов. Но совершенству нет предела и вы можете усовершенствовать моё решение.
quarckster
Какой же этот Дженкинс убогий. Понимаю, что из опенсорс мира мало что сравнится с ним, но вы на скриншоты посмотрите! Да скриптовый пайплайны это круто, но это невозможно отлаживать. Доколе?!
fougasse
Взрослые фанаты опенсорса рекомендуют всякие плагины типа Blue Ocean для сокрытия убогости интерфейса и общей архаичности Hudson/Jenkins.
quarckster
BlueOcean тормозит, и он предназначен только для отображения пайпалайнов. Все административные задачи выполняются в классическом UI.
fougasse
Ну, а что остаётся делать?
Рыночек порешал, что если хочешь красиво — плати, хочешь бесплатно — страдай.
adel-s
А ещё, если какая-то ошибка произошла в скрипте, который не находится внутри блока stage — в BlueOcean её не увидишь. Только в классическом интерфейсе, где-то в самом конце.
ALexhha
Так вам шашечки или ехать? ( c )
Можно пример не убогого CI/CD?
fkvf
concourse-ci.org?
quarckster
drone.io
tmk826
Может выглядит не очень, но пашет как бык. Мы его используем с первой версии, когда он ещё hudson назывался. За 15 лет смотрели на много альтернатив. Остальные кроме внешнего вида функционального превосходства не дают.