Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions advertisement.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package slackbot

import (
"fmt"
"slices"
"strings"

"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"
)

type commandAdvertiser interface {
AdvertiseCommands(commands []chat1.UserBotCommandInput) error
}

func (b *Bot) AddAdvertisements(commands ...chat1.UserBotCommandInput) {
b.advertisements = append(b.advertisements, commands...)
}

func (b *Bot) AdvertisedCommands() []chat1.UserBotCommandInput {
commands := []chat1.UserBotCommandInput{{
Name: "help",
Description: "Show available commands",
Usage: fmt.Sprintf("!%s help", b.name),
ExtendedDescription: b.helpExtendedDescription(),
}}

for _, trigger := range b.triggers() {
command := b.commands[trigger]
commands = append(commands, chat1.UserBotCommandInput{
Name: trigger,
Description: command.Description(),
Usage: fmt.Sprintf("!%s %s", b.name, trigger),
})
}

extras := slices.Clone(b.advertisements)
slices.SortFunc(extras, func(a, b chat1.UserBotCommandInput) int {
return strings.Compare(a.Name, b.Name)
})
commands = append(commands, extras...)

return commands
}

func (b *Bot) advertiseCommands() error {
advertiser, ok := b.backend.(commandAdvertiser)
if !ok {
return nil
}
return advertiser.AdvertiseCommands(b.AdvertisedCommands())
}

func (b *Bot) helpExtendedDescription() *chat1.UserBotExtendedDescription {
help := strings.TrimSpace(b.resolvedHelp())
if help == "" {
return nil
}
return &chat1.UserBotExtendedDescription{
Title: fmt.Sprintf("%s help", b.name),
DesktopBody: help,
MobileBody: help,
}
}
19 changes: 14 additions & 5 deletions bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"sort"
"strings"
"text/tabwriter"

"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"
)

type BotCommandRunner interface {
Expand All @@ -30,6 +32,7 @@ type Bot struct {
label string
config Config
commands map[string]Command
advertisements []chat1.UserBotCommandInput
defaultCommand Command
}

Expand Down Expand Up @@ -138,19 +141,25 @@ func (b *Bot) run(args []string, command Command, channel string) {
}
}

