Compare commits

...

8 Commits

Author SHA1 Message Date
Dee Luo 8164de1292 Merge pull request #4 from lddsb/feature/msg-tpl
complete tpl feature
2019-09-20 17:13:42 +08:00
lddsb 9cb8a9b160 fix dry run keyword 2019-09-20 17:04:05 +08:00
lddsb 9eed74739b fix docker build dry run 2019-09-20 16:20:04 +08:00
lddsb 664c2e90c2 complete tpl feature 2019-09-20 10:20:35 +08:00
lddsb 8d080c3b0c remove codebeat badge and drone ci badge, add new badge for docker cloud auto build status 2019-09-09 11:54:07 +08:00
lddsb 0734cc50ff transfer automatic build to DockerHub 2019-09-09 11:35:20 +08:00
lddsb 00fb440336 update readme.md about development 2019-09-08 10:28:53 +08:00
lddsb 580a43e7a1 add editorconfig file 2019-09-07 22:19:32 +08:00
11 changed files with 498 additions and 287 deletions
+11 -37
View File
@@ -9,7 +9,7 @@ steps:
commands: commands:
- make vet - make vet
environment: environment:
GO111MODULE: on GO111MODULE: "on"
volumes: volumes:
- name: gopath - name: gopath
path: /go path: /go
@@ -21,7 +21,7 @@ steps:
- make test - make test
- make coverage - make coverage
environment: environment:
GO111MODULE: on GO111MODULE: "on"
volumes: volumes:
- name: gopath - name: gopath
path: /go path: /go
@@ -37,9 +37,13 @@ volumes:
- name: gopath - name: gopath
temp: {} temp: {}
trigger:
event:
- pull_request
--- ---
kind: pipeline kind: pipeline
name: build name: dryrun
steps: steps:
- name: build - name: build
@@ -49,13 +53,7 @@ steps:
- go build -a -o drone-dingtalk-message . - go build -a -o drone-dingtalk-message .
environment: environment:
CGO_ENABLED: 0 CGO_ENABLED: 0
GO111MODULE: on GO111MODULE: "on"
- name: executable
pull: always
image: golang
commands:
- ./drone-dingtalk-message -h
- name: dryrun - name: dryrun
pull: always pull: always
@@ -63,39 +61,15 @@ steps:
settings: settings:
cache_from: lddsb/drone-dingtalk-message cache_from: lddsb/drone-dingtalk-message
dockerfile: Dockerfile dockerfile: Dockerfile
dryrun: true dry_run: true
repo: lddsb/drone-dingtalk-message repo: lddsb/drone-dingtalk-message
tags: tags:
- latest - latest
- 1.0.0 - 1.0.0
when:
event:
- pull_request
- name: publish
pull: always
image: plugins/docker
settings:
repo: lddsb/drone-dingtalk-message
dockerfile: Dockerfile
tags:
- latest
- 1.0.0
username:
from_secret: docker_username
password:
from_secret: docker_password
when:
status:
- success
event:
- tag
trigger: trigger:
ref: event:
- refs/heads/master - pull_request
- 'refs/pull/**'
- 'refs/tags/**'
depends_on: depends_on:
- testing - testing
+2
View File
@@ -0,0 +1,2 @@
[*.y*ml]
indent_size = 2
+9 -7
View File
@@ -1,9 +1,11 @@
FROM golang AS builder
WORKDIR /app
COPY . .
RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux go build -a -o drone-dingtalk .
FROM alpine:latest FROM alpine:latest
RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*
COPY --from=builder /app/drone-dingtalk /bin
COPY --from=builder /app/tpls /app/tpls
RUN apk update && \ ENTRYPOINT ["/bin/drone-dingtalk"]
apk add \
ca-certificates && \
rm -rf /var/cache/apk/*
ADD drone-dingtalk-message /bin/
ENTRYPOINT ["/bin/drone-dingtalk-message"]
+78 -30
View File
@@ -1,6 +1,7 @@
# Drone CI DingTalk Message Plugin # Drone CI DingTalk Message Plugin
[![Build Status](https://drone.lddsb.com/api/badges/lddsb/drone-dingtalk-message/status.svg)](https://drone.lddsb.com/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) [![codebeat badge](https://codebeat.co/badges/23f68b84-1fd2-4f29-8467-9285c1e0facc)](https://codebeat.co/projects/github-com-lddsb-drone-dingtalk-message-master) [![LICENSE: MIT](https://img.shields.io/github/license/lddsb/drone-dingtalk-message.svg?style=flat-square)](LICENSE) [![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 ### Drone CI Plugin Config
`0.8.x` `0.8.x`
```yaml ```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. 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`. 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`. 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`) `success_pic`
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`)
String. You can customize the picture for the `build success` message by this option. 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. 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 ### Screen Shot
- Send Success - Send Success
@@ -89,28 +143,22 @@ String. You can customize the picture for the `build failure` message by this op
![markdown-massage-customize](https://i.imgur.com/xFrCTZp.jpg) ![markdown-massage-customize](https://i.imgur.com/xFrCTZp.jpg)
### Todo
- Multi-Type
- Multi-Lang
- More User Customization
### Development ### Development
We use `go mod` to manage dependencies, so it's easy to build.
- First get this repo - get this repo
```shell ```shell
go get github.com/lddsb/drone-dingtalk-message $ git clone https://github.com/lddsb/drone-dingtalk-message.git /path/to/you/want
```
- get dependent lib
```shell
dep ensure
``` ```
- build - build
```shell ```shell
cd $GOPATH/src/github.com/lddsb/drone-dingtalk-message && go build . $ cd /path/to/you/want && GO111MODULE=on go build .
``` ```
- run - run
```shell ```shell
./drone-dingtalk-message -h $ ./drone-dingtalk-message -h
``` ```
### Todo
- implement all message type
+1 -1
View File
@@ -4,6 +4,6 @@ go 1.12
require ( require (
github.com/joho/godotenv v1.3.0 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 github.com/urfave/cli v1.20.0
) )
+2 -2
View File
@@ -1,6 +1,6 @@
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= 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/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.1 h1:l4FdTMaRaHnrYfByALukFWK0ru9Rttl0dANg13/SnTI=
github.com/lddsb/dingtalk-webhook v0.0.0-20190307231412-b4abe34b5fa9/go.mod h1:5E+/sOBb6m+3ztqnZl4danEY3I5FeIwb12v12s9osbw= 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 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+125 -56
View File
@@ -2,11 +2,10 @@ package main
import ( import (
"fmt" "fmt"
"log"
"os"
_ "github.com/joho/godotenv/autoload" _ "github.com/joho/godotenv/autoload"
"github.com/urfave/cli" "github.com/urfave/cli"
"log"
"os"
) )
// Version of cli // Version of cli
@@ -36,12 +35,6 @@ func main() {
Usage: "dingtalk webhook access token", Usage: "dingtalk webhook access token",
EnvVar: "PLUGIN_ACCESS_TOKEN,PLUGIN_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{ cli.StringFlag{
Name: "config.message.type,message_type", Name: "config.message.type,message_type",
Usage: "dingtalk message type, like text, markdown, action card, link and feed card...", 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", Usage: "at someone in a dingtalk group need this guy bind's mobile",
EnvVar: "PLUGIN_MSG_AT_MOBILES", 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{ cli.StringFlag{
Name: "commit.author.avatar", Name: "commit.author.avatar",
Usage: "providers the author avatar url for the current commit", Usage: "providers the author avatar url for the current commit",
@@ -94,10 +92,35 @@ func main() {
EnvVar: "DRONE_COMMIT_SHA", EnvVar: "DRONE_COMMIT_SHA",
}, },
cli.StringFlag{ 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", Usage: "providers the full name of the repository",
EnvVar: "DRONE_REPO", 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{ cli.StringFlag{
Name: "build.status", Name: "build.status",
Usage: "build status", Usage: "build status",
@@ -110,39 +133,69 @@ func main() {
EnvVar: "DRONE_BUILD_LINK", EnvVar: "DRONE_BUILD_LINK",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "config.success.pic.url", Name: "build.event",
Usage: "config success picture url", 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", EnvVar: "SUCCESS_PICTURE_URL,PLUGIN_SUCCESS_PIC",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "config.failure.pic.url", Name: "custom.pic.url.failure",
Usage: "config failure picture url", Usage: "custom failure picture url",
EnvVar: "FAILURE_PICTURE_URL,PLUGIN_FAILURE_PIC", EnvVar: "FAILURE_PICTURE_URL,PLUGIN_FAILURE_PIC",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "config.success.color", Name: "custom.color.success",
Usage: "config success color for title in markdown", Usage: "custom success color for title in markdown",
EnvVar: "SUCCESS_COLOR,PLUGIN_SUCCESS_COLOR", EnvVar: "SUCCESS_COLOR,PLUGIN_SUCCESS_COLOR",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "config.failure.color", Name: "custom.color.failure",
Usage: "config failure color for title in markdown", Usage: "custom failure color for title in markdown",
EnvVar: "FAILURE_COLOR,PLUGIN_FAILURE_COLOR", EnvVar: "FAILURE_COLOR,PLUGIN_FAILURE_COLOR",
}, },
cli.BoolFlag{ cli.StringFlag{
Name: "config.message.color", Name: "custom.tpl",
Usage: "configure the message with color or not", Usage: "custom tpl",
EnvVar: "PLUGIN_COLOR,PLUGIN_MESSAGE_COLOR", EnvVar: "PLUGIN_TPL,PLUGIN_CUSTOM_TPL",
}, },
cli.BoolFlag{ cli.StringFlag{
Name: "config.message.pic", Name: "tpl.repo.full.name",
Usage: "configure the message with picture or not", Usage: "tpl custom repo full name",
EnvVar: "PLUGIN_PIC,PLUGIN_MESSAGE_PIC", EnvVar: "PLUGIN_TPL_REPO_FULL_NAME,TPL_REPO_FULL_NAME",
}, },
cli.BoolFlag{ cli.StringFlag{
Name: "config.message.sha.link", Name: "tpl.repo.short.name",
Usage: "link sha source page or not", Usage: "tpl custom repo short name",
EnvVar: "PLUGIN_SHA_LINK,PLUGIN_MESSAGE_SHA_LINK", 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{ Drone: Drone{
// repo info // repo info
Repo: Repo{ 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 info
Build: Build{ Build: Build{
Status: c.String("build.status"), Status: c.String("build.status"),
Link: c.String("build.link"), Link: c.String("build.link"),
Event: c.String("build.event"),
StartAt: c.Int64("build.started"),
FinishedAt: c.Int64("build.finished"),
}, },
Commit: Commit{ Commit: Commit{
Sha: c.String("commit.sha"), Sha: c.String("commit.sha"),
Branch: c.String("commit.branch"), Branch: c.String("commit.branch"),
Message: c.String("commit.message"), Message: c.String("commit.message"),
Link: c.String("commit.link"), Link: c.String("commit.link"),
Authors: struct { Author: CommitAuthor{
Avatar string Avatar: c.String("commit.author.avatar"),
Email string Email: c.String("commit.author.email"),
Name string Name: c.String("commit.author.name"),
}{ Username: c.String("commit.author.username"),
Avatar: c.String("commit.author.avatar"),
Email: c.String("commit.author.email"),
Name: c.String("commit.author.name"),
}, },
}, },
}, },
// custom config // custom config
Config: Config{ Config: Config{
AccessToken: c.String("config.token"), AccessToken: c.String("config.token"),
//Lang: c.String("config.lang"), IsAtALL: c.Bool("config.message.at.all"),
IsAtALL: c.Bool("config.message.at.all"), MsgType: c.String("config.message.type"),
MsgType: c.String("config.message.type"), Mobiles: c.String("config.message.at.mobiles"),
Mobiles: c.String("config.message.at.mobiles"), Debug: c.Bool("config.debug"),
Debug: c.Bool("config.debug"),
}, },
Extra: Extra{ Custom: Custom{
Pic: ExtraPic{ Pic: Pic{
WithPic: c.Bool("config.message.pic"), SuccessPicURL: c.String("custom.pic.url.success"),
SuccessPicURL: c.String("config.success.pic.url"), FailurePicURL: c.String("custom.pic.url.failure"),
FailurePicURL: c.String("config.failure.pic.url"),
}, },
Color: ExtraColor{ Color: Color{
SuccessColor: c.String("config.success.color"), SuccessColor: c.String("custom.color.success"),
FailureColor: c.String("config.failure.color"), FailureColor: c.String("custom.color.failure"),
WithColor: c.Bool("config.message.color"), },
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"),
}, },
} }
+233 -133
View File
@@ -3,48 +3,61 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"strings"
webhook "github.com/lddsb/dingtalk-webhook" webhook "github.com/lddsb/dingtalk-webhook"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"regexp"
"strings"
) )
type ( type (
// Repo `repo base info` // Repo repo base info
Repo struct { 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 { Build struct {
Status string // providers the current build status Status string // providers the current build status
Link string // providers the current build link 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 { Commit struct {
Branch string // providers the branch for the current commit 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) 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 Message string // providers the commit message for the current build
Sha string // providers the commit sha 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` // CommitAuthor commit author info
CommitAuthors struct { CommitAuthor struct {
Avatar string // providers the author avatar for the current commit Avatar string // providers the author avatar for the current commit
Email string // providers the author email for the current commit Email string // providers the author email for the current commit
Name string // providers the author name 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 { Drone struct {
Repo Repo Repo Repo
Build Build Build Build
Commit Commit Commit Commit
} }
// Config `plugin private config` // Config plugin private config
Config struct { Config struct {
Debug bool Debug bool
AccessToken string AccessToken string
@@ -54,12 +67,12 @@ type (
MsgType string MsgType string
} }
// MessageConfig `DingTalk message struct` // MessageConfig DingTalk message struct
MessageConfig struct { MessageConfig struct {
ActionCard ActionCard ActionCard ActionCard
} }
// ActionCard `action card message struct` // ActionCard action card message struct
ActionCard struct { ActionCard struct {
LinkUrls string LinkUrls string
LinkTitles string LinkTitles string
@@ -67,36 +80,59 @@ type (
BtnOrientation bool BtnOrientation bool
} }
// Extra `extra variables` // Pic extra config for pic
Extra struct { Pic struct {
Color ExtraColor
Pic ExtraPic
LinkSha bool
}
// ExtraPic `extra config for pic`
ExtraPic struct {
WithPic bool
SuccessPicURL string SuccessPicURL string
FailurePicURL string FailurePicURL string
} }
// ExtraColor `extra config for color` // Color extra config for color
ExtraColor struct { Color struct {
WithColor bool
SuccessColor string SuccessColor string
FailureColor string FailureColor string
} }
// Plugin `plugin all config` // Plugin plugin all config
Plugin struct { Plugin struct {
Drone Drone Tpl Tpl
Config Config Drone Drone
Extra Extra 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 { func (p *Plugin) Exec() error {
var err error var err error
if 0 == len(p.Config.AccessToken) { if 0 == len(p.Config.AccessToken) {
@@ -104,19 +140,20 @@ func (p *Plugin) Exec() error {
return errors.New(msg) return errors.New(msg)
} }
if 6 > len(p.Drone.Commit.Sha) { tpl, err := p.getMessage()
return errors.New("commit sha cannot short than 6") if err != nil {
return err
} }
newWebhook := webhook.NewWebHook(p.Config.AccessToken) newWebhook := webhook.NewWebHook(p.Config.AccessToken)
mobiles := strings.Split(p.Config.Mobiles, ",") mobiles := strings.Split(p.Config.Mobiles, ",")
switch strings.ToLower(p.Config.MsgType) { switch strings.ToLower(p.Config.MsgType) {
case "markdown": 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": case "text":
err = newWebhook.SendTextMsg(p.baseTpl(), p.Config.IsAtALL, mobiles...) err = newWebhook.SendTextMsg(tpl, p.Config.IsAtALL, mobiles...)
case "link": 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: default:
msg := "not support message type" msg := "not support message type"
err = errors.New(msg) err = errors.New(msg)
@@ -129,90 +166,156 @@ func (p *Plugin) Exec() error {
return err return err
} }
// markdownTpl `output the tpl of markdown` // fileExists check file is exists
func (p *Plugin) markdownTpl() string { func fileExists(filePath string) bool {
var tpl string _, err := os.Stat(filePath)
if err != nil {
// title if os.IsExist(err) {
title := fmt.Sprintf(" %s *Branch Build %s*", return true
strings.Title(p.Drone.Commit.Branch), }
strings.Title(p.Drone.Build.Status)) return false
// with color on title
if p.Extra.Color.WithColor {
title = fmt.Sprintf("<font color=%s>%s</font>", p.getColor(), title)
} }
return true
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("<font color=%s>%s</font>", 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
} }
func (p *Plugin) baseTpl() string { // getTpl get tpl from local file or remote file
tpl := "" func (p *Plugin) getTpl() (tpl string, err error) {
switch strings.ToLower(p.Config.MsgType) { //var tpl string
case "markdown": tplDir := "/app/tpls"
tpl = p.markdownTpl() if "" == p.Custom.Tpl {
case "text": p.Custom.Tpl = fmt.Sprintf("%s/%s.tpl", tplDir, strings.ToLower(p.Config.MsgType))
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
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 return tpl
} }
/** // getEnvs get available envs
get emoticon 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 { func (p *Plugin) getEmoticon() string {
emoticons := make(map[string]string) emoticons := make(map[string]string)
emoticons["success"] = ":)" emoticons["success"] = ":)"
@@ -226,44 +329,41 @@ func (p *Plugin) getEmoticon() string {
return ":(" return ":("
} }
/** // get picture url
get picture url
*/
func (p *Plugin) getPicURL() string { func (p *Plugin) getPicURL() string {
pics := make(map[string]string) pics := make(map[string]string)
// success picture url // success picture url
pics["success"] = "https://ws4.sinaimg.cn/large/006tNc79gy1fz05g5a7utj30he0bfjry.jpg" pics["success"] = "https://ws4.sinaimg.cn/large/006tNc79gy1fz05g5a7utj30he0bfjry.jpg"
if p.Extra.Pic.SuccessPicURL != "" { if p.Custom.Pic.SuccessPicURL != "" {
pics["success"] = p.Extra.Pic.SuccessPicURL pics["success"] = p.Custom.Pic.SuccessPicURL
} }
// failure picture url // failure picture url
pics["failure"] = "https://ws1.sinaimg.cn/large/006tNc79gy1fz0b4fghpnj30hd0bdmxn.jpg" pics["failure"] = "https://ws1.sinaimg.cn/large/006tNc79gy1fz0b4fghpnj30hd0bdmxn.jpg"
if p.Extra.Pic.FailurePicURL != "" { if p.Custom.Pic.FailurePicURL != "" {
pics["failure"] = p.Extra.Pic.FailurePicURL pics["failure"] = p.Custom.Pic.FailurePicURL
} }
url, ok := pics[p.Drone.Build.Status] picURL, ok := pics[p.Drone.Build.Status]
if ok { if ok {
return url return picURL
} }
return "" return ""
} }
/** // get color for message title
get color for message title
*/
func (p *Plugin) getColor() string { func (p *Plugin) getColor() string {
colors := make(map[string]string) colors := make(map[string]string)
// success color // success color
colors["success"] = "#008000" colors["success"] = "#008000"
if p.Extra.Color.SuccessColor != "" { if p.Custom.Color.SuccessColor != "" {
colors["success"] = "#" + p.Extra.Color.SuccessColor colors["success"] = "#" + p.Custom.Color.SuccessColor
} }
// failure color // failure color
colors["failure"] = "#FF0000" colors["failure"] = "#FF0000"
if p.Extra.Color.FailureColor != "" { if p.Custom.Color.FailureColor != "" {
colors["failure"] = "#" + p.Extra.Color.FailureColor colors["failure"] = "#" + p.Custom.Color.FailureColor
} }
color, ok := colors[p.Drone.Build.Status] color, ok := colors[p.Drone.Build.Status]
+23 -21
View File
@@ -12,43 +12,45 @@ func TestPlugin(t *testing.T) {
} }
p.Config.AccessToken = "example-access-token" p.Config.AccessToken = "example-access-token"
err = p.Exec() p.Custom.Tpl = "tpls/markdown.tpl"
if nil == err {
t.Error("commit sha length error should be catch!")
}
p.Drone.Commit.Sha = "53729847dfksj"
err = p.Exec() err = p.Exec()
if nil == err { if nil == err {
t.Error("not support message type error should be catch!") 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" p.Config.MsgType = "link"
err = p.Exec() err = p.Exec()
if nil == err { if nil == err {
t.Error("access token invalid error should be catch!") t.Error("access token invalid error should be catch!")
} }
p.Extra.Color.WithColor = true p.Custom.Tpl = "https://aaa.com"
p.Extra.Color.FailureColor = "#555555" p.Config.MsgType = "text"
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"
err = p.Exec() err = p.Exec()
if nil == err { if nil == err {
t.Error("access token invalid error should be catch!") 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" p.Drone.Build.Status = "failure"
err = p.Exec() err = p.Exec()
if nil == err { if nil == err {
+9
View File
@@ -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])
+5
View File
@@ -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])