Merge pull request #1 from romdo/basics

feat(ci): add Makefile and GitHub Actions configuration
This commit is contained in:
2020-11-01 18:21:31 +00:00
committed by GitHub
8 changed files with 383 additions and 15 deletions

60
.github/workflows/ci.yml vendored Normal file
View File

@@ -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"

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
bin/*
coverage.out
tools/bin/*

78
.golangci.yml Normal file
View File

@@ -0,0 +1,78 @@
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
- source: "`flag:"
linters:
- lll
run:
timeout: 2m
allow-parallel-runners: true
modules-download-mode: readonly

154
Makefile Normal file
View File

@@ -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: golangci-lint
$(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

2
go.mod
View File

@@ -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

1
go.sum
View File

@@ -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=

89
main.go
View File

@@ -4,9 +4,12 @@ import (
"bytes"
"errors"
"flag"
"fmt"
"html/template"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
"time"
@@ -18,6 +21,7 @@ import (
convcom "github.com/wfscheper/convcom"
)
//nolint: lll
const changelogTemplate = `
## {{ .Version }} ({{ simpleDate .LatestTagCommit.Committer.When }})
{{ range $type, $commits := .CommitsGrouped }}
@@ -28,6 +32,12 @@ const changelogTemplate = `
{{ end }}
`
var (
Version string
Commit string
Date string
)
type (
config struct {
// action
@@ -49,6 +59,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
@@ -86,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
}
@@ -102,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 {
@@ -111,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 {
@@ -133,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
}
}
@@ -164,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
}
@@ -182,6 +207,7 @@ func gitTagUpdate(c *config) error {
latestTagCommit = commit
latestTagName = tagRef.Name().Short()
}
return nil
})
if err != nil && err != errDone {
@@ -200,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
@@ -228,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
}
@@ -246,6 +280,7 @@ func changelogUpdate(c *config) error {
latestTagCommit = commit
latestTagName = tagRef.Name().Short()
}
return nil
})
if err != nil && err != errDone {
@@ -272,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
}
@@ -300,6 +339,7 @@ func changelogUpdate(c *config) error {
commitsSinceTagGrouped[commitType],
changelogEntry,
)
return nil
})
if err != nil && err != errDone {
@@ -355,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
}
@@ -374,19 +415,20 @@ 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) //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"
}
@@ -394,13 +436,16 @@ func fileUpdate(c *config) error {
if err != nil {
return err
}
return ioutil.WriteFile(c.FilePath, []byte(newVersion), 0644)
//nolint: gosec
return ioutil.WriteFile(c.FilePath, []byte(newVersion), 0o644)
}
func bumpAtLeastMinor(c *config) error {
if !c.BumpMajor && !c.BumpMinor && !c.BumpPatch {
c.BumpPatch = true
}
return nil
}
@@ -420,9 +465,20 @@ func bumpVersion(currentVersion string, c *config) (string, error) {
if c.BumpPatch {
cleanNewVersion = cleanNewVersion.IncPatch()
}
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 +491,11 @@ func main() {
}
flag.Parse()
if c.PrintVersion {
printVersion()
os.Exit(0)
}
actions := []func(*config) error{
autodetectBump,
bumpAtLeastMinor,

11
main_test.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_errDone(t *testing.T) {
assert.EqualError(t, errDone, "done")
}