diff --git a/ci/scripts/generate-release-notes/generate-release-notes.go b/ci/scripts/generate-release-notes/generate-release-notes.go index 235bbe6e..fd31bfda 100644 --- a/ci/scripts/generate-release-notes/generate-release-notes.go +++ b/ci/scripts/generate-release-notes/generate-release-notes.go @@ -183,15 +183,28 @@ func (c *command) createReleaseNoteLines(version semver.Version) ([]string, erro releaseTimeLine, ), } + + hasNotes := false for _, patchNotesPath := range c.PatchNotesPath { rawContents, err := ioutil.ReadFile(patchNotesPath) contents := strings.TrimSuffix(string(rawContents), "\n") if err != nil { return nil, fmt.Errorf("could not read patch notes path: %s, %w", patchNotesPath, err) } + if strings.TrimSpace(contents) != "" { + hasNotes = true + } lines = append(lines, strings.Split(contents, "\n")...) } + if !hasNotes { + return nil, fmt.Errorf( + "all patch notes files are empty (%s); populate them with release notes for v%s before generating release notes, otherwise a heading-only section would be committed and permanently skipped on future runs", + strings.Join(c.PatchNotesPath, ", "), + version.String(), + ) + } + lines = append(lines, "") return lines, nil } diff --git a/ci/scripts/generate-release-notes/generate_release_notes_test.go b/ci/scripts/generate-release-notes/generate_release_notes_test.go index 2a4fd346..5228aad5 100644 --- a/ci/scripts/generate-release-notes/generate_release_notes_test.go +++ b/ci/scripts/generate-release-notes/generate_release_notes_test.go @@ -111,6 +111,43 @@ var _ = Describe("GenerateReleaseNotes", func() { }) }) + When("the patch notes are empty", func() { + assertRefusesToGenerate := func(emptyPatchNotesPaths ...string) { + args := []string{"--docs-dir", repo.dir} + for _, path := range emptyPatchNotesPaths { + args = append(args, "--patch-notes-path", path) + } + args = append(args, "--patch-versions", "1.0.1") + + command := exec.Command(compiledPath, args...) + session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + Eventually(session).Should(gexec.Exit(1)) + Expect(session.Err).To(gbytes.Say("all patch notes files are empty")) + + By("not writing a heading-only section for the version") + notes, err := repo.readFileFrom("develop", "docs/release-notes.html.md.erb") + Expect(err).NotTo(HaveOccurred()) + Expect(notes).To(Equal(stableReleaseNotes)) + } + + It("errors instead of writing a heading-only section", func() { + emptyPatchNotesFile, err := ioutil.TempFile("", "") + Expect(err).NotTo(HaveOccurred()) + + assertRefusesToGenerate(emptyPatchNotesFile.Name()) + }) + + It("errors when both the cve and version-specific patch notes files are empty", func() { + emptyCveNotesFile, err := ioutil.TempFile("", "") + Expect(err).NotTo(HaveOccurred()) + emptyVersionNotesFile, err := ioutil.TempFile("", "") + Expect(err).NotTo(HaveOccurred()) + + assertRefusesToGenerate(emptyCveNotesFile.Name(), emptyVersionNotesFile.Name()) + }) + }) + It("adds the notes in the correct place based on semver", func() { patchNotesFile, err := ioutil.TempFile("", "") Expect(err).NotTo(HaveOccurred())