Skip to content

Commit

Permalink
improve table handling and testability
Browse files Browse the repository at this point in the history
  • Loading branch information
tillkuhn committed Nov 18, 2024
1 parent 273df0b commit 57e9ff4
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 54 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ vulncheck: ## Run govulncheck scanner
run: ## Run app in tracker mode (dev env), add -drop-create to recreate db
go run main.go --debug track --env dev --idle 10s --interval 5s

.PHONY: punch
punch: ## Show punch clock report for default db
go run main.go --debug punch --env default

.PHONY: report-dev
report-dev: ## Show report for dev env db
go run main.go --debug report --env dev
Expand Down
39 changes: 8 additions & 31 deletions cmd/punch.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"fmt"
"time"

"github.com/fatih/color"

"github.com/spf13/cobra"
"github.com/tillkuhn/billy-idle/pkg/tracker"
)
Expand All @@ -22,9 +20,12 @@ var punchCmd = &cobra.Command{
Long: "If no args are provided, the current status for all punched records will be shown",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
return punchCreate(cmd.Context(), args)
if err := punchCreate(cmd.Context(), args); err != nil {
return err
}
}
return punchReport(cmd.Context(), tracker.New(&punchOpts))
t := tracker.New(&punchOpts)
return t.PunchReport(cmd.Context())
},
}

Expand All @@ -35,6 +36,7 @@ func init() {
punchCmd.PersistentFlags().DurationVar(&punchOpts.RegBusy, "reg-busy", 7*time.Hour+48*time.Minute, "Regular busy period per day (w/o breaks), report only")
}

// punchCreate creates a new punch record for a particular day
func punchCreate(ctx context.Context, args []string) error {
var err error
var day time.Time
Expand All @@ -51,32 +53,7 @@ func punchCreate(ctx context.Context, args []string) error {
return err
}
t := tracker.New(&punchOpts)
if err := t.UpsertPunchRecord(ctx, dur, day); err != nil {
return err
}
// show current report at the end of each new entry
return punchReport(ctx, t)
return t.UpsertPunchRecord(ctx, dur, day)
}

func punchReport(ctx context.Context, t *tracker.Tracker) error {
recs, err := t.PunchRecords(ctx)
if err != nil {
return err
}
var spentBusy time.Duration
for _, r := range recs {
spentDay := time.Duration(r.BusySecs) * time.Second
fmt.Printf("🕰️ %-22s: actual busy time %v\n", r.Day.Format("2006-01-02 (Monday)"), spentDay)
spentBusy += spentDay
}
spentBusy = spentBusy.Round(time.Minute)
pDays := len(recs)
expected := time.Duration(pDays) * punchOpts.RegBusy
overtime := spentBusy - expected
color.Set(color.FgGreen)
fmt.Printf("TotalBusy(%dd): %v AvgPerDay: %v Expected(%dd*%v): %v Overtime: %v\n",
pDays, tracker.FDur(spentBusy), tracker.FDur(spentBusy/time.Duration(pDays)),
pDays, tracker.FDur(punchOpts.RegBusy), tracker.FDur(expected), tracker.FDur(overtime))
color.Unset()
return nil
}
// punchReport displays the current punch report
23 changes: 0 additions & 23 deletions cmd/punch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,8 @@ package cmd

import (
"bytes"
"context"
"slices"
"testing"
"time"

"github.com/DATA-DOG/go-sqlmock"
"github.com/jmoiron/sqlx"
"github.com/tillkuhn/billy-idle/pkg/tracker"

"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -57,23 +51,6 @@ func TestSum(t *testing.T) {
}
}

func Test_PunchReport(t *testing.T) {
mockDB, mock, err := sqlmock.New()
assert.NoError(t, err)
sqlxDB := sqlx.NewDb(mockDB, "sqlmock")
today := tracker.TruncateDay(time.Now())
mock.ExpectQuery("SELECT (.*)").
WillReturnRows(
mock.NewRows([]string{"day", "busy_secs"}).
AddRow(today, 3600).
AddRow(today, 7200),
)
mock.ExpectClose()
tr := tracker.NewWithDB(&punchOpts, sqlxDB)
err = punchReport(context.Background(), tr)
assert.NoError(t, err)
}

