Merge pull request #1609 from crazy-max/0.10.3_cherry_picks

[v0.10] cherry-picks for v0.10.3
pull/1635/head
CrazyMax 2 years ago committed by GitHub
commit f2feea8bed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -78,6 +78,7 @@ func ParseCompose(cfgs []compose.ConfigFile, envs map[string]string) (*Config, e
// compose does not support nil values for labels // compose does not support nil values for labels
labels := map[string]*string{} labels := map[string]*string{}
for k, v := range s.Build.Labels { for k, v := range s.Build.Labels {
v := v
labels[k] = &v labels[k] = &v
} }

@ -670,6 +670,24 @@ func TestJSONFunctions(t *testing.T) {
require.Equal(t, ptrstr("pre-<FOO-abc>"), c.Targets[0].Args["v1"]) require.Equal(t, ptrstr("pre-<FOO-abc>"), c.Targets[0].Args["v1"])
} }
func TestJSONInvalidFunctions(t *testing.T) {
dt := []byte(`{
"target": {
"app": {
"args": {
"v1": "myfunc(\"foo\")"
}
}
}}`)
c, err := ParseFile(dt, "docker-bake.json")
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app")
require.Equal(t, ptrstr(`myfunc("foo")`), c.Targets[0].Args["v1"])
}
func TestHCLFunctionInAttr(t *testing.T) { func TestHCLFunctionInAttr(t *testing.T) {
dt := []byte(` dt := []byte(`
function "brace" { function "brace" {

@ -14,15 +14,7 @@ func funcCalls(exp hcl.Expression) ([]string, hcl.Diagnostics) {
if !ok { if !ok {
fns, err := jsonFuncCallsRecursive(exp) fns, err := jsonFuncCallsRecursive(exp)
if err != nil { if err != nil {
return nil, hcl.Diagnostics{ return nil, wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr())
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid expression",
Detail: err.Error(),
Subject: exp.Range().Ptr(),
Context: exp.Range().Ptr(),
},
}
} }
return fns, nil return fns, nil
} }

@ -62,7 +62,9 @@ type parser struct {
doneB map[*hcl.Block]map[string]struct{} doneB map[*hcl.Block]map[string]struct{}
} }
func (p *parser) loadDeps(exp hcl.Expression, exclude map[string]struct{}) hcl.Diagnostics { var errUndefined = errors.New("undefined")
func (p *parser) loadDeps(exp hcl.Expression, exclude map[string]struct{}, allowMissing bool) hcl.Diagnostics {
fns, hcldiags := funcCalls(exp) fns, hcldiags := funcCalls(exp)
if hcldiags.HasErrors() { if hcldiags.HasErrors() {
return hcldiags return hcldiags
@ -70,15 +72,10 @@ func (p *parser) loadDeps(exp hcl.Expression, exclude map[string]struct{}) hcl.D
for _, fn := range fns { for _, fn := range fns {
if err := p.resolveFunction(fn); err != nil { if err := p.resolveFunction(fn); err != nil {
return hcl.Diagnostics{ if allowMissing && errors.Is(err, errUndefined) {
&hcl.Diagnostic{ continue
Severity: hcl.DiagError,
Summary: "Invalid expression",
Detail: err.Error(),
Subject: exp.Range().Ptr(),
Context: exp.Range().Ptr(),
},
} }
return wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr())
} }
} }
@ -128,27 +125,17 @@ func (p *parser) loadDeps(exp hcl.Expression, exclude map[string]struct{}) hcl.D
} }
} }
if err := p.resolveBlock(blocks[0], target); err != nil { if err := p.resolveBlock(blocks[0], target); err != nil {
return hcl.Diagnostics{ if allowMissing && errors.Is(err, errUndefined) {
&hcl.Diagnostic{ continue
Severity: hcl.DiagError,
Summary: "Invalid expression",
Detail: err.Error(),
Subject: v.SourceRange().Ptr(),
Context: v.SourceRange().Ptr(),
},
} }
return wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr())
} }
} else { } else {
if err := p.resolveValue(v.RootName()); err != nil { if err := p.resolveValue(v.RootName()); err != nil {
return hcl.Diagnostics{ if allowMissing && errors.Is(err, errUndefined) {
&hcl.Diagnostic{ continue
Severity: hcl.DiagError,
Summary: "Invalid expression",
Detail: err.Error(),
Subject: v.SourceRange().Ptr(),
Context: v.SourceRange().Ptr(),
},
} }
return wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr())
} }
} }
} }
@ -167,7 +154,7 @@ func (p *parser) resolveFunction(name string) error {
if _, ok := p.ectx.Functions[name]; ok { if _, ok := p.ectx.Functions[name]; ok {
return nil return nil
} }
return errors.Errorf("undefined function %s", name) return errors.Wrapf(errUndefined, "function %q does not exit", name)
} }
if _, ok := p.progressF[name]; ok { if _, ok := p.progressF[name]; ok {
return errors.Errorf("function cycle not allowed for %s", name) return errors.Errorf("function cycle not allowed for %s", name)
@ -217,7 +204,7 @@ func (p *parser) resolveFunction(name string) error {
return diags return diags
} }
if diags := p.loadDeps(f.Result.Expr, params); diags.HasErrors() { if diags := p.loadDeps(f.Result.Expr, params, false); diags.HasErrors() {
return diags return diags
} }
@ -255,7 +242,7 @@ func (p *parser) resolveValue(name string) (err error) {
if _, builtin := p.opt.Vars[name]; !ok && !builtin { if _, builtin := p.opt.Vars[name]; !ok && !builtin {
vr, ok := p.vars[name] vr, ok := p.vars[name]
if !ok { if !ok {
return errors.Errorf("undefined variable %q", name) return errors.Wrapf(errUndefined, "variable %q does not exit", name)
} }
def = vr.Default def = vr.Default
} }
@ -270,7 +257,7 @@ func (p *parser) resolveValue(name string) (err error) {
return return
} }
if diags := p.loadDeps(def.Expr, nil); diags.HasErrors() { if diags := p.loadDeps(def.Expr, nil, true); diags.HasErrors() {
return diags return diags
} }
vv, diags := def.Expr.Value(p.ectx) vv, diags := def.Expr.Value(p.ectx)
@ -314,14 +301,7 @@ func (p *parser) resolveValue(name string) (err error) {
func (p *parser) resolveBlock(block *hcl.Block, target *hcl.BodySchema) (err error) { func (p *parser) resolveBlock(block *hcl.Block, target *hcl.BodySchema) (err error) {
name := block.Labels[0] name := block.Labels[0]
if err := p.opt.ValidateLabel(name); err != nil { if err := p.opt.ValidateLabel(name); err != nil {
return hcl.Diagnostics{ return wrapErrorDiagnostic("Invalid name", err, &block.LabelRanges[0], &block.LabelRanges[0])
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid name",
Detail: err.Error(),
Subject: &block.LabelRanges[0],
},
}
} }
if _, ok := p.doneB[block]; !ok { if _, ok := p.doneB[block]; !ok {
@ -395,7 +375,7 @@ func (p *parser) resolveBlock(block *hcl.Block, target *hcl.BodySchema) (err err
return diag return diag
} }
for _, a := range content.Attributes { for _, a := range content.Attributes {
diag := p.loadDeps(a.Expr, nil) diag := p.loadDeps(a.Expr, nil, true)
if diag.HasErrors() { if diag.HasErrors() {
return diag return diag
} }
@ -573,15 +553,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
return diags return diags
} }
r := p.vars[k].Body.MissingItemRange() r := p.vars[k].Body.MissingItemRange()
return hcl.Diagnostics{ return wrapErrorDiagnostic("Invalid value", err, &r, &r)
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid value",
Detail: err.Error(),
Subject: &r,
Context: &r,
},
}
} }
} }
@ -604,15 +576,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
} }
} }
} }
return hcl.Diagnostics{ return wrapErrorDiagnostic("Invalid function", err, subject, context)
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid function",
Detail: err.Error(),
Subject: subject,
Context: context,
},
}
} }
} }
@ -673,15 +637,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
continue continue
} }
} else { } else {
return hcl.Diagnostics{ return wrapErrorDiagnostic("Invalid block", err, &b.LabelRanges[0], &b.DefRange)
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid attribute",
Detail: err.Error(),
Subject: &b.LabelRanges[0],
Context: &b.DefRange,
},
}
} }
} }
@ -726,21 +682,34 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
if diags, ok := err.(hcl.Diagnostics); ok { if diags, ok := err.(hcl.Diagnostics); ok {
return diags return diags
} }
return hcl.Diagnostics{ return wrapErrorDiagnostic("Invalid attribute", err, &p.attrs[k].Range, &p.attrs[k].Range)
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid attribute",
Detail: err.Error(),
Subject: &p.attrs[k].Range,
Context: &p.attrs[k].Range,
},
}
} }
} }
return nil return nil
} }
// wrapErrorDiagnostic wraps an error into a hcl.Diagnostics object.
// If the error is already an hcl.Diagnostics object, it is returned as is.
func wrapErrorDiagnostic(message string, err error, subject *hcl.Range, context *hcl.Range) hcl.Diagnostics {
switch err := err.(type) {
case *hcl.Diagnostic:
return hcl.Diagnostics{err}
case hcl.Diagnostics:
return err
default:
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: message,
Detail: err.Error(),
Subject: subject,
Context: context,
},
}
}
}
func setLabel(v reflect.Value, lbl string) int { func setLabel(v reflect.Value, lbl string) int {
// cache field index? // cache field index?
numFields := v.Elem().Type().NumField() numFields := v.Elem().Type().NumField()

@ -34,9 +34,9 @@ func ReadRemoteFiles(ctx context.Context, nodes []builder.Node, url string, name
var files []File var files []File
var node *builder.Node var node *builder.Node
for _, n := range nodes { for i, n := range nodes {
if n.Err == nil { if n.Err == nil {
node = &n node = &nodes[i]
continue continue
} }
} }

@ -64,7 +64,7 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
return res, nil return res, nil
} }
if sha, err := gitc.FullCommit(); err != nil { if sha, err := gitc.FullCommit(); err != nil && !gitutil.IsUnknownRevision(err) {
return res, errors.Wrapf(err, "buildx: failed to get git commit") return res, errors.Wrapf(err, "buildx: failed to get git commit")
} else if sha != "" { } else if sha != "" {
if gitc.IsDirty() { if gitc.IsDirty() {

@ -88,6 +88,9 @@ BuildKit currently supports:
Use `--attest=type=provenance` to generate provenance for an image at Use `--attest=type=provenance` to generate provenance for an image at
build-time. Alternatively, you can use the [`--provenance` shorthand](#provenance). build-time. Alternatively, you can use the [`--provenance` shorthand](#provenance).
By default, a minimal provenance attestation will be created for the build
result, which will only be attached for images pushed to registries.
For more information, see [here](https://docs.docker.com/build/attestations/slsa-provenance/). For more information, see [here](https://docs.docker.com/build/attestations/slsa-provenance/).
### <a name="allow"></a> Allow extra privileged entitlement (--allow) ### <a name="allow"></a> Allow extra privileged entitlement (--allow)
@ -477,8 +480,20 @@ $ docker buildx build --load --progress=plain .
### <a name="provenance"></a> Create provenance attestations (--provenance) ### <a name="provenance"></a> Create provenance attestations (--provenance)
Shorthand for [`--attest=type=provenance`](#attest). Enables provenance Shorthand for [`--attest=type=provenance`](#attest), used to configure
attestations for the build result. provenance attestations for the build result. For example,
`--provenance=mode=max` can be used as an abbreviation for
`--attest=type=provenance,mode=max`.
Additionally, `--provenance` can be used with boolean values to broadly enable
or disable provenance attestations. For example, `--provenance=false` can be
used to disable all provenance attestations, while `--provenance=true` can be
used to enable all provenance attestations.
By default, a minimal provenance attestation will be created for the build
result, which will only be attached for images pushed to registries.
For more information, see [here](https://docs.docker.com/build/attestations/slsa-provenance/).
### <a name="push"></a> Push the build result to a registry (--push) ### <a name="push"></a> Push the build result to a registry (--push)
@ -487,8 +502,16 @@ build result to registry.
### <a name="sbom"></a> Create SBOM attestations (--sbom) ### <a name="sbom"></a> Create SBOM attestations (--sbom)
Shorthand for [`--attest=type=sbom`](#attest). Enables SBOM attestations for Shorthand for [`--attest=type=sbom`](#attest), used to configure SBOM
the build result. attestations for the build result. For example,
`--sbom=generator=<user>/<generator-image>` can be used as an abbreviation for
`--attest=type=sbom,generator=<user>/<generator-image>`.
Additionally, `--sbom` can be used with boolean values to broadly enable or
disable SBOM attestations. For example, `--sbom=false` can be used to disable
all SBOM attestations.
For more information, see [here](https://docs.docker.com/build/attestations/sbom/).
### <a name="secret"></a> Secret to expose to the build (--secret) ### <a name="secret"></a> Secret to expose to the build (--secret)

@ -93,6 +93,7 @@ func GetNodeGroup(txn *store.Txn, dockerCli command.Cli, name string) (*store.No
Endpoint: name, Endpoint: name,
}, },
}, },
DockerContext: true,
} }
if ng.LastActivity, err = txn.GetLastActivity(ng); err != nil { if ng.LastActivity, err = txn.GetLastActivity(ng); err != nil {
return nil, err return nil, err

@ -3,6 +3,7 @@ package gitutil
import ( import (
"bytes" "bytes"
"context" "context"
"os"
"os/exec" "os/exec"
"strings" "strings"
@ -116,6 +117,9 @@ func (c *Git) run(args ...string) (string, error) {
cmd.Dir = c.wd cmd.Dir = c.wd
} }
// Override the locale to ensure consistent output
cmd.Env = append(os.Environ(), "LC_ALL=C")
stdout := bytes.Buffer{} stdout := bytes.Buffer{}
stderr := bytes.Buffer{} stderr := bytes.Buffer{}
cmd.Stdout = &stdout cmd.Stdout = &stdout
@ -134,3 +138,12 @@ func (c *Git) clean(out string, err error) (string, error) {
} }
return out, err return out, err
} }
func IsUnknownRevision(err error) bool {
if err == nil {
return false
}
// https://github.com/git/git/blob/a6a323b31e2bcbac2518bddec71ea7ad558870eb/setup.c#L204
errMsg := strings.ToLower(err.Error())
return strings.Contains(errMsg, "unknown revision or path not in the working tree") || strings.Contains(errMsg, "bad revision")
}

@ -46,6 +46,18 @@ func TestGitShortCommit(t *testing.T) {
require.Equal(t, 7, len(out)) require.Equal(t, 7, len(out))
} }
func TestGitFullCommitErr(t *testing.T) {
Mktmp(t)
c, err := New()
require.NoError(t, err)
GitInit(c, t)
_, err = c.FullCommit()
require.Error(t, err)
require.True(t, IsUnknownRevision(err))
}
func TestGitTagsPointsAt(t *testing.T) { func TestGitTagsPointsAt(t *testing.T) {
Mktmp(t) Mktmp(t)
c, err := New() c, err := New()

@ -21,8 +21,11 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
const ( var (
annotationReference = "vnd.docker.reference.digest" annotationReferences = []string{
"com.docker.reference.digest",
"vnd.docker.reference.digest", // TODO: deprecate/remove after migration to new annotation
}
) )
type contentCache interface { type contentCache interface {
@ -167,8 +170,13 @@ func (l *loader) fetch(ctx context.Context, fetcher remotes.Fetcher, desc ocispe
} }
r.mu.Unlock() r.mu.Unlock()
ref, ok := desc.Annotations[annotationReference] found := false
if ok { for _, annotationReference := range annotationReferences {
ref, ok := desc.Annotations[annotationReference]
if !ok {
continue
}
refdgst, err := digest.Parse(ref) refdgst, err := digest.Parse(ref)
if err != nil { if err != nil {
return err return err
@ -176,7 +184,10 @@ func (l *loader) fetch(ctx context.Context, fetcher remotes.Fetcher, desc ocispe
r.mu.Lock() r.mu.Lock()
r.refs[refdgst] = append(r.refs[refdgst], desc.Digest) r.refs[refdgst] = append(r.refs[refdgst], desc.Digest)
r.mu.Unlock() r.mu.Unlock()
} else { found = true
break
}
if !found {
p := desc.Platform p := desc.Platform
if p == nil { if p == nil {
p, err = l.readPlatformFromConfig(ctx, fetcher, mfst.Config) p, err = l.readPlatformFromConfig(ctx, fetcher, mfst.Config)

Loading…
Cancel
Save