golang懒人开发者必备的Slack机器人插件slack-bot支持自定义命令和集成Jenkins/Jira/Bitbucket/Github

Golang懒人开发者必备的Slack机器人插件slack-bot

这个Slack机器人可以显著提升开发团队的工作效率,特别针对Jenkins、GitHub、GitLab和Jira的集成提供了开箱即用的支持。同时也支持自定义命令、宏、定时任务等项目特定功能的灵活实现。

安装指南

1. 创建并准备Slack应用

使用Manifest文件作为应用模板:

  1. 创建一个Slack应用(点击"Create New App")
  2. 选择"From an app manifest"
  3. 选择你的工作区
  4. 粘贴以下Yaml代码:
_metadata:
  major_version: 1
  minor_version: 1
display_information:
  name: slack_bot
  background_color: "#382e38"
features:
  app_home:
    messages_tab_enabled: true
    messages_tab_read_only_enabled: false
  bot_user:
    display_name: bot
    always_online: true
oauth_config:
  scopes:
    bot:
      - app_mentions:read
      - channels:read
      - channels:history
      - groups:history
      - chat:write
      - im:history
      - im:write
      - mpim:history
      - reactions:read
      - reactions:write
      - users:read
      - files:read
      - pins:write
settings:
  event_subscriptions:
    bot_events:
      - app_mention
      - message.im
  interactivity:
    is_enabled: true
  org_deploy_enabled: false
  socket_mode_enabled: true
  token_rotation_enabled: false
  1. 创建应用!
  2. “Basic information” → “Display Information” → 上传图片(512px+) + 设置合适的名称
  3. “App Home” → “Show Tabs” → 勾选"Allow users to send Slash commands and messages from the messages tab"
  4. “Basic Information” → “App-Level Tokens” → “Generate Token and scopes” → 使用"bot token"作为token名称,"connections:write"作为scope
  5. 你会看到一个以xapp-开头的App-Level Token。将其设置为config.yaml中的"slack.socket_token"
  6. Basic Information → “Request to install” + "Install to Workspace"继续安装
  7. 然后你会得到另一个token(在"Install App"标签页显示),以"xoxb-"开头。将其作为"slack.token"用在config.yaml中
  8. 在你的Slack客户端中,你可以在任何频道添加机器人或开始私聊

2. 准备配置

首先准备config.yaml,可以参考config-example.yaml:

  • 至少需要Slack token和socket-token

3. 运行机器人

选项1:通过go运行

  1. 安装go(至少1.22)
  2. 创建config.yaml(至少需要Slack token和socket-token)或参考config-example.yaml
  3. go run github.com/innogames/slack-bot/v2/cmd/bot

选项2:通过Docker

  1. 安装Docker包括docker-compose
  2. 克隆此仓库或至少获取docker-compose.yaml
  3. 在config.yaml的"allowed_users:"部分添加你的Slack用户ID或用户名
  4. docker-compose up

选项3:高级:计划在机器人核心上工作时

  1. 安装go
  2. 克隆/分叉此仓库
  3. 运行go run cmd/bot/main.gomake run来运行go应用

使用方式

作为Slack用户,你只需要向机器人用户/应用发送包含要执行命令的私信。此外,你可以将机器人添加到任何频道,并通过在命令前加上@bot_name来执行机器人命令,例如@slack-bot start job DailyDeployment

注意: 你必须邀请机器人进入频道才能处理命令。

机器人命令

帮助

help命令会打印此机器人所有可用命令的列表。使用help *command*你可以获得单个命令的简短描述和一些示例。

Jenkins

机器人能够以简单但强大的方式启动和监控Jenkins作业。

默认情况下,在配置文件中定义"jenkins.host"之前,命令不可用且不会显示在"help"中。

启动Jenkins作业

start job命令启动一个Jenkins作业并显示当前进度。注意: 只有配置中白名单的作业可以启动!

