Merge pull request #3726 from crazy-max/buildkit-git-cli

gitutil: migrate to BuildKit GitCLI API
This commit is contained in:
Tõnis Tiigi
2026-04-15 09:52:53 -07:00
committed by GitHub
17 changed files with 213 additions and 229 deletions
+8 -6
View File
@@ -12,6 +12,7 @@ import (
"github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/gitutil"
"github.com/docker/buildx/util/osutil" "github.com/docker/buildx/util/osutil"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
bkgitutil "github.com/moby/buildkit/util/gitutil"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1" ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@@ -61,7 +62,7 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) (
} }
wd = osutil.SanitizePath(wd) wd = osutil.SanitizePath(wd)
gitc, err := gitutil.New(gitutil.WithContext(ctx), gitutil.WithWorkingDir(wd)) gitc, err := gitutil.New(bkgitutil.WithDir(wd))
if err != nil { if err != nil {
if st, err1 := os.Stat(path.Join(wd, ".git")); err1 == nil && st.IsDir() { if st, err1 := os.Stat(path.Join(wd, ".git")); err1 == nil && st.IsDir() {
return nil, errors.Wrap(err, "git was not found in the system") return nil, errors.Wrap(err, "git was not found in the system")
@@ -69,21 +70,22 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) (
return nil, nil return nil, nil
} }
if !gitc.IsInsideWorkTree() { if !gitc.IsInsideWorkTree(ctx) {
if st, err := os.Stat(path.Join(wd, ".git")); err == nil && st.IsDir() { if st, err := os.Stat(path.Join(wd, ".git")); err == nil && st.IsDir() {
return nil, errors.New("failed to read current commit information with git rev-parse --is-inside-work-tree") return nil, errors.New("failed to read current commit information with git rev-parse --is-inside-work-tree")
} }
return nil, nil return nil, nil
} }
root, err := gitc.RootDir() root, err := gitc.WorkTree(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to get git root dir") return nil, errors.Wrap(err, "failed to get git root dir")
} }
root = osutil.SanitizePath(root)
res := make(map[string]string) res := make(map[string]string)
if sha, err := gitc.FullCommit(); err != nil && !gitutil.IsUnknownRevision(err) { if sha, err := gitc.FullCommit(ctx); err != nil && !gitutil.IsUnknownRevision(err) {
return nil, errors.Wrap(err, "failed to get git commit") return nil, errors.Wrap(err, "failed to get git commit")
} else if sha != "" { } else if sha != "" {
checkDirty := false checkDirty := false
@@ -92,7 +94,7 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) (
checkDirty = v checkDirty = v
} }
} }
if checkDirty && gitc.IsDirty() { if checkDirty && gitc.IsDirty(ctx) {
sha += "-dirty" sha += "-dirty"
} }
if setGitLabels { if setGitLabels {
@@ -103,7 +105,7 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) (
} }
} }
if rurl, err := gitc.RemoteURL(); err == nil && rurl != "" { if rurl, err := gitc.RemoteURL(ctx); err == nil && rurl != "" {
if setGitLabels { if setGitLabels {
res["label:"+ocispecs.AnnotationSource] = rurl res["label:"+ocispecs.AnnotationSource] = rurl
} }
+3 -2
View File
@@ -20,6 +20,7 @@ import (
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/formatter"
"github.com/docker/go-units" "github.com/docker/go-units"
bkgitutil "github.com/moby/buildkit/util/gitutil"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -59,14 +60,14 @@ func runLs(ctx context.Context, dockerCli command.Cli, opts lsOptions) error {
if err != nil { if err != nil {
return err return err
} }
gitc, err := gitutil.New(gitutil.WithContext(ctx), gitutil.WithWorkingDir(wd)) gitc, err := gitutil.New(bkgitutil.WithDir(wd))
if err != nil { if err != nil {
if st, err1 := os.Stat(path.Join(wd, ".git")); err1 == nil && st.IsDir() { if st, err1 := os.Stat(path.Join(wd, ".git")); err1 == nil && st.IsDir() {
return errors.Wrap(err, "git was not found in the system") return errors.Wrap(err, "git was not found in the system")
} }
return errors.Wrapf(err, "could not find git repository for local filter") return errors.Wrapf(err, "could not find git repository for local filter")
} }
remote, err := gitc.RemoteURL() remote, err := gitc.RemoteURL(ctx)
if err != nil { if err != nil {
return errors.Wrapf(err, "could not get remote URL for local filter") return errors.Wrapf(err, "could not get remote URL for local filter")
} }
+1 -1
View File
@@ -30,7 +30,7 @@ require (
github.com/hashicorp/hcl/v2 v2.24.0 github.com/hashicorp/hcl/v2 v2.24.0
github.com/in-toto/in-toto-golang v0.10.0 github.com/in-toto/in-toto-golang v0.10.0
github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/moby/buildkit v0.29.0 github.com/moby/buildkit v0.29.1-0.20260408185135-a243ce438aee
github.com/moby/go-archive v0.2.0 github.com/moby/go-archive v0.2.0
github.com/moby/moby/api v1.54.1 github.com/moby/moby/api v1.54.1
github.com/moby/moby/client v0.4.0 github.com/moby/moby/client v0.4.0
+2 -2
View File
@@ -420,8 +420,8 @@ github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/buildkit v0.29.0 h1:wxLEFbCOJntEDjSNNN2YWd8zxltZxT5muDQ0LzpbtpU= github.com/moby/buildkit v0.29.1-0.20260408185135-a243ce438aee h1:hA4wfynYJPaSnE4r1Ak5t/9goiG+OBKdQT29ZNxONrc=
github.com/moby/buildkit v0.29.0/go.mod h1:Dmv2FeDe34t75QuzeU87rBoZpAAkcpT5zeu4hXzmASc= github.com/moby/buildkit v0.29.1-0.20260408185135-a243ce438aee/go.mod h1:afndr4EIChUihZio6mhkfTePNtO6KOJh4qW7zOXHhW0=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8= github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
+15 -14
View File
@@ -23,6 +23,7 @@ import (
"github.com/moby/buildkit/identity" "github.com/moby/buildkit/identity"
provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types" provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types"
"github.com/moby/buildkit/util/contentutil" "github.com/moby/buildkit/util/contentutil"
bkgitutil "github.com/moby/buildkit/util/gitutil"
"github.com/moby/buildkit/util/testutil" "github.com/moby/buildkit/util/testutil"
"github.com/moby/buildkit/util/testutil/integration" "github.com/moby/buildkit/util/testutil/integration"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -551,7 +552,7 @@ COPY super-cool.txt /
fstest.CreateFile("bar/super-cool.txt", []byte("super cool"), 0600), fstest.CreateFile("bar/super-cool.txt", []byte("super cool"), 0600),
) )
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
gittestutil.GitAdd(git, t, "docker-bake.hcl", "bar") gittestutil.GitAdd(git, t, "docker-bake.hcl", "bar")
@@ -688,7 +689,7 @@ EOT
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -718,7 +719,7 @@ EOT
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -765,7 +766,7 @@ EOT
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) git, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -834,7 +835,7 @@ EOT
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) git, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -868,14 +869,14 @@ EOT
) )
dirDest := t.TempDir() dirDest := t.TempDir()
gitSpec, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) gitSpec, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(gitSpec, t) gittestutil.GitInit(gitSpec, t)
gittestutil.GitAdd(gitSpec, t, "docker-bake.hcl") gittestutil.GitAdd(gitSpec, t, "docker-bake.hcl")
gittestutil.GitCommit(gitSpec, t, "initial commit") gittestutil.GitCommit(gitSpec, t, "initial commit")
addrSpec := gittestutil.GitServeHTTP(gitSpec, t) addrSpec := gittestutil.GitServeHTTP(gitSpec, t)
gitSrc, err := gitutil.New(gitutil.WithWorkingDir(dirSrc)) gitSrc, err := gitutil.New(bkgitutil.WithDir(dirSrc))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(gitSrc, t) gittestutil.GitInit(gitSrc, t)
gittestutil.GitAdd(gitSrc, t, "foo") gittestutil.GitAdd(gitSrc, t, "foo")
@@ -909,7 +910,7 @@ COPY super-cool.txt /
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
gittestutil.GitAdd(git, t, "docker-bake.hcl", "bar") gittestutil.GitAdd(git, t, "docker-bake.hcl", "bar")
@@ -948,7 +949,7 @@ COPY --from=files file.txt /file.txt
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
gittestutil.GitAdd(git, t, "docker-bake.hcl", "build", "files-src") gittestutil.GitAdd(git, t, "docker-bake.hcl", "build", "files-src")
@@ -984,7 +985,7 @@ COPY --from=files marker.txt /marker.txt
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
gittestutil.GitAdd(git, t, "docker-bake.hcl", "build", "marker.txt") gittestutil.GitAdd(git, t, "docker-bake.hcl", "build", "marker.txt")
@@ -1023,7 +1024,7 @@ EOT
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) git, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -1071,7 +1072,7 @@ EOT
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) git, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -1127,7 +1128,7 @@ COPY foo /foo
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) git, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -1179,7 +1180,7 @@ COPY foo /foo
fstest.CreateFile("foo", []byte("foo"), 0600), fstest.CreateFile("foo", []byte("foo"), 0600),
) )
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) git, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
+8 -7
View File
@@ -28,6 +28,7 @@ import (
provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types" provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types"
"github.com/moby/buildkit/util/appdefaults" "github.com/moby/buildkit/util/appdefaults"
"github.com/moby/buildkit/util/contentutil" "github.com/moby/buildkit/util/contentutil"
bkgitutil "github.com/moby/buildkit/util/gitutil"
"github.com/moby/buildkit/util/testutil" "github.com/moby/buildkit/util/testutil"
"github.com/moby/buildkit/util/testutil/integration" "github.com/moby/buildkit/util/testutil/integration"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
@@ -130,7 +131,7 @@ COPY foo /foo
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -155,7 +156,7 @@ COPY foo /foo
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -182,7 +183,7 @@ COPY foo /foo
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -215,7 +216,7 @@ COPY foo /foo
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -248,7 +249,7 @@ COPY foo /foo
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -281,7 +282,7 @@ COPY foo /foo
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -403,7 +404,7 @@ COPY foo /foo
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
+3 -2
View File
@@ -12,6 +12,7 @@ import (
"github.com/containerd/continuity/fs/fstest" "github.com/containerd/continuity/fs/fstest"
"github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/gitutil"
"github.com/docker/buildx/util/gitutil/gittestutil" "github.com/docker/buildx/util/gitutil/gittestutil"
bkgitutil "github.com/moby/buildkit/util/gitutil"
"github.com/moby/buildkit/util/testutil/integration" "github.com/moby/buildkit/util/testutil/integration"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -196,7 +197,7 @@ COPY foo /foo
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -245,7 +246,7 @@ EOT
) )
dirDest := t.TempDir() dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir)) git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
+11 -6
View File
@@ -3,6 +3,7 @@ package tests
import ( import (
"archive/tar" "archive/tar"
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@@ -20,6 +21,7 @@ import (
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
"github.com/moby/buildkit/identity" "github.com/moby/buildkit/identity"
"github.com/moby/buildkit/util/contentutil" "github.com/moby/buildkit/util/contentutil"
bkgitutil "github.com/moby/buildkit/util/gitutil"
"github.com/moby/buildkit/util/testutil" "github.com/moby/buildkit/util/testutil"
"github.com/moby/buildkit/util/testutil/httpserver" "github.com/moby/buildkit/util/testutil/httpserver"
"github.com/moby/buildkit/util/testutil/integration" "github.com/moby/buildkit/util/testutil/integration"
@@ -822,7 +824,7 @@ func testBuildPolicyGit(t *testing.T, sb integration.Sandbox) {
require.NoError(t, os.WriteFile(filepath.Join(gitDir, "Dockerfile"), []byte("FROM busybox:latest\nRUN echo git\n"), 0600)) require.NoError(t, os.WriteFile(filepath.Join(gitDir, "Dockerfile"), []byte("FROM busybox:latest\nRUN echo git\n"), 0600))
require.NoError(t, os.WriteFile(filepath.Join(gitDir, "a"), []byte("a"), 0600)) require.NoError(t, os.WriteFile(filepath.Join(gitDir, "a"), []byte("a"), 0600))
git, err := gitutil.New(gitutil.WithWorkingDir(gitDir)) git, err := gitutil.New(bkgitutil.WithDir(gitDir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
@@ -834,15 +836,18 @@ func testBuildPolicyGit(t *testing.T, sb integration.Sandbox) {
require.NoError(t, os.WriteFile(filepath.Join(gitDir, "b"), []byte("b"), 0600)) require.NoError(t, os.WriteFile(filepath.Join(gitDir, "b"), []byte("b"), 0600))
gittestutil.GitAdd(git, t, "b") gittestutil.GitAdd(git, t, "b")
gittestutil.GitCommit(git, t, "b") gittestutil.GitCommit(git, t, "b")
_, err = git.Run("checkout", "-B", "v2") _, err = git.Run(context.TODO(), "checkout", "-B", "v2")
require.NoError(t, err) require.NoError(t, err)
commitHead, err := git.Run("rev-parse", "HEAD") commitHeadB, err := git.Run(context.TODO(), "rev-parse", "HEAD")
require.NoError(t, err) require.NoError(t, err)
commitTag, err := git.Run("rev-parse", "v0.1") commitHead := strings.TrimSpace(string(commitHeadB))
commitTagB, err := git.Run(context.TODO(), "rev-parse", "v0.1")
require.NoError(t, err) require.NoError(t, err)
commitTagCommit, err := git.Run("rev-parse", "v0.1^{commit}") commitTag := strings.TrimSpace(string(commitTagB))
commitTagCommitB, err := git.Run(context.TODO(), "rev-parse", "v0.1^{commit}")
require.NoError(t, err) require.NoError(t, err)
commitTagCommit := strings.TrimSpace(string(commitTagCommitB))
baseURL := gittestutil.GitServeHTTP(git, t) baseURL := gittestutil.GitServeHTTP(git, t)
tagURL := baseURL + "#v0.1" tagURL := baseURL + "#v0.1"
branchURL := baseURL + "#v2" branchURL := baseURL + "#v2"
@@ -1318,7 +1323,7 @@ default allow = true
decision := {"allow": allow} decision := {"allow": allow}
`), 0600)) `), 0600))
git, err := gitutil.New(gitutil.WithWorkingDir(gitDir)) git, err := gitutil.New(bkgitutil.WithDir(gitDir))
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(git, t) gittestutil.GitInit(git, t)
gittestutil.GitAdd(git, t, ".") gittestutil.GitAdd(git, t, ".")
-44
View File
@@ -1,44 +0,0 @@
package gitutil
import "testing"
func TestStripCredentials(t *testing.T) {
cases := []struct {
name string
url string
want string
}{
{
name: "non-blank Password",
url: "https://user:password@host.tld/this:that",
want: "https://host.tld/this:that",
},
{
name: "blank Password",
url: "https://user@host.tld/this:that",
want: "https://host.tld/this:that",
},
{
name: "blank Username",
url: "https://:password@host.tld/this:that",
want: "https://host.tld/this:that",
},
{
name: "blank Username, blank Password",
url: "https://host.tld/this:that",
want: "https://host.tld/this:that",
},
{
name: "invalid URL",
url: "1https://foo.com",
want: "1https://foo.com",
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
if g, w := stripCredentials(tt.url), tt.want; g != w {
t.Fatalf("got: %q\nwant: %q", g, w)
}
})
}
}
+20 -10
View File
@@ -1,15 +1,17 @@
package gittestutil package gittestutil
import ( import (
"context"
"os" "os"
"strings" "strings"
"testing" "testing"
"github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/gitutil"
"github.com/pkg/errors"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func GitInit(c *gitutil.Git, tb testing.TB) { func GitInit(c *gitutil.GitCLI, tb testing.TB) {
tb.Helper() tb.Helper()
out, err := fakeGit(c, "init") out, err := fakeGit(c, "init")
require.NoError(tb, err) require.NoError(tb, err)
@@ -19,48 +21,48 @@ func GitInit(c *gitutil.Git, tb testing.TB) {
_, _ = fakeGit(c, "branch", "-D", "master") _, _ = fakeGit(c, "branch", "-D", "master")
} }
func GitCommit(c *gitutil.Git, tb testing.TB, msg string) { func GitCommit(c *gitutil.GitCLI, tb testing.TB, msg string) {
tb.Helper() tb.Helper()
out, err := fakeGit(c, "commit", "--allow-empty", "-m", msg) out, err := fakeGit(c, "commit", "--allow-empty", "-m", msg)
require.NoError(tb, err) require.NoError(tb, err)
require.Contains(tb, out, "main", msg) require.Contains(tb, out, "main", msg)
} }
func GitTag(c *gitutil.Git, tb testing.TB, tag string) { func GitTag(c *gitutil.GitCLI, tb testing.TB, tag string) {
tb.Helper() tb.Helper()
out, err := fakeGit(c, "tag", tag) out, err := fakeGit(c, "tag", tag)
require.NoError(tb, err) require.NoError(tb, err)
require.Empty(tb, out) require.Empty(tb, out)
} }
func GitTagAnnotated(c *gitutil.Git, tb testing.TB, tag, message string) { func GitTagAnnotated(c *gitutil.GitCLI, tb testing.TB, tag, message string) {
tb.Helper() tb.Helper()
out, err := fakeGit(c, "tag", "-a", tag, "-m", message) out, err := fakeGit(c, "tag", "-a", tag, "-m", message)
require.NoError(tb, err) require.NoError(tb, err)
require.Empty(tb, out) require.Empty(tb, out)
} }
func GitCheckoutBranch(c *gitutil.Git, tb testing.TB, name string) { func GitCheckoutBranch(c *gitutil.GitCLI, tb testing.TB, name string) {
tb.Helper() tb.Helper()
out, err := fakeGit(c, "checkout", "-b", name) out, err := fakeGit(c, "checkout", "-b", name)
require.NoError(tb, err) require.NoError(tb, err)
require.Empty(tb, out) require.Empty(tb, out)
} }
func GitAdd(c *gitutil.Git, tb testing.TB, files ...string) { func GitAdd(c *gitutil.GitCLI, tb testing.TB, files ...string) {
tb.Helper() tb.Helper()
args := append([]string{"add"}, files...) args := append([]string{"add"}, files...)
_, err := fakeGit(c, args...) _, err := fakeGit(c, args...)
require.NoError(tb, err) require.NoError(tb, err)
} }
func GitSetRemote(c *gitutil.Git, tb testing.TB, name string, url string) { func GitSetRemote(c *gitutil.GitCLI, tb testing.TB, name string, url string) {
tb.Helper() tb.Helper()
_, err := fakeGit(c, "remote", "add", name, url) _, err := fakeGit(c, "remote", "add", name, url)
require.NoError(tb, err) require.NoError(tb, err)
} }
func GitSetMainUpstream(c *gitutil.Git, tb testing.TB, remote, target string) { func GitSetMainUpstream(c *gitutil.GitCLI, tb testing.TB, remote, target string) {
tb.Helper() tb.Helper()
_, err := fakeGit(c, "fetch", "--depth", "1", remote, target) _, err := fakeGit(c, "fetch", "--depth", "1", remote, target)
require.NoError(tb, err) require.NoError(tb, err)
@@ -81,7 +83,7 @@ func Mktmp(tb testing.TB) string {
return folder return folder
} }
func fakeGit(c *gitutil.Git, args ...string) (string, error) { func fakeGit(c *gitutil.GitCLI, args ...string) (string, error) {
allArgs := []string{ allArgs := []string{
"-c", "user.name=buildx", "-c", "user.name=buildx",
"-c", "user.email=buildx@docker.com", "-c", "user.email=buildx@docker.com",
@@ -90,7 +92,15 @@ func fakeGit(c *gitutil.Git, args ...string) (string, error) {
"-c", "log.showSignature=false", "-c", "log.showSignature=false",
} }
allArgs = append(allArgs, args...) allArgs = append(allArgs, args...)
return c.Run(allArgs...) return clean(c.Run(context.TODO(), allArgs...))
}
func clean(dt []byte, err error) (string, error) {
out := strings.ReplaceAll(strings.Split(string(dt), "\n")[0], "'", "")
if err != nil {
err = errors.New(strings.TrimSuffix(err.Error(), "\n"))
}
return out, err
} }
func IsAmbiguousArgument(err error) bool { func IsAmbiguousArgument(err error) bool {
+3 -3
View File
@@ -24,7 +24,7 @@ func WithAccessToken(token string) GitServeOpt {
} }
} }
func GitServeHTTP(c *gitutil.Git, t testing.TB, opts ...GitServeOpt) (url string) { func GitServeHTTP(c *gitutil.GitCLI, t testing.TB, opts ...GitServeOpt) (url string) {
t.Helper() t.Helper()
gitUpdateServerInfo(c, t) gitUpdateServerInfo(c, t)
ctx, cancel := context.WithCancelCause(context.TODO()) ctx, cancel := context.WithCancelCause(context.TODO())
@@ -38,7 +38,7 @@ func GitServeHTTP(c *gitutil.Git, t testing.TB, opts ...GitServeOpt) (url string
done := make(chan struct{}) done := make(chan struct{})
name := "test.git" name := "test.git"
dir, err := c.GitDir() dir, err := c.GitDir(context.TODO())
if err != nil { if err != nil {
cancel(err) cancel(err)
} }
@@ -93,7 +93,7 @@ func GitServeHTTP(c *gitutil.Git, t testing.TB, opts ...GitServeOpt) (url string
return fmt.Sprintf("http://%s/%s", addr, name) return fmt.Sprintf("http://%s/%s", addr, name)
} }
func gitUpdateServerInfo(c *gitutil.Git, tb testing.TB) { func gitUpdateServerInfo(c *gitutil.GitCLI, tb testing.TB) {
tb.Helper() tb.Helper()
_, err := fakeGit(c, "update-server-info") _, err := fakeGit(c, "update-server-info")
require.NoError(tb, err) require.NoError(tb, err)
+46 -112
View File
@@ -1,122 +1,98 @@
package gitutil package gitutil
import ( import (
"bytes"
"context" "context"
"net/url"
"os"
"os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/docker/buildx/util/osutil" "github.com/docker/buildx/util/osutil"
bkgitutil "github.com/moby/buildkit/util/gitutil"
bkurlutil "github.com/moby/buildkit/util/urlutil"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// Git represents an active git object // GitCLI represents an active git object.
type Git struct { type GitCLI struct {
ctx context.Context bkgitutil.GitCLI
wd string
gitpath string
} }
// Option provides a variadic option for configuring the git client. // New initializes a new git client.
type Option func(b *Git) func New(opts ...bkgitutil.Option) (*GitCLI, error) {
cli := bkgitutil.NewGitCLI(append(opts, bkgitutil.WithHostGitConfig())...)
// WithContext sets context. gitpath, err := gitPath(cli.Dir())
func WithContext(ctx context.Context) Option {
return func(b *Git) {
b.ctx = ctx
}
}
// WithWorkingDir sets working directory.
func WithWorkingDir(wd string) Option {
return func(b *Git) {
b.wd = wd
}
}
// New initializes a new git client
func New(opts ...Option) (*Git, error) {
var err error
c := &Git{
ctx: context.Background(),
}
for _, opt := range opts {
opt(c)
}
c.gitpath, err = gitPath(c.wd)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return c, nil cli = cli.New(
bkgitutil.WithGitBinary(gitpath),
bkgitutil.WithArgs("-c", "log.showSignature=false"),
)
return &GitCLI{*cli}, nil
} }
func (c *Git) IsInsideWorkTree() bool { func (cli *GitCLI) IsInsideWorkTree(ctx context.Context) bool {
out, err := c.Run("rev-parse", "--is-inside-work-tree") out, err := cli.clean(cli.Run(ctx, "rev-parse", "--is-inside-work-tree"))
return out == "true" && err == nil return out == "true" && err == nil
} }
func (c *Git) IsDirty() bool { func (cli *GitCLI) IsDirty(ctx context.Context) bool {
out, err := c.Run("status", "--porcelain", "--ignored") out, err := cli.Run(ctx, "status", "--porcelain", "--ignored")
return strings.TrimSpace(out) != "" || err != nil return strings.TrimSpace(string(out)) != "" || err != nil
} }
func (c *Git) RootDir() (string, error) { func (cli *GitCLI) WorkTree(ctx context.Context) (string, error) {
root, err := c.Run("rev-parse", "--show-toplevel") root, err := cli.GitCLI.WorkTree(ctx)
if err != nil { if err != nil {
return "", err return "", err
} }
return osutil.SanitizePath(root), nil return osutil.SanitizePath(root), nil
} }
func (c *Git) GitDir() (string, error) { func (cli *GitCLI) GitDir(ctx context.Context) (string, error) {
dir, err := c.RootDir() dir, err := cli.WorkTree(ctx)
if err != nil { if err != nil {
return "", err return "", err
} }
return filepath.Join(dir, ".git"), nil return filepath.Join(dir, ".git"), nil
} }
func (c *Git) RemoteURL() (string, error) { func (cli *GitCLI) RemoteURL(ctx context.Context) (string, error) {
// Try default remote based on remote tracking branch // Try default remote based on remote tracking branch.
if remote, err := c.currentRemote(); err == nil && remote != "" { if remote, err := cli.currentRemote(ctx); err == nil && remote != "" {
if ru, err := c.clean(c.run("remote", "get-url", remote)); err == nil && ru != "" { if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", remote)); err == nil && ru != "" {
return stripCredentials(ru), nil return bkurlutil.RedactCredentials(ru), nil
} }
} }
// Next try to get the remote URL from the origin remote first // Next try to get the remote URL from the origin remote first.
if ru, err := c.clean(c.run("remote", "get-url", "origin")); err == nil && ru != "" { if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", "origin")); err == nil && ru != "" {
return stripCredentials(ru), nil return bkurlutil.RedactCredentials(ru), nil
} }
// If that fails, try to get the remote URL from the upstream remote // If that fails, try to get the remote URL from the upstream remote.
if ru, err := c.clean(c.run("remote", "get-url", "upstream")); err == nil && ru != "" { if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", "upstream")); err == nil && ru != "" {
return stripCredentials(ru), nil return bkurlutil.RedactCredentials(ru), nil
} }
return "", errors.New("no remote URL found for either origin or upstream") return "", errors.New("no remote URL found for either origin or upstream")
} }
func (c *Git) FullCommit() (string, error) { func (cli *GitCLI) FullCommit(ctx context.Context) (string, error) {
return c.clean(c.run("show", "--format=%H", "HEAD", "--quiet", "--")) return cli.clean(cli.Run(ctx, "show", "--format=%H", "HEAD", "--quiet", "--"))
} }
func (c *Git) ShortCommit() (string, error) { func (cli *GitCLI) ShortCommit(ctx context.Context) (string, error) {
return c.clean(c.run("show", "--format=%h", "HEAD", "--quiet", "--")) return cli.clean(cli.Run(ctx, "show", "--format=%h", "HEAD", "--quiet", "--"))
} }
func (c *Git) Tag() (string, error) { func (cli *GitCLI) Tag(ctx context.Context) (string, error) {
var tag string var tag string
var err error var err error
for _, fn := range []func() (string, error){ for _, fn := range []func() (string, error){
func() (string, error) { func() (string, error) {
return c.clean(c.run("tag", "--points-at", "HEAD", "--sort", "-version:creatordate")) return cli.clean(cli.Run(ctx, "tag", "--points-at", "HEAD", "--sort", "-version:creatordate"))
}, },
func() (string, error) { func() (string, error) {
return c.clean(c.run("describe", "--tags", "--abbrev=0")) return cli.clean(cli.Run(ctx, "describe", "--tags", "--abbrev=0"))
}, },
} { } {
tag, err = fn() tag, err = fn()
@@ -127,36 +103,8 @@ func (c *Git) Tag() (string, error) {
return tag, err return tag, err
} }
func (c *Git) Run(args ...string) (string, error) { func (cli *GitCLI) clean(dt []byte, err error) (string, error) {
return c.clean(c.run(args...)) out := string(dt)
}
func (c *Git) run(args ...string) (string, error) {
var extraArgs = []string{
"-c", "log.showSignature=false",
}
args = append(extraArgs, args...)
cmd := exec.CommandContext(c.ctx, c.gitpath, args...)
if c.wd != "" {
cmd.Dir = c.wd
}
// Override the locale to ensure consistent output
cmd.Env = append(os.Environ(), "LC_ALL=C")
stdout := bytes.Buffer{}
stderr := bytes.Buffer{}
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return "", errors.New(stderr.String())
}
return stdout.String(), nil
}
func (c *Git) clean(out string, err error) (string, error) {
out = strings.ReplaceAll(strings.Split(out, "\n")[0], "'", "") out = strings.ReplaceAll(strings.Split(out, "\n")[0], "'", "")
if err != nil { if err != nil {
err = errors.New(strings.TrimSuffix(err.Error(), "\n")) err = errors.New(strings.TrimSuffix(err.Error(), "\n"))
@@ -164,16 +112,15 @@ func (c *Git) clean(out string, err error) (string, error) {
return out, err return out, err
} }
func (c *Git) currentRemote() (string, error) { func (cli *GitCLI) currentRemote(ctx context.Context) (string, error) {
symref, err := c.Run("symbolic-ref", "-q", "HEAD") symref, err := cli.clean(cli.Run(ctx, "symbolic-ref", "-q", "HEAD"))
if err != nil { if err != nil {
return "", err return "", err
} }
if symref == "" { if symref == "" {
return "", nil return "", nil
} }
// git for-each-ref --format='%(upstream:remotename)' remote, err := cli.clean(cli.Run(ctx, "for-each-ref", "--format=%(upstream:remotename)", symref))
remote, err := c.Run("for-each-ref", "--format=%(upstream:remotename)", symref)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -188,16 +135,3 @@ func IsUnknownRevision(err error) bool {
errMsg := strings.ToLower(err.Error()) errMsg := strings.ToLower(err.Error())
return strings.Contains(errMsg, "unknown revision or path not in the working tree") || strings.Contains(errMsg, "bad revision") return strings.Contains(errMsg, "unknown revision or path not in the working tree") || strings.Contains(errMsg, "bad revision")
} }
// stripCredentials takes a URL and strips username and password from it.
// e.g. "https://user:password@host.tld/path.git" will be changed to
// "https://host.tld/path.git".
// TODO: remove this function once fix from BuildKit is vendored here
func stripCredentials(s string) string {
ru, err := url.Parse(s)
if err != nil {
return s // string is not a URL, just return it
}
ru.User = nil
return ru.String()
}
+22 -12
View File
@@ -1,6 +1,8 @@
package gitutil_test package gitutil_test
import ( import (
"context"
"strings"
"testing" "testing"
"github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/gitutil"
@@ -9,6 +11,7 @@ import (
) )
func TestGit(t *testing.T) { func TestGit(t *testing.T) {
ctx := context.TODO()
gittestutil.Mktmp(t) gittestutil.Mktmp(t)
c, err := gitutil.New() c, err := gitutil.New()
require.NoError(t, err) require.NoError(t, err)
@@ -16,17 +19,18 @@ func TestGit(t *testing.T) {
gittestutil.GitInit(c, t) gittestutil.GitInit(c, t)
gittestutil.GitCommit(c, t, "bar") gittestutil.GitCommit(c, t, "bar")
out, err := c.Run("status") out, err := c.Run(ctx, "status")
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, out) require.NotEmpty(t, out)
out, err = c.Run("not-exist") out, err = c.Run(ctx, "not-exist")
require.Error(t, err) require.Error(t, err)
require.Empty(t, out) require.Empty(t, out)
require.Equal(t, "git: 'not-exist' is not a git command. See 'git --help'.", err.Error()) require.Contains(t, err.Error(), "git: 'not-exist' is not a git command. See 'git --help'.")
} }
func TestGitFullCommit(t *testing.T) { func TestGitFullCommit(t *testing.T) {
ctx := context.TODO()
gittestutil.Mktmp(t) gittestutil.Mktmp(t)
c, err := gitutil.New() c, err := gitutil.New()
require.NoError(t, err) require.NoError(t, err)
@@ -34,12 +38,13 @@ func TestGitFullCommit(t *testing.T) {
gittestutil.GitInit(c, t) gittestutil.GitInit(c, t)
gittestutil.GitCommit(c, t, "bar") gittestutil.GitCommit(c, t, "bar")
out, err := c.FullCommit() out, err := c.FullCommit(ctx)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 40, len(out)) require.Equal(t, 40, len(out))
} }
func TestGitShortCommit(t *testing.T) { func TestGitShortCommit(t *testing.T) {
ctx := context.TODO()
gittestutil.Mktmp(t) gittestutil.Mktmp(t)
c, err := gitutil.New() c, err := gitutil.New()
require.NoError(t, err) require.NoError(t, err)
@@ -47,38 +52,41 @@ func TestGitShortCommit(t *testing.T) {
gittestutil.GitInit(c, t) gittestutil.GitInit(c, t)
gittestutil.GitCommit(c, t, "bar") gittestutil.GitCommit(c, t, "bar")
out, err := c.ShortCommit() out, err := c.ShortCommit(ctx)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 7, len(out)) require.Equal(t, 7, len(out))
} }
func TestGitFullCommitErr(t *testing.T) { func TestGitFullCommitErr(t *testing.T) {
ctx := context.TODO()
gittestutil.Mktmp(t) gittestutil.Mktmp(t)
c, err := gitutil.New() c, err := gitutil.New()
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(c, t) gittestutil.GitInit(c, t)
_, err = c.FullCommit() _, err = c.FullCommit(ctx)
require.Error(t, err) require.Error(t, err)
require.True(t, gitutil.IsUnknownRevision(err)) require.True(t, gitutil.IsUnknownRevision(err))
require.False(t, gittestutil.IsAmbiguousArgument(err)) require.False(t, gittestutil.IsAmbiguousArgument(err))
} }
func TestGitShortCommitErr(t *testing.T) { func TestGitShortCommitErr(t *testing.T) {
ctx := context.TODO()
gittestutil.Mktmp(t) gittestutil.Mktmp(t)
c, err := gitutil.New() c, err := gitutil.New()
require.NoError(t, err) require.NoError(t, err)
gittestutil.GitInit(c, t) gittestutil.GitInit(c, t)
_, err = c.ShortCommit() _, err = c.ShortCommit(ctx)
require.Error(t, err) require.Error(t, err)
require.True(t, gitutil.IsUnknownRevision(err)) require.True(t, gitutil.IsUnknownRevision(err))
require.False(t, gittestutil.IsAmbiguousArgument(err)) require.False(t, gittestutil.IsAmbiguousArgument(err))
} }
func TestGitTagsPointsAt(t *testing.T) { func TestGitTagsPointsAt(t *testing.T) {
ctx := context.TODO()
gittestutil.Mktmp(t) gittestutil.Mktmp(t)
c, err := gitutil.New() c, err := gitutil.New()
require.NoError(t, err) require.NoError(t, err)
@@ -89,12 +97,13 @@ func TestGitTagsPointsAt(t *testing.T) {
gittestutil.GitCommit(c, t, "foo") gittestutil.GitCommit(c, t, "foo")
gittestutil.GitTag(c, t, "v0.9.0") gittestutil.GitTag(c, t, "v0.9.0")
out, err := c.Run("tag", "--points-at", "HEAD", "--sort", "-version:creatordate") out, err := c.Run(ctx, "tag", "--points-at", "HEAD", "--sort", "-version:creatordate")
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "v0.9.0", out) require.Equal(t, "v0.9.0", strings.TrimSpace(string(out)))
} }
func TestGitDescribeTags(t *testing.T) { func TestGitDescribeTags(t *testing.T) {
ctx := context.TODO()
gittestutil.Mktmp(t) gittestutil.Mktmp(t)
c, err := gitutil.New() c, err := gitutil.New()
require.NoError(t, err) require.NoError(t, err)
@@ -105,12 +114,13 @@ func TestGitDescribeTags(t *testing.T) {
gittestutil.GitCommit(c, t, "foo") gittestutil.GitCommit(c, t, "foo")
gittestutil.GitTag(c, t, "v0.9.0") gittestutil.GitTag(c, t, "v0.9.0")
out, err := c.Run("describe", "--tags", "--abbrev=0") out, err := c.Run(ctx, "describe", "--tags", "--abbrev=0")
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "v0.9.0", out) require.Equal(t, "v0.9.0", strings.TrimSpace(string(out)))
} }
func TestGitRemoteURL(t *testing.T) { func TestGitRemoteURL(t *testing.T) {
ctx := context.TODO()
type remote struct { type remote struct {
name string name string
url string url string
@@ -218,7 +228,7 @@ func TestGitRemoteURL(t *testing.T) {
} }
} }
ru, err := c.RemoteURL() ru, err := c.RemoteURL(ctx)
if tt.fail { if tt.fail {
require.Error(t, err) require.Error(t, err)
return return
+2 -2
View File
@@ -25,10 +25,10 @@ func getSalt() []byte {
return salt return salt
} }
func CredentialsFunc(sm *session.Manager, g session.Group) func(string) (session, username, secret string, err error) { func CredentialsFunc(ctx context.Context, sm *session.Manager, g session.Group) func(string) (session, username, secret string, err error) {
return func(host string) (string, string, string, error) { return func(host string) (string, string, string, error) {
var sessionID, user, secret string var sessionID, user, secret string
err := sm.Any(context.TODO(), g, func(ctx context.Context, id string, c session.Caller) error { err := sm.Any(ctx, g, func(ctx context.Context, id string, c session.Caller) error {
client := NewAuthClient(c.Conn()) client := NewAuthClient(c.Conn())
resp, err := client.Credentials(ctx, &CredentialsRequest{ resp, err := client.Credentials(ctx, &CredentialsRequest{
+34 -5
View File
@@ -27,6 +27,7 @@ type GitCLI struct {
sshAuthSock string sshAuthSock string
sshKnownHosts string sshKnownHosts string
hostGitConfig bool
} }
// Option provides a variadic option for configuring the git client. // Option provides a variadic option for configuring the git client.
@@ -97,6 +98,15 @@ func WithSSHKnownHosts(sshKnownHosts string) Option {
} }
} }
// WithHostGitConfig allows git to read the host system and user git config.
// This is intended for client-side local git inspection. The default remains
// isolated so daemon-side callers do not leak host configuration into git.
func WithHostGitConfig() Option {
return func(b *GitCLI) {
b.hostGitConfig = true
}
}
type StreamFunc func(context.Context) (io.WriteCloser, io.WriteCloser, func()) type StreamFunc func(context.Context) (io.WriteCloser, io.WriteCloser, func())
// WithStreams configures a callback for getting the streams for a command. The // WithStreams configures a callback for getting the streams for a command. The
@@ -108,7 +118,7 @@ func WithStreams(streams StreamFunc) Option {
} }
} }
// New initializes a new git client // NewGitCLI initializes a new git client
func NewGitCLI(opts ...Option) *GitCLI { func NewGitCLI(opts ...Option) *GitCLI {
c := &GitCLI{} c := &GitCLI{}
for _, opt := range opts { for _, opt := range opts {
@@ -191,9 +201,28 @@ func (cli *GitCLI) Run(ctx context.Context, args ...string) (_ []byte, err error
"GIT_TERMINAL_PROMPT=0", "GIT_TERMINAL_PROMPT=0",
"GIT_SSH_COMMAND=" + getGitSSHCommand(cli.sshKnownHosts), "GIT_SSH_COMMAND=" + getGitSSHCommand(cli.sshKnownHosts),
// "GIT_TRACE=1", // "GIT_TRACE=1",
"GIT_CONFIG_NOSYSTEM=1", // Disable reading from system gitconfig. "LC_ALL=C", // Ensure consistent output.
"HOME=/dev/null", // Disable reading from user gitconfig. }
"LC_ALL=C", // Ensure consistent output. if cli.hostGitConfig {
for _, ev := range [...]string{
"HOME",
"XDG_CONFIG_HOME",
"USERPROFILE",
"HOMEDRIVE",
"HOMEPATH",
"GIT_CONFIG_GLOBAL",
"GIT_CONFIG_SYSTEM",
} {
if v, ok := os.LookupEnv(ev); ok {
cmd.Env = append(cmd.Env, ev+"="+v)
}
}
} else {
cmd.Env = append(cmd.Env,
"GIT_CONFIG_NOSYSTEM=1", // Disable reading from system gitconfig.
"HOME="+os.DevNull, // Disable reading from user gitconfig.
"GIT_CONFIG_GLOBAL="+os.DevNull, // Disable reading from global gitconfig.
)
} }
for _, ev := range proxyEnvVars { for _, ev := range proxyEnvVars {
if v, ok := os.LookupEnv(ev); ok { if v, ok := os.LookupEnv(ev); ok {
@@ -244,7 +273,7 @@ func (cli *GitCLI) Run(ctx context.Context, args ...string) (_ []byte, err error
} }
func getGitSSHCommand(knownHosts string) string { func getGitSSHCommand(knownHosts string) string {
gitSSHCommand := "ssh -F /dev/null" gitSSHCommand := "ssh -F " + os.DevNull
if knownHosts != "" { if knownHosts != "" {
gitSSHCommand += " -o UserKnownHostsFile=" + knownHosts gitSSHCommand += " -o UserKnownHostsFile=" + knownHosts
} else { } else {
+33
View File
@@ -0,0 +1,33 @@
package urlutil
import (
"net/url"
)
const mask = "xxxxx"
// RedactCredentials takes a URL and redacts username and password from it.
// e.g. "https://user:password@host.tld/path.git" will be changed to
// "https://xxxxx:xxxxx@host.tld/path.git".
func RedactCredentials(s string) string {
ru, err := url.Parse(s)
if err != nil {
return s // string is not a URL, just return it
}
var (
hasUsername bool
hasPassword bool
)
if ru.User != nil {
hasUsername = len(ru.User.Username()) > 0
_, hasPassword = ru.User.Password()
}
if hasUsername && hasPassword {
ru.User = url.UserPassword(mask, mask)
} else if hasUsername {
ru.User = url.User(mask)
} else if hasPassword {
ru.User = url.UserPassword(ru.User.Username(), mask)
}
return ru.String()
}
+2 -1
View File
@@ -646,7 +646,7 @@ github.com/mitchellh/go-wordwrap
# github.com/mitchellh/hashstructure/v2 v2.0.2 # github.com/mitchellh/hashstructure/v2 v2.0.2
## explicit; go 1.14 ## explicit; go 1.14
github.com/mitchellh/hashstructure/v2 github.com/mitchellh/hashstructure/v2
# github.com/moby/buildkit v0.29.0 # github.com/moby/buildkit v0.29.1-0.20260408185135-a243ce438aee
## explicit; go 1.25.5 ## explicit; go 1.25.5
github.com/moby/buildkit/api/services/control github.com/moby/buildkit/api/services/control
github.com/moby/buildkit/api/types github.com/moby/buildkit/api/types
@@ -743,6 +743,7 @@ github.com/moby/buildkit/util/tracing/delegated
github.com/moby/buildkit/util/tracing/detect github.com/moby/buildkit/util/tracing/detect
github.com/moby/buildkit/util/tracing/env github.com/moby/buildkit/util/tracing/env
github.com/moby/buildkit/util/tracing/otlptracegrpc github.com/moby/buildkit/util/tracing/otlptracegrpc
github.com/moby/buildkit/util/urlutil
github.com/moby/buildkit/version github.com/moby/buildkit/version
# github.com/moby/docker-image-spec v1.3.1 # github.com/moby/docker-image-spec v1.3.1
## explicit; go 1.18 ## explicit; go 1.18