keel/bot/hipchat/hipchat.go

194 lines
4.2 KiB
Go

package hipchat
import (
"context"
"errors"
"os"
"regexp"
"strconv"
"strings"
"github.com/keel-hq/keel/bot"
"github.com/keel-hq/keel/constants"
h "github.com/daneharrigan/hipchat"
log "github.com/sirupsen/logrus"
)
const connectionAttemptsDefault = 5
// Bot - main hipchat bot container
type Bot struct {
id string // bot id
name string // bot name
userName string // bot user name
password string // bot user password
hipchatClient XmppImplementer
approvalsChannel string
ctx context.Context
botMessagesChannel chan *bot.BotMessage
approvalsRespCh chan *bot.ApprovalResponse
}
func init() {
if isHipchatConfigured() {
bot.RegisterBot("hipchat", &Bot{})
}
}
func (b *Bot) Configure(approvalsRespCh chan *bot.ApprovalResponse, botMessagesChannel chan *bot.BotMessage) bool {
if isHipchatConfigured() {
b.name = "keel"
if os.Getenv(constants.EnvHipchatApprovalsBotName) != "" {
b.name = os.Getenv(constants.EnvHipchatApprovalsBotName)
}
b.userName = os.Getenv(constants.EnvHipchatApprovalsUserName)
b.password = os.Getenv(constants.EnvHipchatApprovalsPasswort)
connAttempts := getConnectionAttempts()
cli := connect(b.userName, b.password, connAttempts)
if cli != nil {
b.hipchatClient = cli
}
b.botMessagesChannel = botMessagesChannel
b.approvalsRespCh = approvalsRespCh
b.approvalsChannel = "general"
if os.Getenv(constants.EnvHipchatApprovalsChannel) != "" {
b.approvalsChannel = os.Getenv(constants.EnvHipchatApprovalsChannel)
}
return true
}
log.Info("bot.hipchat.Configure(): HipChat approval bot is not configured")
return false
}
// Start the bot
func (b *Bot) Start(ctx context.Context) error {
if b.hipchatClient == nil {
return errors.New("could not conect to hipchat server")
}
// setting root context
b.ctx = ctx
client := b.hipchatClient
client.Status("chat")
client.Join(b.approvalsChannel, b.name)
b.postMessage("Keel bot was started")
go client.KeepAlive()
go func() {
for {
select {
case <-b.ctx.Done():
return
case message := <-client.Messages():
b.handleMessage(message)
}
}
}()
return nil
}
func (b *Bot) Respond(response string, channel string) {
b.hipchatClient.Say(channel, b.name, formatAsSnippet(response))
}
func (b *Bot) handleMessage(message *h.Message) {
msg := b.trimXMPPMessage(message)
if msg.From == "" || msg.To == "" {
log.Debugln("hipchat.handleMessage(): fields 'From:' or 'To:' are empty, ignore")
return
}
if !b.isBotMessage(msg) {
log.Debugf("handleMessage(): is not a bot message [%#v]", msg)
return
}
approval, ok := bot.IsApproval(msg.From, msg.Body)
if ok {
b.approvalsRespCh <- approval
return
}
b.botMessagesChannel <- &bot.BotMessage{
Message: msg.Body,
User: msg.From,
Channel: b.approvalsChannel,
Name: "hipchat",
}
return
}
func formatAsSnippet(msg string) string {
return "/code " + msg
}
func (b *Bot) trimXMPPMessage(message *h.Message) *h.Message {
msg := h.Message{}
msg.Body = b.trimBot(message.Body)
msg.From = b.trimUser(message.From)
msg.To = b.trimUser(message.To)
return &msg
}
func (b *Bot) trimUser(user string) string {
re := regexp.MustCompile("/(.*?)$")
match := re.FindStringSubmatch(user)
if match == nil {
return ""
}
if len(match) != 0 {
return match[1]
}
return ""
}
func (b *Bot) postMessage(msg string) error {
b.hipchatClient.Say(b.approvalsChannel, b.name, msg)
return nil
}
func (b *Bot) trimBot(msg string) string {
var re = regexp.MustCompile(`(^@\w+)`)
msg = re.ReplaceAllString(msg, "")
msg = strings.Trim(msg, "\n")
msg = strings.TrimSpace(msg)
return strings.ToLower(msg)
}
func (b *Bot) isBotMessage(message *h.Message) bool {
if message.To == "bot" {
return true
}
return false
}
func isHipchatConfigured() bool {
if os.Getenv(constants.EnvHipchatApprovalsPasswort) != "" &&
os.Getenv(constants.EnvHipchatApprovalsUserName) != "" {
return true
}
return false
}
func getConnectionAttempts() int {
if os.Getenv(constants.EnvHipchatConnectionAttempts) != "" {
i, err := strconv.Atoi(os.Getenv(constants.EnvHipchatConnectionAttempts))
if err == nil {
return i
}
return connectionAttemptsDefault
}
return connectionAttemptsDefault
}