Skip to content

Commit a4d8970

Browse files
Add support for artifact file (#7)
* Add support for artifact file * Fix UT * Fix get digest * Add UT * Fix digest error log
1 parent 99d0da9 commit a4d8970

File tree

8 files changed

+236
-54
lines changed

8 files changed

+236
-54
lines changed

.drone.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ platform:
1212

1313
steps:
1414
- name: vet
15-
image: golang:1.17
15+
image: golang:1.20
1616
commands:
1717
- go vet ./...
1818
environment:
@@ -22,7 +22,7 @@ steps:
2222
path: /go
2323

2424
- name: test
25-
image: golang:1.17
25+
image: golang:1.20
2626
commands:
2727
- go test -cover ./...
2828
environment:

app.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package docker
33
import (
44
"os"
55

6+
"github.com/drone-plugins/drone-plugin-lib/drone"
67
"github.com/joho/godotenv"
78
"github.com/sirupsen/logrus"
89
"github.com/urfave/cli"
@@ -300,6 +301,21 @@ func Run() {
300301
Name: "buildx-load",
301302
EnvVar: "PLUGIN_BUILDX_LOAD",
302303
},
304+
cli.StringFlag{
305+
Name: "metadata-file",
306+
Usage: "Location of metadata file that will be generated by the plugin. This file will include information of docker images that are uploaded by the plugin which will be used to create the artifact file.",
307+
EnvVar: "PLUGIN_METADATA_FILE",
308+
},
309+
cli.StringFlag{
310+
Name: "artifact-file",
311+
Usage: "Artifact file location that will be generated by the plugin. This file will include information of docker images that are uploaded by the plugin.",
312+
EnvVar: "PLUGIN_ARTIFACT_FILE",
313+
},
314+
cli.StringFlag{
315+
Name: "registry-type",
316+
Usage: "registry type",
317+
EnvVar: "PLUGIN_REGISTRY_TYPE",
318+
},
303319
}
304320

305321
if err := app.Run(os.Args); err != nil {
@@ -308,6 +324,11 @@ func Run() {
308324
}
309325

310326
func run(c *cli.Context) error {
327+
registryType := drone.Docker
328+
if c.String("registry-type") != "" {
329+
registryType = drone.RegistryType(c.String("registry-type"))
330+
}
331+
311332
plugin := Plugin{
312333
Dryrun: c.Bool("dry-run"),
313334
Cleanup: c.BoolT("docker.purge"),
@@ -318,7 +339,9 @@ func run(c *cli.Context) error {
318339
Email: c.String("docker.email"),
319340
Config: c.String("docker.config"),
320341
},
321-
CardPath: c.String("drone-card-path"),
342+
CardPath: c.String("drone-card-path"),
343+
MetadataFile: c.String("metadata-file"),
344+
ArtifactFile: c.String("artifact-file"),
322345
Build: Build{
323346
Remote: c.String("remote.url"),
324347
Name: c.String("commit.sha"),
@@ -361,6 +384,7 @@ func run(c *cli.Context) error {
361384
DNS: c.StringSlice("daemon.dns"),
362385
DNSSearch: c.StringSlice("daemon.dns-search"),
363386
MTU: c.String("daemon.mtu"),
387+
RegistryType: registryType,
364388
},
365389
Builder: Builder{
366390
Name: c.String("builder-name"),

docker.go

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
package docker
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"os"
67
"os/exec"
78
"path/filepath"
89
"strings"
910
"time"
11+
12+
"github.com/drone-plugins/drone-plugin-lib/drone"
1013
)
1114

1215
type (
1316
// Daemon defines Docker daemon parameters.
1417
Daemon struct {
15-
Registry string // Docker registry
16-
Mirror string // Docker registry mirror
17-
Insecure bool // Docker daemon enable insecure registries
18-
StorageDriver string // Docker daemon storage driver
19-
StoragePath string // Docker daemon storage path
20-
Disabled bool // DOcker daemon is disabled (already running)
21-
Debug bool // Docker daemon started in debug mode
22-
Bip string // Docker daemon network bridge IP address
23-
DNS []string // Docker daemon dns server
24-
DNSSearch []string // Docker daemon dns search domain
25-
MTU string // Docker daemon mtu setting
26-
IPv6 bool // Docker daemon IPv6 networking
18+
Registry string // Docker registry
19+
Mirror string // Docker registry mirror
20+
Insecure bool // Docker daemon enable insecure registries
21+
StorageDriver string // Docker daemon storage driver
22+
StoragePath string // Docker daemon storage path
23+
Disabled bool // DOcker daemon is disabled (already running)
24+
Debug bool // Docker daemon started in debug mode
25+
Bip string // Docker daemon network bridge IP address
26+
DNS []string // Docker daemon dns server
27+
DNSSearch []string // Docker daemon dns search domain
28+
MTU string // Docker daemon mtu setting
29+
IPv6 bool // Docker daemon IPv6 networking
30+
RegistryType drone.RegistryType // Docker registry type
2731
}
2832

2933
Builder struct {
@@ -76,13 +80,15 @@ type (
7680

7781
// Plugin defines the Docker plugin parameters.
7882
Plugin struct {
79-
Login Login // Docker login configuration
80-
Build Build // Docker build configuration
81-
Builder Builder // Docker Buildx builder configuration
82-
Daemon Daemon // Docker daemon configuration
83-
Dryrun bool // Docker push is skipped
84-
Cleanup bool // Docker purge is enabled
85-
CardPath string // Card path to write file to
83+
Login Login // Docker login configuration
84+
Build Build // Docker build configuration
85+
Builder Builder // Docker Buildx builder configuration
86+
Daemon Daemon // Docker daemon configuration
87+
Dryrun bool // Docker push is skipped
88+
Cleanup bool // Docker purge is enabled
89+
CardPath string // Card path to write file to
90+
MetadataFile string // Location to write the metadata file
91+
ArtifactFile string // Artifact path to write file to
8692
}
8793

8894
Card []struct {
@@ -204,7 +210,7 @@ func (p Plugin) Exec() error {
204210
cmds = append(cmds, commandInfo()) // docker info
205211

206212
// Command to build, tag and push
207-
cmds = append(cmds, commandBuildx(p.Build, p.Builder, p.Dryrun)) // docker build
213+
cmds = append(cmds, commandBuildx(p.Build, p.Builder, p.Dryrun, p.MetadataFile)) // docker build
208214

209215
// execute all commands in batch mode.
210216
for _, cmd := range cmds {
@@ -223,8 +229,21 @@ func (p Plugin) Exec() error {
223229
}
224230

225231
// output the adaptive card
226-
if err := p.writeCard(); err != nil {
227-
fmt.Printf("Could not create adaptive card. %s\n", err)
232+
if p.Builder.Driver == defaultDriver {
233+
if err := p.writeCard(); err != nil {
234+
fmt.Printf("Could not create adaptive card. %s\n", err)
235+
}
236+
}
237+
238+
// write to artifact file
239+
if p.ArtifactFile != "" {
240+
if digest, err := getDigest(p.MetadataFile); err == nil {
241+
if err = drone.WritePluginArtifactFile(p.Daemon.RegistryType, p.ArtifactFile, p.Daemon.Registry, p.Build.Repo, digest, p.Build.Tags); err != nil {
242+
fmt.Printf("Failed to write plugin artifact file at path: %s with error: %s\n", p.ArtifactFile, err)
243+
}
244+
} else {
245+
fmt.Printf("Could not fetch the digest. %s\n", err)
246+
}
228247
}
229248

230249
// execute cleanup routines in batch mode
@@ -245,6 +264,27 @@ func (p Plugin) Exec() error {
245264
return nil
246265
}
247266

267+
func getDigest(metadataFile string) (string, error) {
268+
file, err := os.Open(metadataFile)
269+
if err != nil {
270+
return "", fmt.Errorf("unable to open the metadata file %s with error: %s", metadataFile, err)
271+
}
272+
defer file.Close()
273+
274+
var metadata map[string]interface{}
275+
if err = json.NewDecoder(file).Decode(&metadata); err != nil {
276+
return "", fmt.Errorf("unable to decode the metadata with error: %s", err)
277+
}
278+
279+
if d, found := metadata["containerimage.digest"]; found {
280+
if digest, ok := d.(string); ok {
281+
return digest, nil
282+
}
283+
return "", fmt.Errorf("unable to parse containerimage.digest from metadata json")
284+
}
285+
return "", fmt.Errorf("containerimage.digest not found in metadata json")
286+
}
287+
248288
// helper function to create the docker login command.
249289
func commandLogin(login Login) *exec.Cmd {
250290
if login.Email != "" {
@@ -288,7 +328,7 @@ func commandInfo() *exec.Cmd {
288328
}
289329

290330
// helper function to create the docker buildx command.
291-
func commandBuildx(build Build, builder Builder, dryrun bool) *exec.Cmd {
331+
func commandBuildx(build Build, builder Builder, dryrun bool, metadataFile string) *exec.Cmd {
292332
args := []string{
293333
"buildx",
294334
"build",
@@ -310,6 +350,9 @@ func commandBuildx(build Build, builder Builder, dryrun bool) *exec.Cmd {
310350
args = append(args, "--push")
311351
}
312352
args = append(args, build.Context)
353+
if metadataFile != "" {
354+
args = append(args, "--metadata-file", metadataFile)
355+
}
313356
if build.Squash {
314357
args = append(args, "--squash")
315358
}

docker_test.go

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
package docker
22

33
import (
4+
"os"
45
"os/exec"
56
"reflect"
67
"testing"
78
)
89

910
func TestCommandBuildx(t *testing.T) {
1011
tcs := []struct {
11-
name string
12-
build Build
13-
builder Builder
14-
dryrun bool
15-
want *exec.Cmd
12+
name string
13+
build Build
14+
builder Builder
15+
dryrun bool
16+
metadata string
17+
want *exec.Cmd
1618
}{
1719
{
1820
name: "secret from env var",
@@ -181,17 +183,78 @@ func TestCommandBuildx(t *testing.T) {
181183
"--ssh id_rsa=/root/.ssh/id_rsa",
182184
),
183185
},
186+
{
187+
name: "metadata file",
188+
build: Build{
189+
Name: "plugins/drone-docker:latest",
190+
Dockerfile: "Dockerfile",
191+
Context: ".",
192+
Repo: "plugins/drone-docker",
193+
Tags: []string{"latest"},
194+
},
195+
metadata: "/tmp/metadata.json",
196+
want: exec.Command(
197+
dockerExe,
198+
"buildx",
199+
"build",
200+
"--rm=true",
201+
"-f",
202+
"Dockerfile",
203+
"-t",
204+
"plugins/drone-docker:latest",
205+
"--push",
206+
".",
207+
"--metadata-file /tmp/metadata.json",
208+
),
209+
},
184210
}
185211

186212
for _, tc := range tcs {
187213
tc := tc
188214

189215
t.Run(tc.name, func(t *testing.T) {
190-
cmd := commandBuildx(tc.build, tc.builder, tc.dryrun)
216+
cmd := commandBuildx(tc.build, tc.builder, tc.dryrun, tc.metadata)
191217

192218
if !reflect.DeepEqual(cmd.String(), tc.want.String()) {
193219
t.Errorf("Got cmd %v, want %v", cmd, tc.want)
194220
}
195221
})
196222
}
197223
}
224+
225+
func TestGetDigest(t *testing.T) {
226+
227+
tcs := []struct {
228+
name string
229+
path string
230+
digest string
231+
}{
232+
{
233+
name: "single platform",
234+
path: "testdata/metadata.json",
235+
digest: "sha256:02fd68a300e3a863791744802ea3eeaac43a36e98888cdb9ffb22da8006f7eee",
236+
},
237+
{
238+
name: "cross platform",
239+
path: "testdata/metadata_cross_platform.json",
240+
digest: "sha256:0cff645119742b04807c4a3953925a579e21654baaeaf20f33c05554a6decbce",
241+
},
242+
}
243+
244+
dir, err := os.Getwd()
245+
if err != nil {
246+
t.Fatal("unable to get working dir")
247+
}
248+
249+
for _, tc := range tcs {
250+
t.Run(tc.name, func(t *testing.T) {
251+
digest, err := getDigest(dir + "/" + tc.path)
252+
if err != nil {
253+
t.Errorf("unable to get digest with error %s", err)
254+
}
255+
if digest != tc.digest {
256+
t.Errorf("Got digest %s, want %s", digest, tc.digest)
257+
}
258+
})
259+
}
260+
}

go.mod

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,20 @@ module github.com/drone-plugins/drone-buildx
33
require (
44
github.com/aws/aws-sdk-go v1.26.7
55
github.com/coreos/go-semver v0.3.0
6+
github.com/drone-plugins/drone-plugin-lib v0.4.1
67
github.com/drone/drone-go v1.7.1
78
github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743
89
github.com/joho/godotenv v1.3.0
9-
github.com/sirupsen/logrus v1.3.0
10+
github.com/sirupsen/logrus v1.9.0
1011
github.com/urfave/cli v1.22.2
1112
)
1213

1314
require (
14-
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
15+
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
1516
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
16-
github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect
17-
github.com/russross/blackfriday/v2 v2.0.1 // indirect
18-
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
19-
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 // indirect
20-
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 // indirect
17+
github.com/russross/blackfriday/v2 v2.1.0 // indirect
18+
golang.org/x/sys v0.0.0-20220731174439-a90be440212d // indirect
2119
gopkg.in/yaml.v2 v2.2.8 // indirect
2220
)
2321

24-
go 1.17
22+
go 1.20

0 commit comments

Comments
 (0)