此外,每个作业可以有一个可配置的trigger,这使得可以创建自定义命令来启动作业。(它是一个考虑参数名的正则表达式) 例如,"start daily deployment"可以是一个Jenkins作业的触发器。向机器人发送此文本将启动该作业。

启动作业后,机器人将显示预计的构建时间和一些操作按钮。在那里你可以直接打开日志或中止构建。

机器人还能够解析参数并使用模糊分支搜索查找分支名称。

示例:

  • trigger job DeployBeta
  • start job BackendTests TEST-123(搜索包含TEST-123的完整分支名称,例如feature/TEST-123-added-feature-456)

Jenkins构建通知

机器人还可以为Jenkins构建创建一次性通知。这对于长时间运行的作业,开发人员正在等待结果时可能很有用。

示例:

  • inform me about build NightlyTests(监视最近运行的构建)
  • inform me about build MyJobName #423(指定构建号)
  • inform job MyJobName(替代语法)

Jenkins作业通知

接收给定作业所有处理构建的Slack消息:

示例:

  • watch JenkinsSelfCheck 通知关于Job JenkinsSelfCheck的任何构建
  • unwatch JenkinsSelfCheck

Jenkins状态

禁用/启用Jenkins端作业执行的小命令。

示例:

  • disable job NightlyTests(在Jenkins上禁用作业)
  • enable job NightlyTests

Jenkins重试

当构建失败时,你可以通过以下方式重试任何构建:

示例:

  • retry build NightlyTests(重试作业的最后一次构建)
  • retry build NightlyTests #100(重试给定的构建)

节点

jenkins nodes列出所有可用的Jenkins节点。可以看到在线/离线状态和执行器数量。

拉取请求

如果你只是粘贴GitHub/GitLab/Bitbucket/Stash拉取请求的链接,机器人将跟踪票证的状态!

  • 当开发者被添加为审查者时,它将添加一个"eyes"反应,向其他开发者显示已经有人在查看
  • 当审查者批准票证时,会添加一个勾选标记
  • 合并拉取请求后,它将添加一个"merge"反应

你也可以设置自定义的"approved"反应。例如,要直接查看谁或哪个组件/部门批准了拉取请求,你可以使用反应名称或直接使用Unicode字符

示例配置:

pullrequest:
  reactions:
    merged: custom_merge_arrow
    review: 👀
  custom_approve_reaction:
    nerdydev: "approved_backend"
    iamamobiledev: "approved_mobile"
    iamamobiledev2: "approved_mobile"

额外功能: 对于Bitbucket,机器人能够提取当前构建状态(例如来自Jenkins/Bamboo等),并显示失败和正在运行的构建(火反应)作为反应(圆圈箭头反应)。当构建稳定时,构建反应会消失。

命令队列

queue命令(别名为then)能够将给定命令排队,直到当前运行的命令完成。

示例场景: 你有一个构建作业(可能需要几分钟)和一个依赖于构建产物的部署作业。现在你可以:

  • trigger job Build feature1234 用给定分支启动构建作业
  • queue trigger job DeployBranch feature1234
  • queue reply Deployment is done!

其他示例:

  • delay 1h
  • then send message #backend coffee time?

要查看所有正在运行的背景命令(如Jenkins作业或PR监视器),使用此命令:

  • list queue

Jira

机器人能够从Jira查询信息,无论是单个票证还是一整个票证列表。

默认情况下,在配置文件中定义"jira.host"之前,命令不可用且不会显示在"help"中。

示例

  • jira TEST-1234
  • jira 1242(打开票证,使用配置的默认jira项目)
  • jql type=bug and status=open(默认使用默认项目)
  • jira "Second city"(在默认项目中搜索票证的文本)

也可以在有状态更改的特定Jira票证时获取通知。

示例

  • watch ticket PROJ-12234

交互

可以创建按钮,在按下按钮时执行任何机器人操作。Slack交互

示例:

  • add button "Start Deployment" "trigger job LiveDeployment"

注意

  • 只有白名单用户可以点击按钮
  • 每个按钮只激活一次

自定义变量

