mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 09:17:49 +08:00
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
|
return val, ok
|
||||||
})),
|
})),
|
||||||
CacheFrom: s.Build.CacheFrom,
|
CacheFrom: s.Build.CacheFrom,
|
||||||
// TODO: add platforms
|
}
|
||||||
|
if err = t.composeExtTarget(s.Build.Extensions); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
if s.Build.Target != "" {
|
if s.Build.Target != "" {
|
||||||
target := s.Build.Target
|
target := s.Build.Target
|
||||||
t.Target = &target
|
t.Target = &target
|
||||||
}
|
}
|
||||||
if s.Image != "" {
|
if len(t.Tags) == 0 && s.Image != "" {
|
||||||
t.Tags = []string{s.Image}
|
t.Tags = []string{s.Image}
|
||||||
}
|
}
|
||||||
c.Targets = append(c.Targets, t)
|
c.Targets = append(c.Targets, t)
|
||||||
@ -111,3 +113,82 @@ func flatten(in compose.MappingWithEquals) compose.Mapping {
|
|||||||
}
|
}
|
||||||
return out
|
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)
|
_, err := ParseCompose(dt)
|
||||||
require.NoError(t, err)
|
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…
x
Reference in New Issue
Block a user