If your team is using Drone extensions, you may want to combine multiple extensions into a single codebase and microservice. In the below example we create a registry extension (returning registry credentials used when pulling private images) and an environment extension (returning environment variables automatically injected into the pipeline).
package main
import (
"net/http"
"github.com/drone/drone-go/plugin/environ"
"github.com/drone/drone-go/plugin/registry"
"github.com/foo/bar/plugin"
_ "github.com/joho/godotenv/autoload"
"github.com/kelseyhightower/envconfig"
"github.com/sirupsen/logrus"
)
// spec provides the plugin settings.
type spec struct {
Bind string `envconfig:"DRONE_BIND"`
Debug bool `envconfig:"DRONE_DEBUG"`
Secret string `envconfig:"DRONE_SECRET"`
}
func main() {
spec := new(spec)
err := envconfig.Process("", spec)
if err != nil {
logrus.Fatal(err)
}
if spec.Debug {
logrus.SetLevel(logrus.DebugLevel)
}
if spec.Secret == "" {
logrus.Fatalln("missing secret key")
}
if spec.Bind == "" {
spec.Bind = ":3000"
}
// create a handler for our registry extension.
h1 := registry.Handler(
spec.Secret,
plugin.NewRegistry(),
logrus.StandardLogger(),
)
// create a handler for our environment extension.
h2 := environ.Handler(
spec.Secret,
plugins.NewEnviron()
logrus.StandardLogger(),
)
logrus.Infof("server listening on address %s", spec.Bind)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// when the runner makes an API call to the extension
// it uses the Accept header to limit the request to a
// specific data type. This can therefore be used to
// route requests to a single server to different extension
// handlers.
switch r.Header.Get("Accept"): {
case registry.V1:
h1.ServeHTTP(w, r)
case environ.V1:
h2.ServeHTTP(w, r)
case environ.V2:
h2.ServeHTTP(w, r)
}
})
logrus.Fatal(http.ListenAndServe(spec.Bind, nil))
}
Here is our registry plugin:
package plugin
import (
"context"
"github.com/drone/drone-go/drone"
"github.com/drone/drone-go/plugin/registry"
)
// New returns a new registry plugin.
func NewRegistry() registry.Plugin {
return ®istryPlugin{}
}
type registryPlugin struct {
}
func (p *registryPlugin) List(ctx context.Context, req *registry.Request) ([]*drone.Registry, error) {
// TODO replace or remove
// we can return a list of credentials for
// multiple registries.
credentials := []*drone.Registry{
{
Address: "index.docker.io",
Username: "octocat",
Password: "correct-horse-battery-staple",
},
}
return credentials, nil
}
and here is our environment plugin:
package plugin
import (
"context"
"github.com/drone/drone-go/plugin/environ"
)
// NewEnviron returns a new environ plugin.
func NewEnviron() environ.Plugin {
return &environPlugin{}
}
type environPlugin struct {
}
func (p *environPlugin) List(ctx context.Context, req *environ.Request) ([]*environ.Variable, error) {
// TODO replace or remove
// return a list of static environment variables
// this is for demo purposes only.
environ := []*environ.Variable{
{
Name: "foo",
Data: "bar",
Mask: false,
},
}
return environ, nil
}