Merge pull request #721 from crazy-max/compose-ext

bake: `x-bake` extension field with compose
This commit is contained in:
Tõnis Tiigi 2021-08-13 07:51:23 -07:00 committed by GitHub
commit cb185f095f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 255 additions and 2 deletions

View File

@ -80,13 +80,15 @@ func ParseCompose(dt []byte) (*Config, error) {
return val, ok
})),
CacheFrom: s.Build.CacheFrom,
// TODO: add platforms
}
if err = t.composeExtTarget(s.Build.Extensions); err != nil {
return nil, err
}
if s.Build.Target != "" {
target := s.Build.Target
t.Target = &target
}
if s.Image != "" {
if len(t.Tags) == 0 && s.Image != "" {
t.Tags = []string{s.Image}
}
c.Targets = append(c.Targets, t)
@ -111,3 +113,82 @@ func flatten(in compose.MappingWithEquals) compose.Mapping {
}
return out
}
// composeExtTarget converts Compose build extension x-bake to bake Target
// https://github.com/compose-spec/compose-spec/blob/master/spec.md#extension
func (t *Target) composeExtTarget(exts map[string]interface{}) error {
if ext, ok := exts["x-bake"]; ok {
for key, val := range ext.(map[string]interface{}) {
switch key {
case "tags":
if res, k := val.(string); k {
t.Tags = append(t.Tags, res)
} else {
for _, res := range val.([]interface{}) {
t.Tags = append(t.Tags, res.(string))
}
}
case "cache-from":
t.CacheFrom = []string{} // Needed to override the main field
if res, k := val.(string); k {
t.CacheFrom = append(t.CacheFrom, res)
} else {
for _, res := range val.([]interface{}) {
t.CacheFrom = append(t.CacheFrom, res.(string))
}
}
case "cache-to":
if res, k := val.(string); k {
t.CacheTo = append(t.CacheTo, res)
} else {
for _, res := range val.([]interface{}) {
t.CacheTo = append(t.CacheTo, res.(string))
}
}
case "secret":
if res, k := val.(string); k {
t.Secrets = append(t.Secrets, res)
} else {
for _, res := range val.([]interface{}) {
t.Secrets = append(t.Secrets, res.(string))
}
}
case "ssh":
if res, k := val.(string); k {
t.SSH = append(t.SSH, res)
} else {
for _, res := range val.([]interface{}) {
t.SSH = append(t.SSH, res.(string))
}
}
case "platforms":
if res, k := val.(string); k {
t.Platforms = append(t.Platforms, res)
} else {
for _, res := range val.([]interface{}) {
t.Platforms = append(t.Platforms, res.(string))
}
}
case "output":
if res, k := val.(string); k {
t.Outputs = append(t.Outputs, res)
} else {
for _, res := range val.([]interface{}) {
t.Outputs = append(t.Outputs, res.(string))
}
}
case "pull":
if res, ok := val.(bool); ok {
t.Pull = &res
}
case "no-cache":
if res, ok := val.(bool); ok {
t.NoCache = &res
}
default:
return fmt.Errorf("compose file invalid: unkwown %s field for x-bake", key)
}
}
}
return nil
}

View File

