-
Notifications
You must be signed in to change notification settings - Fork 496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hierarchical release note feature functions #435
Changes from 3 commits
d020597
3f67cdb
3b596e6
a05dc4c
4c4eb7d
313b952
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/google/go-github/github" | ||
) | ||
|
||
type dictSIG map[string]dictArea | ||
type dictArea map[string]dictIssue | ||
type dictIssue map[int]dictPR | ||
type dictPR map[int]bool | ||
|
||
func hierarchicalNoteLayout(f *os.File, dict dictSIG, issueMap map[int]*github.Issue) { | ||
for sig, areas := range dict { | ||
f.WriteString(fmt.Sprintf(" - %s\n\n", strings.Title(sig))) | ||
for area, issues := range areas { | ||
f.WriteString(fmt.Sprintf(" - %s\n\n", strings.Title(area))) | ||
for issue, prs := range issues { | ||
if issue >= 0 { | ||
f.WriteString(fmt.Sprintf(" - %s (#%d)\n", *issueMap[issue].Title, issue)) | ||
} else { | ||
f.WriteString(fmt.Sprintf(" - NullIssue\n")) | ||
} | ||
for pr := range prs { | ||
f.WriteString(fmt.Sprintf(" * %s (#%d, @%s)\n", extractReleaseNote(issueMap[pr]), pr, *issueMap[pr].User.Login)) | ||
} | ||
f.WriteString("\n") | ||
} | ||
} | ||
} | ||
} | ||
|
||
// createHierarchicalNote given release PRs and issue map, creates hierarchical release note | ||
// map[SIG]map[Area]map[Issue]PR. | ||
func createHierarchicalNote(prs []int, issueMap map[int]*github.Issue) dictSIG { | ||
var dict = dictSIG{} | ||
|
||
for _, pr := range prs { | ||
issues := extractFixedIssues(*issueMap[pr].Body) | ||
if len(issues) == 0 { | ||
// In our design doc, the automation should enforce every release-note PR | ||
// with at least one issue. However it's observed that the rule is not | ||
// applied yet. Also old PRs may not link to an issue. | ||
// | ||
// To produce info-richer release note, we try to get SIG and Area label | ||
// from PRs which don't link to any issue. | ||
issues = append(issues, pr) | ||
} | ||
for _, i := range issues { | ||
sigs := extractIssueSIGs(issueMap[i]) | ||
area := extractIssueArea(issueMap[i]) | ||
// For PRs that don't link to any issue, restore the nullIssue information | ||
if issueMap[i].PullRequestLinks != nil { | ||
i = -1 | ||
} | ||
if len(sigs) == 0 { | ||
setNoteDict(dict, "nullSig", area, i, pr) | ||
continue | ||
} | ||
for _, s := range sigs { | ||
setNoteDict(dict, s, area, i, pr) | ||
} | ||
} | ||
} | ||
|
||
return dict | ||
} | ||
|
||
// setNoteDict sets the entry dict[sig][area][issue][pr] to be true, initializes nil maps along | ||
// the way. | ||
func setNoteDict(dict dictSIG, sig, area string, issue, pr int) { | ||
if dict[sig] == nil { | ||
dict[sig] = dictArea{} | ||
} | ||
if dict[sig][area] == nil { | ||
dict[sig][area] = dictIssue{} | ||
} | ||
if dict[sig][area][issue] == nil { | ||
dict[sig][area][issue] = dictPR{} | ||
} | ||
dict[sig][area][issue][pr] = true | ||
} | ||
|
||
// extractFixedIssues parses the fixed issues' id from PR body. | ||
func extractFixedIssues(msg string) []int { | ||
var issues = make([]int, 0) | ||
re, _ := regexp.Compile("fixes #([0-9]+)") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note that github not only supports There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and it can also fixes issue in other repo, e.g., |
||
matches := re.FindAllStringSubmatch(strings.ToLower(msg), -1) | ||
for _, match := range matches { | ||
id, _ := strconv.Atoi(match[1]) | ||
issues = append(issues, id) | ||
} | ||
|
||
return issues | ||
} | ||
|
||
// extractIssueSIGs gets the SIGs of the input issue (if there is any) | ||
func extractIssueSIGs(i *github.Issue) []string { | ||
var sigs = make([]string, 0) | ||
for _, l := range i.Labels { | ||
if strings.HasPrefix(*l.Name, "sig/") { | ||
sigs = append(sigs, (*l.Name)[4:]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not using TrimPrefix here? |
||
} | ||
} | ||
|
||
return sigs | ||
} | ||
|
||
// extractIssueSIGs gets the Areas of the input issue and returns as a single string. If the issue | ||
// doesn't have any Area label, the function returns "nullArea". | ||
func extractIssueArea(i *github.Issue) string { | ||
var areas = make([]string, 0) | ||
for _, l := range i.Labels { | ||
if strings.HasPrefix(*l.Name, "area/") { | ||
areas = append(areas, (*l.Name)[5:]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does github api guarantee anything about the order of the labels returned? I am wondering because if two issues have labels "area/Alpha" and "area/Beta" and the labels can be in any order, then they might be put into different area buckets in the final document, even though they have the same areas There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jennybuckley I think it guarantees alphabetical order. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also |
||
} | ||
} | ||
|
||
if len(areas) == 0 { | ||
return "nullArea" | ||
} | ||
|
||
return strings.Join(areas, " & ") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, most of PRs don't have either sig or area label. I once felt a bit painful when I wanted to filter PRs by sig. I was thinking we enforce sig labels on PRs as we already do on issues. Then we may get more info here. @enisoc @Bradamant3 WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enforcing sig label on PR will also be helpful for #348.