-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4bfa1bf
Showing
23 changed files
with
1,513 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
dist | ||
cosign.key | ||
cosign.pub | ||
punchout | ||
debug.log | ||
punchout.v*.db | ||
.quickrun |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# punchout | ||
|
||
✨ Overview | ||
--- | ||
|
||
`punchout` takes the suck out of tracking work on JIRA. | ||
|
||
Install | ||
--- | ||
|
||
**go**: | ||
|
||
```sh | ||
go install github.com/dhth/punchout@latest | ||
``` | ||
|
||
Acknowledgements | ||
--- | ||
|
||
`punchout` is built using the awesome TUI framework [bubbletea][1]. | ||
|
||
[1]: https://github.com/charmbracelet/bubbletea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package cmd | ||
|
||
import "database/sql" | ||
|
||
const ( | ||
PUNCHOUT_DB_VERSION = "1" | ||
) | ||
|
||
func setupDB(dbpath string) (*sql.DB, error) { | ||
|
||
db, err := sql.Open("sqlite", dbpath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if _, err = db.Exec(` | ||
CREATE TABLE IF NOT EXISTS issue_log ( | ||
ID INTEGER PRIMARY KEY AUTOINCREMENT, | ||
issue_key TEXT NOT NULL, | ||
begin_ts TIMESTAMP NOT NULL, | ||
end_ts TIMESTAMP, | ||
comment VARCHAR(255), | ||
active BOOLEAN NOT NULL, | ||
synced BOOLEAN NOT NULL | ||
); | ||
CREATE TRIGGER IF NOT EXISTS prevent_duplicate_active_insert | ||
BEFORE INSERT ON issue_log | ||
BEGIN | ||
SELECT CASE | ||
WHEN EXISTS (SELECT 1 FROM issue_log WHERE active = 1) | ||
THEN RAISE(ABORT, 'Only one row with active=1 is allowed') | ||
END; | ||
END; | ||
`); err != nil { | ||
return nil, err | ||
} | ||
return db, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package cmd | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
"os/user" | ||
|
||
jira "github.com/andygrunwald/go-jira/v2/onpremise" | ||
"github.com/dhth/punchout/ui" | ||
) | ||
|
||
func die(msg string, args ...any) { | ||
fmt.Fprintf(os.Stderr, msg+"\n", args...) | ||
os.Exit(1) | ||
} | ||
|
||
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 +/-") | ||
) | ||
|
||
func Execute() { | ||
currentUser, err := user.Current() | ||
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") | ||
flag.PrintDefaults() | ||
fmt.Fprintf(os.Stderr, "\n------\n%s", ui.HelpText) | ||
} | ||
flag.Parse() | ||
|
||
if *dbPath == "" { | ||
die("db-path cannot be empty") | ||
} | ||
|
||
if *jql == "" { | ||
die("jql cannot be empty") | ||
} | ||
|
||
if *jiraURL == "" { | ||
die("jira-url cannot be empty") | ||
} | ||
|
||
if *jiraToken == "" { | ||
die("jira-token cannot be empty") | ||
} | ||
|
||
db, err := setupDB(*dbPath) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Couldn't set up punchout database. This is a fatal error") | ||
os.Exit(1) | ||
} | ||
|
||
tp := jira.BearerAuthTransport{ | ||
Token: *jiraToken, | ||
} | ||
cl, err := jira.NewClient(*jiraURL, tp.Client()) | ||
if err != nil { | ||
panic(err) | ||
} | ||
ui.RenderUI(db, cl, *jql, *jiraTimeDeltaMins) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package main | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
"os" | ||
"time" | ||
|
||
_ "modernc.org/sqlite" | ||
) | ||
|
||
type IssueLogEntry struct { | ||
Id int | ||
IssueKey string | ||
BeginTS time.Time | ||
EndTS time.Time | ||
Active bool | ||
Synced bool | ||
LastUpdated time.Time | ||
} | ||
|
||
func main() { | ||
db, err := sql.Open("sqlite", "punchoutdb") | ||
if err != nil { | ||
fmt.Println(err.Error()) | ||
os.Exit(1) | ||
} | ||
|
||
if _, err = db.Exec(` | ||
CREATE TABLE IF NOT EXISTS issue_log ( | ||
ID INTEGER PRIMARY KEY AUTOINCREMENT, | ||
issue_key TEXT NOT NULL, | ||
begin_ts TIMESTAMP NOT NULL, | ||
end_ts TIMESTAMP, | ||
active BOOLEAN NOT NULL, | ||
synced BOOLEAN NOT NULL, | ||
last_updated TIMESTAMP NOT NULL | ||
); | ||
CREATE TRIGGER IF NOT EXISTS prevent_duplicate_active_insert | ||
BEFORE INSERT ON issue_log | ||
BEGIN | ||
SELECT CASE | ||
WHEN EXISTS (SELECT 1 FROM issue_log WHERE active = 1) | ||
THEN RAISE(ABORT, 'Only one row with active=1 is allowed') | ||
END; | ||
END; | ||
`); err != nil { | ||
fmt.Println(err.Error()) | ||
os.Exit(1) | ||
} | ||
|
||
entry := IssueLogEntry{ | ||
IssueKey: "WEBENG-1099", | ||
BeginTS: time.Now().Add(time.Hour * -3), | ||
Active: true, | ||
Synced: false, | ||
LastUpdated: time.Now(), | ||
} | ||
|
||
insertEntry(db, entry) | ||
time.Sleep(time.Second * 10) | ||
entry.EndTS = time.Now() | ||
entry.Active = false | ||
entry.LastUpdated = time.Now() | ||
updateEntry(db, entry) | ||
|
||
} | ||
|
||
func insertEntry(db *sql.DB, entry IssueLogEntry) { | ||
stmt, err := db.Prepare(` | ||
INSERT INTO issue_log (issue_key, begin_ts, active, synced, last_updated) | ||
VALUES (?, ?, ?, ?, ?); | ||
`) | ||
|
||
if err != nil { | ||
fmt.Println(err.Error()) | ||
os.Exit(1) | ||
} | ||
defer stmt.Close() | ||
|
||
_, err = stmt.Exec(entry.IssueKey, entry.BeginTS, entry.Active, entry.Synced, entry.LastUpdated) | ||
if err != nil { | ||
fmt.Println(err.Error()) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func updateEntry(db *sql.DB, entry IssueLogEntry) { | ||
stmt, err := db.Prepare(` | ||
UPDATE issue_log | ||
SET active = 0, | ||
end_ts = ?, | ||
last_updated = ? | ||
WHERE issue_key = ? | ||
AND active = 1; | ||
`) | ||
if err != nil { | ||
fmt.Println(err.Error()) | ||
os.Exit(1) | ||
} | ||
defer stmt.Close() | ||
|
||
if err != nil { | ||
fmt.Println(err.Error()) | ||
os.Exit(1) | ||
} | ||
defer stmt.Close() | ||
|
||
_, err = stmt.Exec(entry.EndTS, entry.LastUpdated, entry.IssueKey) | ||
if err != nil { | ||
fmt.Println(err.Error()) | ||
os.Exit(1) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
module github.com/dhth/punchout | ||
|
||
go 1.22.0 | ||
|
||
require ( | ||
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 | ||
github.com/charmbracelet/lipgloss v0.10.0 | ||
modernc.org/sqlite v1.29.3 | ||
) | ||
|
||
require ( | ||
github.com/atotto/clipboard v0.1.4 // indirect | ||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect | ||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect | ||
github.com/dustin/go-humanize v1.0.1 // indirect | ||
github.com/fatih/structs v1.1.0 // indirect | ||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect | ||
github.com/google/go-querystring v1.1.0 // indirect | ||
github.com/google/uuid v1.3.0 // indirect | ||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect | ||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect | ||
github.com/mattn/go-isatty v0.0.18 // indirect | ||
github.com/mattn/go-localereader v0.0.1 // indirect | ||
github.com/mattn/go-runewidth v0.0.15 // indirect | ||
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect | ||
github.com/muesli/cancelreader v0.2.2 // indirect | ||
github.com/muesli/reflow v0.3.0 // indirect | ||
github.com/muesli/termenv v0.15.2 // indirect | ||
github.com/ncruces/go-strftime v0.1.9 // indirect | ||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect | ||
github.com/rivo/uniseg v0.4.7 // indirect | ||
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect | ||
github.com/trivago/tgo v1.0.7 // indirect | ||
golang.org/x/sync v0.1.0 // indirect | ||
golang.org/x/sys v0.16.0 // indirect | ||
golang.org/x/term v0.6.0 // indirect | ||
golang.org/x/text v0.3.8 // indirect | ||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect | ||
modernc.org/libc v1.41.0 // indirect | ||
modernc.org/mathutil v1.6.0 // indirect | ||
modernc.org/memory v1.7.2 // indirect | ||
modernc.org/strutil v1.2.0 // indirect | ||
modernc.org/token v1.1.0 // indirect | ||
) |
Oops, something went wrong.