Skip to content

Commit 71b2265

Browse files
committed
bake: set input:context for remote builds
Signed-off-by: CrazyMax <[email protected]>
1 parent 23c3c87 commit 71b2265

File tree

4 files changed

+165
-1
lines changed

4 files changed

+165
-1
lines changed

bake/bake.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/moby/buildkit/client"
3030
"github.com/moby/buildkit/client/llb"
3131
"github.com/moby/buildkit/session/auth/authprovider"
32+
"github.com/moby/buildkit/util/gitutil"
3233
"github.com/pkg/errors"
3334
"github.com/zclconf/go-cty/cty"
3435
"github.com/zclconf/go-cty/cty/convert"
@@ -1278,6 +1279,45 @@ func updateContext(t *build.Inputs, inp *Input) {
12781279
return
12791280
}
12801281

1282+
// formatGitURL converts a git URL to fragment format with only ref and
1283+
// adds the subdir if defined.
1284+
formatGitURL := func(url string, subdir string) string {
1285+
gitRef, err := gitutil.ParseURL(url)
1286+
if err == nil && gitRef != nil {
1287+
u := gitRef.Remote
1288+
var ref string
1289+
if gitRef.Opts != nil {
1290+
ref = gitRef.Opts.Ref
1291+
}
1292+
if len(gitRef.Query) > 0 {
1293+
for k, v := range gitRef.Query {
1294+
if len(v) == 0 {
1295+
continue
1296+
}
1297+
switch k {
1298+
case "ref":
1299+
ref = v[0]
1300+
case "branch":
1301+
ref = "refs/heads/" + v[0]
1302+
case "tag":
1303+
ref = "refs/tags/" + v[0]
1304+
}
1305+
}
1306+
}
1307+
if ref != "" {
1308+
u += "#" + ref
1309+
}
1310+
if subdir != "" && subdir != "." {
1311+
if ref == "" {
1312+
u += "#"
1313+
}
1314+
u += ":" + subdir
1315+
}
1316+
return u
1317+
}
1318+
return url
1319+
}
1320+
12811321
for k, v := range t.NamedContexts {
12821322
if v.Path == "." {
12831323
t.NamedContexts[k] = build.NamedContext{Path: inp.URL}
@@ -1289,7 +1329,7 @@ func updateContext(t *build.Inputs, inp *Input) {
12891329
continue
12901330
}
12911331
st := llb.Scratch().File(llb.Copy(*inp.State, v.Path, "/"), llb.WithCustomNamef("set context %s to %s", k, v.Path))
1292-
t.NamedContexts[k] = build.NamedContext{State: &st}
1332+
t.NamedContexts[k] = build.NamedContext{State: &st, Path: formatGitURL(inp.URL, v.Path)}
12931333
}
12941334

12951335
if t.ContextPath == "." {
@@ -1309,6 +1349,7 @@ func updateContext(t *build.Inputs, inp *Input) {
13091349
llb.WithCustomNamef("set context to %s", t.ContextPath),
13101350
)
13111351
t.ContextState = &st
1352+
t.ContextPath = formatGitURL(inp.URL, t.ContextPath)
13121353
}
13131354

13141355
func isRemoteContext(t build.Inputs, inp *Input) bool {

build/opt.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,9 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp *Inputs, pw pro
427427
}
428428
target.FrontendInputs["context"] = *inp.ContextState
429429
target.FrontendInputs["dockerfile"] = *inp.ContextState
430+
if IsRemoteURL(inp.ContextPath) {
431+
target.FrontendAttrs["input:context"] = inp.ContextPath
432+
}
430433
case inp.ContextPath == "-":
431434
if inp.DockerfilePath == "-" {
432435
return nil, errors.Errorf("invalid argument: can't use stdin for both build context and dockerfile")
@@ -543,6 +546,9 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp *Inputs, pw pro
543546
caps["moby.buildkit.frontend.contexts+forward"] = struct{}{}
544547
if v.State != nil {
545548
target.FrontendAttrs["context:"+k] = "input:" + k
549+
if IsRemoteURL(v.Path) {
550+
target.FrontendAttrs["input:git_state_"+k] = v.Path
551+
}
546552
if target.FrontendInputs == nil {
547553
target.FrontendInputs = make(map[string]llb.State)
548554
}

tests/bake.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
4141
testBakePrintSensitive,
4242
testBakePrintOverrideEmpty,
4343
testBakePrintKeepEscaped,
44+
testBakePrintRemoteContextSubdir,
4445
testBakeLocal,
4546
testBakeLocalMulti,
4647
testBakeRemote,
@@ -393,6 +394,56 @@ EOT
393394
require.NoError(t, err, string(out))
394395
}
395396

397+
func testBakePrintRemoteContextSubdir(t *testing.T, sb integration.Sandbox) {
398+
bakefile := []byte(`
399+
target default {
400+
context = "bar"
401+
}
402+
`)
403+
dockerfile := []byte(`
404+
FROM scratch
405+
COPY super-cool.txt /
406+
`)
407+
408+
dir := tmpdir(
409+
t,
410+
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
411+
fstest.CreateDir("bar", 0700),
412+
fstest.CreateFile("bar/Dockerfile", dockerfile, 0600),
413+
fstest.CreateFile("bar/super-cool.txt", []byte("super cool"), 0600),
414+
)
415+
416+
git, err := gitutil.New(gitutil.WithWorkingDir(dir))
417+
require.NoError(t, err)
418+
gittestutil.GitInit(git, t)
419+
gittestutil.GitAdd(git, t, "docker-bake.hcl", "bar")
420+
gittestutil.GitCommit(git, t, "initial commit")
421+
addr := gittestutil.GitServeHTTP(git, t)
422+
423+
cmd := buildxCmd(sb, withDir("/tmp"), withArgs("bake", addr, "--print"))
424+
stdout := bytes.Buffer{}
425+
stderr := bytes.Buffer{}
426+
cmd.Stdout = &stdout
427+
cmd.Stderr = &stderr
428+
require.NoError(t, cmd.Run(), stdout.String(), stderr.String())
429+
430+
require.JSONEq(t, fmt.Sprintf(`{
431+
"group": {
432+
"default": {
433+
"targets": [
434+
"default"
435+
]
436+
}
437+
},
438+
"target": {
439+
"default": {
440+
"context": %q,
441+
"dockerfile": "Dockerfile"
442+
}
443+
}
444+
}`, addr+"#:bar"), stdout.String())
445+
}
446+
396447
func testBakeLocal(t *testing.T, sb integration.Sandbox) {
397448
dockerfile := []byte(`
398449
FROM scratch

tests/history.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,72 @@ COPY foo /foo
240240
require.Equal(t, md.BuildRef, rec.Ref)
241241
require.Equal(t, addr+"?ref=main", rec.Name)
242242
})
243+
244+
t.Run("bake git", func(t *testing.T) {
245+
bakefile := []byte(`
246+
target "default" {
247+
dockerfile-inline = <<EOT
248+
FROM scratch
249+
COPY foo /foo
250+
EOT
251+
}
252+
`)
253+
dir := tmpdir(
254+
t,
255+
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
256+
fstest.CreateFile("foo", []byte("foo"), 0600),
257+
)
258+
dirDest := t.TempDir()
259+
260+
git, err := gitutil.New(gitutil.WithWorkingDir(dir))
261+
require.NoError(t, err)
262+
263+
gittestutil.GitInit(git, t)
264+
gittestutil.GitAdd(git, t, "docker-bake.hcl", "foo")
265+
gittestutil.GitCommit(git, t, "initial commit")
266+
addr := gittestutil.GitServeHTTP(git, t)
267+
268+
out, err := bakeCmd(sb, withDir(dir),
269+
withArgs(addr, "--set", "*.output=type=local,dest="+dirDest, "--metadata-file", filepath.Join(dir, "md.json")),
270+
)
271+
require.NoError(t, err, out)
272+
require.FileExists(t, filepath.Join(dirDest, "foo"))
273+
274+
dt, err := os.ReadFile(filepath.Join(dir, "md.json"))
275+
require.NoError(t, err)
276+
277+
type mdT struct {
278+
Default struct {
279+
BuildRef string `json:"buildx.build.ref"`
280+
} `json:"default"`
281+
}
282+
var md mdT
283+
err = json.Unmarshal(dt, &md)
284+
require.NoError(t, err)
285+
286+
refParts := strings.Split(md.Default.BuildRef, "/")
287+
require.Len(t, refParts, 3)
288+
289+
cmd := buildxCmd(sb, withArgs("history", "ls", "--filter=ref="+refParts[2], "--format=json"))
290+
bout, err := cmd.Output()
291+
require.NoError(t, err, string(bout))
292+
293+
type recT struct {
294+
Ref string `json:"ref"`
295+
Name string `json:"name"`
296+
Status string `json:"status"`
297+
CreatedAt *time.Time `json:"created_at"`
298+
CompletedAt *time.Time `json:"completed_at"`
299+
TotalSteps int32 `json:"total_steps"`
300+
CompletedSteps int32 `json:"completed_steps"`
301+
CachedSteps int32 `json:"cached_steps"`
302+
}
303+
var rec recT
304+
err = json.Unmarshal(bout, &rec)
305+
require.NoError(t, err)
306+
require.Equal(t, md.Default.BuildRef, rec.Ref)
307+
require.Equal(t, addr, rec.Name)
308+
})
243309
}
244310

245311
type buildRef struct {

0 commit comments

Comments
 (0)