Инструменты пользователя

Инструменты сайта


jenkins:pipelines

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
jenkins:pipelines [2024/05/15 09:58]
admin
jenkins:pipelines [2025/01/19 15:53] (текущий)
admin
Строка 1: Строка 1:
 ====== Pipelines ====== ====== Pipelines ======
- 
- 
 ===== Общее ===== ===== Общее =====
- 
 <code groovy> <code groovy>
 if (params.getOrDefault('BOOLEAN_PARAM_NAME', true)) if (params.getOrDefault('BOOLEAN_PARAM_NAME', true))
Строка 268: Строка 265:
 <details> <details>
 <summary>:!: multiline</summary> <summary>:!: multiline</summary>
- 
 <code groovy> <code groovy>
 // Так не работает, переменные не раскрываются // Так не работает, переменные не раскрываются
Строка 289: Строка 285:
  
 ===== Дата/Время ===== ===== Дата/Время =====
- 
   * **java.time.LocalDateTime** - Дата и время без часового пояса в календарной системе ISO-8601, например 2007-12-03T10:15:30\\ неизменяемый объект даты и времени, с точностью до наносекунды, не хранит и не представляет часовой пояс\\   * **java.time.LocalDateTime** - Дата и время без часового пояса в календарной системе ISO-8601, например 2007-12-03T10:15:30\\ неизменяемый объект даты и времени, с точностью до наносекунды, не хранит и не представляет часовой пояс\\
   * **java.time.Instant** - тут что то более жесткое   * **java.time.Instant** - тут что то более жесткое
Строка 343: Строка 338:
  
  
-===== Примеры =====+===== Сохранение артефактов ===== 
 +<details> 
 +<summary>:!: Stash</summary> 
 +Сохраняет указанные файлы для дальнейшего использования в пайплайне, вне зависимости от агентов\\ 
 +Сохраняет в виде TAR архива, поэтому большие файлы не рекомендуется передавать т.к будет проседать ЦП\\ 
 +По умолчанию чистится после каждой сборки, но есть плагины позволяющие сохранить между запусками, "preserveStashes()"\\ 
 +Можно добавить исключения на добавляемые файлы. Сохраняет указанные файлы в текущем рабочем каталоге, распаковывает сохраняя относительные пути\\
  
 +<code groovy>
 +stage("first") {
 +  agent { slave1 }
 +  steps {
 +    (...)
 +    stash includes: 'terraform.tfstate, terraform.backup, .terraform/**', name: DYNAMIC_SLAVE
 +  }
 +}
 +
 +stage("second") {
 +  agent { master }
 +  steps {
 +    cleanWs()
 +    unstash name: DYNAMIC_SLAVE
 +  }
 +}
 +</code>
 +
 +Указывать нужно с маской, например **includes: "my_dir/*"**, при этом сохраняет всю папку
 +<code groovy>
 +        stage("first stage") {
 +            steps {
 +                script {
 +                    sh """
 +                        mkdir my_dir
 +                        touch my_dir/first_file_${BUILD_NUMBER}
 +                        touch my_dir/second_file_${BUILD_NUMBER}
 +                        touch my_dir/three_file_${BUILD_NUMBER}
 +                        ls -l 
 +                    """
 +                    stash includes: "my_dir/*", name: "dirr"
 +                }
 +            }
 +        }
 +        
 +        stage("second stage") {
 +            steps {
 +                script {
 +                    cleanWs()
 +                    sh "ls -l"
 +                }
 +            }
 +        }
 +        
 +        stage("three stage") {
 +            steps {
 +                script {
 +                    unstash name: "dirr"
 +                    sh "ls -l my_dir"
 +                }
 +            }
 +        }
 +</code>
 +</details>
 +
 +
 +<details>
 +<summary>:!: archiveArtifacts</summary>
 +Архивирует артефакты сборки, затем они доступны на веб-странице джобы\\
 +По умолчанию Maven автоматически архивирует произведенные артефакты. Указанные здесь артефакты будут архивированы поверх\\
 +Файлы указываются так же маской\\
 +
 +<code groovy>
 +archiveArtifacts artifacts: 'target/*.jar'
 +archiveArtifacts artifacts: 'target/*.jar, target/*.war'
 +archiveArtifacts artifacts: '**/*.jar'
 +
 +# Из примера выше
 +archiveArtifacts artifacts: 'my_dir/*'
 +</code>
 +</details>
 +
 +
 +
 +
 +===== Примеры =====
 <details> <details>
 <summary>:!: Работа с grafana API</summary> <summary>:!: Работа с grafana API</summary>
