Загрузите общую библиотеку Jenkins Pipeline из того же хранилища

TL; DR Есть ли способ импортировать код в Jenkinsfile из локального репозитория (кроме шага load)?

Зачем?

Я Jenkinsfile что для сложных сборок Jenkinsfile становится громоздким и не очень Jenkinsfile обслуживаемым.
Теперь, когда заданием на сборку является код, было бы замечательно иметь те же средства, что и для другого кода. То есть я хотел бы разделить его на более мелкие (более обслуживаемые) блоки и провести их модульное тестирование.

Что я пробовал

  • разделяемые библиотеки: позволяют разделить нашу логику Jenkins Pipeline на меньшие файлы в отдельном модуле и даже выполнить ее модульное тестирование.
    Однако они должны находиться в другом хранилище и (если не на GitHub) должны быть настроены в Jenkins.
  • Шаг load: разрешить загрузку скриптов Groovy из репозитория.
    Однако файлы должны быть сценариями, а не "полными" классами Groovy, что затрудняет создание нескольких файлов или классов, которые зависят друг от друга. Например наследование невозможно.
    Кроме того, эти файлы не отображаются при воспроизведении задания Jenkins, что затрудняет их разработку и отладку.

Мои вопросы

  • Есть ли способ (или обходной путь) создать общую библиотеку в том же хранилище, что и Jenkinsfile и импортировать эту библиотеку в Jenkinsfile?
  • Или есть еще какой-то способ, которым я еще не пробовал?

Пример структуры каталогов

Подобно структуре каталогов, описанной для разделяемых библиотек, я бы хотел, чтобы в одном репозитории было следующее.

(root)
+- someModule
|   +- ...
+- jenkins           # Classes/Scripts used by Jenkins in a separate module
|   +- src                       # Groovy source files
|      +- org
|          +- foo
|              +- Bar.groovy     # for org.foo.Bar class
|   +- test                      # Groovy test files
|      +- org
|          +- foo
|              +- BarTest.groovy # Test for org.foo.Bar class
|   +- pom.xml or build.groovy   # Build for local library
+- Jenkinsfile     # Build "someModule", uses classes from "jenkins" module

Ответ 1

Решение:

library identifier: '[email protected]', retriever: legacySCM(scm)

Подход, используемый в настоящее время в PR 37, не будет работать должным образом с агентами сборки, и в любом случае будет работать только для сценариев, использующих шаг library, а не аннотацию @Library.

Кстати, файлы, загруженные с шага load, отображаются в Replay. Но это правда, что ваш скрипт не может статически ссылаться на типы, определенные в таких файлах. Другими словами, вы можете смоделировать библиотеку vars/*.groovy, но не src/**/*.groovy - то же ограничение, что и в текущем PR 37.

Ответ 2

Я предполагаю, что правильный способ сделать это - реализовать пользовательский SCMRetriever.

Однако вы можете использовать следующий хак:

Предполагая, что jenkins/vars/log.groovy в вашем локальном репо содержит:

def info(message) {
    echo "INFO: ${message}"
}

Ваш Jenkinsfile может загрузить эту общую библиотеку из каталога jenkins/, используя шаг library:

node('node1') { // load library
    checkout scm
    // create new git repo inside jenkins subdirectory
    sh('cd jenkins && git init && git add --all . && git commit -m init &> /dev/null') 
    def repoPath = sh(returnStdout: true, script: 'pwd').trim() + "/jenkins"
    library identifier: '[email protected]', retriever: modernSCM([$class: 'GitSCMSource', remote: repoPath])
}

node('node2') {
    stage('Build') {
        log.info("called shared lib") // use the loaded library
    }
}

Ответ 3

Вы можете взглянуть на плагин, который я написал, который позволяет использовать подкаталоги репо, где ваш конвейер является разделяемыми библиотеками: https://github.com/karolgil/SharedLibrary

После его создания и установки вы можете просто добавить следующее в свой конвейер:

@SharedLibrary('dir/in/repo') _

Чтобы начать использовать dir/in/repo в качестве общей библиотеки для ваших конвейеров.

Ответ 4

Хотелось сделать то же самое и в итоге создало это:

https://github.com/jenkinsci/workflow-cps-global-lib-plugin/pull/37

и вот как я его использую:

https://github.com/syndesisio/syndesis-pipeline-library/blob/master/Jenkinsfile#L3

В моем случае я хотел создать файл Jenkins, который фактически tests содержит библиотеку конвейера, содержащую репозиторий.

Сообщите мне, что вы думаете, и не стесняйтесь добавлять комментарии к PR тоже.

Ответ 5

Я обнаружил, что версия от Pawel имеет проблемы, если вы проверяете конвейер из SCM (не встроенный в конфигурацию пользовательского интерфейса задания Jenkins). Это моя версия для этих случаев:

node {
    def scriptFolder = sh(script: "echo \$(pwd | sed 's,\\(.*\\)\\(@[0-9]*\$\\),\\1,')@script/\$(sed -n '2,\$p' ../config.xml | xmllint --xpath '(//scriptPath/text())' - | xargs dirname)", returnStdout: true).trim()
    sh("cd ${scriptFolder} && ls -l vars/ && if [ -d .git ]; then rm -rf .git; fi; git init && git add --all . && git commit -m init &> /dev/null")
    library identifier: '[email protected]', retriever: modernSCM([$class: 'GitSCMSource', remote: scriptFolder])

    stage('Build') {
        log.info("called shared lib") // use the loaded library
    }
}

В этих случаях сам конвейер извлекается в другом рабочем пространстве (с тем же именем каталога, но с именем @script), чем то, что определяет сам конвейер.