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/27 04:54:36 UTC

[skywalking-eyes] branch deps created (now 5f30d70)

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

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


      at 5f30d70  Polish the report output, deps 1.0 is finished

This branch includes the following new commits:

     new 8132280  Resolve dependencies' license files
     new 2bbe2c8  Resolve Apache-2.0, BSD-3-Clause, and MIT licenses
     new 5f30d70  Polish the report output, deps 1.0 is finished

The 3 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.



[skywalking-eyes] 02/03: Resolve Apache-2.0, BSD-3-Clause, and MIT licenses

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 2bbe2c875bd19249e994e470b059548aa77a2db9
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Sun Dec 27 11:37:26 2020 +0800

    Resolve Apache-2.0, BSD-3-Clause, and MIT licenses
---
 .licenserc.yaml                                    |   1 +
 license-eye/README.adoc                            |   2 +-
 .../Apache-2.0-ASF.txt                             |   0
 .../Apache-2.0.txt                                 |   0
 license-eye/assets/lcs-templates/Apache-2.0.txt    | 181 +++++++++++++++++++--
 license-eye/assets/lcs-templates/BSD-3-Clause.txt  |  27 +++
 license-eye/assets/lcs-templates/MIT.txt           |  19 +++
 license-eye/commands/deps_resolve.go               |   3 +-
 license-eye/go.sum                                 |   1 +
 license-eye/pkg/deps/golang.go                     |  11 +-
 license-eye/pkg/deps/result.go                     |   2 +-
 license-eye/pkg/header/config.go                   |   4 +-
 license-eye/pkg/license/identifier.go              |  35 ++++
 license-eye/pkg/license/norm.go                    |  39 +++++
 14 files changed, 306 insertions(+), 19 deletions(-)

diff --git a/.licenserc.yaml b/.licenserc.yaml
index 0e5aab6..db09875 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -69,6 +69,7 @@ header: # `header` section is configurations for source codes license header.
     - '**/go.sum'
     - 'LICENSE'
     - 'NOTICE'
+    - '**/assets/header-templates/**'
     - '**/assets/lcs-templates/**'
     - '**/assets/languages.yaml'
     - '**/assets/assets.gen.go'
diff --git a/license-eye/README.adoc b/license-eye/README.adoc
index d22ade3..9118635 100644
--- a/license-eye/README.adoc
+++ b/license-eye/README.adoc
@@ -195,7 +195,7 @@ include::assets/styles.yaml[tags=SlashAsterisk]
 == Contribution
 
 - If you find any file type should be supported by the aforementioned configurations but is not listed there, feel free to link:https://github.com/apache/skywalking-eyes/pulls[open a pull request] to add the configuration into the 2 files.
-- If you find the license template of an SPDX ID is not supported, feel free to link:https://github.com/apache/skywalking-eyes/pulls[open a pull request] to add it into link:assets/lcs-templates[the template folder].
+- If you find the license template of an SPDX ID is not supported, feel free to link:https://github.com/apache/skywalking-eyes/pulls[open a pull request] to add it into link:assets/header-templates[the template folder].
 
 == License
 
diff --git a/license-eye/assets/lcs-templates/Apache-2.0-ASF.txt b/license-eye/assets/header-templates/Apache-2.0-ASF.txt
similarity index 100%
rename from license-eye/assets/lcs-templates/Apache-2.0-ASF.txt
rename to license-eye/assets/header-templates/Apache-2.0-ASF.txt
diff --git a/license-eye/assets/lcs-templates/Apache-2.0.txt b/license-eye/assets/header-templates/Apache-2.0.txt
similarity index 100%
copy from license-eye/assets/lcs-templates/Apache-2.0.txt
copy to license-eye/assets/header-templates/Apache-2.0.txt
diff --git a/license-eye/assets/lcs-templates/Apache-2.0.txt b/license-eye/assets/lcs-templates/Apache-2.0.txt
index 83cfa23..dd5b3a5 100644
--- a/license-eye/assets/lcs-templates/Apache-2.0.txt
+++ b/license-eye/assets/lcs-templates/Apache-2.0.txt
@@ -1,13 +1,174 @@
-Copyright [year] [owner]
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
 
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
-http://www.apache.org/licenses/LICENSE-2.0
+   1. Definitions.
 
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
diff --git a/license-eye/assets/lcs-templates/BSD-3-Clause.txt b/license-eye/assets/lcs-templates/BSD-3-Clause.txt
new file mode 100644
index 0000000..3d387bc
--- /dev/null
+++ b/license-eye/assets/lcs-templates/BSD-3-Clause.txt
@@ -0,0 +1,27 @@
+Copyright (c) [year] [owner]. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of the copyright holder nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/license-eye/assets/lcs-templates/MIT.txt b/license-eye/assets/lcs-templates/MIT.txt
new file mode 100644
index 0000000..a45b07f
--- /dev/null
+++ b/license-eye/assets/lcs-templates/MIT.txt
@@ -0,0 +1,19 @@
+Copyright (c) [year] [owner]
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next paragraph)
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/license-eye/commands/deps_resolve.go b/license-eye/commands/deps_resolve.go
index 96ca6ca..f4d492f 100644
--- a/license-eye/commands/deps_resolve.go
+++ b/license-eye/commands/deps_resolve.go
@@ -35,8 +35,7 @@ var ResolveCommand = &cobra.Command{
 		}
 
 		for _, result := range report.Resolved {
-			logger.Log.Debugln("Resolved:", result.Dependency)
-			logger.Log.Debugln("License:", result.LicenseFilePath)
+			logger.Log.Debugln("Pkg: ", result.Dependency, " License:", result.LicenseSpdxID)
 		}
 
 		logger.Log.Debugln("Skipped:", len(report.Skipped))
