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

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

commit 25dbc665bdca7aa408ebdaf9b00cac8fc37f1be5
Author: kezhenxu94 <[email protected]>
AuthorDate: Wed Aug 18 21:32:16 2021 +0800

    Set up mechanism to check dependencies' license compatibilities
---
 README.md                            | 29 ++++++++++++
 assets/compatibility/Apache-2.0.yaml | 92 ++++++++++++++++++++++++++++++++++++
 commands/deps.go                     |  3 +-
 commands/{deps.go => deps_check.go}  | 18 +++----
 commands/deps_resolve.go             |  2 +-
 pkg/deps/check.go                    | 90 +++++++++++++++++++++++++++++++++++
 pkg/license/identifier_test.go       | 70 +++++++++++++++++++++++++++
 pkg/license/norm.go                  | 10 ++++
 8 files changed, 303 insertions(+), 11 deletions(-)

diff --git a/README.md b/README.md
index 61dd4a0..effb082 100644
--- a/README.md
+++ b/README.md
@@ -95,6 +95,8 @@ INFO Totally checked 20 files, valid: 10, invalid: 10, 
ignored: 0, fixed: 10
 
 #### Resolve Dependencies' licenses
 
+This command serves as assistance for human beings to audit the dependencies 
license, it's exit code is always 0.
+
 ```bash
 $ bin/darwin/license-eye -c test/testdata/.licenserc_for_test_check.yaml dep 
resolve
 INFO GITHUB_TOKEN is not set, license-eye won't comment on the pull request
@@ -135,6 +137,33 @@ ERROR failed to identify the licenses of following 
packages:
 gopkg.in/yaml.v3
 ```
 
