├── .gitignore ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── main.go ├── plugin.yaml ├── render ├── common-funcs.go ├── values.go └── yaml-funcs.go ├── scripts ├── install_plugin.sh └── make-assets.sh └── tests ├── base-values1.yaml ├── base-values2.yaml ├── extended-values1.yaml ├── extended-values2.yaml ├── template-patterns.yaml ├── template-values.yaml ├── test-glob-values.yaml ├── testglob ├── service1 │ └── values.yaml └── service2 │ └── values.yaml └── values_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .vscode 3 | assets 4 | .DS_Store 5 | render-values 6 | releases 7 | main -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # helm-plugin-render-values 2 | 3 | The `helm-plugin-render-values` is a Helm downloader plugin that enhances the rendering of templated values. 4 | 5 | This plugin is particularly useful when working with third-party charts that don't have the tpl() function for values, but you still want to utilize it. 6 | 7 | Feel free to explore the capabilities of this plugin and enjoy a more streamlined and efficient Helm charting experience! 8 | 9 | ## Install 10 | Use helm CLI to install this plugin: 11 | ``` 12 | $ helm plugin install https://github.com/vivid-money/helm-plugin-render-values --version 0.2.6 13 | ``` 14 | 15 | ## Usage 16 | ``` 17 | helm upgrade name . -f render://templated-values.yaml 18 | ``` 19 | templated-values.yaml should looks like this 20 | ``` 21 | ## Extra files values imorted from. They must not have templating 22 | importValuesFrom: 23 | - base-values1.yaml 24 | - base-values2.yaml 25 | - services/*/deploy.yaml 26 | - services/*/env/dev.yaml 27 | 28 | ## Extra files with templating to render. They should have templating 29 | extendRenderWith: 30 | - extended-values1.yaml 31 | 32 | myapp: 33 | cluster: {{ .Values.clusterName }} 34 | enabled: {{ .Values.enabled }} 35 | {{if .Values.default }} 36 | run: {{ .Values.default }} 37 | {{- end }} 38 | ``` 39 | ### *importValuesFrom* 40 | - The `importValuesFrom` keyword allows you to specify a list of sources for values to render them. 41 | - These files should not contain any templating. Only values for templating! 42 | - If you use `importValuesFrom` with a pattern, the values will be nested under the corresponding folder structure. For example, if you have values in files under the `folder1/folder2` directory, they will be nested under `"folder1"."folder2"` in the rendered values. 43 | - The values specified in `importValuesFrom` will be merged, and if there are conflicting keys, the last imported value will override the first one. 44 | 45 | ### *extendRenderWith* 46 | - The `extendRenderWith` section specifies a list of files with templating to render. These files can contain templating logic. In the example, values are extended from extended-values1.yaml 47 | 48 | ### Self values rendering 49 | If neither `importValuesFrom` nor `extendRenderWith` is specified in the file, the values will be taken from the same file, and the file itself will be used for template rendering. 50 | 51 | - Since this file renders values based on its own values, templating will only work with a single level of nesting. For example, if we define param1: value1, we can use it for param2: {{ .Values.param1 }}, but we cannot use param2 to generate the next value. 52 | 53 | - The plugin doesn't know about `.Release` values! 54 | 55 | - Another limitation is that you cannot use string values with `{{ xxx }}` in the main file that should not be rendered (e.g., passing strings with templating for Prometheus rules). 56 | 57 | Example: 58 | 59 | `helm upgrade releasename -f render://test-values.yaml` 60 | ```test-values.yaml 61 | env: dev 62 | namespace: release-{{.Value.env}} 63 | hostname: service-{{.Value.env}}.domain.com 64 | ``` 65 | ## Notes 66 | 67 | v0.2.7 68 | - fix render output 69 | 70 | 71 | v0.2.6 72 | - update go packages 73 | 74 | v0.2.5 75 | - Adds support for Glob Patterns in extendRenderWith 76 | 77 | v0.2.4 78 | - update go to 1.23 and packages 79 | 80 | v0.2.3 81 | - update go to 1.20 82 | - add test for glob import files 83 | - fix glob import files 84 | 85 | v0.2.2 86 | - update go to 1.19 87 | - added tests 88 | - update README 89 | 90 | v0.2.1 91 | - importValuesFrom now can been set with files pattern 92 | 93 | v0.2.0 94 | - add "extendRenderWith" key to include those files to output render 95 | - fix mergeKeys func 96 | 97 | v0.1.3 98 | - fixed all from previous(0.1.2) note 99 | - could use "self" in importValuesFrom 100 | 101 | *** 102 | 103 | ## Development 104 | 105 | Run tests 106 | `go test ./tests/ -v` 107 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module main 2 | 3 | go 1.23 4 | 5 | toolchain go1.23.2 6 | 7 | require ( 8 | github.com/Masterminds/sprig/v3 v3.3.0 9 | gopkg.in/yaml.v2 v2.4.0 10 | ) 11 | 12 | require ( 13 | dario.cat/mergo v1.0.1 // indirect 14 | github.com/Masterminds/goutils v1.1.1 // indirect 15 | github.com/Masterminds/semver/v3 v3.3.1 // indirect 16 | github.com/google/uuid v1.6.0 // indirect 17 | github.com/huandu/xstrings v1.5.0 // indirect 18 | github.com/imdario/mergo v0.3.16 // indirect 19 | github.com/kr/pretty v0.3.1 // indirect 20 | github.com/mitchellh/copystructure v1.2.0 // indirect 21 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 22 | github.com/shopspring/decimal v1.4.0 // indirect 23 | github.com/spf13/cast v1.7.1 // indirect 24 | github.com/stretchr/testify v1.7.0 // indirect 25 | golang.org/x/crypto v0.32.0 // indirect 26 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect 27 | gopkg.in/yaml.v3 v3.0.1 // indirect 28 | ) 29 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= 2 | dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 3 | github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= 4 | github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= 5 | github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= 6 | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 7 | github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= 8 | github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= 9 | github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= 10 | github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= 11 | github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= 12 | github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= 13 | github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= 14 | github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= 15 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 16 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 18 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 19 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 20 | github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= 21 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 22 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 23 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 24 | github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= 25 | github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 26 | github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= 27 | github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 28 | github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= 29 | github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= 30 | github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= 31 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 32 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 33 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 34 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 35 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 36 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 37 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 38 | github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= 39 | github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= 40 | github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= 41 | github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= 42 | github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= 43 | github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 44 | github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= 45 | github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 46 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 47 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 48 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 49 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 50 | github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= 51 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 52 | github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= 53 | github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= 54 | github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= 55 | github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 56 | github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= 57 | github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= 58 | github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= 59 | github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= 60 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 61 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 62 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 63 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 64 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 65 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 66 | golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 67 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 68 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 69 | golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= 70 | golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= 71 | golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= 72 | golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= 73 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 74 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 75 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 76 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 77 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 78 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 79 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 80 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 81 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 82 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 83 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 84 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 85 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 86 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 87 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 88 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "os" 7 | "path/filepath" 8 | 9 | "main/render" 10 | ) 11 | 12 | var ( 13 | debugMode = flag.Bool("debug", false, "run in debugMode") 14 | ) 15 | 16 | const ( 17 | argPrefix = "render://" 18 | ) 19 | 20 | func main() { 21 | var errLog log.Logger 22 | errLog.SetOutput(os.Stderr) 23 | 24 | flag.Parse() 25 | args := flag.Args() 26 | if len(args) == 0 { 27 | errLog.Fatalf(` 28 | ERROR: Required arguments are missing. 29 | Usage: %s %s`, filepath.Base(os.Args[0]), argPrefix) 30 | } 31 | argFilename := args[len(args)-1] 32 | valuesRender := new(render.ValuesRenderer) 33 | valuesRender.Debug = *debugMode 34 | valuesRender.Run(argFilename, argPrefix) 35 | } 36 | -------------------------------------------------------------------------------- /plugin.yaml: -------------------------------------------------------------------------------- 1 | name: "helm-render-values" 2 | version: "0.2.7" 3 | ignoreFlags: false 4 | description: |- 5 | Render value-file as a template and use it. 6 | downloaders: 7 | - command: "render-values" 8 | protocols: 9 | - "render" 10 | 11 | hooks: 12 | install: "cd $HELM_PLUGIN_DIR; scripts/install_plugin.sh" 13 | update: "cd $HELM_PLUGIN_DIR; scripts/install_plugin.sh" 14 | -------------------------------------------------------------------------------- /render/common-funcs.go: -------------------------------------------------------------------------------- 1 | package render 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | // "fmt" 7 | ) 8 | 9 | // Read the file. 10 | func readFile(file string) []byte { 11 | data, err := os.ReadFile(file) 12 | if err != nil { 13 | errLog.Fatalf("ERROR: \"%v\"}", err) 14 | } 15 | return data 16 | } 17 | 18 | // Recursively merge right Values into left one 19 | func mergeKeys(left, right Values) Values { 20 | for key, rightVal := range right { 21 | if leftVal, present := left[key]; present { 22 | if _, ok := leftVal.(Values); ok { 23 | left[key] = mergeKeys(leftVal.(Values), rightVal.(Values)) 24 | } else { 25 | left[key] = rightVal 26 | } 27 | } else { 28 | if left == nil { 29 | left = make(Values) 30 | } 31 | left[key] = rightVal 32 | } 33 | } 34 | return left 35 | } 36 | 37 | // If glob is used. Then map folder tree as yaml structure. 38 | func DirrectoryMapping(dir []string, val Values) Values { 39 | data := make(Values) 40 | if len(dir) > 1 { 41 | data[dir[0]] = DirrectoryMapping(dir[1:], val) 42 | } else if dir[0] != "." { 43 | data[dir[0]] = val 44 | } else { 45 | data = val 46 | } 47 | return data 48 | } 49 | 50 | // Make file path absolut depend on main file. 51 | func absolutePath(basefile, depenfile string) string { 52 | dir := filepath.Dir(basefile) 53 | return filepath.Join(dir, depenfile) 54 | } 55 | -------------------------------------------------------------------------------- /render/values.go: -------------------------------------------------------------------------------- 1 | package render 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | "text/template" 10 | 11 | "gopkg.in/yaml.v2" 12 | ) 13 | 14 | var ( 15 | errLog log.Logger 16 | ) 17 | 18 | type Values map[interface{}]interface{} 19 | 20 | type Files struct { 21 | ImportValues []string `yaml:"importValuesFrom"` 22 | ExtendRender []string `yaml:"extendRenderWith"` 23 | } 24 | 25 | type ValuesRenderer struct { 26 | filename string 27 | files Files 28 | values Values 29 | Debug bool 30 | } 31 | 32 | func (vr *ValuesRenderer) Debuging(format string, v ...any) { 33 | if vr.Debug { 34 | errLog.Printf(format, v...) 35 | } 36 | } 37 | 38 | // Create new render. 39 | func (vr *ValuesRenderer) Run(filename, argPrefix string) { 40 | errLog.SetOutput(os.Stderr) 41 | vr.Debuging("DEBUG: filename: %s", string(filename)) 42 | 43 | vr.filename = strings.TrimPrefix(filename, argPrefix) 44 | 45 | if err := vr.GetFiles(); err != nil { 46 | errLog.Fatalf("ERROR: %s", err) 47 | } 48 | if err := vr.ReadValues(); err != nil { 49 | errLog.Fatalf("ERROR: %s", err) 50 | } 51 | if err := vr.RenderTemplate(); err != nil { 52 | errLog.Fatalf("ERROR: %s", err) 53 | } 54 | } 55 | 56 | // Get files for importValuesFrom/extendRenderWith. 57 | func (vr *ValuesRenderer) GetFiles() error { 58 | 59 | rawFile := readFile(vr.filename) 60 | yamlFile := strings.ReplaceAll(string(rawFile), "{{", "#{{") 61 | extraFiles := Files{} 62 | dmsgs := []string{} 63 | err := yaml.Unmarshal([]byte(yamlFile), &extraFiles) 64 | if err != nil { 65 | return fmt.Errorf("broken file: \"%s\" reason: \"%v\"", vr.filename, err) 66 | } 67 | if len(extraFiles.ImportValues) > 0 { 68 | for i, importFilename := range extraFiles.ImportValues { 69 | if importFilename == "self" { 70 | extraFiles.ImportValues[i] = vr.filename 71 | dmsgs = append(dmsgs, "importValuesFiles: self file will been used for values\n") 72 | } else { 73 | extraFiles.ImportValues[i] = absolutePath(vr.filename, importFilename) 74 | dmsgs = append(dmsgs, "importValuesFiles: extrafile "+importFilename+" will been used for values\n") 75 | } 76 | } 77 | } else { 78 | extraFiles.ImportValues = append(extraFiles.ImportValues, vr.filename) 79 | dmsgs = append(dmsgs, "importValuesFiles: there is no import values. Selfile will been used\n") 80 | } 81 | if len(extraFiles.ExtendRender) > 0 { 82 | var renderFiles []string 83 | for _, renderFilename := range extraFiles.ExtendRender { 84 | matches, err := filepath.Glob(absolutePath(vr.filename, renderFilename)) 85 | if err != nil { 86 | return fmt.Errorf("invalid glob pattern: %s, error: %v", renderFilename, err) 87 | } 88 | renderFiles = append(renderFiles, matches...) 89 | } 90 | extraFiles.ExtendRender = renderFiles 91 | } else { 92 | dmsgs = append(dmsgs, "extendRenderWith: there is no extended files for render\n") 93 | } 94 | 95 | extraFiles.ExtendRender = append(extraFiles.ExtendRender, vr.filename) 96 | vr.files = extraFiles 97 | 98 | vr.Debuging("DEBUG: %v\n", dmsgs) 99 | return err 100 | } 101 | 102 | // Read values from files. 103 | func (vr *ValuesRenderer) ReadValues() error { 104 | 105 | vals := make(Values) 106 | 107 | for _, file := range vr.files.ImportValues { 108 | vr.Debuging("DEBUG: read values from file: %#v\n", file) 109 | var rawFile []byte 110 | var data Values 111 | 112 | if strings.Contains(file, "*") { 113 | data = ParseYamlGlogFile(file) 114 | } else { 115 | rawFile = readFile(file) 116 | if file == vr.filename { 117 | yamlFile := strings.ReplaceAll(string(rawFile), "{{", "#{{") 118 | rawFile = []byte(yamlFile) 119 | } 120 | err := yaml.Unmarshal(rawFile, &data) 121 | if err != nil { 122 | return fmt.Errorf("broken file: \"%s\" reason: \"%v\"", file, err) 123 | } 124 | } 125 | mergeKeys(vals, data) 126 | } 127 | if len(vals) == 0 { 128 | vals = Values{} 129 | } 130 | vr.values = make(Values) 131 | vr.Debuging("DEBUG: total values: %#v\n", vals) 132 | vr.values["Values"] = vals 133 | return nil 134 | } 135 | 136 | // Read glob files. 137 | func ParseYamlGlogFile(pattern string) Values { 138 | 139 | var data Values 140 | matches, err := filepath.Glob(pattern) 141 | if err != nil { 142 | errLog.Fatalf("ERROR: wrong glob: \"%s\"; stack:\"%v\"", pattern, err) 143 | } 144 | for _, file := range matches { 145 | dir := strings.Split(filepath.Dir(file), "/") 146 | fileValue := make(Values) 147 | 148 | rawFile := readFile(file) 149 | err := yaml.Unmarshal(rawFile, &fileValue) 150 | if err != nil { 151 | errLog.Fatalf("ERROR: ReadValues: Can't parse file: \"%s\"; stack:\"%v\"", file, err) 152 | } 153 | data = mergeKeys(data, DirrectoryMapping(dir, fileValue)) 154 | } 155 | return data 156 | } 157 | 158 | // Render Values template to a stdout. 159 | func (vr *ValuesRenderer) RenderTemplate() error { 160 | 161 | valuesResult := make(Values) 162 | for _, file := range vr.files.ExtendRender { 163 | var data Values 164 | var buf strings.Builder 165 | tpl, err := template.New("render").Funcs(funcMap()).ParseFiles(file) 166 | 167 | if err != nil { 168 | return fmt.Errorf("can't create template: %s}", err) 169 | } 170 | tpl.Option("missingkey=error") 171 | 172 | err = tpl.ExecuteTemplate(&buf, filepath.Base(file), vr.values) 173 | if err != nil { 174 | return fmt.Errorf("can't render template: %s}", err) 175 | } 176 | rendered := strings.ReplaceAll(buf.String(), "", "") 177 | 178 | // merge output in a single YAML 179 | err = yaml.Unmarshal([]byte(rendered), &data) 180 | if err != nil { 181 | return fmt.Errorf("can't parse file: \"%s\"; stack:\"%s\"", file, err) 182 | } 183 | mergeKeys(valuesResult, data) 184 | } 185 | renderedValues, err := yaml.Marshal(valuesResult) 186 | vr.Debuging("DEBUG: rendered: %#v", string(renderedValues)) 187 | if err != nil { 188 | return fmt.Errorf("can't marshal yaml: \"%#v\"; stack:\"%v\"", valuesResult, err) 189 | } 190 | fmt.Println(string(renderedValues)) 191 | return nil 192 | 193 | } 194 | -------------------------------------------------------------------------------- /render/yaml-funcs.go: -------------------------------------------------------------------------------- 1 | // There are some functions like in helm 2 | package render 3 | 4 | import ( 5 | "encoding/json" 6 | "log" 7 | "strings" 8 | "text/template" 9 | 10 | "github.com/Masterminds/sprig/v3" 11 | "gopkg.in/yaml.v2" 12 | ) 13 | 14 | func funcMap() template.FuncMap { 15 | f := sprig.TxtFuncMap() 16 | delete(f, "env") 17 | delete(f, "expandenv") 18 | 19 | extra := template.FuncMap{ 20 | "toYaml": toYAML, 21 | "toJson": toJSON, 22 | "fromYaml": fromYAML, 23 | 24 | // functions are not implemented and I don't want to 25 | "include": func(string, interface{}) string { return "not implemented" }, 26 | "tpl": func(string, interface{}) string { return "not implemented" }, 27 | "required": func(string, interface{}) string { return "not implemented" }, 28 | } 29 | 30 | for k, v := range extra { 31 | f[k] = v 32 | } 33 | 34 | return f 35 | } 36 | 37 | func toYAML(v interface{}) string { 38 | data, err := yaml.Marshal(v) 39 | if err != nil { 40 | log.Fatalf("Error: Can't execute toYAML func:\"%v\"\n \"%s\"", err, v) 41 | } 42 | return strings.TrimSuffix(string(data), "\n") 43 | } 44 | 45 | func toJSON(v interface{}) string { 46 | data, err := json.Marshal(v) 47 | if err != nil { 48 | log.Fatalf("Error: Can't execute toJSON func:\"%v\"\n \"%s\"", err, v) 49 | } 50 | return string(data) 51 | } 52 | 53 | func fromYAML(str string) map[string]interface{} { 54 | m := map[string]interface{}{} 55 | 56 | if err := yaml.Unmarshal([]byte(str), &m); err != nil { 57 | m["Error"] = err.Error() 58 | } 59 | return m 60 | } 61 | -------------------------------------------------------------------------------- /scripts/install_plugin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | set -xe 3 | 4 | # Copied w/ love from the excellent hypnoglow/helm-s3 5 | 6 | if [ -n "${HELM_PUSH_PLUGIN_NO_INSTALL_HOOK}" ]; then 7 | echo "Development mode: not downloading versioned release." 8 | exit 0 9 | fi 10 | 11 | version="$(cat plugin.yaml | grep "version" | cut -d '"' -f 2)" 12 | echo "Downloading and installing helm-push v${version} ..." 13 | 14 | arch="" 15 | url="" 16 | if [ "$(arch)" = "aarch64" ]; then 17 | arch="arm64" 18 | elif [ "$(arch)" = "arm" ] ; then 19 | arch="arm64" 20 | else 21 | arch="amd64" 22 | fi 23 | 24 | 25 | if [ "$(uname)" = "Darwin" ]; then 26 | url="https://github.com/vivid-money/helm-plugin-render-values/releases/download/v${version}/helm-plugin-render-values_${version}_darwin_${arch}.tar.gz" 27 | elif [ "$(uname)" = "Linux" ] ; then 28 | url="https://github.com/vivid-money/helm-plugin-render-values/releases/download/v${version}/helm-plugin-render-values_${version}_linux_${arch}.tar.gz" 29 | else 30 | url="https://github.com/vivid-money/helm-plugin-render-values/releases/download/v${version}/helm-plugin-render-values_${version}_windows_${arch}.tar.gz" 31 | fi 32 | 33 | echo $url 34 | 35 | mkdir -p "releases/v${version}" 36 | 37 | # Download with curl if possible. 38 | if [ -x "$(which curl 2>/dev/null)" ]; then 39 | curl -sSL "${url}" -o "releases/v${version}.tar.gz" 40 | else 41 | wget -q "${url}" -O "releases/v${version}.tar.gz" 42 | fi 43 | tar xzf "releases/v${version}.tar.gz" -C "releases/v${version}" 44 | mv "releases/v${version}/render-values" "render-values" || \ 45 | mv "releases/v${version}/render-values.exe" "render-values" 46 | -------------------------------------------------------------------------------- /scripts/make-assets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # set -x 3 | 4 | VERSION="0.2.7" 5 | mkdir -p assets 6 | 7 | OS_LIST="darwin/arm64 8 | darwin/amd64 9 | linux/arm64 10 | linux/amd64 11 | windows/amd64 12 | " 13 | 14 | mkdir -p assets/plugin 15 | cp plugin.yaml LICENSE assets/plugin/ 16 | 17 | for OS_ARCH in $(echo $OS_LIST) 18 | do 19 | OS=${OS_ARCH%/*} 20 | ARCH=${OS_ARCH#*/} 21 | env GOOS=${OS} GOARCH=${ARCH} go build -o assets/plugin/render-values . 22 | tar -czf assets/helm-plugin-render-values_${VERSION}_${OS}_${ARCH}.tar.gz -C assets/plugin . 23 | done 24 | -------------------------------------------------------------------------------- /tests/base-values1.yaml: -------------------------------------------------------------------------------- 1 | defaults: 2 | minReplicas: 2 3 | resources: 4 | limits: 5 | cpu: 1 6 | memory: 512Mi 7 | requests: 8 | cpu: 50m 9 | memory: 256Mi 10 | -------------------------------------------------------------------------------- /tests/base-values2.yaml: -------------------------------------------------------------------------------- 1 | enabled: true 2 | clusterName: aws-eu-test-42 3 | default: from_base 4 | defaults: 5 | minReplicas: 3 6 | testint: 2 -------------------------------------------------------------------------------- /tests/extended-values1.yaml: -------------------------------------------------------------------------------- 1 | myapp1: 2 | clusterExt: {{ .Values.clusterName }} 3 | controllerExt: 4 | autoscaling: 5 | enabled: true 6 | minReplicas: {{ .Values.defaults.minReplicas }} 7 | {{- if .Values.default }} 8 | run: {{ .Values.default }} 9 | {{- end }} 10 | 11 | resources: {{ toYaml .Values.defaults.resources | nindent 6 }} 12 | --- 13 | -------------------------------------------------------------------------------- /tests/extended-values2.yaml: -------------------------------------------------------------------------------- 1 | myapp2: 2 | clusterExt: {{ .Values.clusterName }} 3 | controllerExt: 4 | autoscaling: 5 | enabled: true 6 | minReplicas: {{ .Values.defaults.minReplicas }} 7 | {{- if .Values.default }} 8 | run: {{ .Values.default }} 9 | {{- end }} 10 | 11 | resources: {{ toYaml .Values.defaults.resources | nindent 6 }} 12 | --- 13 | -------------------------------------------------------------------------------- /tests/template-patterns.yaml: -------------------------------------------------------------------------------- 1 | importValuesFrom: 2 | - self 3 | - base-*.yaml 4 | 5 | extendRenderWith: 6 | - extended-*.yaml 7 | 8 | default: from_this 9 | testint: 1 10 | template: '{\{ template $expr }}' 11 | myapp0: 12 | cluster: {{ .Values.clusterName }} 13 | enabled: {{ .Values.enabled }} 14 | controller: 15 | autoscaling: 16 | enabled: true 17 | minReplicas: {{ .Values.defaults.minReplicas }} 18 | {{- if .Values.default }} 19 | run: {{ .Values.default }} 20 | {{- end }} 21 | 22 | resources: {{ toYaml .Values.defaults.resources | nindent 6 }} 23 | -------------------------------------------------------------------------------- /tests/template-values.yaml: -------------------------------------------------------------------------------- 1 | importValuesFrom: 2 | - self 3 | - base-values1.yaml 4 | - base-values2.yaml 5 | 6 | extendRenderWith: 7 | - extended-values1.yaml 8 | 9 | default: from_this 10 | testint: 1 11 | template: '{\{ template $expr }}' 12 | myapp: 13 | cluster: {{ .Values.clusterName }} 14 | enabled: {{ .Values.enabled }} 15 | controller: 16 | autoscaling: 17 | enabled: true 18 | minReplicas: {{ .Values.defaults.minReplicas }} 19 | {{- if .Values.default }} 20 | run: {{ .Values.default }} 21 | {{- end }} 22 | 23 | resources: {{ toYaml .Values.defaults.resources | nindent 6 }} 24 | -------------------------------------------------------------------------------- /tests/test-glob-values.yaml: -------------------------------------------------------------------------------- 1 | importValuesFrom: 2 | - self 3 | - testglob/*/values.yaml 4 | 5 | global: 6 | env: test 7 | 8 | {{ range $name, $app := .Values.testglob }} 9 | "{{ $name }}": 10 | name: {{ $app.name }} 11 | replicas: {{ $app.replicas }} 12 | {{ end}} 13 | -------------------------------------------------------------------------------- /tests/testglob/service1/values.yaml: -------------------------------------------------------------------------------- 1 | name: my-service1 2 | replicas: 3 -------------------------------------------------------------------------------- /tests/testglob/service2/values.yaml: -------------------------------------------------------------------------------- 1 | name: second-service2 2 | replicas: 2 -------------------------------------------------------------------------------- /tests/values_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "testing" 5 | 6 | "main/render" 7 | ) 8 | 9 | func TestRunRender(t *testing.T) { 10 | 11 | t.Run("template-values.yaml", func(t *testing.T) { 12 | valuesRender := new(render.ValuesRenderer) 13 | valuesRender.Run("template-values.yaml", "") 14 | }) 15 | 16 | t.Run("base1-values1.yaml", func(t *testing.T) { 17 | valuesRender := new(render.ValuesRenderer) 18 | valuesRender.Run("base-values1.yaml", "") 19 | }) 20 | 21 | t.Run("test-glob-values.yaml", func(t *testing.T) { 22 | valuesRender := new(render.ValuesRenderer) 23 | valuesRender.Run("test-glob-values.yaml", "") 24 | }) 25 | 26 | t.Run("template-patterns.yaml", func(t *testing.T) { 27 | valuesRender := new(render.ValuesRenderer) 28 | valuesRender.Run("template-patterns.yaml", "") 29 | }) 30 | 31 | // t.Run("extended-values1.yaml", func(t *testing.T) { 32 | // valuesRender := new(render.ValuesRenderer) 33 | // valuesRender.Run("extended-values1.yaml", "") 34 | // }) 35 | } 36 | --------------------------------------------------------------------------------