Skip to content

Commit

Permalink
Add incident summary as initial content when adding a note
Browse files Browse the repository at this point in the history
Adds an incident summary (format below) to the initial content when
opening the editor to add a note to an incident, and drops comment lines
("#") before writing the note, mirroring the behavior of a git commit
message.

Fixes #37

Format:

```
```

Signed-off-by: Chris Collins <[email protected]>
  • Loading branch information
clcollins committed Jul 30, 2024
1 parent b85e627 commit 6cc5f13
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 12 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Features:
* Reassign incidents to a (configured) "silent" user (ie. silence the alert)
* Acknowledge incidents
* Resizes nicely(-ish) when the terminal is resized
* Un-Acknowledge incidents (re-assign to the Escalation Policy)

Planned Features:

* Un-Acknowledge incidents (re-assign to the Escalation Policy)
* View arbitrary incidents
* Assign incidents to any PagerDuty User ID
* Edit incident titles
Expand Down
58 changes: 51 additions & 7 deletions pkg/tui/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"os/exec"
"slices"
"strings"
"time"

"github.com/PagerDuty/go-pagerduty"
Expand Down Expand Up @@ -301,7 +302,7 @@ type editorFinishedMsg struct {
file *os.File
}

func openEditorCmd(editor []string) tea.Cmd {
func openEditorCmd(editor []string, initialMsg ...string) tea.Cmd {
log.Debug("tui.openEditorCmd(): opening editor")
var args []string

Expand All @@ -313,6 +314,18 @@ func openEditorCmd(editor []string) tea.Cmd {
}
}

if len(initialMsg) > 0 {
for _, msg := range initialMsg {
_, err = file.WriteString(msg)
if err != nil {
log.Debug(fmt.Sprintf("tui.openEditorCmd(): error: %v", err))
return func() tea.Msg {
return errMsg{error: err}
}
}
}
}

args = append(args, editor[1:]...)
args = append(args, file.Name())

Expand All @@ -328,6 +341,19 @@ func openEditorCmd(editor []string) tea.Cmd {
})
}

type parseTemplateForNoteMsg string
type parsedTemplateForNoteMsg struct {
content string
err error
}

func parseTemplateForNote(p *pagerduty.Incident) tea.Cmd {
return func() tea.Msg {
content, err := addNoteTemplate(p.HTMLURL, p.Title, p.Service.Summary)
return parsedTemplateForNoteMsg{content, err}
}
}