diff --git a/license-eye/go.sum b/license-eye/go.sum
index 3143ee6..2da1b0f 100644
--- a/license-eye/go.sum
+++ b/license-eye/go.sum
@@ -290,6 +290,7 @@ golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=
+golang.org/x/tools v0.0.0-20201226215659-b1c90890d22a h1:pdfjQ7VswBeGam3EpuEJ4e8EAb7JgaubV570LO/SIQM=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/license-eye/pkg/deps/golang.go b/license-eye/pkg/deps/golang.go
index cea090f..99f4fe2 100644
--- a/license-eye/pkg/deps/golang.go
+++ b/license-eye/pkg/deps/golang.go
@@ -24,6 +24,7 @@ import (
 	"regexp"
 
 	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
+	"github.com/apache/skywalking-eyes/license-eye/pkg/license"
 	"golang.org/x/mod/modfile"
 	"golang.org/x/tools/go/packages"
 )
@@ -79,7 +80,7 @@ func (resolver *GoModeResolver) ResolvePackages(pkgNames []string, report *Repor
 	packages.Visit(requiredPkgs, func(p *packages.Package) bool {
 		err := resolver.ResolvePackageLicense(p, report)
 		if err != nil {
-			logger.Log.Warnln("Failed to resolve the license of dependency:", p.Name, err)
+			logger.Log.Warnln("Failed to resolve the license of dependency:", p.PkgPath, err)
 		}
 		return true
 	}, nil)
@@ -123,11 +124,15 @@ func (resolver *GoModeResolver) ResolvePackageLicense(p *packages.Package, repor
 			if err != nil {
 				return err
 			}
+			identifier, err := license.Identify(string(content))
+			if err != nil {
+				return err
+			}
 			report.Resolve(&Result{
 				Dependency:      p.PkgPath,
-				LicenseContent:  string(content),
 				LicenseFilePath: licenseFilePath,
-				LicenseSpdxID:   "", // TODO: identify the SPDX ID
+				LicenseContent:  string(content),
+				LicenseSpdxID:   []string{identifier},
 			})
 			return nil
 		}
diff --git a/license-eye/pkg/deps/result.go b/license-eye/pkg/deps/result.go
index bfea534..abf8669 100644
--- a/license-eye/pkg/deps/result.go
+++ b/license-eye/pkg/deps/result.go
@@ -28,7 +28,7 @@ type Result struct {
 	Dependency      string
 	LicenseFilePath string
 	LicenseContent  string
-	LicenseSpdxID   string
+	LicenseSpdxID   []string
 }
 
 // Report is a collection of resolved Result.
diff --git a/license-eye/pkg/header/config.go b/license-eye/pkg/header/config.go
index df2d630..219a388 100644
--- a/license-eye/pkg/header/config.go
+++ b/license-eye/pkg/header/config.go
@@ -137,12 +137,12 @@ func (config *ConfigHeader) GetLicenseContent() string {
 
 func readLicenseFromSpdx(config *ConfigHeader) (string, error) {
 	spdxID, owner := config.License.SpdxID, config.License.CopyrightOwner
-	filename := fmt.Sprintf("assets/lcs-templates/%v.txt", spdxID)
+	filename := fmt.Sprintf("assets/header-templates/%v.txt", spdxID)
 
 	if spdxID == "Apache-2.0" && ASFNames.MatchString(owner) {
 		// Note that the Apache Software Foundation uses a different source header that is related to our use of a CLA.
 		// Our instructions for our project's source headers are here (https://www.apache.org/legal/src-headers.html#headers).
-		filename = "assets/lcs-templates/Apache-2.0-ASF.txt"
+		filename = "assets/header-templates/Apache-2.0-ASF.txt"
 	}
 
 	content, err := assets.Asset(filename)
diff --git a/license-eye/pkg/license/identifier.go b/license-eye/pkg/license/identifier.go
new file mode 100644
index 0000000..9751607
--- /dev/null
+++ b/license-eye/pkg/license/identifier.go
@@ -0,0 +1,35 @@
+package license
+
+import (
+	"fmt"
+	"path/filepath"
+	"strings"
+
+	"github.com/apache/skywalking-eyes/license-eye/assets"
+)
+
+const templatesDir = "assets/lcs-templates"
+
+// Identify identifies the Spdx ID of the given license content
+func Identify(content string) (string, error) {
+	content = Normalize(content)
+
+	templates, err := assets.AssetDir(templatesDir)
+	if err != nil {
+		return "", err
+	}
+
+	for _, template := range templates {
+		t, err := assets.Asset(filepath.Join(templatesDir, template))
+		if err != nil {
+			return "", err
+		}
+		license := string(t)
+		license = Normalize(license)
+		if license == content {
+			return strings.TrimSuffix(template, filepath.Ext(template)), nil
+		}
+	}
+
+	return "", fmt.Errorf("cannot identify license content")
+}
diff --git a/license-eye/pkg/license/norm.go b/license-eye/pkg/license/norm.go
index 6cd5612..1e723f3 100644
--- a/license-eye/pkg/license/norm.go
+++ b/license-eye/pkg/license/norm.go
@@ -30,9 +30,11 @@ var (
 	// meanings, according to the matching guide in https://spdx.dev/license-list/matching-guidelines.
 	// The order matters.
 	normalizers = []Normalizer{
+		VariablesNormalizer,
 		OneLineNormalizer,
 		FlattenSpaceNormalizer,
 		SubstantiveTextsNormalizer,
+		FlattenSpaceNormalizer,
 		strings.ToLower,
 		strings.TrimSpace,
 	}
@@ -116,6 +118,34 @@ var (
 
 		{regexp.MustCompile(`(?i)\b(the )?Apache Software Foundation( \(ASF\))?`), "the ASF"},
 	}
+
+	variables = []struct {
+		regexp      *regexp.Regexp
+		replacement string
+	}{
+		// BSD-3-Clause
+		{
+			regexp.MustCompile(`(?im)(^(Copyright \(c\)) (\d{4}) (.+?) (All rights reserved\.)?$\n?)+`),
+			"$2 [year] [owner]. $5",
+		},
+		{
+			regexp.MustCompile(`(?i)(neither the name of) (.+?) (nor the names of)`),
+			"$1 the copyright holder $3",
+		},
+		// MIT
+		{ // remove optional header
+			regexp.MustCompile(`(?im)^The MIT License \(MIT\)$`),
+			"",
+		},
+		{
+			regexp.MustCompile(`(?im)^(Copyright \(c\)) (\d{4}) (.+?)$`),
+			"$1 [year] [owner]",
+		},
+		{
+			regexp.MustCompile(`(?im)\(including the next paragraph\)`),
+			"",
+		},
+	}
 )
 
 // NormalizePattern applies a chain of Normalizers to the license pattern to make it cleaner for identification.
@@ -169,3 +199,12 @@ func CommentIndicatorNormalizer(text string) string {
 func FlattenSpaceNormalizer(text string) string {
 	return flattenSpace.ReplaceAllString(text, " ")
 }
+
+// VariablesNormalizer replace the variables actual value into variable name.
+func VariablesNormalizer(text string) string {
+	for _, v := range variables {
+		text = v.regexp.ReplaceAllString(text, v.replacement)
+	}
+
+	return text
+}


[skywalking-eyes] 01/03: Resolve dependencies' license files

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 813228043565b242bebda8ecc6ec8a35b54f1a0d
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Sat Dec 26 22:57:45 2020 +0800

    Resolve dependencies' license files
---
 .github/workflows/license-eye-check.yaml           |   2 -
 .licenserc.yaml                                    |   4 +
 license-eye/commands/{header/header.go => deps.go} |  23 ++--
 .../config/config.go => commands/deps_resolve.go}  |  42 +++---
 license-eye/commands/{header => }/header.go        |   8 +-
 .../commands/{header/check.go => header_check.go}  |  17 +--
 .../commands/{header/fix.go => header_fix.go}      |  15 +--
 license-eye/commands/root.go                       |  25 ++--
 license-eye/go.mod                                 |   2 +
 license-eye/go.sum                                 |  11 ++
 license-eye/pkg/config/config.go                   |   6 +
 license-eye/pkg/{config => deps}/config.go         |  29 ++--
 license-eye/pkg/deps/golang.go                     | 149 +++++++++++++++++++++
 .../header/header.go => pkg/deps/resolve.go}       |  40 +++---
 .../pkg/{config/config.go => deps/result.go}       |  46 +++----
 license-eye/pkg/header/check.go                    |   9 +-
 license-eye/pkg/header/check_test.go               |   9 +-
 license-eye/pkg/header/fix.go                      |   7 +-
 license-eye/pkg/{ => header}/result.go             |   2 +-
 license-eye/pkg/review/header.go                   |  11 +-
 20 files changed, 301 insertions(+), 156 deletions(-)

diff --git a/.github/workflows/license-eye-check.yaml b/.github/workflows/license-eye-check.yaml
index 869db6d..2bcfd23 100644
--- a/.github/workflows/license-eye-check.yaml
+++ b/.github/workflows/license-eye-check.yaml
@@ -44,8 +44,6 @@ jobs:
 
       - name: License Check
         run: make license
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 
       - name: Test
         run: make test
diff --git a/.licenserc.yaml b/.licenserc.yaml
index 5b6a539..0e5aab6 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -74,3 +74,7 @@ header: # `header` section is configurations for source codes license header.
     - '**/assets/assets.gen.go'
 
   comment: on-failure # on what condition license-eye will comment on the pull request, `on-failure`, `always`, `never`.
+
+dependency:
+  files:
+    - license-eye/go.mod
diff --git a/license-eye/commands/header/header.go b/license-eye/commands/deps.go
similarity index 61%
copy from license-eye/commands/header/header.go
copy to license-eye/commands/deps.go
index 8786217..87aadfd 100644
--- a/license-eye/commands/header/header.go
+++ b/license-eye/commands/deps.go
@@ -1,3 +1,4 @@
+//
 // Licensed to Apache Software Foundation (ASF) under one or more contributor
 // license agreements. See the NOTICE file distributed with
 // this work for additional information regarding copyright
@@ -14,27 +15,19 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-//
-package header
+package commands
 
 import (
 	"github.com/spf13/cobra"
 )
 
-var (
-	// cfgFile is the config path to the config file of header command.
-	cfgFile string
-)
-
-var Header = &cobra.Command{
-	Use:     "header",
-	Aliases: []string{"h"},
-	Short:   "License header related commands; e.g. check, fix, etc.",
-	Long:    "`header` command walks the specified paths recursively and checks if the specified files have the license header in the config file.",
+var Deps = &cobra.Command{
+	Use:     "deps",
+	Aliases: []string{"d"},
+	Short:   "Dependencies related commands; e.g. check, etc.",
+	Long:    "deps command checks all dependencies of a module and their transitive dependencies.",
 }
 
 func init() {
-	Header.PersistentFlags().StringVarP(&cfgFile, "config", "c", ".licenserc.yaml", "the config file")
-	Header.AddCommand(CheckCommand)
-	Header.AddCommand(FixCommand)
+	Deps.AddCommand(ResolveCommand)
 }
diff --git a/license-eye/pkg/config/config.go b/license-eye/commands/deps_resolve.go
similarity index 57%
copy from license-eye/pkg/config/config.go
copy to license-eye/commands/deps_resolve.go
index 3b7c417..96ca6ca 100644
--- a/license-eye/pkg/config/config.go
+++ b/license-eye/commands/deps_resolve.go
@@ -1,3 +1,4 @@
+//
 // Licensed to Apache Software Foundation (ASF) under one or more contributor
 // license agreements. See the NOTICE file distributed with
 // this work for additional information regarding copyright
@@ -14,35 +15,32 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-//
-package config
+package commands
 
 import (
-	"io/ioutil"
-
 	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
-	"github.com/apache/skywalking-eyes/license-eye/pkg/header"
-
-	"gopkg.in/yaml.v3"
+	"github.com/apache/skywalking-eyes/license-eye/pkg/deps"
+	"github.com/spf13/cobra"
 )
 
-type Config struct {
-	Header header.ConfigHeader `yaml:"header"`
-}
+var ResolveCommand = &cobra.Command{
+	Use:     "resolve",
+	Aliases: []string{"r"},
+	Long:    "resolves all dependencies of a go.mod file and their transitive dependencies",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		report := deps.Report{}
 
-// Parse reads and parses the header check configurations in config file.
-func (config *Config) Parse(file string) error {
-	logger.Log.Infoln("Loading configuration from file:", file)
+		if err := deps.Resolve(&Config.Deps, &report); err != nil {
+			return err
+		}
 
-	if bytes, err := ioutil.ReadFile(file); err != nil {
-		return err
-	} else if err := yaml.Unmarshal(bytes, config); err != nil {
-		return err
-	}
+		for _, result := range report.Resolved {
+			logger.Log.Debugln("Resolved:", result.Dependency)
+			logger.Log.Debugln("License:", result.LicenseFilePath)
+		}
 
-	if err := config.Header.Finalize(); err != nil {
-		return err
-	}
+		logger.Log.Debugln("Skipped:", len(report.Skipped))
 
-	return nil
+		return nil
+	},
 }
diff --git a/license-eye/commands/header/header.go b/license-eye/commands/header.go
similarity index 85%
copy from license-eye/commands/header/header.go
copy to license-eye/commands/header.go
index 8786217..aec10de 100644
--- a/license-eye/commands/header/header.go
+++ b/license-eye/commands/header.go
@@ -15,17 +15,12 @@
 // specific language governing permissions and limitations
 // under the License.
 //
-package header
+package commands
 
 import (
 	"github.com/spf13/cobra"
 )
 
-var (
-	// cfgFile is the config path to the config file of header command.
-	cfgFile string
-)
-
 var Header = &cobra.Command{
 	Use:     "header",
 	Aliases: []string{"h"},
@@ -34,7 +29,6 @@ var Header = &cobra.Command{
 }
 
 func init() {
-	Header.PersistentFlags().StringVarP(&cfgFile, "config", "c", ".licenserc.yaml", "the config file")
 	Header.AddCommand(CheckCommand)
 	Header.AddCommand(FixCommand)
 }
diff --git a/license-eye/commands/header/check.go b/license-eye/commands/header_check.go
similarity index 80%
rename from license-eye/commands/header/check.go
rename to license-eye/commands/header_check.go
index 6f9e76f..e721eb1 100644
--- a/license-eye/commands/header/check.go
+++ b/license-eye/commands/header_check.go
@@ -15,12 +15,10 @@
 // specific language governing permissions and limitations
 // under the License.
 //
-package header
+package commands
 
 import (
 	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
-	"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"
 
@@ -32,26 +30,21 @@ var CheckCommand = &cobra.Command{
 	Aliases: []string{"c"},
 	Long:    "check command walks the specified paths recursively and checks if the specified files have the license header in the config file.",
 	RunE: func(cmd *cobra.Command, args []string) error {
-		var config config.Config
-		var result pkg.Result
-
-		if err := config.Parse(cfgFile); err != nil {
-			return err
-		}
+		var result header.Result
 
 		if len(args) > 0 {
 			logger.Log.Debugln("Overriding paths with command line args.")
-			config.Header.Paths = args
+			Config.Header.Paths = args
 		}
 
-		if err := header.Check(&config.Header, &result); err != nil {
+		if err := header.Check(&Config.Header, &result); err != nil {
 			return err
 		}
 
 		logger.Log.Infoln(result.String())
 
 		if result.HasFailure() {
-			if err := review.Header(&result, &config); err != nil {
+			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/commands/header/fix.go b/license-eye/commands/header_fix.go
similarity index 80%
rename from license-eye/commands/header/fix.go
rename to license-eye/commands/header_fix.go
index 4fbba48..4f1e50f 100644
--- a/license-eye/commands/header/fix.go
+++ b/license-eye/commands/header_fix.go
@@ -16,15 +16,13 @@
 // specific language governing permissions and limitations
 // under the License.
 //
-package header
+package commands
 
 import (
 	"fmt"
 	"strings"
 
 	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
-	"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/spf13/cobra"
 )
@@ -34,20 +32,15 @@ var FixCommand = &cobra.Command{
 	Aliases: []string{"f"},
 	Long:    "fix command walks the specified paths recursively and fix the license header if the specified files don't have the license header.",
 	RunE: func(cmd *cobra.Command, args []string) error {
-		var config config.Config
-		var result pkg.Result
+		var result header.Result
 
-		if err := config.Parse(cfgFile); err != nil {
-			return err
-		}
-
-		if err := header.Check(&config.Header, &result); err != nil {
+		if err := header.Check(&Config.Header, &result); err != nil {
 			return err
 		}
 
 		var errors []string
 		for _, file := range result.Failure {
-			if err := header.Fix(file, &config.Header, &result); err != nil {
+			if err := header.Fix(file, &Config.Header, &result); err != nil {
 				errors = append(errors, err.Error())
 			}
 		}
diff --git a/license-eye/commands/root.go b/license-eye/commands/root.go
index ab16bf8..fbe6b01 100644
--- a/license-eye/commands/root.go
+++ b/license-eye/commands/root.go
@@ -18,19 +18,21 @@
 package commands
 
 import (
-	headercommand "github.com/apache/skywalking-eyes/license-eye/commands/header"
 	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
+	"github.com/apache/skywalking-eyes/license-eye/pkg/config"
 
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 )
 
 var (
-	verbosity string
+	verbosity  string
+	configFile string
+	Config     config.Config
 )
 
-// Root represents the base command when called without any subcommands
-var Root = &cobra.Command{
+// root represents the base command when called without any subcommands
+var root = &cobra.Command{
 	Use:           "license-eye command [flags]",
 	Long:          "A full-featured license guard to check and fix license headers and dependencies' licenses",
 	SilenceUsage:  true,
@@ -41,17 +43,24 @@ var Root = &cobra.Command{
 			return err
 		}
 		logger.Log.SetLevel(level)
+
+		if err := Config.Parse(configFile); err != nil {
+			return err
+		}
+
 		return nil
 	},
 	Version: version,
 }
 
 // Execute sets flags to the root command appropriately.
-// This is called by main.main(). It only needs to happen once to the Root.
+// This is called by main.main(). It only needs to happen once to the root.
 func Execute() error {
-	Root.PersistentFlags().StringVarP(&verbosity, "verbosity", "v", logrus.InfoLevel.String(), "log level (debug, info, warn, error, fatal, panic")
+	root.PersistentFlags().StringVarP(&verbosity, "verbosity", "v", logrus.InfoLevel.String(), "log level (debug, info, warn, error, fatal, panic")
+	root.PersistentFlags().StringVarP(&configFile, "config", "c", ".licenserc.yaml", "the config file")
 
-	Root.AddCommand(headercommand.Header)
+	root.AddCommand(Header)
+	root.AddCommand(Deps)
 
-	return Root.Execute()
+	return root.Execute()
 }
diff --git a/license-eye/go.mod b/license-eye/go.mod
index 096d2fb..c66062d 100644
--- a/license-eye/go.mod
+++ b/license-eye/go.mod
@@ -7,6 +7,8 @@ require (
 	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/mod v0.4.0
 	golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
+	golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
 	gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
 )
diff --git a/license-eye/go.sum b/license-eye/go.sum
index b1a492f..3143ee6 100644
--- a/license-eye/go.sum
+++ b/license-eye/go.sum
@@ -16,6 +16,7 @@ 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-20201226021955-d798d4f56aa5 h1:cMn7kz937Lz92NBpMXbawQlizM4qe3LYMil+DWQxznE=
 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=
@@ -199,6 +200,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
 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/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/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=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -216,7 +219,10 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0 h1:sfUMP1Gu8qASkorDVjnMuvgJzwFbTZSeXFiGBYAVdl4=
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -281,7 +287,12 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8=
 golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
diff --git a/license-eye/pkg/config/config.go b/license-eye/pkg/config/config.go
index 3b7c417..6db18be 100644
--- a/license-eye/pkg/config/config.go
+++ b/license-eye/pkg/config/config.go
@@ -21,6 +21,7 @@ import (
 	"io/ioutil"
 
 	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
+	"github.com/apache/skywalking-eyes/license-eye/pkg/deps"
 	"github.com/apache/skywalking-eyes/license-eye/pkg/header"
 
 	"gopkg.in/yaml.v3"
@@ -28,6 +29,7 @@ import (
 
 type Config struct {
 	Header header.ConfigHeader `yaml:"header"`
+	Deps   deps.ConfigDeps     `yaml:"dependency"`
 }
 
 // Parse reads and parses the header check configurations in config file.
@@ -44,5 +46,9 @@ func (config *Config) Parse(file string) error {
 		return err
 	}
 
+	if err := config.Deps.Finalize(file); err != nil {
+		return err
+	}
+
 	return nil
 }
diff --git a/license-eye/pkg/config/config.go b/license-eye/pkg/deps/config.go
similarity index 58%
copy from license-eye/pkg/config/config.go
copy to license-eye/pkg/deps/config.go
index 3b7c417..b682aa4 100644
--- a/license-eye/pkg/config/config.go
+++ b/license-eye/pkg/deps/config.go
@@ -1,3 +1,4 @@
+//
 // Licensed to Apache Software Foundation (ASF) under one or more contributor
 // license agreements. See the NOTICE file distributed with
 // this work for additional information regarding copyright
@@ -14,34 +15,24 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-//
-package config
+package deps
 
 import (
-	"io/ioutil"
-
-	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
-	"github.com/apache/skywalking-eyes/license-eye/pkg/header"
-
-	"gopkg.in/yaml.v3"
+	"path/filepath"
 )
 
-type Config struct {
-	Header header.ConfigHeader `yaml:"header"`
+type ConfigDeps struct {
+	Files []string `yaml:"files"`
 }
 
-// Parse reads and parses the header check configurations in config file.
-func (config *Config) Parse(file string) error {
-	logger.Log.Infoln("Loading configuration from file:", file)
-
-	if bytes, err := ioutil.ReadFile(file); err != nil {
-		return err
-	} else if err := yaml.Unmarshal(bytes, config); err != nil {
+func (config *ConfigDeps) Finalize(configFile string) error {
+	configFileAbsPath, err := filepath.Abs(configFile)
+	if err != nil {
 		return err
 	}
 
-	if err := config.Header.Finalize(); err != nil {
-		return err
+	for i, file := range config.Files {
+		config.Files[i] = filepath.Join(filepath.Dir(configFileAbsPath), file)
 	}
 
 	return nil
diff --git a/license-eye/pkg/deps/golang.go b/license-eye/pkg/deps/golang.go
new file mode 100644
index 0000000..cea090f
--- /dev/null
+++ b/license-eye/pkg/deps/golang.go
@@ -0,0 +1,149 @@
+//
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package deps
+
+import (
+	"go/build"
+	"io/ioutil"
+	"path/filepath"
+	"regexp"
+
+	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
+	"golang.org/x/mod/modfile"
+	"golang.org/x/tools/go/packages"
+)
+
+type GoModeResolver struct {
+	Resolver
+}
+
+func (resolver *GoModeResolver) CanResolve(file string) bool {
+	base := filepath.Base(file)
+	logger.Log.Debugln("Base name:", base)
+	return base == "go.mod"
+}
+
+// Resolve resolves licenses of all dependencies declared in the go.mod file.
+func (resolver *GoModeResolver) Resolve(goModFile string, report *Report) error {
+	content, err := ioutil.ReadFile(goModFile)
+	if err != nil {
+		return err
+	}
+
+	file, err := modfile.Parse(goModFile, content, nil)
+	if err != nil {
+		return err
+	}
+
+	logger.Log.Debugln("Resolving module:", file.Module.Mod)
+
+	requiredPkgNames := make([]string, len(file.Require))
+	for i, require := range file.Require {
+		requiredPkgNames[i] = require.Mod.Path
+	}
+
+	logger.Log.Debugln("Required packages:", requiredPkgNames)
+
+	if err := resolver.ResolvePackages(requiredPkgNames, report); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// ResolvePackages resolves the licenses of the given packages.
+func (resolver *GoModeResolver) ResolvePackages(pkgNames []string, report *Report) error {
+	requiredPkgs, err := packages.Load(&packages.Config{
+		Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedDeps,
+	}, pkgNames...)
+
+	if err != nil {
+		return err
+	}
+
+	packages.Visit(requiredPkgs, func(p *packages.Package) bool {
+		err := resolver.ResolvePackageLicense(p, report)
+		if err != nil {
+			logger.Log.Warnln("Failed to resolve the license of dependency:", p.Name, err)
+		}
+		return true
+	}, nil)
+
+	return nil
+}
+
+var possibleLicenseFileName = regexp.MustCompile(`(?i)^LICENSE|LICENCE(\.txt)?$`)
+
+func (resolver *GoModeResolver) ResolvePackageLicense(p *packages.Package, report *Report) error {
+	var filesInPkg []string
+	if len(p.GoFiles) > 0 {
+		filesInPkg = p.GoFiles
+	} else if len(p.CompiledGoFiles) > 0 {
+		filesInPkg = p.CompiledGoFiles
+	} else if len(p.OtherFiles) > 0 {
+		filesInPkg = p.OtherFiles
+	}
+
+	if len(filesInPkg) == 0 {
+		return nil
+	}
+
+	absPath, err := filepath.Abs(filesInPkg[0])
+	if err != nil {
+		return err
+	}
+	dir := filepath.Dir(absPath)
+
+	for {
+		files, err := ioutil.ReadDir(dir)
+		if err != nil {
+			return err
+		}
+		for _, info := range files {
+			if !possibleLicenseFileName.MatchString(info.Name()) {
+				continue
+			}
+			licenseFilePath := filepath.Join(dir, info.Name())
+			content, err := ioutil.ReadFile(licenseFilePath)
+			if err != nil {
+				return err
+			}
+			report.Resolve(&Result{
+				Dependency:      p.PkgPath,
+				LicenseContent:  string(content),
+				LicenseFilePath: licenseFilePath,
+				LicenseSpdxID:   "", // TODO: identify the SPDX ID
+			})
+			return nil
+		}
+		if resolver.shouldStopAt(dir) {
+			break
+		}
+		dir = filepath.Dir(dir)
+	}
+	return nil
+}
+
+func (resolver *GoModeResolver) shouldStopAt(dir string) bool {
+	for _, srcDir := range build.Default.SrcDirs() {
+		if srcDir == dir {
+			return true
+		}
+	}
+	return false
+}
diff --git a/license-eye/commands/header/header.go b/license-eye/pkg/deps/resolve.go
similarity index 58%
rename from license-eye/commands/header/header.go
rename to license-eye/pkg/deps/resolve.go
index 8786217..86fbe96 100644
--- a/license-eye/commands/header/header.go
+++ b/license-eye/pkg/deps/resolve.go
@@ -1,3 +1,4 @@
+//
 // Licensed to Apache Software Foundation (ASF) under one or more contributor
 // license agreements. See the NOTICE file distributed with
 // this work for additional information regarding copyright
@@ -14,27 +15,34 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-//
-package header
+package deps
 
 import (
-	"github.com/spf13/cobra"
+	"fmt"
 )
 
-var (
-	// cfgFile is the config path to the config file of header command.
-	cfgFile string
-)
+type Resolver interface {
+	CanResolve(string) bool
+	Resolve(string, *Report) error
+}
 
-var Header = &cobra.Command{
-	Use:     "header",
-	Aliases: []string{"h"},
-	Short:   "License header related commands; e.g. check, fix, etc.",
-	Long:    "`header` command walks the specified paths recursively and checks if the specified files have the license header in the config file.",
+var Resolvers = []Resolver{
+	new(GoModeResolver),
 }
 
-func init() {
-	Header.PersistentFlags().StringVarP(&cfgFile, "config", "c", ".licenserc.yaml", "the config file")
-	Header.AddCommand(CheckCommand)
-	Header.AddCommand(FixCommand)
+func Resolve(config *ConfigDeps, report *Report) error {
+	for _, file := range config.Files {
+		for _, resolver := range Resolvers {
+			if !resolver.CanResolve(file) {
+				continue
+			}
+			if err := resolver.Resolve(file, report); err != nil {
+				return err
+			}
+			return nil
+		}
+		return fmt.Errorf("unable to find a resolver to resolve dependency declaration file: %v", file)
+	}
+
+	return nil
 }
diff --git a/license-eye/pkg/config/config.go b/license-eye/pkg/deps/result.go
similarity index 54%
copy from license-eye/pkg/config/config.go
copy to license-eye/pkg/deps/result.go
index 3b7c417..bfea534 100644
--- a/license-eye/pkg/config/config.go
+++ b/license-eye/pkg/deps/result.go
@@ -1,3 +1,4 @@
+//
 // Licensed to Apache Software Foundation (ASF) under one or more contributor
 // license agreements. See the NOTICE file distributed with
 // this work for additional information regarding copyright
@@ -14,35 +15,34 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-//
-package config
-
-import (
-	"io/ioutil"
+package deps
 
-	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
-	"github.com/apache/skywalking-eyes/license-eye/pkg/header"
+type SpdxID string
 
-	"gopkg.in/yaml.v3"
+const (
+	Unknown string = "Unknown"
 )
 
-type Config struct {
-	Header header.ConfigHeader `yaml:"header"`
+// Result is a single item that represents a resolved dependency license.
+type Result struct {
+	Dependency      string
+	LicenseFilePath string
+	LicenseContent  string
+	LicenseSpdxID   string
 }
 
-// Parse reads and parses the header check configurations in config file.
-func (config *Config) Parse(file string) error {
-	logger.Log.Infoln("Loading configuration from file:", file)
-
-	if bytes, err := ioutil.ReadFile(file); err != nil {
-		return err
-	} else if err := yaml.Unmarshal(bytes, config); err != nil {
-		return err
-	}
+// Report is a collection of resolved Result.
+type Report struct {
+	Resolved []*Result
+	Skipped  []*Result
+}
 
-	if err := config.Header.Finalize(); err != nil {
-		return err
-	}
+// Resolve marks the dependency's license is resolved.
+func (report *Report) Resolve(result *Result) {
+	report.Resolved = append(report.Resolved, result)
+}
 
-	return nil
+// Skip marks the dependency's license is skipped for some reasons.
+func (report *Report) Skip(result *Result) {
+	report.Skipped = append(report.Skipped, result)
 }
diff --git a/license-eye/pkg/header/check.go b/license-eye/pkg/header/check.go
index ff59b34..0bdccb5 100644
--- a/license-eye/pkg/header/check.go
+++ b/license-eye/pkg/header/check.go
@@ -26,7 +26,6 @@ import (
 	"strings"
 
 	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
-	"github.com/apache/skywalking-eyes/license-eye/pkg"
 	lcs "github.com/apache/skywalking-eyes/license-eye/pkg/license"
 
 	"github.com/bmatcuk/doublestar/v2"
@@ -39,7 +38,7 @@ var (
 )
 
 // Check checks the license headers of the specified paths/globs.
-func Check(config *ConfigHeader, result *pkg.Result) error {
+func Check(config *ConfigHeader, result *Result) error {
 	for _, pattern := range config.Paths {
 		if err := checkPattern(pattern, result, config); err != nil {
 			return err
@@ -51,7 +50,7 @@ func Check(config *ConfigHeader, result *pkg.Result) error {
 
 var seen = make(map[string]bool)
 
-func checkPattern(pattern string, result *pkg.Result, config *ConfigHeader) error {
+func checkPattern(pattern string, result *Result, config *ConfigHeader) error {
 	paths, err := doublestar.Glob(pattern)
 
 	if err != nil {
@@ -72,7 +71,7 @@ func checkPattern(pattern string, result *pkg.Result, config *ConfigHeader) erro
 	return nil
 }
 
-func checkPath(path string, result *pkg.Result, config *ConfigHeader) error {
+func checkPath(path string, result *Result, config *ConfigHeader) error {
 	defer func() { seen[path] = true }()
 
 	if yes, err := config.ShouldIgnore(path); yes || seen[path] || err != nil {
@@ -105,7 +104,7 @@ func checkPath(path string, result *pkg.Result, config *ConfigHeader) error {
 }
 
 // CheckFile checks whether or not the file contains the configured license header.
-func CheckFile(file string, config *ConfigHeader, result *pkg.Result) error {
+func CheckFile(file string, config *ConfigHeader, result *Result) error {
 	if yes, err := config.ShouldIgnore(file); yes || err != nil {
 		if !seen[file] {
 			result.Ignore(file)
diff --git a/license-eye/pkg/header/check_test.go b/license-eye/pkg/header/check_test.go
index cbd898b..b5e8148 100644
--- a/license-eye/pkg/header/check_test.go
+++ b/license-eye/pkg/header/check_test.go
@@ -24,7 +24,6 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/apache/skywalking-eyes/license-eye/pkg"
 	"gopkg.in/yaml.v3"
 )
 
@@ -49,7 +48,7 @@ func TestCheckFile(t *testing.T) {
 	type args struct {
 		name       string
 		file       string
-		result     *pkg.Result
+		result     *Result
 		wantErr    bool
 		hasFailure bool
 	}
@@ -65,7 +64,7 @@ func TestCheckFile(t *testing.T) {
 			cases = append(cases, args{
 				name:       file,
 				file:       file,
-				result:     &pkg.Result{},
+				result:     &Result{},
 				wantErr:    false,
 				hasFailure: false,
 			})
@@ -100,7 +99,7 @@ func TestCheckFileFailure(t *testing.T) {
 	type args struct {
 		name       string
 		file       string
-		result     *pkg.Result
+		result     *Result
 		wantErr    bool
 		hasFailure bool
 	}
@@ -116,7 +115,7 @@ func TestCheckFileFailure(t *testing.T) {
 			cases = append(cases, args{
 				name:       file,
 				file:       file,
-				result:     &pkg.Result{},
+				result:     &Result{},
 				wantErr:    false,
 				hasFailure: true,
 			})
diff --git a/license-eye/pkg/header/fix.go b/license-eye/pkg/header/fix.go
index fb8413c..7e6d776 100644
--- a/license-eye/pkg/header/fix.go
+++ b/license-eye/pkg/header/fix.go
@@ -26,13 +26,12 @@ import (
 	"strings"
 
 	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
-	"github.com/apache/skywalking-eyes/license-eye/pkg"
 	"github.com/apache/skywalking-eyes/license-eye/pkg/comments"
 )
 
 // Fix adds the configured license header to the given file.
-func Fix(file string, config *ConfigHeader, result *pkg.Result) error {
-	var r pkg.Result
+func Fix(file string, config *ConfigHeader, result *Result) error {
+	var r Result
 	if err := CheckFile(file, config, &r); err != nil || !r.HasFailure() {
 		logger.Log.Warnln("Try to fix a valid file, do nothing:", file)
 		return err
@@ -51,7 +50,7 @@ func Fix(file string, config *ConfigHeader, result *pkg.Result) error {
 	return nil
 }
 
-func InsertComment(file string, style *comments.CommentStyle, config *ConfigHeader, result *pkg.Result) error {
+func InsertComment(file string, style *comments.CommentStyle, config *ConfigHeader, result *Result) error {
 	stat, err := os.Stat(file)
 	if err != nil {
 		return err
diff --git a/license-eye/pkg/result.go b/license-eye/pkg/header/result.go
similarity index 99%
rename from license-eye/pkg/result.go
rename to license-eye/pkg/header/result.go
index 9333671..068fe75 100644
--- a/license-eye/pkg/result.go
+++ b/license-eye/pkg/header/result.go
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 //
-package pkg
+package header
 
 import (
 	"fmt"
diff --git a/license-eye/pkg/review/header.go b/license-eye/pkg/review/header.go
index 4ad84e7..7c5b790 100644
--- a/license-eye/pkg/review/header.go
+++ b/license-eye/pkg/review/header.go
@@ -30,7 +30,6 @@ import (
 	"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"
@@ -59,7 +58,7 @@ var (
 )
 
 func init() {
-	if os.Getenv("GITHUB_TOKEN") == "" {
+	if os.Getenv("INPUT_GITHUB_TOKEN") == "" {
 		logger.Log.Warnln("GITHUB_TOKEN is not set, license-eye won't comment on the pull request")
 		return
 	}
@@ -110,7 +109,7 @@ func init() {
 }
 
 // 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 {
+func Header(result *header2.Result, config *config2.Config) error {
 	if !result.HasFailure() || !IsPR() || gh == nil || config.Header.Comment == header2.Never {
 		return nil
 	}
@@ -171,7 +170,7 @@ func Header(result *pkg.Result, config *config2.Config) error {
 	return nil
 }
 
-func tryReview(result *pkg.Result, config *config2.Config, comments []*github.DraftReviewComment) error {
+func tryReview(result *header2.Result, config *config2.Config, comments []*github.DraftReviewComment) error {
 	tryBestEffortToComment := func() error {
 		if err := doReview(result, comments); err != nil {
 			logger.Log.Warnln("Failed to create review comment, fallback to a plain comment:", err)
@@ -193,7 +192,7 @@ func tryReview(result *pkg.Result, config *config2.Config, comments []*github.Dr
 	return nil
 }
 
-func doReview(result *pkg.Result, comments []*github.DraftReviewComment) error {
+func doReview(result *header2.Result, comments []*github.DraftReviewComment) error {
 	logger.Log.Debugln("Comments:", comments)
 
 	c := Markdown(result)
@@ -257,7 +256,7 @@ func IsPR() bool {
 }
 
 // TODO add fixing guide
-func Markdown(result *pkg.Result) string {
+func Markdown(result *header2.Result) string {
 	return fmt.Sprintf(`
 <!-- %s -->
 [license-eye](https://github.com/apache/skywalking-eyes/tree/main/license-eye) has totally checked %d files.


[skywalking-eyes] 03/03: Polish the report output, deps 1.0 is finished

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 5f30d70be32716bbf7e89a546a8f89014bad6ccd
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Sun Dec 27 12:09:50 2020 +0800

    Polish the report output, deps 1.0 is finished
---
 license-eye/commands/deps_resolve.go | 19 ++++++++++++++-----
 license-eye/pkg/deps/golang.go       |  4 ++++
 license-eye/pkg/deps/result.go       | 34 ++++++++++++++++++++++++++++++++++
 license-eye/pkg/review/header.go     |  2 +-
 4 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/license-eye/commands/deps_resolve.go b/license-eye/commands/deps_resolve.go
index f4d492f..b493952 100644
--- a/license-eye/commands/deps_resolve.go
+++ b/license-eye/commands/deps_resolve.go
@@ -18,7 +18,9 @@
 package commands
 
 import (
-	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
+	"fmt"
+	"strings"
+
 	"github.com/apache/skywalking-eyes/license-eye/pkg/deps"
 	"github.com/spf13/cobra"
 )
@@ -34,11 +36,18 @@ var ResolveCommand = &cobra.Command{
 			return err
 		}
 
-		for _, result := range report.Resolved {
-			logger.Log.Debugln("Pkg: ", result.Dependency, " License:", result.LicenseSpdxID)
-		}
+		fmt.Println(report.String())
 
-		logger.Log.Debugln("Skipped:", len(report.Skipped))
+		if skipped := len(report.Skipped); skipped > 0 {
+			pkgs := make([]string, skipped)
+			for i, s := range report.Skipped {
+				pkgs[i] = s.Dependency
+			}
+			return fmt.Errorf(
+				"failed to identify the licenses of following packages:\n%s",
+				strings.Join(pkgs, "\n"),
+			)
+		}
 
 		return nil
 	},
diff --git a/license-eye/pkg/deps/golang.go b/license-eye/pkg/deps/golang.go
index 99f4fe2..cb9eac1 100644
--- a/license-eye/pkg/deps/golang.go
+++ b/license-eye/pkg/deps/golang.go
@@ -81,6 +81,10 @@ func (resolver *GoModeResolver) ResolvePackages(pkgNames []string, report *Repor
 		err := resolver.ResolvePackageLicense(p, report)
 		if err != nil {
 			logger.Log.Warnln("Failed to resolve the license of dependency:", p.PkgPath, err)
+			report.Skip(&Result{
+				Dependency:    p.PkgPath,
+				LicenseSpdxID: []string{Unknown},
+			})
 		}
 		return true
 	}, nil)
diff --git a/license-eye/pkg/deps/result.go b/license-eye/pkg/deps/result.go
index abf8669..5ab00d6 100644
--- a/license-eye/pkg/deps/result.go
+++ b/license-eye/pkg/deps/result.go
@@ -17,6 +17,12 @@
 // under the License.
 package deps
 
+import (
+	"fmt"
+	"math"
+	"strings"
+)
+
 type SpdxID string
 
 const (
@@ -46,3 +52,31 @@ func (report *Report) Resolve(result *Result) {
 func (report *Report) Skip(result *Result) {
 	report.Skipped = append(report.Skipped, result)
 }
+
+func (report *Report) String() string {
+	dWidth, lWidth := .0, .0
+	for _, r := range report.Skipped {
+		dWidth = math.Max(float64(len(r.Dependency)), dWidth)
+		for _, s := range r.LicenseSpdxID {
+			lWidth = math.Max(float64(len(s)), lWidth)
+		}
+	}
+	for _, r := range report.Resolved {
+		dWidth = math.Max(float64(len(r.Dependency)), dWidth)
+		for _, s := range r.LicenseSpdxID {
+			lWidth = math.Max(float64(len(s)), lWidth)
+		}
+	}
+
+	rowTemplate := fmt.Sprintf("%%-%dv | %%%dv\n", int(dWidth), int(lWidth))
+	s := fmt.Sprintf(rowTemplate, "Dependency", "License")
+	s += fmt.Sprintf(rowTemplate, strings.Repeat("-", int(dWidth)), strings.Repeat("-", int(lWidth)))
+	for _, r := range report.Resolved {
+		s += fmt.Sprintf(rowTemplate, r.Dependency, strings.Join(r.LicenseSpdxID, ","))
+	}
+	for _, r := range report.Skipped {
+		s += fmt.Sprintf(rowTemplate, r.Dependency, Unknown)
+	}
+
+	return s
+}
diff --git a/license-eye/pkg/review/header.go b/license-eye/pkg/review/header.go
index 7c5b790..b43cfaa 100644
--- a/license-eye/pkg/review/header.go
+++ b/license-eye/pkg/review/header.go
@@ -59,7 +59,7 @@ var (
 
 func init() {
 	if os.Getenv("INPUT_GITHUB_TOKEN") == "" {
-		logger.Log.Warnln("GITHUB_TOKEN is not set, license-eye won't comment on the pull request")
+		logger.Log.Infoln("GITHUB_TOKEN is not set, license-eye won't comment on the pull request")
 		return
 	}