diff --git a/.drone.yml b/.drone.yml
index 9d62987..e85dbce 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -1,39 +1,29 @@
-build:
-  image: golang:1.5
-  environment:
-    - CGO_ENABLED=0
-  commands:
-    - make deps
-    - make vet
-    - make build
-    - make test
+workspace:
+  base: /go
 
-publish:
-  coverage:
-    when:
-      branch: master
-  docker:
-    username: $$DOCKER_USER
-    password: $$DOCKER_PASS
-    email: $$DOCKER_EMAIL
-    repo: plugins/drone-github-release
-    tag: latest
+pipeline:
+  test:
+    image: golang:1.6
+    environment:
+      - CGO_ENABLED=0
+    commands:
+      - go vet
+      - go test -cover -coverprofile=coverage.out
+      - go build -ldflags "-s -w -X main.build=$DRONE_BUILD_NUMBER" -a -tags netgo
+
+  latest:
+    image: docker
+    repo: plugins/github-release
+    tags: [ "latest", "1.0", "1" ]
     when:
       branch: master
-  docker:
-    username: $$DOCKER_USER
-    password: $$DOCKER_PASS
-    email: $$DOCKER_EMAIL
-    repo: plugins/drone-github-release
-    tag: develop
-    when:
-      branch: develop
+      event: push
 
 plugin:
   name: GitHub Release
   desc: Publish files and artifacts to GitHub Releases
   type: publish
-  image: plugins/drone-github-release
+  image: plugins/github-release
   labels:
     - github
     - release
diff --git a/.drone.yml.sig b/.drone.yml.sig
new file mode 100644
index 0000000..57a6885
--- /dev/null
+++ b/.drone.yml.sig
@@ -0,0 +1 @@
+eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9nbwoKcGlwZWxpbmU6CiAgdGVzdDoKICAgIGltYWdlOiBnb2xhbmc6MS42CiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBDR09fRU5BQkxFRD0wCiAgICBjb21tYW5kczoKICAgICAgLSBnbyB2ZXQKICAgICAgLSBnbyB0ZXN0IC1jb3ZlciAtY292ZXJwcm9maWxlPWNvdmVyYWdlLm91dAogICAgICAtIGdvIGJ1aWxkIC1sZGZsYWdzICItcyAtdyAtWCBtYWluLmJ1aWxkPSREUk9ORV9CVUlMRF9OVU1CRVIiIC1hIC10YWdzIG5ldGdvCgogIGxhdGVzdDoKICAgIGltYWdlOiBkb2NrZXIKICAgIHJlcG86IHBsdWdpbnMvZ2l0aHViLXJlbGVhc2UKICAgIHRhZ3M6IFsgImxhdGVzdCIsICIxLjAiLCAiMSIgXQogICAgd2hlbjoKICAgICAgYnJhbmNoOiBtYXN0ZXIKICAgICAgZXZlbnQ6IHB1c2gKCnBsdWdpbjoKICBuYW1lOiBHaXRIdWIgUmVsZWFzZQogIGRlc2M6IFB1Ymxpc2ggZmlsZXMgYW5kIGFydGlmYWN0cyB0byBHaXRIdWIgUmVsZWFzZXMKICB0eXBlOiBwdWJsaXNoCiAgaW1hZ2U6IHBsdWdpbnMvZ2l0aHViLXJlbGVhc2UKICBsYWJlbHM6CiAgICAtIGdpdGh1YgogICAgLSByZWxlYXNlCg.5FZW1Auk18CljY9LW5P82r9RM_spPCYMYg82PFj2irM
\ No newline at end of file
diff --git a/DOCS.md b/DOCS.md
index 4259020..07d11ce 100644
--- a/DOCS.md
+++ b/DOCS.md
@@ -1,30 +1,61 @@
-Use this  plugin for publishing files and artifacts to GitHub releases. You
-can override the default configuration with the following parameters:
+Use this plugin for publishing files and artifacts to GitHub releases. Be aware
+that you can use this plugin only for tags, GitHub doesn't support the release
+of branches.
 
-* `api_key` - GitHub oauth token with public_repo or repo permission
-* `files` - Files to upload to GitHub Release, globs are allowed
-* `file_exists` - What to do if an file asset already exists, supported values: **overwrite** (default), **skip** and **fail**
-* `checksum` - Checksum takes hash methods to include in your GitHub release for the files specified. Supported hash methods include md5, sha1, sha256, sha512, adler32, and crc32.
-* `draft` - create a draft release if set to true
-* `base_url` - GitHub base URL, only required for GHE
-* `upload_url` - GitHub upload URL, only required for GHE
+## Config
 