func (b *Bot) sendHelpMessage(channel string) {
help := b.help
if help == "" {
help = b.HelpMessage()
func (b *Bot) resolvedHelp() string {
if b.help != "" {
return b.help
}
b.backend.SendMessage(help, channel)
return b.HelpMessage()
}

func (b *Bot) sendHelpMessage(channel string) {
b.backend.SendMessage(b.resolvedHelp(), channel)
}

func (b *Bot) SendMessage(text string, channel string) {
b.backend.SendMessage(text, channel)
}

func (b *Bot) Listen() {
if err := b.advertiseCommands(); err != nil {
log.Printf("Error advertising commands: %s", err)
}
b.backend.Listen(b)
}

Expand Down
44 changes: 41 additions & 3 deletions bot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ package slackbot

import (
"testing"

"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"
"github.com/stretchr/testify/require"
)

func TestHelp(t *testing.T) {
bot, err := NewTestBot()
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
bot.AddCommand("date", NewExecCommand("/bin/date", nil, true, "Show the current date", &config{}))
bot.AddCommand("utc", NewExecCommand("/bin/date", []string{"-u"}, true, "Show the current date (utc)", &config{}))
msg := bot.HelpMessage()
Expand All @@ -27,3 +28,40 @@ func TestParseInput(t *testing.T) {
t.Fatal("Invalid parse")
}
}

func TestAdvertisedCommands(t *testing.T) {
bot, err := NewTestBot()
require.NoError(t, err)
bot.AddCommand("date", NewExecCommand("/bin/date", nil, true, "Show the current date", &config{}))
bot.SetHelp("help body")
bot.AddAdvertisements(chat1.UserBotCommandInput{
Name: "build",
Description: "Build things",
Usage: "!testbot build <target>",
})

commands := bot.AdvertisedCommands()
if len(commands) != 3 {
t.Fatalf("expected 3 advertised commands, got %d", len(commands))
}
if commands[0].Name != "help" {
t.Fatalf("expected help command first, got %q", commands[0].Name)
}
if commands[0].ExtendedDescription == nil || commands[0].ExtendedDescription.DesktopBody != "help body" {
t.Fatalf("unexpected help extended description: %+v", commands[0].ExtendedDescription)
}
if commands[1] != (chat1.UserBotCommandInput{
Name: "date",
Description: "Show the current date",
Usage: "!testbot date",
}) {
t.Fatalf("unexpected builtin command: %+v", commands[1])
}
if commands[2] != (chat1.UserBotCommandInput{
Name: "build",
Description: "Build things",
Usage: "!testbot build <target>",
}) {
t.Fatalf("unexpected extra command: %+v", commands[2])
}
}
15 changes: 15 additions & 0 deletions kbchat.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ func (b *KeybaseChatBotBackend) SendMessage(text string, convID string) {
}
}

func (b *KeybaseChatBotBackend) AdvertiseCommands(commands []chat1.UserBotCommandInput) error {
if b.convID == "" {
return nil
}
_, err := b.kbc.AdvertiseCommands(kbchat.Advertisement{
Alias: b.name,
Advertisements: []chat1.AdvertiseCommandAPIParam{{
Typ: "conv",
Commands: commands,
ConvID: b.convID,
}},
})
return err
}

func (b *KeybaseChatBotBackend) Listen(runner BotCommandRunner) {
sub, err := b.kbc.ListenForNewTextMessages()
if err != nil {
Expand Down
16 changes: 16 additions & 0 deletions keybot/keybot.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strconv"
"strings"

"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"
"github.com/keybase/slackbot"
"github.com/keybase/slackbot/cli"
"github.com/keybase/slackbot/launchd"
Expand Down Expand Up @@ -311,3 +312,18 @@ func (k *keybot) Help(bot *slackbot.Bot) string {
}
return out
}

func (k *keybot) Advertisements(bot *slackbot.Bot) []chat1.UserBotCommandInput {
prefix := "!" + bot.Name()
return []chat1.UserBotCommandInput{
{Name: "build", Description: "Build darwin, mobile, android, or ios artifacts", Usage: prefix + " build <darwin|mobile|android|ios> [flags]"},
{Name: "cancel", Description: "Cancel a launchd job by label", Usage: prefix + " cancel <label>"},
{Name: "dumplog", Description: "Show the log file for a launchd job", Usage: prefix + " dumplog <label>"},
{Name: "gclean", Description: "Clean the go/go-ios/go-android repos", Usage: prefix + " gclean"},
{Name: "gdiff", Description: "Show the git diff for a repo under $GOPATH/src", Usage: prefix + " gdiff <repo>"},
{Name: "nodeModuleClean", Description: "Clean the ios/android node_modules", Usage: prefix + " nodeModuleClean"},
{Name: "release", Description: "Promote or mark releases as broken", Usage: prefix + " release <promote|broken> ..."},
{Name: "smoketest", Description: "Set smoketesting status for a build", Usage: prefix + " smoketest --build-a <id> --platform <name> --enable <bool> --max-testers <n>"},
{Name: "upgrade", Description: "Upgrade a package", Usage: prefix + " upgrade <name>"},
}
}
3 changes: 3 additions & 0 deletions keybot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"runtime"

"github.com/keybase/go-keybase-chat-bot/kbchat"
"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"

"github.com/keybase/slackbot"
"github.com/keybase/slackbot/launchd"
Expand Down Expand Up @@ -68,6 +69,7 @@ func addBasicCommands(bot *slackbot.Bot) {
type extension interface {
Run(b *slackbot.Bot, channel string, args []string) (string, error)
Help(bot *slackbot.Bot) string
Advertisements(bot *slackbot.Bot) []chat1.UserBotCommandInput
}

func main() {
Expand Down Expand Up @@ -143,6 +145,7 @@ func main() {
}
bot.SetDefault(slackbot.NewFuncCommand(runFn, "Extension", bot.Config()))
bot.SetHelp(bot.HelpMessage() + "\n\n" + ext.Help(bot))
bot.AddAdvertisements(ext.Advertisements(bot)...)

bot.SendMessage("I'm running.", channel)

Expand Down
14 changes: 14 additions & 0 deletions keybot/winbot.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"sync"
"time"

"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"
"github.com/keybase/slackbot"
"github.com/keybase/slackbot/cli"
kingpin "gopkg.in/alecthomas/kingpin.v2"
Expand Down Expand Up @@ -442,6 +443,19 @@ func (d *winbot) Help(bot *slackbot.Bot) string {
return out
}

func (d *winbot) Advertisements(bot *slackbot.Bot) []chat1.UserBotCommandInput {
prefix := "!" + bot.Name()
return []chat1.UserBotCommandInput{
{Name: "build", Description: "Start a windows build", Usage: prefix + " build [--test] [--client-commit <sha>] [--kbfs-commit <sha>] [--updater-commit <sha>] [--skip-ci] [--smoke] [--dev-cert]"},
{Name: "cancel", Description: "Cancel the current windows build", Usage: prefix + " cancel"},
{Name: "dumplog", Description: "Show the last windows build log file", Usage: prefix + " dumplog"},
{Name: "gclean", Description: "Clean a repo under $GOPATH/src", Usage: prefix + " gclean <repo>"},
{Name: "gdiff", Description: "Show the git diff for a repo under $GOPATH/src", Usage: prefix + " gdiff <repo>"},
{Name: "restart", Description: "Quit and let the calling script restart the bot", Usage: prefix + " restart"},
{Name: "startAutoTimer", Description: "Start or stop the automatic build timer", Usage: prefix + " startAutoTimer [--interval <hours>] [--startHour <hour>] [--delay <hours>]"},
}
}

func Exists(name string) (bool, error) {
_, err := os.Stat(name)
if os.IsNotExist(err) {
Expand Down
Loading