Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
40 changes: 35 additions & 5 deletions tools/cli/internal/changelog/outputfilter/squash.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,27 +112,40 @@ func newSquashHandlers() []handler {
}

// EntryMappings groups entries by ID and then by OperationID and returns a Map[changeCode, Map[operationId, List[oasdiffEntry]]]
func newEntriesMapPerIDAndOperationID(entries []*OasDiffEntry) map[string]map[string][]*OasDiffEntry {
result := make(map[string]map[string][]*OasDiffEntry)
func newEntriesMapPerIDAndOperationID(entries []*OasDiffEntry) (result, hiddenResult map[string]map[string][]*OasDiffEntry) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

could you update the function comment to include the new returned map?

result = make(map[string]map[string][]*OasDiffEntry)
hiddenResult = make(map[string]map[string][]*OasDiffEntry)

for _, entry := range entries {
code := entry.ID
operationID := entry.OperationID
hidden := entry.HideFromChangelog

// Ensure the code map exists
if _, exists := result[code]; !exists {
result[code] = make(map[string][]*OasDiffEntry)
}

if _, exists := hiddenResult[code]; !exists {
hiddenResult[code] = make(map[string][]*OasDiffEntry)
}
Copy link
Collaborator

@andreaangiolillo andreaangiolillo Nov 13, 2024

Choose a reason for hiding this comment

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

Shouldn't you create a new entry in the map only if there is at least one entry hidden? if yes., you add this inside the hidden if

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

we could but the way its being done for the visible ones is like this, both end up adding the code into the map before, even if there are no entries. in that case I can do that for both, I just wasn't sure if this statement existed to cover some corner case I'm not aware of

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm making the change and not finding any failures so lets try that!


if hidden {
// Append the entry to the appropriate operationID slice
hiddenResult[code][operationID] = append(hiddenResult[code][operationID], entry)
continue
}

// Append the entry to the appropriate operationID slice
result[code][operationID] = append(result[code][operationID], entry)
}

return result
return result, hiddenResult
}

func squashEntries(entries []*OasDiffEntry) ([]*OasDiffEntry, error) {
entriesMap := newEntriesMapPerIDAndOperationID(entries)
entriesByIDandOperationID, hiddenEntriesByIDandOperationID := newEntriesMapPerIDAndOperationID(entries)

squashHandlers := newSquashHandlers()
squashedEntries := []*OasDiffEntry{}

Expand All @@ -145,6 +158,24 @@ func squashEntries(entries []*OasDiffEntry) ([]*OasDiffEntry, error) {
}
}

squashedEntriesNotHidden, err := appplySquashHandlerToMap(squashHandlers, entriesByIDandOperationID)
if err != nil {
return nil, err
}

squashedEntriesHidden, err := appplySquashHandlerToMap(squashHandlers, hiddenEntriesByIDandOperationID)
if err != nil {
return nil, err
}

squashedEntries = append(squashedEntries, squashedEntriesNotHidden...)
squashedEntries = append(squashedEntries, squashedEntriesHidden...)

return squashedEntries, nil
}

func appplySquashHandlerToMap(squashHandlers []handler, entriesMap map[string]map[string][]*OasDiffEntry) ([]*OasDiffEntry, error) {
squashedEntries := []*OasDiffEntry{}
for _, handler := range squashHandlers {
entryMapPerOperationID, ok := entriesMap[handler.id]
if !ok {
Expand All @@ -158,7 +189,6 @@ func squashEntries(entries []*OasDiffEntry) ([]*OasDiffEntry, error) {

squashedEntries = append(squashedEntries, sortEntriesByDescription(entries)...)
}

return squashedEntries, nil
}

Expand Down
244 changes: 236 additions & 8 deletions tools/cli/internal/changelog/outputfilter/squash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@ package outputfilter

import (
"reflect"
"sort"
"testing"

"github.com/stretchr/testify/require"
)

func TestNewEntriesMapPerIDAndOperationID(t *testing.T) {
testCases := []struct {
name string
entries []*OasDiffEntry
want map[string]map[string][]*OasDiffEntry
name string
entries []*OasDiffEntry
want map[string]map[string][]*OasDiffEntry
wantHidden map[string]map[string][]*OasDiffEntry
}{
{
name: "Empty entries",
entries: []*OasDiffEntry{},
want: map[string]map[string][]*OasDiffEntry{},
name: "Empty entries",
entries: []*OasDiffEntry{},
want: map[string]map[string][]*OasDiffEntry{},
wantHidden: map[string]map[string][]*OasDiffEntry{},
},
{
name: "Single entry",
Expand All @@ -30,6 +33,8 @@ func TestNewEntriesMapPerIDAndOperationID(t *testing.T) {
},
},
},
wantHidden: map[string]map[string][]*OasDiffEntry{
"response-write-only-property-enum-value-added": {}},
},
{
name: "Multiple entries with same ID",
Expand All @@ -47,8 +52,9 @@ func TestNewEntriesMapPerIDAndOperationID(t *testing.T) {
},
},
},
wantHidden: map[string]map[string][]*OasDiffEntry{
"response-write-only-property-enum-value-added": {}},
},