配置用户特定变量以自定义机器人行为。例如,每个开发者都有自己的服务器环境。

示例: 使用此全局配置:

commands:
  - name: Deploy
    trigger: "deploy (?P<branch>.*)"
    commands:
      - deploy {{.branch}} to {{ customVariable "defaultServer" }}

每个开发者现在可以调用一次这样的命令:set variable defaultSerer foobarX.local 来注册自定义的"defaultServer"。

当现在调用deploy mater时,它将把master分支部署到foobarX.local服务器。

另一个示例 这是一个使用Go模板的高级版本。 最终,命令将生成一个子命令,如: reply <!here> demo for <https://jira.example.com/TEST-1234|TEST-1234: Example-Ticket> 这将发布链接到Slack频道。

  - name: demo
    trigger: "demo (?P<ticketId>\\w+-\\d+)"
    commands:
      - |
        {{ $ticket := jiraTicket .ticketId }}
        {{ if $ticket }}
          reply <!here> demo for <{{ jiraTicketUrl $ticket.Key }}|{{ $ticket.Key }}: {{ $ticket.Fields.Summary }}>
        {{ else }}
          reply Ticket {{ .ticketId }} not found :white_frowning_face:
        {{ end }}
    description: Informs the current channel about a demo of a Jira ticket. It directly posts a link to the ticket
    examples:
      - demo XYZ-1232

用户可以定义他的默认环境一次,使用set variable serverEnvironment aws-02

然后deploy feature-123将把分支部署到定义的aws-02环境。 每个用户可以定义自己的变量。

Openai/ChatGPT/Dall-e集成

也可以使用官方OpenAI集成(GPT3.5)进行类似ChatGPT的对话!

只需在你的问题前输入"openai"或"chatgpt"以创建一个新线程,其行为类似于众所周知的ChatGPT页面。最后10条消息的内容被用作上下文。 要使其工作,必须在配置中提供有效的"openai.api_key"。

扩展配置:

openai:
  api_key: "sk-123....789"
  initial_system_message: "You are a Slack bot for Project XYZ, please answer shortly."
  update_interval: '3s' # fewer Slack messages update during generation
  model: gpt-3.5-turbo
  temperature: 0.8
  log_texts: true # opt in: log all input/output text to the log

当在现有线程中使用"openai XXX"命令时,先前的消息被用作进一步调用的上下文。

也可以在模板中使用该功能(如在自定义命令或定时任务中)。

{{ openai "Say some short welcome words to @Jon_Doe"}} 会打印类似 Hello Jon, welcome! How can I assist you today? 的内容

DALL-E集成

机器人还能够借助DALL-E生成图像。 只需在你的提示前加上"dalle",机器人就会根据你的文本生成图像。

测验命令

如果你需要小憩并想玩个小测验游戏,你可以通过调用此命令来实现。 不允许超过50个问题。 问题来自不同类别和难度级别,可以是多项选择或真/假问题。

命令

  • quiz 10 开始一个有10个问题的测验
  • answer 1 用第一个答案回答问题

天气命令

可以设置OpenWeatherMap来获取当前位置的当前天气信息。

示例配置:

open_weather:
  apikey: "612325WD623562376678"
  location: "Hamburg, DE"
  units: "metric"

自定义命令

每个用户都能够定义自己的命令别名。 这是一个方便的功能,可以避免每天输入相同的命令。

示例用法

  • list commands 只列出当前用户定义的命令
  • add command 'myCommand' 'trigger job RestoreWorld 7 -> 然后稍后只需调用myCommand
  • add command 'build master' 'trigger job Deploy master ; then trigger job DeployClient master'
  • delete command 'build master'
  • -> 然后你可以执行myCommand来触发这个Jenkins作业

命令

定义的"Commands"(以前称为"Macros")非常神奇,可以在yaml配置文件中定义。

它们有一个触发器(一个正则表达式)和一个将被执行的子命令列表。 它们考虑来自正则表达式的参数组 - 所以它们可以非常灵活!

一个简单的示例,用给定的分支名称同时启动两个Jenkins作业:

