Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
Signed-off-by: Evsyukov Denis <denis.evsyukov@flant.com>
  • Loading branch information
juev committed Sep 17, 2024
1 parent cc85002 commit a84fb8c
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 98 deletions.
8 changes: 8 additions & 0 deletions pkg/config/linters_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,15 @@ var defaultLintersSettings = LintersSettings{
SkipDocRe: `doc-ru-.+\.ya?ml$|_RU\.md$|_ru\.html$|docs/site/_.+|docs/documentation/_.+|tools/spelling/.+`,
SkipI18NRe: `/i18n/`,
},
Copyright: CopyrightSettings{
CopyrightExcludes: map[string]struct{}{},
},
}

type LintersSettings struct {
OpenAPI OpenAPISettings
NoCyrillic NoCyrillicSettings
Copyright CopyrightSettings
Custom map[string]CustomLinterSettings
}

Expand Down Expand Up @@ -207,3 +211,7 @@ type NoCyrillicSettings struct {
SkipI18NRe string `mapstructure:"skip-i18n-re"`
SkipSelfRe string `mapstructure:"skip-self-re"`
}

type CopyrightSettings struct {
CopyrightExcludes map[string]struct{} `mapstructure:"copyright-excludes"`
}
161 changes: 63 additions & 98 deletions pkg/linters/copyright/copyright.go
Original file line number Diff line number Diff line change
@@ -1,128 +1,93 @@
package copyright

import (
"fmt"
"os"
"regexp"
"path/filepath"
"strings"
)

var EELicenseRe = regexp.MustCompile(`(?s)Copyright 202[1-9] Flant JSC.*Licensed under the Deckhouse Platform Enterprise Edition \(EE\) license.*See https://github.com/deckhouse/deckhouse/blob/main/ee/LICENSE`)
"github.com/deckhouse/d8-lint/pkg/config"
"github.com/deckhouse/d8-lint/pkg/errors"
"github.com/deckhouse/d8-lint/pkg/module"
)

var CELicenseRe = regexp.MustCompile(`(?s)[/#{!-]*(\s)*Copyright 202[1-9] Flant JSC[-!}\n#/]*
[/#{!-]*(\s)*Licensed under the Apache License, Version 2.0 \(the \"License\"\);[-!}\n]*
[/#{!-]*(\s)*you may not use this file except in compliance with the License.[-!}\n]*
[/#{!-]*(\s)*You may obtain a copy of the License at[-!}\n#/]*
[/#{!-]*(\s)*http://www.apache.org/licenses/LICENSE-2.0[-!}\n#/]*
[/#{!-]*(\s)*Unless required by applicable law or agreed to in writing, software[-!}\n]*
[/#{!-]*(\s)*distributed under the License is distributed on an \"AS IS\" BASIS,[-!}\n]*
[/#{!-]*(\s)*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.[-!}\n]*
[/#{!-]*(\s)*See the License for the specific language governing permissions and[-!}\n]*
[/#{!-]*(\s)*limitations under the License.[-!}\n]*`)
// Copyright linter
type Copyright struct {
name, desc string
cfg *config.CopyrightSettings
}

var fileToCheckRe = regexp.MustCompile(`\.go$|/[^/.]+$|\.sh$|\.lua$|\.py$|^\.github/(scripts|workflows|workflow_templates)/.+\.(js|yml|yaml|sh)$`)
var fileToSkipRe = regexp.MustCompile(`geohash.lua$|\.github/CODEOWNERS|Dockerfile$|Makefile$|/docs/documentation/|/docs/site/|bashrc$|inputrc$|modules_menu_skip$|LICENSE$|tools/spelling/.+`)
type Module interface {
GetName() string
GetPath() string
}

