You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by ke...@apache.org on 2020/12/23 10:23:50 UTC
[skywalking-eyes] 01/01: Add new feature to review the pull request
and suggest adding license headers
This is an automated email from the ASF dual-hosted git repository.
kezhenxu94 pushed a commit to branch review
in repository https://gitbox.apache.org/repos/asf/skywalking-eyes.git
commit 801ff22c34de0d9bb56847bb94086dd51ef7df84
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Wed Dec 23 18:23:32 2020 +0800
Add new feature to review the pull request and suggest adding license headers
---
license-eye/commands/header/check.go | 4 +
license-eye/go.mod | 2 +
license-eye/go.sum | 11 +-
license-eye/pkg/header/fix.go | 4 +-
license-eye/pkg/header/fix_test.go | 4 +-
license-eye/pkg/review/header.go | 211 +++++++++++++++++++++++++++++++++++
6 files changed, 231 insertions(+), 5 deletions(-)
diff --git a/license-eye/commands/header/check.go b/license-eye/commands/header/check.go
index 0578286..6f9e76f 100644
--- a/license-eye/commands/header/check.go
+++ b/license-eye/commands/header/check.go
@@ -22,6 +22,7 @@ import (
"github.com/apache/skywalking-eyes/license-eye/pkg"
"github.com/apache/skywalking-eyes/license-eye/pkg/config"
"github.com/apache/skywalking-eyes/license-eye/pkg/header"
+ "github.com/apache/skywalking-eyes/license-eye/pkg/review"
"github.com/spf13/cobra"
)
@@ -50,6 +51,9 @@ var CheckCommand = &cobra.Command{
logger.Log.Infoln(result.String())
if result.HasFailure() {
+ if err := review.Header(&result, &config); err != nil {
+ logger.Log.Warnln("Failed to create review comments", err)
+ }
return result.Error()
}
diff --git a/license-eye/go.mod b/license-eye/go.mod
index bba41da..096d2fb 100644
--- a/license-eye/go.mod
+++ b/license-eye/go.mod
@@ -4,7 +4,9 @@ go 1.13
require (
github.com/bmatcuk/doublestar/v2 v2.0.4
+ github.com/google/go-github/v33 v33.0.0
github.com/sirupsen/logrus v1.7.0
github.com/spf13/cobra v1.1.1
+ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
)
diff --git a/license-eye/go.sum b/license-eye/go.sum
index 59737cb..b1a492f 100644
--- a/license-eye/go.sum
+++ b/license-eye/go.sum
@@ -16,7 +16,6 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/apache/skywalking-eyes v0.0.0-20201221094504-6a06cc7bcc31 h1:Bc/I5QMp74IjLbTGlfAGabjjlFRr0nTlF5F04/WaE/k=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
@@ -57,11 +56,17 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
+github.com/google/go-github/v33 v33.0.0 h1:qAf9yP0qc54ufQxzwv+u9H0tiVOnPJxo0lI/JXqw3ZM=
+github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg=
+github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -192,6 +197,7 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -224,9 +230,11 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -282,6 +290,7 @@ google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
diff --git a/license-eye/pkg/header/fix.go b/license-eye/pkg/header/fix.go
index 203de06..f5e061d 100644
--- a/license-eye/pkg/header/fix.go
+++ b/license-eye/pkg/header/fix.go
@@ -62,7 +62,7 @@ func InsertComment(file string, style *comments.CommentStyle, config *ConfigHead
return err
}
- licenseHeader, err := generateLicenseHeader(style, config)
+ licenseHeader, err := GenerateLicenseHeader(style, config)
if err != nil {
return err
}
@@ -94,7 +94,7 @@ func rewriteContent(style *comments.CommentStyle, content []byte, licenseHeader
)
}
-func generateLicenseHeader(style *comments.CommentStyle, config *ConfigHeader) (string, error) {
+func GenerateLicenseHeader(style *comments.CommentStyle, config *ConfigHeader) (string, error) {
if err := style.Validate(); err != nil {
return "", err
}
diff --git a/license-eye/pkg/header/fix_test.go b/license-eye/pkg/header/fix_test.go
index c6f307f..57da4c4 100644
--- a/license-eye/pkg/header/fix_test.go
+++ b/license-eye/pkg/header/fix_test.go
@@ -57,7 +57,7 @@ func TestFix(t *testing.T) {
for _, test := range tests {
t.Run(test.filename, func(t *testing.T) {
style := comments.FileCommentStyle(test.filename)
- if c, err := generateLicenseHeader(style, config); err != nil || c != test.comments {
+ if c, err := GenerateLicenseHeader(style, config); err != nil || c != test.comments {
t.Log("Actual:", c)
t.Log("Expected:", test.comments)
t.Logf("Middle:'%v'\n", style.Middle)
@@ -213,7 +213,7 @@ echo 'Hello' | echo 'world!'
}
func getLicenseHeader(filename string, tError func(args ...interface{})) string {
- s, err := generateLicenseHeader(comments.FileCommentStyle(filename), config)
+ s, err := GenerateLicenseHeader(comments.FileCommentStyle(filename), config)
if err != nil {
tError(err)
}
diff --git a/license-eye/pkg/review/header.go b/license-eye/pkg/review/header.go
new file mode 100644
index 0000000..9b47ac5
--- /dev/null
+++ b/license-eye/pkg/review/header.go
@@ -0,0 +1,211 @@
+package review
+
+import (
+ "context"
+ "encoding/base64"
+ "fmt"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/apache/skywalking-eyes/license-eye/internal/logger"
+ "github.com/apache/skywalking-eyes/license-eye/pkg"
+ comments2 "github.com/apache/skywalking-eyes/license-eye/pkg/comments"
+ config2 "github.com/apache/skywalking-eyes/license-eye/pkg/config"
+ header2 "github.com/apache/skywalking-eyes/license-eye/pkg/header"
+ "github.com/google/go-github/v33/github"
+ "golang.org/x/oauth2"
+)
+
+var (
+ Identification = "license-eye hidden identification"
+
+ gh *github.Client
+ ctx context.Context
+
+ owner string
+ repo string
+ sha string
+ pr int
+
+ requiredEnvVars = []string{
+ "GITHUB_SHA",
+ "GITHUB_TOKEN",
+ "GITHUB_HEAD_REF",
+ "GITHUB_REPOSITORY",
+ "GITHUB_EVENT_NAME",
+ }
+)
+
+func init() {
+ if !IsGHA() {
+ panic(fmt.Errorf(fmt.Sprintf(
+ `this must be run on GitHub Actions or you have to set the environment variables %v manually.`, requiredEnvVars,
+ )))
+ }
+
+ sha = os.Getenv("GITHUB_SHA")
+ token := os.Getenv("GITHUB_TOKEN")
+ ref := os.Getenv("GITHUB_HEAD_REF")
+ ownerRepo := strings.Split(os.Getenv("GITHUB_REPOSITORY"), "/")
+ owner, repo = ownerRepo[0], ownerRepo[1]
+ prString := regexp.MustCompile(`refs/pull/(\d+)/merge`).FindStringSubmatch(ref)[1]
+ if p, err := strconv.Atoi(prString); err == nil {
+ pr = p
+ } else {
+ logger.Log.Warnln("Failed to parse pull request number.", err)
+ return
+ }
+
+ ctx = context.Background()
+ ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
+ tc := oauth2.NewClient(ctx, ts)
+ gh = github.NewClient(tc)
+}
+
+// Header reviews the license header, including suggestions on the pull request and an overview of the checks.
+func Header(result *pkg.Result, config *config2.Config) error {
+ if !result.HasFailure() || !IsPR() || gh == nil {
+ return nil
+ }
+
+ commentedFiles := make(map[string]bool)
+ for _, comment := range GetAllReviewsComments() {
+ decodeString := comment.GetBody()
+ if strings.Contains(decodeString, Identification) {
+ logger.Log.Debugln("Path:", comment.GetPath())
+ commentedFiles[comment.GetPath()] = true
+ }
+ }
+ logger.Log.Debugln("CommentedFiles:", commentedFiles)
+
+ s := "RIGHT"
+ l := 1
+
+ var comments []*github.DraftReviewComment
+ for _, changedFile := range GetChangedFiles() {
+ logger.Log.Debugln("ChangedFile:", changedFile.GetFilename())
+ if commentedFiles[changedFile.GetFilename()] {
+ logger.Log.Debugln("ChangedFile was reviewed, skipping:", changedFile.GetFilename())
+ continue
+ }
+ for _, invalidFile := range result.Failure {
+ if !strings.HasSuffix(invalidFile, changedFile.GetFilename()) {
+ continue
+ }
+ blob, _, err := gh.Git.GetBlob(ctx, owner, repo, changedFile.GetSHA())
+ if err != nil {
+ logger.Log.Warnln("Failed to get blob:", changedFile.GetFilename(), changedFile.GetSHA())
+ continue
+ }
+ header, err := header2.GenerateLicenseHeader(comments2.FileCommentStyle(changedFile.GetFilename()), &config.Header)
+ if err != nil {
+ logger.Log.Warnln("Failed to generate comment header:", changedFile.GetFilename())
+ continue
+ }
+ decodeString, err := base64.StdEncoding.DecodeString(blob.GetContent())
+ if err != nil {
+ logger.Log.Debugln("Failed to decode blob content:", err)
+ continue
+ }
+ body := "```suggestion\n" + header + strings.Split(string(decodeString), "\n")[0] + "\n```\n" + fmt.Sprintf(`<!-- %v -->`, Identification)
+ comments = append(comments, &github.DraftReviewComment{
+ Path: changedFile.Filename,
+ Body: &body,
+ Side: &s,
+ Line: &l,
+ })
+ }
+ }
+
+ if len(comments) == 0 {
+ logger.Log.Debugln("Comments is empty, nothing to do")
+ return nil
+ }
+ logger.Log.Debugln("Comments:", comments)
+
+ c := Markdown(result)
+ e := "COMMENT"
+ if _, _, err := gh.PullRequests.CreateReview(ctx, owner, repo, pr, &github.PullRequestReviewRequest{
+ CommitID: &sha,
+ Body: &c,
+ Event: &e,
+ Comments: comments,
+ }); err != nil {
+ logger.Log.Warnln("Failed to create review comment:", err)
+ return nil
+ }
+
+ return nil
+}
+
+// GetChangedFiles returns the changed files in this pull request.
+func GetChangedFiles() []*github.CommitFile {
+ prsvc := gh.PullRequests
+ options := &github.ListOptions{Page: 1, PerPage: 100}
+
+ var allFiles []*github.CommitFile
+ for files, response, err := prsvc.ListFiles(ctx, owner, repo, pr, options); err == nil; {
+ allFiles = append(allFiles, files...)
+ if response.NextPage <= options.Page {
+ break
+ }
+ options = &github.ListOptions{Page: response.NextPage, PerPage: options.PerPage}
+ }
+ return allFiles
+}
+
+// GetAllReviewsComments returns all review comments of the pull request.
+func GetAllReviewsComments() []*github.PullRequestComment {
+ prsvc := gh.PullRequests
+ options := &github.PullRequestListCommentsOptions{ListOptions: github.ListOptions{Page: 1, PerPage: 100}}
+
+ var allComments []*github.PullRequestComment
+ for comments, response, err := prsvc.ListComments(ctx, owner, repo, pr, options); err == nil; {
+ allComments = append(allComments, comments...)
+ if response.NextPage <= options.Page {
+ break
+ }
+ options = &github.PullRequestListCommentsOptions{
+ ListOptions: github.ListOptions{Page: response.NextPage, PerPage: options.PerPage},
+ }
+ }
+ return allComments
+}
+
+func IsGHA() bool {
+ for _, key := range requiredEnvVars {
+ if val := os.Getenv(key); val == "" {
+ return false
+ }
+ }
+ return true
+}
+
+func IsPR() bool {
+ return os.Getenv("GITHUB_EVENT_NAME") == "pull_request"
+}
+
+func Markdown(result *pkg.Result) string {
+ return fmt.Sprintf(`
+<!-- %s -->
+[license-eye](https://github.com/apache/skywalking-eyes/tree/main/license-eye) has totally checked %d files.
+| Valid | Invalid | Ignored | Fixed |
+| --- | --- | --- | --- |
+| %d | %d | %d | %d |
+<details>
+ <summary>Click to see the invalid file list</summary>
+
+ %v
+</details>
+`,
+ Identification,
+ len(result.Success)+len(result.Failure)+len(result.Ignored),
+ len(result.Success),
+ len(result.Failure),
+ len(result.Ignored),
+ len(result.Fixed),
+ "- "+strings.Join(result.Failure, "\n- "),
+ )
+}