Skip to content

Commit

Permalink
feat: show notification on watch finish
Browse files Browse the repository at this point in the history
  • Loading branch information
dlvhdr committed Jan 5, 2024
1 parent 11ba142 commit f4f5731
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 14 deletions.
4 changes: 4 additions & 0 deletions data/issueapi.go
Expand Up @@ -39,6 +39,10 @@ type IssueLabels struct {
Nodes []Label
}

func (data IssueData) GetTitle() string {
return data.Title
}

func (data IssueData) GetRepoNameWithOwner() string {
return data.Repository.NameWithOwner
}
Expand Down
36 changes: 36 additions & 0 deletions data/prapi.go
Expand Up @@ -2,11 +2,13 @@ package data

import (
"fmt"
"net/url"
"time"

"github.com/charmbracelet/log"
gh "github.com/cli/go-gh/v2/pkg/api"
graphql "github.com/cli/shurcooL-graphql"
"github.com/shurcooL/githubv4"
)

type PullRequestData struct {
Expand Down Expand Up @@ -118,6 +120,10 @@ type PageInfo struct {
EndCursor string
}

func (data PullRequestData) GetTitle() string {
return data.Title
}

func (data PullRequestData) GetRepoNameWithOwner() string {
return data.Repository.NameWithOwner
}
Expand Down Expand Up @@ -191,3 +197,33 @@ func FetchPullRequests(query string, limit int, pageInfo *PageInfo) (PullRequest
PageInfo: queryResult.Search.PageInfo,
}, nil
}

func FetchPullRequest(prUrl string) (PullRequestData, error) {
var err error
client, err := gh.DefaultGraphQLClient()

if err != nil {
return PullRequestData{}, err
}

var queryResult struct {
Resource struct {
PullRequest PullRequestData `graphql:"... on PullRequest"`
} `graphql:"resource(url: $url)"`
}
parsedUrl, err := url.Parse(prUrl)
if err != nil {
return PullRequestData{}, err
}
variables := map[string]interface{}{
"url": githubv4.URI{URL: parsedUrl},
}
log.Debug("Fetching PR", "url", prUrl)
err = client.Query("FetchPullRequest", &queryResult, variables)
if err != nil {
return PullRequestData{}, err
}
log.Debug("Successfully fetched PR", "url", prUrl, "data", queryResult.Resource.PullRequest)

return queryResult.Resource.PullRequest, nil
}
5 changes: 4 additions & 1 deletion data/utils.go
@@ -1,9 +1,12 @@
package data

import "time"
import (
"time"
)

