Skip to content

fix: make --find-renames work with --output=dyff#961

Merged
yxxhero merged 1 commit intomasterfrom
fix-dyff-find-renames
Mar 24, 2026
Merged

fix: make --find-renames work with --output=dyff#961
yxxhero merged 1 commit intomasterfrom
fix-dyff-find-renames

Conversation

@yxxhero
Copy link
Collaborator

@yxxhero yxxhero commented Mar 24, 2026

Summary

  • Remove dyff.DetectRenames(true) from dyff output format to allow helm-diff's --find-renames option to work correctly
  • Fix tautological condition warning in doDiff function
  • Add unit tests for dyff report output

Fixes #632

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes dyff output behavior so helm-diff’s --find-renames option can control rename detection (instead of dyff doing its own rename pairing), and adds/updates tests around dyff report generation.

Changes:

  • Disable dyff’s internal rename detection in printDyffReport to restore --find-renames semantics for --output=dyff.
  • Simplify doDiff by removing a tautological oldContent != nil check in the remove case.
  • Add unit tests covering basic dyff report output paths.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
diff/report.go Removes dyff.DetectRenames(true) by switching to an explicit options slice passed into dyff comparison.
diff/diff.go Simplifies remove-case logic in doDiff by eliminating redundant nil checks.
diff/report_test.go Adds unit tests exercising printDyffReport output generation.
Comments suppressed due to low confidence (1)

diff/report.go:124

  • dyff.CompareInputFiles and reportWriter.WriteReport errors are being ignored. If parsing/comparison fails, report may be nil and WriteReport can panic or silently emit incomplete output. Please handle these errors (e.g., write an error message to to and return, or change printDyffReport to return an error and propagate it).
	var compareOptions []dyff.CompareOption
	compareOptions = append(compareOptions,
		dyff.IgnoreWhitespaceChanges(true),
		dyff.KubernetesEntityDetection(true),
	)
	report, _ := dyff.CompareInputFiles(currentInputFile, newInputFile, compareOptions...)
	reportWriter := &dyff.HumanReport{
		Report:               report,
		OmitHeader:           true,
		MinorChangeThreshold: 0.1,
	}
	_ = reportWriter.WriteReport(to)

Comment on lines +70 to +103
func TestPrintDyffReportWithAddAndRemove(t *testing.T) {
report := &Report{
Entries: []ReportEntry{
{
Key: "default, old-app, Deployment (apps)",
Kind: "Deployment",
ChangeType: "REMOVE",
Diffs: []difflib.DiffRecord{
{Payload: "apiVersion: apps/v1", Delta: difflib.LeftOnly},
{Payload: "kind: Deployment", Delta: difflib.LeftOnly},
{Payload: "metadata:", Delta: difflib.LeftOnly},
{Payload: " name: old-app", Delta: difflib.LeftOnly},
},
},
{
Key: "default, new-app, Deployment (apps)",
Kind: "Deployment",
ChangeType: "ADD",
Diffs: []difflib.DiffRecord{
{Payload: "apiVersion: apps/v1", Delta: difflib.RightOnly},
{Payload: "kind: Deployment", Delta: difflib.RightOnly},
{Payload: "metadata:", Delta: difflib.RightOnly},
{Payload: " name: new-app", Delta: difflib.RightOnly},
},
},
},
}

var buf bytes.Buffer
printDyffReport(report, &buf)

output := buf.String()
require.NotEmpty(t, output)
}
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new dyff tests don't assert the regression fix described in #632. In particular, TestPrintDyffReportWithAddAndRemove only checks non-empty output, so it would pass even if dyff still reorders/pairs removed+added resources (the original bug). Please strengthen this test (or add another) to assert that add/remove output is distinguishable from a rename-as-modify scenario (e.g., compare outputs for REMOVE+ADD vs a single MODIFY entry and assert they differ / contain expected identifiers).

