frag-review/main.go
Matej Focko 36efeb2aab
feat: Major rework
- Refactor bits of code
- Remove unused functions `PrintComments`
- Introduce configuration file
- Implement support for multiple languages

Signed-off-by: Matej Focko <mfocko@redhat.com>
2021-09-11 19:14:06 +02:00

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)
}