Enhance checking/fixing command, more tests, more comment styles (#2)
- `fix` command should properly tackle shebang and xml declaration;
- Add more known comment styles;
- Add more test cases;
- Support checking a single file for debugging;
- Append .gitignore content automatically, add `LicenseLocationThreshold`
diff --git a/.github/workflows/license-eye-check.yaml b/.github/workflows/license-eye-check.yaml
index cd40f8c..2bcfd23 100644
--- a/.github/workflows/license-eye-check.yaml
+++ b/.github/workflows/license-eye-check.yaml
@@ -50,3 +50,6 @@
- name: Build
run: make build
+
+ - name: Build Docker Image
+ run: make docker
diff --git a/.gitignore b/.gitignore
index a559c8f..a90f1dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,4 @@
bin/
license-eye/assets/assets.gen.go
.DS_Store
+coverage.txt
diff --git a/.golangci.yml b/.golangci.yml
index ca0227f..f4a7795 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -51,7 +51,7 @@
disabled-checks:
- ifElseChain
funlen:
- lines: 100
+ lines: 150
statements: 50
whitespace:
multi-if: false
diff --git a/.licenserc.yaml b/.licenserc.yaml
index 049ce1b..dc3b932 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -1,3 +1,21 @@
+#
+# 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.
+#
header: # `header` section is configurations for source codes license header.
license: | # `license` will be used as the content when `fix` command needs to insert a license header.
Licensed to Apache Software Foundation (ASF) under one or more contributor
@@ -16,7 +34,10 @@
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
- pattern: | # `pattern` is optional regexp if all the file headers are the same as `license` (linebreaks doesn't matter).
+
+ # `pattern` is optional regexp if all the file headers are the same as `license` (linebreaks doesn't matter);
+ # In the `pattern`, all punctuations should be removed unless they are part of the regex;
+ pattern: |
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
@@ -34,14 +55,12 @@
specific language governing permissions and limitations
under the License.
- paths: # `paths` are the path list that will be checked (and fixed) by license-eye.
+ paths: # `paths` are the path list that will be checked (and fixed) by license-eye, default is ['**'].
- '**'
paths-ignore: # `paths-ignore` are the path list that will be ignored by license-eye.
- - '.git/**'
- - '.idea/**'
- - 'dist/**'
- - 'licenses/**'
+ - 'dist'
+ - 'licenses'
- '**/bin/**'
- '**/*.md'
- '**/.DS_Store'
@@ -50,5 +69,5 @@
- '**/go.sum'
- 'LICENSE'
- 'NOTICE'
- - '**/assets.gen.go'
- '**/assets/languages.yaml'
+ - '**/assets/assets.gen.go'
diff --git a/license-eye/Makefile b/license-eye/Makefile
index 0629e37..09f9fca 100644
--- a/license-eye/Makefile
+++ b/license-eye/Makefile
@@ -61,7 +61,7 @@
.PHONY: test
test: clean codegen
- $(GO_TEST) ./...
+ $(GO_TEST) ./... -coverprofile=coverage.txt -covermode=atomic
@>&2 echo "Great, all tests passed."
.PHONY: $(PLATFORMS)
@@ -80,3 +80,4 @@
clean:
-rm -rf bin
-rm -rf assets/*.gen.go
+ -rm -rf coverage.txt
diff --git a/license-eye/assets/languages.yaml b/license-eye/assets/languages.yaml
index e4af70e..2d179ae 100644
--- a/license-eye/assets/languages.yaml
+++ b/license-eye/assets/languages.yaml
@@ -2232,6 +2232,7 @@
codemirror_mode: haskell
codemirror_mime_type: text/x-haskell
language_id: 157
+ comment_style_id: CurlyBracketDash
Haxe:
type: programming
ace_mode: haxe
@@ -3708,6 +3709,7 @@
- ocamlscript
tm_scope: source.ocaml
language_id: 255
+ comment_style_id: RoundBracketAsterisk
ObjDump:
type: data
extensions:
@@ -3977,6 +3979,7 @@
- ".trg"
- ".vw"
language_id: 273
+ comment_style_id: DoubleDash
PLpgSQL:
type: programming
ace_mode: pgsql
@@ -3987,6 +3990,7 @@
- ".pgsql"
- ".sql"
language_id: 274
+ comment_style_id: DoubleDash
POV-Ray SDL:
type: programming
aliases:
@@ -5026,6 +5030,7 @@
- ".udf"
- ".viw"
language_id: 333
+ comment_style_id: DoubleDash
SQLPL:
type: programming
ace_mode: sql
@@ -5036,6 +5041,7 @@
- ".sql"
- ".db2"
language_id: 334
+ comment_style_id: DoubleDash
SRecode Template:
type: markup
color: "#348a34"
@@ -5549,6 +5555,7 @@
ace_mode: sql
tm_scope: source.tsql
language_id: 918334941
+ comment_style_id: DoubleDash
TSV:
type: data
ace_mode: text
@@ -5969,6 +5976,7 @@
- vimrc
ace_mode: text
language_id: 388
+ comment_style_id: Quotes
Visual Basic .NET:
type: programming
color: "#945db7"
@@ -6393,6 +6401,7 @@
codemirror_mode: yaml
codemirror_mime_type: text/x-yaml
language_id: 407
+ comment_style_id: Hashtag
YANG:
type: data
extensions:
diff --git a/license-eye/assets/styles.yaml b/license-eye/assets/styles.yaml
index deb64a5..216232f 100644
--- a/license-eye/assets/styles.yaml
+++ b/license-eye/assets/styles.yaml
@@ -18,16 +18,17 @@
- id: DoubleSlash
start: '//'
- middle: ~
- end: ~
+ middle: '//'
+ end: '//'
- id: Hashtag
+ after: '(?m)^*#!.+$'
start: '#'
- middle: ~
- end: ~
- skip: '^#!'
+ middle: '#'
+ end: '#'
- id: AngleBracket
+ after: '(?ms)^<\?.+?\?>$'
start: '<!--'
middle: ' ~'
end: '-->'
@@ -38,3 +39,23 @@
middle: ' *' # <2>
end: ' */' # <3>
# end::SlashAsterisk[]
+
+- id: RoundBracketAsterisk
+ start: '(*'
+ middle: '(*'
+ end: '(*'
+
+- id: CurlyBracketDash
+ start: '{-'
+ middle: ~
+ end: '-}'
+
+- id: DoubleDash
+ start: '--'
+ middle: '--'
+ end: '--'
+
+- id: Quotes
+ start: '"'
+ middle: '"'
+ end: '"'
diff --git a/license-eye/commands/header/check.go b/license-eye/commands/header/check.go
index 1de9115..c349ace 100644
--- a/license-eye/commands/header/check.go
+++ b/license-eye/commands/header/check.go
@@ -37,6 +37,11 @@
return err
}
+ if len(args) > 0 {
+ logger.Log.Debugln("Overriding paths with command line args.")
+ config.Header.Paths = args
+ }
+
if err := header.Check(&config.Header, &result); err != nil {
return err
}
diff --git a/license-eye/internal/logger/log.go b/license-eye/internal/logger/log.go
index 7fc102e..1c641e8 100644
--- a/license-eye/internal/logger/log.go
+++ b/license-eye/internal/logger/log.go
@@ -29,7 +29,7 @@
if Log == nil {
Log = logrus.New()
}
- Log.Level = logrus.DebugLevel
+ Log.Level = logrus.InfoLevel
Log.SetOutput(os.Stdout)
Log.SetFormatter(&logrus.TextFormatter{
DisableTimestamp: true,
diff --git a/license-eye/pkg/comments/config.go b/license-eye/pkg/comments/config.go
index 8b2db6f..28f4462 100644
--- a/license-eye/pkg/comments/config.go
+++ b/license-eye/pkg/comments/config.go
@@ -27,6 +27,7 @@
type CommentStyle struct {
ID string `yaml:"id"`
+ After string `yaml:"after"`
Start string `yaml:"start"`
Middle string `yaml:"middle"`
End string `yaml:"end"`
@@ -39,15 +40,6 @@
return nil
}
-func (style *CommentStyle) Finalize() {
- if style.Middle == "" {
- style.Middle = style.Start
- }
- if style.End == "" {
- style.End = style.Start
- }
-}
-
type Language struct {
Type string `yaml:"type"`
Extensions []string `yaml:"extensions"`
@@ -107,7 +99,6 @@
}
for _, style := range styles {
- style.Finalize()
comments[style.ID] = style
}
}
diff --git a/license-eye/pkg/config/Config.go b/license-eye/pkg/config/config.go
similarity index 100%
rename from license-eye/pkg/config/Config.go
rename to license-eye/pkg/config/config.go
diff --git a/license-eye/pkg/header/check.go b/license-eye/pkg/header/check.go
index a0541e6..5325692 100644
--- a/license-eye/pkg/header/check.go
+++ b/license-eye/pkg/header/check.go
@@ -29,7 +29,13 @@
"github.com/bmatcuk/doublestar/v2"
)
-const CommentChars = "/*#- !~'\"(){}"
+// TODO: also trim stop words
+var (
+ // LicenseLocationThreshold specifies the index threshold where the license header can be located,
+ // after all, a "header" cannot be TOO far from the file start.
+ LicenseLocationThreshold = 80
+ Punctuations = regexp.MustCompile("[\\[\\]/*:;\\s#\\-!~'\"(){}?]+")
+)
// Check checks the license headers of the specified paths/globs.
func Check(config *ConfigHeader, result *Result) error {
@@ -111,31 +117,45 @@
reader, err := os.Open(file)
if err != nil {
- return nil
+ return err
}
var lines []string
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
- line := strings.ToLower(strings.Trim(scanner.Text(), CommentChars))
- line = regexp.MustCompile("[ '\"]+").ReplaceAllString(line, " ")
+ line := strings.ToLower(Punctuations.ReplaceAllString(scanner.Text(), " "))
if len(line) > 0 {
lines = append(lines, line)
}
}
- content := strings.Join(lines, " ")
+ content := Punctuations.ReplaceAllString(strings.Join(lines, " "), " ")
license, pattern := config.NormalizedLicense(), config.NormalizedPattern()
- if strings.Contains(content, license) || (pattern != nil && pattern.MatchString(content)) {
+ if satisfy(content, license, pattern) {
result.Succeed(file)
} else {
logger.Log.Debugln("Content is:", content)
- logger.Log.Debugln("Pattern is:", pattern)
+ if pattern != nil {
+ logger.Log.Debugln("Pattern is:", pattern)
+ }
result.Fail(file)
}
return nil
}
+
+func satisfy(content, license string, pattern *regexp.Regexp) bool {
+ if index := strings.Index(content, license); index >= 0 {
+ return index < LicenseLocationThreshold
+ }
+
+ if pattern == nil {
+ return false
+ }
+ index := pattern.FindStringIndex(content)
+
+ return len(index) == 2 && index[0] < LicenseLocationThreshold
+}
diff --git a/license-eye/pkg/header/check_test.go b/license-eye/pkg/header/check_test.go
new file mode 100644
index 0000000..2cc2de7
--- /dev/null
+++ b/license-eye/pkg/header/check_test.go
@@ -0,0 +1,143 @@
+//
+// 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 header
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "gopkg.in/yaml.v3"
+)
+
+var c struct {
+ Header ConfigHeader `yaml:"header"`
+}
+
+func init() {
+ content, err := ioutil.ReadFile("../../test/testdata/.licenserc_for_test_check.yaml")
+ if err != nil {
+ panic(err)
+ }
+ if err := yaml.Unmarshal(content, &c); err != nil {
+ panic(err)
+ }
+ if err := c.Header.Finalize(); err != nil {
+ panic(err)
+ }
+}
+
+func TestCheckFile(t *testing.T) {
+ type args struct {
+ name string
+ file string
+ result *Result
+ wantErr bool
+ hasFailure bool
+ }
+ tests := func() []args {
+ files, err := filepath.Glob("../../test/testdata/include_test/with_license/*")
+ if err != nil {
+ t.Error(err)
+ }
+
+ var cases []args
+
+ for _, file := range files {
+ cases = append(cases, args{
+ name: file,
+ file: file,
+ result: &Result{},
+ wantErr: false,
+ hasFailure: false,
+ })
+ }
+
+ return cases
+ }()
+
+ if len(tests) == 0 {
+ t.Errorf("Tests should not be empty")
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if strings.TrimSpace(c.Header.License) == "" {
+ t.Errorf("License should not be empty")
+ }
+ if err := CheckFile(tt.file, &c.Header, tt.result); (err != nil) != tt.wantErr {
+ t.Errorf("CheckFile() error = %v, wantErr %v", err, tt.wantErr)
+ }
+ if len(tt.result.Ignored) > 0 {
+ t.Errorf("Should not ignore any file, %v", tt.result.Ignored)
+ }
+ if tt.result.HasFailure() != tt.hasFailure {
+ t.Errorf("CheckFile() result has failure = %v, wanted = %v", tt.result.Failure, tt.hasFailure)
+ }
+ })
+ }
+}
+
+func TestCheckFileFailure(t *testing.T) {
+ type args struct {
+ name string
+ file string
+ result *Result
+ wantErr bool
+ hasFailure bool
+ }
+ tests := func() []args {
+ files, err := filepath.Glob("../../test/testdata/include_test/without_license/*")
+ if err != nil {
+ panic(err)
+ }
+
+ var cases []args
+
+ for _, file := range files {
+ cases = append(cases, args{
+ name: file,
+ file: file,
+ result: &Result{},
+ wantErr: false,
+ hasFailure: true,
+ })
+ }
+
+ return cases
+ }()
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if strings.TrimSpace(c.Header.License) == "" {
+ t.Errorf("License should not be empty")
+ }
+ if err := CheckFile(tt.file, &c.Header, tt.result); (err != nil) != tt.wantErr {
+ t.Errorf("CheckFile() error = %v, wantErr %v", err, tt.wantErr)
+ }
+ if len(tt.result.Ignored) > 0 {
+ t.Errorf("Should not ignore any file, %v", tt.result.Ignored)
+ }
+ if tt.result.HasFailure() != tt.hasFailure {
+ t.Errorf("CheckFile() result has failure = %v, wanted = %v", tt.result.Failure, tt.hasFailure)
+ }
+ })
+ }
+}
diff --git a/license-eye/pkg/header/config.go b/license-eye/pkg/header/config.go
index 0293d1f..8911cfc 100644
--- a/license-eye/pkg/header/config.go
+++ b/license-eye/pkg/header/config.go
@@ -18,7 +18,9 @@
package header
import (
+ "bufio"
"io/ioutil"
+ "os"
"regexp"
"strings"
@@ -36,17 +38,15 @@
}
// NormalizedLicense returns the normalized string of the license content,
-// "normalized" means the linebreaks and CommentChars are all trimmed.
+// "normalized" means the linebreaks and Punctuations are all trimmed.
func (config *ConfigHeader) NormalizedLicense() string {
var lines []string
for _, line := range strings.Split(config.License, "\n") {
if len(line) > 0 {
- line = strings.ToLower(strings.Trim(line, CommentChars))
- line = regexp.MustCompile(" +").ReplaceAllString(line, " ")
- lines = append(lines, line)
+ lines = append(lines, Punctuations.ReplaceAllString(line, " "))
}
}
- return strings.Join(lines, " ")
+ return strings.ToLower(regexp.MustCompile("(?m)[\\s\"']+").ReplaceAllString(strings.Join(lines, " "), " "))
}
func (config *ConfigHeader) NormalizedPattern() *regexp.Regexp {
@@ -57,11 +57,11 @@
var lines []string
for _, line := range strings.Split(config.Pattern, "\n") {
if len(line) > 0 {
- line = regexp.MustCompile("[ \"']+").ReplaceAllString(line, " ")
- lines = append(lines, strings.TrimSpace(line))
+ lines = append(lines, line)
}
}
- return regexp.MustCompile("(?i).*" + strings.Join(lines, " ") + ".*")
+ content := regexp.MustCompile("(?m)[\\s\"':;/\\-]+").ReplaceAllString(strings.Join(lines, " "), " ")
+ return regexp.MustCompile("(?i).*" + content + ".*")
}
// Parse reads and parses the header check configurations in config file.
@@ -89,6 +89,16 @@
return matched, err
}
}
+
+ if stat, err := os.Stat(path); err == nil {
+ for _, ignorePattern := range config.PathsIgnore {
+ ignorePattern = strings.TrimRight(ignorePattern, "/")
+ if strings.HasPrefix(path, ignorePattern+"/") || stat.Name() == ignorePattern {
+ return true, nil
+ }
+ }
+ }
+
return false, nil
}
@@ -99,5 +109,20 @@
config.Paths = []string{"**"}
}
+ config.PathsIgnore = append(config.PathsIgnore, ".git")
+
+ if file, err := os.Open(".gitignore"); err == nil {
+ defer func() { _ = file.Close() }()
+
+ for scanner := bufio.NewScanner(file); scanner.Scan(); {
+ line := scanner.Text()
+ if strings.HasPrefix(line, "#") || strings.TrimSpace(line) == "" {
+ continue
+ }
+ logger.Log.Debugln("Add ignore path from .gitignore:", line)
+ config.PathsIgnore = append(config.PathsIgnore, strings.TrimSpace(line))
+ }
+ }
+
return nil
}
diff --git a/license-eye/pkg/header/fix.go b/license-eye/pkg/header/fix.go
index a710106..40acde7 100644
--- a/license-eye/pkg/header/fix.go
+++ b/license-eye/pkg/header/fix.go
@@ -22,6 +22,7 @@
"fmt"
"io/ioutil"
"os"
+ "regexp"
"strings"
"github.com/apache/skywalking-eyes/license-eye/internal/logger"
@@ -60,12 +61,14 @@
return err
}
- lines, err := generateLicenseHeader(style, config)
+ licenseHeader, err := generateLicenseHeader(style, config)
if err != nil {
return err
}
- if err := ioutil.WriteFile(file, append([]byte(lines), content...), stat.Mode()); err != nil {
+ content = rewriteContent(style, content, licenseHeader)
+
+ if err := ioutil.WriteFile(file, content, stat.Mode()); err != nil {
return err
}
@@ -74,7 +77,22 @@
return nil
}
-// TODO: tackle with shebang and xml declaration
+func rewriteContent(style *comments.CommentStyle, content []byte, licenseHeader string) []byte {
+ if style.After == "" {
+ return append([]byte(licenseHeader), content...)
+ }
+
+ content = []byte(strings.TrimLeft(string(content), " \n"))
+ afterPattern := regexp.MustCompile(style.After)
+ location := afterPattern.FindIndex(content)
+ if location == nil || len(location) != 2 {
+ return append([]byte(licenseHeader), content...)
+ }
+ return append(content[0:location[1]],
+ append(append([]byte("\n"), []byte(licenseHeader)...), content[location[1]+1:]...)...,
+ )
+}
+
func generateLicenseHeader(style *comments.CommentStyle, config *ConfigHeader) (string, error) {
if err := style.Validate(); err != nil {
return "", err
@@ -82,7 +100,7 @@
middleLines := strings.Split(config.License, "\n")
for i, line := range middleLines {
- middleLines[i] = fmt.Sprintf("%v %v", style.Middle, line)
+ middleLines[i] = strings.TrimRight(fmt.Sprintf("%v %v", style.Middle, line), " ")
}
lines := fmt.Sprintf("%v\n%v\n", style.Start, strings.Join(middleLines, "\n"))
@@ -90,5 +108,5 @@
lines += style.End
}
- return lines, nil
+ return strings.TrimSpace(lines) + "\n", nil
}
diff --git a/license-eye/pkg/header/fix_test.go b/license-eye/pkg/header/fix_test.go
index a3ea449..c6f307f 100644
--- a/license-eye/pkg/header/fix_test.go
+++ b/license-eye/pkg/header/fix_test.go
@@ -1,85 +1,63 @@
+//
+// 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 header
import (
+ "reflect"
"testing"
"github.com/apache/skywalking-eyes/license-eye/pkg/comments"
)
var config = &ConfigHeader{
- License: `
-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.
-`,
+ License: `Apache License 2.0
+ http://www.apache.org/licenses/LICENSE-2.0
+Apache License 2.0`,
}
-func Test(t *testing.T) {
+func TestFix(t *testing.T) {
tests := []struct {
filename string
comments string
}{
{
filename: "Test.java",
- comments: `/*
- * 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.
- *
+ comments: `/*
+ * Apache License 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Apache License 2.0
*/
`,
},
{
filename: "Test.py",
comments: `#
-# 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.
-#
-#
+# Apache License 2.0
+# http://www.apache.org/licenses/LICENSE-2.0
+# Apache License 2.0
`,
},
}
for _, test := range tests {
t.Run(test.filename, func(t *testing.T) {
style := comments.FileCommentStyle(test.filename)
- if c, err := generateLicenseHeader(style, config); err != nil && c != test.comments {
+ if c, err := generateLicenseHeader(style, config); err != nil || c != test.comments {
t.Log("Actual:", c)
t.Log("Expected:", test.comments)
t.Logf("Middle:'%v'\n", style.Middle)
@@ -89,3 +67,155 @@
})
}
}
+
+func TestRewriteContent(t *testing.T) {
+ tests := []struct {
+ name string
+ style *comments.CommentStyle
+ content string
+ licenseHeader string
+ expectedContent string
+ }{
+ {
+ name: "Ocaml",
+ style: comments.FileCommentStyle("test.ml"),
+ content: `print_string "hello worlds!\n";;
+`,
+ licenseHeader: getLicenseHeader("test.ml", t.Error),
+ expectedContent: `(*
+(* Apache License 2.0
+(* http://www.apache.org/licenses/LICENSE-2.0
+(* Apache License 2.0
+print_string "hello worlds!\n";;
+`},
+ {
+ name: "Python with Shebang",
+ style: comments.FileCommentStyle("test.py"),
+ content: `
+#!/usr/bin/env python3
+if __name__ == '__main__':
+ print('Hello World')
+`,
+ licenseHeader: getLicenseHeader("test.py", t.Error),
+ expectedContent: `#!/usr/bin/env python3
+#
+# Apache License 2.0
+# http://www.apache.org/licenses/LICENSE-2.0
+# Apache License 2.0
+if __name__ == '__main__':
+ print('Hello World')
+`},
+ {
+ name: "Python",
+ style: comments.FileCommentStyle("test.py"),
+ content: `
+if __name__ == '__main__':
+ print('Hello World')
+`,
+ licenseHeader: getLicenseHeader("test.py", t.Error),
+ expectedContent: `#
+# Apache License 2.0
+# http://www.apache.org/licenses/LICENSE-2.0
+# Apache License 2.0
+if __name__ == '__main__':
+ print('Hello World')
+`},
+ {
+ name: "XML one line declaration",
+ style: comments.FileCommentStyle("test.xml"),
+ content: `
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+ <modelVersion>4.0.0</modelVersion>
+</project>
+`,
+ licenseHeader: getLicenseHeader("test.xml", t.Error),
+ expectedContent: `<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Apache License 2.0
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~ Apache License 2.0
+-->
+<project>
+ <modelVersion>4.0.0</modelVersion>
+</project>
+`},
+ {
+ name: "XML multi-line declaration",
+ style: comments.FileCommentStyle("test.xml"),
+ content: `
+<?xml
+ version="1.0"
+ encoding="UTF-8"
+?>
+<project>
+ <modelVersion>4.0.0</modelVersion>
+</project>
+`,
+ licenseHeader: getLicenseHeader("test.xml", t.Error),
+ expectedContent: `<?xml
+ version="1.0"
+ encoding="UTF-8"
+?>
+<!--
+ ~ Apache License 2.0
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~ Apache License 2.0
+-->
+<project>
+ <modelVersion>4.0.0</modelVersion>
+</project>
+`},
+ {
+ name: "SQL",
+ style: comments.FileCommentStyle("test.sql"),
+ content: `select * from user;`,
+ licenseHeader: getLicenseHeader("test.sql", t.Error),
+ expectedContent: `--
+-- Apache License 2.0
+-- http://www.apache.org/licenses/LICENSE-2.0
+-- Apache License 2.0
+select * from user;`},
+ {
+ name: "Haskell",
+ style: comments.FileCommentStyle("test.hs"),
+ content: `import Foundation.Hashing.Hashable`,
+ licenseHeader: getLicenseHeader("test.hs", t.Error),
+ expectedContent: `{-
+ Apache License 2.0
+ http://www.apache.org/licenses/LICENSE-2.0
+ Apache License 2.0
+-}
+import Foundation.Hashing.Hashable`},
+ {
+ name: "Vim",
+ style: comments.FileCommentStyle("test.vim"),
+ content: `echo 'Hello' | echo 'world!'
+`,
+ licenseHeader: getLicenseHeader("test.vim", t.Error),
+ expectedContent: `"
+" Apache License 2.0
+" http://www.apache.org/licenses/LICENSE-2.0
+" Apache License 2.0
+echo 'Hello' | echo 'world!'
+`},
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ content := rewriteContent(test.style, []byte(test.content), test.licenseHeader)
+ if !reflect.DeepEqual(content, []byte(test.expectedContent)) {
+ t.Log("Actual\n" + string(content))
+ t.Log("Expected\n" + test.expectedContent)
+ t.Fail()
+ }
+ })
+ }
+}
+
+func getLicenseHeader(filename string, tError func(args ...interface{})) string {
+ s, err := generateLicenseHeader(comments.FileCommentStyle(filename), config)
+ if err != nil {
+ tError(err)
+ }
+ return s
+}
diff --git a/license-eye/test/testdata/.licenserc_for_test_check.yaml b/license-eye/test/testdata/.licenserc_for_test_check.yaml
index 1ae329e..eee7d39 100644
--- a/license-eye/test/testdata/.licenserc_for_test_check.yaml
+++ b/license-eye/test/testdata/.licenserc_for_test_check.yaml
@@ -18,7 +18,7 @@
under the License.
paths:
- - 'testdata/**'
+ - 'test/testdata/**'
paths-ignore:
- '**/.DS_Store'
diff --git a/license-eye/test/testdata/.licenserc_for_test_fix.yaml b/license-eye/test/testdata/.licenserc_for_test_fix.yaml
index 008e9f4..facb12f 100644
--- a/license-eye/test/testdata/.licenserc_for_test_fix.yaml
+++ b/license-eye/test/testdata/.licenserc_for_test_fix.yaml
@@ -18,7 +18,7 @@
under the License.
paths:
- - 'testdata/include_test/**'
+ - 'test/testdata/include_test/**'
paths-ignore:
- '**/.DS_Store'
diff --git a/license-eye/test/testdata/include_test/with_license/testcase.go b/license-eye/test/testdata/include_test/with_license/testcase.go
index c382b60..9b47627 100644
--- a/license-eye/test/testdata/include_test/with_license/testcase.go
+++ b/license-eye/test/testdata/include_test/with_license/testcase.go
@@ -2,7 +2,8 @@
// 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
+// 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
//
diff --git a/license-eye/test/testdata/include_test/with_license/testcase.java b/license-eye/test/testdata/include_test/with_license/testcase.java
index a388cbc..c24ce1f 100644
--- a/license-eye/test/testdata/include_test/with_license/testcase.java
+++ b/license-eye/test/testdata/include_test/with_license/testcase.java
@@ -1,9 +1,12 @@
/**
- * Licensed to Apache Software Foundation (ASF) under one or more contributor
+ * 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
+ * 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
*
@@ -12,7 +15,7 @@
* 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
+ * KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
diff --git a/license-eye/test/testdata/include_test/with_license/testcase.ml b/license-eye/test/testdata/include_test/with_license/testcase.ml
new file mode 100644
index 0000000..246ff88
--- /dev/null
+++ b/license-eye/test/testdata/include_test/with_license/testcase.ml
@@ -0,0 +1,19 @@
+(* 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.
+
+let to_string = function Left -> "Left" | Non -> "Non" | Right -> "Right"
diff --git a/license-eye/test/testdata/include_test/without_license/testcase.py b/license-eye/test/testdata/include_test/without_license/testcase.py
index 5030e1c..ce55ff9 100644
--- a/license-eye/test/testdata/include_test/without_license/testcase.py
+++ b/license-eye/test/testdata/include_test/without_license/testcase.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
# Esse enim dolore adipisicing in cillum eiusmod excepteur quis nisi sit dolor anim anim id id nostrud nostrud tempor.
# Elit sit enim cillum adipisicing non magna aute nostrud ullamco dolor dolore consequat ut ea occaecat veniam incididunt
# occaecat consectetur eiusmod sint eiusmod aute eu duis fugiat dolore in laboris enim eiusmod aliquip nisi aliqua irure