Matej Focko
36efeb2aab
- Refactor bits of code - Remove unused functions `PrintComments` - Introduce configuration file - Implement support for multiple languages Signed-off-by: Matej Focko <mfocko@redhat.com>
207 lines
5 KiB
Go
207 lines
5 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"code.gitea.io/sdk/gitea"
|
|
"github.com/bbrks/wrap/v2"
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
type Config struct {
|
|
Gitea struct {
|
|
InstanceURL string `yaml:"instance_url"`
|
|
Owner string `yaml:"owner"`
|
|
Repository string `yaml:"repository"`
|
|
} `yaml:"gitea"`
|
|
Language struct {
|
|
OpeningOnSeparateLine bool `yaml:"separate_opening"`
|
|
Opening string `yaml:"opening"`
|
|
Continuation string `yaml:"continuation"`
|
|
Closing string `yaml:"closing"`
|
|
} `yaml:"language"`
|
|
}
|
|
|
|
var config Config = Config{}
|
|
|
|
type ByLineNum []*gitea.PullReviewComment
|
|
|
|
func (a ByLineNum) Len() int { return len(a) }
|
|
func (a ByLineNum) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
func (a ByLineNum) Less(i, j int) bool { return a[i].LineNum < a[j].LineNum }
|
|
|
|
func ExitOnError(err error) {
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func RetrieveComments(client *gitea.Client, prID, reviewID int64) []*gitea.PullReviewComment {
|
|
comments, _, err := client.ListPullReviewComments(
|
|
config.Gitea.Owner, config.Gitea.Repository, prID, reviewID,
|
|
)
|
|
ExitOnError(err)
|
|
return comments
|
|
}
|
|
|
|
func SplitByFile(
|
|
splitComments map[string]([]*gitea.PullReviewComment),
|
|
comments []*gitea.PullReviewComment,
|
|
) map[string]([]*gitea.PullReviewComment) {
|
|
for _, comment := range comments {
|
|
arr, found := splitComments[comment.Path]
|
|
|
|
if !found {
|
|
arr = make([]*gitea.PullReviewComment, 0)
|
|
}
|
|
|
|
splitComments[comment.Path] = append(arr, comment)
|
|
}
|
|
|
|
return splitComments
|
|
}
|
|
|
|
func BackUpSource(filepath string) {
|
|
inputFile, err := os.Open(filepath)
|
|
ExitOnError(err)
|
|
defer inputFile.Close()
|
|
|
|
BackUpSourceFile, err := os.Create(filepath + ".bck")
|
|
ExitOnError(err)
|
|
defer BackUpSourceFile.Close()
|
|
|
|
_, err = io.Copy(BackUpSourceFile, inputFile)
|
|
ExitOnError(err)
|
|
}
|
|
|
|
func GetSeparatorForMultiline() string {
|
|
if config.Language.OpeningOnSeparateLine {
|
|
return "\n"
|
|
}
|
|
return " "
|
|
}
|
|
|
|
func FormatComment(body string, beenWrapped bool) string {
|
|
if beenWrapped && !config.Language.OpeningOnSeparateLine {
|
|
body = " " + strings.TrimPrefix(body, " "+config.Language.Continuation)
|
|
}
|
|
if !beenWrapped && !config.Language.OpeningOnSeparateLine && !strings.HasSuffix(body, "\n") {
|
|
body = body + "\n"
|
|
}
|
|
return fmt.Sprintf("%s%s%s", config.Language.Opening, body, config.Language.Closing)
|
|
}
|
|
|
|
func PatchFiles(wrapper *wrap.Wrapper, commentsByFile map[string]([]*gitea.PullReviewComment)) {
|
|
for filepath, comments := range commentsByFile {
|
|
fmt.Printf("FILE: %s\n", filepath)
|
|
|
|
BackUpSource(filepath)
|
|
|
|
inputFile, err := os.Open(filepath + ".bck")
|
|
ExitOnError(err)
|
|
defer inputFile.Close()
|
|
|
|
outputFile, err := os.Create(filepath)
|
|
ExitOnError(err)
|
|
defer outputFile.Close()
|
|
|
|
var i uint64 = 1
|
|
nextComment, commentsLength := 0, len(comments)
|
|
|
|
scanner := bufio.NewScanner(inputFile)
|
|
for scanner.Scan() {
|
|
for (nextComment < commentsLength) && comments[nextComment].LineNum == i {
|
|
body := comments[nextComment].Body
|
|
|
|
beenWrapped := len(body)+len(config.Language.Opening)+len(config.Language.Closing) > 100
|
|
if beenWrapped {
|
|
body = GetSeparatorForMultiline() + wrapper.Wrap(body, 100)
|
|
} else {
|
|
body = " " + body
|
|
}
|
|
|
|
body = strings.Replace(body, "\r", "", -1)
|
|
body = strings.Replace(
|
|
body,
|
|
config.Language.Continuation+"\n",
|
|
strings.TrimRightFunc(config.Language.Continuation, unicode.IsSpace)+"\n",
|
|
-1,
|
|
)
|
|
comment := FormatComment(body, beenWrapped)
|
|
|
|
fmt.Fprint(outputFile, comment)
|
|
fmt.Printf("L%04d:\n%s\n", comments[nextComment].LineNum, comment)
|
|
nextComment++
|
|
}
|
|
|
|
fmt.Fprintln(outputFile, scanner.Text())
|
|
i++
|
|
}
|
|
}
|
|
}
|
|
|
|
func GetReviewsPerPR(client *gitea.Client, prID int64) []int64 {
|
|
reviews, _, err := client.ListPullReviews(
|
|
config.Gitea.Owner, config.Gitea.Repository, prID, gitea.ListPullReviewsOptions{},
|
|
)
|
|
ExitOnError(err)
|
|
|
|
result := make([]int64, 0)
|
|
for _, review := range reviews {
|
|
result = append(result, review.ID)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func LoadConfig(filename string) {
|
|
if filename == "" {
|
|
filename = ".frag_review.yml"
|
|
}
|
|
|
|
configFile, err := os.Open(filename)
|
|
ExitOnError(err)
|
|
defer configFile.Close()
|
|
|
|
decoder := yaml.NewDecoder(configFile)
|
|
err = decoder.Decode(&config)
|
|
ExitOnError(err)
|
|
}
|
|
|
|
func main() {
|
|
token := os.Getenv("GITEA_TOKEN")
|
|
LoadConfig(os.Getenv("FRAG_REVIEW_CONFIG"))
|
|
|
|
client, err := gitea.NewClient(config.Gitea.InstanceURL, gitea.SetToken(token))
|
|
ExitOnError(err)
|
|
|
|
if len(os.Args) < 2 {
|
|
fmt.Fprintf(os.Stderr, "Usage: %s pr-id\n", os.Args[0])
|
|
os.Exit(1)
|
|
}
|
|
|
|
prID, err := strconv.ParseInt(os.Args[1], 10, 64)
|
|
ExitOnError(err)
|
|
|
|
reviews := GetReviewsPerPR(client, prID)
|
|
|
|
splitComments := make(map[string]([]*gitea.PullReviewComment))
|
|
for _, reviewID := range reviews {
|
|
comments := RetrieveComments(client, prID, reviewID)
|
|
sort.Sort(ByLineNum(comments))
|
|
splitComments = SplitByFile(splitComments, comments)
|
|
}
|
|
|
|
wrapper := wrap.NewWrapper()
|
|
wrapper.OutputLinePrefix = config.Language.Continuation
|
|
|
|
PatchFiles(&wrapper, splitComments)
|
|
}
|