Copilot uses AI. Check for mistakes.
Comment on lines +66 to +67
require.True(t, strings.Contains(output, "replicas") || strings.Contains(output, "2") || strings.Contains(output, "3"),
"Expected dyff output to contain information about replicas change")
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

require.True(strings.Contains(output, "replicas") || strings.Contains(output, "2") || strings.Contains(output, "3")) is very permissive and can pass even if the dyff output isn't actually describing the replicas change (e.g., if some unrelated "2" appears). Please tighten the assertion to check for a more specific/robust signal of the replicas field change (for example requiring the field name and at least one of the expected values).

Suggested change
require.True(t, strings.Contains(output, "replicas") || strings.Contains(output, "2") || strings.Contains(output, "3"),
"Expected dyff output to contain information about replicas change")
require.Contains(t, output, "replicas: 2", "Expected dyff output to show original replicas value")
require.Contains(t, output, "replicas: 3", "Expected dyff output to show updated replicas value")

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment on lines +146 to +147
{Payload: "- name: old-app", Delta: difflib.LeftOnly},
{Payload: "+ name: new-app", Delta: difflib.RightOnly},
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In modifyReport, the DiffRecord payloads include diff markers (- / + ). difflib.Diff payloads are raw input lines (the delta encodes left/right), so these prefixes make the YAML content here unrepresentative and can change YAML structure compared to real manifests. Consider using the actual YAML lines (with consistent indentation) and rely on Delta to indicate removal/addition.

Suggested change
{Payload: "- name: old-app", Delta: difflib.LeftOnly},
{Payload: "+ name: new-app", Delta: difflib.RightOnly},
{Payload: " name: old-app", Delta: difflib.LeftOnly},
{Payload: " name: new-app", Delta: difflib.RightOnly},

Copilot uses AI. Check for mistakes.
The dyff output format was always using dyff.DetectRenames(true), which
overrode helm-diff's --find-renames option. This caused renames detected
by helm-diff to be re-evaluated by dyff, resulting in inconsistent output
compared to other formats (diff, simple).

Fixes #632

Signed-off-by: yxxhero <aiopsclub@163.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

diff/report.go:124

  • Errors from dyff.CompareInputFiles and reportWriter.WriteReport are discarded. If dyff fails to compare or render (e.g., due to YAML parsing issues), the command can appear to succeed while producing incomplete output. Please handle these errors (at least surface them to stderr / the writer) so failures are diagnosable.
	report, _ := dyff.CompareInputFiles(currentInputFile, newInputFile, compareOptions...)
	reportWriter := &dyff.HumanReport{
		Report:               report,
		OmitHeader:           true,
		MinorChangeThreshold: 0.1,
	}
	_ = reportWriter.WriteReport(to)

Comment on lines 111 to 115
currentInputFile, newInputFile, _ := ytbx.LoadFiles(currentFile.Name(), newFile.Name())

report, _ := dyff.CompareInputFiles(
currentInputFile, newInputFile,
var compareOptions []dyff.CompareOption
compareOptions = append(compareOptions,
dyff.IgnoreWhitespaceChanges(true),
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return error from ytbx.LoadFiles is currently ignored. If loading/parsing either temp file fails, dyff comparison may silently produce empty/incorrect output. Consider checking the error and writing a clear message (or falling back to the default diff output) instead of proceeding with a potentially invalid input state.

Copilot uses AI. Check for mistakes.
Comment on lines +167 to +177
func TestPrintDyffReportEmpty(t *testing.T) {
report := &Report{
Entries: []ReportEntry{},
}

var buf bytes.Buffer
printDyffReport(report, &buf)

output := buf.String()
require.Equal(t, "\n", output)
}
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The empty-report assertion is very strict (expects exactly a single newline). Since dyff's human output formatting can change across dyff versions, this may be brittle. Consider asserting that the output is empty/whitespace-only (or that it contains no diff markers) rather than matching an exact string.

Copilot uses AI. Check for mistakes.
@yxxhero yxxhero merged commit 1ce0182 into master Mar 24, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Option --find-renames doesn't work for --output=dyff

2 participants