Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions client/llb/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ func TestGit(t *testing.T) {
"git.fullurl": "https://github.com/foo/bar.git",
},
},
{
name: "debug commands",
st: Git("github.com/foo/bar.git", "ref", GitDebugCommands()),
identifier: "git://github.com/foo/bar.git#ref",
attrs: map[string]string{
"git.authheadersecret": "GIT_AUTH_HEADER",
"git.authtokensecret": "GIT_AUTH_TOKEN",
"git.debugcommands": "true",
"git.fullurl": "https://github.com/foo/bar.git",
},
},
}

for _, tc := range tcases {
Expand Down
12 changes: 11 additions & 1 deletion client/llb/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,11 +470,14 @@ func Git(url, fragment string, opts ...GitOption) State {
attrs[pb.AttrGitChecksum] = checksum
addCap(&gi.Constraints, pb.CapSourceGitChecksum)
}

if gi.SkipSubmodules {
attrs[pb.AttrGitSkipSubmodules] = "true"
addCap(&gi.Constraints, pb.CapSourceGitSkipSubmodules)
}
if gi.DebugCommands {
attrs[pb.AttrGitDebugCommands] = "true"
addCap(&gi.Constraints, pb.CapSourceGitDebugCommands)
}

addCap(&gi.Constraints, pb.CapSourceGit)

Expand Down Expand Up @@ -503,6 +506,7 @@ type GitInfo struct {
Ref string
SubDir string
SkipSubmodules bool
DebugCommands bool
}

func GitRef(v string) GitOption {
Expand All @@ -529,6 +533,12 @@ func KeepGitDir() GitOption {
})
}

func GitDebugCommands() GitOption {
return gitOptionFunc(func(gi *GitInfo) {
gi.DebugCommands = true
})
}

