Skip to content

Commit 1c28330

Browse files
Thomas StrombergThomas Stromberg
authored andcommitted
Improve block styling
1 parent 520bdc6 commit 1c28330

File tree

5 files changed

+284
-565
lines changed

5 files changed

+284
-565
lines changed

pkg/dailyreport/report.go

Lines changed: 20 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55
"context"
66
"fmt"
77
"log/slog"
8-
"sort"
9-
"strings"
108
"time"
119

1210
"github.com/codeGROOVE-dev/slacker/pkg/home"
@@ -224,146 +222,40 @@ func randomGreeting() string {
224222
}
225223

226224
// Pick greeting based on time for variety
227-
greetingIdx := (now.Hour()*60 + now.Minute()) % len(greetings)
228-
return greetings[greetingIdx]
225+
i := (now.Hour()*60 + now.Minute()) % len(greetings)
226+
return greetings[i]
229227
}
230228

231-
// formatPRLine formats a single PR as a line of text (goose-inspired format).
232-
// Returns a string like: "■ repo#123 • title — action" or " repo#456 • title".
233-
func formatPRLine(pr *home.PR) string {
234-
// Extract repo name from "org/repo" format
235-
parts := strings.SplitN(pr.Repository, "/", 2)
236-
repo := pr.Repository
237-
if len(parts) == 2 {
238-
repo = parts[1]
239-
}
240-
241-
// Determine bullet character based on blocking status
242-
var bullet string
243-
switch {
244-
case pr.IsBlocked || pr.NeedsReview:
245-
// Critical: blocked on user
246-
bullet = "■"
247-
case pr.ActionKind != "":
248-
// Non-critical: has action but not blocking
249-
bullet = "•"
250-
default:
251-
// No action for user - use 2-space indent to align with bullets
252-
bullet = " "
253-
}
254-
255-
// Build PR reference with link
256-
ref := fmt.Sprintf("<%s|%s#%d>", pr.URL, repo, pr.Number)
257-
258-
// Build line: bullet repo#123 • title
259-
line := fmt.Sprintf("%s %s • %s", bullet, ref, pr.Title)
260-
261-
// Add action kind if present (only show user's next action)
262-
if pr.ActionKind != "" {
263-
action := strings.ReplaceAll(pr.ActionKind, "_", " ")
264-
line = fmt.Sprintf("%s — %s", line, action)
265-
}
266-
267-
return line
268-
}
269-
270-
// BuildReportBlocks creates Block Kit blocks for a daily report.
271-
// Format inspired by goose - simple, minimal, action-focused.
229+
// BuildReportBlocks creates Block Kit blocks for a daily report with greeting.
230+
// Uses home.BuildPRSections for consistent formatting with the dashboard.
272231
func BuildReportBlocks(incoming, outgoing []home.PR) []slack.Block {
273-
// Sort PRs by most recently updated first (make copies to avoid modifying input)
274-
incomingSorted := make([]home.PR, len(incoming))
275-
copy(incomingSorted, incoming)
276-
sort.Slice(incomingSorted, func(i, j int) bool {
277-
return incomingSorted[i].UpdatedAt.After(incomingSorted[j].UpdatedAt)
278-
})
279-
280-
outgoingSorted := make([]home.PR, len(outgoing))
281-
copy(outgoingSorted, outgoing)
282-
sort.Slice(outgoingSorted, func(i, j int) bool {
283-
return outgoingSorted[i].UpdatedAt.After(outgoingSorted[j].UpdatedAt)
284-
})
232+
slog.Info("building report blocks",
233+
"incoming_count", len(incoming),
234+
"outgoing_count", len(outgoing))
235+
236+
// Log outgoing PRs to debug blocking detection
237+
for i := range outgoing {
238+
slog.Info("outgoing PR for report",
239+
"pr", outgoing[i].URL,
240+
"title", outgoing[i].Title,
241+
"is_blocked", outgoing[i].IsBlocked,
242+
"action_kind", outgoing[i].ActionKind,
243+
"action_reason", outgoing[i].ActionReason)
244+
}
285245

286246
var blocks []slack.Block
287247

288248
// Greeting
289-
greeting := randomGreeting()
290249
blocks = append(blocks,
291250
slack.NewSectionBlock(
292-
slack.NewTextBlockObject("mrkdwn", fmt.Sprintf("%s Here is your daily report:", greeting), false, false),
251+
slack.NewTextBlockObject("mrkdwn", fmt.Sprintf("%s Here is your daily report:", randomGreeting()), false, false),
293252
nil,
294253
nil,
295254
),
296255
)
297256

298-
// Incoming PRs section (only if there are incoming PRs)
299-
if len(incomingSorted) > 0 {
300-
// Count blocked PRs
301-
n := 0
302-
for i := range incomingSorted {
303-
if incomingSorted[i].IsBlocked || incomingSorted[i].NeedsReview {
304-
n++
305-
}
306-
}
307-
308-
// Section header
309-
header := "*Incoming*"
310-
if n > 0 {
311-
if n == 1 {
312-
header = "*Incoming — 1 blocked on you*"
313-
} else {
314-
header = fmt.Sprintf("*Incoming — %d blocked on you*", n)
315-
}
316-
}
317-
318-
// Build PR list
319-
var prLines []string
320-
for i := range incomingSorted {
321-
prLines = append(prLines, formatPRLine(&incomingSorted[i]))
322-
}
323-
324-
blocks = append(blocks,
325-
slack.NewSectionBlock(
326-
slack.NewTextBlockObject("mrkdwn", header+"\n\n"+strings.Join(prLines, "\n"), false, false),
327-
nil,
328-
nil,
329-
),
330-
)
331-
}
332-
333-
// Outgoing PRs section (only if there are outgoing PRs)
334-
if len(outgoingSorted) > 0 {
335-
// Count blocked PRs
336-
n := 0
337-
for i := range outgoingSorted {
338-
if outgoingSorted[i].IsBlocked {
339-
n++
340-
}
341-
}
342-
343-
// Section header
344-
header := "*Outgoing*"
345-
if n > 0 {
346-
if n == 1 {
347-
header = "*Outgoing — 1 blocked on you*"
348-
} else {
349-
header = fmt.Sprintf("*Outgoing — %d blocked on you*", n)
350-
}
351-
}
352-
353-
// Build PR list
354-
var prLines []string
355-
for i := range outgoingSorted {
356-
prLines = append(prLines, formatPRLine(&outgoingSorted[i]))
357-
}
358-
359-
blocks = append(blocks,
360-
slack.NewSectionBlock(
361-
slack.NewTextBlockObject("mrkdwn", header+"\n\n"+strings.Join(prLines, "\n"), false, false),
362-
nil,
363-
nil,
364-
),
365-
)
366-
}
257+
// Add PR sections (uses home.BuildPRSections for unified formatting)
258+
blocks = append(blocks, home.BuildPRSections(incoming, outgoing)...)
367259

368260
return blocks
369261
}

