Создание интеграции с сервисом Jenkins при помощи пользовательских скриптов


Пользовательские скрипты доступны только в Self-Hosted версии

Существует два способа работы с Jenkins, которые можно использовать отдельно или вместе:

  1. Запуск задач Jenkins по событию в Gitflic (или другому триггеру)
  2. Создание “зеркальных” конвейеров из Jenkins в Gitflic

Запуск задач по событиям

В рамках такого вида интеграции задачи в Jenkins запускаются по событиям gitflic при помощи REST-API Jenkins.

Настройка

Интеграция осуществляется при помощи REST-API Jenkins. Для работы с ним необходимо изнакомиться с документацией Jenkins: https://www.jenkins.io/doc/book/using/remote-access-api/

На настройках Item, которым вы хотите управлять, необходимо включить настройку Trigger builds remotely (e.g., from scripts) и указать название (не содержание) REST-API токена Jenkins, который вы хотите связать с данным Item

После, необходимо создать переменные для скрипта. Переходим во вкладку проекта “Скрипты”, далее - во вкладку переменные

image.png

Необходимо создать переменные:

JENKINS_BASE_URL - базовый путь к Jenkins

JENKINS_JOB_NAME - название запускаемой задачи

JENKINS_TOKEN_NAME - имя токена REST-API Jenkins

JENKINS_TOKEN - токен REST-API Jenkins

JENKINS_BASIC_AUTH_BASE64 - базовая аутентификация REST-API Jenkins

Создадим скрипт. Для этого перейдём во вкладку проекта “Скрипты” и нажмём на “Новый скрипт +”

image.png

В качестве тестовой настройки можете использовать следующий код:

const url = '${JENKINS_BASE_URL}/job/${JENKINS_JOB_NAME}/build?token=${JENKINS_TOKEN_NAME}'
req = http.post(url, {}, { headers: { "Authorization": `Basic ${JENKINS_BASIC_AUTH_BASE64}` } });

console.log(JSON.stringify(req))
req.code

В качестве переменных укажите все, которые создали ранее.

Триггеры можно указать любые, в качестве отладки рекомендуем использовать событие BRANCH_UPDATE (push).

При обновлении ветки в вашем проекте, результатом работы скрипта будет запуск Item в Jenkins:

image.png

Создание “зеркальных” конвейеров

При таком варианте интеграции, запущенные в Jenkins конвейеры будут отображаться в Gitflic на странице CI/CD, однако не будут выполняться агентами. В таком случае при запуске конвейера в Jenkins создаётся “пустой” конвейер (который не обрабаывается раннерами и не имеет логов выполнения) в Gitflic, и по окончании его выполнения в Jeknins, обновляется статус в Gitflic, при этом также после выполнения отображаются стадии и их статусы, время выполнения пайплайна в Jenkins.

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

Настройка

Настройка Gitflic

Сперва необходимо создать скрипт, который будет обрабатывать запросы с Jenkins. Для этого перейжите на вкладку “Скрипты” и нажмите на кнопку “Новый скрипт”

image.png

Далее укажите название и описание, в качестве скрипта используйте код ниже:

let res = undefined;
console.log(request);
request = JSON.parse(request);
const event = request.event;

function createStages(stages, pipelineId) {
    return stages.map(stage => pipelineService.createStage(pipelineId, stage.name, stage.status));
}

if (event == "new_pipeline") {
    console.log("creating pipeline");
    res = pipelineService.createBlank(projectId, request.ref);
}

if (event == "pipeline_finished") {
    console.log("finished pipeline");
    pipelineService.changeStatus(request.uuid, request.pipelineStatus);
    createStages(request.stages, request.uuid);
    pipelineService.setExecutionTime(request.uuid, request.duration);
    res = "ok";
}

res;

Нажмите на кнопку “Создать скрипт +”

image.png

После сохранения, проверьте корректность отображения скрипта. Скопируйте UUID скрипта для настройки Jenkins

image.png

Создайте файл Jenkinsfile в репозитории со следующим содержанием:

pipeline {
    agent any

    stages {
        stage('echo'){
            steps {
                echo 'hello Jenkins from Gitflic!!! =)'
            }
        }
    }
}

image.png

Настройка Jenkins

Для работы интеграции необходимо установить следующие плагины:

