import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import jenkins.model.Jenkins
// ВНИМАНИЕ - println пишет В ЛОГ и читать сообщение надо в логе дженкинса
// НА современных линуксах например:
// journalctl -u jenkins --since -1m -f
// Список приложений и их доступов
List reposAndKeys = [
[
"name": "app1",
"repo": "git@github.com:app1.git",
"repoKeyId": "app1-git-deployment-key",
],
[
"name": "app2",
"repo": "git@github.com:app2.git",
"repoKeyId": "appN-git-deployment-key",
],
...
[
"name": "appN",
"repo": "git@github.com:appN.git",
"repoKeyId": "appN-git-deployment-key",
]
]
// Получение списка всех бранчей
def getAllBranches( String url, String credentialID, Boolean activeChoice = false,
String defaultBranch = 'master', Boolean includeTags = false, String logTag = "") {
def jenkinsCredentials = CredentialsProvider.lookupCredentials(
com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey,
Jenkins.instance
);
def key = jenkinsCredentials.findResult { it.id == credentialID ? it.privateKey : null }
if (!key) {
return "[${logTag}]Error: credentials not found"
} else {
print("[${logTag}] Key Found: \n ${key} \n")
}
// иногда с первого раза не удается получить все бранчи
Integer attemptsLeft = 5
def out = new StringBuilder()
def err = new StringBuilder()
while(attemptsLeft > 0) {
try {
print("[${logTag}] Starting process\n")
Process process = ['ssh-agent', 'bash', '-c', "echo '" + key + "' | ssh-add - 2> /dev/null && git ls-remote -t -h " + url].execute()
process.consumeProcessOutput(out, err)
print("[${logTag}] Waiting for started process\n")
process.waitFor()
print("[${logTag}] Process is finished\n")
print("[${logTag}] Out: \n${out}\n\n")
if (out == null) {
attemptsLeft = attemptsLeft - 1
print("[${logTag}] Output ${out} is null. attemptsLeft = ${attemptsLeft} \n")
continue
}
if (out.size() == 0) {
attemptsLeft = attemptsLeft - 1
print("[${logTag}] Output ${out} is empty. attemptsLeft = ${attemptsLeft} \n")
continue
}
print("[${logTag}] Out: ${out} looks OK\n")
break
} catch(Exception Ex) {
println("[${logTag}] " + Ex.toString())
throw new Exception(Ex)
}
} // while
if (err.size() > 0) {
return err
}
if (out.size() > 0) {
def branches = out.readLines().collect {
it.split()[1]
}.findAll {
it.startsWith('refs/heads/') || includeTags
}.collect {
it.replaceAll('refs/heads/', '').replaceAll('refs/tags/', '')
}
if (activeChoice) {
def defaultBranchIndex = branches.indexOf(defaultBranch)
if (defaultBranchIndex >= 0) {
branches.set(defaultBranchIndex, defaultBranch + ':selected')
}
}
println("Branches found: ${branches}")
return branches
}
}
List applications = []
List branches = []
// Просто список приложений - только имена
reposAndKeys.each { repoAndKey ->
applications.add(repoAndKey["name"])
}
println("applications = ${applications}")
//Флаг который нужен что бы определить когда
// чекбокс снят
Boolean isDisabled = false
List triggeredByParameterNames = []
// Параметр который триггерит вызов этого скрипта должен называться так же как одно
// из имен приложений
// Логика тут примерно такая
// - есть несколько параметров приложений, например app1, app2, app3 ... appN
// - есть массив конфигураций с конфигурацией для каждого приложение - ИМЯ, адрес, ключ ..
// - ИМЯ приложения в этом массиве ДОЛЖНО совпадать с именем переменной которая является Referenced parameters
// Другими словами имя параментра (например app1) должно совпадать с именем ("name": "app1") в массиве конйигураций
// При старте скрипта в нем создается переменная которая указана в Referenced parameters с таким же именем
// т.е. всегда будет доступна одна из переменных - app1 ИЛИ app2 ИЛИ ... ИЛИ appN но проблема
// в том что в коде заранее не известно имя этой переменной (так как код скрипта полностью одинаков и делать
// несколько копий скрипта, каждая для своего приложения, не хочется)
//
// Код ниже пытается определить какая из переменных определена, для этого он последовательно пробует прочитать значения
// всех возможных и в случае успеха - запоминает какая переменная доступна
// Есди переменная доступна но ее значение - пуста строка то это значит что чекбокс снят и нужно выдать пустой список
// Если переменная доступна и ее значение не равно пустой строке - то это значит что чекбокс выбран и нужно получить список
// бранчей
// (Пустрая строка или что-то другое - зависит от ТИПА переменной и этот код не универсален)
applications.each { it ->
try {
// если it указывает на несуществующее значенеи то тут будет исключение
println("${it} = ${this[ it ]}")
// Если чекбокс не выбран - то в значении переменной (имя переменной это имя параметра) будет пустая строка
// тут нужно добаить другие проверки если планируется использовать другиме типы параметов
if ("${this[ it ]}" == "") {
isDisabled = true
}
triggeredByParameterNames.add("${it}")
} catch(Exception Ex) {
println("${it}")
println(Ex)
}
}
print("triggeredByParameterNames = ${triggeredByParameterNames}\n")
print("triggeredByParameterNames size = ${triggeredByParameterNames.size()}\n")
if (isDisabled) {
print("Application is not selected for deploy\n")
return []
}
// В какой-то момент времени происходит выхов и НИ одна переменная не оказывается доступна - что бы не ловить исключения
// аозвращаю пустой List
if (triggeredByParameterNames.size == 0 ) {
print("No valid applivation found (Possible reason: script misconfiguration or started without required parameters)\n")
return []
}
// Проверить что вызвано только одним приложением
// Это означает что для каждого приложения должен быть свой параметр имени ветки
// и нельзя сделать так что бы пересчет этого параметра триггерился 2 или более
// параметрами (так как это в целом не имеет смысла)
if (triggeredByParameterNames.size > 1 ) {
return ["Triggered by multiple parameters is not supported, please check Referenced parameters setting, only one parameter is allowed "]
}
String logTag = triggeredByParameterNames[0].toString()
repoAndKey = reposAndKeys.findAll { it.name == triggeredByParameterNames[0] }
print("[${logTag}] Parameters are: ${repoAndKey}\n")
String credentialsId = repoAndKey[0]['repoKeyId']
String url = repoAndKey[0]['repo']
// Собственно вызов получения списка бранчей
getAllBranches(url, credentialsId, true, "master", false, logTag)