Skip to content

Commit

Permalink
feat: add support for reading config from a file
Browse files Browse the repository at this point in the history
  • Loading branch information
dhth committed Mar 12, 2024
1 parent d55733a commit df0f475
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 27 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ punchout
debug.log
punchout.v*.db
.quickrun
justfile
32 changes: 32 additions & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cmd

import (
"github.com/BurntSushi/toml"
)

type JiraConfig struct {
JiraURL *string `toml:"jira_url"`
JiraToken *string `toml:"jira_token"`
Jql *string
JiraTimeDeltaMins *int `toml:"jira_time_delta_mins"`
}

type POConfig struct {
DbPath *string `toml:"db_path"`
Jira JiraConfig
}

func readConfig(filePath string) (POConfig, error) {

var config POConfig
_, err := toml.DecodeFile(expandTilde(filePath), &config)
if err != nil {
return config, err
}
if config.DbPath != nil {
*config.DbPath = expandTilde(*config.DbPath)
}

return config, nil

}
94 changes: 77 additions & 17 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"os/user"
"strconv"

jira "github.com/andygrunwald/go-jira/v2/onpremise"
"github.com/dhth/punchout/ui"
Expand All @@ -16,56 +17,115 @@ func die(msg string, args ...any) {
}

var (
jiraURL = flag.String("jira-url", "https://jira.company.com", "URL of the JIRA server")
jiraToken = flag.String("jira-token", "", "personal access token for the JIRA server")
jql = flag.String("jql", "assignee = currentUser() AND updatedDate >= -14d ORDER BY updatedDate DESC", "JQL to use to query issues at startup")
jiraTimeDeltaMins = flag.Int("jira-time-delta-mins", 0, "Time delta (in minutes) between your timezone and the timezone of the server; can be +/-")
jiraURL = flag.String("jira-url", "", "URL of the JIRA server")
jiraToken = flag.String("jira-token", "", "personal access token for the JIRA server")
jql = flag.String("jql", "", "JQL to use to query issues at startup")
jiraTimeDeltaMinsStr = flag.String("jira-time-delta-mins", "", "Time delta (in minutes) between your timezone and the timezone of the server; can be +/-")
listConfig = flag.Bool("list-config", false, "Whether to only print out the config that punchout will use or not")
)

func Execute() {
currentUser, err := user.Current()

var defaultConfigFP string
if err == nil {
defaultConfigFP = fmt.Sprintf("%s/.config/punchout/punchout.toml", currentUser.HomeDir)
}
configFilePath := flag.String("config-file-path", defaultConfigFP, "location of the punchout config file")

var defaultDBPath string
if err == nil {
defaultDBPath = fmt.Sprintf("%s/punchout.v%s.db", currentUser.HomeDir, PUNCHOUT_DB_VERSION)
}
dbPath := flag.String("db-path", defaultDBPath, "location where punchout should create its DB file")

flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Take the suck out of logging time on JIRA.\n\nFlags:\n")
fmt.Fprintf(os.Stdout, "Take the suck out of logging time on JIRA.\n\nFlags:\n")
flag.CommandLine.SetOutput(os.Stdout)
flag.PrintDefaults()
fmt.Fprintf(os.Stderr, "\n------\n%s", ui.HelpText)
fmt.Fprintf(os.Stdout, "\n------\n%s", ui.HelpText)
}
flag.Parse()