commands:
 - name: build clients
   trigger: "build clients (?P<branch>.*)"
   commands:
    - "reply I'll build {{ .branch }} for you"
    - "trigger job BuildFrontendClient {{ .branch }}"
    - "trigger job BuildMobileClient {{ .branch }}"
    - "then reply done! :checkmark:"

注意: 在命令中,你可以使用go模板功能的完整集合 -> 循环/条件是可能的!

模板函数

除了通常的go模板功能外,模板范围内还提供了一堆机器人特定命令。

所有可用函数(带有参数和返回类型)的列表可以通过使用list template functions命令生成。

注意: 这些模板函数可以在不同的命令/功能中使用:

重试

使用retryrepeat将重新执行你最后执行的命令。-> 当失败的Jenkins作业被修复时很有用。

延迟

一个小命令,可能与command命令结合使用或作为Jenkins作业的钩子很有用。

示例命令:delay 10m trigger job DeployWorldwide

作为回复,你将获得一个命令来停止排队的作业(如stop timer 123456)。因为每个人都可以发送命令,该命令可以用于宣布部署,在怀疑时,执行仍然可以被任何人停止。

回复/发送消息

replysend message也是小命令,与command或Jenkins钩子结合使用时很有用。

示例:

  • send message to #backend The job failed :panic:
  • delay 10m send message to @peter_pan I should notify you to...

随机

如果你无法在不同选项之间做出决定,这是一个简单的命令

示例

  • random Pizza Pasta -> 产生"Pizza"或"Pasta"
  • random Peter Paul Tom Jan -> 今天谁必须负责组织食物?

配置

配置通过简单的.yaml文件管理,这些文件存储外部服务的凭据和自定义命令等。

最简单的方法是只有一个包含所有需要选项的config.yaml文件,默认加载config.yaml。也可以将配置拆分为多个文件。

具有多个配置文件的示例结构:

  • secret.yaml 包含外部服务(Slack,Jenkins)的凭据 - 可以通过puppet/ansible等管理
  • jenkins.yaml Jenkins作业及其参数等的配置
  • project-X.yaml 特定团队的自定义命令
  • project-Y.yaml

