mirror of
https://github.com/thegeeklab/wp-docker-buildx.git
synced 2024-11-22 00:00:40 +00:00
refactor: update dependencies and use plugin boilerplate
This commit is contained in:
parent
441d5a1f52
commit
ba28c39a7d
261
cmd/drone-docker-buildx/config.go
Normal file
261
cmd/drone-docker-buildx/config.go
Normal file
@ -0,0 +1,261 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/thegeeklab/drone-docker-buildx/plugin"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// settingsFlags has the cli.Flags for the plugin.Settings.
|
||||
func settingsFlags(settings *plugin.Settings) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "dry-run",
|
||||
Usage: "dry run disables docker push",
|
||||
EnvVars: []string{"PLUGIN_DRY_RUN"},
|
||||
Destination: &settings.Dryrun,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "remote.url",
|
||||
Usage: "git remote url",
|
||||
EnvVars: []string{"DRONE_REMOTE_URL"},
|
||||
Destination: &settings.Build.Remote,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "commit.sha",
|
||||
Usage: "git commit sha",
|
||||
EnvVars: []string{"DRONE_COMMIT_SHA"},
|
||||
Value: "00000000",
|
||||
Destination: &settings.Build.Name,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "commit.ref",
|
||||
Usage: "git commit ref",
|
||||
EnvVars: []string{"DRONE_COMMIT_REF"},
|
||||
Destination: &settings.Build.Ref,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "daemon.mirror",
|
||||
Usage: "docker daemon registry mirror",
|
||||
EnvVars: []string{"PLUGIN_MIRROR", "DOCKER_PLUGIN_MIRROR"},
|
||||
Destination: &settings.Daemon.Mirror,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "daemon.storage-driver",
|
||||
Usage: "docker daemon storage driver",
|
||||
EnvVars: []string{"PLUGIN_STORAGE_DRIVER"},
|
||||
Destination: &settings.Daemon.StorageDriver,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "daemon.storage-path",
|
||||
Usage: "docker daemon storage path",
|
||||
Value: "/var/lib/docker",
|
||||
EnvVars: []string{"PLUGIN_STORAGE_PATH"},
|
||||
Destination: &settings.Daemon.StoragePath,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "daemon.bip",
|
||||
Usage: "docker daemon bride ip address",
|
||||
EnvVars: []string{"PLUGIN_BIP"},
|
||||
Destination: &settings.Daemon.Bip,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "daemon.mtu",
|
||||
Usage: "docker daemon custom mtu setting",
|
||||
EnvVars: []string{"PLUGIN_MTU"},
|
||||
Destination: &settings.Daemon.MTU,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "daemon.dns",
|
||||
Usage: "docker daemon dns server",
|
||||
EnvVars: []string{"PLUGIN_CUSTOM_DNS"},
|
||||
Destination: &settings.Daemon.DNS,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "daemon.dns-search",
|
||||
Usage: "docker daemon dns search domains",
|
||||
EnvVars: []string{"PLUGIN_CUSTOM_DNS_SEARCH"},
|
||||
Destination: &settings.Daemon.DNSSearch,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "daemon.insecure",
|
||||
Usage: "docker daemon allows insecure registries",
|
||||
EnvVars: []string{"PLUGIN_INSECURE"},
|
||||
Destination: &settings.Daemon.Insecure,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "daemon.ipv6",
|
||||
Usage: "docker daemon IPv6 networking",
|
||||
EnvVars: []string{"PLUGIN_IPV6"},
|
||||
Destination: &settings.Daemon.IPv6,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "daemon.experimental",
|
||||
Usage: "docker daemon Experimental mode",
|
||||
EnvVars: []string{"PLUGIN_EXPERIMENTAL"},
|
||||
Destination: &settings.Daemon.Experimental,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "daemon.debug",
|
||||
Usage: "docker daemon executes in debug mode",
|
||||
EnvVars: []string{"PLUGIN_DEBUG", "DOCKER_LAUNCH_DEBUG"},
|
||||
Destination: &settings.Daemon.Debug,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "daemon.off",
|
||||
Usage: "don't start the docker daemon",
|
||||
EnvVars: []string{"PLUGIN_DAEMON_OFF"},
|
||||
Destination: &settings.Daemon.Disabled,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "dockerfile",
|
||||
Usage: "build dockerfile",
|
||||
Value: "Dockerfile",
|
||||
EnvVars: []string{"PLUGIN_DOCKERFILE"},
|
||||
Destination: &settings.Build.Dockerfile,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "context",
|
||||
Usage: "build context",
|
||||
Value: ".",
|
||||
EnvVars: []string{"PLUGIN_CONTEXT"},
|
||||
Destination: &settings.Build.Context,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "tags",
|
||||
Usage: "build tags",
|
||||
Value: cli.NewStringSlice([]string{"latest"}...),
|
||||
EnvVars: []string{"PLUGIN_TAG", "PLUGIN_TAGS"},
|
||||
FilePath: ".tags",
|
||||
Destination: &settings.Build.Tags,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "tags.auto",
|
||||
Usage: "default build tags",
|
||||
EnvVars: []string{"PLUGIN_DEFAULT_TAGS", "PLUGIN_AUTO_TAG"},
|
||||
Destination: &settings.Build.TagsAuto,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "tags.suffix",
|
||||
Usage: "default build tags with suffix",
|
||||
EnvVars: []string{"PLUGIN_DEFAULT_SUFFIX", "PLUGIN_AUTO_TAG_SUFFIX"},
|
||||
Destination: &settings.Build.TagsSuffix,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "args",
|
||||
Usage: "build args",
|
||||
EnvVars: []string{"PLUGIN_BUILD_ARGS"},
|
||||
Destination: &settings.Build.Args,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "args-from-env",
|
||||
Usage: "build args",
|
||||
EnvVars: []string{"PLUGIN_BUILD_ARGS_FROM_ENV"},
|
||||
Destination: &settings.Build.ArgsEnv,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "quiet docker build",
|
||||
EnvVars: []string{"PLUGIN_QUIET"},
|
||||
Destination: &settings.Build.Quiet,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "target",
|
||||
Usage: "build target",
|
||||
EnvVars: []string{"PLUGIN_TARGET"},
|
||||
Destination: &settings.Build.Target,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "cache-from",
|
||||
Usage: "images to consider as cache sources",
|
||||
EnvVars: []string{"PLUGIN_CACHE_FROM"},
|
||||
Destination: &settings.Build.CacheFrom,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "squash",
|
||||
Usage: "squash the layers at build time",
|
||||
EnvVars: []string{"PLUGIN_SQUASH"},
|
||||
Destination: &settings.Build.Squash,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "pull-image",
|
||||
Usage: "force pull base image at build time",
|
||||
EnvVars: []string{"PLUGIN_PULL_IMAGE"},
|
||||
Value: true,
|
||||
Destination: &settings.Build.Pull,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "compress",
|
||||
Usage: "compress the build context using gzip",
|
||||
EnvVars: []string{"PLUGIN_COMPRESS"},
|
||||
Destination: &settings.Build.Compress,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
Usage: "docker repository",
|
||||
EnvVars: []string{"PLUGIN_REPO"},
|
||||
Destination: &settings.Build.Repo,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "docker.registry",
|
||||
Usage: "docker registry",
|
||||
Value: "https://index.docker.io/v1/",
|
||||
EnvVars: []string{"PLUGIN_REGISTRY", "DOCKER_REGISTRY"},
|
||||
Destination: &settings.Login.Registry,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "docker.username",
|
||||
Usage: "docker username",
|
||||
EnvVars: []string{"PLUGIN_USERNAME", "DOCKER_USERNAME"},
|
||||
Destination: &settings.Login.Username,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "docker.password",
|
||||
Usage: "docker password",
|
||||
EnvVars: []string{"PLUGIN_PASSWORD", "DOCKER_PASSWORD"},
|
||||
Destination: &settings.Login.Password,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "docker.email",
|
||||
Usage: "docker email",
|
||||
EnvVars: []string{"PLUGIN_EMAIL", "DOCKER_EMAIL"},
|
||||
Destination: &settings.Login.Email,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "docker.config",
|
||||
Usage: "docker json dockerconfig content",
|
||||
EnvVars: []string{"PLUGIN_CONFIG", "DOCKER_PLUGIN_CONFIG"},
|
||||
Destination: &settings.Login.Config,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "docker.purge",
|
||||
Usage: "docker should cleanup images",
|
||||
EnvVars: []string{"PLUGIN_PURGE"},
|
||||
Value: true,
|
||||
Destination: &settings.Cleanup,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repo.branch",
|
||||
Usage: "repository default branch",
|
||||
EnvVars: []string{"DRONE_REPO_BRANCH"},
|
||||
Destination: &settings.Build.Branch,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "no-cache",
|
||||
Usage: "do not use cached intermediate containers",
|
||||
EnvVars: []string{"PLUGIN_NO_CACHE"},
|
||||
Destination: &settings.Build.NoCache,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "add-host",
|
||||
Usage: "additional host:IP mapping",
|
||||
EnvVars: []string{"PLUGIN_ADD_HOST"},
|
||||
Destination: &settings.Build.AddHost,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "platforms",
|
||||
Usage: "arget platform for build",
|
||||
EnvVars: []string{"PLUGIN_PLATFORMS"},
|
||||
Destination: &settings.Build.Platforms,
|
||||
},
|
||||
}
|
||||
}
|
@ -4,308 +4,61 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/thegeeklab/drone-docker-buildx/plugin"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
docker "github.com/drone-plugins/drone-docker"
|
||||
"github.com/drone-plugins/drone-plugin-lib/errors"
|
||||
"github.com/drone-plugins/drone-plugin-lib/urfave"
|
||||
)
|
||||
|
||||
var (
|
||||
version = "unknown"
|
||||
)
|
||||
var version = "unknown"
|
||||
|
||||
func main() {
|
||||
// Load env-file if it exists first
|
||||
if env := os.Getenv("PLUGIN_ENV_FILE"); env != "" {
|
||||
godotenv.Load(env)
|
||||
settings := &plugin.Settings{}
|
||||
|
||||
if _, err := os.Stat("/run/drone/env"); err == nil {
|
||||
godotenv.Overload("/run/drone/env")
|
||||
}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "drone-docker-buildx"
|
||||
app.Usage = "Build docker container with DinD and buildx."
|
||||
app.Action = run
|
||||
app.Version = version
|
||||
app.Flags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "dry-run",
|
||||
Usage: "dry run disables docker push",
|
||||
EnvVar: "PLUGIN_DRY_RUN",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "remote.url",
|
||||
Usage: "git remote url",
|
||||
EnvVar: "DRONE_REMOTE_URL",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "commit.sha",
|
||||
Usage: "git commit sha",
|
||||
EnvVar: "DRONE_COMMIT_SHA",
|
||||
Value: "00000000",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "commit.ref",
|
||||
Usage: "git commit ref",
|
||||
EnvVar: "DRONE_COMMIT_REF",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "daemon.mirror",
|
||||
Usage: "docker daemon registry mirror",
|
||||
EnvVar: "PLUGIN_MIRROR,DOCKER_PLUGIN_MIRROR",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "daemon.storage-driver",
|
||||
Usage: "docker daemon storage driver",
|
||||
EnvVar: "PLUGIN_STORAGE_DRIVER",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "daemon.storage-path",
|
||||
Usage: "docker daemon storage path",
|
||||
Value: "/var/lib/docker",
|
||||
EnvVar: "PLUGIN_STORAGE_PATH",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "daemon.bip",
|
||||
Usage: "docker daemon bride ip address",
|
||||
EnvVar: "PLUGIN_BIP",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "daemon.mtu",
|
||||
Usage: "docker daemon custom mtu setting",
|
||||
EnvVar: "PLUGIN_MTU",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "daemon.dns",
|
||||
Usage: "docker daemon dns server",
|
||||
EnvVar: "PLUGIN_CUSTOM_DNS",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "daemon.dns-search",
|
||||
Usage: "docker daemon dns search domains",
|
||||
EnvVar: "PLUGIN_CUSTOM_DNS_SEARCH",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "daemon.insecure",
|
||||
Usage: "docker daemon allows insecure registries",
|
||||
EnvVar: "PLUGIN_INSECURE",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "daemon.ipv6",
|
||||
Usage: "docker daemon IPv6 networking",
|
||||
EnvVar: "PLUGIN_IPV6",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "daemon.experimental",
|
||||
Usage: "docker daemon Experimental mode",
|
||||
EnvVar: "PLUGIN_EXPERIMENTAL",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "daemon.debug",
|
||||
Usage: "docker daemon executes in debug mode",
|
||||
EnvVar: "PLUGIN_DEBUG,DOCKER_LAUNCH_DEBUG",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "daemon.off",
|
||||
Usage: "don't start the docker daemon",
|
||||
EnvVar: "PLUGIN_DAEMON_OFF",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "dockerfile",
|
||||
Usage: "build dockerfile",
|
||||
Value: "Dockerfile",
|
||||
EnvVar: "PLUGIN_DOCKERFILE",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "context",
|
||||
Usage: "build context",
|
||||
Value: ".",
|
||||
EnvVar: "PLUGIN_CONTEXT",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "tags",
|
||||
Usage: "build tags",
|
||||
Value: &cli.StringSlice{"latest"},
|
||||
EnvVar: "PLUGIN_TAG,PLUGIN_TAGS",
|
||||
FilePath: ".tags",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "tags.auto",
|
||||
Usage: "default build tags",
|
||||
EnvVar: "PLUGIN_DEFAULT_TAGS,PLUGIN_AUTO_TAG",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tags.suffix",
|
||||
Usage: "default build tags with suffix",
|
||||
EnvVar: "PLUGIN_DEFAULT_SUFFIX,PLUGIN_AUTO_TAG_SUFFIX",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "args",
|
||||
Usage: "build args",
|
||||
EnvVar: "PLUGIN_BUILD_ARGS",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "args-from-env",
|
||||
Usage: "build args",
|
||||
EnvVar: "PLUGIN_BUILD_ARGS_FROM_ENV",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "quiet docker build",
|
||||
EnvVar: "PLUGIN_QUIET",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "target",
|
||||
Usage: "build target",
|
||||
EnvVar: "PLUGIN_TARGET",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "cache-from",
|
||||
Usage: "images to consider as cache sources",
|
||||
EnvVar: "PLUGIN_CACHE_FROM",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "squash",
|
||||
Usage: "squash the layers at build time",
|
||||
EnvVar: "PLUGIN_SQUASH",
|
||||
},
|
||||
cli.BoolTFlag{
|
||||
Name: "pull-image",
|
||||
Usage: "force pull base image at build time",
|
||||
EnvVar: "PLUGIN_PULL_IMAGE",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "compress",
|
||||
Usage: "compress the build context using gzip",
|
||||
EnvVar: "PLUGIN_COMPRESS",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "repo",
|
||||
Usage: "docker repository",
|
||||
EnvVar: "PLUGIN_REPO",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "docker.registry",
|
||||
Usage: "docker registry",
|
||||
Value: "https://index.docker.io/v1/",
|
||||
EnvVar: "PLUGIN_REGISTRY,DOCKER_REGISTRY",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "docker.username",
|
||||
Usage: "docker username",
|
||||
EnvVar: "PLUGIN_USERNAME,DOCKER_USERNAME",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "docker.password",
|
||||
Usage: "docker password",
|
||||
EnvVar: "PLUGIN_PASSWORD,DOCKER_PASSWORD",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "docker.email",
|
||||
Usage: "docker email",
|
||||
EnvVar: "PLUGIN_EMAIL,DOCKER_EMAIL",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "docker.config",
|
||||
Usage: "docker json dockerconfig content",
|
||||
EnvVar: "PLUGIN_CONFIG,DOCKER_PLUGIN_CONFIG",
|
||||
},
|
||||
cli.BoolTFlag{
|
||||
Name: "docker.purge",
|
||||
Usage: "docker should cleanup images",
|
||||
EnvVar: "PLUGIN_PURGE",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "repo.branch",
|
||||
Usage: "repository default branch",
|
||||
EnvVar: "DRONE_REPO_BRANCH",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-cache",
|
||||
Usage: "do not use cached intermediate containers",
|
||||
EnvVar: "PLUGIN_NO_CACHE",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "add-host",
|
||||
Usage: "additional host:IP mapping",
|
||||
EnvVar: "PLUGIN_ADD_HOST",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "platforms",
|
||||
Usage: "arget platform for build",
|
||||
EnvVar: "PLUGIN_PLATFORMS",
|
||||
},
|
||||
app := &cli.App{
|
||||
Name: "drone-docker-buildx",
|
||||
Usage: "build docker container with DinD and buildx",
|
||||
Version: version,
|
||||
Flags: append(settingsFlags(settings), urfave.Flags()...),
|
||||
Action: run(settings),
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
logrus.Fatal(err)
|
||||
errors.HandleExit(err)
|
||||
}
|
||||
}
|
||||
|
||||
func run(c *cli.Context) error {
|
||||
plugin := docker.Plugin{
|
||||
Dryrun: c.Bool("dry-run"),
|
||||
Cleanup: c.BoolT("docker.purge"),
|
||||
Login: docker.Login{
|
||||
Registry: c.String("docker.registry"),
|
||||
Username: c.String("docker.username"),
|
||||
Password: c.String("docker.password"),
|
||||
Email: c.String("docker.email"),
|
||||
Config: c.String("docker.config"),
|
||||
},
|
||||
Build: docker.Build{
|
||||
Remote: c.String("remote.url"),
|
||||
Name: c.String("commit.sha"),
|
||||
Dockerfile: c.String("dockerfile"),
|
||||
Context: c.String("context"),
|
||||
Tags: c.StringSlice("tags"),
|
||||
Platforms: c.StringSlice("platforms"),
|
||||
Args: c.StringSlice("args"),
|
||||
ArgsEnv: c.StringSlice("args-from-env"),
|
||||
Target: c.String("target"),
|
||||
Squash: c.Bool("squash"),
|
||||
Pull: c.BoolT("pull-image"),
|
||||
CacheFrom: c.StringSlice("cache-from"),
|
||||
Compress: c.Bool("compress"),
|
||||
Repo: c.String("repo"),
|
||||
NoCache: c.Bool("no-cache"),
|
||||
AddHost: c.StringSlice("add-host"),
|
||||
Quiet: c.Bool("quiet"),
|
||||
},
|
||||
Daemon: docker.Daemon{
|
||||
Registry: c.String("docker.registry"),
|
||||
Mirror: c.String("daemon.mirror"),
|
||||
StorageDriver: c.String("daemon.storage-driver"),
|
||||
StoragePath: c.String("daemon.storage-path"),
|
||||
Insecure: c.Bool("daemon.insecure"),
|
||||
Disabled: c.Bool("daemon.off"),
|
||||
IPv6: c.Bool("daemon.ipv6"),
|
||||
Debug: c.Bool("daemon.debug"),
|
||||
Bip: c.String("daemon.bip"),
|
||||
DNS: c.StringSlice("daemon.dns"),
|
||||
DNSSearch: c.StringSlice("daemon.dns-search"),
|
||||
MTU: c.String("daemon.mtu"),
|
||||
Experimental: c.Bool("daemon.experimental"),
|
||||
},
|
||||
}
|
||||
func run(settings *plugin.Settings) cli.ActionFunc {
|
||||
return func(ctx *cli.Context) error {
|
||||
urfave.LoggingFromContext(ctx)
|
||||
|
||||
if c.Bool("tags.auto") {
|
||||
if docker.UseDefaultTag( // return true if tag event or default branch
|
||||
c.String("commit.ref"),
|
||||
c.String("repo.branch"),
|
||||
) {
|
||||
tag, err := docker.DefaultTagSuffix(
|
||||
c.String("commit.ref"),
|
||||
c.String("tags.suffix"),
|
||||
plugin := plugin.New(
|
||||
*settings,
|
||||
urfave.PipelineFromContext(ctx),
|
||||
urfave.NetworkFromContext(ctx),
|
||||
)
|
||||
if err != nil {
|
||||
logrus.Printf("cannot build docker image for %s, invalid semantic version", c.String("commit.ref"))
|
||||
return err
|
||||
|
||||
if err := plugin.Validate(); err != nil {
|
||||
if e, ok := err.(errors.ExitCoder); ok {
|
||||
return e
|
||||
}
|
||||
plugin.Build.Tags = tag
|
||||
} else {
|
||||
logrus.Printf("skipping automated docker build for %s", c.String("commit.ref"))
|
||||
|
||||
return errors.ExitMessagef("validation failed: %w", err)
|
||||
}
|
||||
|
||||
if err := plugin.Execute(); err != nil {
|
||||
if e, ok := err.(errors.ExitCoder); ok {
|
||||
return e
|
||||
}
|
||||
|
||||
return errors.ExitMessagef("execution failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return plugin.Exec()
|
||||
}
|
||||
|
392
docker.go
392
docker.go
@ -1,392 +0,0 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
// Daemon defines Docker daemon parameters.
|
||||
Daemon struct {
|
||||
Registry string // Docker registry
|
||||
Mirror string // Docker registry mirror
|
||||
Insecure bool // Docker daemon enable insecure registries
|
||||
StorageDriver string // Docker daemon storage driver
|
||||
StoragePath string // Docker daemon storage path
|
||||
Disabled bool // DOcker daemon is disabled (already running)
|
||||
Debug bool // Docker daemon started in debug mode
|
||||
Bip string // Docker daemon network bridge IP address
|
||||
DNS []string // Docker daemon dns server
|
||||
DNSSearch []string // Docker daemon dns search domain
|
||||
MTU string // Docker daemon mtu setting
|
||||
IPv6 bool // Docker daemon IPv6 networking
|
||||
Experimental bool // Docker daemon enable experimental mode
|
||||
}
|
||||
|
||||
// Login defines Docker login parameters.
|
||||
Login struct {
|
||||
Registry string // Docker registry address
|
||||
Username string // Docker registry username
|
||||
Password string // Docker registry password
|
||||
Email string // Docker registry email
|
||||
Config string // Docker Auth Config
|
||||
}
|
||||
|
||||
// Build defines Docker build parameters.
|
||||
Build struct {
|
||||
Remote string // Git remote URL
|
||||
Name string // Docker build using default named tag
|
||||
Dockerfile string // Docker build Dockerfile
|
||||
Context string // Docker build context
|
||||
Tags []string // Docker build tags
|
||||
Platforms []string // Docker build target platforms
|
||||
Args []string // Docker build args
|
||||
ArgsEnv []string // Docker build args from env
|
||||
Target string // Docker build target
|
||||
Squash bool // Docker build squash
|
||||
Pull bool // Docker build pull
|
||||
CacheFrom []string // Docker build cache-from
|
||||
Compress bool // Docker build compress
|
||||
Repo string // Docker build repository
|
||||
NoCache bool // Docker build no-cache
|
||||
AddHost []string // Docker build add-host
|
||||
Quiet bool // Docker build quiet
|
||||
}
|
||||
|
||||
// Plugin defines the Docker plugin parameters.
|
||||
Plugin struct {
|
||||
Login Login // Docker login configuration
|
||||
Build Build // Docker build configuration
|
||||
Daemon Daemon // Docker daemon configuration
|
||||
Dryrun bool // Docker push is skipped
|
||||
Cleanup bool // Docker purge is enabled
|
||||
}
|
||||
)
|
||||
|
||||
// Exec executes the plugin step
|
||||
func (p Plugin) Exec() error {
|
||||
// start the Docker daemon server
|
||||
if !p.Daemon.Disabled {
|
||||
p.startDaemon()
|
||||
}
|
||||
|
||||
// poll the docker daemon until it is started. This ensures the daemon is
|
||||
// ready to accept connections before we proceed.
|
||||
for i := 0; i < 15; i++ {
|
||||
cmd := commandInfo()
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 1)
|
||||
}
|
||||
|
||||
// Create Auth Config File
|
||||
if p.Login.Config != "" {
|
||||
os.MkdirAll(dockerHome, 0600)
|
||||
|
||||
path := filepath.Join(dockerHome, "config.json")
|
||||
err := ioutil.WriteFile(path, []byte(p.Login.Config), 0600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing config.json: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// login to the Docker registry
|
||||
if p.Login.Password != "" {
|
||||
cmd := commandLogin(p.Login)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error authenticating: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case p.Login.Password != "":
|
||||
fmt.Println("Detected registry credentials")
|
||||
case p.Login.Config != "":
|
||||
fmt.Println("Detected registry credentials file")
|
||||
default:
|
||||
fmt.Println("Registry credentials or Docker config not provided. Guest mode enabled.")
|
||||
}
|
||||
|
||||
if p.Build.Squash && !p.Daemon.Experimental {
|
||||
fmt.Println("Squash build flag is only available when Docker deamon is started with experimental flag. Ignoring...")
|
||||
p.Build.Squash = false
|
||||
}
|
||||
|
||||
// add proxy build args
|
||||
addProxyBuildArgs(&p.Build)
|
||||
|
||||
var cmds []*exec.Cmd
|
||||
cmds = append(cmds, commandVersion()) // docker version
|
||||
cmds = append(cmds, commandInfo()) // docker info
|
||||
cmds = append(cmds, commandBuilder())
|
||||
cmds = append(cmds, commandBuildx())
|
||||
|
||||
// pre-pull cache images
|
||||
for _, img := range p.Build.CacheFrom {
|
||||
cmds = append(cmds, commandPull(img))
|
||||
}
|
||||
|
||||
cmds = append(cmds, commandBuild(p.Build)) // docker build
|
||||
|
||||
for _, tag := range p.Build.Tags {
|
||||
cmds = append(cmds, commandTag(p.Build, tag)) // docker tag
|
||||
|
||||
if !p.Dryrun {
|
||||
cmds = append(cmds, commandPush(p.Build, tag)) // docker push
|
||||
}
|
||||
}
|
||||
|
||||
if p.Cleanup {
|
||||
cmds = append(cmds, commandRmi(p.Build.Name)) // docker rmi
|
||||
cmds = append(cmds, commandPrune()) // docker system prune -f
|
||||
}
|
||||
|
||||
// execute all commands in batch mode.
|
||||
for _, cmd := range cmds {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
trace(cmd)
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil && isCommandPull(cmd.Args) {
|
||||
fmt.Printf("Could not pull cache-from image %s. Ignoring...\n", cmd.Args[2])
|
||||
} else if err != nil && isCommandPrune(cmd.Args) {
|
||||
fmt.Printf("Could not prune system containers. Ignoring...\n")
|
||||
} else if err != nil && isCommandRmi(cmd.Args) {
|
||||
fmt.Printf("Could not remove image %s. Ignoring...\n", cmd.Args[2])
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// helper function to create the docker login command.
|
||||
func commandLogin(login Login) *exec.Cmd {
|
||||
if login.Email != "" {
|
||||
return commandLoginEmail(login)
|
||||
}
|
||||
return exec.Command(
|
||||
dockerExe, "login",
|
||||
"-u", login.Username,
|
||||
"-p", login.Password,
|
||||
login.Registry,
|
||||
)
|
||||
}
|
||||
|
||||
// helper to check if args match "docker pull <image>"
|
||||
func isCommandPull(args []string) bool {
|
||||
return len(args) > 2 && args[1] == "pull"
|
||||
}
|
||||
|
||||
func commandPull(repo string) *exec.Cmd {
|
||||
return exec.Command(dockerExe, "pull", repo)
|
||||
}
|
||||
|
||||
func commandLoginEmail(login Login) *exec.Cmd {
|
||||
return exec.Command(
|
||||
dockerExe, "login",
|
||||
"-u", login.Username,
|
||||
"-p", login.Password,
|
||||
"-e", login.Email,
|
||||
login.Registry,
|
||||
)
|
||||
}
|
||||
|
||||
// helper function to create the docker info command.
|
||||
func commandVersion() *exec.Cmd {
|
||||
return exec.Command(dockerExe, "version")
|
||||
}
|
||||
|
||||
// helper function to create the docker info command.
|
||||
func commandInfo() *exec.Cmd {
|
||||
return exec.Command(dockerExe, "info")
|
||||
}
|
||||
|
||||
func commandBuilder() *exec.Cmd {
|
||||
return exec.Command(dockerExe, "buildx", "create", "--use")
|
||||
}
|
||||
|
||||
func commandBuildx() *exec.Cmd {
|
||||
return exec.Command(dockerExe, "buildx", "ls")
|
||||
}
|
||||
|
||||
// helper function to create the docker build command.
|
||||
func commandBuild(build Build) *exec.Cmd {
|
||||
args := []string{
|
||||
"buildx",
|
||||
"build",
|
||||
"--load",
|
||||
"--rm=true",
|
||||
"-f", build.Dockerfile,
|
||||
"-t", build.Name,
|
||||
}
|
||||
|
||||
args = append(args, build.Context)
|
||||
if build.Squash {
|
||||
args = append(args, "--squash")
|
||||
}
|
||||
if build.Compress {
|
||||
args = append(args, "--compress")
|
||||
}
|
||||
if build.Pull {
|
||||
args = append(args, "--pull=true")
|
||||
}
|
||||
if build.NoCache {
|
||||
args = append(args, "--no-cache")
|
||||
}
|
||||
for _, arg := range build.CacheFrom {
|
||||
args = append(args, "--cache-from", arg)
|
||||
}
|
||||
for _, arg := range build.ArgsEnv {
|
||||
addProxyValue(&build, arg)
|
||||
}
|
||||
for _, arg := range build.Args {
|
||||
args = append(args, "--build-arg", arg)
|
||||
}
|
||||
for _, host := range build.AddHost {
|
||||
args = append(args, "--add-host", host)
|
||||
}
|
||||
if build.Target != "" {
|
||||
args = append(args, "--target", build.Target)
|
||||
}
|
||||
if build.Quiet {
|
||||
args = append(args, "--quiet")
|
||||
}
|
||||
|
||||
if len(build.Platforms) > 0 {
|
||||
args = append(args, "--platform", strings.Join(build.Platforms[:], ","))
|
||||
}
|
||||
|
||||
return exec.Command(dockerExe, args...)
|
||||
}
|
||||
|
||||
// helper function to add proxy values from the environment
|
||||
func addProxyBuildArgs(build *Build) {
|
||||
addProxyValue(build, "http_proxy")
|
||||
addProxyValue(build, "https_proxy")
|
||||
addProxyValue(build, "no_proxy")
|
||||
}
|
||||
|
||||
// helper function to add the upper and lower case version of a proxy value.
|
||||
func addProxyValue(build *Build, key string) {
|
||||
value := getProxyValue(key)
|
||||
|
||||
if len(value) > 0 && !hasProxyBuildArg(build, key) {
|
||||
build.Args = append(build.Args, fmt.Sprintf("%s=%s", key, value))
|
||||
build.Args = append(build.Args, fmt.Sprintf("%s=%s", strings.ToUpper(key), value))
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to get a proxy value from the environment.
|
||||
//
|
||||
// assumes that the upper and lower case versions of are the same.
|
||||
func getProxyValue(key string) string {
|
||||
value := os.Getenv(key)
|
||||
|
||||
if len(value) > 0 {
|
||||
return value
|
||||
}
|
||||
|
||||
return os.Getenv(strings.ToUpper(key))
|
||||
}
|
||||
|
||||
// helper function that looks to see if a proxy value was set in the build args.
|
||||
func hasProxyBuildArg(build *Build, key string) bool {
|
||||
keyUpper := strings.ToUpper(key)
|
||||
|
||||
for _, s := range build.Args {
|
||||
if strings.HasPrefix(s, key) || strings.HasPrefix(s, keyUpper) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// helper function to create the docker tag command.
|
||||
func commandTag(build Build, tag string) *exec.Cmd {
|
||||
var (
|
||||
source = build.Name
|
||||
target = fmt.Sprintf("%s:%s", build.Repo, tag)
|
||||
)
|
||||
return exec.Command(
|
||||
dockerExe, "tag", source, target,
|
||||
)
|
||||
}
|
||||
|
||||
// helper function to create the docker push command.
|
||||
func commandPush(build Build, tag string) *exec.Cmd {
|
||||
target := fmt.Sprintf("%s:%s", build.Repo, tag)
|
||||
return exec.Command(dockerExe, "push", target)
|
||||
}
|
||||
|
||||
// helper function to create the docker daemon command.
|
||||
func commandDaemon(daemon Daemon) *exec.Cmd {
|
||||
args := []string{
|
||||
"--data-root", daemon.StoragePath,
|
||||
"--host=unix:///var/run/docker.sock",
|
||||
}
|
||||
|
||||
if daemon.StorageDriver != "" {
|
||||
args = append(args, "-s", daemon.StorageDriver)
|
||||
}
|
||||
if daemon.Insecure && daemon.Registry != "" {
|
||||
args = append(args, "--insecure-registry", daemon.Registry)
|
||||
}
|
||||
if daemon.IPv6 {
|
||||
args = append(args, "--ipv6")
|
||||
}
|
||||
if len(daemon.Mirror) != 0 {
|
||||
args = append(args, "--registry-mirror", daemon.Mirror)
|
||||
}
|
||||
if len(daemon.Bip) != 0 {
|
||||
args = append(args, "--bip", daemon.Bip)
|
||||
}
|
||||
for _, dns := range daemon.DNS {
|
||||
args = append(args, "--dns", dns)
|
||||
}
|
||||
for _, dnsSearch := range daemon.DNSSearch {
|
||||
args = append(args, "--dns-search", dnsSearch)
|
||||
}
|
||||
if len(daemon.MTU) != 0 {
|
||||
args = append(args, "--mtu", daemon.MTU)
|
||||
}
|
||||
if daemon.Experimental {
|
||||
args = append(args, "--experimental")
|
||||
}
|
||||
return exec.Command(dockerdExe, args...)
|
||||
}
|
||||
|
||||
// helper to check if args match "docker prune"
|
||||
func isCommandPrune(args []string) bool {
|
||||
return len(args) > 3 && args[2] == "prune"
|
||||
}
|
||||
|
||||
func commandPrune() *exec.Cmd {
|
||||
return exec.Command(dockerExe, "system", "prune", "-f")
|
||||
}
|
||||
|
||||
// helper to check if args match "docker rmi"
|
||||
func isCommandRmi(args []string) bool {
|
||||
return len(args) > 2 && args[1] == "rmi"
|
||||
}
|
||||
|
||||
func commandRmi(tag string) *exec.Cmd {
|
||||
return exec.Command(dockerExe, "rmi", tag)
|
||||
}
|
||||
|
||||
// trace writes each command to stdout with the command wrapped in an xml
|
||||
// tag so that it can be extracted and displayed in the logs.
|
||||
func trace(cmd *exec.Cmd) {
|
||||
fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
|
||||
}
|
@ -1 +0,0 @@
|
||||
package docker
|
5
go.mod
5
go.mod
@ -1,12 +1,13 @@
|
||||
module github.com/drone-plugins/drone-docker
|
||||
module github.com/thegeeklab/drone-docker-buildx
|
||||
|
||||
require (
|
||||
github.com/coreos/go-semver v0.3.0
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/drone-plugins/drone-plugin-lib v0.4.0
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.7.0
|
||||
github.com/urfave/cli v1.22.5
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061 // indirect
|
||||
)
|
||||
|
||||
|
22
go.sum
22
go.sum
@ -7,8 +7,13 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/drone-plugins/drone-plugin-lib v0.4.0 h1:qywEYGhquUuid6zNLmKia8CWY1TUa8jPQQ/G9ozfAmc=
|
||||
github.com/drone-plugins/drone-plugin-lib v0.4.0/go.mod h1:EgqogX38GoJFtckeSQyhBJYX8P+KWBPhdprAVvyRxF8=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
@ -17,16 +22,29 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061 h1:DQmQoKxQWtyybCtX/3dIuDBcAhFszqq8YiNeS6sNu1c=
|
||||
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
|
@ -1,6 +1,4 @@
|
||||
// +build !windows
|
||||
|
||||
package docker
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
@ -12,8 +10,8 @@ const dockerdExe = "/usr/local/bin/dockerd"
|
||||
const dockerHome = "/root/.docker/"
|
||||
|
||||
func (p Plugin) startDaemon() {
|
||||
cmd := commandDaemon(p.Daemon)
|
||||
if p.Daemon.Debug {
|
||||
cmd := commandDaemon(p.settings.Daemon)
|
||||
if p.settings.Daemon.Debug {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
} else {
|
233
plugin/docker.go
Normal file
233
plugin/docker.go
Normal file
@ -0,0 +1,233 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// helper function to create the docker login command.
|
||||
func commandLogin(login Login) *exec.Cmd {
|
||||
if login.Email != "" {
|
||||
return commandLoginEmail(login)
|
||||
}
|
||||
return exec.Command(
|
||||
dockerExe, "login",
|
||||
"-u", login.Username,
|
||||
"-p", login.Password,
|
||||
login.Registry,
|
||||
)
|
||||
}
|
||||
|
||||
// helper to check if args match "docker pull <image>"
|
||||
func isCommandPull(args []string) bool {
|
||||
return len(args) > 2 && args[1] == "pull"
|
||||
}
|
||||
|
||||
func commandPull(repo string) *exec.Cmd {
|
||||
return exec.Command(dockerExe, "pull", repo)
|
||||
}
|
||||
|
||||
func commandLoginEmail(login Login) *exec.Cmd {
|
||||
return exec.Command(
|
||||
dockerExe, "login",
|
||||
"-u", login.Username,
|
||||
"-p", login.Password,
|
||||
"-e", login.Email,
|
||||
login.Registry,
|
||||
)
|
||||
}
|
||||
|
||||
// helper function to create the docker info command.
|
||||
func commandVersion() *exec.Cmd {
|
||||
return exec.Command(dockerExe, "version")
|
||||
}
|
||||
|
||||
// helper function to create the docker info command.
|
||||
func commandInfo() *exec.Cmd {
|
||||
return exec.Command(dockerExe, "info")
|
||||
}
|
||||
|
||||
func commandBuilder() *exec.Cmd {
|
||||
return exec.Command(dockerExe, "buildx", "create", "--use")
|
||||
}
|
||||
|
||||
func commandBuildx() *exec.Cmd {
|
||||
return exec.Command(dockerExe, "buildx", "ls")
|
||||
}
|
||||
|
||||
// helper function to create the docker build command.
|
||||
func commandBuild(build Build) *exec.Cmd {
|
||||
args := []string{
|
||||
"buildx",
|
||||
"build",
|
||||
"--load",
|
||||
"--rm=true",
|
||||
"-f", build.Dockerfile,
|
||||
"-t", build.Name,
|
||||
}
|
||||
|
||||
args = append(args, build.Context)
|
||||
if build.Squash {
|
||||
args = append(args, "--squash")
|
||||
}
|
||||
if build.Compress {
|
||||
args = append(args, "--compress")
|
||||
}
|
||||
if build.Pull {
|
||||
args = append(args, "--pull=true")
|
||||
}
|
||||
if build.NoCache {
|
||||
args = append(args, "--no-cache")
|
||||
}
|
||||
for _, arg := range build.CacheFrom.Value() {
|
||||
args = append(args, "--cache-from", arg)
|
||||
}
|
||||
for _, arg := range build.ArgsEnv.Value() {
|
||||
addProxyValue(&build, arg)
|
||||
}
|
||||
for _, arg := range build.Args.Value() {
|
||||
args = append(args, "--build-arg", arg)
|
||||
}
|
||||
for _, host := range build.AddHost.Value() {
|
||||
args = append(args, "--add-host", host)
|
||||
}
|
||||
if build.Target != "" {
|
||||
args = append(args, "--target", build.Target)
|
||||
}
|
||||
if build.Quiet {
|
||||
args = append(args, "--quiet")
|
||||
}
|
||||
|
||||
if len(build.Platforms.Value()) > 0 {
|
||||
args = append(args, "--platform", strings.Join(build.Platforms.Value()[:], ","))
|
||||
}
|
||||
|
||||
return exec.Command(dockerExe, args...)
|
||||
}
|
||||
|
||||
// helper function to add proxy values from the environment
|
||||
func addProxyBuildArgs(build *Build) {
|
||||
addProxyValue(build, "http_proxy")
|
||||
addProxyValue(build, "https_proxy")
|
||||
addProxyValue(build, "no_proxy")
|
||||
}
|
||||
|
||||
// helper function to add the upper and lower case version of a proxy value.
|
||||
func addProxyValue(build *Build, key string) {
|
||||
value := getProxyValue(key)
|
||||
|
||||
if len(value) > 0 && !hasProxyBuildArg(build, key) {
|
||||
args := build.Args.Value()
|
||||
args = append(build.Args.Value(), fmt.Sprintf("%s=%s", key, value))
|
||||
args = append(build.Args.Value(), fmt.Sprintf("%s=%s", strings.ToUpper(key), value))
|
||||
build.Args = *cli.NewStringSlice(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to get a proxy value from the environment.
|
||||
//
|
||||
// assumes that the upper and lower case versions of are the same.
|
||||
func getProxyValue(key string) string {
|
||||
value := os.Getenv(key)
|
||||
|
||||
if len(value) > 0 {
|
||||
return value
|
||||
}
|
||||
|
||||
return os.Getenv(strings.ToUpper(key))
|
||||
}
|
||||
|
||||
// helper function that looks to see if a proxy value was set in the build args.
|
||||
func hasProxyBuildArg(build *Build, key string) bool {
|
||||
keyUpper := strings.ToUpper(key)
|
||||
|
||||
for _, s := range build.Args.Value() {
|
||||
if strings.HasPrefix(s, key) || strings.HasPrefix(s, keyUpper) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// helper function to create the docker tag command.
|
||||
func commandTag(build Build, tag string) *exec.Cmd {
|
||||
var (
|
||||
source = build.Name
|
||||
target = fmt.Sprintf("%s:%s", build.Repo, tag)
|
||||
)
|
||||
return exec.Command(
|
||||
dockerExe, "tag", source, target,
|
||||
)
|
||||
}
|
||||
|
||||
// helper function to create the docker push command.
|
||||
func commandPush(build Build, tag string) *exec.Cmd {
|
||||
target := fmt.Sprintf("%s:%s", build.Repo, tag)
|
||||
return exec.Command(dockerExe, "push", target)
|
||||
}
|
||||
|
||||
// helper function to create the docker daemon command.
|
||||
func commandDaemon(daemon Daemon) *exec.Cmd {
|
||||
args := []string{
|
||||
"--data-root", daemon.StoragePath,
|
||||
"--host=unix:///var/run/docker.sock",
|
||||
}
|
||||
|
||||
if daemon.StorageDriver != "" {
|
||||
args = append(args, "-s", daemon.StorageDriver)
|
||||
}
|
||||
if daemon.Insecure && daemon.Registry != "" {
|
||||
args = append(args, "--insecure-registry", daemon.Registry)
|
||||
}
|
||||
if daemon.IPv6 {
|
||||
args = append(args, "--ipv6")
|
||||
}
|
||||
if len(daemon.Mirror) != 0 {
|
||||
args = append(args, "--registry-mirror", daemon.Mirror)
|
||||
}
|
||||
if len(daemon.Bip) != 0 {
|
||||
args = append(args, "--bip", daemon.Bip)
|
||||
}
|
||||
for _, dns := range daemon.DNS.Value() {
|
||||
args = append(args, "--dns", dns)
|
||||
}
|
||||
for _, dnsSearch := range daemon.DNSSearch.Value() {
|
||||
args = append(args, "--dns-search", dnsSearch)
|
||||
}
|
||||
if len(daemon.MTU) != 0 {
|
||||
args = append(args, "--mtu", daemon.MTU)
|
||||
}
|
||||
if daemon.Experimental {
|
||||
args = append(args, "--experimental")
|
||||
}
|
||||
return exec.Command(dockerdExe, args...)
|
||||
}
|
||||
|
||||
// helper to check if args match "docker prune"
|
||||
func isCommandPrune(args []string) bool {
|
||||
return len(args) > 3 && args[2] == "prune"
|
||||
}
|
||||
|
||||
func commandPrune() *exec.Cmd {
|
||||
return exec.Command(dockerExe, "system", "prune", "-f")
|
||||
}
|
||||
|
||||
// helper to check if args match "docker rmi"
|
||||
func isCommandRmi(args []string) bool {
|
||||
return len(args) > 2 && args[1] == "rmi"
|
||||
}
|
||||
|
||||
func commandRmi(tag string) *exec.Cmd {
|
||||
return exec.Command(dockerExe, "rmi", tag)
|
||||
}
|
||||
|
||||
// trace writes each command to stdout with the command wrapped in an xml
|
||||
// tag so that it can be extracted and displayed in the logs.
|
||||
func trace(cmd *exec.Cmd) {
|
||||
fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
|
||||
}
|
1
plugin/docker_test.go
Normal file
1
plugin/docker_test.go
Normal file
@ -0,0 +1 @@
|
||||
package plugin
|
203
plugin/impl.go
Normal file
203
plugin/impl.go
Normal file
@ -0,0 +1,203 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Daemon defines Docker daemon parameters.
|
||||
type Daemon struct {
|
||||
Registry string // Docker registry
|
||||
Mirror string // Docker registry mirror
|
||||
Insecure bool // Docker daemon enable insecure registries
|
||||
StorageDriver string // Docker daemon storage driver
|
||||
StoragePath string // Docker daemon storage path
|
||||
Disabled bool // DOcker daemon is disabled (already running)
|
||||
Debug bool // Docker daemon started in debug mode
|
||||
Bip string // Docker daemon network bridge IP address
|
||||
DNS cli.StringSlice // Docker daemon dns server
|
||||
DNSSearch cli.StringSlice // Docker daemon dns search domain
|
||||
MTU string // Docker daemon mtu setting
|
||||
IPv6 bool // Docker daemon IPv6 networking
|
||||
Experimental bool // Docker daemon enable experimental mode
|
||||
}
|
||||
|
||||
// Login defines Docker login parameters.
|
||||
type Login struct {
|
||||
Registry string // Docker registry address
|
||||
Username string // Docker registry username
|
||||
Password string // Docker registry password
|
||||
Email string // Docker registry email
|
||||
Config string // Docker Auth Config
|
||||
}
|
||||
|
||||
// Build defines Docker build parameters.
|
||||
type Build struct {
|
||||
Remote string // Git remote URL
|
||||
Name string // Git commit sha used as docker default named tag
|
||||
Ref string // Git commit ref
|
||||
Branch string // Git repository branch
|
||||
Dockerfile string // Docker build Dockerfile
|
||||
Context string // Docker build context
|
||||
TagsAuto bool // Docker build auto tag
|
||||
TagsSuffix string // Docker build tags with suffix
|
||||
Tags cli.StringSlice // Docker build tags
|
||||
Platforms cli.StringSlice // Docker build target platforms
|
||||
Args cli.StringSlice // Docker build args
|
||||
ArgsEnv cli.StringSlice // Docker build args from env
|
||||
Target string // Docker build target
|
||||
Squash bool // Docker build squash
|
||||
Pull bool // Docker build pull
|
||||
CacheFrom cli.StringSlice // Docker build cache-from
|
||||
Compress bool // Docker build compress
|
||||
Repo string // Docker build repository
|
||||
NoCache bool // Docker build no-cache
|
||||
AddHost cli.StringSlice // Docker build add-host
|
||||
Quiet bool // Docker build quiet
|
||||
}
|
||||
|
||||
// Settings for the Plugin.
|
||||
type Settings struct {
|
||||
Daemon Daemon
|
||||
Login Login
|
||||
Build Build
|
||||
Dryrun bool
|
||||
Cleanup bool
|
||||
}
|
||||
|
||||
// Validate handles the settings validation of the plugin.
|
||||
func (p *Plugin) Validate() error {
|
||||
p.settings.Daemon.Registry = p.settings.Login.Registry
|
||||
|
||||
if p.settings.Build.TagsAuto {
|
||||
// return true if tag event or default branch
|
||||
if UseDefaultTag(
|
||||
p.settings.Build.Ref,
|
||||
p.settings.Build.Branch,
|
||||
) {
|
||||
tag, err := DefaultTagSuffix(
|
||||
p.settings.Build.Ref,
|
||||
p.settings.Build.TagsSuffix,
|
||||
)
|
||||
if err != nil {
|
||||
logrus.Printf("cannot build docker image for %s, invalid semantic version", p.settings.Build.Ref)
|
||||
return err
|
||||
}
|
||||
p.settings.Build.Tags = *cli.NewStringSlice(tag...)
|
||||
} else {
|
||||
logrus.Printf("skipping automated docker build for %s", p.settings.Build.Ref)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Execute provides the implementation of the plugin.
|
||||
func (p *Plugin) Execute() error {
|
||||
// start the Docker daemon server
|
||||
if !p.settings.Daemon.Disabled {
|
||||
p.startDaemon()
|
||||
}
|
||||
|
||||
// poll the docker daemon until it is started. This ensures the daemon is
|
||||
// ready to accept connections before we proceed.
|
||||
for i := 0; i < 15; i++ {
|
||||
cmd := commandInfo()
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 1)
|
||||
}
|
||||
|
||||
// Create Auth Config File
|
||||
if p.settings.Login.Config != "" {
|
||||
os.MkdirAll(dockerHome, 0600)
|
||||
|
||||
path := filepath.Join(dockerHome, "config.json")
|
||||
err := ioutil.WriteFile(path, []byte(p.settings.Login.Config), 0600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing config.json: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// login to the Docker registry
|
||||
if p.settings.Login.Password != "" {
|
||||
cmd := commandLogin(p.settings.Login)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error authenticating: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case p.settings.Login.Password != "":
|
||||
fmt.Println("Detected registry credentials")
|
||||
case p.settings.Login.Config != "":
|
||||
fmt.Println("Detected registry credentials file")
|
||||
default:
|
||||
fmt.Println("Registry credentials or Docker config not provided. Guest mode enabled.")
|
||||
}
|
||||
|
||||
if p.settings.Build.Squash && !p.settings.Daemon.Experimental {
|
||||
fmt.Println("Squash build flag is only available when Docker deamon is started with experimental flag. Ignoring...")
|
||||
p.settings.Build.Squash = false
|
||||
}
|
||||
|
||||
// add proxy build args
|
||||
addProxyBuildArgs(&p.settings.Build)
|
||||
|
||||
var cmds []*exec.Cmd
|
||||
cmds = append(cmds, commandVersion()) // docker version
|
||||
cmds = append(cmds, commandInfo()) // docker info
|
||||
cmds = append(cmds, commandBuilder())
|
||||
cmds = append(cmds, commandBuildx())
|
||||
|
||||
// pre-pull cache images
|
||||
for _, img := range p.settings.Build.CacheFrom.Value() {
|
||||
cmds = append(cmds, commandPull(img))
|
||||
}
|
||||
|
||||
cmds = append(cmds, commandBuild(p.settings.Build)) // docker build
|
||||
|
||||
for _, tag := range p.settings.Build.Tags.Value() {
|
||||
cmds = append(cmds, commandTag(p.settings.Build, tag)) // docker tag
|
||||
|
||||
if !p.settings.Dryrun {
|
||||
cmds = append(cmds, commandPush(p.settings.Build, tag)) // docker push
|
||||
}
|
||||
}
|
||||
|
||||
if p.settings.Cleanup {
|
||||
cmds = append(cmds, commandRmi(p.settings.Build.Name)) // docker rmi
|
||||
cmds = append(cmds, commandPrune()) // docker system prune -f
|
||||
}
|
||||
|
||||
// execute all commands in batch mode.
|
||||
for _, cmd := range cmds {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
trace(cmd)
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil && isCommandPull(cmd.Args) {
|
||||
fmt.Printf("Could not pull cache-from image %s. Ignoring...\n", cmd.Args[2])
|
||||
} else if err != nil && isCommandPrune(cmd.Args) {
|
||||
fmt.Printf("Could not prune system containers. Ignoring...\n")
|
||||
} else if err != nil && isCommandRmi(cmd.Args) {
|
||||
fmt.Printf("Could not remove image %s. Ignoring...\n", cmd.Args[2])
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
21
plugin/plugin.go
Normal file
21
plugin/plugin.go
Normal file
@ -0,0 +1,21 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"github.com/drone-plugins/drone-plugin-lib/drone"
|
||||
)
|
||||
|
||||
// Plugin implements drone.Plugin to provide the plugin implementation.
|
||||
type Plugin struct {
|
||||
settings Settings
|
||||
pipeline drone.Pipeline
|
||||
network drone.Network
|
||||
}
|
||||
|
||||
// New initializes a plugin from the given Settings, Pipeline, and Network.
|
||||
func New(settings Settings, pipeline drone.Pipeline, network drone.Network) drone.Plugin {
|
||||
return &Plugin{
|
||||
settings: settings,
|
||||
pipeline: pipeline,
|
||||
network: network,
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package docker
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
@ -1,4 +1,4 @@
|
||||
package docker
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"reflect"
|
Loading…
Reference in New Issue
Block a user