Initial commit. Should work, but no promises (yet).
This commit is contained in:
commit
9893315796
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Discordrone
|
||||
|
||||
This is Drone CI plugin for pushing messages about CI/CD things into Discord channels using webhooks.
|
143
env/env.go
vendored
Normal file
143
env/env.go
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
// other
|
||||
"github.com/vrischmann/envconfig"
|
||||
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var Data *environmentData
|
||||
|
||||
type environmentData struct {
|
||||
CI bool `envconfig:"optional"`
|
||||
IsDrone bool `envconfig:"DRONE,optional"`
|
||||
Debug bool `envconfig:"optional"`
|
||||
|
||||
Drone struct {
|
||||
Branch string `envconfig:"optional"`
|
||||
Build struct {
|
||||
Action string `envconfig:"optional"`
|
||||
Created int `envconfig:"optional"`
|
||||
Event string `envconfig:"optional"`
|
||||
Finished int `envconfig:"optional"`
|
||||
Link string `envconfig:"optional"`
|
||||
Number int `envconfig:"optional"`
|
||||
Parent string `envconfig:"optional"`
|
||||
Started int `envconfig:"optional"`
|
||||
Status string `envconfig:"optional"`
|
||||
}
|
||||
CommitHash string `envconfig:"DRONE_COMMIT,optional"`
|
||||
Commit struct {
|
||||
After string `envconfig:"optional"`
|
||||
AuthorName string `envconfig:"DRONE_COMMIT_AUTHOR,optional"`
|
||||
Author struct {
|
||||
Avatar string `envconfig:"optional"`
|
||||
Email string `envconfig:"optional"`
|
||||
Name string `envconfig:"optional"`
|
||||
}
|
||||
Before string `envconfig:"optional"`
|
||||
Branch string `envconfig:"optional"`
|
||||
Link string `envconfig:"optional"`
|
||||
Message string `envconfig:"optional"`
|
||||
Ref string `envconfig:"optional"`
|
||||
Sha string `envconfig:"optional"`
|
||||
}
|
||||
Deploy struct {
|
||||
To string `envconfig:"optional"`
|
||||
}
|
||||
Failed struct {
|
||||
Stages string `envconfig:"optional"`
|
||||
Steps string `envconfig:"optional"`
|
||||
}
|
||||
Git struct {
|
||||
HTTP struct {
|
||||
URL string `envconfig:"optional"`
|
||||
}
|
||||
SSH struct {
|
||||
URL string `envconfig:"optional"`
|
||||
}
|
||||
}
|
||||
Pull struct {
|
||||
Request string `envconfig:"optional"`
|
||||
}
|
||||
Remote struct {
|
||||
URL string `envconfig:"optional"`
|
||||
}
|
||||
RepoName string `envconfig:"DRONE_REPO_NAME,optional"`
|
||||
Repo struct {
|
||||
Branch string `envconfig:"optional"`
|
||||
Link string `envconfig:"optional"`
|
||||
Name string `envconfig:"optional"`
|
||||
Namespace string `envconfig:"optional"`
|
||||
Owner string `envconfig:"optional"`
|
||||
Private bool `envconfig:"optional"`
|
||||
SCM string `envconfig:"optional"`
|
||||
Visibility string `envconfig:"optional"`
|
||||
}
|
||||
SemverData string `envconfig:"DRONE_SEMVER,optional"`
|
||||
Semver struct {
|
||||
Build string `envconfig:"optional"`
|
||||
Error string `envconfig:"optional"`
|
||||
Major int `envconfig:"optional"`
|
||||
Minor int `envconfig:"optional"`
|
||||
Patch int `envconfig:"optional"`
|
||||
Prerelease string `envconfig:"optional"`
|
||||
Short string `envconfig:"optional"`
|
||||
}
|
||||
Source struct {
|
||||
Branch string `envconfig:"optional"`
|
||||
}
|
||||
Stage struct {
|
||||
Arch string `envconfig:"optional"`
|
||||
Depends struct {
|
||||
On string `envconfig:"optional"`
|
||||
}
|
||||
Finished int `envconfig:"optional"`
|
||||
Kind string `envconfig:"optional"`
|
||||
Machine string `envconfig:"optional"`
|
||||
Name string `envconfig:"optional"`
|
||||
Number int `envconfig:"optional"`
|
||||
OS string `envconfig:"optional"`
|
||||
Started int `envconfig:"optional"`
|
||||
Status string `envconfig:"optional"`
|
||||
Type string `envconfig:"optional"`
|
||||
Variant string `envconfig:"optional"`
|
||||
}
|
||||
Step struct {
|
||||
Name string `envconfig:"optional"`
|
||||
Number int `envconfig:"optional"`
|
||||
}
|
||||
System struct {
|
||||
Host string `envconfig:"optional"`
|
||||
Hostname string `envconfig:"optional"`
|
||||
Proto string `envconfig:"optional"`
|
||||
Version string `envconfig:"optional"`
|
||||
}
|
||||
Tag string `envconfig:"optional"`
|
||||
Target struct {
|
||||
Branch string `envconfig:"optional"`
|
||||
}
|
||||
}
|
||||
Plugin struct {
|
||||
Avatar struct {
|
||||
URL string `envconfig:"optional"`
|
||||
}
|
||||
Color string `envconfig:"optional"`
|
||||
Message string `envconfig:"optional"`
|
||||
Webhook struct {
|
||||
ID string `envconfig:"optional"`
|
||||
Token string `envconfig:"optional"`
|
||||
}
|
||||
TTS bool `envconfig:"optional"`
|
||||
Username string `envconfig:"optional"`
|
||||
}
|
||||
}
|
||||
|
||||
func ParseEnv() {
|
||||
Data = &environmentData{}
|
||||
err := envconfig.Init(Data)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
10
go.mod
Normal file
10
go.mod
Normal file
@ -0,0 +1,10 @@
|
||||
module go.dev.pztrn.name/discordrone
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/drone/drone-template-lib v1.0.0
|
||||
github.com/stretchr/testify v1.4.0 // indirect
|
||||
github.com/vrischmann/envconfig v1.2.0
|
||||
gopkg.in/yaml.v2 v2.2.4 // indirect
|
||||
)
|
38
go.sum
Normal file
38
go.sum
Normal file
@ -0,0 +1,38 @@
|
||||
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/sprig v2.18.0+incompatible h1:QoGhlbC6pter1jxKnjMFxT8EqsLuDE6FEcNbWEpw+lI=
|
||||
github.com/Masterminds/sprig v2.18.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/aymerick/raymond v2.0.2+incompatible h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfKMjPOA3SbKLtnU0=
|
||||
github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
||||
github.com/bouk/monkey v1.0.0 h1:k6z8fLlPhETfn5l9rlWVE7Q6B23DoaqosTdArvNQRdc=
|
||||
github.com/bouk/monkey v1.0.0/go.mod h1:PG/63f4XEUlVyW1ttIeOJmJhhe1+t9EC/je3eTjvFhE=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/drone/drone-template-lib v1.0.0 h1:PNBBfUhifRnrPCoWBlTitk3jipXdv8u8WLbIf7h7j00=
|
||||
github.com/drone/drone-template-lib v1.0.0/go.mod h1:Hqy1tgqPH5mtbFOZmow19l4jOkZvp+WZ00cB4W3MJhg=
|
||||
github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s=
|
||||
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0=
|
||||
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
||||
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
|
||||
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tkuchiki/faketime v0.0.0-20170607100027-a4500a4f4643 h1:ii/sHfgFMByozryLeiDmn1ClZ/Pena4NgpJ4P7UuX9o=
|
||||
github.com/tkuchiki/faketime v0.0.0-20170607100027-a4500a4f4643/go.mod h1:RXY/TXAwGGL36IKDjrHFMcjpUrEiyWSEtLhFPw3UWF0=
|
||||
github.com/vrischmann/envconfig v1.2.0 h1:5/u4fI34/g3m0SdTQj/6f3r640jv9E5+yTXIZOWsxk0=
|
||||
github.com/vrischmann/envconfig v1.2.0/go.mod h1:c5DuUlkzfsnspy1g7qiqryPCsW+NjsrLsYq4zhwsoHo=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
24
main.go
Normal file
24
main.go
Normal file
@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"log"
|
||||
"os"
|
||||
|
||||
// local
|
||||
"go.dev.pztrn.name/discordrone/env"
|
||||
"go.dev.pztrn.name/discordrone/message"
|
||||
)
|
||||
|
||||
func main() {
|
||||
env.ParseEnv()
|
||||
if env.Data.Debug {
|
||||
log.Printf("Starting Discordrone with parameters: %+v\n", env.Data)
|
||||
}
|
||||
|
||||
err := message.Process()
|
||||
if err != nil {
|
||||
log.Fatalln("Error appeared:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
43
message/payload.go
Normal file
43
message/payload.go
Normal file
@ -0,0 +1,43 @@
|
||||
package message
|
||||
|
||||
type (
|
||||
// Payload that will be sent to Discord.
|
||||
payload struct {
|
||||
Wait bool `json:"wait"`
|
||||
Content string `json:"content"`
|
||||
Username string `json:"username"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
TTS bool `json:"tts"`
|
||||
Embeds []EmbedObject `json:"embeds"`
|
||||
}
|
||||
|
||||
// EmbedFooterObject for Embed Footer Structure.
|
||||
EmbedFooterObject struct {
|
||||
Text string `json:"text"`
|
||||
IconURL string `json:"icon_url"`
|
||||
}
|
||||
|
||||
// EmbedAuthorObject for Embed Author Structure
|
||||
EmbedAuthorObject struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
IconURL string `json:"icon_url"`
|
||||
}
|
||||
|
||||
// EmbedFieldObject for Embed Field Structure
|
||||
EmbedFieldObject struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// EmbedObject is for Embed Structure
|
||||
EmbedObject struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
URL string `json:"url"`
|
||||
Color int `json:"color"`
|
||||
Footer EmbedFooterObject `json:"footer"`
|
||||
Author EmbedAuthorObject `json:"author"`
|
||||
Fields []EmbedFieldObject `json:"fields"`
|
||||
}
|
||||
)
|
8
message/prepare.go
Normal file
8
message/prepare.go
Normal file
@ -0,0 +1,8 @@
|
||||
package message
|
||||
|
||||
// stdlib
|
||||
|
||||
// local
|
||||
|
||||
// other
|
||||
//"github.com/drone/drone-template-lib/template"
|
55
message/process.go
Normal file
55
message/process.go
Normal file
@ -0,0 +1,55 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
// local
|
||||
"go.dev.pztrn.name/discordrone/env"
|
||||
|
||||
// other
|
||||
"github.com/drone/drone-template-lib/template"
|
||||
)
|
||||
|
||||
// Process starts message(s) processing.
|
||||
func Process() error {
|
||||
if env.Data.Debug {
|
||||
log.Println("Preparing message for sending...")
|
||||
}
|
||||
|
||||
// Webhook data should present.
|
||||
if env.Data.Plugin.Webhook.ID == "" && env.Data.Plugin.Webhook.Token == "" {
|
||||
return errors.New("webhook id or token is missing")
|
||||
}
|
||||
|
||||
// Payload.
|
||||
p := &payload{
|
||||
Embeds: []EmbedObject{
|
||||
createEmbed(),
|
||||
},
|
||||
}
|
||||
|
||||
// If no additional message was passed - send what we got.
|
||||
if len(env.Data.Plugin.Message) == 0 {
|
||||
err := sendMessage(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If message was set - format it.
|
||||
if len(env.Data.Plugin.Message) > 0 {
|
||||
text, err := template.RenderTrim(env.Data.Plugin.Message, env.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Content = text
|
||||
err1 := sendMessage(p)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
28
message/send_message.go
Normal file
28
message/send_message.go
Normal file
@ -0,0 +1,28 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
// local
|
||||
"go.dev.pztrn.name/discordrone/env"
|
||||
)
|
||||
|
||||
// Sends message to Discord.
|
||||
func sendMessage(message interface{}) error {
|
||||
webhookURL := fmt.Sprintf("https://discordapp.com/api/webhooks/%s/%s", env.Data.Plugin.Webhook.ID, env.Data.Plugin.Webhook.Token)
|
||||
b := new(bytes.Buffer)
|
||||
if err := json.NewEncoder(b).Encode(message); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := http.Post(webhookURL, "application/json; charset=utf-8", b)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
79
message/template.go
Normal file
79
message/template.go
Normal file
@ -0,0 +1,79 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
// local
|
||||
"go.dev.pztrn.name/discordrone/env"
|
||||
)
|
||||
|
||||
const (
|
||||
// DroneIconURL default drone logo url
|
||||
droneIconURL = "https://c1.staticflickr.com/5/4236/34957940160_435d83114f_z.jpg"
|
||||
// DroneDesc default drone description
|
||||
droneDesc = "Powered by DiscoDrone Plugin"
|
||||
)
|
||||
|
||||
func createEmbed() EmbedObject {
|
||||
// Create initial payload object.
|
||||
// Description.
|
||||
// Color.
|
||||
embed := EmbedObject{
|
||||
Title: env.Data.Drone.Commit.Message,
|
||||
URL: env.Data.Drone.Build.Link,
|
||||
Author: EmbedAuthorObject{
|
||||
Name: env.Data.Drone.Commit.Author.Name,
|
||||
IconURL: env.Data.Drone.Commit.Author.Avatar,
|
||||
},
|
||||
Footer: EmbedFooterObject{
|
||||
Text: droneDesc,
|
||||
IconURL: droneIconURL,
|
||||
},
|
||||
}
|
||||
|
||||
// Compose description.
|
||||
var description string
|
||||
// ToDo: promote/rollback?
|
||||
switch env.Data.Drone.Build.Event {
|
||||
case "pull_request":
|
||||
var branch string
|
||||
if env.Data.Drone.Commit.Ref != "" {
|
||||
branch = env.Data.Drone.Commit.Ref
|
||||
} else {
|
||||
branch = env.Data.Drone.Commit.Branch
|
||||
}
|
||||
description = env.Data.Drone.Commit.Author.Name + " updated pull request " + branch
|
||||
case "push":
|
||||
description = env.Data.Drone.Commit.Author.Name + " pushed to " + env.Data.Drone.Commit.Branch
|
||||
case "tag":
|
||||
description = env.Data.Drone.Commit.Author.Name + " pushed tag " + env.Data.Drone.Commit.Branch
|
||||
}
|
||||
|
||||
embed.Description = description
|
||||
|
||||
// Compose color.
|
||||
var color int
|
||||
if env.Data.Plugin.Color != "" {
|
||||
env.Data.Plugin.Color = strings.Replace(env.Data.Plugin.Color, "#", "", -1)
|
||||
if s, err := strconv.ParseInt(env.Data.Plugin.Color, 16, 32); err == nil {
|
||||
color = int(s)
|
||||
}
|
||||
}
|
||||
|
||||
switch env.Data.Drone.Build.Status {
|
||||
case "success":
|
||||
// green
|
||||
color = 0x1ac600
|
||||
case "failure", "error", "killed":
|
||||
// red
|
||||
color = 0xff3232
|
||||
default:
|
||||
// yellow
|
||||
color = 0xffd930
|
||||
}
|
||||
embed.Color = color
|
||||
|
||||
return embed
|
||||
}
|
Reference in New Issue
Block a user