From 25626f1f7593591096fb090a53a3234fd16aa23b Mon Sep 17 00:00:00 2001 From: Matej Focko Date: Tue, 7 Dec 2021 00:25:29 +0100 Subject: [PATCH 1/4] refactor: Improve error logging Signed-off-by: Matej Focko --- src/cmd/patch.go | 12 ++++++------ src/core/configuration.go | 4 ++-- src/core/gitea_comments.go | 5 +++-- src/core/utils.go | 9 +++++---- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/cmd/patch.go b/src/cmd/patch.go index c0ac1a2..50525df 100644 --- a/src/cmd/patch.go +++ b/src/cmd/patch.go @@ -25,10 +25,10 @@ var ( PreRun: InitializeConfig, Run: func(cmd *cobra.Command, args []string) { client, err := gitea.NewClient(config.Gitea.InstanceURL, gitea.SetToken(config.Gitea.Token)) - core.ExitOnError(err) + core.ExitOnError("Couldn't create gitea client", err) err = GetPrID(client, &prID) - core.ExitOnError(err) + core.ExitOnError("Couldn't get PR ID", err) comments := core.GetComments(&config, client, prID) core.ProcessComments(&config, &comments) @@ -54,7 +54,7 @@ func GetPrID(client *gitea.Client, prID *int64) error { gitCmd.Stdout = &capturedOutput err := gitCmd.Run() - core.ExitOnError(err) + core.ExitOnError("Couldn't list git branches", err) branch = strings.TrimSpace(capturedOutput.String()) } @@ -62,7 +62,7 @@ func GetPrID(client *gitea.Client, prID *int64) error { prs, _, err := client.ListRepoPullRequests( config.Gitea.Owner, config.Gitea.Repository, gitea.ListPullRequestsOptions{}, ) - core.ExitOnError(err) + core.ExitOnError("Couldn't list pull requests", err) for _, pr := range prs { if pr.Head.Name == branch { @@ -94,11 +94,11 @@ func ProcessFile(filepath string, comments []*gitea.PullReviewComment) { core.BackUpSource(filepath) inputFile, err := os.Open(filepath + ".bck") - core.ExitOnError(err) + core.ExitOnError("Couldn't open backup file", err) defer inputFile.Close() outputFile, err := os.Create(filepath) - core.ExitOnError(err) + core.ExitOnError("Couldn't overwrite original file", err) defer outputFile.Close() var i uint64 = 1 diff --git a/src/core/configuration.go b/src/core/configuration.go index 0e0f0ab..384477e 100644 --- a/src/core/configuration.go +++ b/src/core/configuration.go @@ -23,10 +23,10 @@ type Config struct { func LoadConfig(config *Config, filename string) { configFile, err := os.Open(filename) - ExitOnError(err) + ExitOnError("Couldn't open config file", err) defer configFile.Close() decoder := yaml.NewDecoder(configFile) err = decoder.Decode(&config) - ExitOnError(err) + ExitOnError("Couldn't decode config file", err) } diff --git a/src/core/gitea_comments.go b/src/core/gitea_comments.go index 2ecfe25..d03e16e 100644 --- a/src/core/gitea_comments.go +++ b/src/core/gitea_comments.go @@ -2,6 +2,7 @@ package core import ( "sort" + "fmt" "code.gitea.io/sdk/gitea" ) @@ -10,7 +11,7 @@ func GetReviewsPerPR(config *Config, client *gitea.Client, prID int64) []int64 { reviews, _, err := client.ListPullReviews( config.Gitea.Owner, config.Gitea.Repository, prID, gitea.ListPullReviewsOptions{}, ) - ExitOnError(err) + ExitOnError("Couldn't list reviews per PR ID", err) result := make([]int64, 0) for _, review := range reviews { @@ -24,7 +25,7 @@ func RetrieveComments(config *Config, client *gitea.Client, prID, reviewID int64 comments, _, err := client.ListPullReviewComments( config.Gitea.Owner, config.Gitea.Repository, prID, reviewID, ) - ExitOnError(err) + ExitOnError("Couldn't list review comments for review", err) return comments } diff --git a/src/core/utils.go b/src/core/utils.go index 5127516..fc59faa 100644 --- a/src/core/utils.go +++ b/src/core/utils.go @@ -14,8 +14,9 @@ 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) { +func ExitOnError(msg string, err error) { if err != nil { + fmt.Fprintf(os.Stderr, "%s: ", msg) fmt.Fprintln(os.Stderr, err) os.Exit(1) } @@ -23,13 +24,13 @@ func ExitOnError(err error) { func BackUpSource(filepath string) { inputFile, err := os.Open(filepath) - ExitOnError(err) + ExitOnError("Couldn't open input file for backup", err) defer inputFile.Close() BackUpSourceFile, err := os.Create(filepath + ".bck") - ExitOnError(err) + ExitOnError("Couldn't create backup file", err) defer BackUpSourceFile.Close() _, err = io.Copy(BackUpSourceFile, inputFile) - ExitOnError(err) + ExitOnError("Couldn't copy into backup file", err) } From c9ec7c865c022e3cd2b841e3764411ceceb6a2cf Mon Sep 17 00:00:00 2001 From: Matej Focko Date: Tue, 7 Dec 2021 00:26:04 +0100 Subject: [PATCH 2/4] feat: Implement opening of PRs per milestone Fixes #5 Signed-off-by: Matej Focko --- src/cmd/open.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ src/cmd/root.go | 1 + 2 files changed, 59 insertions(+) create mode 100644 src/cmd/open.go diff --git a/src/cmd/open.go b/src/cmd/open.go new file mode 100644 index 0000000..01ac752 --- /dev/null +++ b/src/cmd/open.go @@ -0,0 +1,58 @@ +package cmd + +import ( + "fmt" + "strings" + + "code.gitea.io/sdk/gitea" + "github.com/spf13/cobra" + + "git.mfocko.xyz/mfocko/frag-review/core" +) + +var ( + openMilestone string + + openCmd = &cobra.Command{ + Use: "open", + Short: "Opens pull requests for review.", + PreRun: InitializeConfig, + Run: func(cmd *cobra.Command, args []string) { + client, err := gitea.NewClient(config.Gitea.InstanceURL, gitea.SetToken(config.Gitea.Token)) + core.ExitOnError("Couldn't create gitea client", err) + + milestone, _, err := client.GetMilestoneByName(config.Gitea.Owner, config.Gitea.Repository, openMilestone) + core.ExitOnError("Couldn't find the milestone", err) + + fmt.Printf("Milestone found %s (deadline %s)\n", milestone.Title, milestone.Deadline) + + branches, _, err := client.ListRepoBranches(config.Gitea.Owner, config.Gitea.Repository, gitea.ListRepoBranchesOptions{}) + core.ExitOnError("Couldn't list all the branches", err) + + ProcessBranches(client, milestone, branches) + }, + } +) + +func init() { + openCmd.Flags().StringVarP(&openMilestone, "milestone", "m", "", "specifies milestone, i.e. the task") +} + +func ProcessBranches(client *gitea.Client, milestone *gitea.Milestone, branches []*gitea.Branch) { + for _, branch := range branches { + if !strings.HasPrefix(branch.Name, milestone.Title) { + continue + } + + fmt.Printf("- Processing %s\n", branch.Name) + pr, _, err := client.CreatePullRequest(config.Gitea.Owner, config.Gitea.Repository, gitea.CreatePullRequestOption{ + Head: branch.Name, + Base: "main", + Title: branch.Name, + Milestone: milestone.ID, + }) + core.ExitOnError("Couldn't create PR", err) + + fmt.Printf("Created PR #%s\n", pr.ID) + } +} \ No newline at end of file diff --git a/src/cmd/root.go b/src/cmd/root.go index 182e8ba..acdb13d 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -32,4 +32,5 @@ func Execute() error { func init() { rootCmd.PersistentFlags().StringVarP(&configFilepath, "conf", "c", ".frag_review.yml", "path to the config file") rootCmd.AddCommand(patchCmd) + rootCmd.AddCommand(openCmd) } From df2660698d93988c08d6f8a0995a033ce20463fc Mon Sep 17 00:00:00 2001 From: Matej Focko Date: Sat, 11 Dec 2021 16:43:21 +0100 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20Remove=20unused=20=E2=80=B9fmt?= =?UTF-8?q?=E2=80=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matej Focko --- src/core/gitea_comments.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/gitea_comments.go b/src/core/gitea_comments.go index d03e16e..eba4fcf 100644 --- a/src/core/gitea_comments.go +++ b/src/core/gitea_comments.go @@ -2,7 +2,6 @@ package core import ( "sort" - "fmt" "code.gitea.io/sdk/gitea" ) From a24d7bdc0c5f5bf2f32b4770f6bb9223a9e19d35 Mon Sep 17 00:00:00 2001 From: Matej Focko Date: Sat, 11 Dec 2021 16:43:49 +0100 Subject: [PATCH 4/4] feat: Implement statistics Fixes #8 Signed-off-by: Matej Focko --- src/cmd/root.go | 1 + src/cmd/stats.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ src/go.mod | 2 +- src/go.sum | 4 +++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/cmd/stats.go diff --git a/src/cmd/root.go b/src/cmd/root.go index acdb13d..ff8e062 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -33,4 +33,5 @@ func init() { rootCmd.PersistentFlags().StringVarP(&configFilepath, "conf", "c", ".frag_review.yml", "path to the config file") rootCmd.AddCommand(patchCmd) rootCmd.AddCommand(openCmd) + rootCmd.AddCommand(statsCmd) } diff --git a/src/cmd/stats.go b/src/cmd/stats.go new file mode 100644 index 0000000..f1eb918 --- /dev/null +++ b/src/cmd/stats.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "fmt" + "strings" + + "code.gitea.io/sdk/gitea" + "github.com/spf13/cobra" + + "git.mfocko.xyz/mfocko/frag-review/core" +) + +var ( + statsMilestone string + + statsCmd = &cobra.Command{ + Use: "stats", + Short: "Shows stats from already graded reviews.", + PreRun: InitializeConfig, + Run: func(cmd *cobra.Command, args []string) { + client, err := gitea.NewClient(config.Gitea.InstanceURL, gitea.SetToken(config.Gitea.Token)) + core.ExitOnError("Couldn't create gitea client", err) + + milestone, _, err := client.GetMilestoneByName(config.Gitea.Owner, config.Gitea.Repository, statsMilestone) + core.ExitOnError("Couldn't find the milestone", err) + + fmt.Printf("Milestone found %s (deadline %s)\n", milestone.Title, milestone.Deadline) + + prs, _, err := client.ListRepoPullRequests(config.Gitea.Owner, config.Gitea.Repository, gitea.ListPullRequestsOptions{ + Milestone: milestone.ID, + }) + core.ExitOnError("Couldn't list the pull requests", err) + + GetStats(client, milestone, prs) + }, + } +) + +func init() { + statsCmd.Flags().StringVarP(&statsMilestone, "milestone", "m", "", "specifies milestone, i.e. the task") +} + +func GetStats(client *gitea.Client, milestone *gitea.Milestone, prs []*gitea.PullRequest) { + graded := 0 + histogram := make(map[string]int) + + for _, pr := range prs { + for _, label := range pr.Labels { + if strings.HasPrefix(label.Name, "grade:") { + grade := strings.Split(label.Name, ":")[1] + + histogram[grade] += 1 + graded += 1 + + break + } + } + } + + for grade, count := range histogram { + if (count == 0) { + continue + } + + fmt.Printf("%s: %d\n", grade, count) + } + + if (len(prs) - graded > 0) { + fmt.Printf("ungraded: %d\n", len(prs) - graded) + } +} \ No newline at end of file diff --git a/src/go.mod b/src/go.mod index 4b80341..93099cc 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,7 +3,7 @@ module git.mfocko.xyz/mfocko/frag-review go 1.16 require ( - code.gitea.io/sdk/gitea v0.14.0 // indirect + code.gitea.io/sdk/gitea v0.15.0 // indirect github.com/bbrks/wrap/v2 v2.5.0 // indirect github.com/spf13/cobra v1.2.1 gopkg.in/yaml.v2 v2.4.0 diff --git a/src/go.sum b/src/go.sum index e7991ef..a2b0cf6 100644 --- a/src/go.sum +++ b/src/go.sum @@ -36,8 +36,11 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= code.gitea.io/sdk/gitea v0.14.0 h1:m4J352I3p9+bmJUfS+g0odeQzBY/5OXP91Gv6D4fnJ0= code.gitea.io/sdk/gitea v0.14.0/go.mod h1:89WiyOX1KEcvjP66sRHdu0RafojGo60bT9UqW17VbWs= +code.gitea.io/sdk/gitea v0.15.0 h1:tsNhxDM/2N1Ohv1Xq5UWrht/esg0WmtRj4wsHVHriTg= +code.gitea.io/sdk/gitea v0.15.0/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -427,6 +430,7 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=