mirror of https://github.com/docker/buildx.git
Merge pull request #721 from crazy-max/compose-ext
bake: `x-bake` extension field with compose
This commit is contained in:
commit
cb185f095f
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
|
|
Loading…
Reference in New Issue