Skip to content

Commit 5aa0587

Browse files
committed
Merge branch 'fix-smart-flow'
2 parents cfae990 + b7ab5b1 commit 5aa0587

File tree

2 files changed

+123
-5
lines changed

2 files changed

+123
-5
lines changed

command/smart_flow.go

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,58 @@ func processSmartFlowVersion(q flowQuerier, files ForceMetadataFiles) (ForceMeta
142142
delete(files, oldMeta)
143143
}
144144
}
145-
// If any inactive versions, generate destructiveChangesPost.xml
145+
// If any inactive versions, generate or merge destructiveChangesPost.xml
146146
if len(dest.Members) > 0 {
147147
// sort members for consistency
148148
sort.Strings(dest.Members)
149-
pkg := DestructivePackage{
150-
Xmlns: "http://soap.sforce.com/2006/04/metadata",
151-
Types: []DestructiveType{dest},
152-
Version: strings.TrimPrefix(ApiVersion(), "v"),
149+
150+
var pkg DestructivePackage
151+
152+
// Check if destructiveChangesPost.xml already exists
153+
if existing, ok := files["destructiveChangesPost.xml"]; ok {
154+
// Parse existing destructiveChangesPost.xml
155+
if err := xml.Unmarshal(existing, &pkg); err != nil {
156+
return files, fmt.Errorf("parse existing destructiveChangesPost.xml: %w", err)
157+
}
158+
159+
// Find existing Flow type or create new one
160+
flowTypeFound := false
161+
for i, t := range pkg.Types {
162+
if t.Name == "Flow" {
163+
// Merge with existing Flow members, avoiding duplicates
164+
memberSet := make(map[string]struct{})
165+
for _, m := range t.Members {
166+
memberSet[m] = struct{}{}
167+
}
168+
for _, m := range dest.Members {
169+
memberSet[m] = struct{}{}
170+
}
171+
172+
// Convert back to slice and sort
173+
var mergedMembers []string
174+
for m := range memberSet {
175+
mergedMembers = append(mergedMembers, m)
176+
}
177+
sort.Strings(mergedMembers)
178+
pkg.Types[i].Members = mergedMembers
179+
flowTypeFound = true
180+
break
181+
}
182+
}
183+
184+
// If no Flow type found, add it
185+
if !flowTypeFound {
186+
pkg.Types = append(pkg.Types, dest)
187+
}
188+
} else {
189+
// Create new destructiveChangesPost.xml
190+
pkg = DestructivePackage{
191+
Xmlns: "http://soap.sforce.com/2006/04/metadata",
192+
Types: []DestructiveType{dest},
193+
Version: strings.TrimPrefix(ApiVersion(), "v"),
194+
}
153195
}
196+
154197
out, err := xml.MarshalIndent(pkg, "", " ")
155198
if err != nil {
156199
return files, fmt.Errorf("marshal destructiveChangesPost: %w", err)

command/smart_flow_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,78 @@ func TestProcessSmartFlowVersion_InactiveAndActive(t *testing.T) {
172172
t.Errorf("destructiveChangesPost missing MyFlow-2, got %s", string(dc))
173173
}
174174
}
175+
176+
// Test that existing destructiveChangesPost.xml is merged with flow deletions
177+
func TestProcessSmartFlowVersion_MergeExistingDestructive(t *testing.T) {
178+
name := "MyFlow"
179+
fq := &fakeQuerier{results: map[string]lib.ForceQueryResult{
180+
name: {Records: []lib.ForceRecord{
181+
{"VersionNumber": float64(2), "Status": "Inactive"},
182+
{"VersionNumber": float64(3), "Status": "Active"},
183+
}},
184+
}}
185+
186+
// Existing destructiveChangesPost.xml with some other metadata
187+
existingDC := []byte(`<?xml version="1.0" encoding="UTF-8"?>
188+
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
189+
<types>
190+
<members>TestClass</members>
191+
<name>ApexClass</name>
192+
</types>
193+
<version>61.0</version>
194+
</Package>`)
195+
196+
files := lib.ForceMetadataFiles{
197+
"flows/MyFlow.flow": []byte("<flow></flow>"),
198+
"flows/MyFlow.flow-meta.xml": []byte("<fullName>MyFlow</fullName>"),
199+
"destructiveChangesPost.xml": existingDC,
200+
}
201+
202+
out, err := processSmartFlowVersion(fq, files)
203+
if err != nil {
204+
t.Fatalf("unexpected error: %v", err)
205+
}
206+
207+
// Check that destructiveChangesPost.xml contains both ApexClass and Flow types
208+
dc, ok := out["destructiveChangesPost.xml"]
209+
if !ok {
210+
t.Fatalf("missing destructiveChangesPost.xml")
211+
}
212+
213+
var pkg struct {
214+
Types []struct {
215+
Members []string `xml:"members"`
216+
Name string `xml:"name"`
217+
} `xml:"types"`
218+
}
219+
if err := xml.Unmarshal(dc, &pkg); err != nil {
220+
t.Fatalf("unmarshal dc xml: %v", err)
221+
}
222+
223+
foundApexClass := false
224+
foundFlow := false
225+
226+
for _, typ := range pkg.Types {
227+
if typ.Name == "ApexClass" {
228+
for _, m := range typ.Members {
229+
if m == "TestClass" {
230+
foundApexClass = true
231+
}
232+
}
233+
}
234+
if typ.Name == "Flow" {
235+
for _, m := range typ.Members {
236+
if m == "MyFlow-2" {
237+
foundFlow = true
238+
}
239+
}
240+
}
241+
}
242+
243+
if !foundApexClass {
244+
t.Errorf("existing ApexClass member missing from merged destructiveChangesPost.xml")
245+
}
246+
if !foundFlow {
247+
t.Errorf("new Flow member missing from merged destructiveChangesPost.xml")
248+
}
249+
}

0 commit comments

Comments
 (0)