Строка 426: Строка 503:
  
 <details> <details>
-<summary>:!: </summary>+<summary>:!: Минимальный пример, скачивание репозитория </summary>
 <code groovy> <code groovy>
 +pipeline {
  
 +    agent {
 +        label 'main-node'
 +    }
 +
 +    options {
 +        quietPeriod 5
 +        ansiColor('xterm')
 +        timestamps()
 +        buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', numToKeepStr: '10')
 +    }
 +
 +    stages {
 +        stage('Prepare') {
 +            steps {
 +                script {
 +                    cleanWs()
 +                    sh(
 +                    label: 'repo sync',
 +                    script: '''
 +                        PATH="${HOME}/.bin:${PATH}"
 +                        repo init -u ssh://username:port/myproject --depth=1
 +                        repo sync
 +                        repo forall -c git checkout "master"
 +                    '''
 +                    )
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +
 +#
 +# Выбор ветки
 +#
 +        stage('Prepare') {
 +            steps {
 +                script {
 +                    SetParameters()
 +                    cleanWs()
 +                    sh(
 +                    label: 'repo sync',
 +                    script: '''
 +                        PATH="${HOME}/.bin:${PATH}"
 +                        repo init -u ssh://username:port/project --depth=1
 +                        repo sync
 +                        if [ ${BRANCH} != "master" ] ; then
 +                            repo forall -c git checkout ${BRANCH}
 +                        fi
 +                        if [ ${GERRIT_REFSPEC} != "master" ] ; then
 +                            cd igs/smodls/i_adm && git fetch ssh://url-repo:port/myproject ${GERRIT_REFSPEC} && git checkout FETCH_HEAD
 +                        fi
 +                    '''
 +                    )
 +                }
 +            }
 +        }
 </code> </code>
 </details> </details>
Строка 434: Строка 569:
  
  
-====== Use Gradle ======+<details> 
 +<summary>:!: Проверка и откат</summary> 
 +<code bash> 
 +    - name: "Проверка и откат" 
 +      block: 
 +        - name: "Перезапускаем сервис" 
 +          import_tasks: 60-restart_service.yml
  
 +        - name: "Делаем паузу и проверяем состояние сервиса"
 +          ansible.builtin.shell:
 +            cmd: "sleep 25 && systemctl is-active myservice@{{ instance_name }}.service"
 +      rescue:
 +        - name: "Откатываемся на бекап"
 +          ansible.builtin.shell:
 +            cmd: 'tar -xzvf ./backups/previous_version.tar.gz -C .'
 +            chdir: '{{ instance.root_path }}/{{ instance_name }}'
 +
 +        - name: "Перезапускаем сервис, уже после отката"
 +          import_tasks: 60-restart_service.yml
 +
 +        - name: "Прерываем выполнение в случае отката"
 +          ansible.builtin.fail:
 +            msg: "!!! Откат изменений после сбоя. Прерываем дальнейшее выполнение !!!"
 +</code>
 +</details>
 +
 +
 +
 +<details>
 +<summary>:!: Выбор инстансов</summary>
 +<code java>
 +pipeline {
 +
 +    agent {
 +        label 'ConfigServerExt'
 +    }
 +
 +    options {
 +        quietPeriod 5
 +        ansiColor('xterm')
 +        timestamps()
 +        buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', numToKeepStr: '10')
 +    }
 +
 +    environment {
 +        EXTRAS = getExtras()
 +    }
 +
 +    stages {
 +        stage('Prepare') {
 +            steps {
 +                script {
 +                    SetParameters()
 +                    cleanWs()
 +                    script {
 +                        currentBuild.displayName = "${params.VERSION}"
 +                        buildDescription "${params.APP_INSTANCE}"
 +                    }
 +                    sh(
 +                    label: 'repo sync',
 +                    script: '''
 +                        PATH="${HOME}/.bin:${PATH}"
 +                        repo init -u ssh://jenkins@gerrit.ru/igs-meta --depth=1
 +                        repo sync
 +                        if [ ${BRANCH} != "master" ] ; then
 +                            repo forall -c git checkout ${BRANCH}
 +                        fi
 +                        if [ ${GERRIT_REFSPEC} != "master" ] ; then
 +                            cd igs/modules/repo && git fetch ssh://gerrit.ru/proj ${GERRIT_REFSPEC} && git checkout FETCH_HEAD
 +                        fi
 +                    '''
 +                    )
 +                }
 +            }
 +        }
 +        stage('Build') {
 +            when {
 +                expression {
 +                    !params.SKIP_BUILD
 +                }
 +            }
 +            environment {
 +                NEXUS_CREDS = credentials('11111-1111-1111')
 +            }
 +            steps {
 +                sh label: 'gradle publish', script: '''
 +                    cd $WORKSPACE/igas
 +                    ./gradlew \
 +                        "-PnexusUrl=https://nexus.ru/repository" \
 +                        "-PnexusUser=${NEXUS_CREDS_USR}" \
 +                        "-PnexusPassword=${NEXUS_CREDS_PSW}" \
 +                        :my_app:publish
 +                '''
 +            }
 +        }
 +        stage('Deploy') {
 +            steps {
 +                dir("${WORKSPACE}/proj/pathToPlaybook") {
 +                    ansiblePlaybook(
 +                        playbook: "playbooks-deploy/my_role.yml",
 +                        extras: "${env.EXTRAS}",
 +                        colorized: true,
 +                    )
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +def getExtras() {
 +    if ("all".equals(params.APP_INSTANCE)) {
 +        return "-e version=${params.VERSION}"
 +    } else {
 +        return "-e version=${params.VERSION} -e instances=${params.APP_INSTANCE}"
 +    }
 +}
 +
 +def SetParameters() {
 +    properties([
 +        parameters([
 +            booleanParam(
 +                name: 'SKIP_BUILD',
 +                description: 'Поставьте галочку и выберите версию если нужен только деплой существующей версии',
 +                defaultValue: false
 +            ),
 +            [
 +                $class: 'ChoiceParameter',
 +                choiceType: 'PT_SINGLE_SELECT',
 +                description: 'Ветка для сборки приложения',
 +                name: 'BRANCH',
 +                randomName: 'choice-parameter-73664823423423',
 +                filterable: false,
 +                script: [
 +                    $class: 'GroovyScript',
 +                    fallbackScript: [
 +                        classpath: [],
 +                        sandbox: false,
 +                        script:
 +                        '''
 +                            return['Could not get branches list from gerrit']
 +                        '''.trim()
 +                    ],
 +                    script: [
 +                        classpath: [],
 +                        sandbox: false,
 +                        script:
 +                        '''
 +                            def cmd = ['/bin/bash',  '-c',  'git ls-remote --quiet --heads ssh://login@gerrit.ru/proj | grep -oP refs.* | sed "s|refs/heads|origin|g; s|master|master:selected|"']
 +                            def result = cmd.execute().text.tokenize()
 +                            return result
 +                        '''.trim()
 +                    ]
 +                ]
 +            ],
 +            [
 +                $class: 'ChoiceParameter',
 +                choiceType: 'PT_SINGLE_SELECT',
 +                name: 'VERSION',
 +                description: 'Укажите, если нужен деплой уже существующей версии',
 +                randomName: 'choice-parameter-5631314456178618',
 +                script: [
 +                    $class: 'GroovyScript',
 +                    script: [
 +                        classpath: [],
 +                        sandbox: false,
 +                        script: '''\
 +                            import com.cloudbees.plugins.credentials.CredentialsMatchers
 +                            import com.cloudbees.plugins.credentials.CredentialsProvider
 +                            import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials
 +                            import com.cloudbees.plugins.credentials.domains.DomainRequirement
 +                            import jenkins.model.Jenkins
 +                            import hudson.security.ACL
 +                            jenkins = Jenkins.get()
 +                            def lookupSystemCredentials = {
 +                                credentialsId -> return CredentialsMatchers.firstOrNull(
 +                                    CredentialsProvider.lookupCredentials(
 +                                        StandardUsernameCredentials.class,
 +                                        jenkins,
 +                                        ACL.SYSTEM,
 +                                        Collections.<DomainRequirement>emptyList()
 +                                    ),
 +                                    CredentialsMatchers.withId(credentialsId)
 +                                )
 +                            }
 +                            credential = lookupSystemCredentials("111111-1111-111")
 +                            nexusLogin = credential.getUsername()
 +                            nexusPasswd = credential.getPassword().getPlainText()
 +                            def targetUrl="https://$nexusLogin:$nexusPasswd@nexus.url.ru/repository/myapp-snapshots/com/gmware/applications/myapp/maven-metadata.xml"
 +                            def sout = new StringBuilder(), serr = new StringBuilder()
 +                            def proc = "curl -X GET $targetUrl".execute()
 +                            proc.consumeProcessOutput(sout, serr)
 +                            proc.waitForOrKill(1000)
 +                            def response=sout.toString()
 +                            def metadata = new XmlParser().parseText(response)
 +                            def versions = ['latest:selected']
 +                            versions.addAll(metadata.versioning.versions.version.collect({it.text()}).reverse())
 +                            return versions
 +                        '''.stripIndent()
 +                    ]
 +                ]
 +            ],
 +            [
 +                $class      : 'ChoiceParameter',
 +                choiceType  : 'PT_MULTI_SELECT',
 +                filterLength: 1,
 +                filterable  : false,
 +                name        : 'FM_INSTANCE',
 +                randomName  : 'choice-parameter-5631314339613980',
 +                script      : [
 +                    $class: 'GroovyScript',
 +                    script: [
 +                        classpath: [],
 +                        sandbox  : false,
 +                        script   : '''\
 +                            def fm_instances = []
 +                            def file1 = new File("/pathToFile/file.txt")
 +                            file1.eachLine {
 +                                fm_instances.add(it)
 +                            }
 +                            def result = ["all:selected"]
 +                            result.addAll(fm_instances)
 +                            return result'''.stripIndent()
 +                    ]
 +                ]
 +            ],
 +            string(
 +                defaultValue: 'master',
 +                description: 'Укажите патчсет, например, refs/changes/12/34567/1, откуда забирать плейбуки ansible',
 +                name: 'GERRIT_REFSPEC',
 +                trim: true
 +            )
 +        ])
 +    ])
 +}
 +</code>
 +</details>
 +
 +
 +
 +<details>
 +<summary>:!: Минимальный образец пайплайна</summary>
 +<code groovy>
 +pipeline {
 +    environment {
 +        MY_VAR = "123"
 +    }
 +
 +    agent {
 +        node {
 +            label 'my-super-agent'
 +        }
 +    }
 +
 +    parameters {
 +        string description: 'my param', name: 'MY_PARAM', defaultValue: ''
 +    }
 +
 +    stages {
 +        stage("First") {
 +            when {
 +                expression {
 +                    MY_VAR == "123"
 +                }
 +            }
 +            steps {
 +                cleanWs()
 +                script {
 +                    sh "echo 'this is first stage'"
 +                }
 +            }
 +        }
 +    
 +        stage("Second") {
 +            when {
 +                expression {
 +                    MY_VAR == "123"
 +                }
 +            }
 +            steps {
 +                script {
 +                    sh "echo 'this is second stage'"
 +                }
 +            }
 +        }
 +
 +    }
 +}
 +
 +</code>
 +</details>
 +
 +
 +
 +<details>
 +<summary>:!: When</summary>
 +<code groovy>
 +stage('first-stage') {
 +    when {
 +        branch 'master'
 + branch 'feature/*'
 +
 +    }
 +-----
 +    when {
 +        expression {
 +            return env.BRANCH_NAME != 'master';
 +     inputOptimizer == "OpenCV DNN" 
 +        }
 +    }
 +-----
 +    when { 
 +        environment name: 'NAME', value: 'this' 
 +    }
 +-----
 +
 +    steps {
 +        echo 'run this stage - ony if the branch = master branch'
 +    // Так же внутри степа
 +        script {
 +            if (env.BRANCH_NAME == "myBranch") {
 +                echo 'triggered by myBranch'
 +            } else {
 +                echo 'triggered by something else'
 +            }
 +        }
 +
 +    }
 +}
 +</code>
 +
 +Вариативность: "not", "allOf" и "anyOf"\\
 +<code groovy>
 +when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }
 +---
 +when { anyOf { branch 'master'; branch 'staging' } }
 +---
 +when { not { branch 'master' } }
 +----
 +
 +// Комбинировать тоже можно 
 +     when {
 +                branch 'production'
 +                anyOf {
 +                    environment name: 'DEPLOY_TO', value: 'production'
 +                    environment name: 'DEPLOY_TO', value: 'staging'
 +                }
 +            }
 +---
 +
 +    when {
 +                expression { BRANCH_NAME ==~ /(production|staging)/ }
 +                anyOf {
 +                    environment name: 'DEPLOY_TO', value: 'production'
 +                    environment name: 'DEPLOY_TO', value: 'staging'
 +                }
 +            }
 +---
 +
 +
 +</code>
 +
 +
 +Еще можно задать параметры сравнения (comparator): "EQUALS", "REGEXP"\\
 +<code groovy>
 +// Сравнивать по регулярке
 +when { branch pattern: "release-\\d+", comparator: "REGEXP"}
 +
 +// Простое сравнение
 +when { branch: "release", comparator: "EQUALS"}
 +</code>
 +
 +
 +
 +:!: Строки могут плохо преобразовываться в логические значения, например "0" или "False" все равно оценится как True тк не пустая строка\\
 +
 +
 +Вариативность выполнения в зависимости от переменных и параметров\\
 +В т.ч подходит для инициализации джобы запуском без параметров\\
 +<code groovy>
 +pipeline {
 +    environment {
 +        MY_VAR = "123"
 +    }
 +
 +    agent any
 +
 +    parameters {
 +        string description: 'my param', name: 'MY_PARAM', defaultValue: ''
 +        string description: 'my param', name: 'MY_PARAM2', defaultValue: ''
 +        string description: 'my param', name: 'MY_PARAM3', defaultValue: ''
 +    }
 +
 +    stages {
 +        stage("First") {
 +            when {
 +                expression { params.MY_VAR }
 +                expression { params.MY_VAR2 != "" }
 +                expression { !params.MY_VAR2 }
 +                expression { params.MY_PARAM == "1" }
 +            }
 +            steps {
 +                cleanWs()
 +                script {
 +                    sh "echo 'this is first stage'"
 +                }
 +            }
 +        }
 +    }
 +}
 +</code>
 +</details>
 +
 +
 +
 +<details>
 +<summary>:!: Использование config файла</summary>
 +<code groovy>
 +// Создание файла
 +configFileProvider([configFile(fileId: 'kubeconf', targetLocation: 'kubeconf.сщта')]) {
 +  script {
 +  }
 +}
 +
 +// Данные в переменной
 +configFileProvider([configFile(fileId: 'kubeconf', variable: 'kubeconf')]) {
 +  script {
 +  }
 +}
 +
 +</code>
 +</details>
 +
 +
 +
 +<details>
 +<summary>:!: Запись в файл. Декларативный метод</summary>
 +<code groovy>
 +writeFile file: "${MY_FILENAME}.txt", text: """
 +  text: ${var1}
 +  test: ${var2}
 +""".stripIndent()
 +</code>
 +</details>
 +
 +
 +
 +==== Запись результатов/Артефакты джобы ====
 +
 +<details>
 +<summary>:!: Примеры</summary>
 +
 +Запись резов текстом, сразу на странице джобы\\
 +Можно применять html\\
 +<code bash>
 +currentBuild.description = "Сборка BIN-артефакта - ${my-variable.getAbsoluteUrl()}"
 +</code>
 +
 +Артефакты файлами\\
 +<code bash>
 +archiveArtifacts artifacts: 'result.html'
 +</code>
 +
 +
 +Публикация полноценного отчета, доступен слева в меню\\
 +<code bash>
 +publishHTML (target : [allowMissing: false, alwaysLinkToLastBuild: true,
 +keepAll: true, reportDir: '', reportFiles: 'result.html',
 +reportName: 'My Reports', reportTitles: 'The Report'])
 +</code>
 +</details>
 +
 +
 +
 +
 +
 +
 +
 +
 +====== Use Gradle ======
 <details> <details>
 <summary>:!: Общее </summary> <summary>:!: Общее </summary>
Строка 464: Строка 1076:
 </code> </code>
 </details> </details>
 +
  
  
Строка 484: Строка 1097:
 </code> </code>
 </details> </details>
 +
 +
 +
 +
 +
 +Прерывание
 +
 +
 +
 +if (!params.MY_VAR.contains("@")) {
 +    currentBuild.result = 'ABORTED'
 +    error("Параметр 'MY_VAR' указан неверно")
 +}
 +
 +
  
  
  
jenkins/pipelines.1715767092.txt.gz · Последнее изменение: 2024/05/15 09:58 — admin