From c0b16cc988e4b97229955acd069eabb4b13cd152 Mon Sep 17 00:00:00 2001 From: Marcel Seidel Date: Tue, 2 Jun 2026 09:43:04 +0200 Subject: [PATCH 1/4] Fixing the string replacement in the helm chart to update the tag instead of the image --- scripts/lib/gitops-functions.sh | 2 +- tests/lib-gitops-functions.bats | 119 +++++++++++++++++++++++++++++++- tests/test_helper/setup.bash | 6 ++ 3 files changed, 125 insertions(+), 2 deletions(-) diff --git a/scripts/lib/gitops-functions.sh b/scripts/lib/gitops-functions.sh index 5c4cf71..fbe75f0 100755 --- a/scripts/lib/gitops-functions.sh +++ b/scripts/lib/gitops-functions.sh @@ -41,7 +41,7 @@ update_file() { else local field_type field_type=$(yq "(.${field} | type)" "${file}" 2>/dev/null || echo "!!null") - if [[ "${field_type}" == "!!map" ]] && yq -e ".${field}.tag" "${file}" > /dev/null 2>&1; then + if [[ "${field_type}" == "!!map" ]]; then yq -i ".${field}.tag=\"${INPUT_TAG}\"" "${file}" else yq -i ."${field}"=\""${image}"\" "${file}" diff --git a/tests/lib-gitops-functions.bats b/tests/lib-gitops-functions.bats index 81fa67e..0a7c624 100644 --- a/tests/lib-gitops-functions.bats +++ b/tests/lib-gitops-functions.bats @@ -64,7 +64,7 @@ YQ_MOCK ! grep -q ".tag=\"${INPUT_TAG}\"" "${TEST_TEMP_DIR}/yq_calls.log" } -@test "update_file writes tag to .tag subfield when field is a map with tag property" { +@test "update_file writes tag to .tag subfield when field is a map" { cat > "${TEST_TEMP_DIR}/mocks/yq" << 'YQ_MOCK' #!/usr/bin/env bash echo "yq $*" >> "${MOCK_CALLS_DIR}/yq_calls.log" @@ -77,6 +77,123 @@ YQ_MOCK ! grep -q "${IMAGE}" "${TEST_TEMP_DIR}/yq_calls.log" } +# --- Integration tests using real yq --- + +@test "INTEGRATION: map with repository+tag preserves structure and updates tag" { + skip_if_no_yq + rm -rf "${TEST_TEMP_DIR}/mocks" + local test_file="${TEST_TEMP_DIR}/helmrelease.yaml" + cat > "$test_file" << 'EOF' +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: test-svc + annotations: {} +spec: + values: + workload: + container: + image: + repository: registry.example.com/my-image + tag: old-tag +EOF + + update_file "$test_file" "spec.values.workload.container.image" "$IMAGE" + + run yq '.spec.values.workload.container.image.tag' "$test_file" + assert_output "$INPUT_TAG" + + run yq '.spec.values.workload.container.image.repository' "$test_file" + assert_output "registry.example.com/my-image" + + run yq '.spec.values.workload.container.image | type' "$test_file" + assert_output "!!map" +} + +@test "INTEGRATION: map with only repository gets tag added" { + skip_if_no_yq + rm -rf "${TEST_TEMP_DIR}/mocks" + local test_file="${TEST_TEMP_DIR}/helmrelease.yaml" + cat > "$test_file" << 'EOF' +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: test-svc + annotations: {} +spec: + values: + workload: + container: + image: + repository: registry.example.com/my-image +EOF + + update_file "$test_file" "spec.values.workload.container.image" "$IMAGE" + + run yq '.spec.values.workload.container.image.tag' "$test_file" + assert_output "$INPUT_TAG" + + run yq '.spec.values.workload.container.image.repository' "$test_file" + assert_output "registry.example.com/my-image" + + run yq '.spec.values.workload.container.image | type' "$test_file" + assert_output "!!map" +} + +@test "INTEGRATION: map with only tag updates tag" { + skip_if_no_yq + rm -rf "${TEST_TEMP_DIR}/mocks" + local test_file="${TEST_TEMP_DIR}/helmrelease.yaml" + cat > "$test_file" << 'EOF' +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: test-svc + annotations: {} +spec: + values: + workload: + container: + image: + tag: old-tag +EOF + + update_file "$test_file" "spec.values.workload.container.image" "$IMAGE" + + run yq '.spec.values.workload.container.image.tag' "$test_file" + assert_output "$INPUT_TAG" + + run yq '.spec.values.workload.container.image | type' "$test_file" + assert_output "!!map" +} + +@test "INTEGRATION: scalar image field gets full URI" { + skip_if_no_yq + rm -rf "${TEST_TEMP_DIR}/mocks" + local test_file="${TEST_TEMP_DIR}/deployment.yaml" + cat > "$test_file" << 'EOF' +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-svc + annotations: {} +spec: + template: + spec: + containers: + - name: app + image: registry.example.com/old-image:old-tag +EOF + + update_file "$test_file" 'spec.template.spec.containers[0].image' "$IMAGE" + + run yq '.spec.template.spec.containers[0].image' "$test_file" + assert_output "$IMAGE" + + run yq '.spec.template.spec.containers[0].image | type' "$test_file" + assert_output "!!str" +} + @test "update_file writes tag only when field path ends with .tag" { update_file "helmrelease.yaml" "spec.values.workload.container.image.tag" "$IMAGE" grep -q ".spec.values.workload.container.image.tag=\"${INPUT_TAG}\"" "${TEST_TEMP_DIR}/yq_calls.log" diff --git a/tests/test_helper/setup.bash b/tests/test_helper/setup.bash index bc5d60c..ddd5822 100644 --- a/tests/test_helper/setup.bash +++ b/tests/test_helper/setup.bash @@ -15,6 +15,12 @@ teardown_common() { rm -rf "$TEST_TEMP_DIR" } +skip_if_no_yq() { + if ! command -v yq &> /dev/null; then + skip "yq not installed" + fi +} + # Assert that a specific output was written to GITHUB_OUTPUT assert_output_value() { local name="$1" From d66364cfbadb0bff61e0b871e32f6b8eb3332724 Mon Sep 17 00:00:00 2001 From: Marcel Seidel Date: Tue, 2 Jun 2026 09:55:13 +0200 Subject: [PATCH 2/4] Remove extra tests --- tests/lib-gitops-functions.bats | 85 --------------------------------- 1 file changed, 85 deletions(-) diff --git a/tests/lib-gitops-functions.bats b/tests/lib-gitops-functions.bats index 0a7c624..7b917d3 100644 --- a/tests/lib-gitops-functions.bats +++ b/tests/lib-gitops-functions.bats @@ -79,37 +79,6 @@ YQ_MOCK # --- Integration tests using real yq --- -@test "INTEGRATION: map with repository+tag preserves structure and updates tag" { - skip_if_no_yq - rm -rf "${TEST_TEMP_DIR}/mocks" - local test_file="${TEST_TEMP_DIR}/helmrelease.yaml" - cat > "$test_file" << 'EOF' -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: test-svc - annotations: {} -spec: - values: - workload: - container: - image: - repository: registry.example.com/my-image - tag: old-tag -EOF - - update_file "$test_file" "spec.values.workload.container.image" "$IMAGE" - - run yq '.spec.values.workload.container.image.tag' "$test_file" - assert_output "$INPUT_TAG" - - run yq '.spec.values.workload.container.image.repository' "$test_file" - assert_output "registry.example.com/my-image" - - run yq '.spec.values.workload.container.image | type' "$test_file" - assert_output "!!map" -} - @test "INTEGRATION: map with only repository gets tag added" { skip_if_no_yq rm -rf "${TEST_TEMP_DIR}/mocks" @@ -140,60 +109,6 @@ EOF assert_output "!!map" } -@test "INTEGRATION: map with only tag updates tag" { - skip_if_no_yq - rm -rf "${TEST_TEMP_DIR}/mocks" - local test_file="${TEST_TEMP_DIR}/helmrelease.yaml" - cat > "$test_file" << 'EOF' -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: test-svc - annotations: {} -spec: - values: - workload: - container: - image: - tag: old-tag -EOF - - update_file "$test_file" "spec.values.workload.container.image" "$IMAGE" - - run yq '.spec.values.workload.container.image.tag' "$test_file" - assert_output "$INPUT_TAG" - - run yq '.spec.values.workload.container.image | type' "$test_file" - assert_output "!!map" -} - -@test "INTEGRATION: scalar image field gets full URI" { - skip_if_no_yq - rm -rf "${TEST_TEMP_DIR}/mocks" - local test_file="${TEST_TEMP_DIR}/deployment.yaml" - cat > "$test_file" << 'EOF' -apiVersion: apps/v1 -kind: Deployment -metadata: - name: test-svc - annotations: {} -spec: - template: - spec: - containers: - - name: app - image: registry.example.com/old-image:old-tag -EOF - - update_file "$test_file" 'spec.template.spec.containers[0].image' "$IMAGE" - - run yq '.spec.template.spec.containers[0].image' "$test_file" - assert_output "$IMAGE" - - run yq '.spec.template.spec.containers[0].image | type' "$test_file" - assert_output "!!str" -} - @test "update_file writes tag only when field path ends with .tag" { update_file "helmrelease.yaml" "spec.values.workload.container.image.tag" "$IMAGE" grep -q ".spec.values.workload.container.image.tag=\"${INPUT_TAG}\"" "${TEST_TEMP_DIR}/yq_calls.log" From 0748ac63a4b900d8753f3cdc87ca54d7f3c7f8ad Mon Sep 17 00:00:00 2001 From: Marcel Seidel Date: Tue, 2 Jun 2026 11:01:13 +0200 Subject: [PATCH 3/4] Fix helm chart field check to ensure tag or repository exists before updating --- scripts/lib/gitops-functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/lib/gitops-functions.sh b/scripts/lib/gitops-functions.sh index fbe75f0..2b4f64b 100755 --- a/scripts/lib/gitops-functions.sh +++ b/scripts/lib/gitops-functions.sh @@ -41,7 +41,7 @@ update_file() { else local field_type field_type=$(yq "(.${field} | type)" "${file}" 2>/dev/null || echo "!!null") - if [[ "${field_type}" == "!!map" ]]; then + if [[ "${field_type}" == "!!map" ]] && yq -e ".${field} | (has(\"tag\") or has(\"repository\"))" "${file}" > /dev/null 2>&1; then yq -i ".${field}.tag=\"${INPUT_TAG}\"" "${file}" else yq -i ."${field}"=\""${image}"\" "${file}" From 58da5404e130e0aaa86a1a3b3309eea0be49e6d1 Mon Sep 17 00:00:00 2001 From: Marcel Seidel <47413751+m-seidel@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:10:39 +0200 Subject: [PATCH 4/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tests/lib-gitops-functions.bats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib-gitops-functions.bats b/tests/lib-gitops-functions.bats index 7b917d3..635cbba 100644 --- a/tests/lib-gitops-functions.bats +++ b/tests/lib-gitops-functions.bats @@ -80,8 +80,8 @@ YQ_MOCK # --- Integration tests using real yq --- @test "INTEGRATION: map with only repository gets tag added" { - skip_if_no_yq rm -rf "${TEST_TEMP_DIR}/mocks" + skip_if_no_yq local test_file="${TEST_TEMP_DIR}/helmrelease.yaml" cat > "$test_file" << 'EOF' apiVersion: helm.toolkit.fluxcd.io/v2