harness-drone/docs/plugin/example.md
2015-09-29 17:16:20 -07:00

156 lines
4.3 KiB
Markdown

# Plugin Tutorial
We're going to create a plugin that allows Drone to send a webhook when a build completes. The webhook will send an http POST request to one or more URLs with the build details, encoded in JSON format.
## Plugin Yaml
Many plugins call for some options the user can set, which can be specified in the `.drone.yml` file. This is an example configuration for our `webhook` plugin:
```yaml
---
notify:
webhook:
image: bradrydzewski/webhook
urls:
- http://foo.com/post/to/this/url
```
The `image` attribute refers to the name of our plugin's Docker image. The `urls` attribute is a custom option allowing the user to define the list of webhook urls.
## Plugin executable
The next step is to write the code for our plugin. Our plugin will need access to information about the running build, and it will need its configuration options. Luckily, the build and repository details are passed to the program as a JSON encoded string over `arg[1]`.
The Drone team created the `drone-plugin-go` library to simplify plugin development, and we'll use this library to create our webhook plugin. First, we'll need to download the library using `go get` and import into our `main.go` file:
```go
import (
"github.com/drone/drone-plugin-go"
)
```
Next we'll need to read and unmarshal the repository and build detail from `arg[1]`. Our plugin package provides simple helper functions, modeled after the `flag` package, to fetch this data. We'll also need to read and unmarshal our plugin options. Plugin options are passed as the `vargs` paramter.
```go
func main() {
var repo = plugin.Repo{}
var build = plugin.Build{}
var vargs = struct {
Urls []string `json:"urls"`
}{}
plugin.Param("repo", &repo)
plugin.Param("build", &build)
plugin.Param("vargs", &vargs)
plugin.Parse()
// post build and repo data to webhook urls
}
```
Once we've parsed the build and repository details, and the webhook urls, we are ready to make the http requests. First, we'll need to construct our payload and marshal to JSON:
```go
data := struct{
Repo plugin.Repo `json:"repo"`
Build plugin.Build `json:"build"`
}{repo, build}
payload, _ := json.Marshal(&data)
```
And finally, for each URL in the list, we post the JSON payload:
```go
for _, url := range vargs.Urls {
resp, _ := http.Post(url, "application/json", bytes.NewBuffer(payload))
resp.Body.Close()
}
```
## Plugin image
Since plugins are distributed as Docker images, we'll need to create a `Dockerfile` for our plugin:
```dockerfile
FROM gliderlabs/alpine:3.1
RUN apk-install ca-certificates
ADD drone-webhook /bin/
ENTRYPOINT ["/bin/drone-webhook"]
```
We recommend using the `gliderlabs/alpine` base image due to its compact size. Plugins are downloaded automatically during build execution, therefore, smaller images and faster download times provide a better overall user experience.
## Plugin testing
We can quickly test our plugin from the command line, with dummy data, to make sure everything works. Note that you can send the JSON string over `stdin` instead of `arg[1]` only when testing:
```bash
go run main.go <<EOF
{
"repo": {
"owner": "octocat",
"name": "hello-world",
"full_name": "octocat/hello-world"
},
"build": {
"number": 1,
"status": "success"
},
"vargs": {
"urls": [ "http://foo.com/post/to/this/url" ]
}
}
EOF
```
## Complete example
Here is the complete Go program:
```go
import (
"bytes"
"encoding/json"
"net/http"
"github.com/drone/drone-plugin-go"
)
func main() {
var repo = plugin.Repo{}
var build = plugin.Build{}
var vargs = struct {
Urls []string `json:"urls"`
}{}
plugin.Param("repo", &repo)
plugin.Param("build", &build)
plugin.Param("vargs", &vargs)
plugin.Parse()
// data structure
data := struct{
Repo plugin.Repo `json:"repo"`
Build plugin.Build `json:"build"`
}{repo, build}
// json payload that will be posted
payload, _ := json.Marshal(&data)
// post payload to each url
for _, url := range vargs.Urls {
resp, _ := http.Post(url, "application/json", bytes.NewBuffer(payload))
resp.Body.Close()
}
}
```
And the Dockerfile:
```dockerfile
FROM gliderlabs/alpine:3.1
RUN apk-install ca-certificates
ADD drone-webhook /bin/
ENTRYPOINT ["/bin/drone-webhook"]
```