This is an automated email from the ASF dual-hosted git repository.
kezhenxu94 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-eyes.git
The following commit(s) were added to refs/heads/main by this push:
new 63d8963 Enhance NPM dependency resolver to resolve deprecated license
styles (#52)
63d8963 is described below
commit 63d89639812f1a94bd45d9329d0f936ec4769a37
Author: Youhan Wu <[email protected]>
AuthorDate: Sat Aug 7 17:29:22 2021 +0800
Enhance NPM dependency resolver to resolve deprecated license styles (#52)
---
pkg/deps/npm.go | 61 +++++++++++++++++++++++++---
pkg/deps/npm_test.go | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 164 insertions(+), 6 deletions(-)
diff --git a/pkg/deps/npm.go b/pkg/deps/npm.go
index 05753a2..fc51930 100644
--- a/pkg/deps/npm.go
+++ b/pkg/deps/npm.go
@@ -27,6 +27,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "strings"
"time"
"github.com/apache/skywalking-eyes/license-eye/internal/logger"
@@ -37,11 +38,19 @@ type NpmResolver struct {
Resolver
}
+// Lcs represents the license style in package.json
+type Lcs struct {
+ Type string `json:"type"`
+ URL string `json:"url"`
+}
+
// Package represents package.json
+// License field has inconsistent styles, so we just store the byte array here
to postpone unmarshalling
type Package struct {
- Name string `json:"name"`
- License string `json:"license"`
- Path string
+ Name string `json:"name"`
+ License json.RawMessage `json:"license"`
+ Licenses []Lcs `json:"licenses"`
+ Path string `json:"-"`
}
const PkgFileName = "package.json"
@@ -206,10 +215,50 @@ func (resolver *NpmResolver) ResolvePkgFile(pkgFile
string) (string, error) {
if err != nil {
return "", err
}
- if packageInfo.License == "" {
- return "", fmt.Errorf("cannot capture the license field")
+
+ if lcs, ok := resolver.ResolveLicenseField(packageInfo.License); ok {
+ return lcs, nil
+ }
+
+ if lcs, ok := resolver.ResolveLicensesField(packageInfo.Licenses); ok {
+ return lcs, nil
+ }
+
+ return "", fmt.Errorf(`cannot parse the "license"/"licenses" field`)
+}
+
+// ResolveLicenseField parses and validates the "license" field in
package.json file
+func (resolver *NpmResolver) ResolveLicenseField(rawData []byte) (string,
bool) {
+ if len(rawData) > 0 {
+ switch rawData[0] {
+ case '"':
+ var lcs string
+ _ = json.Unmarshal(rawData, &lcs)
+ if lcs != "" {
+ return lcs, true
+ }
+ case '{':
+ var lcs Lcs
+ _ = json.Unmarshal(rawData, &lcs)
+ if t := lcs.Type; t != "" {
+ return t, true
+ }
+ }
+ }
+ return "", false
+}
+
+// ResolveLicensesField parses and validates the "licenses" field in
package.json file
+// Additionally, the output is converted into the SPDX license expression
syntax version 2.0 string, like "ISC OR GPL-3.0"
+func (resolver *NpmResolver) ResolveLicensesField(licenses []Lcs) (string,
bool) {
+ var lcs []string
+ for _, l := range licenses {
+ lcs = append(lcs, l.Type)
+ }
+ if len(lcs) == 0 {
+ return "", false
}
- return packageInfo.License, nil
+ return strings.Join(lcs, " OR "), true
}
// ResolveLcsFile tries to find the license file to identify the license
diff --git a/pkg/deps/npm_test.go b/pkg/deps/npm_test.go
new file mode 100644
index 0000000..ba11961
--- /dev/null
+++ b/pkg/deps/npm_test.go
@@ -0,0 +1,109 @@
+//
+// 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_test
+
+import (
+ "github.com/apache/skywalking-eyes/license-eye/pkg/deps"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+var lcsString = `
+{
+ "license": "ISC"
+}`
+var lcsStruct = `
+{
+ "license": {
+ "type" : "ISC",
+ "url" : "https://opensource.org/licenses/ISC"
+ }
+}`
+var lcss = `
+{
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://www.opensource.org/licenses/mit-license.php"
+ },
+ {
+ "type": "Apache-2.0",
+ "url": "https://opensource.org/licenses/apache2.0.php"
+ }
+ ]
+}`
+var lcsStringEmpty = `
+{
+ "license": ""
+}`
+var lcsStructEmpty = `
+{
+ "license": {
+ }
+}`
+var lcssEmpty = `
+{
+ "licenses": [
+ ]
+}`
+var lcssInvalid = `
+{
+ "licenses": {
+ }
+}`
+
+var TestData = []struct {
+ data string
+ result string
+ hasErr bool
+}{
+ {lcsString, "ISC", false},
+ {lcsStruct, "ISC", false},
+ {lcss, "MIT OR Apache-2.0", false},
+ {lcsStringEmpty, "", true},
+ {lcsStructEmpty, "", true},
+ {lcssEmpty, "", true},
+ {lcssInvalid, "", true},
+}
+
+func TestResolvePkgFile(t *testing.T) {
+ dir, err := ioutil.TempDir(os.TempDir(), "")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ resolver := new(deps.NpmResolver)
+ for _, data := range TestData {
+ f, err := ioutil.TempFile(dir, "*.json")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = f.WriteString(data.data)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ lcs, err := resolver.ResolvePkgFile(f.Name())
+ if lcs != data.result && (err != nil) == data.hasErr {
+ t.Fail()
+ }
+ _ = f.Close()
+ }
+}