Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions assets/issues/issue-686/from.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
data:
values.yaml: |
image:
registry: custom-registry
service:
port: 80
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
metrics: {}
resources:
limits:
cpu: 100m
priorityClassName: my-priority
15 changes: 15 additions & 0 deletions assets/issues/issue-686/to.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
data:
values.yaml: |
image:
registry: custom-registry
service:
port: 80
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
metrics: {}
resources:
limits:
cpu: 100m
priorityClassName: my-priority
14 changes: 0 additions & 14 deletions assets/kubernetes/rename/expected-dyff.human
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@

data.pinniped.yaml
± value change in multiline text (one insert, no deletions)
discovery:
url: null
api:
servingCertificate:

[two lines unchanged)]

apiGroupSuffix: pinniped.dev
# aggregatedAPIServerPort may be set here, although other YAML references to the default port (10250) may also need to be updated
# impersonationProxyServerPort may be set here, although other YAML references to the default port (8444) may also need to be updated
Expand All @@ -17,13 +10,6 @@ data.pinniped.yaml
credentialIssuer: pinniped-concierge-config
apiService: pinniped-concierge-api
impersonationLoadBalancerService: pinniped-concierge-impersonation-proxy-load-balancer

[five lines unchanged)]

labels: {"app": "pinniped-concierge"}
kubeCertAgent:
namePrefix: pinniped-concierge-kube-cert-agent-
image: projects.registry.vmware.com/pinniped/pinniped-server:latest



Expand Down
14 changes: 0 additions & 14 deletions assets/multiline/expected-dyff-spruce.github
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,6 @@

@@ files.complex.content @@
! ± value change in multiline text (two inserts, two deletions)
 Begin line 1
 Begin line 2
 Begin line 3
 Begin line 4
 
 [four lines unchanged)]
 
 PreChange line 1
 PreChange line 2
 PreChange line 3
Expand Down Expand Up @@ -84,11 +77,4 @@
 PostDelete line 2
 PostDelete line 3
 PostDelete line 4
 
 [22 lines unchanged)]
 
 End line 1
 End line 2
 End line 3
 End line 4

14 changes: 0 additions & 14 deletions assets/multiline/expected-dyff-spruce.human
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,6 @@

files.complex.content
± value change in multiline text (two inserts, two deletions)
 Begin line 1
 Begin line 2
 Begin line 3
 Begin line 4
 
 [four lines unchanged)]
 
 PreChange line 1
 PreChange line 2
 PreChange line 3
Expand Down Expand Up @@ -86,12 +79,5 @@
 PostDelete line 2
 PostDelete line 3
 PostDelete line 4
 
 [22 lines unchanged)]
 
 End line 1
 End line 2
 End line 3
 End line 4


32 changes: 29 additions & 3 deletions pkg/dyff/output_human.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ func (report *HumanReport) writeStringDiff(output stringWriter, from string, to
var ins, del int
var buf bytes.Buffer
multilineContextLines := report.MultilineContextLines
for _, d := range diff {
for i, d := range diff {
// color and format each diff by type
switch d.Type {
case diffmatchpatch.DiffInsert:
Expand All @@ -384,6 +384,24 @@ func (report *HumanReport) writeStringDiff(output stringWriter, from string, to
if multilineContextLines <= 0 || len(d.Text) == 0 {
continue
}

// Only keep context adjacent to actual changes (issue #686). Leading equal
// hunks used to also emit the start of the file; trailing ones the end.
hasChangeBefore := false
for j := 0; j < i; j++ {
if diff[j].Type != diffmatchpatch.DiffEqual {
hasChangeBefore = true
break
}
}
hasChangeAfter := false
for j := i + 1; j < len(diff); j++ {
if diff[j].Type != diffmatchpatch.DiffEqual {
hasChangeAfter = true
break
}
}

// add amount of unchanged lines as configured
lines := strings.Split(d.Text, "\n")
lower := int(math.Min(float64(len(lines)), float64(multilineContextLines)))
Expand All @@ -393,9 +411,17 @@ func (report *HumanReport) writeStringDiff(output stringWriter, from string, to
upper--
}
var val string
if upper <= lower {
switch {
case upper <= lower:
val = strings.Join(lines, "\n")
} else {
case !hasChangeBefore && hasChangeAfter:
// Leading equal hunk: context before the following change only.
val = strings.Join(lines[upper:], "\n")
case hasChangeBefore && !hasChangeAfter:
// Trailing equal hunk: context after the preceding change only.
val = strings.Join(lines[:lower], "\n")
default:
// Equal hunk between changes: keep both ends.
val = fmt.Sprintf("%s\n\n[%s unchanged)]\n\n%s",
strings.Join(lines[:lower], "\n"),
text.Plural((upper-lower), "line"),
Expand Down
36 changes: 36 additions & 0 deletions pkg/dyff/output_human_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
package dyff_test

import (
"bufio"
"bytes"
"fmt"

. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -227,6 +229,40 @@ variables.ROUTER_TLS_PEM.options
false,
)
})

It("should only keep multiline context adjacent to changes (https://github.com/homeport/dyff/issues/686)", func() {
from, to := loadFiles(
assets("issues", "issue-686", "from.yml"),
assets("issues", "issue-686", "to.yml"),
)

report, err := dyff.CompareInputFiles(from, to)
Expect(err).ToNot(HaveOccurred())

reportWriter := &dyff.HumanReport{
Report: report,
Indent: 2,
UseIndentLines: true,
OmitHeader: true,
MinorChangeThreshold: 0.1,
MultilineContextLines: 2,
}

buffer := &bytes.Buffer{}
writer := bufio.NewWriter(buffer)
Expect(reportWriter.WriteReport(writer)).To(Succeed())
Expect(writer.Flush()).To(Succeed())

actual := RemoveAllEscapeSequences(buffer.String())
Expect(actual).To(ContainSubstring("minReplicas: 2"))
Expect(actual).To(ContainSubstring("minReplicas: 3"))
Expect(actual).To(ContainSubstring("autoscaling:"))
Expect(actual).To(ContainSubstring("maxReplicas: 10"))
// Leading/trailing file bookends must not appear when context is local only.
Expect(actual).ToNot(ContainSubstring("registry: custom-registry"))
Expect(actual).ToNot(ContainSubstring("priorityClassName"))
Expect(actual).ToNot(ContainSubstring("unchanged)"))
})
})

Context("reported output issues (without colors)", func() {
Expand Down