@@ -78,18 +78,18 @@ runs:
7878 steps :
7979 - uses : hoverkraft-tech/ci-github-common/actions/checkout@4c9d51717dc04d823dac2dc9ac2857e7b3069454 # 0.35.0
8080
81- - id : chart-values -updates
81+ - id : chart-tag -updates
8282 uses : actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
8383 env :
8484 INPUT_PATH : ${{ inputs.path }}
8585 INPUT_TAG : ${{ inputs.tag }}
8686 INPUT_UPDATE_TAG_PATHS : ${{ inputs.update-tag-paths }}
87+ INPUT_VALUES : ${{ inputs.values }}
8788 REPOSITORY_NAME : ${{ github.event.repository.name }}
8889 with :
8990 script : |
9091 const path = require('node:path');
9192
92- const yqUpdates = {};
9393 const basePath = process.env.INPUT_PATH;
9494 if (!basePath) {
9595 throw new Error(`"path" input is missing`);
@@ -100,153 +100,111 @@ runs:
100100 throw new Error(`"tag" input is missing`);
101101 }
102102
103- const updateTagPaths = process.env.INPUT_UPDATE_TAG_PATHS.trim().split(',').map(p => p.trim()).filter(p => p);
104-
105- // Chart.yml files
106- const globber = await glob.create(`${basePath}/**/Chart.yaml`, {followSymbolicLinks: false})
107- for await (const chartFile of globber.globGenerator()) {
108- const filePath = path.relative(process.env.GITHUB_WORKSPACE, chartFile);
109- if (!yqUpdates[filePath]) {
110- yqUpdates[filePath] = [];
111- }
112-
113- const isRootChart = filePath === path.join(basePath, "Chart.yaml");
114- if (isRootChart) {
115- // Update name for root chart
116- yqUpdates[filePath].push(`.name = "${process.env.REPOSITORY_NAME}"`);
117-
118- // Update dependencies version where repository starts with file://
119- if (updateTagPaths.includes('.version')) {
120- yqUpdates[filePath].push(
121- `(. as $doc | (select(has("dependencies")) | (.dependencies[] | select(.repository == "file://*")).version = "${tag}") // $doc)`
122- );
123- }
124- }
125-
126- // Update tag fields
127- for (const path of updateTagPaths) {
128- yqUpdates[filePath].push(`${path} = "${tag}"`);
129- }
130- }
131-
132- // values.yml files
133- const chartValuesInput = `${{ inputs.values }}`;
134- if (chartValuesInput) {
135-
136- // Check if is valid Json
137- let chartValues = null;
103+ const inputValues = process.env.INPUT_VALUES;
104+ let chartValues = [];
105+ if (inputValues) {
138106 try {
139- chartValues = JSON.parse(chartValuesInput );
107+ chartValues = JSON.parse(inputValues );
140108 } catch (error) {
141109 throw new Error(`"values" input is not a valid JSON: ${error}`);
142110 }
143111
144- // Check if is an array
145112 if (!Array.isArray(chartValues)) {
146113 throw new Error(`"values" input is not an array`);
147114 }
115+ }
148116
149- if (chartValues.length) {
150- const defaultValuesPath = "values.yaml";
151-
152- // Check each item
153- for (const key in chartValues) {
154- const chartValue = chartValues[key];
155- if (typeof chartValue !== 'object') {
156- throw new Error(`"values[${key}]" input is not an object`);
157- }
158-
159- // Check mandatory properties
160- for (const property of ['path', 'value']) {
161- if (!chartValue.hasOwnProperty(property)) {
162- throw new Error(`"values[${key}].${property}" input is missing`);
163- }
164- }
117+ const updateTagPaths = process.env.INPUT_UPDATE_TAG_PATHS.trim().split(',').map(p => p.trim()).filter(p => p);
118+ const chartRootPath = path.resolve(process.env.GITHUB_WORKSPACE ?? '.', basePath);
119+ const generatedValues = [];
165120
166- const valueFilePath = chartValue['file'] ? chartValue['file'] : defaultValuesPath;
167- const filePath = `${basePath}/${valueFilePath}`;
121+ const globber = await glob.create(`${basePath}/**/Chart.yaml`, { followSymbolicLinks: false });
122+ for await (const chartFile of globber.globGenerator()) {
123+ const filePath = path.relative(chartRootPath, chartFile);
168124
169- if (!yqUpdates[filePath]) {
170- yqUpdates[filePath] = [];
171- }
125+ const isRootChart = filePath === 'Chart.yaml';
126+ if (isRootChart) {
127+ generatedValues.push({
128+ file: filePath,
129+ path: '.name',
130+ value: process.env.REPOSITORY_NAME,
131+ });
172132
173- yqUpdates[filePath].push(`${chartValue.path} = "${chartValue.value}"`);
133+ if (updateTagPaths.includes('.version')) {
134+ generatedValues.push({
135+ file: filePath,
136+ path: '(.dependencies[]? | select(.repository | test("^file://")).version)',
137+ value: tag,
138+ });
174139 }
175140 }
176- }
177141
178- // Build yq commands
179- const yqCommands = Object.entries(yqUpdates).map(([filePath, updates]) => {
180- return `yq -i '${updates.join(' | ')}' ${filePath}`;
181- });
142+ for (const path of updateTagPaths) {
143+ generatedValues.push({
144+ file: filePath,
145+ path,
146+ value: tag,
147+ });
148+ }
149+ }
182150
183- core.setOutput('yq-command ', yqCommands.join('\n' ));
151+ core.setOutput('values ', JSON.stringify([...generatedValues, ...chartValues] ));
184152
185- - uses : mikefarah/yq@751d8ad57b84f1794661bc70c0afb92a22ad7b3c # v4.53.2
153+ - uses : ./actions/helm/update-chart-values
186154 with :
187- cmd : |
188- ${{ steps.chart-values -updates.outputs.yq-command }}
155+ path : ${{ inputs.path }}
156+ values : ${{ steps.chart-tag -updates.outputs.values }}
189157
190158 - name : Setup Node.js
191159 uses : hoverkraft-tech/ci-github-nodejs/actions/setup-node@a10d5e32daef8e060c49fe617833fb0d53476f22 # 0.24.0
192160 with :
193161 working-directory : ${{ github.action_path }}
194162
195- - name : Rewrite the Chart.lock to match with updated ombrella dependencies if any
163+ - name : Rewrite the Chart.lock to match with updated umbrella dependencies if any
196164 uses : actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
197165 env :
166+ INPUT_PATH : ${{ inputs.path }}
167+ INPUT_TAG : ${{ inputs.tag }}
198168 NODE_PATH : ${{ github.action_path }}/node_modules
199169 with :
200170 script : |
201171 const fs = require('node:fs');
202- const path = require('node:path');
203172 const crypto = require('node:crypto');
204- const yaml = require(" yaml" );
173+ const yaml = require(' yaml' );
205174
206- const rootChartFile = `${{ inputs.path }} /Chart.yaml` ;
175+ const rootChartFile = process.env.INPUT_PATH + ' /Chart.yaml' ;
207176 const rootChartFileContent = yaml.parse(fs.readFileSync(rootChartFile, 'utf8'));
208177
209- // Check if the root chart has dependencies
210178 if (!rootChartFileContent.dependencies || rootChartFileContent.dependencies.length === 0) {
211179 return;
212180 }
213181
214- const chartLockFile = `${{ inputs.path }} /Chart.lock` ;
182+ const chartLockFile = process.env.INPUT_PATH + ' /Chart.lock' ;
215183 if (!fs.existsSync(chartLockFile)) {
216184 return core.setFailed(`Chart.lock file not found: ${chartLockFile}`);
217185 }
218186
219187 const chartLockFileContent = yaml.parse(fs.readFileSync(chartLockFile, 'utf8'));
220188
221- // Update ombrella dependencies versions
222189 let hasLocalDependencies = false;
223190 const dependencies = chartLockFileContent.dependencies;
224191
225- // Check if dependencies are empt
226192 for (const dependency of dependencies) {
227- const isLocalDependency = dependency.repository.startsWith(" file://" ) && dependency.version === " 0.0.0" ;
193+ const isLocalDependency = dependency.repository.startsWith(' file://' ) && dependency.version === ' 0.0.0' ;
228194
229- // Check if the dependency is a local file
230195 if (isLocalDependency) {
231- // Update the version to the tag
232- dependency.version = `${{ inputs.tag }}`;
196+ dependency.version = process.env.INPUT_TAG;
233197 hasLocalDependencies = true;
234198 }
235199 }
236200
237- // If no local dependencies, exit
238201 if (!hasLocalDependencies) {
239202 return;
240203 }
241204
242- // Update generated
243205 chartLockFileContent.generated = new Date().toISOString();
244206
245- // Update global digest.
246-
247- // See Helm hashReq function: https://github.com/helm/helm/blob/99c065789ef8c45bade24d4bc2d33432595de956/internal/resolver/resolver.go#L214
248207 function hashReq(req, lock) {
249- // Sort the dependencies
250208 req = req.map(sortDependencyFields);
251209 lock = lock.map(sortDependencyFields);
252210
@@ -261,8 +219,6 @@ runs:
261219 return hash.digest('hex');
262220 }
263221
264- // Should respect the Helm struct order
265- // See https://github.com/helm/helm/blob/99c065789ef8c45bade24d4bc2d33432595de956/pkg/chart/v2/dependency.go#L24
266222 function sortDependencyFields(dependency) {
267223 const fieldOrder = [
268224 'name',
@@ -274,10 +230,9 @@ runs:
274230 'import-values',
275231 'alias',
276232 ];
277- // Sort the dependency fields
278233 const sortedDependency = {};
279234 for (const field of fieldOrder) {
280- if (dependency. hasOwnProperty( field)) {
235+ if (Object.prototype. hasOwnProperty.call(dependency, field)) {
281236 sortedDependency[field] = dependency[field];
282237 }
283238 }
@@ -288,13 +243,11 @@ runs:
288243 const req = rootChartFileContent.dependencies;
289244 const lock = dependencies;
290245
291- const hash = hashReq(req, lock);
292- chartLockFileContent.digest = hash;
246+ chartLockFileContent.digest = hashReq(req, lock);
293247
294248 const updatedChartLockFileContent = yaml.stringify(chartLockFileContent);
295249 core.debug(`Updated Chart.lock file content:\n${updatedChartLockFileContent}`);
296250
297- // Update Chart.lock file
298251 fs.writeFileSync(chartLockFile, updatedChartLockFileContent, 'utf8');
299252
300253 - uses : azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0
0 commit comments