Here’s a quick example of porting drone-downstream to my current prototype API.
The main focus is to investigate how they differ in look and feel, all the
mentioned error print formatting and other features which brings value under
the hood is yet to be added.
before
package main
import (
"fmt"
"os"
"github.com/Sirupsen/logrus"
"github.com/joho/godotenv"
"github.com/urfave/cli"
)
var build = "0" // build number set at compile-time
func main() {
app := cli.NewApp()
app.Name = "downstream plugin"
app.Usage = "downstream plugin"
app.Action = run
app.Version = fmt.Sprintf("1.0.%s", build)
app.Flags = []cli.Flag{
cli.StringSliceFlag{
Name: "repositories",
Usage: "List of repositories to trigger",
EnvVar: "PLUGIN_REPOSITORIES",
},
cli.StringFlag{
Name: "server",
Usage: "Trigger a drone build on a custom server",
EnvVar: "DOWNSTREAM_SERVER,PLUGIN_SERVER",
},
cli.StringFlag{
Name: "token",
Usage: "Drone API token from your user settings",
EnvVar: "DOWNSTREAM_TOKEN,PLUGIN_TOKEN",
},
cli.BoolFlag{
Name: "fork",
Usage: "Trigger a new build for a repository",
EnvVar: "PLUGIN_FORK",
},
cli.StringFlag{
Name: "env-file",
Usage: "source env file",
},
}
if err := app.Run(os.Args); err != nil {
logrus.Fatal(err)
}
}
func run(c *cli.Context) error {
if c.String("env-file") != "" {
_ = godotenv.Load(c.String("env-file"))
}
plugin := Plugin{
Repos: c.StringSlice("repositories"),
Server: c.String("server"),
Token: c.String("token"),
Fork: c.Bool("fork"),
}
return plugin.Exec()
}
// Plugin defines the Downstream plugin parameters.
type Plugin struct {
Repos []string
Server string
Token string
Fork bool
}
// Exec runs the plugin
func (p *Plugin) Exec() error {
if len(p.Token) == 0 {
return fmt.Errorf("Error: you must provide your Drone access token.")
}
if len(p.Server) == 0 {
return fmt.Errorf("Error: you must provide your Drone server.")
}
client := drone.NewClientToken(p.Server, p.Token)
...
after
One thing I really noted while doing this was that mixing a lot of lines
beginning with plugins.
and flag.
in sequence looks rather noisy. I renamed
the import to plug
in this example. plugins
should either be renamed to a 4
letter word or mirror all of the flag.**Var()
functions… I chose the package
name plugins because of the current drone plugins convention of having a struct
and instance named plugin.
import (
"flag"
"fmt"
"strings"
"github.com/drone/drone-go/drone"
plug "github.com/thomasf/drone-plugins-go/plugins"
)
var build = "0" // build number set at compile-time
func main() {
var p Plugin
flag.BoolVar(&p.Fork, "fork", false, "Trigger a new build for a repository")
flag.Var(&p.Repos, "repositories", "List of repositories to trigger")
flag.StringVar(&p.Server, "server", "", "Trigger a drone build on a custom server")
plug.FlagEnvNames(&p.Server, "DOWNSTREAM_SERVER,PLUGIN_SERVER", "") // emtpy string means default PLUGIN_...
flag.StringVar(&p.Token, "token", "", "Drone API token from your user settings")
plug.FlagEnvNames(&p.Token, "DOWNSTREAM_TOKEN", "")
plug.EnvFile() // just handles it, no need for a ref?
plug.Parse() // the Exec(Execer) function below should probably take care of the "parse" step
plug.Exec(&p)
}
// Plugin defines the Downstream plugin parameters.
type Plugin struct {
Repos plug.StringSliceFlag
Server string
Token string
Fork bool
}
// Exec runs the plugin
func (p *Plugin) Exec() error {
if len(p.Token) == 0 {
plug.FatalFlagf(&p.Token, "you must provide your Drone access token.")
}
if len(p.Server) == 0 {
plug.FatalFlagf(&p.Server, "you must provide your Drone server.")
}
client := drone.NewClientToken(p.Server, p.Token)
...