refactor: add lint test and refactor code.
- lint test using golangci-lint. - lint test added as a job in the testing stage. - code refactoring based on feedback.
This commit is contained in:
parent
0a2b9c483e
commit
99ebc86270
9 changed files with 132 additions and 44 deletions
|
@ -6,18 +6,28 @@ stages:
|
||||||
variables:
|
variables:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
|
.install-make:
|
||||||
|
before_script:
|
||||||
|
- apk add --no-cache make
|
||||||
|
|
||||||
test:unit:
|
test:unit:
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 30 minutes
|
expire_in: 30 minutes
|
||||||
paths:
|
paths:
|
||||||
- code-coverage.html
|
- code-coverage.html
|
||||||
before_script:
|
extends: .install-make
|
||||||
- apk add --no-cache make
|
|
||||||
image: golang:1.13.6-alpine
|
image: golang:1.13.6-alpine
|
||||||
script:
|
script:
|
||||||
- make test_cover_report
|
- make test_cover_report
|
||||||
stage: test
|
stage: test
|
||||||
|
|
||||||
|
test:lint:
|
||||||
|
extends: .install-make
|
||||||
|
image: golangci/golangci-lint:v1.23.1-alpine
|
||||||
|
script:
|
||||||
|
- make test_lint
|
||||||
|
stage: test
|
||||||
|
|
||||||
pages:
|
pages:
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
|
|
75
.golangci.yml
Normal file
75
.golangci.yml
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
run:
|
||||||
|
concurrency: 2
|
||||||
|
timeout: 1m
|
||||||
|
issues-exit-code: 1
|
||||||
|
tests: true
|
||||||
|
|
||||||
|
output:
|
||||||
|
format: colored-line-number
|
||||||
|
print-issues-lines: true
|
||||||
|
print-linter-name: true
|
||||||
|
|
||||||
|
linters-settings:
|
||||||
|
lll:
|
||||||
|
line-length: 140
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
- bodyclose
|
||||||
|
- deadcode
|
||||||
|
- depguard
|
||||||
|
- dogsled
|
||||||
|
- dupl
|
||||||
|
- errcheck
|
||||||
|
- funlen
|
||||||
|
- gochecknoglobals
|
||||||
|
- gochecknoinits
|
||||||
|
- gocognit
|
||||||
|
- goconst
|
||||||
|
- gocritic
|
||||||
|
- gocyclo
|
||||||
|
- godox
|
||||||
|
- gofmt
|
||||||
|
- goimports
|
||||||
|
- golint
|
||||||
|
- gomnd
|
||||||
|
- goprintffuncname
|
||||||
|
- gosec
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- interfacer
|
||||||
|
- lll
|
||||||
|
- maligned
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- prealloc
|
||||||
|
- rowserrcheck
|
||||||
|
- scopelint
|
||||||
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
|
- stylecheck
|
||||||
|
- typecheck
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- unused
|
||||||
|
- varcheck
|
||||||
|
- whitespace
|
||||||
|
- wsl
|
||||||
|
#disable:
|
||||||
|
disabe-all: false
|
||||||
|
fast: false
|
||||||
|
|
||||||
|
issues:
|
||||||
|
exclude-rules:
|
||||||
|
- path: version.go
|
||||||
|
linters:
|
||||||
|
- gochecknoglobals
|
||||||
|
- path: _test.go
|
||||||
|
linters:
|
||||||
|
- gomnd
|
||||||
|
- scopelint
|
||||||
|
- path: cases_test.go
|
||||||
|
linters:
|
||||||
|
- gochecknoglobals
|
3
Makefile
3
Makefile
|
@ -12,6 +12,9 @@ test_unit:
|
||||||
test_cover_report: test_unit
|
test_cover_report: test_unit
|
||||||
@go tool cover -html=cover.out -o code-coverage.html
|
@go tool cover -html=cover.out -o code-coverage.html
|
||||||
|
|
||||||
|
test_lint:
|
||||||
|
@golangci-lint run --color always
|
||||||
|
|
||||||
build:
|
build:
|
||||||
@go build -a -v -o $(BIN_FILE)
|
@go build -a -v -o $(BIN_FILE)
|
||||||
|
|
||||||
|
|
21
alert.go
21
alert.go
|
@ -28,35 +28,36 @@ import (
|
||||||
|
|
||||||
const iconPath string = "assets/icon/tomato.png"
|
const iconPath string = "assets/icon/tomato.png"
|
||||||
|
|
||||||
var notifier *notificator.Notificator
|
|
||||||
|
|
||||||
// initNotifier initialises the new desktop notifier.
|
// initNotifier initialises the new desktop notifier.
|
||||||
func initNotifier() {
|
func initNotifier() *notificator.Notificator {
|
||||||
notifier = notificator.New(notificator.Options{
|
return notificator.New(notificator.Options{
|
||||||
DefaultIcon: getIconPath(),
|
DefaultIcon: getNotificationIconPath(),
|
||||||
AppName: "Pominal",
|
AppName: "Pominal",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// getIconPath returns the absolute path of the tomoato icon
|
// getNotificationIconPath returns the absolute path of the tomoato icon
|
||||||
// used for desktop notifications.
|
// used for desktop notifications.
|
||||||
// If there is an error getting the path to the executing program
|
// If there is an error getting the path to the executing program
|
||||||
// then an empty string is returned.
|
// then an empty string is returned.
|
||||||
func getIconPath() string {
|
func getNotificationIconPath() string {
|
||||||
|
|
||||||
var result string
|
var result string
|
||||||
|
|
||||||
exe, err := os.Executable()
|
exe, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ERROR: Unable to determine path to this executable. %s", err.Error())
|
fmt.Printf("ERROR: Unable to determine path to this executable. %s", err.Error())
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
result = filepath.Dir(exe) + "/" + iconPath
|
result = filepath.Dir(exe) + "/" + iconPath
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// alert creates a new desktop notification.
|
// alert creates a new desktop notification.
|
||||||
func alert(l string) {
|
func desktopAlert(l string, notifier *notificator.Notificator) {
|
||||||
title := "Pominal notification."
|
title := "Pominal notification."
|
||||||
text := l + " session has started."
|
text := l + " session has started."
|
||||||
notifier.Push(title, text, "", notificator.UR_NORMAL)
|
|
||||||
|
_ = notifier.Push(title, text, "", notificator.UR_NORMAL)
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ var sessionsTestCases = []struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Test session 4",
|
name: "Test session 4",
|
||||||
description: "When the second work session has finished and the long break has started because the maximum number of work sessions is reached.",
|
description: "When the second work session has finished and the long break has started.",
|
||||||
expectedWorkSession: 2,
|
expectedWorkSession: 2,
|
||||||
expectedCycle: 1,
|
expectedCycle: 1,
|
||||||
expectedLabel: longBreakTimerLabel,
|
expectedLabel: longBreakTimerLabel,
|
||||||
|
|
33
main.go
33
main.go
|
@ -20,30 +20,27 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func main() {
|
||||||
workTime string
|
var (
|
||||||
shortBreakTime string
|
workTime string
|
||||||
longBreakTime string
|
shortBreakTime string
|
||||||
maxWorkSessions int
|
longBreakTime string
|
||||||
printVersion bool
|
maxWorkSessions int
|
||||||
)
|
printVersion bool
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.StringVar(&workTime, "work", "25m", "sets the timer for your work session.")
|
flag.StringVar(&workTime, "work", "25m", "sets the timer for your work session.")
|
||||||
flag.StringVar(&shortBreakTime, "short-break", "5m", "sets the timer for your short break.")
|
flag.StringVar(&shortBreakTime, "short-break", "5m", "sets the timer for your short break.")
|
||||||
flag.StringVar(&longBreakTime, "long-break", "20m", "sets the timer for your long break.")
|
flag.StringVar(&longBreakTime, "long-break", "20m", "sets the timer for your long break.")
|
||||||
flag.IntVar(&maxWorkSessions, "max-work-sessions", 4, "sets the maximum number of work cycles to complete before taking a long break.")
|
flag.IntVar(&maxWorkSessions, "max-work-sessions", 4, "sets the maximum number of work cycles to complete before taking a long break.")
|
||||||
flag.BoolVar(&printVersion, "version", false, "print version and exit.")
|
flag.BoolVar(&printVersion, "version", false, "print version and exit.")
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if printVersion {
|
if printVersion {
|
||||||
|
@ -51,24 +48,19 @@ func main() {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
initNotifier()
|
|
||||||
|
|
||||||
w, err := time.ParseDuration(workTime)
|
w, err := time.ParseDuration(workTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ERROR: Unable to set the work timer. %s", err.Error())
|
log.Fatalf("ERROR: Unable to set the work timer. %s", err.Error())
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := time.ParseDuration(shortBreakTime)
|
s, err := time.ParseDuration(shortBreakTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ERROR: Unable to set the work timer. %s", err.Error())
|
log.Fatalf("ERROR: Unable to set the work timer. %s", err.Error())
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l, err := time.ParseDuration(longBreakTime)
|
l, err := time.ParseDuration(longBreakTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ERROR: Unable to set the work timer. %s", err.Error())
|
log.Fatalf("ERROR: Unable to set the work timer. %s", err.Error())
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pominal := NewPominal(
|
pominal := NewPominal(
|
||||||
|
@ -84,6 +76,7 @@ func main() {
|
||||||
flex := newFlex(infoUI, timerUI)
|
flex := newFlex(infoUI, timerUI)
|
||||||
|
|
||||||
go pominal.Run(infoUI, timerUI)
|
go pominal.Run(infoUI, timerUI)
|
||||||
|
|
||||||
if err := app.SetRoot(flex, false).SetFocus(flex).Run(); err != nil {
|
if err := app.SetRoot(flex, false).SetFocus(flex).Run(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
21
pominal.go
21
pominal.go
|
@ -65,11 +65,13 @@ type Pominal struct {
|
||||||
|
|
||||||
// NewPominal creates a new pominal instance
|
// NewPominal creates a new pominal instance
|
||||||
func NewPominal(w, s, l float64, m int) Pominal {
|
func NewPominal(w, s, l float64, m int) Pominal {
|
||||||
|
initWorkSession := 1
|
||||||
|
initCycle := 1
|
||||||
|
|
||||||
return Pominal{
|
return Pominal{
|
||||||
workSession: 1,
|
workSession: initWorkSession,
|
||||||
maxWorkSessions: setMaxWorkSessions(m),
|
maxWorkSessions: setMaxWorkSessions(m),
|
||||||
cycle: 1,
|
cycle: initCycle,
|
||||||
work: setSessionTime(w),
|
work: setSessionTime(w),
|
||||||
shortBreak: setSessionTime(s),
|
shortBreak: setSessionTime(s),
|
||||||
longBreak: setSessionTime(l),
|
longBreak: setSessionTime(l),
|
||||||
|
@ -79,11 +81,14 @@ func NewPominal(w, s, l float64, m int) Pominal {
|
||||||
|
|
||||||
// Run Pominal
|
// Run Pominal
|
||||||
func (p *Pominal) Run(infoUI, timerUI *tview.TextView) {
|
func (p *Pominal) Run(infoUI, timerUI *tview.TextView) {
|
||||||
|
|
||||||
p.stopChan = make(chan struct{})
|
p.stopChan = make(chan struct{})
|
||||||
p.UpdateSession()
|
p.UpdateSession()
|
||||||
drawInfo(infoUI, p.cycle, p.workSession, p.maxWorkSessions, p.label)
|
drawInfo(infoUI, p.cycle, p.workSession, p.maxWorkSessions, p.label)
|
||||||
t := time.NewTicker(1 * time.Second)
|
|
||||||
|
// notifier is used for desktop notifications
|
||||||
|
notifier := initNotifier()
|
||||||
|
|
||||||
|
t := time.NewTicker(time.Second)
|
||||||
|
|
||||||
infinite:
|
infinite:
|
||||||
for {
|
for {
|
||||||
|
@ -103,9 +108,9 @@ infinite:
|
||||||
p.maxWorkSessions,
|
p.maxWorkSessions,
|
||||||
p.label,
|
p.label,
|
||||||
)
|
)
|
||||||
alert(p.label)
|
desktopAlert(p.label, notifier)
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(time.Second)
|
||||||
t = time.NewTicker(1 * time.Second)
|
t = time.NewTicker(time.Second)
|
||||||
} else {
|
} else {
|
||||||
drawTimer(timerUI, p.countdown)
|
drawTimer(timerUI, p.countdown)
|
||||||
}
|
}
|
||||||
|
@ -158,6 +163,7 @@ func setSessionTime(s float64) float64 {
|
||||||
if s < min {
|
if s < min {
|
||||||
return min
|
return min
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,5 +176,6 @@ func setMaxWorkSessions(w int) int {
|
||||||
if w < min {
|
if w < min {
|
||||||
return min
|
return min
|
||||||
}
|
}
|
||||||
|
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,9 +71,6 @@ func TestRun(t *testing.T) {
|
||||||
infoUI := tview.NewTextView()
|
infoUI := tview.NewTextView()
|
||||||
timerUI := tview.NewTextView()
|
timerUI := tview.NewTextView()
|
||||||
|
|
||||||
// TODO: Remove when support for disabling desktop notifications is in place.
|
|
||||||
initNotifier()
|
|
||||||
|
|
||||||
go pominal.Run(infoUI, timerUI)
|
go pominal.Run(infoUI, timerUI)
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
4
ui.go
4
ui.go
|
@ -56,5 +56,7 @@ func drawInfo(t *tview.TextView, pominalCycle, workSessions, maxWorkSessions int
|
||||||
|
|
||||||
func drawTimer(t *tview.TextView, countdown float64) {
|
func drawTimer(t *tview.TextView, countdown float64) {
|
||||||
t.Clear()
|
t.Clear()
|
||||||
fmt.Fprintf(t, "\nTime remaining:\n%02d:%02d", int(countdown)/60, int(countdown)%60)
|
|
||||||
|
secondsPerMinute := 60
|
||||||
|
fmt.Fprintf(t, "\nTime remaining:\n%02d:%02d", int(countdown)/secondsPerMinute, int(countdown)%secondsPerMinute)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue