├── plugin ├── const.go ├── types.go └── param.go ├── .gitignore ├── example └── main.go ├── README.md └── LICENSE /plugin/const.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | const ( 4 | StatePending = "pending" 5 | StateRunning = "running" 6 | StateSuccess = "success" 7 | StateFailure = "failure" 8 | StateKilled = "killed" 9 | StateError = "error" 10 | ) 11 | 12 | const ( 13 | EventPush = "push" 14 | EventPull = "pull_request" 15 | EventTag = "tag" 16 | EventDeploy = "deploy" 17 | ) 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | example/example -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/drone/drone-plugin-go/plugin" 10 | ) 11 | 12 | func main() { 13 | var repo = plugin.Repo{} 14 | var build = plugin.Build{} 15 | var vargs = struct { 16 | Urls []string `json:"urls"` 17 | }{} 18 | 19 | plugin.Param("repo", &repo) 20 | plugin.Param("build", &build) 21 | plugin.Param("vargs", &vargs) 22 | plugin.Parse() 23 | 24 | // data structure 25 | data := struct { 26 | Repo plugin.Repo `json:"repo"` 27 | Build plugin.Build `json:"build"` 28 | }{repo, build} 29 | 30 | // json payload that will be posted 31 | payload, err := json.Marshal(&data) 32 | if err != nil { 33 | os.Exit(1) 34 | } 35 | 36 | // post payload to each url 37 | for _, url := range vargs.Urls { 38 | resp, err := http.Post(url, "application/json", bytes.NewBuffer(payload)) 39 | if err != nil { 40 | os.Exit(1) 41 | } 42 | resp.Body.Close() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /plugin/types.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | // Repo represents a version control repository. 4 | type Repo struct { 5 | Kind string `json:"scm"` 6 | Owner string `json:"owner"` 7 | Name string `json:"name"` 8 | FullName string `json:"full_name"` 9 | Avatar string `json:"avatar_url"` 10 | Link string `json:"link_url"` 11 | Clone string `json:"clone_url"` 12 | Branch string `json:"default_branch"` 13 | Timeout int64 `json:"timeout"` 14 | IsPrivate bool `json:"private"` 15 | IsTrusted bool `json:"trusted"` 16 | AllowPull bool `json:"allow_pr"` 17 | AllowPush bool `json:"allow_push"` 18 | AllowDeploy bool `json:"allow_deploys"` 19 | AllowTag bool `json:"allow_tags"` 20 | } 21 | 22 | // System provides important information about the Drone 23 | // server to the plugin. 24 | type System struct { 25 | Version string `json:"version"` 26 | Link string `json:"link_url"` 27 | Plugins []string `json:"plugins"` 28 | Globals []string `json:"globals"` 29 | Escalates []string `json:"privileged_plugins"` 30 | } 31 | 32 | // Workspace defines the build's workspace inside the 33 | // container. This helps the plugin locate the source 34 | // code directory. 35 | type Workspace struct { 36 | Root string `json:"root"` 37 | Path string `json:"path"` 38 | 39 | Netrc *Netrc `json:"netrc"` 40 | Keys *Keypair `json:"keys"` 41 | } 42 | 43 | // Keypair represents an RSA public and private key assigned to a 44 | // repository. It may be used to clone private repositories, or as 45 | // a deployment key. 46 | type Keypair struct { 47 | Public string `json:"public"` 48 | Private string `json:"private"` 49 | } 50 | 51 | // Netrc defines a default .netrc file that should be injected 52 | // into the build environment. It will be used to authorize access 53 | // to https resources, such as git+https clones. 54 | type Netrc struct { 55 | Machine string `json:"machine"` 56 | Login string `json:"login"` 57 | Password string `json:"user"` 58 | } 59 | 60 | // Build represents the process of compiling and testing a changeset, 61 | // typically triggered by the remote system (ie GitHub). 62 | type Build struct { 63 | Number int `json:"number"` 64 | Event string `json:"event"` 65 | Status string `json:"status"` 66 | Enqueued int64 `json:"enqueued_at"` 67 | Created int64 `json:"created_at"` 68 | Started int64 `json:"started_at"` 69 | Finished int64 `json:"finished_at"` 70 | Deploy string `json:"deploy_to"` 71 | Commit string `json:"commit"` 72 | Branch string `json:"branch"` 73 | Ref string `json:"ref"` 74 | Refspec string `json:"refspec"` 75 | Remote string `json:"remote"` 76 | Title string `json:"title"` 77 | Message string `json:"message"` 78 | Timestamp int64 `json:"timestamp"` 79 | Author string `json:"author"` 80 | Avatar string `json:"author_avatar"` 81 | Email string `json:"author_email"` 82 | Link string `json:"link_url"` 83 | } 84 | 85 | // Job represents a single job that is being executed as part 86 | // of a Build. 87 | type Job struct { 88 | ID int64 `json:"id"` 89 | Number int `json:"number"` 90 | Status string `json:"status"` 91 | ExitCode int `json:"exit_code"` 92 | Enqueued int64 `json:"enqueued_at"` 93 | Started int64 `json:"started_at"` 94 | Finished int64 `json:"finished_at"` 95 | 96 | Environment map[string]string `json:"environment"` 97 | } 98 | -------------------------------------------------------------------------------- /plugin/param.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "os" 9 | ) 10 | 11 | var Stdin *ParamSet 12 | 13 | func init() { 14 | // defaults to stdin 15 | Stdin = NewParamSet(os.Stdin) 16 | 17 | // check for params after the double dash 18 | // in the command string 19 | for i, argv := range os.Args { 20 | if argv == "--" { 21 | arg := os.Args[i+1] 22 | buf := bytes.NewBufferString(arg) 23 | Stdin = NewParamSet(buf) 24 | break 25 | } 26 | } 27 | } 28 | 29 | // this init function is deprecated, but I'm keeping it 30 | // around just in case it proves useful in the future. 31 | func deprecated_init() { 32 | // if piping from stdin we can just exit 33 | // and use the default Stdin value 34 | stat, _ := os.Stdin.Stat() 35 | if (stat.Mode() & os.ModeCharDevice) == 0 { 36 | return 37 | } 38 | 39 | // check for params after the double dash 40 | // in the command string 41 | for i, argv := range os.Args { 42 | if argv == "--" { 43 | arg := os.Args[i+1] 44 | buf := bytes.NewBufferString(arg) 45 | Stdin = NewParamSet(buf) 46 | return 47 | } 48 | } 49 | 50 | // else use the first variable in the list 51 | if len(os.Args) > 1 { 52 | buf := bytes.NewBufferString(os.Args[1]) 53 | Stdin = NewParamSet(buf) 54 | } 55 | } 56 | 57 | type ParamSet struct { 58 | reader io.Reader 59 | params map[string]interface{} 60 | } 61 | 62 | func NewParamSet(reader io.Reader) *ParamSet { 63 | var p = new(ParamSet) 64 | p.reader = reader 65 | p.params = map[string]interface{}{} 66 | return p 67 | } 68 | 69 | // Param defines a parameter with the specified name. 70 | func (p ParamSet) Param(name string, value interface{}) { 71 | p.params[name] = value 72 | } 73 | 74 | // Parse parses parameter definitions from the map. 75 | func (p ParamSet) Parse() error { 76 | raw := map[string]json.RawMessage{} 77 | err := json.NewDecoder(p.reader).Decode(&raw) 78 | if err != nil { 79 | return err 80 | } 81 | 82 | for key, val := range p.params { 83 | data, ok := raw[key] 84 | if !ok { 85 | continue 86 | } 87 | err := json.Unmarshal(data, val) 88 | if err != nil { 89 | return fmt.Errorf("Unable to unarmshal %s. %s", key, err) 90 | } 91 | } 92 | 93 | return nil 94 | } 95 | 96 | // Unmarshal parses the JSON payload from the command 97 | // arguments and unmarshal into a value pointed to by v. 98 | func (p ParamSet) Unmarshal(v interface{}) error { 99 | return json.NewDecoder(p.reader).Decode(v) 100 | } 101 | 102 | // Param defines a parameter with the specified name. 103 | func Param(name string, value interface{}) { 104 | Stdin.Param(name, value) 105 | } 106 | 107 | // Parse parses parameter definitions from the map. 108 | func Parse() error { 109 | return Stdin.Parse() 110 | } 111 | 112 | // Unmarshal parses the JSON payload from the command 113 | // arguments and unmarshal into a value pointed to by v. 114 | func Unmarshal(v interface{}) error { 115 | return Stdin.Unmarshal(v) 116 | } 117 | 118 | // Unmarshal parses the JSON payload from the command 119 | // arguments and unmarshal into a value pointed to by v. 120 | func MustUnmarshal(v interface{}) error { 121 | return Stdin.Unmarshal(v) 122 | } 123 | 124 | // MustParse parses parameter definitions from the map 125 | // and panics if there is a parsing error. 126 | func MustParse() { 127 | err := Parse() 128 | if err != nil { 129 | panic(err) 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | drone-plugin-go 2 | =============== 3 | 4 | This is a package with simple support for writing Drone plugins in Go. 5 | 6 | ## Overview 7 | 8 | Plugins are executable files run by Drone to customize the build lifecycle. Plugins receive input data from `stdin` (or `arg[1]`) and write the results to `stdout` 9 | 10 | ```sh 11 | ./slack-plugin <