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 056313d510dab84634ed57ff62460f126077dfbb Author: kezhenxu94 <[email protected]> AuthorDate: Wed Aug 18 21:32:16 2021 +0800 Set up mechanism to check dependencies' license compatibilities --- 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 ++++ 7 files changed, 274 insertions(+), 11 deletions(-) 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..44447c6 --- /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", 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 {