/*
func Test_ExecuteTrackCommandMissingArg(t *testing.T) {
assert.ErrorContains(t, rootCmd.Execute(), "expected a duration")
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/spf13/pflag v1.0.5 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down
52 changes: 52 additions & 0 deletions pkg/tracker/punch.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ package tracker

import (
"context"
"fmt"
"log"
"strconv"
"time"

"github.com/fatih/color"
"github.com/olekukonko/tablewriter"

"github.com/pkg/errors"
)

Expand All @@ -13,6 +18,53 @@ const (
hoursPerDay = 24
)

// PunchReport displays the current punch report table layout
func (t *Tracker) PunchReport(ctx context.Context) error {
recs, err := t.PunchRecords(ctx)
if err != nil {
return err
}
var spentBusy time.Duration
table := tablewriter.NewWriter(t.opts.Out)
bold := tablewriter.Colors{tablewriter.Bold}
table.SetHeader([]string{"🕰 Date", "CW", "Weekday", "🐝 Busy Time"})
table.SetHeaderColor(bold, bold, bold, bold)
table.SetBorder(false)
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)

for _, r := range recs {
spentDay := time.Duration(r.BusySecs) * time.Second
_, week := r.Day.ISOWeek()
table.Append([]string{
r.Day.Format(" 2006-01-02"),
strconv.Itoa(week),
r.Day.Format("Monday"),
FDur(spentDay),
})
spentBusy += spentDay
}

spentBusy = spentBusy.Round(time.Minute)
pDays := len(recs)
expected := time.Duration(pDays) * t.opts.RegBusy
overtime := spentBusy - expected

// Table Footer with totals
table.SetFooter([]string{"", "", "Total\nOvertime",
fmt.Sprintf("%s (%ddays)\n%v (>%v)", FDur(spentBusy), pDays, FDur(overtime), FDur(expected)),
}) // Add Footer
table.SetFooterColor(tablewriter.Colors{}, tablewriter.Colors{}, bold,
tablewriter.Colors{tablewriter.FgHiGreenColor})
table.Render()

color.Set(color.FgGreen)
// fmt.Printf("AVG/DAY: %v REGULAR (%dd*%v): %v\n", tracker.FDur(spentBusy/time.Duration(pDays)), pDays, tracker.FDur(punchOpts.RegBusy) )
color.Unset()

return nil
}

func (t *Tracker) UpsertPunchRecord(ctx context.Context, busyDuration time.Duration, day time.Time) error {
uQuery := `UPDATE ` + tablePunch + `
SET busy_secs=$2,client=$3
Expand Down
21 changes: 21 additions & 0 deletions pkg/tracker/punch_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tracker

import (
"bytes"
"context"
"testing"
"time"
Expand Down Expand Up @@ -50,3 +51,23 @@ func Test_SelectPunch(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 2, len(recs))
}

func Test_PunchReport(t *testing.T) {
tr, mock := DBMock(t)
var output bytes.Buffer
tr.opts.Out = &output

day, err := time.Parse("2006-01-02 15:04:05", "2024-01-23 13:14:15") // is a tuesday
assert.NoError(t, err)
day = TruncateDay(day)
mock.ExpectQuery("SELECT (.*)").
WillReturnRows(
mock.NewRows([]string{"day", "busy_secs"}).
AddRow(day, 3600).
AddRow(day, 7200),
)
mock.ExpectClose()
err = tr.PunchReport(context.Background())
assert.NoError(t, err)
assert.Contains(t, output.String(), "Tuesday")
}
4 changes: 4 additions & 0 deletions pkg/tracker/tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"math/rand/v2"
"os"
"sync"
"time"

Expand All @@ -21,6 +22,9 @@ type Tracker struct {

// New returns a new Tracker configured with the given Options
func New(opts *Options) *Tracker {
if opts.Out == nil {
opts.Out = os.Stdout
}
db, err := initDB(opts)
if err != nil {
log.Fatal(err)
Expand Down
2 changes: 2 additions & 0 deletions pkg/tracker/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tracker
import (
"database/sql"
"fmt"
"io"
"path/filepath"
"time"
)
Expand All @@ -20,6 +21,7 @@ type Options struct {
MinBusy time.Duration
MaxBusy time.Duration
RegBusy time.Duration
Out io.Writer
}

func (o Options) AppDir() string {
Expand Down

0 comments on commit 57e9ff4

Please sign in to comment.