From 14154effe0a508a1f00efea290529ce8210ad65e Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sat, 31 Oct 2020 18:35:07 +0000 Subject: [PATCH 1/4] feat(ci): add Makefile and GitHub Actions configuration And also enable printing conver's own version with `-version` option. --- .github/workflows/ci.yml | 60 +++++++++++++++ .gitignore | 3 + .golangci.yml | 75 +++++++++++++++++++ Makefile | 154 +++++++++++++++++++++++++++++++++++++++ main.go | 30 +++++++- 5 files changed, 320 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .golangci.yml create mode 100644 Makefile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..19818e4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,60 @@ +--- +name: CI +on: [push] + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: golangci-lint + uses: golangci/golangci-lint-action@v2 + with: + version: v1.31 + env: + VERBOSE: "true" + + tidy: + name: Tidy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: 1.15 + - name: Check if mods are tidy + run: make check-tidy + + cov: + name: Code coverage + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: 1.15 + - name: Publish coverage + uses: paambaati/codeclimate-action@v2.7.4 + with: + coverageCommand: make cov + prefix: github.com/${{ github.repository }} + coverageLocations: | + ${{ github.workspace }}/coverage.out:gocov + env: + VERBOSE: "true" + GOMAXPROCS: 4 + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: 1.15 + - name: Run tests + run: make test + env: + VERBOSE: "true" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..72bb60a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +bin/* +coverage.out +tools/bin/* diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..14b06be --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,75 @@ +linters-settings: + funlen: + lines: 100 + statements: 150 + gocyclo: + min-complexity: 20 + golint: + min-confidence: 0 + govet: + check-shadowing: true + enable-all: true + lll: + line-length: 80 + tab-width: 4 + maligned: + suggest-new: true + misspell: + locale: US + +linters: + disable-all: true + enable: + - bodyclose + - deadcode + - depguard + - dupl + - errcheck + - funlen + - gochecknoinits + - goconst + - gocritic + - gocyclo + - goimports + - golint + - goprintffuncname + - goprintffuncname + - gosec + - gosimple + - govet + - ineffassign + - lll + - misspell + - nakedret + - nlreturn + - noctx + - nolintlint + - scopelint + - sqlclosecheck + - staticcheck + - structcheck + - typecheck + - unconvert + - unused + - varcheck + - whitespace + +issues: + exclude: + - Using the variable on range scope `tt` in function literal + - Using the variable on range scope `tc` in function literal + exclude-rules: + - path: "_test\\.go" + linters: + - funlen + - source: "^//go:generate " + linters: + - lll + - source: "`json:" + linters: + - lll + +run: + timeout: 2m + allow-parallel-runners: true + modules-download-mode: readonly diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8ab6b05 --- /dev/null +++ b/Makefile @@ -0,0 +1,154 @@ +NAME := conver +ROOT := $(CURDIR) +SOURCES := $(shell find . -name "*.go" -or -name "go.mod" -or -name "go.sum" \ + -or -name "Makefile") + +# Verbose output +ifdef VERBOSE +V = -v +endif + +# +# Environment +# + +BINDIR := bin +TOOLDIR := tools/bin + +# Global environment variables for all targets +SHELL ?= /bin/bash +SHELL := env \ + GO111MODULE=on \ + GOBIN=$(CURDIR)/$(TOOLDIR) \ + CGO_ENABLED=1 \ + PATH='$(CURDIR)/$(BINDIR):$(CURDIR)/$(TOOLDIR):$(PATH)' \ + $(SHELL) + +# +# Defaults +# + +# Default target +.DEFAULT_GOAL := build + +.PHONY: all +all: lint test build + +# +# Tools +# + +TOOLS += $(TOOLDIR)/gobin +gobin: $(TOOLDIR)/gobin +$(TOOLDIR)/gobin: + GO111MODULE=off go get -u github.com/myitcv/gobin + +# external tool +define tool # 1: binary-name, 2: go-import-path +TOOLS += $(TOOLDIR)/$(1) + +.PHONY: $(1) +$(1): $(TOOLDIR)/$(1) + +$(TOOLDIR)/$(1): $(TOOLDIR)/gobin Makefile + gobin $(V) "$(2)" +endef + +$(eval $(call tool,gofumports,mvdan.cc/gofumpt/gofumports)) +$(eval $(call tool,golangci-lint,github.com/golangci/golangci-lint/cmd/golangci-lint@v1.31)) + +.PHONY: tools +tools: $(TOOLS) + +# +# Build +# + +BINARY=$(BINDIR)/$(NAME) +LDFLAGS := -w -s + +VERSION ?= $(shell git describe --tags 2>/dev/null) +GIT_SHA ?= $(shell git rev-parse --short HEAD 2>/dev/null) +DATE ?= $(shell date +%s) + +ifeq ($(trim $(VERSION)),) + VERSION = dev +endif + +.PHONY: build +build: $(BINARY) + +$(BINARY): $(SOURCES) + go build $(V) -a -o "$@" -ldflags "$(LDFLAGS) \ + -X main.Version=$(VERSION) \ + -X main.Commit=$(GIT_SHA) \ + -X main.Date=$(DATE)" + +# +# Development +# + +.PHONY: clean +clean: + rm -rf $(BINS) $(TOOLS) + rm -f ./coverage.out ./go.mod.tidy-check ./go.sum.tidy-check + +.PHONY: test +test: + go test $(V) -count=1 --race ./... + +.PHONY: lint +lint: $(TOOLS) + $(info Running Go linters) + GOGC=off golangci-lint $(V) run + +.PHONY: format +format: gofumports + gofumports -w . + +# +# Coverage +# + +.PHONY: cov +cov: coverage.out + +.PHONY: cov-html +cov-html: coverage.out + go tool cover -html=coverage.out + +.PHONY: cov-func +cov-func: coverage.out + go tool cover -func=coverage.out + +coverage.out: $(SOURCES) + go test $(V) -covermode=count -coverprofile=coverage.out ./... + +# +# Dependencies +# + +.PHONY: deps +deps: + $(info Downloading dependencies) + go mod download + +.PHONY: tidy +tidy: + go mod tidy $(V) + +.PHONY: verify +verify: + go mod verify + +.SILENT: check-tidy +.PHONY: check-tidy +check-tidy: + cp go.mod go.mod.tidy-check + cp go.sum go.sum.tidy-check + go mod tidy + -diff go.mod go.mod.tidy-check + -diff go.sum go.sum.tidy-check + -rm -f go.mod go.sum + -mv go.mod.tidy-check go.mod + -mv go.sum.tidy-check go.sum diff --git a/main.go b/main.go index 383963b..958ba21 100644 --- a/main.go +++ b/main.go @@ -4,9 +4,12 @@ import ( "bytes" "errors" "flag" + "fmt" "html/template" "io/ioutil" "log" + "os" + "strconv" "strings" "time" @@ -28,6 +31,12 @@ const changelogTemplate = ` {{ end }} ` +var ( + Version string + Commit string + Date string +) + type ( config struct { // action @@ -49,6 +58,8 @@ type ( // changelog config ChangelogUpdate bool `flag:"changelog-update" desc:"Update changelog"` ChangelogPath string `flag:"changelog-path" desc:"Changelog file path"` + + PrintVersion bool `flag:"version" desc:"print version"` } changelogEntry struct { Version string @@ -374,7 +385,7 @@ func changelogUpdate(c *config) error { mergedBody := append(newBody.Bytes(), changelogBody...) // and update file - return ioutil.WriteFile(c.ChangelogPath, mergedBody, 0644) + return ioutil.WriteFile(c.ChangelogPath, mergedBody, 0o644) } func fileUpdate(c *config) error { @@ -394,7 +405,7 @@ func fileUpdate(c *config) error { if err != nil { return err } - return ioutil.WriteFile(c.FilePath, []byte(newVersion), 0644) + return ioutil.WriteFile(c.FilePath, []byte(newVersion), 0o644) } func bumpAtLeastMinor(c *config) error { @@ -423,6 +434,16 @@ func bumpVersion(currentVersion string, c *config) (string, error) { return c.VersionPrefix + cleanNewVersion.String(), nil } +func printVersion() { + if Date != "" { + ts, err := strconv.Atoi(Date) + if err == nil { + Date = time.Unix(int64(ts), 0).UTC().String() + } + } + fmt.Printf("conver %s (%s, %s)\n", Version, Commit, Date) +} + func main() { c := &config{ FilePath: "VERSION", @@ -435,6 +456,11 @@ func main() { } flag.Parse() + if c.PrintVersion { + printVersion() + os.Exit(0) + } + actions := []func(*config) error{ autodetectBump, bumpAtLeastMinor, From 6d8c5023498cc97764160f383a7bb3b497c05dff Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sun, 1 Nov 2020 16:37:45 +0000 Subject: [PATCH 2/4] fix(makefile): reduce deps of lint target --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8ab6b05..7bb849a 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ test: go test $(V) -count=1 --race ./... .PHONY: lint -lint: $(TOOLS) +lint: golangci-lint $(info Running Go linters) GOGC=off golangci-lint $(V) run From 2530bea25b96d6397032cc7f0673dda3429151c5 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sun, 1 Nov 2020 16:38:07 +0000 Subject: [PATCH 3/4] style(lint): address all lint complaints --- .golangci.yml | 3 +++ main.go | 61 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 14b06be..fc8ba72 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -68,6 +68,9 @@ issues: - source: "`json:" linters: - lll + - source: "`flag:" + linters: + - lll run: timeout: 2m diff --git a/main.go b/main.go index 958ba21..846764c 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,7 @@ import ( convcom "github.com/wfscheper/convcom" ) +//nolint: lll const changelogTemplate = ` ## {{ .Version }} ({{ simpleDate .LatestTagCommit.Committer.When }}) {{ range $type, $commits := .CommitsGrouped }} @@ -97,9 +98,13 @@ func autodetectBump(c *config) error { // find the latest tag var latestTagCommit *object.Commit tagRefs, err := repo.Tags() + if err != nil { + return err + } + err = tagRefs.ForEach(func(tagRef *plumbing.Reference) error { rev := plumbing.Revision(tagRef.Name().String()) - tagCommitHash, err := repo.ResolveRevision(rev) + tagCommitHash, err := repo.ResolveRevision(rev) //nolint:govet if err != nil { return err } @@ -113,6 +118,7 @@ func autodetectBump(c *config) error { if commit.Committer.When.After(latestTagCommit.Committer.When) { latestTagCommit = commit } + return nil }) if err != nil && err != errDone { @@ -122,12 +128,17 @@ func autodetectBump(c *config) error { // find commits since the latest tag commitsSinceTag := []*object.Commit{} commitIter, err := repo.Log(&git.LogOptions{}) + if err != nil { + return err + } + err = commitIter.ForEach(func(commit *object.Commit) error { // once we reach the commit of the latest tag, we're done if commit.Hash == latestTagCommit.Hash { return errDone } commitsSinceTag = append(commitsSinceTag, commit) + return nil }) if err != nil && err != errDone { @@ -144,8 +155,7 @@ func autodetectBump(c *config) error { c.BumpMinor = false c.BumpPatch = false for _, commit := range commitsSinceTag { - switch { - case strings.Contains(commit.Message, "BREAKING"): + if strings.Contains(commit.Message, "BREAKING") { c.BumpMajor = true } } @@ -175,9 +185,13 @@ func gitTagUpdate(c *config) error { var latestTagCommit *object.Commit var latestTagName string tagRefs, err := repo.Tags() + if err != nil { + return err + } + err = tagRefs.ForEach(func(tagRef *plumbing.Reference) error { rev := plumbing.Revision(tagRef.Name().String()) - tagCommitHash, err := repo.ResolveRevision(rev) + tagCommitHash, err := repo.ResolveRevision(rev) //nolint: govet if err != nil { return err } @@ -193,6 +207,7 @@ func gitTagUpdate(c *config) error { latestTagCommit = commit latestTagName = tagRef.Name().Short() } + return nil }) if err != nil && err != errDone { @@ -211,13 +226,17 @@ func gitTagUpdate(c *config) error { } // create new tag - repo.CreateTag(newVersion, head.Hash(), &git.CreateTagOptions{ + _, err = repo.CreateTag(newVersion, head.Hash(), &git.CreateTagOptions{ Message: "chore(version): bump version to " + newVersion, }) + if err != nil { + return err + } + return nil } -func changelogUpdate(c *config) error { +func changelogUpdate(c *config) error { //nolint: funlen,gocyclo // check if we are updating changelog if !c.ChangelogUpdate { return nil @@ -239,9 +258,13 @@ func changelogUpdate(c *config) error { var latestTagCommit *object.Commit var latestTagName string tagRefs, err := repo.Tags() + if err != nil { + return err + } + err = tagRefs.ForEach(func(tagRef *plumbing.Reference) error { rev := plumbing.Revision(tagRef.Name().String()) - tagCommitHash, err := repo.ResolveRevision(rev) + tagCommitHash, err := repo.ResolveRevision(rev) //nolint: govet if err != nil { return err } @@ -257,6 +280,7 @@ func changelogUpdate(c *config) error { latestTagCommit = commit latestTagName = tagRef.Name().Short() } + return nil }) if err != nil && err != errDone { @@ -283,12 +307,16 @@ func changelogUpdate(c *config) error { commitsSinceTag := []*changelogCommit{} commitsSinceTagGrouped := map[string][]*changelogCommit{} commitIter, err := repo.Log(&git.LogOptions{}) + if err != nil { + return err + } + err = commitIter.ForEach(func(commit *object.Commit) error { // once we reach the commit of the latest tag, we're done if commit.Hash == latestTagCommit.Hash { return errDone } - convCommit, err := convComParser.Parse(commit.Message) + convCommit, err := convComParser.Parse(commit.Message) //nolint: govet if err != nil { return err } @@ -311,6 +339,7 @@ func changelogUpdate(c *config) error { commitsSinceTagGrouped[commitType], changelogEntry, ) + return nil }) if err != nil && err != errDone { @@ -366,12 +395,13 @@ func changelogUpdate(c *config) error { // render template var newBody bytes.Buffer - if err := tmpl.Execute(&newBody, &changelogEntry{ + err = tmpl.Execute(&newBody, &changelogEntry{ Version: newVersion, LatestTagCommit: latestTagCommit, Commits: commitsSinceTag, CommitsGrouped: commitsSinceTagGrouped, - }); err != nil { + }) + if err != nil { return err } @@ -385,19 +415,20 @@ func changelogUpdate(c *config) error { mergedBody := append(newBody.Bytes(), changelogBody...) // and update file - return ioutil.WriteFile(c.ChangelogPath, mergedBody, 0o644) + return ioutil.WriteFile(c.ChangelogPath, mergedBody, 0o644) //nolint: gosec } func fileUpdate(c *config) error { if !c.FileUpdate { return nil } - currentVersion := "0.0.0" + versionFileBody, err := ioutil.ReadFile(c.FilePath) if err != nil { return err } - currentVersion = string(versionFileBody) + + currentVersion := string(versionFileBody) if currentVersion == "" { currentVersion = c.VersionPrefix + "0.0.0" } @@ -405,6 +436,8 @@ func fileUpdate(c *config) error { if err != nil { return err } + + //nolint: gosec return ioutil.WriteFile(c.FilePath, []byte(newVersion), 0o644) } @@ -412,6 +445,7 @@ func bumpAtLeastMinor(c *config) error { if !c.BumpMajor && !c.BumpMinor && !c.BumpPatch { c.BumpPatch = true } + return nil } @@ -431,6 +465,7 @@ func bumpVersion(currentVersion string, c *config) (string, error) { if c.BumpPatch { cleanNewVersion = cleanNewVersion.IncPatch() } + return c.VersionPrefix + cleanNewVersion.String(), nil } From 69056295b9d7377b6a4e043dd65bc23ee465f7d5 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sun, 1 Nov 2020 16:44:21 +0000 Subject: [PATCH 4/4] ci(coverage): add basic test for main.go file to get coverage CI step passing --- go.mod | 2 +- go.sum | 1 + main_test.go | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 main_test.go diff --git a/go.mod b/go.mod index 921f05f..042b135 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/go-git/go-git/v5 v5.2.0 github.com/octago/sflags v0.2.0 github.com/pkg/errors v0.9.1 // indirect - github.com/stretchr/testify v1.5.1 // indirect + github.com/stretchr/testify v1.5.1 github.com/wfscheper/convcom v0.0.0-20200418012201-7aa0e60ba66c golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee // indirect golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect diff --git a/go.sum b/go.sum index 0bd935c..62687c8 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magefile/mage v1.9.0 h1:t3AU2wNwehMCW97vuqQLtw6puppWXHO+O2MHo5a50XE= github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..8e3b0f5 --- /dev/null +++ b/main_test.go @@ -0,0 +1,11 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_errDone(t *testing.T) { + assert.EqualError(t, errDone, "done") +}