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:41:51 UTC

[skywalking-eyes] branch review updated (6898f78 -> f0e2da4)

This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a change to branch review
in repository https://gitbox.apache.org/repos/asf/skywalking-eyes.git.


 discard 6898f78  Add new feature to review the pull request and suggest adding license headers
     new f0e2da4  Add new feature to review the pull request and suggest adding license headers

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (6898f78)
            \
             N -- N -- N   refs/heads/review (f0e2da4)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 license-eye/pkg/review/header.go | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)


[skywalking-eyes] 01/01: Add new feature to review the pull request and suggest adding license headers

Posted by ke...@apache.org.
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 f0e2da4f20bd7f5718e1199b1ed34388634395b4
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     | 213 +++++++++++++++++++++++++++++++++++
 6 files changed, 233 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..de11639
--- /dev/null
+++ b/license-eye/pkg/review/header.go
@@ -0,0 +1,213 @@
+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")
+	fullName := os.Getenv("GITHUB_REPOSITORY")
+	logger.Log.Debugln("ref:", ref, "; repo:", fullName)
+	ownerRepo := strings.Split(fullName, "/")
+	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- "),
+	)
+}