fix(copilot): implement official transactional hook contract

This commit is contained in:
ZacharyZhang-NY committed 2026-07-20 12:58:30 -04:00
1 parent 050d0043ea
commit 827374e7f8
16 files changed
+2243 -510

No files matched your search

+23 -1
View File
@@ -100,7 +100,12 @@ func prepareSourceChange(
}, nil
}
func writeChanges(changes []*fileChange, label string, rename renameFunc) error {
func writeChanges(
changes []*fileChange,
label string,
rename renameFunc,
preconditions ...filePrecondition,
) error {
filtered := make([]fileChange, 0, len(changes))
targets := map[string]bool{}
for _, change := range changes {
@@ -117,6 +122,9 @@ func writeChanges(changes []*fileChange, label string, rename renameFunc) error
targets[target] = true
filtered = append(filtered, *change)
}
if err := assertFilePreconditions(preconditions, label); err != nil {
return fmt.Errorf("%s: %w", label, err)
}
if len(filtered) == 0 {
return nil
}
@@ -132,13 +140,27 @@ func writeChanges(changes []*fileChange, label string, rename renameFunc) error
}
staged = append(staged, item)
}
if err := assertFilePreconditions(preconditions, label); err != nil {
cleanupErrors := cleanupStaging(staged)
return joinTransactionFailure(fmt.Errorf("%s: %w", label, err), cleanupErrors, "cleanup failed")
}
for index := range staged {
if err := assertFilePreconditions(preconditions, label); err != nil {
recoveryErrors := rollbackChanges(staged, rename)
recoveryErrors = append(recoveryErrors, cleanupStaging(staged)...)
return joinTransactionFailure(fmt.Errorf("%s: %w", label, err), recoveryErrors, "recovery failed")
}
if err := commitChange(&staged[index], rename); err != nil {
recoveryErrors := rollbackChanges(staged, rename)
recoveryErrors = append(recoveryErrors, cleanupStaging(staged)...)
return joinTransactionFailure(fmt.Errorf("%s: %w", label, err), recoveryErrors, "recovery failed")
}
}
if err := assertFilePreconditions(preconditions, label); err != nil {
recoveryErrors := rollbackChanges(staged, rename)
recoveryErrors = append(recoveryErrors, cleanupStaging(staged)...)
return joinTransactionFailure(fmt.Errorf("%s: %w", label, err), recoveryErrors, "recovery failed")
}
cleanupErrors := cleanupStaging(staged)
if len(cleanupErrors) > 0 {
return joinTransactionFailure(fmt.Errorf("%s cleanup failed", label), cleanupErrors, "cleanup failed")