Skip to content
You're viewing an older version of this GitHub Action. Do you want to see the latest version instead?
git-pull-request

GitHub Action

dstlled-diff

v0.1.3

dstlled-diff

git-pull-request

dstlled-diff

Github action to make reviewing large structural code changes easier

Installation

Copy and paste the following snippet into your .yml file.

              

- name: dstlled-diff

uses: dhth/dstlled-diff-action@v0.1.3

Learn more about this action in dhth/dstlled-diff-action

Choose a version

dstlled-diff action

✨ Overview

dstlled-diff (short for "distilled-diff") is a GitHub action that processes a specific git revision range and generates a diff that only includes changes in the signatures of various code constructs (such as classes, functions, and objects, etc.). It is powered by dstll.

The main goal of dstlled-diff is to simplify the review of structural code changes by removing diff components that do not alter signatures.

pr-comment

Δ Difference to regular git diff

Consider this git diff:

expand
diff --git a/cmd/root.go b/cmd/root.go
index 9bdc5c8..8d40f9b 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -1,89 +1,94 @@
 package cmd
 
 import (
 	"context"
+	"errors"
 	"flag"
 	"fmt"
 	"os"
 	"strings"
 
 	"github.com/aws/aws-sdk-go-v2/config"
 	"github.com/aws/aws-sdk-go-v2/service/sqs"
 	"github.com/dhth/cueitup/ui"
 	"github.com/dhth/cueitup/ui/model"
 )
 
-func die(msg string, args ...any) {
-	fmt.Fprintf(os.Stderr, msg+"\n", args...)
-	os.Exit(1)
-}
+var (
+	errQueueURLEmpty        = errors.New("queue URL is empty")
+	errAWSProfileEmpty      = errors.New("AWS profile is empty")
+	errAWSRegionEmpty       = errors.New("AWS region is empty")
+	errQueueURLIncorrect    = errors.New("queue URL is incorrect")
+	errMsgFormatInvalid     = errors.New("message format is invalid")
+	errInvalidFlagUsage     = errors.New("invalid flag usage")
+	errCouldntLoadAWSConfig = errors.New("couldn't load AWS config")
+)
 
 var (
-	queueUrl   = flag.String("queue-url", "", "url of the queue to consume from")
+	queueURL   = flag.String("queue-url", "", "url of the queue to consume from")
 	awsProfile = flag.String("aws-profile", "", "aws profile to use")
 	awsRegion  = flag.String("aws-region", "", "aws region to use")
 	msgFormat  = flag.String("msg-format", "json", "message format")
 	subsetKey  = flag.String("subset-key", "", "extract a nested object inside the JSON body")
 	contextKey = flag.String("context-key", "", "the key to use as for context in the list")
 )
 
