From ebed4b31cc2e6f10914850ffba9cd73fca803333 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Apr 2019 23:46:48 +0300 Subject: [PATCH] feat: implement `skipPaths` option for 'license' policy (#121) Signed-off-by: Andrey Smirnov --- .bettercodehub.yml | 9 -- .codebeatignore | 4 - .conform.yaml | 2 +- .drone.yml | 63 ++++++++++++ Dockerfile | 6 +- Makefile | 16 +-- README.md | 3 + hack/golangci-lint.yaml | 2 + hack/test.sh | 30 +----- internal/policy/commit/commit.go | 8 +- internal/policy/commit/commit_test.go | 139 +++++++++++--------------- internal/policy/license/license.go | 26 +++++ 12 files changed, 173 insertions(+), 135 deletions(-) delete mode 100644 .bettercodehub.yml delete mode 100644 .codebeatignore create mode 100644 .drone.yml diff --git a/.bettercodehub.yml b/.bettercodehub.yml deleted file mode 100644 index bc3e198b..00000000 --- a/.bettercodehub.yml +++ /dev/null @@ -1,9 +0,0 @@ -exclude: -- /vendor/.* -- /docs/.* -- /website/.* -- brigade.js -component_depth: 1 -languages: -- go -- script diff --git a/.codebeatignore b/.codebeatignore deleted file mode 100644 index 48377e9e..00000000 --- a/.codebeatignore +++ /dev/null @@ -1,4 +0,0 @@ -docs/** -vendor/** -website/** -brigade.js diff --git a/.conform.yaml b/.conform.yaml index d0af3baf..912f9a4a 100644 --- a/.conform.yaml +++ b/.conform.yaml @@ -3,7 +3,7 @@ policies: spec: headerLength: 89 dco: true - gpg: true + gpg: false imperative: true conventional: types: diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 00000000..29769000 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,63 @@ +kind: pipeline +name: default + +services: +- name: docker + image: docker:dind + privileged: true + volumes: + - name: dockersock + path: /var/run + +steps: + - name: enforce + image: autonomy/build-container:latest + pull: always + commands: + - make build + - build/conform-linux-amd64 enforce + volumes: + - name: dockersock + path: /var/run + + - name: test + image: autonomy/build-container:latest + pull: always + commands: + - make test + volumes: + - name: dockersock + path: /var/run + + - name: image + image: autonomy/build-container:latest + pull: always + commands: + - make image + volumes: + - name: dockersock + path: /var/run + + - name: push + image: autonomy/build-container:latest + pull: always + environment: + DOCKER_USERNAME: + from_secret: docker_username + DOCKER_PASSWORD: + from_secret: docker_password + commands: + - make login + - make push + volumes: + - name: dockersock + path: /var/run + when: + branch: + - master + event: + - push + +volumes: +- name: dockersock + temp: {} diff --git a/Dockerfile b/Dockerfile index 71ac4570..7e41396f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,10 +5,12 @@ ENV CGO_ENABLED 0 ENV GO111MODULES on WORKDIR /conform -COPY ./ ./ +COPY go.mod ./ +COPY go.sum ./ RUN go mod download RUN go mod verify -RUN go mod tidy +COPY ./ ./ +RUN go list -mod=readonly all FROM common AS build ARG TAG diff --git a/Makefile b/Makefile index 75fa24f8..1e54917d 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ SHA := $(shell gitmeta git sha) TAG := $(shell gitmeta image tag) BUILT := $(shell gitmeta built) -GOLANG_IMAGE ?= golang:1.11.4 +GOLANG_IMAGE ?= golang:1.12.3 COMMON_ARGS := -f ./Dockerfile --build-arg GOLANG_IMAGE=$(GOLANG_IMAGE) --build-arg SHA=$(SHA) --build-arg TAG=$(TAG) --build-arg BUILT="$(BUILT)" . @@ -19,15 +19,15 @@ build: -t conform/$@:$(TAG) \ --target=$@ \ $(COMMON_ARGS) - @docker run --rm -it -v $(PWD)/build:/build conform/$@:$(TAG) cp /conform-linux-amd64 /build - @docker run --rm -it -v $(PWD)/build:/build conform/$@:$(TAG) cp /conform-darwin-amd64 /build + @docker run --rm -v $(PWD)/build:/build conform/$@:$(TAG) cp /conform-linux-amd64 /build + @docker run --rm -v $(PWD)/build:/build conform/$@:$(TAG) cp /conform-darwin-amd64 /build test: @docker build \ -t conform/$@:$(TAG) \ --target=$@ \ $(COMMON_ARGS) - @docker run --rm -it -v $(PWD)/build:/build conform/$@:$(TAG) cp /coverage.txt /build + @docker run --rm -v $(PWD)/build:/build conform/$@:$(TAG) cp /coverage.txt /build image: build @docker build \ @@ -35,14 +35,18 @@ image: build --target=$@ \ $(COMMON_ARGS) +.PHONY: login +login: + @docker login --username $(DOCKER_USERNAME) --password $(DOCKER_PASSWORD) + push: image @docker tag autonomy/conform:$(TAG) autonomy/conform:latest @docker push autonomy/conform:$(TAG) @docker push autonomy/conform:latest deps: - @GO111MODULES=on CGO_ENABLED=0 go get -u github.com/autonomy/gitmeta - @GO111MODULES=on CGO_ENABLED=0 go get -u github.com/autonomy/conform + @GO111MODULE=on CGO_ENABLED=0 go get -u github.com/autonomy/gitmeta + @GO111MODULE=on CGO_ENABLED=0 go get -u github.com/autonomy/conform clean: go clean -modcache diff --git a/README.md b/README.md index e427992b..0837f881 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,9 @@ policies: - "scope" - type: license spec: + skipPaths: + - .git/ + - .build*/ includeSuffixes: - .ext excludeSuffixes: diff --git a/hack/golangci-lint.yaml b/hack/golangci-lint.yaml index 896cfc63..03cc7e3a 100644 --- a/hack/golangci-lint.yaml +++ b/hack/golangci-lint.yaml @@ -99,6 +99,8 @@ linters: disable: - gas - typecheck + - gochecknoglobals + - gochecknoinits disable-all: false fast: false diff --git a/hack/test.sh b/hack/test.sh index e4f6e3d2..468325ca 100755 --- a/hack/test.sh +++ b/hack/test.sh @@ -3,12 +3,11 @@ set -e CGO_ENABLED=1 -GOPACKAGES=$(go list ./...) lint_packages() { if [ "${lint}" = true ]; then echo "linting packages" - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $GOPATH/bin v1.10.1 + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $GOPATH/bin v1.16.0 golangci-lint run --config "${BASH_SOURCE%/*}/golangci-lint.yaml" fi } @@ -21,33 +20,13 @@ go_test() { if [ "${tests}" = true ]; then echo "performing tests" - go test -v ./... - fi -} - -coverage_tests() { - if [ "${coverage}" = true ]; then - echo "performing coverage tests" - local coverage_report="/coverage.txt" - local profile="/profile.out" - if [[ -f ${coverage_report} ]]; then - rm ${coverage_report} - fi - touch ${coverage_report} - for package in ${GOPACKAGES[@]}; do - go test -v -short -race -coverprofile=${profile} -covermode=atomic $package - if [ -f ${profile} ]; then - cat ${profile} >> ${coverage_report} - rm ${profile} - fi - done + go test -v -race -covermode=atomic -coverprofile=/coverage.txt ./... fi } lint=false short=false tests=false -coverage=false case $1 in --lint) @@ -59,21 +38,16 @@ case $1 in --integration) tests=true ;; - --coverage) - coverage=true - ;; --all) lint=true short=true tests=true - coverage=true ;; *) ;; esac go_test -coverage_tests lint_packages exit 0 diff --git a/internal/policy/commit/commit.go b/internal/policy/commit/commit.go index 2bff4a2e..7a8f1810 100644 --- a/internal/policy/commit/commit.go +++ b/internal/policy/commit/commit.go @@ -84,11 +84,9 @@ func (c *Commit) Compliance(options *policy.Options) (report policy.Report) { return } msg = string(contents) - } else { - if msg, err = g.Message(); err != nil { - report.Errors = append(report.Errors, errors.Errorf("failed to get commit message: %v", err)) - return - } + } else if msg, err = g.Message(); err != nil { + report.Errors = append(report.Errors, errors.Errorf("failed to get commit message: %v", err)) + return } if c.HeaderLength != 0 { diff --git a/internal/policy/commit/commit_test.go b/internal/policy/commit/commit_test.go index b1de3e69..53b92899 100644 --- a/internal/policy/commit/commit_test.go +++ b/internal/policy/commit/commit_test.go @@ -21,88 +21,67 @@ func RemoveAll(dir string) { } } -func TestValidConventionalCommitPolicy(t *testing.T) { - dir, err := ioutil.TempDir("", "test") - if err != nil { - log.Fatal(err) - } - defer RemoveAll(dir) - err = os.Chdir(dir) - if err != nil { - t.Error(err) - } - err = initRepo() - if err != nil { - t.Error(err) - } - err = createValidCommit() - if err != nil { - t.Error(err) - } - report, err := runCompliance() - if err != nil { - t.Error(err) - } - if !report.Valid() { - t.Error("Report is invalid with valid conventional commit") - } -} - -func TestInvalidConventionalCommitPolicy(t *testing.T) { - dir, err := ioutil.TempDir("", "test") - if err != nil { - log.Fatal(err) - } - defer RemoveAll(dir) - err = os.Chdir(dir) - if err != nil { - t.Error(err) - } - err = initRepo() - if err != nil { - t.Error(err) - } - err = createInvalidCommit() - if err != nil { - t.Error(err) - } - report, err := runCompliance() - if err != nil { - t.Error(err) - } - if report.Valid() { - t.Error("Report is valid with invalid conventional commit") - } -} - -func TestEmptyConventionalCommitPolicy(t *testing.T) { - dir, err := ioutil.TempDir("", "test") - if err != nil { - log.Fatal(err) - } - defer RemoveAll(dir) - err = os.Chdir(dir) - if err != nil { - t.Error(err) - } - err = initRepo() - if err != nil { - t.Error(err) - } - err = createEmptyCommit() - if err != nil { - t.Error(err) - } - report, err := runCompliance() - if err != nil { - t.Error(err) - } - if report.Valid() { - t.Error("Report is valid with invalid conventional commit") +func TestConventionalCommitPolicy(t *testing.T) { + type testDesc struct { + Name string + CreateCommit func() error + ExpectValid bool + } + + for _, test := range []testDesc{ + { + Name: "Valid", + CreateCommit: createValidCommit, + ExpectValid: true, + }, + { + Name: "Invalid", + CreateCommit: createInvalidCommit, + ExpectValid: false, + }, + { + Name: "Empty", + CreateCommit: createEmptyCommit, + ExpectValid: false, + }, + } { + func(test testDesc) { + t.Run(test.Name, func(tt *testing.T) { + dir, err := ioutil.TempDir("", "test") + if err != nil { + log.Fatal(err) + } + defer RemoveAll(dir) + err = os.Chdir(dir) + if err != nil { + tt.Error(err) + } + err = initRepo() + if err != nil { + tt.Error(err) + } + + err = test.CreateCommit() + if err != nil { + tt.Error(err) + } + report := runCompliance() + + if test.ExpectValid { + if !report.Valid() { + tt.Error("Report is invalid with valid conventional commit") + } + } else { + if report.Valid() { + tt.Error("Report is valid with invalid conventional commit") + } + } + }) + }(test) } } -func runCompliance() (*policy.Report, error) { +func runCompliance() *policy.Report { c := &Commit{ Conventional: &Conventional{ Types: []string{"type"}, @@ -112,7 +91,7 @@ func runCompliance() (*policy.Report, error) { report := c.Compliance(&policy.Options{}) - return &report, nil + return &report } func initRepo() error { diff --git a/internal/policy/license/license.go b/internal/policy/license/license.go index e0d9c1ed..89f31fba 100644 --- a/internal/policy/license/license.go +++ b/internal/policy/license/license.go @@ -18,6 +18,9 @@ import ( // License implements the policy.Policy interface and enforces source code // license headers. type License struct { + // SkipPaths applies fnmatch-style patterns to file paths to skip completely + // parts of the tree which shouldn't be scanned (e.g. .git/) + SkipPaths []string `mapstructure:"skipPaths"` // IncludeSuffixes is the regex used to find files that the license policy // should be applied to. IncludeSuffixes []string `mapstructure:"includeSuffixes"` @@ -29,6 +32,7 @@ type License struct { } // Compliance implements the policy.Policy.Compliance function. +// nolint: gocyclo func (l *License) Compliance(options *policy.Options) (report policy.Report) { var err error @@ -41,6 +45,28 @@ func (l *License) Compliance(options *policy.Options) (report policy.Report) { if err != nil { return err } + + matchPath := path + if info.IsDir() { + // for directories, match against "dir/ + matchPath += "/" + } + for _, pattern := range l.SkipPaths { + var matches bool + matches, err = filepath.Match(pattern, matchPath) + if err != nil { + return err + } + if matches { + if info.IsDir() { + // skip whole directory tree + return filepath.SkipDir + } + // skip single file + return nil + } + } + if info.Mode().IsRegular() { // Skip excluded suffixes. for _, suffix := range l.ExcludeSuffixes {