@ -214,3 +214,70 @@ networks:
_, err := ParseCompose(dt)
require.NoError(t, err)
}
func TestComposeExt(t *testing.T) {
var dt = []byte(`
services:
addon:
image: ct-addon:bar
build:
context: .
dockerfile: ./Dockerfile
cache_from:
- user/app:cache
args:
CT_ECR: foo
CT_TAG: bar
x-bake:
tags:
- ct-addon:foo
- ct-addon:alp
platforms:
- linux/amd64
- linux/arm64
cache-from:
- type=local,src=path/to/cache
cache-to: local,dest=path/to/cache
pull: true
aws:
image: ct-fake-aws:bar
build:
dockerfile: ./aws.Dockerfile
args:
CT_ECR: foo
CT_TAG: bar
x-bake:
secret:
- id=mysecret,src=/local/secret
- id=mysecret2,src=/local/secret2
ssh: default
platforms: linux/arm64
output: type=docker
no-cache: true
`)
c, err := ParseCompose(dt)
require.NoError(t, err)
require.Equal(t, 2, len(c.Targets))
sort.Slice(c.Targets, func(i, j int) bool {
return c.Targets[i].Name < c.Targets[j].Name
})
require.Equal(t, c.Targets[0].Args, map[string]string{"CT_ECR": "foo", "CT_TAG": "bar"})
require.Equal(t, c.Targets[0].Tags, []string{"ct-addon:foo", "ct-addon:alp"})
require.Equal(t, c.Targets[0].Platforms, []string{"linux/amd64", "linux/arm64"})
require.Equal(t, c.Targets[0].CacheFrom, []string{"type=local,src=path/to/cache"})
require.Equal(t, c.Targets[0].CacheTo, []string{"local,dest=path/to/cache"})
require.Equal(t, c.Targets[0].Pull, newBool(true))
require.Equal(t, c.Targets[1].Tags, []string{"ct-fake-aws:bar"})
require.Equal(t, c.Targets[1].Secrets, []string{"id=mysecret,src=/local/secret", "id=mysecret2,src=/local/secret2"})
require.Equal(t, c.Targets[1].SSH, []string{"default"})
require.Equal(t, c.Targets[1].Platforms, []string{"linux/arm64"})
require.Equal(t, c.Targets[1].Outputs, []string{"type=docker"})
require.Equal(t, c.Targets[1].NoCache, newBool(true))
}
func newBool(val bool) *bool {
b := val
return &b
}

View File

@ -756,3 +756,108 @@ $ docker buildx bake --print app
}
}
```
### Extension field with Compose
[Special extension](https://github.com/compose-spec/compose-spec/blob/master/spec.md#extension)
field `x-bake` can be used in your compose file to evaluate fields that are not
(yet) available in the [build definition](https://github.com/compose-spec/compose-spec/blob/master/build.md#build-definition).
```yaml
# docker-compose.yml
services:
addon:
image: ct-addon:bar
build:
context: .
dockerfile: ./Dockerfile
args:
CT_ECR: foo
CT_TAG: bar
x-bake:
tags:
- ct-addon:foo
- ct-addon:alp
platforms:
- linux/amd64
- linux/arm64
cache-from:
- user/app:cache
- type=local,src=path/to/cache
cache-to: type=local,dest=path/to/cache
pull: true
aws:
image: ct-fake-aws:bar
build:
dockerfile: ./aws.Dockerfile
args:
CT_ECR: foo
CT_TAG: bar
x-bake:
secret:
- id=mysecret,src=./secret
- id=mysecret2,src=./secret2
platforms: linux/arm64
output: type=docker
no-cache: true
```
```console
$ docker buildx bake --print
{
"target": {
"addon": {
"context": ".",
"dockerfile": "./Dockerfile",
"args": {
"CT_ECR": "foo",
"CT_TAG": "bar"
},
"tags": [
"ct-addon:foo",
"ct-addon:alp"
],
"cache-from": [
"user/app:cache",
"type=local,src=path/to/cache"
],
"cache-to": [
"type=local,dest=path/to/cache"
],
"platforms": [
"linux/amd64",
"linux/arm64"
],
"pull": true
},
"aws": {
"context": ".",
"dockerfile": "./aws.Dockerfile",
"args": {
"CT_ECR": "foo",
"CT_TAG": "bar"
},
"tags": [
"ct-fake-aws:bar"
],
"secret": [
"id=mysecret,src=./secret",
"id=mysecret2,src=./secret2"
],
"platforms": [
"linux/arm64"
],
"output": [
"type=docker"
],
"no-cache": true
}
}
}
```
Complete list of valid fields for `x-bake`:
`tags`, `cache-from`, `cache-to`, `secret`, `ssh`, `platforms`, `output`,
`pull`, `no-cache`