| Ruslan Gustomiasov | 5d131b6 | 2019-08-21 11:51:26 +0200 | [diff] [blame] | 1 | package com.mirantis.mk | 
|  | 2 |  | 
|  | 3 | /** | 
|  | 4 | * | 
|  | 5 | *  Functions to work with Helm | 
|  | 6 | * | 
|  | 7 | */ | 
|  | 8 |  | 
|  | 9 | /** | 
|  | 10 | * Build index file for helm chart | 
| Sergey Otpuschennikov | 50b248c | 2019-08-28 17:21:18 +0400 | [diff] [blame] | 11 | * @param extra_params   additional params, e.g. --url repository_URL | 
|  | 12 | * @param charts_dir     path to a directory | 
| Ruslan Gustomiasov | 5d131b6 | 2019-08-21 11:51:26 +0200 | [diff] [blame] | 13 | */ | 
|  | 14 |  | 
| Sergey Otpuschennikov | 50b248c | 2019-08-28 17:21:18 +0400 | [diff] [blame] | 15 | def helmRepoIndex(extra_params='', charts_dir='.'){ | 
|  | 16 | sh("helm repo index ${extra_params} ${charts_dir}") | 
|  | 17 | } | 
| Mykyta Karpin | 3c78c0f | 2019-09-11 18:11:06 +0300 | [diff] [blame] | 18 |  | 
|  | 19 | /** | 
| Sergey Otpuschennikov | 958f287 | 2019-10-16 17:04:33 +0400 | [diff] [blame] | 20 | * Rebuild index file for helm chart repo | 
| Sergey Otpuschennikov | cd9b526 | 2021-02-02 20:02:06 +0400 | [diff] [blame] | 21 | * @param absHelmRepoUrl if set to true, URLs to charts will be absolute | 
|  | 22 | * @param helmRepoUrl    repository with helm charts | 
|  | 23 | * @param md5Remote      md5 sum of index.yaml for check | 
| Sergey Otpuschennikov | 958f287 | 2019-10-16 17:04:33 +0400 | [diff] [blame] | 24 | */ | 
|  | 25 |  | 
| Sergey Otpuschennikov | cd9b526 | 2021-02-02 20:02:06 +0400 | [diff] [blame] | 26 | def helmMergeRepoIndex(helmRepoUrl, md5Remote='', absHelmRepoUrl=true) { | 
| Sergey Otpuschennikov | 958f287 | 2019-10-16 17:04:33 +0400 | [diff] [blame] | 27 | def common      = new com.mirantis.mk.Common() | 
|  | 28 |  | 
|  | 29 | def helmRepoDir    = '.' | 
| Sergey Otpuschennikov | cd9b526 | 2021-02-02 20:02:06 +0400 | [diff] [blame] | 30 | def helmExtraParams = '' | 
|  | 31 | if (absHelmRepoUrl) { | 
|  | 32 | helmExtraParams = "--url ${helmRepoUrl}" | 
|  | 33 | } | 
| Sergey Otpuschennikov | 958f287 | 2019-10-16 17:04:33 +0400 | [diff] [blame] | 34 |  | 
|  | 35 | def indexRes = common.shCmdStatus("wget -O index-upstream.yaml ${helmRepoUrl}/index.yaml") | 
| Sergey Otpuschennikov | cd9b526 | 2021-02-02 20:02:06 +0400 | [diff] [blame] | 36 |  | 
| Sergey Otpuschennikov | 958f287 | 2019-10-16 17:04:33 +0400 | [diff] [blame] | 37 | if (indexRes['status']){ | 
|  | 38 | if (indexRes['status'] == 8 && indexRes['stderr'].contains('ERROR 404') && !md5Remote) { | 
|  | 39 | common.warningMsg("Index.yaml not found in ${helmRepoUrl} and will be fully regenerated") | 
|  | 40 | } else { | 
|  | 41 | error("Something went wrong during index.yaml download: ${indexRes['stderr']}") | 
|  | 42 | } | 
|  | 43 | } else { | 
|  | 44 | if (md5Remote) { | 
|  | 45 | def md5Local = sh(script: "md5sum index-upstream.yaml | cut -d ' ' -f 1", returnStdout: true).readLines()[0] | 
|  | 46 | if (md5Local != md5Remote) { | 
|  | 47 | error 'Target repository already exist, but upstream index.yaml broken or not found' | 
|  | 48 | } | 
|  | 49 | } | 
|  | 50 | helmExtraParams += " --merge index-upstream.yaml" | 
|  | 51 | } | 
| Sergey Otpuschennikov | 892b4e7 | 2019-10-29 14:54:08 +0400 | [diff] [blame] | 52 | helmRepoIndex(helmExtraParams, helmRepoDir) | 
| Sergey Otpuschennikov | 958f287 | 2019-10-16 17:04:33 +0400 | [diff] [blame] | 53 | } | 
|  | 54 |  | 
|  | 55 | /** | 
| Mykyta Karpin | 3c78c0f | 2019-09-11 18:11:06 +0300 | [diff] [blame] | 56 | * Generates version for helm chart based on information from git repository. Tries to search | 
|  | 57 | * first parent git tag using pattern '[0-9]*-{tagSuffix}', if found that tag will be used | 
|  | 58 | * in final version, if not found - version will be formed as '{defaultVersion}-{tagSuffix}'. Number | 
| Ildar Svetlov | 4fb016d | 2021-11-15 23:36:07 +0400 | [diff] [blame] | 59 | * of commits since last tag or/and sha of current commit can be added to version. | 
| Mykyta Karpin | 3c78c0f | 2019-09-11 18:11:06 +0300 | [diff] [blame] | 60 | * | 
| Ildar Svetlov | 4fb016d | 2021-11-15 23:36:07 +0400 | [diff] [blame] | 61 | * @param repoDir         string, path to a directory with git repository of helm charts | 
|  | 62 | * @param devVersion      Boolean, if set to true development version will be calculated e.g 0.1.0-mcp-{sha of current commit} | 
|  | 63 | * @param increment       Boolean, if set to true patch version will be incremented (e.g 0.1.0 -> 0.1.1) | 
|  | 64 | * @param defaultVersion  string, value of version which will be used in case no tags found. should be semver2 compatible | 
|  | 65 | * @param tagSuffix       string, suffix which will be used for finding tags in git repository, also if tag not found, it | 
|  | 66 | *                                will be added to {defaultVersion} e.g {defaultVersion}-{tagSuffix} | 
|  | 67 | * @param extendedVersion Boolean, if set to true non development version (devVersion = false) will be suffixed by {sha of current commit} e.g. | 
|  | 68 | *                                 0.1.0-mcp-{number of commits since last tag}-{sha of current commit}; doesn't affect development version (devVersion = true) | 
| Mykyta Karpin | 3c78c0f | 2019-09-11 18:11:06 +0300 | [diff] [blame] | 69 | */ | 
|  | 70 |  | 
| Ildar Svetlov | 4fb016d | 2021-11-15 23:36:07 +0400 | [diff] [blame] | 71 | def generateChartVersionFromGit(repoDir, devVersion = true, increment = false, defaultVersion = '0.1.0', tagSuffix = 'mcp', extendedVersion = false) { | 
| Mykyta Karpin | 3c78c0f | 2019-09-11 18:11:06 +0300 | [diff] [blame] | 72 | def common = new com.mirantis.mk.Common() | 
|  | 73 | def git = new com.mirantis.mk.Git() | 
| Mykyta Karpin | e755484 | 2019-12-11 17:00:29 +0200 | [diff] [blame] | 74 | String initialVersion = "${defaultVersion}" | 
| Mykyta Karpin | 3c78c0f | 2019-09-11 18:11:06 +0300 | [diff] [blame] | 75 | String countRange | 
|  | 76 | String versionData | 
| Mykyta Karpin | e755484 | 2019-12-11 17:00:29 +0200 | [diff] [blame] | 77 | String tagPattern = "[0-9]*" | 
|  | 78 | if (tagSuffix) { | 
|  | 79 | tagPattern = "${tagPattern}-${tagSuffix}" | 
|  | 80 | initialVersion = "${initialVersion}-${tagSuffix}" | 
|  | 81 | } | 
| Mykyta Karpin | 3c78c0f | 2019-09-11 18:11:06 +0300 | [diff] [blame] | 82 | dir(repoDir){ | 
|  | 83 | Map cmd = common.shCmdStatus("git describe --tags --first-parent --abbrev=0 --match ${tagPattern}") | 
|  | 84 | String lastTag = cmd['stdout'].trim() | 
|  | 85 |  | 
|  | 86 | if (cmd['status'] != 0){ | 
|  | 87 | if (cmd['stderr'].contains('fatal: No names found, cannot describe anything')){ | 
|  | 88 | common.warningMsg("No parent git tag found, using initial version ${initialVersion}") | 
|  | 89 | versionData = initialVersion | 
|  | 90 | countRange = 'HEAD' | 
|  | 91 | } else { | 
|  | 92 | error("Something went wrong, cannot find git information ${cmd['stderr']}") | 
|  | 93 | } | 
|  | 94 | } else { | 
|  | 95 | versionData = lastTag | 
|  | 96 | countRange = "${lastTag}..HEAD" | 
|  | 97 | } | 
|  | 98 | List versionParts = versionData.tokenize('-') | 
|  | 99 |  | 
| Mykyta Karpin | e755484 | 2019-12-11 17:00:29 +0200 | [diff] [blame] | 100 | if (!common.isSemVer(versionData)){ | 
|  | 101 | error "Version ${versionData} is not in semver2 format" | 
| Mykyta Karpin | 3c78c0f | 2019-09-11 18:11:06 +0300 | [diff] [blame] | 102 | } | 
| Mykyta Karpin | e755484 | 2019-12-11 17:00:29 +0200 | [diff] [blame] | 103 | if (tagSuffix && versionParts.size() == 2 && versionParts[1] != tagSuffix){ | 
|  | 104 | error "Tag suffix ${tagSuffix} was specified but not found in ${versionData}" | 
|  | 105 | } | 
|  | 106 | String commitsSinceTag = sh(script: "git rev-list --count ${countRange}", returnStdout: true).trim() | 
|  | 107 | String commitSha = sh(script: 'git rev-parse --short=7 HEAD', returnStdout: true).trim() | 
|  | 108 |  | 
|  | 109 | if (commitsSinceTag == '0'){ | 
|  | 110 | return versionData | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | if (devVersion){ | 
|  | 114 | versionParts.add(commitSha) | 
|  | 115 | } else { | 
|  | 116 | versionParts.add(commitsSinceTag) | 
| Ildar Svetlov | 4fb016d | 2021-11-15 23:36:07 +0400 | [diff] [blame] | 117 | if (extendedVersion){ | 
|  | 118 | versionParts.add(commitSha) | 
|  | 119 | } | 
| Mykyta Karpin | e755484 | 2019-12-11 17:00:29 +0200 | [diff] [blame] | 120 | } | 
|  | 121 | // Patch version will be incremented e.g. 0.1.0 -> 0.1.1 | 
|  | 122 | if (increment) { | 
|  | 123 | versionParts[0] = git.incrementVersion(versionParts[0]) | 
|  | 124 | } | 
|  | 125 | return versionParts.join('-') | 
| Mykyta Karpin | 3c78c0f | 2019-09-11 18:11:06 +0300 | [diff] [blame] | 126 | } | 
| Mykyta Karpin | 6f050b2 | 2019-09-24 13:57:20 +0300 | [diff] [blame] | 127 | } | 
|  | 128 |  | 
|  | 129 | /** | 
|  | 130 | * Takes a list of dependencies and a version, and sets a version for each dependency in requirements.yaml. If dependency isn't | 
|  | 131 | * found in requirements.yaml or requirements.yaml does not exist - does nothing. | 
|  | 132 | * | 
|  | 133 | * @param chartPath      string, path to a directory with helm chart | 
|  | 134 | * @param dependencies   list of hashes with names and versions of dependencies in format: | 
|  | 135 | *                       [['name': 'chart-name1', 'version': '0.1.0-myversion'], ['name': 'chart-name2', 'version': '0.2.0-myversion']] | 
|  | 136 | */ | 
|  | 137 |  | 
|  | 138 | def setChartDependenciesVersion(chartPath, List dependencies){ | 
|  | 139 | def common = new com.mirantis.mk.Common() | 
|  | 140 | if (!dependencies){ | 
|  | 141 | error 'No list of target dependencies is specified' | 
|  | 142 | } | 
|  | 143 | def reqsFilePath = "${chartPath}/requirements.yaml" | 
|  | 144 | def chartYaml = readYaml file: "${chartPath}/Chart.yaml" | 
|  | 145 | def reqsUpdateNeeded = false | 
|  | 146 | def reqsMap = [:] | 
|  | 147 | if (fileExists(reqsFilePath)){ | 
|  | 148 | reqsMap = readYaml file: reqsFilePath | 
|  | 149 | for (i in dependencies) { | 
|  | 150 | for (item in reqsMap.get('dependencies', [])){ | 
|  | 151 | if (item['name'] == i['name']){ | 
| Mykyta Karpin | 882dd36 | 2019-09-25 11:27:55 +0300 | [diff] [blame] | 152 | common.infoMsg("Set version ${i['version']} for dependency ${i['name']} in chart ${chartYaml['name']}") | 
| Mykyta Karpin | 6f050b2 | 2019-09-24 13:57:20 +0300 | [diff] [blame] | 153 | item['version'] = i['version'] | 
|  | 154 | reqsUpdateNeeded = true | 
|  | 155 | } | 
|  | 156 | } | 
|  | 157 | } | 
|  | 158 | } | 
| Oleksandr Kononenko | c5b3f97 | 2021-10-21 14:31:44 +0300 | [diff] [blame] | 159 | else { | 
|  | 160 | common.warningMsg("requirements.yaml doesn't exist at path ${reqsFilePath} or chart doesn't contain ${dependencies}, nothing to set") | 
|  | 161 | } | 
| Mykyta Karpin | 6f050b2 | 2019-09-24 13:57:20 +0300 | [diff] [blame] | 162 | if (reqsUpdateNeeded){ | 
|  | 163 | sh "rm ${reqsFilePath}" | 
|  | 164 | writeYaml file: reqsFilePath, data: reqsMap | 
| Mykyta Karpin | 6f050b2 | 2019-09-24 13:57:20 +0300 | [diff] [blame] | 165 | } | 
| Sergey Otpuschennikov | 958f287 | 2019-10-16 17:04:33 +0400 | [diff] [blame] | 166 | } | 
| Oleksandr Kononenko | c5b3f97 | 2021-10-21 14:31:44 +0300 | [diff] [blame] | 167 |  | 
|  | 168 | /** | 
|  | 169 | * Takes a list of dependencies and a version, and sets a version for each dependency in requirements.yaml. If dependency isn't | 
|  | 170 | * found in requirements.yaml or requirements.yaml does not exist - does nothing. | 
|  | 171 | * | 
|  | 172 | * @param chartPath      string, path to a directory with helm chart | 
|  | 173 | * @param version        string, new version chart that needed to set | 
|  | 174 | */ | 
|  | 175 |  | 
|  | 176 | def setChartVersion(chartPath, version){ | 
|  | 177 | def chartFile = "${chartPath}/Chart.yaml" | 
|  | 178 | def chartYaml = readYaml file: chartFile | 
|  | 179 | chartYaml['version'] = version | 
|  | 180 | sh "rm ${chartFile}" | 
|  | 181 | writeYaml file: chartFile, data: chartYaml | 
|  | 182 | } |