Перемещение «общего кода» из скриптового конвейера jenkins в «общую библиотеку» - PullRequest
0 голосов
/ 04 февраля 2019

Я новичок как в Дженкинс, так и в Groovy:)

Есть репозиторий Bitbucket, а именно. jenkins-stage , который содержит скриптовый конвейерный код (.groovy скрипты в src, vars и т. Д.).Основные конвейеры обращаются к нескольким служебным классам (которые являются частью самого репозитория jenkins-stage), например, в виде линии:

def call(body) {
    def config = [:]
    body.resolveStrategy = Closure.DELEGATE_FIRST
    def componentName = null
    body.delegate = config
    body()

.
.
.
node(globalVars.getAgent('buildAgent')) {
        try {
            def callHandler = ServiceLocator.getInstance().getNotifyHandler(this)
            def dataUtility = ServiceLocator.getInstance().getDataUtility(this)
            stage(CLEAN_STAGE) {
            .
            .
            .
            }
            catch (err) {

            if (err.message.contains("failed in build") == false ) {
                build_status = "Exception ${err.message} in build ${env.BUILD_ID}"
                callHandler.NotifyFail(build_status, PIPELINE_NAME )
            }
            throw err
        }
    }

}
}

Моя задача состоит в том, чтобы «реорганизовать» несколько классов и переместить их в общийМногоразовая библиотека.Таким образом, несколько конвейеров будут использовать один и тот же служебный код.

Существует несколько классов, в качестве примеров я приведу только пару. ServiceLocator , используемый в приведенном выше конвейере, просто возвращает нужную утилиту:

PipelineService .groovy

/**
 * This is the base class for any components that wants to
 * call pipeline methods and access to the jenkins internal calls
 * (such as node, stage, sh, env, etc)
 */
class PipelineService implements Serializable {
    def script
    def env

    PipelineService(Script script) {
        this.script = script
        this.env = script?.env
    }

}

NotifyHandler .groovy (используется для публикации статуса сборки заданий Jenkins в Artifactory, отправки электронных писем и т. д.)

class NotifyHandler extends PipelineService {

    NotifyHandler(Script script) {
        super(script)
    }

    def NotifyStart(message, pipelineName) {
        script.println "Pipeline: ${pipelineName} Notify commit: ${env.GIT_COMMIT} build start: ${message}"
        postBuildStatus('INPROGRESS', pipelineName, env.BUILD_URL, env.GIT_COMMIT, message)
    }

    def NotifySuccess(message, pipelineName) {
        script.println "Pipeline: ${pipelineName} Notify commit: ${env.GIT_COMMIT} build success: ${message}"
        if (env.GIT_TAG != null && env.GIT_TAG != '') {
            sendEmail(message, pipelineName)
        }
        postBuildStatus('SUCCESSFUL', pipelineName, env.BUILD_URL, env.GIT_COMMIT, message)
    }

    def NotifyFail(message, pipelineName) {
        script.println "Pipeline: ${pipelineName} Notify commit: ${env.GIT_COMMIT} build fail: ${message}"
        sendEmail(message, pipelineName)
        postBuildStatus('FAILED', pipelineName, env.BUILD_URL, env.GIT_COMMIT, message)
    }

    def sendEmail(message, pipelineName) {
        def emailBody = """
    <br>Job name: <b>${env.JOB_NAME}</b></br>
    <br>Change made by: <b>${env.GIT_COMMITTER_NAME}</b></br>
    <br>Commit message is: <b>"${env.GIT_COMMIT_MESSAGE}"</b></br>
    <p>${message} in pipeline: ${pipelineName}. <a href="${env.BUILD_URL}">Build link.</a></p>"""
    .
    .
    .
    }

    def postBuildStatus(state, build_name, build_url, commit, message) {
        .
        .
        .

        // the key here should be the build name, as the uniqueness of the build status
        // in bitbucket is kept using the commit hash and the key
        def jsonBody = """
    {
        "state": "${state}",
        "key": "${build_name}",
        "name": "${build_name}",
        "url": "${build_url}",
        "description": "${message}"
    }
    """
        def response = script.httpRequest url: 'https://git.net/rest/build-status/1.0/commits/' + commit,
                ignoreSslErrors: true,
                eptType: 'APPLICATION_JSON',
                authentication: 'stash-api-credentials',
                httpMode: 'POST',
                contentType: 'APPLICATION_JSON',
                requestBody: jsonBody

        // We never reach this code
        script.println('Response from bitbucket:')
        script.println('Status: ' + response.status)
        script.println('content: ' + response.content)

        return response
    }
}

DataUtility .groovy

import com.cloudbees.groovy.cps.NonCPS

import java.util.regex.Matcher
import java.util.regex.Pattern

class DataUtility extends PipelineService {
    DataUtility(Script script) {
        super(script)
    }

    String createPropertiesString(commitId, commiterName, commiterEmail, buildTS, buildName, jiraNumber, buildNumber) {
        //Commiter name looks like "Name Surname", we have to remove the whitespace between, whitespace will interrupt curl put properties request
        return "CommitID=${commitId};Commiter=${commiterName};Email=${commiterEmail};JIRA=${jiraNumber};build.name=${buildName};build.number=${buildNumber};build.timestamp=${buildTS}".replaceAll("\\s", "")
    }

    String createJiraNumber(branchName) {
        // The name should contain only capital letters after '/' , digits and have '-' between them
        Pattern jiraPattern = Pattern.compile("/([A-Z]+\\-[0-9]+)")
        def jiraNumber = null
        Matcher matcher = jiraPattern.matcher(branchName)
        if (matcher.find()) {
            jiraNumber = matcher.group().substring(1)
        }
        return jiraNumber
    }

    @NonCPS
    def getBuildInfoFromGitRepo(creds, path, commitId) {
        def process = ['curl', '-u', "${creds}", '-k', "${path}?at=${commitId}"].execute()
        script.writeFile file: "${env.WORKSPACE}/buildInfo.json", text: process.text
    }

    def updateBuildInfo(json, listOfUpdates) {
        for (i in listOfUpdates) {
            script.println 'Current component: ' + i
            def iName = i.substring(0, i.lastIndexOf(':'))
            if (json.contains(iName)) {
                json = json.replaceAll(/"${iName}:[^"]+/, "\"${i}")
            }
        }
        return json
    }
}

Я имею в видук документации общей библиотеки Jenkins .Предположим, я создаю новый проект / Bitbucket repo, а именно. pipe-utilities , тогда я могу использовать аннотацию @library в Jenkinsfile jenkins-stage, чтобы использовать мою новую библиотеку.У меня есть следующие вопросы / проблемы:

  1. Прежде всего, я на правильном пути?
  2. Я считаю, что ServiceLocator не требуется, особенно после обращения к ' Динамическая загрузка библиотек '
  3. Необходимо / рекомендуется создавать сценарии в каталоге vars, которые будут выступать в качестве переменных в конвейерах на этапах jenkins?Нужно ли каким-либо образом использовать служебные классы с помощью этих сценариев?
  4. Согласно ' доступу к шагам ', 'Библиотечные классы не могут напрямую вызывать такие шаги, как sh или git.'.Хотя я не видел этот сценарий в текущих служебных классах, я не уверен, был ли добавлен класс PipelineService для решения этой проблемы!Я не понял этот раздел «Доступ к шагам»: (
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...