要加载多个配置文件,使用go run cmd/bot/main.go -config /path/to/config/*.yaml,它会合并所有配置。

Slack

要运行此机器人,你需要一个Slack应用程序的"bot token"。有关如何创建具有所需令牌的适当应用程序,请参阅安装部分。

Jenkins配置

要能够启动或监视Jenkins作业,你必须首先设置主机和凭据。用户需要对作业具有读取权限,并且有权触发白名单中的作业。

jenkins:
     host: https://jenkins.example.de
     username: jenkinsuser
     password: secret

Jenkins作业

要能够启动作业,必须在配置中定义作业及其参数。

没有参数的作业看起来非常简单:

jenkins:
  jobs:
    CleanupJob:

然后你可以使用trigger job CleanupJobstart job CleanupJob来启动作业。它还会在作业成功或失败时通知你(包括错误日志)。

接下来,一个有两个参数的作业:

jenkins:
  jobs:
    RunTests:
      parameters:
      - name: BRANCH
        default: master
        type: branch
      - name: GROUP
        default: all

此作业可以处理两个参数:

  • BRANCH: VCS分支名称,"master"作为默认值
  • GROUP: 可选参数,使用"all"作为默认值

如果你在配置中设置了VCS,你不必传递完整的分支名称,而是可以使用模糊搜索。

示例:

  • start job RunTests 将在master分支上启动"all"组
  • start job JIRA-1224 unit 将尝试为票号找到匹配的分支。(如果没有唯一的搜索结果,则显示错误消息!)

现在是一个更复杂的例子,


更多关于golang懒人开发者必备的Slack机器人插件slack-bot支持自定义命令和集成Jenkins/Jira/Bitbucket/Github的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang懒人开发者必备的Slack机器人插件slack-bot支持自定义命令和集成Jenkins/Jira/Bitbucket/Github的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang Slack机器人插件slack-bot开发指南

作为IT专家,我将介绍如何使用Golang开发一个功能强大的Slack机器人插件,支持自定义命令和集成Jenkins、Jira、Bitbucket、Github等常用开发工具。

核心功能概述

这个slack-bot插件将提供以下功能:

  • 自定义命令处理
  • 与CI/CD工具(Jenkins)集成
  • 项目管理(Jira)集成
  • 代码仓库(Bitbucket/Github)集成
  • 交互式消息响应

基础架构

package main

import (
	"log"
	"os"

	"github.com/slack-go/slack"
	"github.com/slack-go/slack/slackevents"
	"github.com/slack-go/slack/socketmode"
)

type Bot struct {
	api      *slack.Client
	client   *socketmode.Client
	handlers map[string]CommandHandler
}

type CommandHandler func(evt *slackevents.AppMentionEvent) error

func NewBot(token, appToken string) *Bot {
	api := slack.New(
		token,
		slack.OptionAppLevelToken(appToken),
	)
	
	client := socketmode.New(api)
	
	return &Bot{
		api:      api,
		client:   client,
		handlers: make(map[string]CommandHandler),
	}
}

func (b *Bot) RegisterCommand(command string, handler CommandHandler) {
	b.handlers[command] = handler
}

func (b *Bot) Start() {
	go func() {
		for evt := range b.client.Events {
			switch evt.Type {
			case socketmode.EventTypeEventsAPI:
				eventsAPIEvent, ok := evt.Data.(slackevents.EventsAPIEvent)
				if !ok {
					continue
				}
				
				b.client.Ack(*evt.Request)
				
				switch eventsAPIEvent.Type {
				case slackevents.CallbackEvent:
					innerEvent := eventsAPIEvent.InnerEvent
					switch ev := innerEvent.Data.(type) {
					case *slackevents.AppMentionEvent:
						b.handleMention(ev)
					}
				}
			}
		}
	}()
	
	b.client.Run()
}

func (b *Bot) handleMention(evt *slackevents.AppMentionEvent) {
	// 解析命令并调用对应的handler
	// ...
}

自定义命令实现

func main() {
	bot := NewBot(os.Getenv("SLACK_BOT_TOKEN"), os.Getenv("SLACK_APP_TOKEN"))
	
	// 注册自定义命令
	bot.RegisterCommand("hello", func(evt *slackevents.AppMentionEvent) error {
		_, _, err := bot.api.PostMessage(evt.Channel, slack.MsgOptionText("Hello there!", false))
		return err
	})
	
	bot.RegisterCommand("help", func(evt *slackevents.AppMentionEvent) error {
		helpText := "Available commands:\n" +
			"- `hello`: Greet the bot\n" +
			"- `help`: Show this help message\n" +
			"- `jira <issue-id>`: Get Jira issue details\n" +
			"- `jenkins <job-name>`: Trigger Jenkins job"
			
		_, _, err := bot.api.PostMessage(evt.Channel, slack.MsgOptionText(helpText, false))
		return err
	})
	
	bot.Start()
}

集成Jenkins

import (
	"github.com/bndr/gojenkins"
)

type JenkinsClient struct {
	client *gojenkins.Jenkins
}

func NewJenkinsClient(url, user, token string) *JenkinsClient {
	jenkins := gojenkins.CreateJenkins(nil, url, user, token)
	_, err := jenkins.Init()
	if err != nil {
		log.Fatal(err)
	}
	return &JenkinsClient{client: jenkins}
}

func (j *JenkinsClient) TriggerJob(jobName string, params map[string]string) (int64, error) {
	queueID, err := j.client.BuildJob(jobName, params)
	if err != nil {
		return 0, err
	}
	return queueID, nil
}

// 注册Jenkins命令
bot.RegisterCommand("jenkins", func(evt *slackevents.AppMentionEvent) error {
	// 解析参数
	args := strings.Fields(evt.Text)
	if len(args) < 2 {
		return errors.New("Usage: jenkins <job-name>")
	}
	
	jobName := args[1]
	jenkins := NewJenkinsClient(
		os.Getenv("JENKINS_URL"),
		os.Getenv("JENKINS_USER"),
		os.Getenv("JENKINS_TOKEN"),
	)
	
	queueID, err := jenkins.TriggerJob(jobName, nil)
	if err != nil {
		_, _, postErr := bot.api.PostMessage(evt.Channel, 
			slack.MsgOptionText(fmt.Sprintf("Failed to trigger job: %v", err), false))
		return postErr
	}
	
	_, _, postErr := bot.api.PostMessage(evt.Channel, 
		slack.MsgOptionText(fmt.Sprintf("Job triggered! Queue ID: %d", queueID), false))
	return postErr
})

集成Jira

import (
	"github.com/andygrunwald/go-jira"
)

type JiraClient struct {
	client *jira.Client
}

func NewJiraClient(url, user, token string) *JiraClient {
	tp := jira.BasicAuthTransport{
		Username: user,
		Password: token,
	}
	
	client, err := jira.NewClient(tp.Client(), url)
	if err != nil {
		log.Fatal(err)
	}
	
	return &JiraClient{client: client}
}

func (j *JiraClient) GetIssue(issueID string) (*jira.Issue, error) {
	issue, _, err := j.client.Issue.Get(issueID, nil)
	return issue, err
}

// 注册Jira命令
bot.RegisterCommand("jira", func(evt *slackevents.AppMentionEvent) error {
	args := strings.Fields(evt.Text)
	if len(args) < 2 {
		return errors.New("Usage: jira <issue-id>")
	}
	
	issueID := args[1]
	jira := NewJiraClient(
		os.Getenv("JIRA_URL"),
		os.Getenv("JIRA_USER"),
		os.Getenv("JIRA_TOKEN"),
	)
	
	issue, err := jira.GetIssue(issueID)
	if err != nil {
		_, _, postErr := bot.api.PostMessage(evt.Channel, 
			slack.MsgOptionText(fmt.Sprintf("Failed to get issue: %v", err), false))
		return postErr
	}
	
	// 创建更丰富的消息格式
	attachment := slack.Attachment{
		Title:     fmt.Sprintf("%s: %s", issue.Key, issue.Fields.Summary),
		TitleLink: fmt.Sprintf("%s/browse/%s", os.Getenv("JIRA_URL"), issue.Key),
		Text:      issue.Fields.Description,
		Color:     "#0052CC",
		Fields: []slack.AttachmentField{
			{
				Title: "Status",
				Value: issue.Fields.Status.Name,
				Short: true,
			},
			{
				Title: "Assignee",
				Value: issue.Fields.Assignee.DisplayName,
				Short: true,
			},
		},
	}
	
	_, _, postErr := bot.api.PostMessage(evt.Channel, 
		slack.MsgOptionAttachments(attachment))
	return postErr
})

部署与配置

  1. 创建Slack应用并获取API令牌

  2. 设置环境变量:

    SLACK_BOT_TOKEN=xoxb-your-bot-token
    SLACK_APP_TOKEN=xapp-your-app-token
    JENKINS_URL=https://your-jenkins.com
    JENKINS_USER=username
    JENKINS_TOKEN=api-token
    JIRA_URL=https://your-company.atlassian.net
    JIRA_USER=email@company.com
    JIRA_TOKEN=api-token
    
  3. 构建并运行:

    go build -o slack-bot
    ./slack-bot
    

扩展建议

  1. 添加Bitbucket/Github集成:使用相应的Go SDK实现PR查询、代码审查等功能
  2. 实现交互式按钮:使用Slack的Block Kit创建更丰富的交互界面
  3. 添加权限控制:基于Slack用户角色限制命令访问
  4. 实现持久化:使用数据库存储常用查询或配置

这个slack-bot框架提供了高度可扩展的基础,开发者可以根据团队需求轻松添加更多集成和自定义命令。

回到顶部