autogits/bots-common/associated_pr_scanner.go

119 lines
2.3 KiB
Go
Raw Normal View History

2024-12-05 18:38:35 +01:00
package common
import (
"bufio"
"errors"
"fmt"
"io"
"regexp"
2024-12-07 14:35:34 +01:00
"slices"
2024-12-05 18:38:35 +01:00
"strconv"
"strings"
)
const PrPattern = "PR: %s/%s#%d"
type BasicPR struct {
org, repo string
num uint64
}
var validOrgAndRepoRx *regexp.Regexp = regexp.MustCompile("^[A-Za-z0-9_-]+$")
func parsePrLine(line string) (BasicPR, error) {
var ret BasicPR
trimmedLine := strings.TrimSpace(line)
// min size > 9 -> must fit all parameters in th PrPattern with at least one item per parameter
if len(trimmedLine) < 9 || trimmedLine[0:4] != "PR: " {
return ret, errors.New("Line too short")
}
trimmedLine = trimmedLine[4:]
org := strings.SplitN(trimmedLine, "/", 2)
ret.org = org[0]
if len(org) != 2 {
return ret, errors.New("missing / separator")
}
repo := strings.SplitN(org[1], "#", 2)
ret.repo = repo[0]
if len(repo) != 2 {
return ret, errors.New("Missing # separator")
}
// Gitea requires that each org and repo be [A-Za-z0-9_-]+
var err error
if ret.num, err = strconv.ParseUint(repo[1], 10, 64); err != nil {
return ret, errors.New("Invalid number")
}
if !validOrgAndRepoRx.MatchString(repo[0]) || !validOrgAndRepoRx.MatchString(org[0]) {
return ret, errors.New("Invalid repo or org character set")
}
return ret, nil
}
2024-12-07 14:35:34 +01:00
func ExtractPRsFromDescription(data *bufio.Scanner) (string, []BasicPR) {
2024-12-05 18:38:35 +01:00
prs := make([]BasicPR, 0, 1)
var desc strings.Builder
for data.Scan() {
line := data.Text()
pr, err := parsePrLine(line)
if err != nil {
desc.WriteString(line)
desc.WriteByte('\n')
} else {
prs = append(prs, pr)
}
}
return strings.TrimSpace(desc.String()), prs
}
func prToLine(writer io.Writer, pr BasicPR) {
writer.Write([]byte("\n"))
2024-12-07 14:35:34 +01:00
fmt.Fprintf(writer, PrPattern, pr.org, pr.repo, pr.num)
}
// returns:
// <0 for a<b
// >0 for a>b
// =0 when equal
func compareBasicPRs(a BasicPR, b BasicPR) int {
if c := strings.Compare(a.org, b.org); c != 0 {
return c
}
if c := strings.Compare(a.repo, b.repo); c != 0 {
return c
}
if a.num > b.num {
return 1
}
if a.num < b.num {
return -1
}
return 0
2024-12-05 18:38:35 +01:00
}
func AppendPRsToDescription(desc string, prs []BasicPR) string {
var out strings.Builder
out.WriteString(strings.TrimSpace(desc))
2024-12-07 14:35:34 +01:00
out.WriteString("\n")
slices.SortFunc(prs, compareBasicPRs)
prs = slices.Compact(prs)
2024-12-05 18:38:35 +01:00
for _, pr := range prs {
prToLine(&out, pr)
}
return out.String()
}