type RowData interface {
GetRepoNameWithOwner() string
GetTitle() string
GetNumber() int
GetUrl() string
GetUpdatedAt() time.Time
Expand Down
7 changes: 7 additions & 0 deletions go.mod
Expand Up @@ -28,9 +28,12 @@ require (
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gen2brain/beeep v0.0.0-20230907135156-1a38885a97fc // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/henvic/httpretty v0.1.3 // indirect
Expand All @@ -45,9 +48,13 @@ require (
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/shurcooL/githubv4 v0.0.0-20231126234147-1cffa1f02456 // indirect
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e // indirect
github.com/yuin/goldmark v1.6.0 // indirect
github.com/yuin/goldmark-emoji v1.0.2 // indirect
Expand Down
14 changes: 14 additions & 0 deletions go.sum
Expand Up @@ -58,6 +58,8 @@ github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gen2brain/beeep v0.0.0-20230907135156-1a38885a97fc h1:NNgdMgPX3j33uEAoVVxNxillDPnxT0xbGv8uh4CKIAo=
github.com/gen2brain/beeep v0.0.0-20230907135156-1a38885a97fc/go.mod h1:0W7dI87PvXJ1Sjs0QPvWXKcQmNERY77e8l7GFhZB/s4=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
Expand All @@ -69,6 +71,10 @@ github.com/go-playground/validator/v10 v10.15.0 h1:nDU5XeOKtB3GEa+uB7GNYwhVKsgjA
github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4/go.mod h1:kW3HQ4UdaAyrUCSSDR4xUzBKW6O2iA4uHhk7AtyYp10=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
Expand Down Expand Up @@ -117,6 +123,8 @@ github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKt
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -126,6 +134,10 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/githubv4 v0.0.0-20231126234147-1cffa1f02456 h1:6dExqsYngGEiixqa1vmtlUd+zbyISilg0Cf3GWVdeYM=
github.com/shurcooL/githubv4 v0.0.0-20231126234147-1cffa1f02456/go.mod h1:zqMwyHmnN/eDOZOdiTohqIUKUrTFX62PNlu7IJdu0q8=
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 h1:17JxqqJY66GmZVHkmAsGEkcIu0oCe3AM420QDgGwZx0=
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466/go.mod h1:9dIRpgIY7hVhoqfe0/FcYp0bpInZaT7dc3BYOprrIUE=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
Expand All @@ -140,6 +152,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e h1:BuzhfgfWQbX0dWzYzT1zsORLnHRv3bcRcsaUk0VmXA8=
github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e/go.mod h1:/Tnicc6m/lsJE0irFMA0LfIwTBo4QP7A8IfyIv4zZKI=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
4 changes: 4 additions & 0 deletions ui/components/prssection/prssection.go
Expand Up @@ -117,6 +117,10 @@ func (m Model) Update(msg tea.Msg) (section.Section, tea.Cmd) {
if err != nil {
m.Ctx.Error = err
}

case key.Matches(msg, keys.PRKeys.WatchChecks):
cmd = m.watchChecks()

}

case UpdatePRMsg:
Expand Down
91 changes: 91 additions & 0 deletions ui/components/prssection/watchChecks.go
@@ -0,0 +1,91 @@
package prssection

import (
"bytes"
"fmt"
"os/exec"

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/log"
"github.com/gen2brain/beeep"

"github.com/dlvhdr/gh-dash/data"
prComponent "github.com/dlvhdr/gh-dash/ui/components/pr"
"github.com/dlvhdr/gh-dash/ui/constants"
"github.com/dlvhdr/gh-dash/ui/context"
)

func (m *Model) watchChecks() tea.Cmd {
pr := m.GetCurrRow()
prNumber := pr.GetNumber()
title := pr.GetTitle()
url := pr.GetUrl()
repoNameWithOwner := pr.GetRepoNameWithOwner()
taskId := fmt.Sprintf("pr_reopen_%d", prNumber)
task := context.Task{
Id: taskId,
StartText: fmt.Sprintf("Watching checks for PR #%d", prNumber),
FinishedText: fmt.Sprintf("Watching checks for PR #%d", prNumber),
State: context.TaskStart,
Error: nil,
}
startCmd := m.Ctx.StartTask(task)
return tea.Batch(startCmd, func() tea.Msg {
c := exec.Command(
"gh",
"pr",
"checks",
"--watch",
"--fail-fast",
fmt.Sprint(m.GetCurrRow().GetNumber()),
"-R",
m.GetCurrRow().GetRepoNameWithOwner(),
)

var outb, errb bytes.Buffer
c.Stdout = &outb
c.Stderr = &errb

err := c.Start()
go func() {
err := c.Wait()
if err != nil {
log.Error("Error waiting for watch command to finish", "err", err)
}

// TODO: check for installation of terminal-notifier or alternative as logo isn't supported
updatedPr, err := data.FetchPullRequest(url)
if err != nil {
log.Error("Error fetching updated PR details", "url", url, "err", err)
}

renderedPr := prComponent.PullRequest{Ctx: m.Ctx, Data: updatedPr}
checksRollup := " Checks are pending"
switch renderedPr.GetStatusChecksRollup() {
case "SUCCESS":
checksRollup = "✅ Checks have passed"
case "FAILURE":
checksRollup = "❌ Checks have failed"
}

err = beeep.Notify(
fmt.Sprintf("gh-dash: %s", title),
fmt.Sprintf("PR #%d in %s\n%s", prNumber, repoNameWithOwner, checksRollup),
"",
)
if err != nil {
log.Error("Error showing system notification", "err", err)
}
}()

return constants.TaskFinishedMsg{
SectionId: m.Id,
SectionType: SectionType,
TaskId: taskId,
Err: err,
Msg: UpdatePRMsg{
PrNumber: prNumber,
},
}
})
}
32 changes: 20 additions & 12 deletions ui/keys/prKeys.go
@@ -1,17 +1,20 @@
package keys

import "github.com/charmbracelet/bubbles/key"
import (
"github.com/charmbracelet/bubbles/key"
)

type PRKeyMap struct {
Assign key.Binding
Unassign key.Binding
Comment key.Binding
Diff key.Binding
Checkout key.Binding
Close key.Binding
Ready key.Binding
Reopen key.Binding
Merge key.Binding
Assign key.Binding
Unassign key.Binding
Comment key.Binding
Diff key.Binding
Checkout key.Binding
Close key.Binding
Ready key.Binding
Reopen key.Binding
Merge key.Binding
WatchChecks key.Binding
}

var PRKeys = PRKeyMap{
Expand Down Expand Up @@ -44,13 +47,17 @@ var PRKeys = PRKeyMap{
key.WithHelp("X", "reopen"),
),
Ready: key.NewBinding(
key.WithKeys("w"),
key.WithHelp("w", "ready for review"),
key.WithKeys("W"),
key.WithHelp("W", "ready for review"),
),
Merge: key.NewBinding(
key.WithKeys("m"),
key.WithHelp("m", "merge"),
),
WatchChecks: key.NewBinding(
key.WithKeys("w"),
key.WithHelp("w", "Watch checks"),
),
}

func PRFullHelp() []key.Binding {
Expand All @@ -64,5 +71,6 @@ func PRFullHelp() []key.Binding {
PRKeys.Ready,
PRKeys.Reopen,
PRKeys.Merge,
PRKeys.WatchChecks,
}
}
10 changes: 9 additions & 1 deletion ui/ui.go
Expand Up @@ -249,7 +249,15 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.sidebar.ScrollToBottom()
return m, cmd

case key.Matches(msg, keys.PRKeys.Close, keys.PRKeys.Reopen, keys.PRKeys.Ready, keys.PRKeys.Merge, keys.IssueKeys.Close, keys.IssueKeys.Reopen):
case key.Matches(
msg,
keys.PRKeys.Close,
keys.PRKeys.Reopen,
keys.PRKeys.Ready,
keys.PRKeys.Merge,
keys.IssueKeys.Close,
keys.IssueKeys.Reopen,
):

var action string
switch {
Expand Down

0 comments on commit f4f5731

Please sign in to comment.