Skip to content

Commit 2aa193e

Browse files
steipetefernandopps
andcommitted
feat(chat): add react shorthand command for reactions create (#435)
- add 'chat messages react <message> <emoji>' as a direct shorthand for reaction creation - keep 'reaction' as the alias for the 'reactions' command group - add regression coverage for the shorthand path Co-authored-by: Fernando Pina dos Santos <fernando.dossantos@trilogy.com>
1 parent 2fe9d95 commit 2aa193e

File tree

5 files changed

+69
-3
lines changed

5 files changed

+69
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
- Admin: add Workspace Admin Directory commands for users and groups, including user list/get/create/suspend and group membership list/add/remove. (#403) — thanks @dl-alexandre.
77
- Auth: add `--access-token` / `GOG_ACCESS_TOKEN` for direct access-token auth in headless or CI flows, bypassing stored refresh tokens. (#419) — thanks @mmkal.
88
- Auth: add Application Default Credentials mode via `GOG_AUTH_MODE=adc` for Workload Identity, Cloud Run, and local `gcloud` ADC flows without stored OAuth refresh tokens. (#357) — thanks @tengis617.
9-
- Chat: add `chat messages reactions create|list|delete` to manage emoji reactions on messages; `react` and `reaction` are aliases for the reactions command group. (#426) — thanks @fernandopps.
9+
- Chat: add `chat messages reactions create|list|delete` to manage emoji reactions on messages; `chat messages react <message> <emoji>` as a shorthand for creating reactions; `reaction` is an alias for `reactions`. (#426) — thanks @fernandopps.
1010
- Sheets: add named range management (`sheets named-ranges`) and let range-based Sheets commands accept named range names where GridRange-backed operations are needed. (#278) — thanks @TheCrazyLex.
1111
- Sheets: add `add-tab`, `rename-tab`, and `delete-tab` commands for managing spreadsheet tabs, with delete dry-run/confirmation guardrails. (#309) — thanks @JulienMalige.
1212
- Docs: add `--tab-id` to editing commands so write/update/insert/delete/find-replace can target a specific Google Docs tab. (#330) — thanks @ignacioreyna.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,7 @@ gog chat messages list spaces/<spaceId> --thread <threadId>
11311131
gog chat messages list spaces/<spaceId> --unread
11321132
gog chat messages send spaces/<spaceId> --text "Build complete!" --thread spaces/<spaceId>/threads/<threadId>
11331133
gog chat messages reactions list spaces/<spaceId>/messages/<messageId>
1134-
gog chat messages react spaces/<spaceId>/messages/<messageId> "👍"
1134+
gog chat messages react spaces/<spaceId>/messages/<messageId> "👍" # shorthand for reactions create
11351135
gog chat messages reactions delete spaces/<spaceId>/messages/<messageId>/reactions/<reactionId>
11361136

11371137
# Threads

internal/cmd/chat_messages.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import (
1515
type ChatMessagesCmd struct {
1616
List ChatMessagesListCmd `cmd:"" name:"list" aliases:"ls" help:"List messages"`
1717
Send ChatMessagesSendCmd `cmd:"" name:"send" aliases:"create,post" help:"Send a message"`
18-
Reactions ChatMessagesReactionsCmd `cmd:"" name:"reactions" aliases:"react,reaction" help:"Manage emoji reactions on a message"`
18+
React ChatMessagesReactCmd `cmd:"" name:"react" help:"Add an emoji reaction to a message"`
19+
Reactions ChatMessagesReactionsCmd `cmd:"" name:"reactions" aliases:"reaction" help:"Manage emoji reactions on a message"`
1920
}
2021

2122
type ChatMessagesListCmd struct {

internal/cmd/chat_reactions.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ import (
1212
"github.com/steipete/gogcli/internal/ui"
1313
)
1414

15+
type ChatMessagesReactCmd struct {
16+
Message string `arg:"" name:"message" help:"Message resource (spaces/.../messages/...) or bare message ID"`
17+
Emoji string `arg:"" name:"emoji" help:"Emoji unicode character (e.g. 👍)"`
18+
Space string `name:"space" help:"Space name (required when message is a bare ID)"`
19+
}
20+
21+
func (c *ChatMessagesReactCmd) Run(ctx context.Context, flags *RootFlags) error {
22+
cmd := &ChatMessagesReactionsCreateCmd{Message: c.Message, Emoji: c.Emoji, Space: c.Space}
23+
return cmd.Run(ctx, flags)
24+
}
25+
1526
type ChatMessagesReactionsCmd struct {
1627
Create ChatMessagesReactionsCreateCmd `cmd:"" name:"create" aliases:"add" help:"Add an emoji reaction to a message"`
1728
List ChatMessagesReactionsListCmd `cmd:"" name:"list" aliases:"ls" help:"List reactions on a message"`

internal/cmd/chat_reactions_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,60 @@ func TestExecute_ChatMessagesReactionsCreate_BareIDWithSpace(t *testing.T) {
165165
}
166166
}
167167

168+
func TestExecute_ChatMessagesReact_Shorthand(t *testing.T) {
169+
origNew := newChatService
170+
t.Cleanup(func() { newChatService = origNew })
171+
172+
var gotPath string
173+
var gotEmoji string
174+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
175+
if !(r.Method == http.MethodPost && strings.Contains(r.URL.Path, "/reactions")) {
176+
http.NotFound(w, r)
177+
return
178+
}
179+
gotPath = r.URL.Path
180+
var body map[string]any
181+
_ = json.NewDecoder(r.Body).Decode(&body)
182+
if emoji, ok := body["emoji"].(map[string]any); ok {
183+
gotEmoji, _ = emoji["unicode"].(string)
184+
}
185+
w.Header().Set("Content-Type", "application/json")
186+
_ = json.NewEncoder(w).Encode(map[string]any{
187+
"name": "spaces/AAA/messages/msg1/reactions/r1",
188+
"emoji": map[string]any{"unicode": gotEmoji},
189+
})
190+
}))
191+
defer srv.Close()
192+
193+
svc, err := chat.NewService(context.Background(),
194+
option.WithoutAuthentication(),
195+
option.WithHTTPClient(srv.Client()),
196+
option.WithEndpoint(srv.URL+"/"),
197+
)
198+
if err != nil {
199+
t.Fatalf("NewService: %v", err)
200+
}
201+
newChatService = func(context.Context, string) (*chat.Service, error) { return svc, nil }
202+
203+
out := captureStdout(t, func() {
204+
_ = captureStderr(t, func() {
205+
if err := Execute([]string{"--account", "a@b.com", "chat", "messages", "react", "spaces/AAA/messages/msg1", "📦"}); err != nil {
206+
t.Fatalf("Execute: %v", err)
207+
}
208+
})
209+
})
210+
211+
if !strings.Contains(gotPath, "spaces/AAA/messages/msg1/reactions") {
212+
t.Fatalf("unexpected request path: %q", gotPath)
213+
}
214+
if gotEmoji != "📦" {
215+
t.Fatalf("unexpected emoji sent: %q", gotEmoji)
216+
}
217+
if !strings.Contains(out, "spaces/AAA/messages/msg1/reactions/r1") {
218+
t.Fatalf("unexpected output: %q", out)
219+
}
220+
}
221+
168222
func TestExecute_ChatMessagesReactionsCreate_ConsumerBlocked(t *testing.T) {
169223
origNew := newChatService
170224
t.Cleanup(func() { newChatService = origNew })

0 commit comments

Comments
 (0)