-Sample configuration:
+The following parameters are used to configure the plugin:
+
+* **api_key** - GitHub oauth token with public_repo or repo permission
+* **files** - files to upload to GitHub Release, globs are allowed
+* **file_exists** - what to do if an file asset already exists, supported values: **overwrite** (default), **skip** and **fail**
+* **checksum** - checksum takes hash methods to include in your GitHub release for the files specified. Supported hash methods include md5, sha1, sha256, sha512, adler32, and crc32.
+* **draft** - create a draft release if set to true
+* **base_url** - GitHub base URL, only required for GHE
+* **upload_url** - GitHub upload URL, only required for GHE
+
+The following secret values can be set to configure the plugin.
+
+* **GITHUB_RELEASE_API_KEY** - corresponds to **api_key**
+* **GITHUB_RELEASE_BASE_URL** - corresponds to **base_url**
+* **GITHUB_RELEASE_UPLOAD_URL** - corresponds to **upload_url**
+
+It is highly recommended to put the **GITHUB_RELEASE_API_KEY** into a secret so
+it is not exposed to users. This can be done using the drone-cli.
+
+```bash
+drone secret add --image=plugins/github-release \
+    octocat/hello-world GITHUB_RELEASE_API_KEY my_github_api_key
+```
+
+Then sign the YAML file after all secrets are added.
+
+```bash
+drone sign octocat/hello-world
+```
+
+See [secrets](http://readme.drone.io/0.5/usage/secrets/) for additional
+information on secrets
+
+## Examples
+
+The following is a sample configuration in your .drone.yml file:
 
 ```yaml
-publish:
+pipeline:
   github_release:
-    api_key: my_github_api_key
+    image: plugins/github-release
     files: dist/*
-    checksum: sha1
+    when:
+      event: tag
 ```
 
-or
+An example for generating checksums and upload additional files:
 
 ```yaml
-publish:
+pipeline:
   github_release:
-    api_key: my_github_api_key
+    image: plugins/github-release
     files:
       - dist/*
       - bin/binary.exe
@@ -35,4 +66,6 @@ publish:
       - sha512
       - adler32
       - crc32
+    when:
+      event: tag
 ```
diff --git a/Dockerfile b/Dockerfile
index bebbe5d..aa86bb2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,4 @@
-# Docker image for the Drone GitHub Release plugin
-#
-#     cd $GOPATH/src/github.com/drone-plugins/drone-github-release
-#     make deps build docker
-
-FROM alpine:3.3
+FROM alpine:3.4
 
 RUN apk update && \
   apk add \
diff --git a/README.md b/README.md
index 56ff55f..541f7c0 100644
--- a/README.md
+++ b/README.md
@@ -1,117 +1,53 @@
 # drone-github-release
 
 [![Build Status](http://beta.drone.io/api/badges/drone-plugins/drone-github-release/status.svg)](http://beta.drone.io/drone-plugins/drone-github-release)
-[![Coverage Status](https://aircover.co/badges/drone-plugins/drone-github-release/coverage.svg)](https://aircover.co/drone-plugins/drone-github-release)
-[![](https://badge.imagelayers.io/plugins/drone-github-release:latest.svg)](https://imagelayers.io/?images=plugins/drone-github-release:latest 'Get your own badge on imagelayers.io')
+[![Go Doc](https://godoc.org/github.com/drone-plugins/drone-github-release?status.svg)](http://godoc.org/github.com/drone-plugins/drone-github-release)
+[![Go Report](https://goreportcard.com/badge/github.com/drone-plugins/drone-github-release)](https://goreportcard.com/report/github.com/drone-plugins/drone-github-release)
+[![Join the chat at https://gitter.im/drone/drone](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/drone/drone)
 
-Drone plugin to publish files and artifacts to GitHub Release. For the usage information and a listing of the available options please take a look at [the docs](DOCS.md).
+Drone plugin to publish files and artifacts to GitHub Release. For the usage
+information and a listing of the available options please take a look at
+[the docs](DOCS.md).
 
-## Binary
+## Build
 
-Build the binary using `make`:
+Build the binary with the following commands:
 
 ```
-make deps build
+go build
+go test
 ```
 
-### Example
+## Docker
 
-```sh
-./drone-github-release <<EOF
-{
-    "repo": {
-        "clone_url": "git://github.com/drone/drone",
-        "owner": "drone",
-        "name": "drone",
-        "full_name": "drone/drone"
-    },
-    "system": {
-        "link_url": "https://beta.drone.io"
-    },
-    "build": {
-        "number": 22,
-        "status": "success",
-        "started_at": 1421029603,
-        "finished_at": 1421029813,
-        "message": "Update the Readme",
-        "author": "johnsmith",
-        "author_email": "john.smith@gmail.com"
-        "event": "push",
-        "branch": "master",
-        "commit": "436b7a6e2abaddfd35740527353e78a227ddcb2c",
-        "ref": "refs/heads/master"
-    },
-    "workspace": {
-        "root": "/drone/src",
-        "path": "/drone/src/github.com/drone/drone"
-    },
-    "vargs": {
-        "api_key": "your_api_key",
-        "files": [
-            "dist/*.txt",
-            "dist/other-file"
-        ],
-        "checksum": [
-            "sha1",
-            "sha256",
-            "sha512"
-        ]
-    }
-}
-EOF
-```
+Build the docker image with the following commands:
 
-## Docker
+```
+CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo
+docker build --rm=true -t plugins/github-release .
+```
 
-Build the container using `make`:
+Please note incorrectly building the image for the correct x64 linux and with
+GCO disabled will result in an error when running the Docker image:
 
 ```
-make deps docker
+docker: Error response from daemon: Container command
+'/bin/drone-github-release' not found or does not exist..
 ```
 
-### Example
+## Usage
+
+Execute from the working directory:
 
 ```sh
-docker run -i plugins/drone-github-release <<EOF
-{
-    "repo": {
-        "clone_url": "git://github.com/drone/drone",
-        "owner": "drone",
-        "name": "drone",
-        "full_name": "drone/drone"
-    },
-    "system": {
-        "link_url": "https://beta.drone.io"
-    },
-    "build": {
-        "number": 22,
-        "status": "success",
-        "started_at": 1421029603,
-        "finished_at": 1421029813,
-        "message": "Update the Readme",
-        "author": "johnsmith",
-        "author_email": "john.smith@gmail.com"
-        "event": "push",
-        "branch": "master",
-        "commit": "436b7a6e2abaddfd35740527353e78a227ddcb2c",
-        "ref": "refs/heads/master"
-    },
-    "workspace": {
-        "root": "/drone/src",
-        "path": "/drone/src/github.com/drone/drone"
-    },
-    "vargs": {
-        "api_key": "your_api_key",
-        "files": [
-            "dist/*.txt",
-            "dist/other-file"
-        ],
-        "checksum": [
-            "sha1",
-            "sha256",
-            "sha512"
-        ]
-    }
-}
-EOF
+docker run --rm \
+  -e DRONE_BUILD_EVENT=tag \
+  -e DRONE_REPO_OWNER=octocat \
+  -e DRONE_REPO_NAME=foo \
+  -e DRONE_COMMIT_REF=refs/heads/master \
+  -e PLUGIN_API_KEY=${HOME}/.ssh/id_rsa \
+  -e PLUGIN_FILES=master \
+  -v $(pwd):$(pwd) \
+  -w $(pwd) \
+  plugins/github-release
 ```
diff --git a/checksum.go b/checksum.go
deleted file mode 100644
index 786f397..0000000
--- a/checksum.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package main
-
-import (
-	"crypto/md5"
-	"crypto/sha1"
-	"crypto/sha256"
-	"crypto/sha512"
-	"fmt"
-	"hash/adler32"
-	"hash/crc32"
-	"io"
-	"io/ioutil"
-	"strconv"
-)
-
-func checksum(r io.Reader, method string) (string, error) {
-	b, err := ioutil.ReadAll(r)
-	if err != nil {
-		return "", err
-	}
-
-	switch method {
-	case "md5":
-		return fmt.Sprintf("%x", md5.Sum(b)), nil
-	case "sha1":
-		return fmt.Sprintf("%x", sha1.Sum(b)), nil
-	case "sha256":
-		return fmt.Sprintf("%x", sha256.Sum256(b)), nil
-	case "sha512":
-		return fmt.Sprintf("%x", sha512.Sum512(b)), nil
-	case "adler32":
-		return strconv.FormatUint(uint64(adler32.Checksum(b)), 10), nil
-	case "crc32":
-		return strconv.FormatUint(uint64(crc32.ChecksumIEEE(b)), 10), nil
-	default:
-		return "", fmt.Errorf("hashing method %s is not supported", method)
-	}
-}
diff --git a/main.go b/main.go
index c5e8522..fd1426a 100644
--- a/main.go
+++ b/main.go
@@ -2,276 +2,120 @@ package main
 
 import (
 	"fmt"
-	"net/url"
 	"os"
-	"path"
-	"path/filepath"
-	"strings"
 
-	"github.com/drone/drone-go/drone"
-	"github.com/drone/drone-go/plugin"
-	"github.com/google/go-github/github"
-	"golang.org/x/oauth2"
+	"github.com/Sirupsen/logrus"
+	"github.com/joho/godotenv"
+	"github.com/urfave/cli"
 )
 
-var (
-	buildCommit string
-)
+var build = "0" // build number set at compile-time
 
 func main() {
-	fmt.Printf("Drone GitHub Release Plugin built from %s\n", buildCommit)
-
-	workspace := drone.Workspace{}
-	repo := drone.Repo{}
-	build := drone.Build{}
-	vargs := Params{}
-
-	plugin.Param("workspace", &workspace)
-	plugin.Param("repo", &repo)
-	plugin.Param("build", &build)
-	plugin.Param("vargs", &vargs)
-	plugin.MustParse()
-
-	if build.Event != "tag" {
-		fmt.Printf("The GitHub Release plugin is only available for tags\n")
-		os.Exit(0)
-	}
-
-	if vargs.FileExists == "" {
-		vargs.FileExists = "overwrite"
-	}
-	if !fileExistsValues[vargs.FileExists] {
-		fmt.Printf("invalid value for file_exists: use [empty], overwrite, skip or fail")
-	}
-
-	if vargs.BaseURL == "" {
-		vargs.BaseURL = "https://api.github.com/"
-	} else if !strings.HasSuffix(vargs.BaseURL, "/") {
-		vargs.BaseURL = vargs.BaseURL + "/"
+	app := cli.NewApp()
+	app.Name = "github-release plugin"
+	app.Usage = "github-release plugin"
+	app.Action = run
+	app.Version = fmt.Sprintf("1.0.%s", build)
+	app.Flags = []cli.Flag{
+		cli.StringFlag{
+			Name:   "api-key",
+			Usage:  "api key to access github api",
+			EnvVar: "PLUGIN_API_KEY,GITHUB_RELEASE_API_KEY",
+		},
+		cli.StringSliceFlag{
+			Name:   "files",
+			Usage:  "list of files to upload",
+			EnvVar: "PLUGIN_FILES,GITHUB_RELEASE_FILES",
+		},
+		cli.StringFlag{
+			Name:   "file-exists",
+			Value:  "overwrite",
+			Usage:  "what to do if file already exist",
+			EnvVar: "PLUGIN_FILE_EXISTS,GITHUB_RELEASE_FILE_EXISTS",
+		},
+		cli.StringSliceFlag{
+			Name:   "checksum",
+			Usage:  "generate specific checksums",
+			EnvVar: "PLUGIN_CHECKSUM,GITHUB_RELEASE_CHECKSUM",
+		},
+		cli.BoolFlag{
+			Name:   "draft",
+			Usage:  "create a draft release",
+			EnvVar: "PLUGIN_DRAFT,GITHUB_RELEASE_DRAFT",
+		},
+		cli.StringFlag{
+			Name:   "base-url",
+			Value:  "https://api.github.com/",
+			Usage:  "api url, needs to be changed for ghe",
+			EnvVar: "PLUGIN_BASE_URL,GITHUB_RELEASE_BASE_URL",
+		},
+		cli.StringFlag{
+			Name:   "upload-url",
+			Value:  "https://uploads.github.com/",
+			Usage:  "upload url, needs to be changed for ghe",
+			EnvVar: "PLUGIN_UPLOAD_URL,GITHUB_RELEASE_UPLOAD_URL",
+		},
+
+		cli.StringFlag{
+			Name:   "repo.owner",
+			Usage:  "repository owner",
+			EnvVar: "DRONE_REPO_OWNER",
+		},
+		cli.StringFlag{
+			Name:   "repo.name",
+			Usage:  "repository name",
+			EnvVar: "DRONE_REPO_NAME",
+		},
+		cli.StringFlag{
+			Name:   "build.event",
+			Value:  "push",
+			Usage:  "build event",
+			EnvVar: "DRONE_BUILD_EVENT",
+		},
+		cli.StringFlag{
+			Name:   "commit.ref",
+			Value:  "refs/heads/master",
+			Usage:  "git commit ref",
+			EnvVar: "DRONE_COMMIT_REF",
+		},
+		cli.StringFlag{
+			Name:  "env-file",
+			Usage: "source env file",
+		},
+	}
+
+	if err := app.Run(os.Args); err != nil {
+		logrus.Fatal(err)
 	}
-
-	if vargs.UploadURL == "" {
-		vargs.UploadURL = "https://uploads.github.com/"
-	} else if !strings.HasSuffix(vargs.UploadURL, "/") {
-		vargs.UploadURL = vargs.UploadURL + "/"
-	}
-
-	if vargs.APIKey == "" {
-		fmt.Printf("You must provide an API key\n")
-		os.Exit(1)
-	}
-
-	if workspace.Path != "" {
-		os.Chdir(workspace.Path)
-	}
-
-	var files []string
-	for _, glob := range vargs.Files.Slice() {
-		globed, err := filepath.Glob(glob)
-		if err != nil {
-			fmt.Printf("Failed to glob %s\n", glob)
-			os.Exit(1)
-		}
-		if globed != nil {
-			files = append(files, globed...)
-		}
-	}
-
-	if vargs.Checksum.Len() > 0 {
-		var err error
-		files, err = writeChecksums(files, vargs.Checksum.Slice())
-		if err != nil {
-			fmt.Println(err)
-			os.Exit(1)
-		}
-	}
-
-	baseURL, err := url.Parse(vargs.BaseURL)
-	if err != nil {
-		fmt.Printf("Failed to parse base URL\n")
-		os.Exit(1)
-	}
-
-	uploadURL, err := url.Parse(vargs.UploadURL)
-	if err != nil {
-		fmt.Printf("Failed to parse upload URL\n")
-		os.Exit(1)
-	}
-
-	ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: vargs.APIKey})
-	tc := oauth2.NewClient(oauth2.NoContext, ts)
-
-	client := github.NewClient(tc)
-	client.BaseURL = baseURL
-	client.UploadURL = uploadURL
-
-	rc := releaseClient{
-		Client: client,
-		Owner:  repo.Owner,
-		Repo:   repo.Name,
-		Tag:    filepath.Base(build.Ref),
-		Draft:  vargs.Draft,
-		FileExists: vargs.FileExists,
-	}
-
-	release, err := rc.buildRelease()
-	if err != nil {
-		fmt.Println(err)
-		os.Exit(1)
-	}
-
-	if err := rc.uploadFiles(*release.ID, files); err != nil {
-		fmt.Println(err)
-		os.Exit(1)
-	}
-}
-
-var fileExistsValues = map[string]bool{
-	"overwrite": true,
-	"fail":      true,
-	"skip":      true,
-}
-
-// Release holds ties the drone env data and github client together.
-type releaseClient struct {
-	*github.Client
-	Owner      string
-	Repo       string
-	Tag        string
-	Draft      bool
-	FileExists string
 }
 
-func (rc *releaseClient) buildRelease() (*github.RepositoryRelease, error) {
-
-	// first attempt to get a release by that tag
-	release, err := rc.getRelease()
-	if err != nil && release == nil {
-		fmt.Println(err)
-	} else if release != nil {
-		return release, nil
-	}
-
-	// if no release was found by that tag, create a new one
-	release, err = rc.newRelease()
-	if err != nil {
-		return nil, fmt.Errorf("Failed to retrieve or create a release: %s", err)
-	}
-
-	return release, nil
-}
-
-func (rc *releaseClient) getRelease() (*github.RepositoryRelease, error) {
-	release, _, err := rc.Client.Repositories.GetReleaseByTag(rc.Owner, rc.Repo, rc.Tag)
-	if err != nil {
-		return nil, fmt.Errorf("Release %s not found", rc.Tag)
-	}
-
-	fmt.Printf("Successfully retrieved %s release\n", rc.Tag)
-	return release, nil
-}
-
-func (rc *releaseClient) newRelease() (*github.RepositoryRelease, error) {
-	rr := &github.RepositoryRelease{
-		TagName: github.String(rc.Tag),
-		Draft:   &rc.Draft,
-	}
-	release, _, err := rc.Client.Repositories.CreateRelease(rc.Owner, rc.Repo, rr)
-	if err != nil {
-		return nil, fmt.Errorf("Failed to create release: %s", err)
-	}
-
-	fmt.Printf("Successfully created %s release\n", rc.Tag)
-	return release, nil
-}
-
-func (rc *releaseClient) uploadFiles(id int, files []string) error {
-	assets, _, err := rc.Client.Repositories.ListReleaseAssets(rc.Owner, rc.Repo, id, &github.ListOptions{})
-	if err != nil {
-		return fmt.Errorf("Failed to fetch existing assets: %s", err)
-	}
-
-	var uploadFiles []string
-files:
-	for _, file := range files {
-		for _, asset := range assets {
-			if *asset.Name == path.Base(file) {
-				switch rc.FileExists {
-				case "overwrite":
-					// do nothing
-				case "fail":
-					return fmt.Errorf("Asset file %s already exists", path.Base(file))
-				case "skip":
-					fmt.Printf("Skipping pre-existing %s artifact\n", *asset.Name)
-					continue files
-				default:
-					return fmt.Errorf("Internal error, unkown file_exist value %s", rc.FileExists)
-				}
-			}
-		}
-		uploadFiles = append(uploadFiles, file)
-	}
-
-	for _, file := range uploadFiles {
-		handle, err := os.Open(file)
-		if err != nil {
-			return fmt.Errorf("Failed to read %s artifact: %s", file, err)
-		}
-
-		for _, asset := range assets {
-			if *asset.Name == path.Base(file) {
-				if _, err := rc.Client.Repositories.DeleteReleaseAsset(rc.Owner, rc.Repo, *asset.ID); err != nil {
-					return fmt.Errorf("Failed to delete %s artifact: %s", file, err)
-				}
-				fmt.Printf("Successfully deleted old %s artifact\n", *asset.Name)
-			}
-		}
-
-		uo := &github.UploadOptions{Name: path.Base(file)}
-		if _, _, err = rc.Client.Repositories.UploadReleaseAsset(rc.Owner, rc.Repo, id, uo, handle); err != nil {
-			return fmt.Errorf("Failed to upload %s artifact: %s", file, err)
-		}
-
-		fmt.Printf("Successfully uploaded %s artifact\n", file)
-	}
-
-	return nil
-}
-
-func writeChecksums(files, methods []string) ([]string, error) {
-
-	checksums := make(map[string][]string)
-	for _, method := range methods {
-		for _, file := range files {
-			handle, err := os.Open(file)
-			if err != nil {
-				return nil, fmt.Errorf("Failed to read %s artifact: %s", file, err)
-			}
-
-			hash, err := checksum(handle, method)
-			if err != nil {
-				return nil, err
-			}
-
-			checksums[method] = append(checksums[method], hash, file)
-		}
-	}
-
-	for method, results := range checksums {
-		filename := method + "sum.txt"
-		f, err := os.Create(filename)
-		if err != nil {
-			return nil, err
-		}
-
-		for i := 0; i < len(results); i += 2 {
-			hash := results[i]
-			file := results[i+1]
-			if _, err := f.WriteString(fmt.Sprintf("%s  %s\n", hash, file)); err != nil {
-				return nil, err
-			}
-		}
-		files = append(files, filename)
-	}
-	return files, nil
+func run(c *cli.Context) error {
+	if c.String("env-file") != "" {
+		_ = godotenv.Load(c.String("env-file"))
+	}
+
+	plugin := Plugin{
+		Repo: Repo{
+			Owner: c.String("repo.owner"),
+			Name:  c.String("repo.name"),
+		},
+		Build: Build{
+			Event: c.String("build.event"),
+		},
+		Commit: Commit{
+			Ref: c.String("commit.sha"),
+		},
+		Config: Config{
+			APIKey:     c.String("api-key"),
+			Files:      c.StringSlice("api-key"),
+			FileExists: c.String("file-exists"),
+			Checksum:   c.StringSlice("checksum"),
+			Draft:      c.Bool("draft"),
+			BaseURL:    c.String("base-url"),
+			UploadURL:  c.String("upload-url"),
+		},
+	}
+
+	return plugin.Exec()
 }
diff --git a/plugin.go b/plugin.go
new file mode 100644
index 0000000..c3282f4
--- /dev/null
+++ b/plugin.go
@@ -0,0 +1,134 @@
+package main
+
+import (
+	"fmt"
+	"net/url"
+	"path/filepath"
+	"strings"
+
+	"github.com/google/go-github/github"
+	"golang.org/x/oauth2"
+)
+
+type (
+	Repo struct {
+		Owner string
+		Name  string
+	}
+
+	Build struct {
+		Event string
+	}
+
+	Commit struct {
+		Ref string
+	}
+
+	Config struct {
+		APIKey     string
+		Files      []string
+		FileExists string
+		Checksum   []string
+		Draft      bool
+		BaseURL    string
+		UploadURL  string
+	}
+
+	Plugin struct {
+		Repo   Repo
+		Build  Build
+		Commit Commit
+		Config Config
+	}
+)
+
+func (p Plugin) Exec() error {
+	var (
+		files []string
+	)
+
+	if p.Build.Event != "tag" {
+		return fmt.Errorf("The GitHub Release plugin is only available for tags")
+	}
+
+	if p.Config.APIKey == "" {
+		return fmt.Errorf("You must provide an API key")
+	}
+
+	if !fileExistsValues[p.Config.FileExists] {
+		return fmt.Errorf("Invalid value for file_exists")
+	}
+
+	if !strings.HasSuffix(p.Config.BaseURL, "/") {
+		p.Config.BaseURL = p.Config.BaseURL + "/"
+	}
+
+	if !strings.HasSuffix(p.Config.UploadURL, "/") {
+		p.Config.UploadURL = p.Config.UploadURL + "/"
+	}
+
+	for _, glob := range p.Config.Files {
+		globed, err := filepath.Glob(glob)
+
+		if err != nil {
+			return fmt.Errorf("Failed to glob %s. %s", glob, err)
+		}
+
+		if globed != nil {
+			files = append(files, globed...)
+		}
+	}
+
+	if len(p.Config.Checksum) > 0 {
+		var (
+			err error
+		)
+
+		files, err = writeChecksums(files, p.Config.Checksum)
+
+		if err != nil {
+			return fmt.Errorf("Failed to write checksums. %s", err)
+		}
+	}
+
+	baseURL, err := url.Parse(p.Config.BaseURL)
+
+	if err != nil {
+		return fmt.Errorf("Failed to parse base URL. %s", err)
+	}
+
+	uploadURL, err := url.Parse(p.Config.UploadURL)
+
+	if err != nil {
+		return fmt.Errorf("Failed to parse upload URL. %s", err)
+	}
+
+	ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: p.Config.APIKey})
+	tc := oauth2.NewClient(oauth2.NoContext, ts)
+
+	client := github.NewClient(tc)
+
+	client.BaseURL = baseURL
+	client.UploadURL = uploadURL
+
+	rc := releaseClient{
+		Client:     client,
+		Owner:      p.Repo.Owner,
+		Repo:       p.Repo.Name,
+		Tag:        filepath.Base(p.Commit.Ref),
+		Draft:      p.Config.Draft,
+		FileExists: p.Config.FileExists,
+	}
+
+	release, err := rc.buildRelease()
+
+	if err != nil {
+		return fmt.Errorf("Failed to create the release. %s", err)
+	}
+
+	if err := rc.uploadFiles(*release.ID, files); err != nil {
+		return fmt.Errorf("Failed to upload the files. %s", err)
+	}
+
+	return nil
+}
diff --git a/release.go b/release.go
new file mode 100644
index 0000000..cd8c833
--- /dev/null
+++ b/release.go
@@ -0,0 +1,125 @@
+package main
+
+import (
+	"fmt"
+	"os"
+	"path"
+
+	"github.com/google/go-github/github"
+)
+
+// Release holds ties the drone env data and github client together.
+type releaseClient struct {
+	*github.Client
+	Owner      string
+	Repo       string
+	Tag        string
+	Draft      bool
+	FileExists string
+}
+
+func (rc *releaseClient) buildRelease() (*github.RepositoryRelease, error) {
+	// first attempt to get a release by that tag
+	release, err := rc.getRelease()
+
+	if err != nil && release == nil {
+		fmt.Println(err)
+	} else if release != nil {
+		return release, nil
+	}
+
+	// if no release was found by that tag, create a new one
+	release, err = rc.newRelease()
+
+	if err != nil {
+		return nil, fmt.Errorf("Failed to retrieve or create a release: %s", err)
+	}
+
+	return release, nil
+}
+
+func (rc *releaseClient) getRelease() (*github.RepositoryRelease, error) {
+	release, _, err := rc.Client.Repositories.GetReleaseByTag(rc.Owner, rc.Repo, rc.Tag)
+
+	if err != nil {
+		return nil, fmt.Errorf("Release %s not found", rc.Tag)
+	}
+
+	fmt.Printf("Successfully retrieved %s release\n", rc.Tag)
+	return release, nil
+}
+
+func (rc *releaseClient) newRelease() (*github.RepositoryRelease, error) {
+	rr := &github.RepositoryRelease{
+		TagName: github.String(rc.Tag),
+		Draft:   &rc.Draft,
+	}
+
+	release, _, err := rc.Client.Repositories.CreateRelease(rc.Owner, rc.Repo, rr)
+
+	if err != nil {
+		return nil, fmt.Errorf("Failed to create release: %s", err)
+	}
+
+	fmt.Printf("Successfully created %s release\n", rc.Tag)
+	return release, nil
+}
+
+func (rc *releaseClient) uploadFiles(id int, files []string) error {
+	assets, _, err := rc.Client.Repositories.ListReleaseAssets(rc.Owner, rc.Repo, id, &github.ListOptions{})
+
+	if err != nil {
+		return fmt.Errorf("Failed to fetch existing assets: %s", err)
+	}
+
+	var uploadFiles []string
+
+files:
+	for _, file := range files {
+		for _, asset := range assets {
+			if *asset.Name == path.Base(file) {
+				switch rc.FileExists {
+				case "overwrite":
+					// do nothing
+				case "fail":
+					return fmt.Errorf("Asset file %s already exists", path.Base(file))
+				case "skip":
+					fmt.Printf("Skipping pre-existing %s artifact\n", *asset.Name)
+					continue files
+				default:
+					return fmt.Errorf("Internal error, unkown file_exist value %s", rc.FileExists)
+				}
+			}
+		}
+
+		uploadFiles = append(uploadFiles, file)
+	}
+
+	for _, file := range uploadFiles {
+		handle, err := os.Open(file)
+
+		if err != nil {
+			return fmt.Errorf("Failed to read %s artifact: %s", file, err)
+		}
+
+		for _, asset := range assets {
+			if *asset.Name == path.Base(file) {
+				if _, err := rc.Client.Repositories.DeleteReleaseAsset(rc.Owner, rc.Repo, *asset.ID); err != nil {
+					return fmt.Errorf("Failed to delete %s artifact: %s", file, err)
+				}
+
+				fmt.Printf("Successfully deleted old %s artifact\n", *asset.Name)
+			}
+		}
+
+		uo := &github.UploadOptions{Name: path.Base(file)}
+
+		if _, _, err = rc.Client.Repositories.UploadReleaseAsset(rc.Owner, rc.Repo, id, uo, handle); err != nil {
+			return fmt.Errorf("Failed to upload %s artifact: %s", file, err)
+		}
+
+		fmt.Printf("Successfully uploaded %s artifact\n", file)
+	}
+
+	return nil
+}
diff --git a/types.go b/types.go
deleted file mode 100644
index 8deee02..0000000
--- a/types.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package main
-
-import "github.com/drone/drone-go/drone"
-
-// Params are the parameters that the GitHub Release plugin can parse.
-type Params struct {
-	BaseURL    string            `json:"base_url"`
-	UploadURL  string            `json:"upload_url"`
-	APIKey     string            `json:"api_key"`
-	Files      drone.StringSlice `json:"files"`
-	Checksum   drone.StringSlice `json:"checksum"`
-	Draft      bool              `json:"draft"`
-	FileExists string            `json:"file_exists"`
-}
diff --git a/utils.go b/utils.go
new file mode 100644
index 0000000..794b0a5
--- /dev/null
+++ b/utils.go
@@ -0,0 +1,103 @@
+package main
+
+import (
+	"crypto/md5"
+	"crypto/sha1"
+	"crypto/sha256"
+	"crypto/sha512"
+	"fmt"
+	"hash/adler32"
+	"hash/crc32"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+)
+
+var (
+	fileExistsValues = map[string]bool{
+		"overwrite": true,
+		"fail":      true,
+		"skip":      true,
+	}
+)
+
+func execute(cmd *exec.Cmd) error {
+	fmt.Println("+", strings.Join(cmd.Args, " "))
+
+	cmd.Stderr = os.Stderr
+	cmd.Stdin = os.Stdin
+
+	return cmd.Run()
+}
+
+func checksum(r io.Reader, method string) (string, error) {
+	b, err := ioutil.ReadAll(r)
+
+	if err != nil {
+		return "", err
+	}
+
+	switch method {
+	case "md5":
+		return fmt.Sprintf("%x", md5.Sum(b)), nil
+	case "sha1":
+		return fmt.Sprintf("%x", sha1.Sum(b)), nil
+	case "sha256":
+		return fmt.Sprintf("%x", sha256.Sum256(b)), nil
+	case "sha512":
+		return fmt.Sprintf("%x", sha512.Sum512(b)), nil
+	case "adler32":
+		return strconv.FormatUint(uint64(adler32.Checksum(b)), 10), nil
+	case "crc32":
+		return strconv.FormatUint(uint64(crc32.ChecksumIEEE(b)), 10), nil
+	}
+
+	return "", fmt.Errorf("Hashing method %s is not supported", method)
+}
+
+func writeChecksums(files, methods []string) ([]string, error) {
+	checksums := make(map[string][]string)
+
+	for _, method := range methods {
+		for _, file := range files {
+			handle, err := os.Open(file)
+
+			if err != nil {
+				return nil, fmt.Errorf("Failed to read %s artifact: %s", file, err)
+			}
+
+			hash, err := checksum(handle, method)
+
+			if err != nil {
+				return nil, err
+			}
+
+			checksums[method] = append(checksums[method], hash, file)
+		}
+	}
+
+	for method, results := range checksums {
+		filename := method + "sum.txt"
+		f, err := os.Create(filename)
+
+		if err != nil {
+			return nil, err
+		}
+
+		for i := 0; i < len(results); i += 2 {
+			hash := results[i]
+			file := results[i+1]
+
+			if _, err := f.WriteString(fmt.Sprintf("%s  %s\n", hash, file)); err != nil {
+				return nil, err
+			}
+		}
+
+		files = append(files, filename)
+	}
+
+	return files, nil
+}