Какой лучший способ массового обновления проектов Jenkins?

У нас есть сотни проектов Дженкинса (в основном созданные из нескольких шаблонов), часто им нужно сделать одинаковые изменения для всех из них. например сегодня мне нужно добавить шаг после сборки, чтобы удалить рабочее пространство в конце. Затем мне нужно изменить шаг для копирования результата сборки на общий диск в репозиторий Nexus.

Какой лучший способ применить такой массовый переход к проектам Дженкинса?

Ответ 1

Groovy, безусловно, лучший способ массового обновления заданий. Возможно, вам придется немного покопаться в API jenkins/plugin, чтобы выяснить, какие вызовы API нужно сделать, но консоль скрипта (http://yourJenkinsUrl/script) предоставляет простой способ поиграться с кодом, пока вы его не получите право.

Для начала вы можете добавить/удалить шаги после сборки, вызвав метод getPublishersList() для задания, а затем вызвав методы добавления/удаления.

def publishersList = Jenkins.instance.getJob("JobName").getPublishersList()
publishersList.removeAll { it.class == whatever.plugin.class }
publishersList.add(new PluginConstructor())

Если вы не уверены, из какого класса издателя вам нужно удалить рабочее пространство, я бы предложил вручную добавить нужные конфигурации в одно задание, а затем запустить getPublishersList() из консоли сценария для этого задания. Вы увидите класс, с которым вы работаете, в списке, а затем вы можете посмотреть на API, чтобы увидеть, что требуется для его создания.

Затем вы можете просмотреть все ваши задания и добавить издателя, выполнив что-то вроде этого:

Jenkins.instance.getView("All Jobs").items.each { job ->
    //Maybe some logic here to filter out specific jobs

    job.getPublishersList().add(new PluginConstructor())
}

В качестве альтернативы, вы можете использовать API-интерфейс Jenkins CLI или API-интерфейс REST, но для обновления действий после сборки вам придется изменить XML файл конфигурации проекта (который не является тривиальным программным способом), а затем перезаписать конфигурацию задания с помощью новый файл конфигурации.

Ответ 2

REST API довольно мощный. Следующая последовательность работала для меня:

В цикле для всех соответствующих проектов (список проектов доступен, например, через /api/xml?tree=jobs[name]):

  • скачать config.xml через /job/{name}/config.xml
  • редактировать, используя ваш любимый XML-редактор со скриптами (мой был xmlstarlet)
  • загрузить новый config xml через /job/{name}/config.xml

Несколько случайных заметок:

  • сделать * BACKUP *, прежде чем делать что-либо
  • Возможно, я мог бы опубликовать пример скрипта bash, если кому-то интересно

Удачи!

РЕДАКТИРОВАТЬ> Пример сценария bash:

#!/bin/bash

jenkinsUrlBase='http://user:[email protected]'

callJenkins() { # funcPath
    curl --silent --show-error -g "${jenkinsUrlBase}${1}"
}

postJenkinsFile() { # funcPath fileName
    curl --silent --show-error -g -d "@${2}" "${jenkinsUrlBase}${1}"
}

callJenkins '/api/xml?tree=jobs[name]' | xmlstarlet sel -t -v '//hudson/job/name' | while read projectName ; do

    echo "Processing ${projectName}..."
    origFile="${projectName}_old.xml"
    newFile="${projectName}_new.xml"
    callJenkins "/job/${projectName}/config.xml" > "$origFile"

    echo " - Updating artifactory url..."
    cat "$origFile" \
        | xmlstarlet ed -P -u '//maven2-moduleset/publishers/org.jfrog.hudson.ArtifactoryRedeployPublisher/details/artifactoryUrl' -v "http://newServer/artifactory" \
    > "${newFile}"

    if false ; then
        echo " - Commiting new config file..."
        postJenkinsFile "/job/${projectName}/config.xml" "$newFile"
    else
        echo " - Dry run: not commiting new config file"
    fi

done

Ответ 4

Вы можете отредактировать файл config.xml с помощью вашего любимого текстового инструмента (я использую Python), а затем перезагрузить конфигурацию jenkins.

В моей настройке задания хранятся в ~/.jenkins/jobs/*/config.xml.

Смотрите: https://wiki.jenkins-ci.org/display/JENKINS/Administering+Jenkins

Вот небольшой пример обновления foo до bar:

    </com.cwctravel.hudson.plugins.extended__choice__parameter.ExtendedChoiceParameterDefinition>
        <hudson.model.StringParameterDefinition>
          <name>additional_requirements</name>
          <description>foo</description>
...

Сценарий:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals, print_function

import sys
from lxml import etree
from collections import defaultdict


def change_parameter_description(config_xml_path, parameter_name, new_description):
    tree=etree.parse(config_xml_path)

    for tag in tree.findall('.//hudson.model.StringParameterDefinition'):
        name_tag=tag.find('./name')
        if not name_tag.text==parameter_name:
            continue
        description=tag.find('./description')
        description.text=new_description
    tree.write(config_xml_path)


for config_xml_path in sys.argv[1:]:
    change_parameter_description(config_xml_path, 'additional_requirements', 'bar')

В этом небольшом примере сработало бы регулярное выражение, но если вещи занимают несколько строк, лучше работать с инструментами xml :-)

Ответ 5

Другие ответы хороши, но если вы используете конвейеры, я бы посоветовал вам использовать Pipeline Shared Libraries.

У нас есть все наши работы в Git-хранилище. Чтобы разработать новую функцию, мы пробуем ее в ветке, поскольку можно указать только одну работу на конкретную ветку. Когда нам нужно обновить их, просто слиться с мастером. Задания обрабатываются как код с соответствующим процессом выпуска.