+#### Check Dependencies' licenses
+
+This command can be used to perform automatic license compatibility check, 
when there is incompatible licenses found,
+the command will exit with status code 1 and fail the command.
+
+```bash
+$ bin/darwin/license-eye -c test/testdata/.licenserc_for_test_check.yaml dep 
check
+INFO GITHUB_TOKEN is not set, license-eye won't comment on the pull request 
+INFO Loading configuration from file: .licenserc.yaml 
+WARNING Failed to resolve the license of <github.com/gogo/protobuf>: cannot 
identify license content 
+WARNING Failed to resolve the license of <github.com/kr/logfmt>: cannot find 
license file 
+WARNING Failed to resolve the license of <github.com/magiconair/properties>: 
cannot identify license content 
+WARNING Failed to resolve the license of <github.com/miekg/dns>: cannot 
identify license content 
+WARNING Failed to resolve the license of <github.com/pascaldekloe/goe>: cannot 
identify license content 
+WARNING Failed to resolve the license of <github.com/russross/blackfriday/v2>: 
cannot identify license content 
+WARNING Failed to resolve the license of <gopkg.in/check.v1>: cannot identify 
license content 
+ERROR the following licenses are incompatible with the main license: 
Apache-2.0 
+License: Unknown Dependency: github.com/gogo/protobuf
+License: Unknown Dependency: github.com/kr/logfmt
+License: Unknown Dependency: github.com/magiconair/properties
+License: Unknown Dependency: github.com/miekg/dns
+License: Unknown Dependency: github.com/pascaldekloe/goe
+License: Unknown Dependency: github.com/russross/blackfriday/v2
+License: Unknown Dependency: gopkg.in/check.v1 
+exit status 1
+```
+
 ## Configurations
 
 ```yaml
diff --git a/assets/compatibility/Apache-2.0.yaml 
b/assets/compatibility/Apache-2.0.yaml
new file mode 100644
index 0000000..44a8271
--- /dev/null
+++ b/assets/compatibility/Apache-2.0.yaml
@@ -0,0 +1,92 @@
+#
+# Licensed to the 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.  The 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.
+#
+
+# The compatibility is extracted from 
https://www.apache.org/legal/resolved.html
+
+compatible:
+  - Apache-2.0
+  - PHP-3.01
+  - BSD-3-Clause
+  - BSD-2-Clause
+  - PostgreSQL
+  - EPL-1.0
+  - ISC
+  - SMLNJ
+  - ICU.txt
+  - NCSA.txt
+  - W3C.txt
+  - Xnet.txt
+  - Zlib.txt
+  - Libpng.txt
+  - AFL-3.0.txt
+  - MS-PL.txt
+  - PSF-2.0.txt
+  - BSL-1.0.txt
+  - WTFPL.txt
+  - Unicode-DFS-2016.txt
+  - Unicode-DFS-2015.txt
+  - ZPL-2.0.txt
+  - Unlicense.txt
+  - HPND.txt
+  - MulanPSL-2.0.txt
+
+incompatible:
+  - Unknown
+  - LGPL-2.0+
+  - LGPL-2.0
+  - LGPL-2.0-only
+  - LGPL-2.0-or-later
+  - LGPL-2.1+
+  - LGPL-2.1
+  - LGPL-2.1-only
+  - LGPL-2.1-or-later
+  - LGPL-3.0+
+  - LGPL-3.0
+  - LGPL-3.0-linking-exception
+  - LGPL-3.0-only
+  - LGPL-3.0-or-later
+  - LGPLLR
+  - GPL-1.0+
+  - GPL-1.0
+  - GPL-1.0-only
+  - GPL-1.0-or-later
+  - GPL-2.0+
+  - GPL-2.0
+  - GPL-2.0-only
+  - GPL-2.0-or-later
+  - GPL-2.0-with-autoconf-exception
+  - GPL-2.0-with-bison-exception
+  - GPL-2.0-with-classpath-exception
+  - GPL-2.0-with-font-exception
+  - GPL-2.0-with-GCC-exception
+  - GPL-3.0+
+  - GPL-3.0
+  - GPL-3.0-linking-exception
+  - GPL-3.0-linking-source-exception
+  - GPL-3.0-only
+  - GPL-3.0-or-later
+  - GPL-3.0-with-autoconf-exception
+  - GPL-3.0-with-GCC-exception
+  - GPL-CC-1.0
+  - QPL-1.0
+  - Sleepycat
+  - SSPL-1.0
+  - CPOL-1.02
+  - NPL-1.0
+  - NPL-1.1
diff --git a/commands/deps.go b/commands/deps.go
index cac7d08..0c38b7a 100644
--- a/commands/deps.go
+++ b/commands/deps.go
@@ -29,5 +29,6 @@ var Deps = &cobra.Command{
 }
 
 func init() {
-       Deps.AddCommand(ResolveCommand)
+       Deps.AddCommand(DepsResolveCommand)
+       Deps.AddCommand(DepsCheckCommand)
 }
diff --git a/commands/deps.go b/commands/deps_check.go
similarity index 69%
copy from commands/deps.go
copy to commands/deps_check.go
index cac7d08..1f4fb93 100644
--- a/commands/deps.go
+++ b/commands/deps_check.go
@@ -19,15 +19,15 @@ package commands
 
 import (
        "github.com/spf13/cobra"
-)
 
-var Deps = &cobra.Command{
-       Use:     "dependency",
-       Aliases: []string{"d", "deps", "dep", "dependencies"},
-       Short:   "Dependencies related commands; e.g. check, etc.",
-       Long:    "deps command checks all dependencies of a module and their 
transitive dependencies.",
-}
+       "github.com/apache/skywalking-eyes/license-eye/pkg/deps"
+)
 
-func init() {
-       Deps.AddCommand(ResolveCommand)
+var DepsCheckCommand = &cobra.Command{
+       Use:     "check",
+       Aliases: []string{"c"},
+       Long:    "resolves and check license compatibility in all dependencies 
of a module and their transitive dependencies",
+       RunE: func(cmd *cobra.Command, args []string) error {
+               return deps.Check(Config.Header.License.SpdxID, &Config.Deps)
+       },
 }
diff --git a/commands/deps_resolve.go b/commands/deps_resolve.go
index c142d6e..4a03927 100644
--- a/commands/deps_resolve.go
+++ b/commands/deps_resolve.go
@@ -26,7 +26,7 @@ import (
        "github.com/apache/skywalking-eyes/license-eye/pkg/deps"
 )
 
-var ResolveCommand = &cobra.Command{
+var DepsResolveCommand = &cobra.Command{
        Use:     "resolve",
        Aliases: []string{"r"},
        Long:    "resolves all dependencies of a module and their transitive 
dependencies",
diff --git a/pkg/deps/check.go b/pkg/deps/check.go
new file mode 100644
index 0000000..a164dcc
--- /dev/null
+++ b/pkg/deps/check.go
@@ -0,0 +1,90 @@
+//
+// 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 (
+       "fmt"
+       "path/filepath"
+       "strings"
+
+       "gopkg.in/yaml.v3"
+
+       "github.com/apache/skywalking-eyes/license-eye/assets"
+       "github.com/apache/skywalking-eyes/license-eye/internal/logger"
+)
+
+type compatibilityMatrix struct {
+       Compatible   []string `yaml:"compatible"`
+       Incompatible []string `yaml:"incompatible"`
+}
+
+var matrices = make(map[string]compatibilityMatrix)
+
+func init() {
+       dir := "compatibility"
+       files, err := assets.AssetDir(dir)
+       if err != nil {
+               logger.Log.Fatalln("Failed to list assets/compatibility 
directory:", err)
+       }
+       for _, file := range files {
+               name := file.Name()
+               matrix := compatibilityMatrix{}
+               if bytes, err := assets.Asset(filepath.Join(dir, name)); err != 
nil {
+                       logger.Log.Fatalln("Failed to read compatibility 
file:", name, err)
+               } else if err := yaml.Unmarshal(bytes, &matrix); err != nil {
+                       logger.Log.Fatalln("Failed to unmarshal compatibility 
file:", file, err)
+               }
+               matrices[strings.TrimSuffix(name, filepath.Ext(name))] = matrix
+       }
+}
+
+func Check(mainLicenseSpdxID string, config *ConfigDeps) error {
+       report := Report{}
+       if err := Resolve(config, &report); err != nil {
+               return nil
+       }
+
+       matrix := matrices[mainLicenseSpdxID]
+       var incompatibleResults []*Result
+       for _, result := range append(report.Resolved, report.Skipped...) {
+               compare := func(list []string) bool {
+                       for _, com := range list {
+                               if result.LicenseSpdxID == com {
+                                       return true
+                               }
+                       }
+                       return false
+               }
+               if compatible := compare(matrix.Compatible); compatible {
+                       continue
+               }
+               if incompatible := compare(matrix.Incompatible); incompatible {
+                       incompatibleResults = append(incompatibleResults, 
result)
+               }
+       }
+
+       if len(incompatibleResults) > 0 {
+               str := ""
+               for _, r := range incompatibleResults {
+                       str += fmt.Sprintf("\nLicense: %v Dependency: %v", 
r.LicenseSpdxID, r.Dependency)
+               }
+               return fmt.Errorf("the following licenses are incompatible with 
the main license: %v %v", mainLicenseSpdxID, str)
+       }
+
+       return nil
+}
diff --git a/pkg/license/identifier_test.go b/pkg/license/identifier_test.go
new file mode 100644
index 0000000..ea7749b
--- /dev/null
+++ b/pkg/license/identifier_test.go
@@ -0,0 +1,70 @@
+//
+// 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 license
+
+import "testing"
+
+func TestIdentify(t *testing.T) {
+       tests := []struct {
+               name    string
+               content string
+               want    string
+       }{
+               {
+                       name: "License per portion",
+                       content: `MIT License
+
+Copyright (c) 2017 Blake Gentry
+
+This license applies to the non-Windows portions of this library. The Windows
+portion maintains its own Apache 2.0 license.
+
+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 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.
+`,
+                       want: `MIT`,
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       got, err := Identify("", tt.content)
+                       if err != nil {
+                               t.Errorf("Identify() error = %v", err)
+                               return
+                       }
+                       if got != tt.want {
+                               t.Errorf("Identify() got = %v, want %v", got, 
tt.want)
+                       }
+               })
+       }
+}
diff --git a/pkg/license/norm.go b/pkg/license/norm.go
index 3687290..46ef393 100644
--- a/pkg/license/norm.go
+++ b/pkg/license/norm.go
@@ -178,6 +178,11 @@ var (
                },
 
                {
+                       regexp.MustCompile(`(?im)This license applies to .+? 
portions of this .+?\. The .+? maintains its own .+? license\.`),
+                       "",
+               },
+
+               {
                        regexp.MustCompile(`(?im)\(including the next 
paragraph\)`),
                        "",
                },
@@ -224,6 +229,11 @@ var (
                        regexp.MustCompile(`(?m)^\s*Copyright (\([cC©]\))?.+$`),
                        "",
                },
+               // All rights reserved
+               {
+                       regexp.MustCompile(`(?m)^\s*All rights reserved\.?$`),
+                       "",
+               },
 
                // This should be the last one processor
                {

Reply via email to