func RunCopyrightValidation(info *DiffInfo) (exitCode int) {
fmt.Printf("Run 'copyright' validation ...\n")
func New(cfg *config.CopyrightSettings) *Copyright {
return &Copyright{
name: "copyright",
desc: "Copyright will check all files in the modules for contains copyright",
cfg: cfg,
}
}

if len(info.Files) == 0 {
fmt.Printf("Nothing to validate, diff is empty\n")
os.Exit(0)
func (o *Copyright) Run(m *module.Module) (errors.LintRuleErrorsList, error) {
files, err := o.getFiles(m.GetPath())
if err != nil {
return errors.LintRuleErrorsList{}, err
}

exitCode = 0
msgs := NewMessages()
for _, fileInfo := range info.Files {
if !fileInfo.HasContent() {
var result errors.LintRuleErrorsList
for _, fileName := range files {
name, _ := strings.CutPrefix(fileName, m.GetPath())
name = m.GetName() + ":" + name
if _, ok := o.cfg.CopyrightExcludes[name]; ok {
continue
}

fileName := fileInfo.NewFileName

if fileToCheckRe.MatchString(fileName) && !fileToSkipRe.MatchString(fileName) {
msgs.Add(checkFileCopyright(fileName))
} else {
msgs.Add(NewSkip(fileName, ""))
ok, er := checkFileCopyright(fileName)
if !ok {
path, _ := strings.CutPrefix(fileName, m.GetPath())
result.Add(errors.NewLintRuleError(
"copyright",
path,
er,
"errors in `%s` module",
m.GetName(),
))
}
}
msgs.PrintReport()

if msgs.CountErrors() > 0 {
exitCode = 1
}

return exitCode
return result, nil
}

var copyrightOrAutogenRe = regexp.MustCompile(`Copyright The|autogenerated|DO NOT EDIT`)
var copyrightRe = regexp.MustCompile(`Copyright`)
var flantRe = regexp.MustCompile(`Flant|Deckhouse`)
func (o *Copyright) getFiles(rootPath string) ([]string, error) {

Check failure on line 62 in pkg/linters/copyright/copyright.go

View workflow job for this annotation

GitHub Actions / golangci-lint

unused-receiver: method receiver 'o' is not referenced in method's body, consider removing or renaming it as _ (revive)
var result []string
err := filepath.Walk(rootPath, func(path string, info os.FileInfo, _ error) error {
if info.Mode()&os.ModeSymlink != 0 {
return filepath.SkipDir
}

// checkFileCopyright returns true if file is readable and has no copyright information in it.
func checkFileCopyright(fName string) Message {
// Original script 'validate_copyright.sh' used 'head -n 10'.
// Here we just read first 1024 bytes.
headBuf, err := readFileHead(fName, 1024)
if err != nil {
return NewSkip(fName, err.Error())
}
if info.IsDir() {
if info.Name() == ".git" {
return filepath.SkipDir
}

// Skip autogenerated file or file already has other than Flant copyright
if copyrightOrAutogenRe.Match(headBuf) {
return NewSkip(fName, "generated code or other license")
}
return nil
}

// Check Flant license if file contains keywords.
if flantRe.Match(headBuf) {
return checkFlantLicense(fName, headBuf)
}
if fileToCheckRe.MatchString(path) && !fileToSkipRe.MatchString(path) {
result = append(result, path)
}

// Skip file with some other copyright
if copyrightRe.Match(headBuf) {
return NewSkip(fName, "contains other license")
}
return nil
})

return NewError(fName, "no copyright or license information", "")
return result, err
}

func checkFlantLicense(fName string, buf []byte) Message {
if strings.HasPrefix(fName, "/ee/") || strings.HasPrefix(fName, "ee/") {
if !EELicenseRe.Match(buf) {
return NewError(fName, "EE related file should contain EE license", "")
}
} else {
if !CELicenseRe.Match(buf) {
return NewError(fName, "should contain CE license", "")
}
}

return NewOK(fName)
func (o *Copyright) Name() string {
return o.name
}

func readFileHead(fName string, size int) ([]byte, error) {
file, err := os.Open(fName)
if err != nil {
return nil, err
}
defer file.Close()

fi, err := file.Stat()
if err != nil {
return nil, err
}
if fi.IsDir() {
return nil, fmt.Errorf("directory")
}
if fi.Mode()&os.ModeSymlink != 0 {
return nil, fmt.Errorf("symlink")
}

headBuf := make([]byte, size)
_, err = file.Read(headBuf)
if err != nil {
return nil, err
}

return headBuf, nil
func (o *Copyright) Desc() string {
return o.desc
}
97 changes: 97 additions & 0 deletions pkg/linters/copyright/library.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package copyright

import (
"errors"
"fmt"
"os"
"regexp"
"strings"
)

var EELicenseRe = regexp.MustCompile(`(?s)Copyright 202[1-9] Flant JSC.*Licensed under the Deckhouse Platform Enterprise Edition \(EE\) license.*See https://github.com/deckhouse/deckhouse/blob/main/ee/LICENSE`)

Check failure on line 11 in pkg/linters/copyright/library.go

View workflow job for this annotation

GitHub Actions / golangci-lint

regexpPattern: '.com' should probably be '\.com' (gocritic)

var CELicenseRe = regexp.MustCompile(`(?s)[/#{!-]*(\s)*Copyright 202[1-9] Flant JSC[-!}\n#/]*

Check failure on line 13 in pkg/linters/copyright/library.go

View workflow job for this annotation

GitHub Actions / golangci-lint

regexpPattern: '.org' should probably be '\.org' (gocritic)
[/#{!-]*(\s)*Licensed under the Apache License, Version 2.0 \(the "License"\);[-!}\n]*
[/#{!-]*(\s)*you may not use this file except in compliance with the License.[-!}\n]*
[/#{!-]*(\s)*You may obtain a copy of the License at[-!}\n#/]*
[/#{!-]*(\s)*http://www.apache.org/licenses/LICENSE-2.0[-!}\n#/]*
[/#{!-]*(\s)*Unless required by applicable law or agreed to in writing, software[-!}\n]*
[/#{!-]*(\s)*distributed under the License is distributed on an "AS IS" BASIS,[-!}\n]*
[/#{!-]*(\s)*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.[-!}\n]*
[/#{!-]*(\s)*See the License for the specific language governing permissions and[-!}\n]*
[/#{!-]*(\s)*limitations under the License.[-!}\n]*`)

var fileToCheckRe = regexp.MustCompile(`\.go$|/[^/.]+$|\.sh$|\.lua$|\.py$|^\.github/(scripts|workflows|workflow_templates)/.+\.(js|yml|yaml|sh)$`)
var fileToSkipRe = regexp.MustCompile(`geohash.lua$|\.github/CODEOWNERS|Dockerfile$|Makefile$|/docs/documentation/|/docs/site/|bashrc$|inputrc$|modules_menu_skip$|LICENSE$|tools/spelling/.+`)

var copyrightOrAutogenRe = regexp.MustCompile(`Copyright The|autogenerated|DO NOT EDIT`)
var copyrightRe = regexp.MustCompile(`Copyright`)
var flantRe = regexp.MustCompile(`Flant|Deckhouse`)

// checkFileCopyright returns true if file is readable and has no copyright information in it.
func checkFileCopyright(fName string) (bool, error) {
// Original script 'validate_copyright.sh' used 'head -n 10'.
// Here we just read first 1024 bytes.
headBuf, err := readFileHead(fName, 1024)
if err != nil {
return false, err
}

// Skip autogenerated file or file already has other than Flant copyright
if copyrightOrAutogenRe.Match(headBuf) {
return true, errors.New("generated code or other license")
}

// Check Flant license if file contains keywords.
if flantRe.Match(headBuf) {
return true, nil
}

// Skip file with some other copyright
if copyrightRe.Match(headBuf) {
return true, errors.New("contains other license")
}

return false, errors.New("no copyright or license information")
}

func checkFlantLicense(fName string, buf []byte) error {

Check failure on line 58 in pkg/linters/copyright/library.go

View workflow job for this annotation

GitHub Actions / golangci-lint

func `checkFlantLicense` is unused (unused)
if strings.HasPrefix(fName, "/ee/") || strings.HasPrefix(fName, "ee/") {
if !EELicenseRe.Match(buf) {
return errors.New("EE related file should contain EE license")
}
} else {
if !CELicenseRe.Match(buf) {
return errors.New("should contain CE license")
}
}

return nil
}

func readFileHead(fName string, size int) ([]byte, error) {
file, err := os.Open(fName)
if err != nil {
return nil, err
}
defer file.Close()

fi, err := file.Stat()
if err != nil {
return nil, err
}
if fi.IsDir() {
return nil, fmt.Errorf("directory")
}
if fi.Mode()&os.ModeSymlink != 0 {
return nil, fmt.Errorf("symlink")
}

headBuf := make([]byte, size)
_, err = file.Read(headBuf)
if err != nil {
return nil, err
}

return headBuf, nil
}
File renamed without changes.
2 changes: 2 additions & 0 deletions pkg/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/deckhouse/d8-lint/pkg/config"
"github.com/deckhouse/d8-lint/pkg/errors"
"github.com/deckhouse/d8-lint/pkg/linters/copyright"
no_cyrillic "github.com/deckhouse/d8-lint/pkg/linters/no-cyrillic"
"github.com/deckhouse/d8-lint/pkg/linters/openapi"
"github.com/deckhouse/d8-lint/pkg/logger"
Expand Down Expand Up @@ -37,6 +38,7 @@ func NewManager(dirs []string, cfg *config.Config) *Manager {
m.Linters = []Linter{
openapi.New(&cfg.LintersSettings.OpenAPI),
no_cyrillic.New(&cfg.LintersSettings.NoCyrillic),
copyright.New(&cfg.LintersSettings.Copyright),
}

m.lintersMap = make(map[string]Linter)
Expand Down

0 comments on commit a84fb8c

Please sign in to comment.