Git Credentials Pipeline: multibranch, Groovy events listener plugin.

Перейдите в настрйоки Jenkins, в секцию System.

На данной странице необходимо определить несколько глобальных переменных, а именно:

GITFLIC_API_BASE_URL - основной путь REST-API Gitflic

GITFLIC_API_TOKEN - токен REST-API Gitflic

GITFLIC_INTEGRATION_SCRIPT_UUID - UUID скрипта, которого мы создали ранее

GITFLIC_PROJECT_ALIAS - название проекта, к которому привязан скрипт

GITFLIC_PROJECT_OWNER_ALIAS - имя автора проекта, к которому привязан скрипт

image.png

Далее в блоке Groovy events listener plugin напишите следующий код:

@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.1')
@Grab('commons-codec:commons-codec:1.9')

import groovyx.net.http.*;
import static groovyx.net.http.ContentType.JSON;
import jenkins.model.*;

def restPath = "/rest-api/project/${env.GITFLIC_PROJECT_OWNER_ALIAS}/${env.GITFLIC_PROJECT_ALIAS}/script/${env.GITFLIC_INTEGRATION_SCRIPT_UUID}";
def restClient = new RESTClient("${env.GITFLIC_API_BASE_URL}");
restClient.headers['Authorization'] = "token ${env.GITFLIC_API_TOKEN}";

def client = [
    executeScript: { Map postParams ->
        restClient.post(
            path: restPath,
            body: postParams,
            requestContentType: JSON
        )
    }
];

if (event == Event.JOB_STARTED) {
    def ref = env.BRANCH_NAME;
    if (ref.startsWith("origin/")) {
        ref = ref.substring(7);
    }
    def resp = client.executeScript([
        "event": "new_pipeline",
        "ref": ref
    ]);
    if (!context.hasProperty('pipelineUuidByBuildId')) {
        context.pipelineUuidByBuildId = [:];
    }
    if (resp.status / 100 == 2 && resp.data.result == "SUCCESS") {
        context.pipelineUuidByBuildId[env.BUILD_ID] = resp.data.returnedValue.id;
    }
}

if (event == Event.JOB_COMPLETED) {
    if (context.containsKey("pipelineUuidByBuildId") && context.get("pipelineUuidByBuildId").containsKey(env.BUILD_ID)) {
        def runResult = run.getResult();
        def pipelineUuid = context.pipelineUuidByBuildId[env.BUILD_ID];
        context.pipelineUuidByBuildId.remove(env.BUILD_ID);
        def pipelineStatus = getStatus(runResult.toString());
        
        client.executeScript([
            "event": "pipeline_finished",
            "pipelineStatus": pipelineStatus,
            "uuid": pipelineUuid,
            "stages": getStages(run).collect{ ["name": it.name, "status": getStatus(it.state)] },
            "duration": run.getDuration(),
            "timestamp": run.getTimeInMillis(),
        ]);
    }
}

def getStatus(rawStatus) {
    switch (rawStatus.toUpperCase()) {
        case "SUCCESS": return "SUCCESS";
        case "UNSTABLE":
        case "FAILURE": return "FAILED";
        case "NOT_BUILT": return "SKIPPED";
        case "ABORTED": return "CANCELED";
    }
}

def getStages(run) {
    def plugin = Jenkins.instance.pluginManager.plugins.find({it.getShortName() == "pipeline-graph-view"});
    def classLoader = plugin.classLoader;
    def graphApiClassName = "io.jenkins.plugins.pipelinegraphview.utils.PipelineGraphApi";
    def graphApiClass = classLoader.loadClass(graphApiClassName);
  return graphApiClass.getConstructor(run.class).newInstance(run).createTree().stages;
}

image.png

Теперь создайте конвейер в Jenkins.

Перейдите на основную страницу и добавьте Multibranch pipeline

image.png

Перейдите в настройки нового конвейера и добавим источник в виде git-репозитория проект в Gitflic

image.png

image.png

Сохраните и запустите конвейер.

В начале выполнения конвйера, в Gitflic появится “пустой” конвейер.

image.png

По окончании выполнения конвейера в Jenkins, его статус обновится в соответствии со статусом в Jenkins, будут добавлены стадии и время выполнения конвейера

image.png