mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 10:03:42 +08:00 
			
		
		
		
	Merge pull request #2156 from crazy-max/frontend-attr-localdirs
build: set local dirs as frontend attributes
This commit is contained in:
		@@ -530,7 +530,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
 | 
				
			|||||||
	for k, opt := range opt {
 | 
						for k, opt := range opt {
 | 
				
			||||||
		multiDriver := len(drivers[k]) > 1
 | 
							multiDriver := len(drivers[k]) > 1
 | 
				
			||||||
		hasMobyDriver := false
 | 
							hasMobyDriver := false
 | 
				
			||||||
		gitattrs, err := getGitAttributes(ctx, opt.Inputs.ContextPath, opt.Inputs.DockerfilePath)
 | 
							gitattrs, addVCSLocalDir, err := getGitAttributes(ctx, opt.Inputs.ContextPath, opt.Inputs.DockerfilePath)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			logrus.WithError(err).Warn("current commit information was not captured by the build")
 | 
								logrus.WithError(err).Warn("current commit information was not captured by the build")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -554,6 +554,9 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
 | 
				
			|||||||
			for k, v := range gitattrs {
 | 
								for k, v := range gitattrs {
 | 
				
			||||||
				so.FrontendAttrs[k] = v
 | 
									so.FrontendAttrs[k] = v
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if addVCSLocalDir != nil {
 | 
				
			||||||
 | 
									addVCSLocalDir(so)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			defers = append(defers, release)
 | 
								defers = append(defers, release)
 | 
				
			||||||
			reqn = append(reqn, &reqForNode{
 | 
								reqn = append(reqn, &reqForNode{
 | 
				
			||||||
				resolvedNode: np,
 | 
									resolvedNode: np,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										68
									
								
								build/git.go
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								build/git.go
									
									
									
									
									
								
							@@ -9,16 +9,17 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/buildx/util/gitutil"
 | 
						"github.com/docker/buildx/util/gitutil"
 | 
				
			||||||
 | 
						"github.com/moby/buildkit/client"
 | 
				
			||||||
	specs "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						specs "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
						"github.com/pkg/errors"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DockerfileLabel = "com.docker.image.source.entrypoint"
 | 
					const DockerfileLabel = "com.docker.image.source.entrypoint"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath string) (res map[string]string, _ error) {
 | 
					func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath string) (map[string]string, func(*client.SolveOpt), error) {
 | 
				
			||||||
	res = make(map[string]string)
 | 
						res := make(map[string]string)
 | 
				
			||||||
	if contextPath == "" {
 | 
						if contextPath == "" {
 | 
				
			||||||
		return
 | 
							return nil, nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setGitLabels := false
 | 
						setGitLabels := false
 | 
				
			||||||
@@ -37,7 +38,7 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !setGitLabels && !setGitInfo {
 | 
						if !setGitLabels && !setGitInfo {
 | 
				
			||||||
		return
 | 
							return nil, nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// figure out in which directory the git command needs to run in
 | 
						// figure out in which directory the git command needs to run in
 | 
				
			||||||
@@ -52,20 +53,25 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
 | 
				
			|||||||
	gitc, err := gitutil.New(gitutil.WithContext(ctx), gitutil.WithWorkingDir(wd))
 | 
						gitc, err := gitutil.New(gitutil.WithContext(ctx), gitutil.WithWorkingDir(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 res, errors.Wrap(err, "git was not found in the system")
 | 
								return res, nil, errors.Wrap(err, "git was not found in the system")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return
 | 
							return nil, nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !gitc.IsInsideWorkTree() {
 | 
						if !gitc.IsInsideWorkTree() {
 | 
				
			||||||
		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 res, errors.New("failed to read current commit information with git rev-parse --is-inside-work-tree")
 | 
								return res, nil, errors.New("failed to read current commit information with git rev-parse --is-inside-work-tree")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return res, nil
 | 
							return nil, nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						root, err := gitc.RootDir()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return res, nil, errors.Wrap(err, "failed to get git root dir")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if sha, err := gitc.FullCommit(); err != nil && !gitutil.IsUnknownRevision(err) {
 | 
						if sha, err := gitc.FullCommit(); err != nil && !gitutil.IsUnknownRevision(err) {
 | 
				
			||||||
		return res, errors.Wrap(err, "failed to get git commit")
 | 
							return res, nil, errors.Wrap(err, "failed to get git commit")
 | 
				
			||||||
	} else if sha != "" {
 | 
						} else if sha != "" {
 | 
				
			||||||
		checkDirty := false
 | 
							checkDirty := false
 | 
				
			||||||
		if v, ok := os.LookupEnv("BUILDX_GIT_CHECK_DIRTY"); ok {
 | 
							if v, ok := os.LookupEnv("BUILDX_GIT_CHECK_DIRTY"); ok {
 | 
				
			||||||
@@ -93,23 +99,35 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setGitLabels {
 | 
						if setGitLabels && root != "" {
 | 
				
			||||||
		if root, err := gitc.RootDir(); err != nil {
 | 
							if dockerfilePath == "" {
 | 
				
			||||||
			return res, errors.Wrap(err, "failed to get git root dir")
 | 
								dockerfilePath = filepath.Join(wd, "Dockerfile")
 | 
				
			||||||
		} else if root != "" {
 | 
							}
 | 
				
			||||||
			if dockerfilePath == "" {
 | 
							if !filepath.IsAbs(dockerfilePath) {
 | 
				
			||||||
				dockerfilePath = filepath.Join(wd, "Dockerfile")
 | 
								cwd, _ := os.Getwd()
 | 
				
			||||||
			}
 | 
								dockerfilePath = filepath.Join(cwd, dockerfilePath)
 | 
				
			||||||
			if !filepath.IsAbs(dockerfilePath) {
 | 
							}
 | 
				
			||||||
				cwd, _ := os.Getwd()
 | 
							if r, err := filepath.Rel(root, dockerfilePath); err == nil && !strings.HasPrefix(r, "..") {
 | 
				
			||||||
				dockerfilePath = filepath.Join(cwd, dockerfilePath)
 | 
								res["label:"+DockerfileLabel] = r
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			dockerfilePath, _ = filepath.Rel(root, dockerfilePath)
 | 
					 | 
				
			||||||
			if !strings.HasPrefix(dockerfilePath, "..") {
 | 
					 | 
				
			||||||
				res["label:"+DockerfileLabel] = dockerfilePath
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return
 | 
						return res, func(so *client.SolveOpt) {
 | 
				
			||||||
 | 
							if !setGitInfo || root == "" {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for k, dir := range so.LocalDirs {
 | 
				
			||||||
 | 
								dir, err = filepath.EvalSymlinks(dir)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								dir, err = filepath.Abs(dir)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if r, err := filepath.Rel(root, dir); err == nil && !strings.HasPrefix(r, "..") {
 | 
				
			||||||
 | 
									so.FrontendAttrs["vcs:localdir:"+k] = r
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/buildx/util/gitutil"
 | 
						"github.com/docker/buildx/util/gitutil"
 | 
				
			||||||
 | 
						"github.com/moby/buildkit/client"
 | 
				
			||||||
	specs "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						specs "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
@@ -30,7 +31,7 @@ func setupTest(tb testing.TB) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetGitAttributesNotGitRepo(t *testing.T) {
 | 
					func TestGetGitAttributesNotGitRepo(t *testing.T) {
 | 
				
			||||||
	_, err := getGitAttributes(context.Background(), t.TempDir(), "Dockerfile")
 | 
						_, _, err := getGitAttributes(context.Background(), t.TempDir(), "Dockerfile")
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,14 +39,14 @@ func TestGetGitAttributesBadGitRepo(t *testing.T) {
 | 
				
			|||||||
	tmp := t.TempDir()
 | 
						tmp := t.TempDir()
 | 
				
			||||||
	require.NoError(t, os.MkdirAll(path.Join(tmp, ".git"), 0755))
 | 
						require.NoError(t, os.MkdirAll(path.Join(tmp, ".git"), 0755))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := getGitAttributes(context.Background(), tmp, "Dockerfile")
 | 
						_, _, err := getGitAttributes(context.Background(), tmp, "Dockerfile")
 | 
				
			||||||
	assert.Error(t, err)
 | 
						assert.Error(t, err)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetGitAttributesNoContext(t *testing.T) {
 | 
					func TestGetGitAttributesNoContext(t *testing.T) {
 | 
				
			||||||
	setupTest(t)
 | 
						setupTest(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gitattrs, err := getGitAttributes(context.Background(), "", "Dockerfile")
 | 
						gitattrs, _, err := getGitAttributes(context.Background(), "", "Dockerfile")
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.Empty(t, gitattrs)
 | 
						assert.Empty(t, gitattrs)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -114,7 +115,7 @@ func TestGetGitAttributes(t *testing.T) {
 | 
				
			|||||||
			if tt.envGitInfo != "" {
 | 
								if tt.envGitInfo != "" {
 | 
				
			||||||
				t.Setenv("BUILDX_GIT_INFO", tt.envGitInfo)
 | 
									t.Setenv("BUILDX_GIT_INFO", tt.envGitInfo)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			gitattrs, err := getGitAttributes(context.Background(), ".", "Dockerfile")
 | 
								gitattrs, _, err := getGitAttributes(context.Background(), ".", "Dockerfile")
 | 
				
			||||||
			require.NoError(t, err)
 | 
								require.NoError(t, err)
 | 
				
			||||||
			for _, e := range tt.expected {
 | 
								for _, e := range tt.expected {
 | 
				
			||||||
				assert.Contains(t, gitattrs, e)
 | 
									assert.Contains(t, gitattrs, e)
 | 
				
			||||||
@@ -139,7 +140,7 @@ func TestGetGitAttributesDirty(t *testing.T) {
 | 
				
			|||||||
	require.NoError(t, os.WriteFile(filepath.Join("dir", "Dockerfile"), df, 0644))
 | 
						require.NoError(t, os.WriteFile(filepath.Join("dir", "Dockerfile"), df, 0644))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Setenv("BUILDX_GIT_LABELS", "true")
 | 
						t.Setenv("BUILDX_GIT_LABELS", "true")
 | 
				
			||||||
	gitattrs, _ := getGitAttributes(context.Background(), ".", "Dockerfile")
 | 
						gitattrs, _, _ := getGitAttributes(context.Background(), ".", "Dockerfile")
 | 
				
			||||||
	assert.Equal(t, 5, len(gitattrs))
 | 
						assert.Equal(t, 5, len(gitattrs))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Contains(t, gitattrs, "label:"+DockerfileLabel)
 | 
						assert.Contains(t, gitattrs, "label:"+DockerfileLabel)
 | 
				
			||||||
@@ -154,3 +155,59 @@ func TestGetGitAttributesDirty(t *testing.T) {
 | 
				
			|||||||
	assert.Contains(t, gitattrs, "vcs:revision")
 | 
						assert.Contains(t, gitattrs, "vcs:revision")
 | 
				
			||||||
	assert.True(t, strings.HasSuffix(gitattrs["vcs:revision"], "-dirty"))
 | 
						assert.True(t, strings.HasSuffix(gitattrs["vcs:revision"], "-dirty"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLocalDirs(t *testing.T) {
 | 
				
			||||||
 | 
						setupTest(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						so := &client.SolveOpt{
 | 
				
			||||||
 | 
							FrontendAttrs: map[string]string{},
 | 
				
			||||||
 | 
							LocalDirs: map[string]string{
 | 
				
			||||||
 | 
								"context":    ".",
 | 
				
			||||||
 | 
								"dockerfile": ".",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, addVCSLocalDir, err := getGitAttributes(context.Background(), ".", "Dockerfile")
 | 
				
			||||||
 | 
						require.NoError(t, err)
 | 
				
			||||||
 | 
						require.NotNil(t, addVCSLocalDir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addVCSLocalDir(so)
 | 
				
			||||||
 | 
						require.Contains(t, so.FrontendAttrs, "vcs:localdir:context")
 | 
				
			||||||
 | 
						assert.Equal(t, ".", so.FrontendAttrs["vcs:localdir:context"])
 | 
				
			||||||
 | 
						require.Contains(t, so.FrontendAttrs, "vcs:localdir:dockerfile")
 | 
				
			||||||
 | 
						assert.Equal(t, ".", so.FrontendAttrs["vcs:localdir:dockerfile"])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLocalDirsSub(t *testing.T) {
 | 
				
			||||||
 | 
						gitutil.Mktmp(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c, err := gitutil.New()
 | 
				
			||||||
 | 
						require.NoError(t, err)
 | 
				
			||||||
 | 
						gitutil.GitInit(c, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						df := []byte("FROM alpine:latest\n")
 | 
				
			||||||
 | 
						assert.NoError(t, os.MkdirAll("app", 0755))
 | 
				
			||||||
 | 
						assert.NoError(t, os.WriteFile("app/Dockerfile", df, 0644))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gitutil.GitAdd(c, t, "app/Dockerfile")
 | 
				
			||||||
 | 
						gitutil.GitCommit(c, t, "initial commit")
 | 
				
			||||||
 | 
						gitutil.GitSetRemote(c, t, "origin", "git@github.com:docker/buildx.git")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						so := &client.SolveOpt{
 | 
				
			||||||
 | 
							FrontendAttrs: map[string]string{},
 | 
				
			||||||
 | 
							LocalDirs: map[string]string{
 | 
				
			||||||
 | 
								"context":    ".",
 | 
				
			||||||
 | 
								"dockerfile": "app",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, addVCSLocalDir, err := getGitAttributes(context.Background(), ".", "app/Dockerfile")
 | 
				
			||||||
 | 
						require.NoError(t, err)
 | 
				
			||||||
 | 
						require.NotNil(t, addVCSLocalDir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addVCSLocalDir(so)
 | 
				
			||||||
 | 
						require.Contains(t, so.FrontendAttrs, "vcs:localdir:context")
 | 
				
			||||||
 | 
						assert.Equal(t, ".", so.FrontendAttrs["vcs:localdir:context"])
 | 
				
			||||||
 | 
						require.Contains(t, so.FrontendAttrs, "vcs:localdir:dockerfile")
 | 
				
			||||||
 | 
						assert.Equal(t, "app", so.FrontendAttrs["vcs:localdir:dockerfile"])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user