type loginMsg string
type loginFinishedMsg struct {
err error
Expand Down Expand Up @@ -469,30 +495,48 @@ type addedIncidentNoteMsg struct {
err error
}

func addNoteToIncident(p *pd.Config, incident *pagerduty.Incident, content *os.File) tea.Cmd {
func addNoteToIncident(p *pd.Config, incident *pagerduty.Incident, file *os.File) tea.Cmd {
return func() tea.Msg {
defer content.Close()
defer file.Close()

bytes, err := os.ReadFile(content.Name())
bytes, err := os.ReadFile(file.Name())
if err != nil {
return errMsg{err}
}
content := string(bytes[:])

note := removeCommentsFromBytes(bytes, "#")

u, err := p.Client.GetCurrentUserWithContext(context.Background(), pagerduty.GetCurrentUserOptions{})
if err != nil {
return errMsg{err}
}

if content != "" {
n, err := pd.PostNote(p.Client, incident.ID, u, content)
if note != "" {
n, err := pd.PostNote(p.Client, incident.ID, u, note)
return addedIncidentNoteMsg{n, err}
}

return addedIncidentNoteMsg{nil, errors.New(nilNoteErr)}
}
}

// removeCommentsFromBytes removes any lines beginning with any of the provided prefixes []byte and returns a string.
func removeCommentsFromBytes(b []byte, prefixes ...string) string {
var content strings.Builder

lines := strings.Split(string(b[:]), "\n")

for _, c := range lines {
for _, a := range prefixes {
if !strings.HasPrefix(c, a) {
content.WriteString(c)
}
}
}

return content.String()
}

// getTeamsAsStrings returns a slice of team IDs as strings from the []*pagerduty.Teams in a *pd.Config
func getTeamsAsStrings(p *pd.Config) []string {
var teams []string
Expand Down
6 changes: 2 additions & 4 deletions pkg/tui/msgHandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@ func switchTableFocusMode(m model, msg tea.Msg) (tea.Model, tea.Cmd) {
return m, doIfIncidentSelected(&m, tea.Sequence(
func() tea.Msg { return getIncidentMsg(incidentID) },
func() tea.Msg {
return waitForSelectedIncidentThenDoMsg{action: openEditorCmd(m.editor), msg: "add note"}
msg := "add note"
return waitForSelectedIncidentThenDoMsg{action: func() tea.Msg { return parseTemplateForNoteMsg(msg) }, msg: msg}
},
))

Expand Down Expand Up @@ -300,9 +301,6 @@ func switchIncidentFocusMode(m model, msg tea.Msg) (tea.Model, tea.Cmd) {
case key.Matches(msg, defaultKeyMap.Silence):
return m, func() tea.Msg { return silenceSelectedIncidentMsg{} }

case key.Matches(msg, defaultKeyMap.Note):
cmds = append(cmds, openEditorCmd(m.editor))

case key.Matches(msg, defaultKeyMap.Refresh):
return m, func() tea.Msg { return getIncidentMsg(m.selectedIncident.ID) }

Expand Down
12 changes: 12 additions & 0 deletions pkg/tui/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,18 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.setStatus(fmt.Sprintf("showing %d/%d incidents...", len(m.table.Rows()), totalIncidentCount))
}

case parseTemplateForNoteMsg:
if m.selectedIncident == nil {
m.setStatus("failed to open editor - no selected incident")
}
cmds = append(cmds, parseTemplateForNote(m.selectedIncident))

case parsedTemplateForNoteMsg:
if msg.err != nil {
return m, func() tea.Msg { return errMsg{msg.err} }
}
cmds = append(cmds, openEditorCmd(m.editor, msg.content))

case editorFinishedMsg:
if msg.err != nil {
return m, func() tea.Msg { return errMsg{msg.err} }
Expand Down
35 changes: 35 additions & 0 deletions pkg/tui/views.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ var (

paddedStyle = mainStyle.Padding(0, 2, 0, 1)

//lint:ignore U1000 - future proofing
warningStyle = lipgloss.NewStyle().Foreground(srepdPallet.warning.text).Background(srepdPallet.warning.background)

tableContainerStyle = lipgloss.NewStyle().Border(lipgloss.RoundedBorder(), true)
Expand Down Expand Up @@ -248,6 +249,29 @@ func (m model) template() (string, error) {
return o.String(), nil
}

func addNoteTemplate(id string, title string, service string) (string, error) {
template, err := template.New("note").Parse(noteTemplate)
if err != nil {
return "", err
}

o := new(bytes.Buffer)
err = template.Execute(o, struct {
ID string
Title string
Service string
}{
ID: id,
Title: title,
Service: service,
})
if err != nil {
return "", err
}

return o.String(), nil
}

func summarize(i *pagerduty.Incident, a []pagerduty.IncidentAlert, n []pagerduty.IncidentNote) incidentSummary {
summary := summarizeIncident(i)
summary.Alerts = summarizeAlerts(a)
Expand Down Expand Up @@ -456,3 +480,14 @@ func renderIncidentMarkdown(content string) (string, error) {

return str, nil
}

const noteTemplate = `
# Please enter the note message content above. Lines starting
# with '#' will be ignored and an empty message aborts the note.
#
# Incident: {{ .ID }}
# Summary: {{ .Title }}
# Service: {{ .Service }}
#
`

0 comments on commit 6cc5f13

Please sign in to comment.