-func Execute() {
-
+func Execute() error {
 	flag.Usage = func() {
 		fmt.Fprintf(os.Stderr, "Inspect messages in an AWS SQS queue in a simple and deliberate manner.\n\nFlags:\n")
 		flag.PrintDefaults()
 		fmt.Fprintf(os.Stderr, "\n------\n%s", model.HelpText)
 	}
 	flag.Parse()
 
-	if *queueUrl == "" {
-		die("queue-url cannot be empty")
-	} else if !strings.HasPrefix(*queueUrl, "https://") {
-		die("queue-url must begin with https")
+	if *queueURL == "" {
+		return errQueueURLEmpty
+	}
+
+	if !strings.HasPrefix(*queueURL, "https://") {
+		return fmt.Errorf("%w: must begin with https", errQueueURLIncorrect)
 	}
 
 	if *awsProfile == "" {
-		die("aws-profile cannot be empty")
+		return errAWSProfileEmpty
 	}
 
 	if *awsRegion == "" {
-		die("aws-region cannot be empty")
+		return errAWSRegionEmpty
 	}
 
 	var msgFmt model.MsgFmt
 	switch *msgFormat {
 	case "json":
-		msgFmt = model.JsonFmt
+		msgFmt = model.JSONFmt
 	case "plaintext":
 		msgFmt = model.PlainTxtFmt
 	default:
-		die("cueitup only supports the following msg-format values: json, plaintext")
+		return fmt.Errorf("%w: supported values: json, plaintext", errMsgFormatInvalid)
 	}
 
-	if *subsetKey != "" && msgFmt != model.JsonFmt {
-		die("subset-key can only be used when msg-format=json")
+	if *subsetKey != "" && msgFmt != model.JSONFmt {
+		return fmt.Errorf("%w: subset-key can only be used when msg-format=json", errInvalidFlagUsage)
 	}
-	if *contextKey != "" && msgFmt != model.JsonFmt {
-		die("context-key can only be used when msg-format=json")
+	if *contextKey != "" && msgFmt != model.JSONFmt {
+		return fmt.Errorf("%w: context-key can only be used when msg-format=json", errInvalidFlagUsage)
 	}
 
 	msgConsumptionConf := model.MsgConsumptionConf{
 		Format:     msgFmt,
 		SubsetKey:  *subsetKey,
 		ContextKey: *contextKey,
 	}
 
 	sdkConfig, err := config.LoadDefaultConfig(context.TODO(),
 		config.WithSharedConfigProfile(*awsProfile),
 		config.WithRegion(*awsRegion),
 	)
 	if err != nil {
-		fmt.Println("Error:", err)
-		os.Exit(1)
+		return fmt.Errorf("%w: %s", errCouldntLoadAWSConfig, err.Error())
 	}
 
 	sqsClient := sqs.NewFromConfig(sdkConfig)
 
-	ui.RenderUI(sqsClient, *queueUrl, msgConsumptionConf)
-
+	return ui.RenderUI(sqsClient, *queueURL, msgConsumptionConf)
 }
diff --git a/cueitup.go b/main.go
similarity index 54%
rename from cueitup.go
rename to main.go
index 4a28df2..0480ca2 100644
--- a/cueitup.go
+++ b/main.go
@@ -1,9 +1,14 @@
 package main
 
 import (
+	"os"
+
 	"github.com/dhth/cueitup/cmd"
 )
 
 func main() {
-	cmd.Execute()
+	err := cmd.Execute()
+	if err != nil {
+		os.Exit(1)
+	}
 }
diff --git a/ui/model/cmds.go b/ui/model/cmds.go
index 837bbeb..038dbd3 100644
--- a/ui/model/cmds.go
+++ b/ui/model/cmds.go
@@ -8,91 +8,86 @@ import (
 	"strconv"
 	"strings"
 	"time"
 
 	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go-v2/service/sqs"
 	"github.com/aws/aws-sdk-go-v2/service/sqs/types"
 	tea "github.com/charmbracelet/bubbletea"
 )
 
-func (m model) FetchMessages(maxMessages int32, waitTime int32) tea.Cmd {
+func (m Model) FetchMessages(maxMessages int32, waitTime int32) tea.Cmd {
 	return func() tea.Msg {
-
 		var messages []types.Message
 		var messagesValues []string
 		var keyValues []string
 		result, err := m.sqsClient.ReceiveMessage(context.TODO(),
 			// WaitTimeSeconds > 0 enables long polling
 			// https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html#sqs-long-polling
 			&sqs.ReceiveMessageInput{
-				QueueUrl:            aws.String(m.queueUrl),
+				QueueUrl:            aws.String(m.queueURL),
 				MaxNumberOfMessages: maxMessages,
 				WaitTimeSeconds:     waitTime,
 				VisibilityTimeout:   30,
 			})
 		if err != nil {
 			return SQSMsgFetchedMsg{
 				messages: nil,
 				err:      err,
 			}
-		} else {
-			messages = result.Messages
-			for _, message := range messages {
-				msgValue, keyValue, _ := getMessageData(&message, m.msgConsumptionConf)
-				messagesValues = append(messagesValues, msgValue)
-				keyValues = append(keyValues, keyValue)
-			}
+		}
+		messages = result.Messages
+		for _, message := range messages {
+			msgValue, keyValue, _ := getMessageData(&message, m.msgConsumptionConf)
+			messagesValues = append(messagesValues, msgValue)
+			keyValues = append(keyValues, keyValue)
 		}
 
 		return SQSMsgFetchedMsg{
 			messages:      messages,
 			messageValues: messagesValues,
 			keyValues:     keyValues,
 			err:           nil,
 		}
 	}
 }
 
-func DeleteMessages(client *sqs.Client, queueUrl string, messages []types.Message) tea.Cmd {
+func DeleteMessages(client *sqs.Client, queueURL string, messages []types.Message) tea.Cmd {
 	return func() tea.Msg {
-
 		entries := make([]types.DeleteMessageBatchRequestEntry, len(messages))
 		for msgIndex := range messages {
 			entries[msgIndex].Id = aws.String(fmt.Sprintf("%v", msgIndex))
 			entries[msgIndex].ReceiptHandle = messages[msgIndex].ReceiptHandle
 		}
 		_, err := client.DeleteMessageBatch(context.TODO(),
 			&sqs.DeleteMessageBatchInput{
 				Entries:  entries,
-				QueueUrl: aws.String(queueUrl),
+				QueueUrl: aws.String(queueURL),
 			})
 		if err != nil {
 			return SQSMsgsDeletedMsg{
 				err: err,
 			}
 		}
 
 		return SQSMsgsDeletedMsg{}
 	}
 }
 
-func GetQueueMsgCount(client *sqs.Client, queueUrl string) tea.Cmd {
+func GetQueueMsgCount(client *sqs.Client, queueURL string) tea.Cmd {
 	return func() tea.Msg {
-
 		approxMsgCountType := types.QueueAttributeNameApproximateNumberOfMessages
 		attribute, err := client.GetQueueAttributes(context.TODO(),
 			&sqs.GetQueueAttributesInput{
-				QueueUrl:       aws.String(queueUrl),
+				QueueUrl:       aws.String(queueURL),
 				AttributeNames: []types.QueueAttributeName{approxMsgCountType},
 			})
-
 		if err != nil {
 			return QueueMsgCountFetchedMsg{
 				approxMsgCount: -1,
 				err:            err,
 			}
 		}
 
 		countStr := attribute.Attributes[string(approxMsgCountType)]
 		count, err := strconv.Atoi(countStr)
 		if err != nil {
@@ -103,32 +98,32 @@ func GetQueueMsgCount(client *sqs.Client, queueUrl string) tea.Cmd {
 		}
 		return QueueMsgCountFetchedMsg{
 			approxMsgCount: count,
 		}
 	}
 }
 
 func saveRecordValueToDisk(filePath string, msgValue string, msgFmt MsgFmt) tea.Cmd {
 	return func() tea.Msg {
 		dir := filepath.Dir(filePath)
-		err := os.MkdirAll(dir, 0755)
+		err := os.MkdirAll(dir, 0o755)
 		if err != nil {
 			return RecordSavedToDiskMsg{err: err}
 		}
 		var data string
 		switch msgFmt {
-		case JsonFmt:
+		case JSONFmt:
 			data = fmt.Sprintf("json\n%s\n", msgValue)
 		case PlainTxtFmt:
 			data = msgValue
 		}
-		err = os.WriteFile(filePath, []byte(data), 0644)
+		err = os.WriteFile(filePath, []byte(data), 0o644)
 		if err != nil {
 			return RecordSavedToDiskMsg{err: err}
 		}
 		return RecordSavedToDiskMsg{path: filePath}
 	}
 }
 
 func setContextSearchValues(userInput string) tea.Cmd {
 	return func() tea.Msg {
 		valuesEls := strings.Split(userInput, ",")
diff --git a/ui/model/delegate.go b/ui/model/delegate.go
index 80805d4..be199a1 100644
--- a/ui/model/delegate.go
+++ b/ui/model/delegate.go
@@ -11,35 +11,34 @@ func newAppItemDelegate() list.DefaultDelegate {
 	d := list.NewDefaultDelegate()
 
 	d.Styles.SelectedTitle = d.Styles.
 		SelectedTitle.
 		Foreground(lipgloss.Color(listColor)).
 		BorderLeftForeground(lipgloss.Color(listColor))
 	d.Styles.SelectedDesc = d.Styles.
 		SelectedTitle
 
 	d.UpdateFunc = func(msg tea.Msg, m *list.Model) tea.Cmd {
-		switch msgType := msg.(type) {
-		case tea.KeyMsg:
-			switch {
-			case key.Matches(msgType,
-				list.DefaultKeyMap().CursorUp,
-				list.DefaultKeyMap().CursorDown,
-				list.DefaultKeyMap().GoToStart,
-				list.DefaultKeyMap().GoToEnd,
-				list.DefaultKeyMap().NextPage,
-				list.DefaultKeyMap().PrevPage,
-			):
-				selected := m.SelectedItem()
-				if selected == nil {
-					return nil
-				}
-				key := selected.FilterValue()
-				return showItemDetails(key)
+		keyMsg, keyMsgOK := msg.(tea.KeyMsg)
+		if !keyMsgOK {
+			return nil
+		}
+		if key.Matches(keyMsg,
+			list.DefaultKeyMap().CursorUp,
+			list.DefaultKeyMap().CursorDown,
+			list.DefaultKeyMap().GoToStart,
+			list.DefaultKeyMap().GoToEnd,
+			list.DefaultKeyMap().NextPage,
+			list.DefaultKeyMap().PrevPage,
+		) {
+			selected := m.SelectedItem()
+			if selected == nil {
+				return nil
 			}
-
+			key := selected.FilterValue()
+			return showItemDetails(key)
 		}
 		return nil
 	}
 
 	return d
 }
diff --git a/ui/model/help.go b/ui/model/help.go
index 76c4bc5..7f9c7d6 100644
--- a/ui/model/help.go
+++ b/ui/model/help.go
@@ -1,61 +1,59 @@
 package model
 
 import "fmt"
 
-var (
-	HelpText = fmt.Sprintf(`
+var HelpText = fmt.Sprintf(`
   %s
 %s
   %s
 
   %s
 %s
   %s
 %s
   %s
 %s
 `,
-		helpHeaderStyle.Render("cueitup Reference Manual"),
-		helpSectionStyle.Render(`
+	helpHeaderStyle.Render("cueitup Reference Manual"),
+	helpSectionStyle.Render(`
   (scroll line by line with j/k/arrow keys or by half a page with <c-d>/<c-u>)
 
   cueitup has 3 views:
   - Message List View
   - Message Value View
   - Help View (this one)
 `),
-		helpHeaderStyle.Render("Keyboard Shortcuts"),
-		helpHeaderStyle.Render("General"),
-		helpSectionStyle.Render(`
+	helpHeaderStyle.Render("Keyboard Shortcuts"),
+	helpHeaderStyle.Render("General"),
+	helpSectionStyle.Render(`
       <tab>                          Switch focus to next section
       <s-tab>                        Switch focus to previous section
       1                              Maximize message value view
       ?                              Show help view
 `),
-		helpHeaderStyle.Render("Message List View"),
-		helpSectionStyle.Render(`
+	helpHeaderStyle.Render("Message List View"),
+	helpSectionStyle.Render(`
       h/<Up>                         Move cursor up
       k/<Down>                       Move cursor down
       n                              Fetch the next message from the queue
       N                              Fetch up to 10 more messages from the queue
       }                              Fetch up to 100 more messages from the queue
       d                              Toggle deletion mode; cueitup will delete messages
                                          after reading them
       <ctrl+s>                       Toggle contextual search prompt
       <ctrl+f>                       Toggle contextual filtering ON/OFF
       <ctrl+p>                       Toggle queue message count polling ON/OFF; ON by default
       p                              Toggle persist mode (cueitup will start persisting
                                          messages, at the location
                                          messages/<topic-name>/<timestamp-when-cueitup-started>/<unix-epoch>-<message-id>.md
       s                              Toggle skipping mode; cueitup will consume messages,
                                          but not populate its internal list, effectively
                                          skipping over them
 `),
-		helpHeaderStyle.Render("Message Value View   "),
-		helpSectionStyle.Render(`
+	helpHeaderStyle.Render("Message Value View   "),
+	helpSectionStyle.Render(`
       q                              Minimize section, and return focus to list view
       [,h                            Show details for the previous entry in the list
       ],l                            Show details for the next entry in the list
 `),
-	)
 )
diff --git a/ui/model/initial.go b/ui/model/initial.go
index e037600..28dd396 100644
--- a/ui/model/initial.go
+++ b/ui/model/initial.go
@@ -5,45 +5,44 @@ import (
 	"os"
 	"strings"
 	"time"
 
 	"github.com/aws/aws-sdk-go-v2/service/sqs"
 	"github.com/charmbracelet/bubbles/list"
 	"github.com/charmbracelet/bubbles/textinput"
 	"github.com/charmbracelet/lipgloss"
 )
 
-func InitialModel(sqsClient *sqs.Client, queueUrl string, msgConsumptionConf MsgConsumptionConf) model {
-
+func InitialModel(sqsClient *sqs.Client, queueURL string, msgConsumptionConf MsgConsumptionConf) Model {
 	appDelegate := newAppItemDelegate()
 	jobItems := make([]list.Item, 0)
 
-	queueParts := strings.Split(queueUrl, "/")
+	queueParts := strings.Split(queueURL, "/")
 	queueName := queueParts[len(queueParts)-1]
 	currentTime := time.Now()
 	timeString := currentTime.Format("2006-01-02-15-04-05")
 	persistDir := fmt.Sprintf("messages/%s/%s", queueName, timeString)
 
 	ti := textinput.New()
 	ti.Prompt = fmt.Sprintf("Filter messages where %s in > ", msgConsumptionConf.ContextKey)
 	ti.Focus()
 	ti.CharLimit = 100
 	ti.Width = 100
 
 	var dbg bool
 	if len(os.Getenv("DEBUG")) > 0 {
 		dbg = true
 	}
 
-	m := model{
+	m := Model{
 		sqsClient:            sqsClient,
-		queueUrl:             queueUrl,
+		queueURL:             queueURL,
 		msgConsumptionConf:   msgConsumptionConf,
 		pollForQueueMsgCount: true,
 		msgsList:             list.New(jobItems, appDelegate, listWidth+10, 0),
 		recordValueStore:     make(map[string]string),
 		persistDir:           persistDir,
 		contextSearchInput:   ti,
 		showHelpIndicator:    true,
 		debugMode:            dbg,
 		firstFetch:           true,
 	}
diff --git a/ui/model/model.go b/ui/model/model.go
index 73f2a00..cce4fc8 100644
--- a/ui/model/model.go
+++ b/ui/model/model.go
@@ -15,36 +15,36 @@ type stateView uint
 const (
 	msgsListView stateView = iota
 	msgValueView
 	helpView
 	contextualSearchView
 )
 
 type MsgFmt uint
 
 const (
-	JsonFmt MsgFmt = iota
+	JSONFmt MsgFmt = iota
 	PlainTxtFmt
 )
 
 const msgCountTickInterval = time.Second * 3
 
 type MsgConsumptionConf struct {
 	Format     MsgFmt
 	SubsetKey  string
 	ContextKey string
 }
 
-type model struct {
+type Model struct {
 	deserializationFmt   MsgFmt
 	sqsClient            *sqs.Client
-	queueUrl             string
+	queueURL             string
 	msgConsumptionConf   MsgConsumptionConf
 	activeView           stateView
 	lastView             stateView
 	pollForQueueMsgCount bool
 	msgsList             list.Model
 	helpVP               viewport.Model
 	showHelpIndicator    bool
 	msgValueVP           viewport.Model
 	recordValueStore     map[string]string
 	contextSearchInput   textinput.Model
@@ -58,17 +58,17 @@ type model struct {
 	helpVPReady          bool
 	vpFullScreen         bool
 	terminalWidth        int
 	terminalHeight       int
 	message              string
 	errorMsg             string
 	debugMode            bool
 	firstFetch           bool
 }
 
-func (m model) Init() tea.Cmd {
+func (m Model) Init() tea.Cmd {
 	return tea.Batch(
-		GetQueueMsgCount(m.sqsClient, m.queueUrl),
+		GetQueueMsgCount(m.sqsClient, m.queueURL),
 		tickEvery(msgCountTickInterval),
 		hideHelp(time.Minute*1),
 	)
 }
diff --git a/ui/model/msgs.go b/ui/model/msgs.go
index 15ec498..e1e52a4 100644
--- a/ui/model/msgs.go
+++ b/ui/model/msgs.go
@@ -1,18 +1,20 @@
 package model
 
 import (
 	"github.com/aws/aws-sdk-go-v2/service/sqs/types"
 )
 
-type MsgCountTickMsg struct{}
-type HideHelpMsg struct{}
+type (
+	MsgCountTickMsg struct{}
+	HideHelpMsg     struct{}
+)
 
 type SQSMsgFetchedMsg struct {
 	messages      []types.Message
 	messageValues []string
 	keyValues     []string
 	err           error
 }
 
 type QueueMsgCountFetchedMsg struct {
 	approxMsgCount int
diff --git a/ui/model/types.go b/ui/model/types.go
index 565b8cb..48c5646 100644
--- a/ui/model/types.go
+++ b/ui/model/types.go
@@ -18,12 +18,12 @@ func (item msgItem) Title() string {
 }
 
 func (item msgItem) Description() string {
 	if item.contextKeyValue != "" {
 		return RightPadTrim(fmt.Sprintf("%s: %s", RightPadTrim(item.contextKeyName, 10), item.contextKeyValue), listWidth)
 	}
 	return ""
 }
 
 func (item msgItem) FilterValue() string {
-	return string(*item.message.MessageId)
+	return *item.message.MessageId
 }
diff --git a/ui/model/update.go b/ui/model/update.go
index ba99b5b..41ae3b9 100644
--- a/ui/model/update.go
+++ b/ui/model/update.go
@@ -3,23 +3,26 @@ package model
 import (
 	"fmt"
 	"time"
 
 	"github.com/charmbracelet/bubbles/list"
 	"github.com/charmbracelet/bubbles/viewport"
 	tea "github.com/charmbracelet/bubbletea"
 	"github.com/tidwall/pretty"
 )
 
-const useHighPerformanceRenderer = false
+const (
+	useHighPerformanceRenderer = false
+	fetchingIndicator          = " ..."
+)
 
-func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	var cmds []tea.Cmd
 	m.message = ""
 	m.errorMsg = ""
 
 	switch msg := msg.(type) {
 	case tea.KeyMsg:
 		switch msg.String() {
 		case "ctrl+c", "q":
 			switch m.activeView {
 			case msgsListView:
@@ -41,31 +44,31 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		case "enter":
 			if m.activeView == contextualSearchView {
 				m.activeView = m.lastView
 				if len(m.contextSearchInput.Value()) > 0 {
 					cmds = append(cmds, setContextSearchValues(m.contextSearchInput.Value()))
 				} else {
 					m.filterMessages = false
 				}
 			}
 		case "n", " ":
-			m.message = " ..."
+			m.message = fetchingIndicator
 			cmds = append(cmds, m.FetchMessages(1, 0))
 		case "N":
-			m.message = " ..."
+			m.message = fetchingIndicator
 			for i := 0; i < 10; i++ {
 				cmds = append(cmds,
 					m.FetchMessages(1, 0),
 				)
 			}
 		case "}":
-			m.message = " ..."
+			m.message = fetchingIndicator
 			for i := 0; i < 20; i++ {
 				cmds = append(cmds,
 					m.FetchMessages(5, 0),
 				)
 			}
 		case "?":
 			m.lastView = m.activeView
 			m.activeView = helpView
 		case "d":
 			if m.activeView == msgsListView {
@@ -96,21 +99,21 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 				selected := m.msgsList.SelectedItem()
 				if selected != nil {
 					result := string(pretty.Color([]byte(m.recordValueStore[selected.FilterValue()]), nil))
 					m.msgValueVP.SetContent(result)
 				}
 			}
 		case "ctrl+p":
 			m.pollForQueueMsgCount = !m.pollForQueueMsgCount
 			if m.pollForQueueMsgCount {
 				cmds = append(cmds,
-					tea.Batch(GetQueueMsgCount(m.sqsClient, m.queueUrl),
+					tea.Batch(GetQueueMsgCount(m.sqsClient, m.queueURL),
 						tickEvery(msgCountTickInterval),
 					),
 				)
 			}
 		case "ctrl+s":
 			if m.activeView == msgsListView {
 				m.lastView = m.activeView
 				m.activeView = contextualSearchView
 			}
 		case "ctrl+f":
@@ -184,82 +187,84 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		m.contextSearchInput.SetValue("")
 		m.filterMessages = true
 
 	case HideHelpMsg:
 		m.showHelpIndicator = false
 
 	case SQSMsgFetchedMsg:
 		if msg.err != nil {
 			m.errorMsg = msg.err.Error()
 		} else {
-			switch m.skipRecords {
-			case false:
+			if !m.skipRecords {
 				vPresenceMap := make(map[string]bool)
 				if m.filterMessages && len(m.contextSearchValues) > 0 {
 					for _, p := range m.contextSearchValues {
 						vPresenceMap[p] = true
 					}
 				}
 				for i, message := range msg.messages {
-
 					// only save/persist values that are requested to be filtered
 					if m.filterMessages && !(msg.keyValues[i] != "" && vPresenceMap[msg.keyValues[i]]) {
 						continue
 					}
 
 					m.msgsList.InsertItem(len(m.msgsList.Items()),
-						msgItem{message: message,
+						msgItem{
+							message:         message,
 							messageValue:    msg.messageValues[i],
 							contextKeyName:  m.msgConsumptionConf.ContextKey,
 							contextKeyValue: msg.keyValues[i],
 						},
 					)
 					m.recordValueStore[*message.MessageId] = msg.messageValues[i]
+
 					if m.persistRecords {
 						prefix := time.Now().Unix()
 						filePath := fmt.Sprintf("%s/%d-%s.md", m.persistDir, prefix, *message.MessageId)
 						cmds = append(cmds,
 							saveRecordValueToDisk(
 								filePath,
 								msg.messageValues[i],
 								m.msgConsumptionConf.Format,
 							),
 						)
 					}
 				}
+
 				if m.deleteMsgs {
 					cmds = append(cmds,
 						DeleteMessages(m.sqsClient,
-							m.queueUrl,
+							m.queueURL,
 							msg.messages),
 					)
 				}
+
 				if m.firstFetch {
 					selected := m.msgsList.SelectedItem()
 					if selected != nil {
 						result := string(pretty.Color([]byte(m.recordValueStore[selected.FilterValue()]), nil))
 						m.msgValueVP.SetContent(result)
 						m.firstFetch = false
 					}
 				}
 			}
 		}
 	case KMsgChosenMsg:
 		switch m.deserializationFmt {
-		case JsonFmt:
+		case JSONFmt:
 			result := string(pretty.Color([]byte(m.recordValueStore[msg.key]), nil))
 			m.msgValueVP.SetContent(result)
 		default:
 			m.msgValueVP.SetContent(m.recordValueStore[msg.key])
 		}
 	case MsgCountTickMsg:
-		cmds = append(cmds, GetQueueMsgCount(m.sqsClient, m.queueUrl))
+		cmds = append(cmds, GetQueueMsgCount(m.sqsClient, m.queueURL))
 		if m.pollForQueueMsgCount {
 			cmds = append(cmds, tickEvery(msgCountTickInterval))
 		}
 	case QueueMsgCountFetchedMsg:
 		if msg.err != nil {
 			m.errorMsg = msg.err.Error()
 		} else {
 			m.msgsList.Title = fmt.Sprintf("Messages (%d in queue)", msg.approxMsgCount)
 		}
 	}
diff --git a/ui/model/utils.go b/ui/model/utils.go
index 21bdc83..24bb3d3 100644
--- a/ui/model/utils.go
+++ b/ui/model/utils.go
@@ -80,30 +80,29 @@ func getRecordValueJSONNested(message *types.Message, extractKey string, context
 	}
 
 	return string(nestedBytes), contextualValue.(string), nil
 }
 
 func getMessageData(message *types.Message, msgConsumptionConf MsgConsumptionConf) (string, string, error) {
 	var msgValue, keyValue string
 	var err error
 
 	switch msgConsumptionConf.Format {
-	case JsonFmt:
+	case JSONFmt:
 		if msgConsumptionConf.SubsetKey != "" {
 			msgValue,
 				keyValue,
 				err = getRecordValueJSONNested(message,
 				msgConsumptionConf.SubsetKey,
 				msgConsumptionConf.ContextKey,
 			)
 		} else {
 			msgValue, err = getRecordValueJSONFull(message)
 		}
 	case PlainTxtFmt:
 		msgValue = *message.Body
 	}
 	if err != nil {
 		return "", "", err
-	} else {
-		return msgValue, keyValue, nil
 	}
+	return msgValue, keyValue, nil
 }
diff --git a/ui/model/view.go b/ui/model/view.go
index 5de1437..5e2bf63 100644
--- a/ui/model/view.go
+++ b/ui/model/view.go
@@ -1,23 +1,21 @@
 package model
 
 import (
 	"fmt"
 
 	"github.com/charmbracelet/lipgloss"
 )
 
-var (
-	listWidth = 50
-)
+var listWidth = 50
 
-func (m model) View() string {
+func (m Model) View() string {
 	var content string
 	var footer string
 	var mode string
 	var statusBar string
 	var debugMsg string
 	var msgValVPTitleStyle lipgloss.Style
 
 	if m.message != "" {
 		statusBar = Trim(m.message, 120)
 	}
diff --git a/ui/ui.go b/ui/ui.go
index f13c6e7..381c448 100644
--- a/ui/ui.go
+++ b/ui/ui.go
@@ -1,27 +1,26 @@
 package ui
 
 import (
+	"errors"
 	"fmt"
-	"log"
 	"os"
 
 	"github.com/aws/aws-sdk-go-v2/service/sqs"
 	tea "github.com/charmbracelet/bubbletea"
 	"github.com/dhth/cueitup/ui/model"
 )
 
-func RenderUI(sqsClient *sqs.Client, queueUrl string, msgConsumptionConf model.MsgConsumptionConf) {
+var errFailedToConfigureDebugging = errors.New("failed to configure debugging")
 
+func RenderUI(sqsClient *sqs.Client, queueURL string, msgConsumptionConf model.MsgConsumptionConf) error {
 	if len(os.Getenv("DEBUG")) > 0 {
 		f, err := tea.LogToFile("debug.log", "debug")
 		if err != nil {
-			fmt.Println("fatal:", err)
-			os.Exit(1)
+			return fmt.Errorf("%w: %s", errFailedToConfigureDebugging, err.Error())
 		}
 		defer f.Close()
 	}
-	p := tea.NewProgram(model.InitialModel(sqsClient, queueUrl, msgConsumptionConf), tea.WithAltScreen())
-	if _, err := p.Run(); err != nil {
-		log.Fatalf("Something went wrong %s", err)
-	}
+	p := tea.NewProgram(model.InitialModel(sqsClient, queueURL, msgConsumptionConf), tea.WithAltScreen())
+	_, err := p.Run()
+	return err
 }

The "distilled-diff" version of the same diff looks like the following:

expand
diff --git a/5c52f68/cmd/root.go b/941d77f/cmd/root.go
index 7e245d5..a1c36f6 100644
--- a/5c52f68/cmd/root.go
+++ b/941d77f/cmd/root.go
@@ -1,2 +1 @@
-func die(msg string, args ...any)
-func Execute()
+func Execute() error
diff --git a/5c52f68/cueitup.go b/941d77f/main.go
similarity index 100%
rename from 5c52f68/cueitup.go
rename to 941d77f/main.go
diff --git a/5c52f68/ui/model/cmds.go b/941d77f/ui/model/cmds.go
index 35aaf4d..e429709 100644
--- a/5c52f68/ui/model/cmds.go
+++ b/941d77f/ui/model/cmds.go
@@ -1,2 +1,2 @@
-func DeleteMessages(client *sqs.Client, queueUrl string, messages []types.Message) tea.Cmd
-func GetQueueMsgCount(client *sqs.Client, queueUrl string) tea.Cmd
+func DeleteMessages(client *sqs.Client, queueURL string, messages []types.Message) tea.Cmd
+func GetQueueMsgCount(client *sqs.Client, queueURL string) tea.Cmd
@@ -8 +8 @@ func hideHelp(interval time.Duration) tea.Cmd
-func (m model) FetchMessages(maxMessages int32, waitTime int32) tea.Cmd
+func (m Model) FetchMessages(maxMessages int32, waitTime int32) tea.Cmd
diff --git a/5c52f68/ui/model/initial.go b/941d77f/ui/model/initial.go
index 1381c76..7654528 100644
--- a/5c52f68/ui/model/initial.go
+++ b/941d77f/ui/model/initial.go
@@ -1 +1 @@
-func InitialModel(sqsClient *sqs.Client, queueUrl string, msgConsumptionConf MsgConsumptionConf) model
+func InitialModel(sqsClient *sqs.Client, queueURL string, msgConsumptionConf MsgConsumptionConf) Model
diff --git a/5c52f68/ui/model/model.go b/941d77f/ui/model/model.go
index 30e48cb..992323e 100644
--- a/5c52f68/ui/model/model.go
+++ b/941d77f/ui/model/model.go
@@ -8 +8 @@ type MsgConsumptionConf struct {
-type model struct {
+type Model struct {
@@ -11 +11 @@ type model struct {
-	queueUrl             string
+	queueURL             string
@@ -38 +38 @@ type model struct {
-func (m model) Init() tea.Cmd
+func (m Model) Init() tea.Cmd
diff --git a/5c52f68/ui/model/msgs.go b/941d77f/ui/model/msgs.go
index 38d7c0c..48a036f 100644
--- a/5c52f68/ui/model/msgs.go
+++ b/941d77f/ui/model/msgs.go
@@ -1,2 +1,4 @@
-type MsgCountTickMsg struct{}
-type HideHelpMsg struct{}
+type (
+	MsgCountTickMsg struct{}
+	HideHelpMsg     struct{}
+)
diff --git a/5c52f68/ui/model/update.go b/941d77f/ui/model/update.go
index bf16682..3a8f3d0 100644
--- a/5c52f68/ui/model/update.go
+++ b/941d77f/ui/model/update.go
@@ -1 +1 @@
-func (m model) Update(tea.Model, tea.Cmd)
+func (m Model) Update(tea.Model, tea.Cmd)
diff --git a/5c52f68/ui/model/view.go b/941d77f/ui/model/view.go
index c62ab48..80c398e 100644
--- a/5c52f68/ui/model/view.go
+++ b/941d77f/ui/model/view.go
@@ -1 +1 @@
-func (m model) View() string
+func (m Model) View() string
diff --git a/5c52f68/ui/ui.go b/941d77f/ui/ui.go
index f8e0ecf..ebdc12a 100644
--- a/5c52f68/ui/ui.go
+++ b/941d77f/ui/ui.go
@@ -1 +1 @@
-func RenderUI(sqsClient *sqs.Client, queueUrl string, msgConsumptionConf model.MsgConsumptionConf)
+func RenderUI(sqsClient *sqs.Client, queueURL string, msgConsumptionConf model.MsgConsumptionConf) error

As seen above, the "distilled" version only shows changes in function signatures, and type definitions, which makes maks reviewing large-scale refactors easier.

⚡️ Usage

name: dstlled-diff

on:
  pull_request:

jobs:
  dstlled-diff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - id: get-dstlled-diff
        uses: dhth/dstlled-diff-action@v0.1.0
        with:
          starting-commit: ${{ github.event.pull_request.base.sha }}
          ending-commit: ${{ github.event.pull_request.head.sha }}
          post-comment-on-pr: 'true'

The "dstlled-diff" will be available as an output of the action, via steps.get-dstlled-diff.outputs.diff.

🔡 Inputs

Following inputs can be used as step.with keys:

Name Type Default Description
starting-commit String Starting commit for the git revision range
ending-commit String Ending commit for the git revision range
pattern String * Pattern to run dstlled-diff on
directory String . Working directory (below repository root)
post-comment-on-pr Bool false Post comment containing dstlled-diff to corresponding pull request
save-diff-to-file Bool false Save diff to a local file called diff.patch

⚙️ Use cases

Web Interface

The output of dstlled-diff can be rendered in a web view (see it running [here][2]), as seen in the image below. Code for this can be found here.

web-demo