From 664c2e90c22c65cf6ac5899a364e30e603544e8a Mon Sep 17 00:00:00 2001 From: lddsb Date: Fri, 20 Sep 2019 10:20:35 +0800 Subject: [PATCH] complete tpl feature --- Dockerfile | 10 +- README.md | 91 +++++++++--- go.mod | 2 +- go.sum | 4 +- main.go | 181 ++++++++++++++++------- plugin.go | 366 +++++++++++++++++++++++++++++----------------- plugin_test.go | 44 +++--- tpls/markdown.tpl | 9 ++ tpls/text.tpl | 5 + 9 files changed, 475 insertions(+), 237 deletions(-) create mode 100644 tpls/markdown.tpl create mode 100644 tpls/text.tpl diff --git a/Dockerfile b/Dockerfile index 8829ecf..7f4f7b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,11 @@ -FROM golang +FROM golang AS builder WORKDIR /app COPY . . -RUN GO111MODULE=on go build -o drone-dingtalk-message . +RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux go build -a -o drone-dingtalk . FROM alpine:latest RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/* -COPY --from=0 /app/drone-dingtalk-message /bin -ENTRYPOINT ["/bin/drone-dingtalk-message"] +COPY --from=builder /app/drone-dingtalk /bin +COPY --from=builder /app/tpls /app/tpls + +ENTRYPOINT ["/bin/drone-dingtalk"] diff --git a/README.md b/README.md index 2493f01..244d288 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Drone CI DingTalk Message Plugin [![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/lddsb/drone-dingtalk-message)](https://hub.docker.com/r/lddsb/drone-dingtalk-message) [![Go Report Card](https://goreportcard.com/badge/github.com/lddsb/drone-dingtalk-message)](https://goreportcard.com/report/github.com/lddsb/drone-dingtalk-message) [![codecov](https://codecov.io/gh/lddsb/drone-dingtalk-message/branch/master/graph/badge.svg)](https://codecov.io/gh/lddsb/drone-dingtalk-message) [![LICENSE: MIT](https://img.shields.io/github/license/lddsb/drone-dingtalk-message.svg?style=flat-square)](LICENSE) +just support `text`, `markdown` and `link` type now ### Drone CI Plugin Config `0.8.x` ```yaml @@ -36,34 +37,87 @@ String. Access token for group bot. (you can get the access token when you add a String. Message type, plan support text, markdown, link and action card, but due to time issue, it's only support `markdown` and `text` now, and you can get the best experience by use markdown. -`message_color`(when `type=markdown`) +`tpl` -Boolean value. This option can change the title and commit message color if turn on. +String. Your custom `tpl`, it can be a local path or a remote http link. -`success_color`(when `message_color=true`) +`success_color` String. You can customize the color for the `build success` message by this option, you should input a hex color, example: `008000`. -`failure_color`(when `message_color=true`) +`failure_color` String. You can customize the color for the `build success` message by this option, you should input a hex color, example: `FF0000`. -`sha_link`(when `type=markdown`) - -Boolean value. This option can link the sha to your source page when it turn on. - -`message_pic`(when `type=markdown`) - -Boolean value. If this option turn on, it will embed a image into the message. - -`success_pic`(when `message_pic=true`) +`success_pic` String. You can customize the picture for the `build success` message by this option. -`failure_pic`(when `message_pic=true`) +`failure_pic` String. You can customize the picture for the `build failure` message by this option. +`tpl_commit_branch_name` + +String. You can customize the [TPL_COMMIT_BRANCH] by this configuration item. + +`tpl_repo_short_name` + +String. You can customize the [TPL_REPO_SHORT_NAME] by this configuration item. + +`tpl_repo_full_name` + +String. You can customize the [TPL_REPO_FULL_NAME] by this configuration item. + +`tpl_build_status_sucdess` + +String. You can customize the [TPL_BUILD_STATUS] (when status=`success`) by this configuration item. + +`tpl_build_status_failure` + +String. You can customize the [TPL_BUILD_STATUS] (when status=`failure`) by this configuration item. + +### TPL +> `tpl` won't work with message type `link` !!! + +That's a good news, we support `tpl` now.This is a example for `markdown` message: + + # [TPL_REPO_FULL_NAME] build [TPL_BUILD_STATUS], takes [TPL_BUILD_CONSUMING]s + [TPL_COMMIT_MSG] + + [TPL_COMMIT_SHA]([TPL_COMMIT_LINK]) + + [[TPL_AUTHOR_NAME]([TPL_AUTHOR_EMAIL])](mailto:[TPL_AUTHOR_EMAIL]) + + [Click To The Build Detail Page [TPL_STATUS_EMOTICON)]]([TPL_BUILD_LINK]) +You can write your own `tpl` what you want. The syntax of `tpl` is very simple, you can fill `tpl` with preset variables. It's a list of currently supported preset variables: + +| Variable | Value | +| :-------------------: | :-------------------------------------------------: | +| [TPL_REPO_SHORT_NAME] | current repo name(bare name) | +| [TPL_REPO_FULL_NAME] | the full name(with group name) of current repo | +| [TPL_REPO_GROUP_NAME] | the group name of current repo | +| [TPL_REPO_OWNER_NAME] | the owner name of current repo | +| [TPL_REPO_REMOTE_URL] | the remote url of current repo | +| [TPL_BUILD_STATUS] | current build status(e.g., success, failure) | +| [TPL_BUILD_LINK] | current build link | +| [TPL_BUILD_EVENT] | current build event(e.g., push, pull request, etc.) | +| [TPL_BUILD_CONSUMING] | current build consuming, second | +| [TPL_COMMIT_SHA] | current commit sha | +| [TPL_COMMIT_REF] | current commit ref(e.g., refs/heads/master, etc.) | +| [TPL_COMMIT_LINK] | current commit remote url link | +| [TPL_COMMIT_BRANCH] | current branch name(e.g., dev, etc) | +| [TPL_COMMIT_MSG] | current commit message | +| [TPL_AUTHOR_NAME] | current commit author name | +| [TPL_AUTHOR_EMAIL] | current commit author email | +| [TPL_AUTHOR_USERNAME] | current commit author username | +| [TPL_AUTHOR_AVATAR] | current commit author avatar | +| [TPL_STATUS_PIC] | custom pic for build status | +| [TPL_STATUS_COLOR] | custom color for build status | +| [TPL_STATUS_EMOTICON] | custom emoticon for build status | + + + ### Screen Shot - Send Success @@ -89,12 +143,6 @@ String. You can customize the picture for the `build failure` message by this op ![markdown-massage-customize](https://i.imgur.com/xFrCTZp.jpg) -### Todo - -- Multi-Type -- Multi-Lang -- More User Customization - ### Development We use `go mod` to manage dependencies, so it's easy to build. @@ -111,3 +159,6 @@ $ cd /path/to/you/want && GO111MODULE=on go build . ```shell $ ./drone-dingtalk-message -h ``` + +### Todo +- implement all message type \ No newline at end of file diff --git a/go.mod b/go.mod index d3af10a..632795c 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,6 @@ go 1.12 require ( github.com/joho/godotenv v1.3.0 - github.com/lddsb/dingtalk-webhook v0.0.0-20190307231412-b4abe34b5fa9 + github.com/lddsb/dingtalk-webhook v0.0.1 github.com/urfave/cli v1.20.0 ) diff --git a/go.sum b/go.sum index da0fc6c..44c6e09 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/lddsb/dingtalk-webhook v0.0.0-20190307231412-b4abe34b5fa9 h1:ZeUdCEbcT0+l10jTSyjU9+18ZbDTz6TdkH6yGiCd9dQ= -github.com/lddsb/dingtalk-webhook v0.0.0-20190307231412-b4abe34b5fa9/go.mod h1:5E+/sOBb6m+3ztqnZl4danEY3I5FeIwb12v12s9osbw= +github.com/lddsb/dingtalk-webhook v0.0.1 h1:l4FdTMaRaHnrYfByALukFWK0ru9Rttl0dANg13/SnTI= +github.com/lddsb/dingtalk-webhook v0.0.1/go.mod h1:5E+/sOBb6m+3ztqnZl4danEY3I5FeIwb12v12s9osbw= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= diff --git a/main.go b/main.go index 09fdf91..717f1ff 100644 --- a/main.go +++ b/main.go @@ -2,11 +2,10 @@ package main import ( "fmt" - "log" - "os" - _ "github.com/joho/godotenv/autoload" "github.com/urfave/cli" + "log" + "os" ) // Version of cli @@ -36,12 +35,6 @@ func main() { Usage: "dingtalk webhook access token", EnvVar: "PLUGIN_ACCESS_TOKEN,PLUGIN_TOKEN", }, - cli.StringFlag{ - Name: "config.lang", - Value: "zh_CN", - Usage: "the lang display (zh_CN or en_US, zh_CN is default)", - EnvVar: "PLUGIN_LANG", - }, cli.StringFlag{ Name: "config.message.type,message_type", Usage: "dingtalk message type, like text, markdown, action card, link and feed card...", @@ -57,6 +50,11 @@ func main() { Usage: "at someone in a dingtalk group need this guy bind's mobile", EnvVar: "PLUGIN_MSG_AT_MOBILES", }, + cli.StringFlag{ + Name: "commit.author.username", + Usage: "providers the author username for the current commit", + EnvVar: "DRONE_COMMIT_AUTHOR", + }, cli.StringFlag{ Name: "commit.author.avatar", Usage: "providers the author avatar url for the current commit", @@ -94,10 +92,35 @@ func main() { EnvVar: "DRONE_COMMIT_SHA", }, cli.StringFlag{ - Name: "repo.fullname", + Name: "commit.ref", + Usage: "provider the commit ref for the current build", + EnvVar: "DRONE_COMMIT_REF", + }, + cli.StringFlag{ + Name: "repo.full.name", Usage: "providers the full name of the repository", EnvVar: "DRONE_REPO", }, + cli.StringFlag{ + Name: "repo.name", + Usage: "provider the name of the repository", + EnvVar: "DRONE_REPO_NAME", + }, + cli.StringFlag{ + Name: "repo.group", + Usage: "provider the group of the repository", + EnvVar: "DRONE_REPO_NAMESPACE", + }, + cli.StringFlag{ + Name: "repo.remote.url", + Usage: "provider the remote url of the repository", + EnvVar: "DRONE_REMOTE_URL", + }, + cli.StringFlag{ + Name: "repo.owner", + Usage: "provider the owner of the repository", + EnvVar: "DRONE_REPO_OWNER", + }, cli.StringFlag{ Name: "build.status", Usage: "build status", @@ -110,39 +133,69 @@ func main() { EnvVar: "DRONE_BUILD_LINK", }, cli.StringFlag{ - Name: "config.success.pic.url", - Usage: "config success picture url", + Name: "build.event", + Usage: "build event", + EnvVar: "DRONE_BUILD_EVENT", + }, + cli.StringFlag{ + Name: "build.started", + Usage: "build started", + EnvVar: "DRONE_BUILD_STARTED", + }, + cli.StringFlag{ + Name: "build.finished", + Usage: "build finished", + EnvVar: "DRONE_BUILD_FINISHED", + }, + cli.StringFlag{ + Name: "tpl.build.status.success", + Usage: "tpl.build status for replace success", + EnvVar: "TPL_BUILD_STATUS_SUCCESS, PLUGIN_TPL_BUILD_STATUS_SUCCESS", + }, + cli.StringFlag{ + Name: "tpl.build.status.failure", + Usage: "tpl.build status for replace failure", + EnvVar: "TPL_BUILD_STATUS_FAILURE, PLUGIN_TPL_BUILD_STATUS_FAILURE", + }, + cli.StringFlag{ + Name: "custom.pic.url.success", + Usage: "custom success picture url", EnvVar: "SUCCESS_PICTURE_URL,PLUGIN_SUCCESS_PIC", }, cli.StringFlag{ - Name: "config.failure.pic.url", - Usage: "config failure picture url", + Name: "custom.pic.url.failure", + Usage: "custom failure picture url", EnvVar: "FAILURE_PICTURE_URL,PLUGIN_FAILURE_PIC", }, cli.StringFlag{ - Name: "config.success.color", - Usage: "config success color for title in markdown", + Name: "custom.color.success", + Usage: "custom success color for title in markdown", EnvVar: "SUCCESS_COLOR,PLUGIN_SUCCESS_COLOR", }, cli.StringFlag{ - Name: "config.failure.color", - Usage: "config failure color for title in markdown", + Name: "custom.color.failure", + Usage: "custom failure color for title in markdown", EnvVar: "FAILURE_COLOR,PLUGIN_FAILURE_COLOR", }, - cli.BoolFlag{ - Name: "config.message.color", - Usage: "configure the message with color or not", - EnvVar: "PLUGIN_COLOR,PLUGIN_MESSAGE_COLOR", + cli.StringFlag{ + Name: "custom.tpl", + Usage: "custom tpl", + EnvVar: "PLUGIN_TPL,PLUGIN_CUSTOM_TPL", }, - cli.BoolFlag{ - Name: "config.message.pic", - Usage: "configure the message with picture or not", - EnvVar: "PLUGIN_PIC,PLUGIN_MESSAGE_PIC", + cli.StringFlag{ + Name: "tpl.repo.full.name", + Usage: "tpl custom repo full name", + EnvVar: "PLUGIN_TPL_REPO_FULL_NAME,TPL_REPO_FULL_NAME", }, - cli.BoolFlag{ - Name: "config.message.sha.link", - Usage: "link sha source page or not", - EnvVar: "PLUGIN_SHA_LINK,PLUGIN_MESSAGE_SHA_LINK", + cli.StringFlag{ + Name: "tpl.repo.short.name", + Usage: "tpl custom repo short name", + EnvVar: "PLUGIN_TPL_REPO_SHORT_NAME,TPL_REPO_SHORT_NAME", + }, + cli.StringFlag{ + Name: "tpl.commit.branch.name", + Usage: "tpl custom commit branch name", + EnvVar: "PLUGIN_TPL_COMMIT_BRANCH_NAME,TPL_COMMIT_BRANCH_NAME", }, } @@ -157,50 +210,66 @@ func run(c *cli.Context) { Drone: Drone{ // repo info Repo: Repo{ - FullName: c.String("repo.fullname"), + ShortName: c.String("repo.name"), + GroupName: c.String("repo.group"), + OwnerName: c.String("repo.owner"), + RemoteURL: c.String("repo.remote.url"), + FullName: c.String("repo.full.name"), }, // build info Build: Build{ - Status: c.String("build.status"), - Link: c.String("build.link"), + Status: c.String("build.status"), + Link: c.String("build.link"), + Event: c.String("build.event"), + StartAt: c.Int64("build.started"), + FinishedAt: c.Int64("build.finished"), }, Commit: Commit{ Sha: c.String("commit.sha"), Branch: c.String("commit.branch"), Message: c.String("commit.message"), Link: c.String("commit.link"), - Authors: struct { - Avatar string - Email string - Name string - }{ - Avatar: c.String("commit.author.avatar"), - Email: c.String("commit.author.email"), - Name: c.String("commit.author.name"), + Author: CommitAuthor{ + Avatar: c.String("commit.author.avatar"), + Email: c.String("commit.author.email"), + Name: c.String("commit.author.name"), + Username: c.String("commit.author.username"), }, }, }, // custom config Config: Config{ AccessToken: c.String("config.token"), - //Lang: c.String("config.lang"), - IsAtALL: c.Bool("config.message.at.all"), - MsgType: c.String("config.message.type"), - Mobiles: c.String("config.message.at.mobiles"), - Debug: c.Bool("config.debug"), + IsAtALL: c.Bool("config.message.at.all"), + MsgType: c.String("config.message.type"), + Mobiles: c.String("config.message.at.mobiles"), + Debug: c.Bool("config.debug"), }, - Extra: Extra{ - Pic: ExtraPic{ - WithPic: c.Bool("config.message.pic"), - SuccessPicURL: c.String("config.success.pic.url"), - FailurePicURL: c.String("config.failure.pic.url"), + Custom: Custom{ + Pic: Pic{ + SuccessPicURL: c.String("custom.pic.url.success"), + FailurePicURL: c.String("custom.pic.url.failure"), }, - Color: ExtraColor{ - SuccessColor: c.String("config.success.color"), - FailureColor: c.String("config.failure.color"), - WithColor: c.Bool("config.message.color"), + Color: Color{ + SuccessColor: c.String("custom.color.success"), + FailureColor: c.String("custom.color.failure"), + }, + Tpl: c.String("custom.tpl"), + }, + Tpl:Tpl{ + Repo: TplRepo{ + FullName: c.String("tpl.repo.full.name"), + ShortName: c.String("tpl.repo.short.name"), + }, + Commit: TplCommit{ + Branch: c.String("tpl.commit.branch.name"), + }, + Build: TplBuild{ + Status:Status{ + Success: c.String("tpl.build.status.success"), + Failure: c.String("tpl.build.status.failure"), + }, }, - LinkSha: c.Bool("config.message.sha.link"), }, } diff --git a/plugin.go b/plugin.go index a888d87..cfa59b9 100644 --- a/plugin.go +++ b/plugin.go @@ -3,48 +3,61 @@ package main import ( "errors" "fmt" - "log" - "strings" - webhook "github.com/lddsb/dingtalk-webhook" + "io/ioutil" + "log" + "net/http" + "net/url" + "os" + "regexp" + "strings" ) type ( - // Repo `repo base info` + // Repo repo base info Repo struct { - FullName string // repository full name + ShortName string // short name + GroupName string // group name + FullName string // repository full name + OwnerName string // repo owner + RemoteURL string // repo remote url } - // Build `build info` + // Build build info Build struct { - Status string // providers the current build status - Link string // providers the current build link + Status string // providers the current build status + Link string // providers the current build link + Event string // trigger event + StartAt int64 // build start at ( unix timestamp ) + FinishedAt int64 // build finish at ( unix timestamp ) } - // Commit `commit info` + // Commit commit info Commit struct { Branch string // providers the branch for the current commit Link string // providers the http link to the current commit in the remote source code management system(e.g.GitHub) Message string // providers the commit message for the current build Sha string // providers the commit sha for the current build - Authors CommitAuthors + Ref string // commit ref + Author CommitAuthor } - // CommitAuthors `commit author info` - CommitAuthors struct { - Avatar string // providers the author avatar for the current commit - Email string // providers the author email for the current commit - Name string // providers the author name for the current commit + // CommitAuthor commit author info + CommitAuthor struct { + Avatar string // providers the author avatar for the current commit + Email string // providers the author email for the current commit + Name string // providers the author name for the current commit + Username string // the author username for the current commit } - // Drone `drone info` + // Drone drone info Drone struct { Repo Repo Build Build Commit Commit } - // Config `plugin private config` + // Config plugin private config Config struct { Debug bool AccessToken string @@ -54,12 +67,12 @@ type ( MsgType string } - // MessageConfig `DingTalk message struct` + // MessageConfig DingTalk message struct MessageConfig struct { ActionCard ActionCard } - // ActionCard `action card message struct` + // ActionCard action card message struct ActionCard struct { LinkUrls string LinkTitles string @@ -67,36 +80,59 @@ type ( BtnOrientation bool } - // Extra `extra variables` - Extra struct { - Color ExtraColor - Pic ExtraPic - LinkSha bool - } - - // ExtraPic `extra config for pic` - ExtraPic struct { - WithPic bool + // Pic extra config for pic + Pic struct { SuccessPicURL string FailurePicURL string } - // ExtraColor `extra config for color` - ExtraColor struct { - WithColor bool + // Color extra config for color + Color struct { SuccessColor string FailureColor string } - // Plugin `plugin all config` + // Plugin plugin all config Plugin struct { - Drone Drone - Config Config - Extra Extra + Tpl Tpl + Drone Drone + Config Config + Custom Custom + Message MessageConfig + } + + Custom struct { + Tpl string + Color Color + Pic Pic + } + + Tpl struct { + Repo TplRepo + Commit TplCommit + Build TplBuild + } + + TplRepo struct { + FullName string + ShortName string + } + + TplCommit struct { + Branch string + } + + TplBuild struct { + Status Status + } + + Status struct { + Success string + Failure string } ) -// Exec `execute webhook` +// Exec execute webhook func (p *Plugin) Exec() error { var err error if 0 == len(p.Config.AccessToken) { @@ -104,19 +140,20 @@ func (p *Plugin) Exec() error { return errors.New(msg) } - if 6 > len(p.Drone.Commit.Sha) { - return errors.New("commit sha cannot short than 6") + tpl, err := p.getMessage() + if err != nil { + return err } newWebhook := webhook.NewWebHook(p.Config.AccessToken) mobiles := strings.Split(p.Config.Mobiles, ",") switch strings.ToLower(p.Config.MsgType) { case "markdown": - err = newWebhook.SendMarkdownMsg("You have a new message...", p.baseTpl(), p.Config.IsAtALL, mobiles...) + err = newWebhook.SendMarkdownMsg("new message", tpl, p.Config.IsAtALL, mobiles...) case "text": - err = newWebhook.SendTextMsg(p.baseTpl(), p.Config.IsAtALL, mobiles...) + err = newWebhook.SendTextMsg(tpl, p.Config.IsAtALL, mobiles...) case "link": - err = newWebhook.SendLinkMsg(p.Drone.Build.Status, p.baseTpl(), p.Drone.Commit.Authors.Avatar, p.Drone.Build.Link) + err = newWebhook.SendLinkMsg(p.Drone.Build.Status, tpl, p.Drone.Commit.Author.Avatar, p.Drone.Build.Link) default: msg := "not support message type" err = errors.New(msg) @@ -129,90 +166,156 @@ func (p *Plugin) Exec() error { return err } -// markdownTpl `output the tpl of markdown` -func (p *Plugin) markdownTpl() string { - var tpl string - - // title - title := fmt.Sprintf(" %s *Branch Build %s*", - strings.Title(p.Drone.Commit.Branch), - strings.Title(p.Drone.Build.Status)) - // with color on title - if p.Extra.Color.WithColor { - title = fmt.Sprintf("%s", p.getColor(), title) +// fileExists check file is exists +func fileExists(filePath string) bool { + _, err := os.Stat(filePath) + if err != nil { + if os.IsExist(err) { + return true + } + return false } - - tpl = fmt.Sprintf("# %s \n", title) - - // with pic - if p.Extra.Pic.WithPic { - tpl += fmt.Sprintf("![%s](%s)\n\n", - p.Drone.Build.Status, - p.getPicURL()) - } - - // commit message - commitMsg := fmt.Sprintf("%s", p.Drone.Commit.Message) - if p.Extra.Color.WithColor { - commitMsg = fmt.Sprintf("%s", p.getColor(), commitMsg) - } - tpl += commitMsg + "\n\n" - - // sha info - commitSha := p.Drone.Commit.Sha - if p.Extra.LinkSha { - commitSha = fmt.Sprintf("[Click To %s Commit Detail Page](%s)", commitSha[:6], p.Drone.Commit.Link) - } - tpl += commitSha + "\n\n" - - // author info - authorInfo := fmt.Sprintf("`%s(%s)`", p.Drone.Commit.Authors.Name, p.Drone.Commit.Authors.Email) - tpl += authorInfo + "\n\n" - - // build detail link - buildDetail := fmt.Sprintf("[Click To The Build Detail Page %s](%s)", - p.getEmoticon(), - p.Drone.Build.Link) - tpl += buildDetail - return tpl + return true } -func (p *Plugin) baseTpl() string { - tpl := "" - switch strings.ToLower(p.Config.MsgType) { - case "markdown": - tpl = p.markdownTpl() - case "text": - tpl = fmt.Sprintf(`[%s] %s -%s (%s) -@%s -%s (%s) -`, - p.Drone.Build.Status, - strings.TrimSpace(p.Drone.Commit.Message), - p.Drone.Repo.FullName, - p.Drone.Commit.Branch, - p.Drone.Commit.Sha, - p.Drone.Commit.Authors.Name, - p.Drone.Commit.Authors.Email) - case "link": - tpl = fmt.Sprintf(`%s(%s) @%s %s(%s)`, - p.Drone.Repo.FullName, - p.Drone.Commit.Branch, - p.Drone.Commit.Sha[:6], - p.Drone.Commit.Authors.Name, - p.Drone.Commit.Authors.Email) - case "actionCard": - // coming soon +// getTpl get tpl from local file or remote file +func (p *Plugin) getTpl() (tpl string, err error) { + //var tpl string + tplDir := "/app/tpls" + if "" == p.Custom.Tpl { + p.Custom.Tpl = fmt.Sprintf("%s/%s.tpl", tplDir, strings.ToLower(p.Config.MsgType)) + } + u, err := url.Parse(p.Custom.Tpl) + if err != nil { + return "", err + } + + if u.Scheme != "" { + resp, err := http.Get(p.Custom.Tpl) + if err != nil { + return "", err + } + + // check response + if u.Path != resp.Request.URL.Path { + return "", errors.New("cannot get tpl from url") + } + + // defer close + defer func() { + _ = resp.Body.Close() + }() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + tpl = string(body) + } else { + if !fileExists(p.Custom.Tpl) { + return "", errors.New("tpl file not exists") + } + + tplStr, err := ioutil.ReadFile(p.Custom.Tpl) + if err != nil { + return "", err + } + + tpl = string(tplStr) + } + + + return tpl, nil +} + +// fillTpl fill the tpl by valid keyword +func (p *Plugin) fillTpl(tpl string) string { + envs := p.getEnvs() + // replace regex + reg := regexp.MustCompile(`\[([^\[\]]*)]`) + match := reg.FindAllStringSubmatch(tpl, -1) + for _, m := range match { + // check if the keyword is legal + if _, ok := envs[m[1]]; ok { + // replace keyword + tpl = strings.ReplaceAll(tpl, m[0], envs[m[1]].(string)) + } } return tpl } -/** -get emoticon -*/ +// getEnvs get available envs +func (p *Plugin) getEnvs() map[string]interface{} { + var envs map[string]interface{} + envs = make(map[string]interface{}) + envs["TPL_REPO_FULL_NAME"] = p.Drone.Repo.FullName + if p.Tpl.Repo.FullName != "" { + envs["TPL_REPO_FULL_NAME"] = p.Tpl.Repo.FullName + } + envs["TPL_REPO_SHORT_NAME"] = p.Drone.Repo.ShortName + if p.Tpl.Repo.ShortName != "" { + envs["TPL_REPO_SHORT_NAME"] = p.Tpl.Repo.ShortName + } + envs["TPL_REPO_GROUP_NAME"] = p.Drone.Repo.GroupName + envs["TPL_REPO_OWNER_NAME"] = p.Drone.Repo.OwnerName + envs["TPL_REPO_REMOTE_URL"] = p.Drone.Repo.RemoteURL + + envs["TPL_BUILD_STATUS"] = p.getStatus() + envs["TPL_BUILD_LINK"] = p.Drone.Build.Link + envs["TPL_BUILD_EVENT"] = p.Drone.Build.Event + envs["TPL_BUILD_CONSUMING"] = fmt.Sprintf("%v", p.Drone.Build.FinishedAt-p.Drone.Build.StartAt) + + envs["TPL_COMMIT_SHA"] = p.Drone.Commit.Sha + envs["TPL_COMMIT_REF"] = p.Drone.Commit.Ref + envs["TPL_COMMIT_LINK"] = p.Drone.Commit.Link + envs["TPL_COMMIT_MSG"] = p.Drone.Commit.Message + envs["TPL_COMMIT_BRANCH"] = p.Drone.Commit.Branch + if p.Tpl.Commit.Branch != "" { + envs["TPL_COMMIT_BRANCH"] = p.Tpl.Commit.Branch + } + + envs["TPL_AUTHOR_NAME"] = p.Drone.Commit.Author.Name + envs["TPL_AUTHOR_USERNAME"] = p.Drone.Commit.Author.Username + envs["TPL_AUTHOR_EMAIL"] = p.Drone.Commit.Author.Email + envs["TPL_AUTHOR_AVATAR"] = p.Drone.Commit.Author.Avatar + + envs["TPL_STATUS_PIC"] = p.getPicURL() + envs["TPL_STATUS_COLOR"] = p.getColor() + envs["TPL_STATUS_EMOTICON"] = p.getEmoticon() + + return envs +} + +// getMessage get message tpl +func (p *Plugin) getMessage() (tpl string, err error) { + tpl, err = p.getTpl() + if err != nil { + return "", err + } + return p.fillTpl(tpl), nil +} + +// getStatus +func (p *Plugin) getStatus() string { + if p.Drone.Build.Status == "success" { + if p.Tpl.Build.Status.Success != "" { + return p.Tpl.Build.Status.Success + } + + return p.Drone.Build.Status + } + + if p.Tpl.Build.Status.Failure != "" { + return p.Tpl.Build.Status.Failure + } + + return p.Drone.Build.Status +} + +// get emoticon func (p *Plugin) getEmoticon() string { emoticons := make(map[string]string) emoticons["success"] = ":)" @@ -226,44 +329,41 @@ func (p *Plugin) getEmoticon() string { return ":(" } -/** -get picture url -*/ +// get picture url func (p *Plugin) getPicURL() string { pics := make(map[string]string) // success picture url pics["success"] = "https://ws4.sinaimg.cn/large/006tNc79gy1fz05g5a7utj30he0bfjry.jpg" - if p.Extra.Pic.SuccessPicURL != "" { - pics["success"] = p.Extra.Pic.SuccessPicURL + if p.Custom.Pic.SuccessPicURL != "" { + pics["success"] = p.Custom.Pic.SuccessPicURL } // failure picture url pics["failure"] = "https://ws1.sinaimg.cn/large/006tNc79gy1fz0b4fghpnj30hd0bdmxn.jpg" - if p.Extra.Pic.FailurePicURL != "" { - pics["failure"] = p.Extra.Pic.FailurePicURL + if p.Custom.Pic.FailurePicURL != "" { + pics["failure"] = p.Custom.Pic.FailurePicURL } - url, ok := pics[p.Drone.Build.Status] + picURL, ok := pics[p.Drone.Build.Status] if ok { - return url + return picURL } return "" } -/** -get color for message title -*/ +// get color for message title func (p *Plugin) getColor() string { colors := make(map[string]string) // success color colors["success"] = "#008000" - if p.Extra.Color.SuccessColor != "" { - colors["success"] = "#" + p.Extra.Color.SuccessColor + if p.Custom.Color.SuccessColor != "" { + colors["success"] = "#" + p.Custom.Color.SuccessColor } + // failure color colors["failure"] = "#FF0000" - if p.Extra.Color.FailureColor != "" { - colors["failure"] = "#" + p.Extra.Color.FailureColor + if p.Custom.Color.FailureColor != "" { + colors["failure"] = "#" + p.Custom.Color.FailureColor } color, ok := colors[p.Drone.Build.Status] diff --git a/plugin_test.go b/plugin_test.go index 5ea7675..e4440e2 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -12,43 +12,45 @@ func TestPlugin(t *testing.T) { } p.Config.AccessToken = "example-access-token" - err = p.Exec() - if nil == err { - t.Error("commit sha length error should be catch!") - } - - p.Drone.Commit.Sha = "53729847dfksj" + p.Custom.Tpl = "tpls/markdown.tpl" err = p.Exec() if nil == err { t.Error("not support message type error should be catch!") } - p.Config.MsgType = "text" - err = p.Exec() - if nil == err { - t.Error("access token invalid error should be catch!") - } - p.Config.MsgType = "link" err = p.Exec() if nil == err { t.Error("access token invalid error should be catch!") } - p.Extra.Color.WithColor = true - p.Extra.Color.FailureColor = "#555555" - p.Extra.Color.SuccessColor = "#222222" - p.Extra.Pic.WithPic = true - p.Extra.Pic.FailurePicURL = "https://www.baidu.com" - p.Extra.Pic.SuccessPicURL = "https://www.baidu.com" - p.Extra.LinkSha = true - // p.Drone.Build.Status = "failure" - p.Config.MsgType = "markdown" + p.Custom.Tpl = "https://aaa.com" + p.Config.MsgType = "text" err = p.Exec() if nil == err { t.Error("access token invalid error should be catch!") } + + p.Custom.Tpl = "" + p.Config.MsgType = "link" + err = p.Exec() + if nil == err { + t.Error("access token invalid error should be catch!") + } + + p.Custom.Color.FailureColor = "#555555" + p.Custom.Color.SuccessColor = "#222222" + p.Custom.Pic.FailurePicURL = "https://www.baidu.com" + p.Custom.Pic.SuccessPicURL = "https://www.baidu.com" + p.Config.MsgType = "markdown" + p.Custom.Tpl = "tpls/markdown.tpl" + err = p.Exec() + if nil == err { + t.Error("access token invalid error should be catch!") + } + + p.Custom.Tpl = "https://gist.githubusercontent.com/lddsb/87065e73678dcf56cd222a3c2f1f32b0/raw/fce9fb28b2c8c768eb93df5598beee8c98cba610/md.tpl" p.Drone.Build.Status = "failure" err = p.Exec() if nil == err { diff --git a/tpls/markdown.tpl b/tpls/markdown.tpl new file mode 100644 index 0000000..c7f72a4 --- /dev/null +++ b/tpls/markdown.tpl @@ -0,0 +1,9 @@ +### [TPL_REPO_SHORT_NAME] build [TPL_BUILD_STATUS] (`takes [TPL_BUILD_CONSUMING]s`) + +[TPL_COMMIT_MSG] + +[[TPL_COMMIT_SHA]]([TPL_COMMIT_LINK]) + +[[TPL_AUTHOR_NAME]([TPL_AUTHOR_EMAIL])](mailto:[TPL_AUTHOR_EMAIL]) + +[Click To The Build Detail Page [TPL_STATUS_EMOTICON]]([TPL_BUILD_LINK]) \ No newline at end of file diff --git a/tpls/text.tpl b/tpls/text.tpl new file mode 100644 index 0000000..063ece9 --- /dev/null +++ b/tpls/text.tpl @@ -0,0 +1,5 @@ +[TPL_REPO_NAME] build [TPL_BUILD_STATUS] (takes [TPL_BUILD_CONSUMING]s) +[TPL_COMMIT_MSG] +[TPL_COMMIT_SHA] ([TPL_COMMIT_LINK]) +[TPL_AUTHOR_NAME] ([TPL_AUTHOR_EMAIL]) +Click To The Build Detail Page [TPL_STATUS_EMOTICON] ([TPL_BUILD_LINK]) \ No newline at end of file