119 lines
2.3 KiB
Go
119 lines
2.3 KiB
Go
package common
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"regexp"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const PrPattern = "PR: %s/%s#%d"
|
|
|
|
type BasicPR struct {
|
|
Org, Repo string
|
|
Num int64
|
|
}
|
|
|
|
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.ParseInt(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
|
|
}
|
|
|
|
func ExtractDescriptionAndPRs(data *bufio.Scanner) (string, []BasicPR) {
|
|
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"))
|
|
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
|
|
}
|
|
|
|
func AppendPRsToDescription(desc string, prs []BasicPR) string {
|
|
var out strings.Builder
|
|
|
|
out.WriteString(strings.TrimSpace(desc))
|
|
out.WriteString("\n")
|
|
|
|
slices.SortFunc(prs, compareBasicPRs)
|
|
prs = slices.Compact(prs)
|
|
|
|
for _, pr := range prs {
|
|
prToLine(&out, pr)
|
|
}
|
|
|
|
return out.String()
|
|
}
|