if (params.getOrDefault('BOOLEAN_PARAM_NAME', true)) if (params.CREDENTIAL_ID.toString().isEmpty()) { currentBuild.result = 'ABORTED' error("CREDENTIAL_ID is empty") }
pipeline { agent any stages { stage("Variables") { steps { my_var = sh label: 'my echo', returnStdout: true, script: 'echo edede' } } stage("Variables") { steps { script{ // хотя хз, чет не сработало script: ''' echo "$my_var" ''' } } } } }
Дока
Глобальная переменная, доступная через env. Объявляется в любом месте, либо в блоке environment либо в script
Хранится только в формате строки, в т.ч. и булевы значения
Обратится можно и без «env» но если нет обычной переменной с таким же именем иначе будет путаница
pipeline { agent any stages { stage("Env Variables") { steps { sh "printenv" // можно sh "printenv | sort" } } } }
Переменные среды могут быть установлены декларативно с помощью environment { }блока, императивно с помощью env.VARIABLE_NAMEили с помощью withEnv([«VARIABLE_NAME=value»]) {}блока.
pipeline { agent any environment { FOO = "bar" } stages { stage("Env Variables") { environment { NAME = "Alan" } steps { echo "FOO = ${env.FOO}" echo "NAME = ${env.NAME}" script { env.TEST_VARIABLE = "some test value" } echo "TEST_VARIABLE = ${env.TEST_VARIABLE}" withEnv(["ANOTHER_ENV_VAR=here is some value"]) { echo "ANOTHER_ENV_VAR = ${env.ANOTHER_ENV_VAR}" } } } } }
pipeline { agent any environment { FOO = "bar" NAME = "Joe" } stages { stage("Env Variables") { environment { NAME = "Alan" // overrides pipeline level NAME env variable BUILD_NUMBER = "2" // overrides the default BUILD_NUMBER } steps { echo "FOO = ${env.FOO}" // prints "FOO = bar" echo "NAME = ${env.NAME}" // prints "NAME = Alan" echo "BUILD_NUMBER = ${env.BUILD_NUMBER}" // prints "BUILD_NUMBER = 2" script { env.SOMETHING = "1" // creates env.SOMETHING variable } } } stage("Override Variables") { steps { script { env.FOO = "IT DOES NOT WORK!" // it can't override env.FOO declared at the pipeline (or stage) level env.SOMETHING = "2" // it can override env variable created imperatively } echo "FOO = ${env.FOO}" // prints "FOO = bar" echo "SOMETHING = ${env.SOMETHING}" // prints "SOMETHING = 2" withEnv(["FOO=foobar"]) { // it can override any env variable echo "FOO = ${env.FOO}" // prints "FOO = foobar" } withEnv(["BUILD_NUMBER=1"]) { echo "BUILD_NUMBER = ${env.BUILD_NUMBER}" // prints "BUILD_NUMBER = 1" } } } } }
Обращаться к переменным следует всегда с префиксами если они есть, например для переменных окружения это «env», для входных параметров это «params». т.к. переменная легко может подменится локальной с таким же именем, не имеющей отношения к переменной окружения или параметру
Модуль sh по всей видимости выполняется напрямую в оболочке, поэтому ему доступны только переменные окружения среды
Задать переменные окружения из скрипта можно в блоке Environment
// Входящий параметр (видимо по умолчанию доступны в переменных окружения) stage('Clone source') { steps { echo params.MY_BRANCH sh label: 'repo sync', script: ''' repo init -u ssh://myrepository.ru repo sync if [ $MY_BRANCH != "master" ] ; then repo forall -c git checkout $MY_BRANCH fi ''' } } // Объявление в скрипте stage('Increment & push MGA_TAG') { environment{ myLocalVar = getValueFromFunction() } steps { script{ if (env.myLocalVar == null || env.myLocalVar.equals("")) { currentBuild.result = 'ABORTED' } } sh label: 'Push tag if it is set', script: ''' cd $WORKSPACE/igas repo forall -c git tag -a $myLocalVar -m $myLocalVar repo forall -c git push origin "$myLocalVar" ''' } } // // Или вот пример stage('Build') { environment { VERSION_STRING = new SimpleDateFormat("yyyy_MM_dd_HH_mm").format(new Date()) } steps { sh label: 'my scritp', script: ''' echo variable in other block1 - $VERSION_STRING echo variable in other block2 - "$VERSION_STRING" echo variable in other block3 - '$VERSION_STRING' <-- эта не раскрывается ''' } } // Объявление входных параметров def setParameters() { properties([ parameters([ gitParameter( name: 'MY_BRANCH', description: 'Тег или ветка, откуда делать сборку', branch: '', branchFilter: '.*', defaultValue: 'origin/master', listSize: '10', quickFilterEnabled: false, requiredParameter: true, selectedValue: 'DEFAULT', sortMode: 'ASCENDING_SMART', tagFilter: '[0-9]*', type: 'PT_BRANCH_TAG' ), string( name: 'APP_VERSION', description: '', defaultValue: '', trim: true ), booleanParam( name: 'RUNACTION', description: '', defaultValue: false ) ]) ]) }
// Так не работает, переменные не раскрываются script{ echo ''' second $MY_PARAM ''' echo ''' three ${MY_PARAM} ''' echo ''' four ${params.MY_PARAM} ''' } // Работает в тройных двойных кавычках, раскрылись все переменные script{ echo """ second $MY_PARAM """ echo """ three ${MY_PARAM} """ echo """ four ${params.MY_PARAM} """ }
import java.time.LocalDateTime // Локальная ДТ, в формате "2024-02-01T19:34:11.905900287" def start = LocalDateTime.now() // Прибавить минуты def start = LocalDateTime.now().plusMinutes(360) // Тоже текущая дата, формат такой же, но дженкинс попросил аппрув (хотя не помню с первым возможно тоже был) import java.time.Instant def current_instant = Instant.now()
import java.time.LocalDateTime import java.time.ZoneId // ZoneId, тут есть явное определение временных зон, пример из джавы ZoneId zone = ZoneId.of("Asia/Almaty") ZonedDateTime time = ZonedDateTime.now(zone) // В груви так работает (тут есть перечень зон https://csharpcoderr.com/5267/ ) def zoned_dt = LocalDateTime.now(ZoneId.of("Asia/Almaty")) // Offset, собсна "смещение", тут в основном фиксированный какой то сдвиг времени от полученного из системы // Так работает def current_dt = LocalDateTime.now() def offset_dt = LocalDateTime.now(ZoneOffset.ofHours(+6)) // Вот тоже пример, по сути тоже самое ZoneOffset zoneOffSet = ZoneOffset.of("+02:00"); OffsetTime time = OffsetTime.now(zoneOffSet);
Сохраняет указанные файлы для дальнейшего использования в пайплайне, вне зависимости от агентов
Сохраняет в виде TAR архива, поэтому большие файлы не рекомендуется передавать т.к будет проседать ЦП
По умолчанию чистится после каждой сборки, но есть плагины позволяющие сохранить между запусками, «preserveStashes()«
Можно добавить исключения на добавляемые файлы. Сохраняет указанные файлы в текущем рабочем каталоге, распаковывает сохраняя относительные пути
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 } }
Указывать нужно с маской, например includes: «my_dir/*», при этом сохраняет всю папку
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" } } }
Архивирует артефакты сборки, затем они доступны на веб-странице джобы
По умолчанию Maven автоматически архивирует произведенные артефакты. Указанные здесь артефакты будут архивированы поверх
Файлы указываются так же маской
archiveArtifacts artifacts: 'target/*.jar' archiveArtifacts artifacts: 'target/*.jar, target/*.war' archiveArtifacts artifacts: '**/*.jar' # Из примера выше archiveArtifacts artifacts: 'my_dir/*'
import java.time.LocalDateTime import java.time.ZoneId pipeline { agent { label 'master' } environment { GRAFANA_API_TOKEN = credentials('sdcsdcdscdsc') } stages { stage('make silence') { steps { SetParameters() script{ //def start_time_silence = LocalDateTime.now(ZoneId.of("Asia/Almaty")) //def end_time_silence = start_time_silence.plusMinutes(params.DURATION_MIN.toInteger()) def start_time_silence = LocalDateTime.now() def end_time_silence = start_time_silence.plusMinutes(params.DURATION_MIN.toInteger()) def response = httpRequest acceptType: 'APPLICATION_JSON', contentType: 'APPLICATION_JSON', responseHandle: 'NONE', httpMode: 'POST', ignoreSslErrors: true, url: 'https://url-grafana/api/alertmanager/grafana/api/v2/silences', wrapAsMultipart: false, authentication: 'dcdcdcdcdc', requestBody: """{ "comment": "comment_string", "createdBy": "user_my", "startsAt": "${start_time_silence}", "endsAt": "${end_time_silence}", "matchers": [ { "isEqual": true, "isRegex": false, "name": "alertname", "value": "${ALERT_NAME}" } ] }""" } } } } } def SetParameters() { properties([ parameters([ string( name: 'ALERT_NAME', description: 'Название alert-правила в grafana', trim: true ), string( name: 'DURATION_MIN', defaultValue: '60', description: 'Продолжительность режима тишины в минутах', trim: true ) ]) ]) }
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 ''' ) } } }
- 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: "!!! Откат изменений после сбоя. Прерываем дальнейшее выполнение !!!"
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 ) ]) ]) }
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'" } } } } }
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' } } } }
Вариативность: «not», «allOf» и «anyOf»
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' } } ---
Еще можно задать параметры сравнения (comparator): «EQUALS», «REGEXP»
// Сравнивать по регулярке when { branch pattern: "release-\\d+", comparator: "REGEXP"} // Простое сравнение when { branch: "release", comparator: "EQUALS"}
Строки могут плохо преобразовываться в логические значения, например «0» или «False» все равно оценится как True тк не пустая строка
Вариативность выполнения в зависимости от переменных и параметров
В т.ч подходит для инициализации джобы запуском без параметров
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'" } } } } }
// Создание файла configFileProvider([configFile(fileId: 'kubeconf', targetLocation: 'kubeconf.сщта')]) { script { } } // Данные в переменной configFileProvider([configFile(fileId: 'kubeconf', variable: 'kubeconf')]) { script { } }
writeFile file: "${MY_FILENAME}.txt", text: """ text: ${var1} test: ${var2} """.stripIndent()
Скрипты справа все таки совпадают с тасками что есть в файле «build.gradle.kts» внутри проекта
вот только как он обновляется ? таску вроде прописал, а справа не появляется этого
// Проверка переданной переменной, через аргументы вызова, "-Pversion" if(!project.hasProperty("version")) throw Exception("no value stop it") // Обращаться к свойству project.properties["buildVersion"] // Вообще таска для ShadowJar tasks { "shadowJar"(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) { mergeServiceFiles() isZip64 = true val serverAppName = "server_app-$serverAppVersion.jar" archiveFileName.set(serverAppName) doFirst { //assert(buildVersion != "non-value") { "Can not get version by git." } if(!project.hasProperty("version")) throw Exception("no value stop it") } } }
# Если скритп "gradlew" в папке с проектом stage('Build jar') { steps { sh "bash ./gradlew shadowJar" } } # Если нет, тогда stage('Build jar') { steps { sh "bash ./gradlew myProject:modules:shadowJar" (хотя не точно уже) } }
Прерывание
if (!params.MY_VAR.contains(»@»)) {
currentBuild.result = 'ABORTED' error("Параметр 'MY_VAR' указан неверно")
}