if *dbPath == "" {
die("db-path cannot be empty")
if *configFilePath == "" {
die("config-file-path cannot be empty")
}

if *jql == "" {
die("jql cannot be empty")
var jiraTimeDeltaMins int
if *jiraTimeDeltaMinsStr != "" {
jiraTimeDeltaMins, err = strconv.Atoi(*jiraTimeDeltaMinsStr)
if err != nil {
die("could't convert jira-time-delta-mins to a number")
}
}

poCfg, err := readConfig(*configFilePath)
if err != nil {
die("error reading config at %s: %s", *configFilePath, err.Error())
}
if *dbPath != "" {
expandedPath := expandTilde(*dbPath)
poCfg.DbPath = &expandedPath
}

if *jiraURL != "" {
poCfg.Jira.JiraURL = jiraURL
}

if *jiraToken != "" {
poCfg.Jira.JiraToken = jiraToken
}

if *jql != "" {
poCfg.Jira.Jql = jql
}
if *jiraTimeDeltaMinsStr != "" {
poCfg.Jira.JiraTimeDeltaMins = &jiraTimeDeltaMins
}

if *jiraURL == "" {
configKeyMaxLen := 40
if *listConfig {
fmt.Fprint(os.Stdout, "Config:\n\n")
fmt.Fprintf(os.Stdout, "%s%s\n", ui.RightPadTrim("Config File Path", configKeyMaxLen), *configFilePath)
fmt.Fprintf(os.Stdout, "%s%s\n", ui.RightPadTrim("DB File Path", configKeyMaxLen), *poCfg.DbPath)
fmt.Fprintf(os.Stdout, "%s%s\n", ui.RightPadTrim("JIRA URL", configKeyMaxLen), *poCfg.Jira.JiraURL)
fmt.Fprintf(os.Stdout, "%s%s\n", ui.RightPadTrim("JIRA Token", configKeyMaxLen), *poCfg.Jira.JiraToken)
fmt.Fprintf(os.Stdout, "%s%s\n", ui.RightPadTrim("JQL", configKeyMaxLen), *poCfg.Jira.Jql)
fmt.Fprintf(os.Stdout, "%s%d\n", ui.RightPadTrim("JIRA Time Delta Mins", configKeyMaxLen), *poCfg.Jira.JiraTimeDeltaMins)
os.Exit(0)
}

// validations
if *poCfg.DbPath == "" {
die("db-path cannot be empty")
}

if *poCfg.Jira.JiraURL == "" {
die("jira-url cannot be empty")
}

if *jiraToken == "" {
if *poCfg.Jira.JiraToken == "" {
die("jira-token cannot be empty")
}

db, err := setupDB(*dbPath)
if *poCfg.Jira.Jql == "" {
die("jql cannot be empty")
}

db, err := setupDB(*poCfg.DbPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Couldn't set up punchout database. This is a fatal error")
fmt.Fprintf(os.Stderr, "Couldn't set up punchout database. This is a fatal error\n")
os.Exit(1)
}

tp := jira.BearerAuthTransport{
Token: *jiraToken,
Token: *poCfg.Jira.JiraToken,
}
cl, err := jira.NewClient(*jiraURL, tp.Client())
cl, err := jira.NewClient(*poCfg.Jira.JiraURL, tp.Client())
if err != nil {
panic(err)
}
ui.RenderUI(db, cl, *jql, *jiraTimeDeltaMins)

ui.RenderUI(db, cl, *poCfg.Jira.Jql, *poCfg.Jira.JiraTimeDeltaMins)

}
18 changes: 18 additions & 0 deletions cmd/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cmd

import (
"os"
"os/user"
"strings"
)

func expandTilde(path string) string {
if strings.HasPrefix(path, "~") {
usr, err := user.Current()
if err != nil {
os.Exit(1)
}
return strings.Replace(path, "~", usr.HomeDir, 1)
}
return path
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/dhth/punchout
go 1.22.0

require (
github.com/BurntSushi/toml v1.3.2
github.com/andygrunwald/go-jira/v2 v2.0.0-20240116150243-50d59fe116d6
github.com/charmbracelet/bubbles v0.18.0
github.com/charmbracelet/bubbletea v0.25.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/andygrunwald/go-jira/v2 v2.0.0-20240116150243-50d59fe116d6 h1:pb8RtP8VEWP/BX1M7Kk/AAIGtqThmahV4L/+VcIVcEc=
github.com/andygrunwald/go-jira/v2 v2.0.0-20240116150243-50d59fe116d6/go.mod h1:TrfsnL20VgD+KgEw4gbTYuSAPE8T1ZxjMCFBGgGvNvI=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
Expand Down
4 changes: 2 additions & 2 deletions ui/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ General List Controls
/ Start filtering
Worklog List View
d Delete worklog entry
<ctrl+d> Delete worklog entry
s Sync all visible entries to JIRA
<ctrl-r> Refresh list
<ctrl+r> Refresh list
`
)
12 changes: 6 additions & 6 deletions ui/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ type Issue struct {
}

func (issue Issue) Title() string {
return fmt.Sprintf("%s", RightPadTrim(issue.Summary, listWidth-20))
return fmt.Sprintf("%s", RightPadTrim(issue.Summary, int(float64(listWidth)*0.6)))
}
func (issue Issue) Description() string {
issueType := getIssueTypeStyle(issue.IssueType).Render(Trim(issue.IssueType, 20))
return fmt.Sprintf("%s%s", RightPadTrim(issue.IssueKey, listWidth-40), issueType)
issueType := getIssueTypeStyle(issue.IssueType).Render(Trim(issue.IssueType, int(float64(listWidth)*0.2)))
return fmt.Sprintf("%s%s", RightPadTrim(issue.IssueKey, int(float64(listWidth)*0.6)), issueType)
}
func (issue Issue) FilterValue() string { return issue.IssueKey + " : " + issue.Summary }

Expand Down Expand Up @@ -53,9 +53,9 @@ func (entry WorklogEntry) Description() string {
minsSpent := int(entry.EndTS.Sub(entry.BeginTS).Minutes())
minsSpentStr := fmt.Sprintf("spent %d mins", minsSpent)
return fmt.Sprintf("%s%s%s%s",
RightPadTrim(entry.IssueKey, 40),
RightPadTrim("started: "+entry.BeginTS.Format("Mon, 3:04pm"), 40),
RightPadTrim(minsSpentStr, 40),
RightPadTrim(entry.IssueKey, int(listWidth/4)),
RightPadTrim("started: "+entry.BeginTS.Format("Mon, 3:04pm"), int(listWidth/4)),
RightPadTrim(minsSpentStr, int(listWidth/4)),
syncedStatus,
)
}
Expand Down
4 changes: 2 additions & 2 deletions ui/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds = append(cmds, fetchLogEntries(m.db))
return m, tea.Batch(cmds...)
}
case "d":
case "ctrl+d":
switch m.activeView {
case WorklogView:
issue, ok := m.worklogList.SelectedItem().(WorklogEntry)
Expand Down Expand Up @@ -216,7 +216,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case WLAddedOnJIRA:
if msg.err != nil {
msg.entry.Error = msg.err
m.worklogList.SetItem(msg.index, msg.entry)
m.worklogList.SetItem(msg.index, msg.entry)
m.messages = append(m.messages, msg.err.Error())
} else {
msg.entry.Synced = true
Expand Down

0 comments on commit df0f475

Please sign in to comment.