From 9d3b4858525253df45dadc50ebe61ce5b2658628 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Thu, 3 Oct 2024 10:35:35 +0200
Subject: [PATCH] fix(helmfile): lock update for multidoc YAML (#31698)

---
 .../manager/helmfile/artifacts.spec.ts        | 90 +++++++++++++++++++
 lib/modules/manager/helmfile/artifacts.ts     | 25 +++---
 2 files changed, 104 insertions(+), 11 deletions(-)

diff --git a/lib/modules/manager/helmfile/artifacts.spec.ts b/lib/modules/manager/helmfile/artifacts.spec.ts
index a6796903f6..ba5e7e6b5c 100644
--- a/lib/modules/manager/helmfile/artifacts.spec.ts
+++ b/lib/modules/manager/helmfile/artifacts.spec.ts
@@ -418,4 +418,94 @@ describe('modules/manager/helmfile/artifacts', () => {
       },
     ]);
   });
+
+  it('updates lockfile with multidoc YAML', async () => {
+    const multidocYaml = codeBlock`
+    apiVersion: source.toolkit.fluxcd.io/v1beta2
+    kind: HelmRepository
+    metadata:
+      name: metallb
+      namespace: flux-system
+    spec:
+      interval: 30m
+      url: https://metallb.github.io/metallb
+    ---
+    apiVersion: helm.toolkit.fluxcd.io/v2beta1
+    kind: HelmRelease
+    metadata:
+      name: metallb
+      namespace: flux-system
+    spec:
+      interval: 5m
+      install:
+        createNamespace: true
+      targetNamespace: metallb-system
+      chart:
+        spec:
+          chart: metallb
+          version: 0.13.10
+          sourceRef:
+            kind: HelmRepository
+            name: metallb
+            namespace: flux-system
+      values:
+        controller:
+          image:
+            repository: quay.io/metallb/controller
+            tag: v0.13.10
+        speaker:
+          image:
+            repository: quay.io/metallb/speaker
+            tag: v0.13.10
+          frr:
+            enabled: false
+    `;
+    const lockFileMultidoc = codeBlock`
+    version: 0.151.0
+    dependencies:
+    - name: metallb
+      repository: https://metallb.github.io/metallb
+      version: 0.13.9
+    digest: sha256:e284706b71f37b757a536703da4cb148d67901afbf1ab431f7d60a9852ca6eef
+    generated: "2023-03-08T21:32:06.122276997+01:00"
+    `;
+    const lockFileMultidocUpdated = codeBlock`
+    version: 0.151.0
+    dependencies:
+    - name: metallb
+      repository: https://metallb.github.io/metallb
+      version: 0.13.10
+    digest: sha256:9d83889176d005effb86041d30c20361625561cbfb439cbd16d7243225bac17c
+    generated: "2023-03-08T21:30:48.273709455+01:00"
+    `;
+
+    git.getFile.mockResolvedValueOnce(lockFileMultidoc as never);
+    fs.getSiblingFileName.mockReturnValueOnce('helmfile.lock');
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValueOnce(lockFileMultidocUpdated as never);
+    fs.privateCacheDir.mockReturnValue(
+      '/tmp/renovate/cache/__renovate-private-cache',
+    );
+    fs.getParentDir.mockReturnValue('');
+    const updatedDeps = [{ depName: 'metallb' }];
+    expect(
+      await helmfile.updateArtifacts({
+        packageFileName: 'helmfile.yaml',
+        updatedDeps,
+        newPackageFileContent: multidocYaml,
+        config,
+      }),
+    ).toEqual([
+      {
+        file: {
+          type: 'addition',
+          path: 'helmfile.lock',
+          contents: lockFileMultidocUpdated,
+        },
+      },
+    ]);
+    expect(execSnapshots).toMatchObject([
+      { cmd: 'helmfile deps -f helmfile.yaml' },
+    ]);
+  });
 });
diff --git a/lib/modules/manager/helmfile/artifacts.ts b/lib/modules/manager/helmfile/artifacts.ts
index 21bcec72e6..745ee835e9 100644
--- a/lib/modules/manager/helmfile/artifacts.ts
+++ b/lib/modules/manager/helmfile/artifacts.ts
@@ -13,7 +13,7 @@ import {
 import { getFile } from '../../../util/git';
 import { regEx } from '../../../util/regex';
 import { Result } from '../../../util/result';
-import { parseSingleYaml } from '../../../util/yaml';
+import { parseYaml } from '../../../util/yaml';
 import { generateHelmEnvs } from '../helmv3/common';
 import type { UpdateArtifact, UpdateArtifactsResult } from '../types';
 import { Doc, LockVersion } from './schema';
@@ -70,21 +70,24 @@ export async function updateArtifacts({
     }
 
     const cmd: string[] = [];
-    const doc = parseSingleYaml(newPackageFileContent, {
+    const docs = parseYaml(newPackageFileContent, {
       removeTemplates: true,
       customSchema: Doc,
+      failureBehaviour: 'filter',
     });
 
-    for (const value of coerceArray(doc.repositories).filter(isOCIRegistry)) {
-      const loginCmd = await generateRegistryLoginCmd(
-        value.name,
-        `https://${value.url}`,
-        // this extracts the hostname from url like format ghcr.ip/helm-charts
-        value.url.replace(regEx(/\/.*/), ''),
-      );
+    for (const doc of docs) {
+      for (const value of coerceArray(doc.repositories).filter(isOCIRegistry)) {
+        const loginCmd = await generateRegistryLoginCmd(
+          value.name,
+          `https://${value.url}`,
+          // this extracts the hostname from url like format ghcr.ip/helm-charts
+          value.url.replace(regEx(/\/.*/), ''),
+        );
 
-      if (loginCmd) {
-        cmd.push(loginCmd);
+        if (loginCmd) {
+          cmd.push(loginCmd);
+        }
       }
     }
 
-- 
GitLab