PLT-6965 jira integration (plus plugin scaffolding) (#6918)
* plugin scaffolding / jira integration * add vendored testify packages * webhook fix * don't change i18n ids * support configuration watching * add basic jira plugin configuration to admin console * fix eslint errors * fix another eslint warning * polish * undo unintentional config.json commit >:( * test fix * add jira plugin diagnostics, remove dm support, add bot tag, generate web-safe secrets * rebase, implement requested changes * requested changes * remove tests and minimize makefile change * add missing license headers * add missing comma * remove bad line from Makefile
Этот коммит содержится в:
168
app/plugin/jira/webhook.go
Обычный файл
168
app/plugin/jira/webhook.go
Обычный файл
@@ -0,0 +1,168 @@
|
||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package jira
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/url"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/mattermost/platform/model"
|
||||
)
|
||||
|
||||
type Webhook struct {
|
||||
WebhookEvent string
|
||||
Issue struct {
|
||||
Self string
|
||||
Key string
|
||||
Fields struct {
|
||||
Assignee *struct {
|
||||
DisplayName string
|
||||
Name string
|
||||
}
|
||||
Summary string
|
||||
Description string
|
||||
Priority *struct {
|
||||
Id string
|
||||
Name string
|
||||
}
|
||||
IssueType struct {
|
||||
Name string
|
||||
IconURL string
|
||||
}
|
||||
Resolution *struct {
|
||||
Id string
|
||||
}
|
||||
Status struct {
|
||||
Id string
|
||||
}
|
||||
}
|
||||
}
|
||||
User struct {
|
||||
Name string
|
||||
AvatarUrls map[string]string
|
||||
DisplayName string
|
||||
}
|
||||
Comment struct {
|
||||
Body string
|
||||
}
|
||||
ChangeLog struct {
|
||||
Items []struct {
|
||||
FromString string
|
||||
ToString string
|
||||
Field string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the text to be placed in the resulting post or an empty string if nothing should be
|
||||
// posted.
|
||||
func (w *Webhook) SlackAttachment() (*model.SlackAttachment, error) {
|
||||
switch w.WebhookEvent {
|
||||
case "jira:issue_created":
|
||||
case "jira:issue_updated":
|
||||
isResolutionChange := false
|
||||
for _, change := range w.ChangeLog.Items {
|
||||
if change.Field == "resolution" {
|
||||
isResolutionChange = (change.FromString == "") != (change.ToString == "")
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isResolutionChange {
|
||||
return nil, nil
|
||||
}
|
||||
case "jira:issue_deleted":
|
||||
if w.Issue.Fields.Resolution != nil {
|
||||
return nil, nil
|
||||
}
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
pretext, err := w.renderText("" +
|
||||
"{{.User.DisplayName}} {{.Verb}} {{.Issue.Fields.IssueType.Name}} " +
|
||||
"[{{.Issue.Key}}]({{.JIRAURL}}/browse/{{.Issue.Key}})" +
|
||||
"")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
text, err := w.renderText("" +
|
||||
"[{{.Issue.Fields.Summary}}]({{.JIRAURL}}/browse/{{.Issue.Key}})" +
|
||||
"{{if eq .WebhookEvent \"jira:issue_created\"}}{{if ne .Issue.Fields.Description \"\"}}" +
|
||||
"\n\n{{.Issue.Fields.Description}}" +
|
||||
"{{end}}{{end}}" +
|
||||
"")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var fields []*model.SlackAttachmentField
|
||||
if w.WebhookEvent == "jira:issue_created" {
|
||||
if w.Issue.Fields.Assignee != nil {
|
||||
fields = append(fields, &model.SlackAttachmentField{
|
||||
Title: "Assignee",
|
||||
Value: w.Issue.Fields.Assignee.DisplayName,
|
||||
Short: true,
|
||||
})
|
||||
}
|
||||
if w.Issue.Fields.Priority != nil {
|
||||
fields = append(fields, &model.SlackAttachmentField{
|
||||
Title: "Priority",
|
||||
Value: w.Issue.Fields.Priority.Name,
|
||||
Short: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &model.SlackAttachment{
|
||||
Fallback: pretext,
|
||||
Color: "#95b7d0",
|
||||
Pretext: pretext,
|
||||
Text: text,
|
||||
Fields: fields,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *Webhook) renderText(tplBody string) (string, error) {
|
||||
issueSelf, err := url.Parse(w.Issue.Self)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
jiraURL := strings.TrimRight(issueSelf.ResolveReference(&url.URL{Path: "/"}).String(), "/")
|
||||
verb := strings.TrimPrefix(w.WebhookEvent, "jira:issue_")
|
||||
|
||||
if w.WebhookEvent == "jira:issue_updated" {
|
||||
for _, change := range w.ChangeLog.Items {
|
||||
if change.Field == "resolution" {
|
||||
if change.ToString == "" && change.FromString != "" {
|
||||
verb = "reopened"
|
||||
} else if change.ToString != "" && change.FromString == "" {
|
||||
verb = "resolved"
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tpl, err := template.New("post").Parse(tplBody)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := tpl.Execute(&buf, struct {
|
||||
*Webhook
|
||||
JIRAURL string
|
||||
Verb string
|
||||
}{
|
||||
Webhook: w,
|
||||
JIRAURL: jiraURL,
|
||||
Verb: verb,
|
||||
}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
Ссылка в новой задаче
Block a user