func AuthTokenSecret(v string) GitOption {
return gitOptionFunc(func(gi *GitInfo) {
gi.AuthTokenSecret = v
Expand Down
21 changes: 11 additions & 10 deletions frontend/dockerfile/docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2715,16 +2715,17 @@ RUN echo "I'm building for $TARGETPLATFORM"

### BuildKit built-in build args

| Arg | Type | Description |
|----------------------------------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `BUILDKIT_BUILD_NAME` | String | Override the build name shown in [`buildx history` command](https://docs.docker.com/reference/cli/docker/buildx/history/) and [Docker Desktop Builds view](https://docs.docker.com/desktop/use-desktop/builds/). |
| `BUILDKIT_CACHE_MOUNT_NS` | String | Set optional cache ID namespace. |
| `BUILDKIT_CONTEXT_KEEP_GIT_DIR` | Bool | Trigger Git context to keep the `.git` directory. |
| `BUILDKIT_INLINE_CACHE`[^2] | Bool | Inline cache metadata to image config or not. |
| `BUILDKIT_MULTI_PLATFORM` | Bool | Opt into deterministic output regardless of multi-platform output or not. |
| `BUILDKIT_SANDBOX_HOSTNAME` | String | Set the hostname (default `buildkitsandbox`) |
| `BUILDKIT_SYNTAX` | String | Set frontend image |
| `SOURCE_DATE_EPOCH` | Int | Set the Unix timestamp for created image and layers. More info from [reproducible builds](https://reproducible-builds.org/docs/source-date-epoch/). Supported since Dockerfile 1.5, BuildKit 0.11 |
| Arg | Type | Description |
|---------------------------------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `BUILDKIT_BUILD_NAME` | String | Override the build name shown in [`buildx history` command](https://docs.docker.com/reference/cli/docker/buildx/history/) and [Docker Desktop Builds view](https://docs.docker.com/desktop/use-desktop/builds/). |
| `BUILDKIT_CACHE_MOUNT_NS` | String | Set optional cache ID namespace. |
| `BUILDKIT_CONTEXT_KEEP_GIT_DIR` | Bool | Trigger Git context to keep the `.git` directory. |
| `BUILDKIT_DEBUG_GIT_COMMANDS` | Bool | Trigger Git context to print executed Git commands in the build log. |
| `BUILDKIT_INLINE_CACHE`[^2] | Bool | Inline cache metadata to image config or not. |
| `BUILDKIT_MULTI_PLATFORM` | Bool | Opt into deterministic output regardless of multi-platform output or not. |
| `BUILDKIT_SANDBOX_HOSTNAME` | String | Set the hostname (default `buildkitsandbox`) |
| `BUILDKIT_SYNTAX` | String | Set frontend image |
| `SOURCE_DATE_EPOCH` | Int | Set the Unix timestamp for created image and layers. More info from [reproducible builds](https://reproducible-builds.org/docs/source-date-epoch/). Supported since Dockerfile 1.5, BuildKit 0.11 |

#### Example: keep `.git` dir

Expand Down
66 changes: 66 additions & 0 deletions frontend/dockerui/build_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package dockerui

import (
"context"
"testing"

"github.com/containerd/platforms"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/solver/pb"
digest "github.com/opencontainers/go-digest"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -98,3 +102,65 @@ func TestNormalizePlatform(t *testing.T) {
require.Equal(t, platforms.FormatAll(platforms.Normalize(tc.p)), tc.expected.ID)
}
}

func TestDetectGitContextForwardsDebugCommands(t *testing.T) {
t.Parallel()

enabled := true
st, ok, err := DetectGitContext("https://github.com/docker/buildx.git?ref=refs/pull/3732/merge", nil, &enabled)
require.True(t, ok)
require.NoError(t, err)

g := marshalGitContext(t, st)
require.Equal(t, "git://github.com/docker/buildx.git#refs/pull/3732/merge", g.Identifier)
require.Equal(t, map[string]string{
"git.authheadersecret": "GIT_AUTH_HEADER",
"git.authtokensecret": "GIT_AUTH_TOKEN",
"git.debugcommands": "true",
"git.fullurl": "https://github.com/docker/buildx.git",
}, g.Attrs)
}

func marshalGitContext(t *testing.T, st *llb.State) *pb.SourceOp {
t.Helper()

def, err := st.Marshal(context.TODO())
require.NoError(t, err)

m, arr := parseDef(t, def.Def)
require.Equal(t, 2, len(arr))

dgst, idx := last(t, arr)
require.Equal(t, 0, idx)
require.Equal(t, m[dgst], arr[0])

return arr[0].Op.(*pb.Op_Source).Source
}

func parseDef(t *testing.T, def [][]byte) (map[string]*pb.Op, []*pb.Op) {
t.Helper()

m := map[string]*pb.Op{}
arr := make([]*pb.Op, 0, len(def))

for _, dt := range def {
var op pb.Op
err := op.Unmarshal(dt)
require.NoError(t, err)
dgst := digest.FromBytes(dt)
m[string(dgst)] = &op
arr = append(arr, &op)
}

return m, arr
}

func last(t *testing.T, arr []*pb.Op) (string, int) {
t.Helper()

require.Greater(t, len(arr), 1)

op := arr[len(arr)-1]
require.Equal(t, 1, len(op.Inputs))
return op.Inputs[0].Digest, int(op.Inputs[0].Index)
}
1 change: 1 addition & 0 deletions frontend/dockerui/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const (
keyHostnameArg = "build-arg:BUILDKIT_SANDBOX_HOSTNAME"
keyDockerfileLintArg = "build-arg:BUILDKIT_DOCKERFILE_CHECK"
keyContextKeepGitDirArg = "build-arg:BUILDKIT_CONTEXT_KEEP_GIT_DIR"
keyDebugGitCommandsArg = "build-arg:BUILDKIT_DEBUG_GIT_COMMANDS"
keySourceDateEpoch = "build-arg:SOURCE_DATE_EPOCH"
)

Expand Down
11 changes: 9 additions & 2 deletions frontend/dockerui/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ func (bc *Client) initContext(ctx context.Context) (*buildContext, error) {
if v, err := strconv.ParseBool(opts[keyContextKeepGitDirArg]); err == nil {
keepGit = &v
}
if st, ok, err := DetectGitContext(opts[localNameContext], keepGit); ok {
var debugGitCommands *bool
if v, err := strconv.ParseBool(opts[keyDebugGitCommandsArg]); err == nil {
debugGitCommands = &v
}
if st, ok, err := DetectGitContext(opts[localNameContext], keepGit, debugGitCommands); ok {
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -143,7 +147,7 @@ func (bc *Client) initContext(ctx context.Context) (*buildContext, error) {
return bctx, nil
}

func DetectGitContext(ref string, keepGit *bool) (*llb.State, bool, error) {
func DetectGitContext(ref string, keepGit *bool, debugGitCommands *bool) (*llb.State, bool, error) {
g, isGit, err := dfgitutil.ParseGitRef(ref)
if err != nil {
return nil, isGit, err
Expand All @@ -158,6 +162,9 @@ func DetectGitContext(ref string, keepGit *bool) (*llb.State, bool, error) {
if keepGit != nil && *keepGit {
gitOpts = append(gitOpts, llb.KeepGitDir())
}
if debugGitCommands != nil && *debugGitCommands {
gitOpts = append(gitOpts, llb.GitDebugCommands())
}
if g.SubDir != "" {
gitOpts = append(gitOpts, llb.GitSubDir(g.SubDir))
}
Expand Down
4 changes: 2 additions & 2 deletions frontend/dockerui/namedcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (nc *NamedContext) load(ctx context.Context, count int) (*llb.State, *docke
}
return &st, &img, nil
case "git":
st, ok, err := DetectGitContext(nc.input, nil)
st, ok, err := DetectGitContext(nc.input, nil, nil)
if !ok {
return nil, nil, errors.Errorf("invalid git context %s", nc.input)
}
Expand All @@ -150,7 +150,7 @@ func (nc *NamedContext) load(ctx context.Context, count int) (*llb.State, *docke
}
return st, nil, nil
case "http", "https":
st, ok, err := DetectGitContext(nc.input, nil)
st, ok, err := DetectGitContext(nc.input, nil, nil)
if !ok {
httpst := llb.HTTP(nc.input, llb.WithCustomName("[context "+nc.nameWithPlatform+"] "+nc.input))
st = &httpst
Expand Down
1 change: 1 addition & 0 deletions solver/pb/attr.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const AttrKnownSSHHosts = "git.knownsshhosts"
const AttrMountSSHSock = "git.mountsshsock"
const AttrGitChecksum = "git.checksum"
const AttrGitSkipSubmodules = "git.skipsubmodules"
const AttrGitDebugCommands = "git.debugcommands"

const AttrGitSignatureVerifyPubKey = "git.sig.pubkey"
const AttrGitSignatureVerifyRejectExpired = "git.sig.rejectexpired"
Expand Down
7 changes: 7 additions & 0 deletions solver/pb/caps.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const (
CapSourceGitSubdir apicaps.CapID = "source.git.subdir"
CapSourceGitChecksum apicaps.CapID = "source.git.checksum"
CapSourceGitSkipSubmodules apicaps.CapID = "source.git.skipsubmodules"
CapSourceGitDebugCommands apicaps.CapID = "source.git.debugcommands"
CapSourceGitSignatureVerify apicaps.CapID = "source.git.signatureverify"

CapSourceHTTP apicaps.CapID = "source.http"
Expand Down Expand Up @@ -249,6 +250,12 @@ func init() {
Status: apicaps.CapStatusExperimental,
})

Caps.Init(apicaps.Cap{
ID: CapSourceGitDebugCommands,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})

Caps.Init(apicaps.Cap{
ID: CapSourceGitSignatureVerify,
Enabled: true,
Expand Down
1 change: 1 addition & 0 deletions source/git/identifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type GitIdentifier struct {
MountSSHSock string
KnownSSHHosts string
SkipSubmodules bool
DebugCommands bool

VerifySignature *GitSignatureVerifyOptions
}
Expand Down
10 changes: 8 additions & 2 deletions source/git/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ func (gs *Source) Identifier(scheme, ref string, attrs map[string]string, platfo
if v == "true" {
id.SkipSubmodules = true
}
case pb.AttrGitDebugCommands:
if v == "true" {
id.DebugCommands = true
}
case pb.AttrGitSignatureVerifyPubKey:
if id.VerifySignature == nil {
id.VerifySignature = &GitSignatureVerifyOptions{}
Expand Down Expand Up @@ -141,7 +145,7 @@ func (gs *Source) Identifier(scheme, ref string, attrs map[string]string, platfo
}

// needs to be called with repo lock
func (gs *Source) mountRemote(ctx context.Context, remote string, authArgs []string, sha256 bool, reset bool, g session.Group) (target string, release func() error, retErr error) {
func (gs *Source) mountRemote(ctx context.Context, remote string, authArgs []string, debugCommands bool, sha256 bool, reset bool, g session.Group) (target string, release func() error, retErr error) {
sis, err := searchGitRemote(ctx, gs.cache, remote)
if err != nil {
return "", nil, errors.Wrapf(err, "failed to search metadata for %s", urlutil.RedactCredentials(remote))
Expand Down Expand Up @@ -206,6 +210,7 @@ func (gs *Source) mountRemote(ctx context.Context, remote string, authArgs []str
git := gitCLI(
gitutil.WithGitDir(dir),
gitutil.WithArgs(authArgs...),
gitutil.WithDebugCommands(debugCommands),
)

if initializeRepo {
Expand Down Expand Up @@ -844,7 +849,7 @@ func (gs *gitSourceHandler) tryRemoteFetch(ctx context.Context, g session.Group,
}
repo.releasers = append(repo.releasers, cleanup)

gitDir, unmountGitDir, err := gs.mountRemote(ctx, gs.src.Remote, gs.authArgs, gs.sha256, reset, g)
gitDir, unmountGitDir, err := gs.mountRemote(ctx, gs.src.Remote, gs.authArgs, gs.src.DebugCommands, gs.sha256, reset, g)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1207,6 +1212,7 @@ func (gs *gitSourceHandler) emptyGitCli(ctx context.Context, g session.Group, op

opts = append([]gitutil.Option{
gitutil.WithArgs(gs.authArgs...),
gitutil.WithDebugCommands(gs.src.DebugCommands),
gitutil.WithSSHAuthSock(sock),
gitutil.WithSSHKnownHosts(knownHosts),
}, opts...)
Expand Down
Loading
Loading