9 Commits

Author SHA1 Message Date
TP Honey
7f2f86cea8 Merge pull request #363 from tphoney/prepv20.12.0
prep for v20.12.0
2022-05-16 10:03:38 +01:00
TP Honey
726b758d78 prep for v20.12.0 2022-05-12 14:29:30 +01:00
Stefano Arlandini
94f2f970db Add support for multiple Buildkit secrets with env vars or files as source (#359) 2022-05-03 10:22:55 +01:00
TP Honey
d0b9da388f Merge pull request #358 from tphoney/DRON-237
(DRON-237) cards add link to image repo, minor cleanup
2022-02-23 14:17:03 +00:00
TP Honey
332b73d3b0 (DRON-237) cards add link to image repo, minor cleanup 2022-02-23 12:28:40 +00:00
TP Honey
b6c9110c83 Merge pull request #356 from tphoney/DRON-232
(DRON-232) enable build-kit for secrets consumption
2022-02-16 12:49:48 +00:00
TP Honey
05357ea390 (DRON-232) enable build-kit for secrets consumption 2022-02-16 11:22:07 +00:00
TP Honey
ad28b4d0f6 (maint) add sample_data.json for adaptive cards 2022-01-19 16:15:08 +00:00
TP Honey
96ee8a4ebf (fix) Update card.json with UX (#355)
* Update card.json
2022-01-19 16:06:21 +00:00
9 changed files with 427 additions and 124 deletions

View File

@@ -1,11 +1,26 @@
# Changelog # Changelog
## [v20.12.0](https://github.com/drone-plugins/drone-docker/tree/v20.12.0) (2022-05-12)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.11.0...v20.12.0)
**Implemented enhancements:**
- Add support for multiple Buildkit secrets with env vars or files as source [\#359](https://github.com/drone-plugins/drone-docker/pull/359) ([ste93cry](https://github.com/ste93cry))
- \(DRON-237\) cards add link to image repo, minor cleanup [\#358](https://github.com/drone-plugins/drone-docker/pull/358) ([tphoney](https://github.com/tphoney))
- \(DRON-232\) enable build-kit for secrets consumption [\#356](https://github.com/drone-plugins/drone-docker/pull/356) ([tphoney](https://github.com/tphoney))
**Fixed bugs:**
- \(fix\) Update card.json with UX [\#355](https://github.com/drone-plugins/drone-docker/pull/355) ([tphoney](https://github.com/tphoney))
## [v20.11.0](https://github.com/drone-plugins/drone-docker/tree/v20.11.0) (2022-01-19) ## [v20.11.0](https://github.com/drone-plugins/drone-docker/tree/v20.11.0) (2022-01-19)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.10.9.1...v20.11.0) [Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.10.9.1...v20.11.0)
**Merged pull requests:** **Merged pull requests:**
- new release to fix window semver error [\#354](https://github.com/drone-plugins/drone-docker/pull/354) ([eoinmcafee00](https://github.com/eoinmcafee00))
- \(feat\) publish docker data to create drone card [\#347](https://github.com/drone-plugins/drone-docker/pull/347) ([eoinmcafee00](https://github.com/eoinmcafee00)) - \(feat\) publish docker data to create drone card [\#347](https://github.com/drone-plugins/drone-docker/pull/347) ([eoinmcafee00](https://github.com/eoinmcafee00))
## [v20.10.9.1](https://github.com/drone-plugins/drone-docker/tree/v20.10.9.1) (2022-01-13) ## [v20.10.9.1](https://github.com/drone-plugins/drone-docker/tree/v20.10.9.1) (2022-01-13)

27
card.go
View File

@@ -8,6 +8,8 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path"
"strings"
"time" "time"
"github.com/drone/drone-go/drone" "github.com/drone/drone-go/drone"
@@ -22,7 +24,7 @@ func (p Plugin) writeCard() error {
return err return err
} }
out := Inspect{} out := Card{}
if err := json.Unmarshal(data, &out); err != nil { if err := json.Unmarshal(data, &out); err != nil {
return err return err
} }
@@ -31,6 +33,14 @@ func (p Plugin) writeCard() error {
inspect.SizeString = fmt.Sprint(bytesize.New(float64(inspect.Size))) inspect.SizeString = fmt.Sprint(bytesize.New(float64(inspect.Size)))
inspect.VirtualSizeString = fmt.Sprint(bytesize.New(float64(inspect.VirtualSize))) inspect.VirtualSizeString = fmt.Sprint(bytesize.New(float64(inspect.VirtualSize)))
inspect.Time = fmt.Sprint(inspect.Metadata.LastTagTime.Format(time.RFC3339)) inspect.Time = fmt.Sprint(inspect.Metadata.LastTagTime.Format(time.RFC3339))
// change slice of tags to slice of TagStruct
var sliceTagStruct []TagStruct
for _, tag := range inspect.RepoTags {
sliceTagStruct = append(sliceTagStruct, TagStruct{Tag: tag})
}
inspect.ParsedRepoTags = sliceTagStruct[1:] // remove the first tag which is always "hash:latest"
// create the url from repo and registry
inspect.URL = mapRegistryToURL(p.Daemon.Registry, p.Build.Repo)
cardData, _ := json.Marshal(inspect) cardData, _ := json.Marshal(inspect)
card := drone.CardInput{ card := drone.CardInput{
@@ -61,3 +71,18 @@ func writeCardTo(out io.Writer, data []byte) {
io.WriteString(out, "\u001B]0m") io.WriteString(out, "\u001B]0m")
io.WriteString(out, "\n") io.WriteString(out, "\n")
} }
func mapRegistryToURL(registry, repo string) (url string) {
url = "https://"
var domain string
if strings.Contains(registry, "amazonaws.com") {
domain = "gallery.ecr.aws/"
} else if strings.Contains(registry, "gcr.io") {
domain = "console.cloud.google.com/gcr/images"
} else {
// default to docker hub
domain = "hub.docker.com/r/"
}
url = path.Join(url, domain, repo)
return url
}

View File

@@ -249,6 +249,21 @@ func main() {
Usage: "additional host:IP mapping", Usage: "additional host:IP mapping",
EnvVar: "PLUGIN_ADD_HOST", EnvVar: "PLUGIN_ADD_HOST",
}, },
cli.StringFlag{
Name: "secret",
Usage: "secret key value pair eg id=MYSECRET",
EnvVar: "PLUGIN_SECRET",
},
cli.StringSliceFlag{
Name: "secrets-from-env",
Usage: "secret key value pair eg secret_name=secret",
EnvVar: "PLUGIN_SECRETS_FROM_ENV",
},
cli.StringSliceFlag{
Name: "secrets-from-file",
Usage: "secret key value pairs eg secret_name=/path/to/secret",
EnvVar: "PLUGIN_SECRETS_FROM_FILE",
},
cli.StringFlag{ cli.StringFlag{
Name: "drone-card-path", Name: "drone-card-path",
Usage: "card path location to write to", Usage: "card path location to write to",
@@ -292,6 +307,9 @@ func run(c *cli.Context) error {
AutoLabel: c.BoolT("auto-label"), AutoLabel: c.BoolT("auto-label"),
Link: c.String("link"), Link: c.String("link"),
NoCache: c.Bool("no-cache"), NoCache: c.Bool("no-cache"),
Secret: c.String("secret"),
SecretEnvs: c.StringSlice("secrets-from-env"),
SecretFiles: c.StringSlice("secrets-from-file"),
AddHost: c.StringSlice("add-host"), AddHost: c.StringSlice("add-host"),
Quiet: c.Bool("quiet"), Quiet: c.Bool("quiet"),
}, },

View File

@@ -58,6 +58,9 @@ type (
Labels []string // Label map Labels []string // Label map
Link string // Git repo link Link string // Git repo link
NoCache bool // Docker build no-cache NoCache bool // Docker build no-cache
Secret string // secret keypair
SecretEnvs []string // Docker build secrets with env var as source
SecretFiles []string // Docker build secrets with file as source
AddHost []string // Docker build add-host AddHost []string // Docker build add-host
Quiet bool // Docker build quiet Quiet bool // Docker build quiet
} }
@@ -72,26 +75,31 @@ type (
CardPath string // Card path to write file to CardPath string // Card path to write file to
} }
Inspect []struct { Card []struct {
ID string `json:"Id"` ID string `json:"Id"`
RepoTags []string `json:"RepoTags"` RepoTags []string `json:"RepoTags"`
RepoDigests []interface{} `json:"RepoDigests"` ParsedRepoTags []TagStruct `json:"ParsedRepoTags"`
Parent string `json:"Parent"` RepoDigests []interface{} `json:"RepoDigests"`
Comment string `json:"Comment"` Parent string `json:"Parent"`
Created time.Time `json:"Created"` Comment string `json:"Comment"`
Container string `json:"Container"` Created time.Time `json:"Created"`
DockerVersion string `json:"DockerVersion"` Container string `json:"Container"`
Author string `json:"Author"` DockerVersion string `json:"DockerVersion"`
Architecture string `json:"Architecture"` Author string `json:"Author"`
Os string `json:"Os"` Architecture string `json:"Architecture"`
Size int `json:"Size"` Os string `json:"Os"`
VirtualSize int `json:"VirtualSize"` Size int `json:"Size"`
Metadata struct { VirtualSize int `json:"VirtualSize"`
Metadata struct {
LastTagTime time.Time `json:"LastTagTime"` LastTagTime time.Time `json:"LastTagTime"`
} `json:"Metadata"` } `json:"Metadata"`
SizeString string SizeString string
VirtualSizeString string VirtualSizeString string
Time string Time string
URL string `json:"URL"`
}
TagStruct struct {
Tag string `json:"Tag"`
} }
) )
@@ -175,7 +183,7 @@ func (p Plugin) Exec() error {
for _, tag := range p.Build.Tags { for _, tag := range p.Build.Tags {
cmds = append(cmds, commandTag(p.Build, tag)) // docker tag cmds = append(cmds, commandTag(p.Build, tag)) // docker tag
if p.Dryrun == false { if !p.Dryrun {
cmds = append(cmds, commandPush(p.Build, tag)) // docker push cmds = append(cmds, commandPush(p.Build, tag)) // docker push
} }
} }
@@ -297,6 +305,19 @@ func commandBuild(build Build) *exec.Cmd {
for _, host := range build.AddHost { for _, host := range build.AddHost {
args = append(args, "--add-host", host) args = append(args, "--add-host", host)
} }
if build.Secret != "" {
args = append(args, "--secret", build.Secret)
}
for _, secret := range build.SecretEnvs {
if arg, err := getSecretStringCmdArg(secret); err == nil {
args = append(args, "--secret", arg)
}
}
for _, secret := range build.SecretFiles {
if arg, err := getSecretFileCmdArg(secret); err == nil {
args = append(args, "--secret", arg)
}
}
if build.Target != "" { if build.Target != "" {
args = append(args, "--target", build.Target) args = append(args, "--target", build.Target)
} }
@@ -328,9 +349,41 @@ func commandBuild(build Build) *exec.Cmd {
} }
} }
// we need to enable buildkit, for secret support
if build.Secret != "" || len(build.SecretEnvs) > 0 || len(build.SecretFiles) > 0 {
os.Setenv("DOCKER_BUILDKIT", "1")
}
return exec.Command(dockerExe, args...) return exec.Command(dockerExe, args...)
} }
func getSecretStringCmdArg(kvp string) (string, error) {
return getSecretCmdArg(kvp, false)
}
func getSecretFileCmdArg(kvp string) (string, error) {
return getSecretCmdArg(kvp, true)
}
func getSecretCmdArg(kvp string, file bool) (string, error) {
delimIndex := strings.IndexByte(kvp, '=')
if delimIndex == -1 {
return "", fmt.Errorf("%s is not a valid secret", kvp)
}
key := kvp[:delimIndex]
value := kvp[delimIndex+1:]
if key == "" || value == "" {
return "", fmt.Errorf("%s is not a valid secret", kvp)
}
if file {
return fmt.Sprintf("id=%s,src=%s", key, value), nil
}
return fmt.Sprintf("id=%s,env=%s", key, value), nil
}
// helper function to add proxy values from the environment // helper function to add proxy values from the environment
func addProxyBuildArgs(build *Build) { func addProxyBuildArgs(build *Build) {
addProxyValue(build, "http_proxy") addProxyValue(build, "http_proxy")

View File

@@ -1 +1,130 @@
package docker package docker
import (
"os/exec"
"reflect"
"testing"
)
func TestCommandBuild(t *testing.T) {
tcs := []struct {
name string
build Build
want *exec.Cmd
}{
{
name: "secret from env var",
build: Build{
Name: "plugins/drone-docker:latest",
Dockerfile: "Dockerfile",
Context: ".",
SecretEnvs: []string{
"foo_secret=FOO_SECRET_ENV_VAR",
},
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
"plugins/drone-docker:latest",
".",
"--secret id=foo_secret,env=FOO_SECRET_ENV_VAR",
),
},
{
name: "secret from file",
build: Build{
Name: "plugins/drone-docker:latest",
Dockerfile: "Dockerfile",
Context: ".",
SecretFiles: []string{
"foo_secret=/path/to/foo_secret",
},
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
"plugins/drone-docker:latest",
".",
"--secret id=foo_secret,src=/path/to/foo_secret",
),
},
{
name: "multiple mixed secrets",
build: Build{
Name: "plugins/drone-docker:latest",
Dockerfile: "Dockerfile",
Context: ".",
SecretEnvs: []string{
"foo_secret=FOO_SECRET_ENV_VAR",
"bar_secret=BAR_SECRET_ENV_VAR",
},
SecretFiles: []string{
"foo_secret=/path/to/foo_secret",
"bar_secret=/path/to/bar_secret",
},
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
"plugins/drone-docker:latest",
".",
"--secret id=foo_secret,env=FOO_SECRET_ENV_VAR",
"--secret id=bar_secret,env=BAR_SECRET_ENV_VAR",
"--secret id=foo_secret,src=/path/to/foo_secret",
"--secret id=bar_secret,src=/path/to/bar_secret",
),
},
{
name: "invalid mixed secrets",
build: Build{
Name: "plugins/drone-docker:latest",
Dockerfile: "Dockerfile",
Context: ".",
SecretEnvs: []string{
"foo_secret=",
"=FOO_SECRET_ENV_VAR",
"",
},
SecretFiles: []string{
"foo_secret=",
"=/path/to/bar_secret",
"",
},
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
"plugins/drone-docker:latest",
".",
),
},
}
for _, tc := range tcs {
tc := tc
t.Run(tc.name, func(t *testing.T) {
cmd := commandBuild(tc.build)
if !reflect.DeepEqual(cmd.String(), tc.want.String()) {
t.Errorf("Got cmd %v, want %v", cmd, tc.want)
}
})
}
}

41
docs/card.data.json Normal file
View File

@@ -0,0 +1,41 @@
{
"Id": "sha256:3b0709c9afb41629c79c93355feed114d08a8c1bedd975eb53af08f4b867fd91",
"RepoTags": [
"798a0dae10d63d281eff4c06eaa12001ffd23740:latest",
"tphoney/test:latest"
],
"ParsedRepoTags": [
{
"Tag": ""
},
{
"Tag": ""
},
{
"Tag": "798a0dae10d63d281eff4c06eaa12001ffd23740:latest"
},
{
"Tag": "tphoney/test:latest"
}
],
"RepoDigests": [
"tphoney/test@sha256:93f8b95aaae7d194208b72e94a3a90544b00c8f2ad45aeb89d81a0c6ccbc5e19"
],
"Parent": "sha256:493aa330a5929027dd8ecded9fa8c473a1508d17c0fd7d6a94a7f197f8d22c60",
"Comment": "",
"Created": "2022-02-16T11:13:40.8956582Z",
"Container": "a57c0ca4dd2e081df8758e00549f7abe83803f1a1a7aaaf1cd8e685a5eb5a097",
"DockerVersion": "20.10.9",
"Author": "",
"Architecture": "amd64",
"Os": "linux",
"Size": 14045949,
"VirtualSize": 14045949,
"Metadata": {
"LastTagTime": "2022-02-16T11:13:40.9433973Z"
},
"SizeString": "13.40MB",
"VirtualSizeString": "13.40MB",
"Time": "2022-02-16T11:13:40Z",
"URL": "http://hub.docker.com/repositories/tphoney/test/"
}

View File

@@ -1,118 +1,138 @@
{ {
"type": "AdaptiveCard", "type": "AdaptiveCard",
"body": [ "body": [
{
"type": "ColumnSet",
"columns": [
{ {
"type": "Column", "type": "ColumnSet",
"items": [ "columns": [
{ {
"type": "Image", "type": "Column",
"url": "https://d36jcksde1wxzq.cloudfront.net/be7833db9bddb4494d2a7c3dd659199a.png", "items": [
"size": "Medium" {
} "type": "Image",
], "url": "https://d36jcksde1wxzq.cloudfront.net/be7833db9bddb4494d2a7c3dd659199a.png",
"width": "auto" "size": "small"
}
],
"width": "auto"
},
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"text": "Plugin: Drone Docker",
"wrap": true,
"size": "Small",
"weight": "Bolder",
"isSubtle": false,
"spacing": "Small"
},
{
"type": "TextBlock",
"text": "DIGEST: ${RepoDigests[0]}",
"wrap": true,
"size": "Small",
"weight": "Lighter",
"isSubtle": true,
"spacing": "Small"
}
],
"width": "stretch"
}
],
"style": "default"
}, },
{ {
"type": "Column", "type": "ColumnSet",
"items": [ "columns": [
{
"type": "TextBlock",
"text": "${RepoTags[0]}",
"size": "Medium"
},
{
"type": "TextBlock",
"text": "DIGEST: ${RepoDigests[0]}",
"wrap": true,
"size": "Small",
"weight": "Lighter",
"isSubtle": true,
"spacing": "Small"
},
{
"type": "ColumnSet",
"columns": [
{ {
"type": "Column", "type": "Column",
"items": [ "items": [
{ {
"type": "TextBlock", "type": "TextBlock",
"weight": "Lighter", "weight": "Lighter",
"text": "OS/ARCH", "text": "TAGS",
"wrap": true, "wrap": true,
"size": "Small", "size": "Small",
"isSubtle": true, "isSubtle": true,
"spacing": "Medium" "spacing": "Medium"
}, },
{ {
"type": "TextBlock", "type": "FactSet",
"text": "${OS}/${Architecture}", "facts": [
"wrap": true, {
"size": "Small", "title": "${Tag}",
"spacing": "Small" "value": ""
} }
], ],
"separator": true, "spacing": "Small",
"width": "auto" "$data": "${ParsedRepoTags}",
"wrap": true,
"size": "Small",
"weight": "Bolder"
}
],
"separator": true,
"width": "auto"
}, },
{ {
"type": "Column", "type": "Column",
"items": [ "items": [
{ {
"type": "TextBlock", "type": "TextBlock",
"weight": "Lighter", "weight": "Lighter",
"text": "SIZE", "text": "SIZE",
"wrap": true, "wrap": true,
"size": "Small", "size": "Small",
"isSubtle": true "isSubtle": true
}, },
{ {
"type": "TextBlock", "type": "TextBlock",
"spacing": "Small", "spacing": "Small",
"text": "${SizeString}", "text": "${SizeString}",
"wrap": true, "wrap": true,
"size": "Small" "weight": "Bolder"
} }
], ],
"width": "auto", "width": "auto",
"separator": true, "separator": true,
"spacing": "Medium" "spacing": "Medium"
}, },
{ {
"type": "Column", "type": "Column",
"items": [ "items": [
{ {
"type": "TextBlock", "type": "TextBlock",
"weight": "Lighter", "weight": "Lighter",
"text": "LAST PUSHED", "text": "LAST PUSHED",
"wrap": true, "wrap": true,
"size": "Small", "size": "Small",
"isSubtle": true "isSubtle": true
}, },
{ {
"type": "TextBlock", "type": "TextBlock",
"spacing": "Small", "spacing": "Small",
"text": "{{DATE(${Time})}} - {{TIME(${Time})}}", "text": "{{DATE(${Time})}} - {{TIME(${Time})}}",
"wrap": true, "wrap": true,
"size": "Small" "weight": "Bolder"
} }
], ],
"width": "auto", "width": "auto",
"separator": true, "separator": true,
"spacing": "Medium" "spacing": "Medium"
} }
], ],
"style": "default" "style": "default",
} "separator": true
],
"width": "stretch"
} }
] ],
} "actions": [
], {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "type": "Action.OpenUrl",
"version": "1.0" "title": "Go to image",
"url": "${url}"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5"
} }

1
go.mod
View File

@@ -18,6 +18,7 @@ require (
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 // indirect golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 // indirect
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 // indirect golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
) )
go 1.17 go 1.17

3
go.sum
View File

@@ -38,5 +38,6 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=