diff --git a/build/_build.csproj b/build/_build.csproj
index b178179720..d4a839b8e6 100644
--- a/build/_build.csproj
+++ b/build/_build.csproj
@@ -24,7 +24,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/source/Calamari.AzureAppService/Calamari.AzureAppService.csproj b/source/Calamari.AzureAppService/Calamari.AzureAppService.csproj
index aa124dd30b..1f444dd39b 100644
--- a/source/Calamari.AzureAppService/Calamari.AzureAppService.csproj
+++ b/source/Calamari.AzureAppService/Calamari.AzureAppService.csproj
@@ -17,7 +17,9 @@
-
+
+ NU1902
+
diff --git a/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj b/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj
index 078fa3263e..a2ff998be7 100644
--- a/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj
+++ b/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj
@@ -15,7 +15,9 @@
-
+
+ NU1902
+
diff --git a/source/Calamari.ConsolidateCalamariPackages/Calamari.ConsolidateCalamariPackages.csproj b/source/Calamari.ConsolidateCalamariPackages/Calamari.ConsolidateCalamariPackages.csproj
index 7a93745308..11096e249b 100644
--- a/source/Calamari.ConsolidateCalamariPackages/Calamari.ConsolidateCalamariPackages.csproj
+++ b/source/Calamari.ConsolidateCalamariPackages/Calamari.ConsolidateCalamariPackages.csproj
@@ -19,7 +19,9 @@
-
+
+ NU1902
+
diff --git a/source/Calamari.Tests/ArgoCD/Helm/HelmValuesImageReplaceStepVariablesTests.cs b/source/Calamari.Tests/ArgoCD/Helm/HelmValuesImageReplaceStepVariablesTests.cs
new file mode 100644
index 0000000000..028ab96656
--- /dev/null
+++ b/source/Calamari.Tests/ArgoCD/Helm/HelmValuesImageReplaceStepVariablesTests.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections.Generic;
+using Calamari.ArgoCD;
+using Calamari.ArgoCD.Conventions;
+using Calamari.ArgoCD.Models;
+using Calamari.Testing.Helpers;
+using FluentAssertions;
+using FluentAssertions.Execution;
+using NUnit.Framework;
+
+namespace Calamari.Tests.ArgoCD.Helm;
+
+public class HelmValuesImageReplaceStepVariablesTests
+{
+ const string DefaultRegistry = "docker.io";
+ readonly InMemoryLog log = new();
+
+ [Test]
+ public void UnstructuredValue_UpdatesTag_TracksWithFriendlyName()
+ {
+ const string yaml = @"
+image:
+ tag: 1.0
+";
+ var replacer = new HelmValuesImageReplaceStepVariables(yaml, DefaultRegistry, log);
+ var images = new List
+ {
+ new(ContainerImageReference.FromReferenceString("nginx:1.27.1", DefaultRegistry), "image.tag")
+ };
+
+ var result = replacer.UpdateImages(images);
+
+ using var scope = new AssertionScope();
+ result.UpdatedImageReferences.Should().BeEquivalentTo(["nginx:1.27.1"]);
+ result.UpdatedContents.Should().Contain("tag: 1.27.1");
+ }
+
+ [Test]
+ public void UnstructuredValue_AlreadyAtTarget_TracksWithFriendlyName()
+ {
+ const string yaml = @"
+image:
+ tag: 1.27.1
+";
+ var replacer = new HelmValuesImageReplaceStepVariables(yaml, DefaultRegistry, log);
+ var images = new List
+ {
+ new(ContainerImageReference.FromReferenceString("nginx:1.27.1", DefaultRegistry), "image.tag")
+ };
+
+ var result = replacer.UpdateImages(images);
+
+ using var scope = new AssertionScope();
+ result.UpdatedImageReferences.Should().BeEmpty();
+ }
+
+ [Test]
+ public void StructuredValue_UpdatesFullRef()
+ {
+ const string yaml = @"
+image:
+ name: nginx:1.0
+";
+ var replacer = new HelmValuesImageReplaceStepVariables(yaml, DefaultRegistry, log);
+ var images = new List
+ {
+ new(ContainerImageReference.FromReferenceString("nginx:1.27.1", DefaultRegistry), "image.name")
+ };
+
+ var result = replacer.UpdateImages(images);
+
+ using var scope = new AssertionScope();
+ result.UpdatedImageReferences.Should().HaveCount(1);
+ result.UpdatedContents.Should().Contain("name: nginx:1.27.1");
+ }
+
+ [Test]
+ public void StructuredValue_AlreadyAtTarget_TracksWithFriendlyName()
+ {
+ const string yaml = @"
+image:
+ name: nginx:1.27.1
+";
+ var replacer = new HelmValuesImageReplaceStepVariables(yaml, DefaultRegistry, log);
+ var images = new List
+ {
+ new(ContainerImageReference.FromReferenceString("nginx:1.27.1", DefaultRegistry), "image.name")
+ };
+
+ var result = replacer.UpdateImages(images);
+
+ using var scope = new AssertionScope();
+ result.UpdatedImageReferences.Should().BeEmpty();
+ }
+
+ [Test]
+ public void TwoImagesWithSameTag_OnlyUpdatesConfiguredPath()
+ {
+ const string yaml = @"
+nginx:
+ tag: 1.0
+redis:
+ tag: 1.0
+";
+
+ var replacer = new HelmValuesImageReplaceStepVariables(yaml, DefaultRegistry, log);
+ var images = new List
+ {
+ new(ContainerImageReference.FromReferenceString("nginx:1.27.1", DefaultRegistry), "nginx.tag")
+ };
+
+ var result = replacer.UpdateImages(images);
+
+ using var scope = new AssertionScope();
+ result.UpdatedImageReferences.Should().BeEquivalentTo(["nginx:1.27.1"]);
+ result.UpdatedContents.Should().Contain($"nginx:{Environment.NewLine} tag: 1.27.1");
+ result.UpdatedContents.Should().Contain($"redis:{Environment.NewLine} tag: 1.0");
+ }
+
+ [Test]
+ public void NoHelmReference_SkipsImage()
+ {
+ const string yaml = @"
+image:
+ tag: 1.0
+";
+ var replacer = new HelmValuesImageReplaceStepVariables(yaml, DefaultRegistry, log);
+ var images = new List
+ {
+ new(ContainerImageReference.FromReferenceString("nginx:1.27.1", DefaultRegistry))
+ };
+
+ var result = replacer.UpdateImages(images);
+
+ using var scope = new AssertionScope();
+ result.UpdatedImageReferences.Should().BeEmpty();
+ }
+
+ [Test]
+ public void PathNotFoundInYaml_SkipsImage()
+ {
+ const string yaml = @"
+image:
+ tag: 1.0
+";
+ var replacer = new HelmValuesImageReplaceStepVariables(yaml, DefaultRegistry, log);
+ var images = new List
+ {
+ new(ContainerImageReference.FromReferenceString("nginx:1.27.1", DefaultRegistry), "nonexistent.path")
+ };
+
+ var result = replacer.UpdateImages(images);
+
+ using var scope = new AssertionScope();
+ result.UpdatedImageReferences.Should().BeEmpty();
+ result.UpdatedContents.Should().Be(yaml);
+ }
+
+ [Test]
+ public void StructuredValue_MismatchedImageName_DoesNotUpdate()
+ {
+ const string yaml = @"
+image:
+ name: alpine:3.18
+";
+ var replacer = new HelmValuesImageReplaceStepVariables(yaml, DefaultRegistry, log);
+ var images = new List
+ {
+ new(ContainerImageReference.FromReferenceString("nginx:1.27.1", DefaultRegistry), "image.name")
+ };
+
+ var result = replacer.UpdateImages(images);
+
+ using var scope = new AssertionScope();
+ result.UpdatedImageReferences.Should().BeEmpty();
+ result.UpdatedContents.Should().Contain("name: alpine:3.18");
+ }
+}
diff --git a/source/Calamari.Tests/Calamari.Tests.csproj b/source/Calamari.Tests/Calamari.Tests.csproj
index b121284417..94b43b7483 100644
--- a/source/Calamari.Tests/Calamari.Tests.csproj
+++ b/source/Calamari.Tests/Calamari.Tests.csproj
@@ -15,7 +15,7 @@
true
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/source/Calamari/ArgoCD/Conventions/UpdateArgoCDAppDeploymentConfig.cs b/source/Calamari/ArgoCD/Conventions/UpdateArgoCDAppDeploymentConfig.cs
index 82503f14dc..fccf3c4cc1 100644
--- a/source/Calamari/ArgoCD/Conventions/UpdateArgoCDAppDeploymentConfig.cs
+++ b/source/Calamari/ArgoCD/Conventions/UpdateArgoCDAppDeploymentConfig.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
+using Octopus.CoreUtilities.Extensions;
namespace Calamari.ArgoCD.Conventions
{
@@ -18,7 +19,7 @@ public UpdateArgoCDAppDeploymentConfig(GitCommitParameters commitParameters, Lis
public bool HasStepBasedHelmValueReferences()
{
- return ImageReferences.Any(ir => ir.HelmReference is not null) && UseHelmReferenceFromContainer;
+ return ImageReferences.Any(ir => !ir.HelmReference.IsNullOrEmpty()) && UseHelmReferenceFromContainer;
}
}
}
diff --git a/source/Calamari/ArgoCD/HelmValuesImageReplaceStepVariables.cs b/source/Calamari/ArgoCD/HelmValuesImageReplaceStepVariables.cs
index 24bd71c1ba..fbb4b0b999 100644
--- a/source/Calamari/ArgoCD/HelmValuesImageReplaceStepVariables.cs
+++ b/source/Calamari/ArgoCD/HelmValuesImageReplaceStepVariables.cs
@@ -33,13 +33,17 @@ public ImageReplacementResult UpdateImages(IReadOnlyCollection
-
+
+ NU1902
+