diff --git a/.github/workflows/golint.yml b/.github/workflows/golint.yml index 4bbea0171..c2ccc6c2b 100644 --- a/.github/workflows/golint.yml +++ b/.github/workflows/golint.yml @@ -1,4 +1,4 @@ -name: golangci-lint +name: golang-lint on: push: tags: @@ -13,7 +13,7 @@ permissions: # pull-requests: read jobs: golangci: - name: lint + name: golangci-lint runs-on: ubuntu-latest steps: - run: | @@ -47,3 +47,12 @@ jobs: # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. # skip-build-cache: true + validate-go: + name: validate-go + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v3 + with: + go-version: 1.17 + - uses: actions/checkout@v3 + - run: make validate-go-action diff --git a/.pipelines/ci.yml b/.pipelines/ci.yml index 9e39902ef..39d209b21 100644 --- a/.pipelines/ci.yml +++ b/.pipelines/ci.yml @@ -46,12 +46,6 @@ jobs: [[ -z "$(git status -s)" ]] displayName: ⚙️ Run Golang code generate - - script: | - set -xe - make validate-go - [[ -z "$(git status -s)" ]] - displayName: 🕵️ Validate Golang code - - script: | set -xe make build-all diff --git a/Makefile b/Makefile index 92bac5060..e9a0d3fa6 100644 --- a/Makefile +++ b/Makefile @@ -158,6 +158,13 @@ validate-go: go vet ./... go test -tags e2e -run ^$$ ./test/e2e/... +validate-go-action: + go run ./hack/licenses -validate -ignored-go vendor,pkg/client,.git -ignored-python python/client,vendor,.git + go run ./hack/validate-imports cmd hack pkg test + @[ -z "$$(ls pkg/util/*.go 2>/dev/null)" ] || (echo error: go files are not allowed in pkg/util, use a subpackage; exit 1) + @[ -z "$$(find -name "*:*")" ] || (echo error: filenames with colons are not allowed on Windows, please rename; exit 1) + @sha256sum --quiet -c .sha256sum || (echo error: client library is stale, please run make client; exit 1) + validate-fips: hack/fips/validate-fips.sh diff --git a/hack/licenses/licenses.go b/hack/licenses/licenses.go deleted file mode 100644 index 72152ad92..000000000 --- a/hack/licenses/licenses.go +++ /dev/null @@ -1,129 +0,0 @@ -package main - -// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0. - -import ( - "bytes" - "io/ioutil" - "os" - "path/filepath" - "strings" -) - -var ( - goLicense = []byte(`// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0.`) - - pythonLicense = []byte(`# Copyright (c) Microsoft Corporation. -# Licensed under the Apache License 2.0.`) -) - -func applyGoLicense() error { - return filepath.Walk(".", func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - switch path { - case "pkg/client", "vendor", ".git": - return filepath.SkipDir - } - - if !strings.HasSuffix(path, ".go") { - return nil - } - - b, err := ioutil.ReadFile(path) - if err != nil { - return err - } - - if bytes.Contains(b, []byte("DO NOT EDIT.")) { - return nil - } - - if !bytes.Contains(b, goLicense) { - i := bytes.Index(b, []byte("package ")) - i += bytes.Index(b[i:], []byte("\n")) - - var bb []byte - bb = append(bb, b[:i]...) - bb = append(bb, []byte("\n\n")...) - bb = append(bb, goLicense...) - bb = append(bb, b[i:]...) - - err = ioutil.WriteFile(path, bb, 0666) - if err != nil { - return err - } - } - - return nil - }) -} - -func applyPythonLicense() error { - return filepath.Walk(".", func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if strings.HasPrefix(path, "pyenv") { - return filepath.SkipDir - } - - switch path { - case "python/client", "vendor": - return filepath.SkipDir - } - - if !strings.HasSuffix(path, ".py") { - return nil - } - - b, err := ioutil.ReadFile(path) - if err != nil { - return err - } - - if !bytes.Contains(b, pythonLicense) { - var bb []byte - - if bytes.HasPrefix(b, []byte("#!")) { - i := bytes.Index(b, []byte("\n")) - - bb = append(bb, b[:i]...) - bb = append(bb, []byte("\n\n")...) - bb = append(bb, pythonLicense...) - bb = append(bb, b[i:]...) - } else { - bb = append(bb, pythonLicense...) - bb = append(bb, []byte("\n\n")...) - bb = append(bb, b...) - } - - err = ioutil.WriteFile(path, bb, 0666) - if err != nil { - return err - } - } - - return nil - }) -} - -func run() error { - err := applyGoLicense() - if err != nil { - return err - } - - return applyPythonLicense() -} - -func main() { - if err := run(); err != nil { - panic(err) - } -} diff --git a/hack/licenses/main.go b/hack/licenses/main.go new file mode 100644 index 000000000..e4e9243c6 --- /dev/null +++ b/hack/licenses/main.go @@ -0,0 +1,252 @@ +package main + +// Copyright (c) Microsoft Corporation. +// Licensed under the Apache License 2.0. + +import ( + "bytes" + "errors" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" +) + +var ( + goLicense = []byte(`// Copyright (c) Microsoft Corporation. +// Licensed under the Apache License 2.0.`) + + pythonLicense = []byte(`# Copyright (c) Microsoft Corporation. +# Licensed under the Apache License 2.0.`) +) + +func main() { + ignoredGo := flag.String("ignored-go", "", "comma separated list of ignored directories") + ignoredPython := flag.String("ignored-python", "", "comma separated list of ignored directories") + dirs := flag.String("dirs", ".", "comma separated list of dirs to parse") + validateOnly := flag.Bool("validate", false, "only validates and does not modify (for CI)") + flag.Parse() + + if *validateOnly { + err := validateLicenses(*ignoredGo, *ignoredPython, *dirs) + if err != nil { + os.Exit(1) + } + os.Exit(0) + } else { + if err := run(); err != nil { + log.Fatalf("error while checking for licences. err: %s ", err) + } + } +} + +func run() error { + err := applyGoLicense() + if err != nil { + return err + } + + return applyPythonLicense() +} + +func applyGoLicense() error { + return filepath.Walk(".", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + switch path { + case "pkg/client", "vendor", ".git": + return filepath.SkipDir + } + + if !strings.HasSuffix(path, ".go") { + return nil + } + + b, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + if bytes.Contains(b, []byte("DO NOT EDIT.")) { + return nil + } + + if !bytes.Contains(b, goLicense) { + i := bytes.Index(b, []byte("package ")) + i += bytes.Index(b[i:], []byte("\n")) + + var bb []byte + bb = append(bb, b[:i]...) + bb = append(bb, []byte("\n\n")...) + bb = append(bb, goLicense...) + bb = append(bb, b[i:]...) + + err = ioutil.WriteFile(path, bb, 0666) + if err != nil { + return err + } + } + + return nil + }) +} + +func applyPythonLicense() error { + return filepath.Walk(".", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if strings.HasPrefix(path, "pyenv") { + return filepath.SkipDir + } + + switch path { + case "python/client", "vendor": + return filepath.SkipDir + } + + if !strings.HasSuffix(path, ".py") { + return nil + } + + b, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + if !bytes.Contains(b, pythonLicense) { + var bb []byte + + if bytes.HasPrefix(b, []byte("#!")) { + i := bytes.Index(b, []byte("\n")) + + bb = append(bb, b[:i]...) + bb = append(bb, []byte("\n\n")...) + bb = append(bb, pythonLicense...) + bb = append(bb, b[i:]...) + } else { + bb = append(bb, pythonLicense...) + bb = append(bb, []byte("\n\n")...) + bb = append(bb, b...) + } + + err = ioutil.WriteFile(path, bb, 0666) + if err != nil { + return err + } + } + + return nil + }) +} + +//returns the lists of files that don't have a license but should +func validateGoLicenses(ignored map[string]bool, dirs []string) []string { + unlicensedFiles := make([]string, 0) + for _, dir := range dirs { + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if ignored[path] { + return filepath.SkipDir + } + + if !strings.HasSuffix(path, ".go") { + return nil + } + + b, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + if bytes.Contains(b, []byte("DO NOT EDIT.")) { + return nil + } + + if !bytes.Contains(b, goLicense) { + unlicensedFiles = append(unlicensedFiles, path) + } + return nil + }) + } + + return unlicensedFiles +} + +//returns the lists of files that don't have a license but should +func validatePythonLicenses(ignored map[string]bool, dirs []string) []string { + unlicensedFiles := make([]string, 0) + + for _, dir := range dirs { + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if strings.HasPrefix(path, "pyenv") { + return filepath.SkipDir + } + + if ignored[path] { + return filepath.SkipDir + } + + if !strings.HasSuffix(path, ".py") { + return nil + } + + b, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + if !bytes.Contains(b, pythonLicense) { + unlicensedFiles = append(unlicensedFiles, path) + } + return nil + }) + } + + return unlicensedFiles +} + +func parseIgnored(commaSeparated string) map[string]bool { + ignored := strings.Split(commaSeparated, ",") + + result := make(map[string]bool) + for _, v := range ignored { + result[v] = true + } + return result +} + +func validateLicenses(ignoredGo, ignoredPython, dirs string) error { + ignoredMapGo := parseIgnored(ignoredGo) + ignoredMapPython := parseIgnored(ignoredPython) + + unlicensedGo := validateGoLicenses(ignoredMapGo, strings.Split(dirs, ",")) + + unlicensedPython := validatePythonLicenses(ignoredMapPython, strings.Split(dirs, ",")) + + for _, v := range unlicensedGo { + fmt.Printf("%s does not have a license\n", v) + } + + for _, v := range unlicensedPython { + fmt.Printf("%s does not have a license\n", v) + } + + if len(unlicensedGo) > 0 || len(unlicensedPython) > 0 { + return errors.New("validation failed") + } + return nil +}