cmd/relnote: avoid TODOs for issues in existing relnotes
Don't write a TODO for an issue that is mentioned in the release
notes.
For golang/go#64169.
Change-Id: I9829957cb07c997a1d763fc00a996aeb2a53ba17
Reviewed-on: https://go-review.googlesource.com/c/build/+/584398
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/cmd/relnote/todo.go b/cmd/relnote/todo.go
index dc5ba52..bf34651 100644
--- a/cmd/relnote/todo.go
+++ b/cmd/relnote/todo.go
@@ -31,29 +31,31 @@
// It takes the doc/next directory of the repo and the date of the last release.
func todo(w io.Writer, fsys fs.FS, prevRelDate time.Time) error {
var todos []ToDo
+ addToDo := func(td ToDo) { todos = append(todos, td) }
- add := func(td ToDo) { todos = append(todos, td) }
+ mentionedIssues := map[int]bool{} // issues mentioned in the existing relnotes
+ addIssue := func(num int) { mentionedIssues[num] = true }
- if err := todosFromDocFiles(fsys, add); err != nil {
+ if err := infoFromDocFiles(fsys, addToDo, addIssue); err != nil {
return err
}
if !prevRelDate.IsZero() {
- if err := todosFromCLs(prevRelDate, add); err != nil {
+ if err := todosFromCLs(prevRelDate, mentionedIssues, addToDo); err != nil {
return err
}
}
return writeToDos(w, todos)
}
-// Collect TODOs from the markdown files in the main repo.
-func todosFromDocFiles(fsys fs.FS, add func(ToDo)) error {
+// Collect TODOs and issue numbers from the markdown files in the main repo.
+func infoFromDocFiles(fsys fs.FS, addToDo func(ToDo), addIssue func(int)) error {
// This is essentially a grep.
return fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() && strings.HasSuffix(path, ".md") {
- if err := todosFromFile(fsys, path, add); err != nil {
+ if err := infoFromFile(fsys, path, addToDo, addIssue); err != nil {
return err
}
}
@@ -61,7 +63,9 @@
})
}
-func todosFromFile(dir fs.FS, filename string, add func(ToDo)) error {
+var issueRE = regexp.MustCompile("/issue/([0-9]+)")
+
+func infoFromFile(dir fs.FS, filename string, addToDo func(ToDo), addIssue func(int)) error {
f, err := dir.Open(filename)
if err != nil {
return err
@@ -71,17 +75,25 @@
ln := 0
for scan.Scan() {
ln++
- if line := scan.Text(); strings.Contains(line, "TODO") {
- add(ToDo{
+ line := scan.Text()
+ if strings.Contains(line, "TODO") {
+ addToDo(ToDo{
message: line,
provenance: fmt.Sprintf("%s:%d", filename, ln),
})
}
+ for _, matches := range issueRE.FindAllStringSubmatch(line, -1) {
+ num, err := strconv.Atoi(matches[1])
+ if err != nil {
+ return fmt.Errorf("%s:%d: %v", filename, ln, err)
+ }
+ addIssue(num)
+ }
}
return scan.Err()
}
-func todosFromCLs(cutoff time.Time, add func(ToDo)) error {
+func todosFromCLs(cutoff time.Time, mentionedIssues map[int]bool, add func(ToDo)) error {
ctx := context.Background()
// The maintner corpus doesn't track inline comments. See go.dev/issue/24863.
// So we need to use a Gerrit API client to fetch them instead. If maintner starts
@@ -120,7 +132,7 @@
}
}
// Add a TODO if the CL refers to an accepted proposal.
- todoFromProposal(ctx, cl, gh, add)
+ todoFromProposal(cl, gh, mentionedIssues, add)
return nil
})
})
@@ -143,11 +155,12 @@
return nil
}
-func todoFromProposal(ctx context.Context, cl *maintner.GerritCL, gh *maintner.GitHubRepo, add func(ToDo)) {
+func todoFromProposal(cl *maintner.GerritCL, gh *maintner.GitHubRepo, mentionedIssues map[int]bool, add func(ToDo)) {
for _, num := range issueNumbers(cl) {
- // TODO(jba): look for CL references in existing release notes to avoid adding TODOs for
- // CLs that have already been documented.
- if issue := gh.Issue(num); issue != nil && hasLabel(issue, "Proposal-Accepted") {
+ if mentionedIssues[num] {
+ continue
+ }
+ if issue := gh.Issue(int32(num)); issue != nil && hasLabel(issue, "Proposal-Accepted") {
// Add a TODO for all issues, regardless of when or whether they are closed.
// Any work on an accepted proposal is potentially worthy of a release note.
add(ToDo{
@@ -223,7 +236,7 @@
var golangGoNumbersRE = regexp.MustCompile(`(?m)golang/go#([0-9]{3,})`)
// issueNumbers returns the golang/go issue numbers referred to by the CL.
-func issueNumbers(cl *maintner.GerritCL) []int32 {
+func issueNumbers(cl *maintner.GerritCL) []int {
var re *regexp.Regexp
if cl.Project.Project() == "go" {
re = numbersRE
@@ -231,10 +244,10 @@
re = golangGoNumbersRE
}
- var list []int32
+ var list []int
for _, s := range re.FindAllStringSubmatch(cl.Commit.Msg, -1) {
if n, err := strconv.Atoi(s[1]); err == nil && n < 1e9 {
- list = append(list, int32(n))
+ list = append(list, n)
}
}
// Remove duplicates.