pkg/home/fetcher.go

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package home
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"log/slog"
78
"net/http"
@@ -254,8 +255,15 @@ func (f *Fetcher) enrichPRs(ctx context.Context, prs []PR, githubUsername string
254255

255256
results := make(chan enrichResult, len(prs))
256257

257-
for i := range prs {
258+
for prIdx := range prs {
258259
go func(idx int, pr PR) {
260+
slog.Info("calling turnclient for PR enrichment",
261+
"pr", pr.URL,
262+
"github_user", githubUsername,
263+
"incoming", incoming,
264+
"bot_username", f.botUsername,
265+
"last_event_time", pr.LastEventTime)
266+
259267
// Use LastEventTime for cache optimization - it's the most recent timestamp
260268
// we know about (max of GitHub UpdatedAt and sprinkler LastEventTime)
261269
var checkResult *turn.CheckResponse
@@ -273,13 +281,42 @@ func (f *Fetcher) enrichPRs(ctx context.Context, prs []PR, githubUsername string
273281
retry.Context(ctx),
274282
)
275283
if err != nil {
276-
slog.Debug("turnclient check failed after retries, using basic PR data",
284+
slog.Warn("turnclient check failed after retries, using basic PR data",
277285
"pr", pr.URL,
286+
"github_user", githubUsername,
287+
"incoming", incoming,
278288
"error", err)
279289
results <- enrichResult{idx: idx, pr: pr}
280290
return
281291
}
282292

293+
// Marshal full response for debugging
294+
responseJSON, err := json.Marshal(checkResult)
295+
if err != nil {
296+
slog.Warn("failed to marshal turnclient response", "pr", pr.URL, "error", err)
297+
} else {
298+
slog.Info("turnclient full response",
299+
"pr", pr.URL,
300+
"github_user", githubUsername,
301+
"incoming", incoming,
302+
"last_event_time_param", pr.LastEventTime,
303+
"response_json", string(responseJSON))
304+
}
305+
306+
slog.Info("turnclient returned response",
307+
"pr", pr.URL,
308+
"github_user", githubUsername,
309+
"incoming", incoming,
310+
"workflow_state", checkResult.Analysis.WorkflowState,
311+
"next_action_count", len(checkResult.Analysis.NextAction),
312+
"next_action_keys", func() []string {
313+
keys := make([]string, 0, len(checkResult.Analysis.NextAction))
314+
for k := range checkResult.Analysis.NextAction {
315+
keys = append(keys, k)
316+
}
317+
return keys
318+
}())
319+
283320
// Extract action for this user
284321
if action, exists := checkResult.Analysis.NextAction[githubUsername]; exists {
285322
pr.ActionReason = action.Reason
@@ -290,6 +327,30 @@ func (f *Fetcher) enrichPRs(ctx context.Context, prs []PR, githubUsername string
290327
} else {
291328
pr.IsBlocked = action.Critical
292329
}
330+
331+
slog.Info("found action for user in turnclient response",
332+
"pr", pr.URL,
333+
"github_user", githubUsername,
334+
"action_kind", action.Kind,
335+
"critical", action.Critical,
336+
"reason", action.Reason,
337+
"incoming", incoming,
338+
"is_blocked", pr.IsBlocked,
339+
"needs_review", pr.NeedsReview)
340+
} else {
341+
// No action for this user in the response
342+
slog.Debug("no action for user in turnclient response",
343+
"pr", pr.URL,
344+
"github_user", githubUsername,
345+
"incoming", incoming,
346+
"workflow_state", checkResult.Analysis.WorkflowState,
347+
"next_action_keys", func() []string {
348+
keys := make([]string, 0, len(checkResult.Analysis.NextAction))
349+
for k := range checkResult.Analysis.NextAction {
350+
keys = append(keys, k)
351+
}
352+
return keys
353+
}())
293354
}
294355

295356
// Extract test state from Analysis
@@ -306,7 +367,7 @@ func (f *Fetcher) enrichPRs(ctx context.Context, prs []PR, githubUsername string
306367
}
307368

308369
results <- enrichResult{idx: idx, pr: pr}
309-
}(i, prs[i])
370+
}(prIdx, prs[prIdx])
310371
}
311372

312373
// Collect results in original order

0 commit comments

Comments
 (0)