Skip to content

Commit eca332b

Browse files
RossTarrantCopilot
andcommitted
Stabilize issue field merge order
Preserve deterministic issue field ordering when merging existing and incoming issue field values so update requests are stable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2e2d0db commit eca332b

2 files changed

Lines changed: 39 additions & 6 deletions

File tree

pkg/github/issues.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -461,15 +461,27 @@ func fetchExistingIssueFieldValues(ctx context.Context, gqlClient *githubv4.Clie
461461
// mergeIssueFieldValues returns a merged slice where incoming values override existing ones
462462
// for the same field ID, and existing fields not present in incoming are preserved.
463463
func mergeIssueFieldValues(existing, incoming []*github.IssueRequestFieldValue) []*github.IssueRequestFieldValue {
464-
merged := make(map[int64]*github.IssueRequestFieldValue, len(existing)+len(incoming))
464+
indexByFieldID := make(map[int64]int, len(existing)+len(incoming))
465+
result := make([]*github.IssueRequestFieldValue, 0, len(existing)+len(incoming))
465466
for _, v := range existing {
466-
merged[v.FieldID] = v
467+
if v == nil {
468+
continue
469+
}
470+
if _, ok := indexByFieldID[v.FieldID]; ok {
471+
continue
472+
}
473+
indexByFieldID[v.FieldID] = len(result)
474+
result = append(result, v)
467475
}
468476
for _, v := range incoming {
469-
merged[v.FieldID] = v
470-
}
471-
result := make([]*github.IssueRequestFieldValue, 0, len(merged))
472-
for _, v := range merged {
477+
if v == nil {
478+
continue
479+
}
480+
if index, ok := indexByFieldID[v.FieldID]; ok {
481+
result[index] = v
482+
continue
483+
}
484+
indexByFieldID[v.FieldID] = len(result)
473485
result = append(result, v)
474486
}
475487
return result

pkg/github/issues_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3182,6 +3182,27 @@ func Test_UpdateIssue(t *testing.T) {
31823182
}
31833183
}
31843184

3185+
func TestMergeIssueFieldValuesPreservesOrder(t *testing.T) {
3186+
existing := []*github.IssueRequestFieldValue{
3187+
{FieldID: 101, Value: "old priority"},
3188+
{FieldID: 102, Value: "Acme"},
3189+
}
3190+
incoming := []*github.IssueRequestFieldValue{
3191+
{FieldID: 101, Value: "P1"},
3192+
{FieldID: 103, Value: float64(7)},
3193+
}
3194+
3195+
merged := mergeIssueFieldValues(existing, incoming)
3196+
3197+
require.Len(t, merged, 3)
3198+
assert.Equal(t, int64(101), merged[0].FieldID)
3199+
assert.Equal(t, "P1", merged[0].Value)
3200+
assert.Equal(t, int64(102), merged[1].FieldID)
3201+
assert.Equal(t, "Acme", merged[1].Value)
3202+
assert.Equal(t, int64(103), merged[2].FieldID)
3203+
assert.Equal(t, float64(7), merged[2].Value)
3204+
}
3205+
31853206
func Test_ParseISOTimestamp(t *testing.T) {
31863207
tests := []struct {
31873208
name string

0 commit comments

Comments
 (0)