JenkinsActiveChoice
Материал из noname.com.ua
Jenkins Active Choice
Есть плагин который позволяет динамически формировать значения параметров, например динамически подтягивать список веток в git (НО нельзя динамически создать параметры, и у меня не вышло сделать скрытыми параметры в зависимости от того что выбрано в другом параметре)
Пример кода
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)