{
name: "Multiple entries with same ID and OperationID",
entries: []*OasDiffEntry{
Expand All @@ -63,6 +69,8 @@ func TestNewEntriesMapPerIDAndOperationID(t *testing.T) {
},
},
},
wantHidden: map[string]map[string][]*OasDiffEntry{
"response-write-only-property-enum-value-added": {}},
},
{
name: "Multiple entries with different IDs",
Expand Down Expand Up @@ -90,15 +98,70 @@ func TestNewEntriesMapPerIDAndOperationID(t *testing.T) {
},
},
},
wantHidden: map[string]map[string][]*OasDiffEntry{
"response-write-only-property-enum-value-added": {},
"request-write-only-property-enum-value-added": {},
},
},
{
name: "Hidden entries",
entries: []*OasDiffEntry{
{ID: "response-write-only-property-enum-value-added", OperationID: "op1", HideFromChangelog: true},
{ID: "response-write-only-property-enum-value-added", OperationID: "op2", HideFromChangelog: true},
},
want: map[string]map[string][]*OasDiffEntry{
"response-write-only-property-enum-value-added": {}},
wantHidden: map[string]map[string][]*OasDiffEntry{
"response-write-only-property-enum-value-added": {
"op1": []*OasDiffEntry{
{ID: "response-write-only-property-enum-value-added", OperationID: "op1", HideFromChangelog: true},
},
"op2": []*OasDiffEntry{
{ID: "response-write-only-property-enum-value-added", OperationID: "op2", HideFromChangelog: true},
},
},
},
},
{
name: "Mixed hidden and non-hidden entries",
entries: []*OasDiffEntry{
{ID: "response-write-only-property-enum-value-added", OperationID: "op1"},
{ID: "response-write-only-property-enum-value-added", OperationID: "op2", HideFromChangelog: true},
{ID: "response-write-only-property-enum-value-added", OperationID: "op3"},
{ID: "response-write-only-property-enum-value-added", OperationID: "op4", HideFromChangelog: true},
},
want: map[string]map[string][]*OasDiffEntry{
"response-write-only-property-enum-value-added": {
"op1": []*OasDiffEntry{
{ID: "response-write-only-property-enum-value-added", OperationID: "op1"},
},
"op3": []*OasDiffEntry{
{ID: "response-write-only-property-enum-value-added", OperationID: "op3"},
},
},
},
wantHidden: map[string]map[string][]*OasDiffEntry{
"response-write-only-property-enum-value-added": {
"op2": []*OasDiffEntry{
{ID: "response-write-only-property-enum-value-added", OperationID: "op2", HideFromChangelog: true},
},
"op4": []*OasDiffEntry{
{ID: "response-write-only-property-enum-value-added", OperationID: "op4", HideFromChangelog: true},
},
},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got := newEntriesMapPerIDAndOperationID(tc.entries)
got, gotHidden := newEntriesMapPerIDAndOperationID(tc.entries)
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("got %v, want %v", got, tc.want)
}
if !reflect.DeepEqual(gotHidden, tc.wantHidden) {
t.Errorf("gotHidden %v, wantHidden %v", gotHidden, tc.wantHidden)
}
})
}
}
Expand Down Expand Up @@ -238,3 +301,168 @@ func TestNewSquashMap(t *testing.T) {
})
}
}

func TestSquashEntries(t *testing.T) {
testCases := []struct {
name string
entries []*OasDiffEntry
want []*OasDiffEntry
}{
{
name: "Empty entries",
entries: []*OasDiffEntry{},
want: []*OasDiffEntry{},
},
{
name: "Single entry",
entries: []*OasDiffEntry{
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM1' enum value to the 'region' response write-only property",
},
},
want: []*OasDiffEntry{
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM1' enum value to the 'region' response write-only property",
},
},
},
{
name: "Multiple entries with same ID and OperationID",
entries: []*OasDiffEntry{
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM1' enum value to the 'region' response write-only property",
},
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM2' enum value to the 'region' response write-only property",
},
},
want: []*OasDiffEntry{
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM1, ENUM2' enum values to the 'region' response write-only property",
},
},
},
{
name: "Multiple entries with different IDs",
entries: []*OasDiffEntry{
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM1' enum value to the 'region' response write-only property",
},
{
ID: "request-write-only-property-enum-value-added",
OperationID: "op2",
Text: "added the new 'ENUM2' enum value to the 'region' request write-only property",
},
},
want: []*OasDiffEntry{
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM1' enum value to the 'region' response write-only property",
},
{
ID: "request-write-only-property-enum-value-added",
OperationID: "op2",
Text: "added the new 'ENUM2' enum value to the 'region' request write-only property",
},
},
},
{
name: "Hidden entries",
entries: []*OasDiffEntry{
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM1' enum value to the 'region' response write-only property",
HideFromChangelog: true,
},
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM2' enum value to the 'region' response write-only property",
HideFromChangelog: true,
},
},
want: []*OasDiffEntry{
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM1, ENUM2' enum values to the 'region' response write-only property",
HideFromChangelog: true,
},
},
},
{
name: "Mixed hidden and non-hidden entries",
entries: []*OasDiffEntry{
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM1' enum value to the 'region' response write-only property",
},
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM2' enum value to the 'region' response write-only property",
HideFromChangelog: true,
},
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM3' enum value to the 'region' response write-only property",
},
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM4' enum value to the 'region' response write-only property",
HideFromChangelog: true,
},
},
want: []*OasDiffEntry{
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM1, ENUM3' enum values to the 'region' response write-only property",
},
{
ID: "response-write-only-property-enum-value-added",
OperationID: "op1",
Text: "added the new 'ENUM2, ENUM4' enum values to the 'region' response write-only property",
HideFromChangelog: true,
},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got, err := squashEntries(tc.entries)
require.NoError(t, err)
sortEntries(got)
sortEntries(tc.want)
require.Equal(t, tc.want, got)
})
}
}

// sortEntries sorts the entries by their ID and OperationID.
func sortEntries(entries []*OasDiffEntry) {
sort.SliceStable(entries, func(i, j int) bool {
if entries[i].ID != entries[j].ID {
return entries[i].ID < entries[j].ID
}
return entries[i].OperationID < entries[j].OperationID
})
}
Loading