in cmd/krel/cmd/release_notes.go [1243:1401]
func editReleaseNote(pr int, workDir string, originalNote, modifiedNote *notes.ReleaseNote) (shouldRetryEditing bool, err error) {
// To edit the note, we will create a yaml file, with the changed fields
// active and we'll add the unaltered fields commented for the user to review
modifiedFields := ¬es.ReleaseNotesMap{PR: pr}
unalteredFields := ¬es.ReleaseNotesMap{PR: pr}
numChanges := 0
if originalNote.Text == modifiedNote.Text {
unalteredFields.ReleaseNote.Text = &originalNote.Text
} else {
modifiedFields.ReleaseNote.Text = &modifiedNote.Text
numChanges++
}
if originalNote.Author == modifiedNote.Author {
unalteredFields.ReleaseNote.Author = &originalNote.Author
} else {
modifiedFields.ReleaseNote.Author = &modifiedNote.Author
numChanges++
}
if fmt.Sprint(originalNote.SIGs) == fmt.Sprint(modifiedNote.SIGs) {
unalteredFields.ReleaseNote.SIGs = &originalNote.SIGs
} else {
modifiedFields.ReleaseNote.SIGs = &modifiedNote.SIGs
numChanges++
}
if fmt.Sprint(originalNote.Kinds) == fmt.Sprint(modifiedNote.Kinds) {
unalteredFields.ReleaseNote.Kinds = &originalNote.Kinds
} else {
modifiedFields.ReleaseNote.Kinds = &modifiedNote.Kinds
numChanges++
}
if fmt.Sprint(originalNote.Areas) == fmt.Sprint(modifiedNote.Areas) {
unalteredFields.ReleaseNote.Areas = &originalNote.Areas
} else {
modifiedFields.ReleaseNote.Areas = &modifiedNote.Areas
numChanges++
}
if fmt.Sprint(originalNote.Feature) == fmt.Sprint(modifiedNote.Feature) {
unalteredFields.ReleaseNote.Feature = &originalNote.Feature
} else {
modifiedFields.ReleaseNote.Feature = &modifiedNote.Feature
numChanges++
}
if fmt.Sprint(originalNote.ActionRequired) == fmt.Sprint(modifiedNote.ActionRequired) {
unalteredFields.ReleaseNote.ActionRequired = &originalNote.ActionRequired
} else {
modifiedFields.ReleaseNote.ActionRequired = &modifiedNote.ActionRequired
numChanges++
}
if fmt.Sprint(originalNote.DoNotPublish) == fmt.Sprint(modifiedNote.DoNotPublish) {
unalteredFields.ReleaseNote.DoNotPublish = &originalNote.DoNotPublish
} else {
modifiedFields.ReleaseNote.DoNotPublish = &modifiedNote.DoNotPublish
numChanges++
}
// TODO: Implement after writing a documentation comparison func
unalteredFields.ReleaseNote.Documentation = &originalNote.Documentation
// Create the release note map for the editor:
output := "---\n" + string(mapEditingInstructions) + "\n"
if numChanges == 0 {
// If there are no changes, present the user with the commented
// map with the original values
yamlCode, err := yaml.Marshal(&unalteredFields)
if err != nil {
return false, errors.Wrap(err, "marshalling release note to map")
}
output += "# " + strings.ReplaceAll(string(yamlCode), "\n", "\n# ")
} else {
// ... otherwise build a mixed map with the changes and the original
// values commented out for reference
yamlCode, err := yaml.Marshal(&modifiedFields)
if err != nil {
return false, errors.Wrap(err, "marshalling release note to map")
}
unalteredYAML, err := yaml.Marshal(&unalteredFields.ReleaseNote)
if err != nil {
return false, errors.Wrap(err, "marshalling release note to map")
}
output += string(yamlCode) + " # " + strings.ReplaceAll(string(unalteredYAML), "\n", "\n # ")
}
kubeEditor := editor.NewDefaultEditor([]string{"KUBE_EDITOR", "EDITOR"})
changes, tempFilePath, err := kubeEditor.LaunchTempFile("release-notes-map-", ".yaml", bytes.NewReader([]byte(output)))
if err != nil {
return false, errors.Wrap(err, "while launching editor")
}
defer func() {
// Cleanup the temporary map file
if err := os.Remove(tempFilePath); err != nil {
logrus.Warn("could not remove temporary mapfile")
}
}()
// If the map was not modified, we don't make any changes
if string(changes) == output || len(changes) == 0 {
logrus.Info("Release notes map was not modified")
return false, nil
}
// If the yaml file is blank, return non error
lines := strings.Split(string(changes), "\n")
re := regexp.MustCompile(`^\s*#|^\s*$`)
blankFile := true
for _, line := range lines {
// If only only one line is not blank/comment
if line != "---" && !re.MatchString(line) {
blankFile = false
break
}
}
if blankFile {
logrus.Info("YAML mapfile is blank, ignoring")
return false, nil
}
// Verify that the new yaml is valid and can be serialized back into a Map
testMap := notes.ReleaseNotesMap{}
err = yaml.Unmarshal(changes, &testMap)
if err != nil {
logrus.Error("The YAML code has errors")
return true, errors.Wrap(err, "while verifying if changes are a valid map")
}
if testMap.PR == 0 {
logrus.Error("The yaml code does not have a PR number")
return true, errors.New("Invalid map: the YAML code did not have a PR number")
}
// Remarshall the newyaml to save only the new values
newYAML, err := yaml.Marshal(testMap)
if err != nil {
return true, errors.Wrap(err, "while re-marshaling new map")
}
// Write the new map, removing the instructions
mapPath := filepath.Join(workDir, mapsMainDirectory, fmt.Sprintf("pr-%d-map.yaml", pr))
err = os.WriteFile(mapPath, newYAML, os.FileMode(0o644))
if err != nil {
logrus.Errorf("Error writing map to %s: %s", mapPath, err)
return true, errors.Wrap(err, "writing modified release note map")
}
return false, nil
}