diff options
author | Zeger-Jan van de Weg <git@zjvandeweg.nl> | 2020-08-20 14:52:20 +0300 |
---|---|---|
committer | Zeger-Jan van de Weg <git@zjvandeweg.nl> | 2020-08-20 14:52:20 +0300 |
commit | 0fe0cfaccc979592610cbf65807f19b307957750 (patch) | |
tree | 99065088c4bfbb611497cf0b955d9b6b2c900189 | |
parent | 78d2b0cdb08b0e45de5324e2ac992282b7ecf691 (diff) | |
parent | 6f2467328e066fbaaeb65ec33b06c967b354f8f8 (diff) |
Merge branch 'pks-git-config' into 'master'
Detect Git executable getting resolved via PATH
See merge request gitlab-org/gitaly!2482
40 files changed, 282 insertions, 170 deletions
@@ -34,6 +34,7 @@ ASSEMBLY_ROOT ?= ${BUILD_DIR}/assembly GIT_PREFIX ?= ${GIT_INSTALL_DIR} # Tools +GIT := $(shell which git) GOIMPORTS := ${BUILD_DIR}/bin/goimports GITALYFMT := ${BUILD_DIR}/bin/gitalyfmt GOLANGCI_LINT := ${BUILD_DIR}/bin/golangci-lint @@ -111,9 +112,10 @@ find_go_sources = $(shell find ${SOURCE_DIR} -type d \( -name ruby -o -name ven find_go_packages = $(dir $(call find_go_sources, 's|[^/]*\.go||')) unexport GOROOT -export GOBIN = ${BUILD_DIR}/bin -export GOPROXY ?= https://proxy.golang.org -export PATH := ${BUILD_DIR}/bin:${PATH} +export GOBIN = ${BUILD_DIR}/bin +export GOPROXY ?= https://proxy.golang.org +export PATH := ${SOURCE_DIR}/internal/testhelper/testdata/home/bin:${BUILD_DIR}/bin:${PATH} +export GITALY_TESTING_GIT_BINARY ?= ${GIT} .NOTPARALLEL: @@ -205,7 +207,9 @@ verify: check-mod-tidy check-formatting notice-up-to-date check-proto rubocop .PHONY: check-mod-tidy check-mod-tidy: - ${Q}${SOURCE_DIR}/_support/check-mod-tidy + ${Q}${GIT} diff --quiet --exit-code go.mod go.sum || (echo "error: uncommitted changes in go.mod or go.sum" && exit 1) + ${Q}go mod tidy + ${Q}${GIT} diff --quiet --exit-code go.mod go.sum || (echo "error: uncommitted changes in go.mod or go.sum" && exit 1) .PHONY: lint lint: ${GOLANGCI_LINT} @@ -290,7 +294,7 @@ proto-lint: ${PROTOC} ${PROTOC_GEN_GO} .PHONY: no-changes no-changes: - ${Q}git status --porcelain | awk '{ print } END { if (NR > 0) { exit 1 } }' + ${Q}${GIT} status --porcelain | awk '{ print } END { if (NR > 0) { exit 1 } }' .PHONY: smoke-test smoke-test: all rspec @@ -306,8 +310,8 @@ download-git: ${BUILD_DIR}/git_full_bins.tgz build-git: ${Q}echo "Getting Git from ${GIT_REPO_URL}" ${Q}rm -rf ${GIT_SOURCE_DIR} ${GIT_INSTALL_DIR} - git clone ${GIT_REPO_URL} ${GIT_SOURCE_DIR} - git -C ${GIT_SOURCE_DIR} checkout ${GIT_VERSION} + ${GIT} clone ${GIT_REPO_URL} ${GIT_SOURCE_DIR} + ${GIT} -C ${GIT_SOURCE_DIR} checkout ${GIT_VERSION} ${Q}rm -rf ${GIT_INSTALL_DIR} ${Q}mkdir -p ${GIT_INSTALL_DIR} ${MAKE} -C ${GIT_SOURCE_DIR} -j$(shell nproc) prefix=${GIT_PREFIX} ${GIT_BUILD_OPTIONS} install @@ -375,20 +379,20 @@ ${GOLANGCI_LINT}: Makefile ${BUILD_DIR}/go.mod | ${BUILD_DIR}/bin ${Q}cd ${BUILD_DIR} && go get github.com/golangci/golangci-lint/cmd/golangci-lint@v${GOLANGCI_LINT_VERSION} ${TEST_REPO}: - git clone --bare --quiet https://gitlab.com/gitlab-org/gitlab-test.git $@ + ${GIT} clone --bare --quiet https://gitlab.com/gitlab-org/gitlab-test.git $@ # Git notes aren't fetched by default with git clone - git -C $@ fetch origin refs/notes/*:refs/notes/* + ${GIT} -C $@ fetch origin refs/notes/*:refs/notes/* rm -rf $@/refs mkdir -p $@/refs/heads $@/refs/tags cp ${SOURCE_DIR}/_support/gitlab-test.git-packed-refs $@/packed-refs - git -C $@ fsck --no-progress + ${GIT} -C $@ fsck --no-progress ${TEST_REPO_GIT}: - git clone --bare --quiet https://gitlab.com/gitlab-org/gitlab-git-test.git $@ + ${GIT} clone --bare --quiet https://gitlab.com/gitlab-org/gitlab-git-test.git $@ rm -rf $@/refs mkdir -p $@/refs/heads $@/refs/tags cp ${SOURCE_DIR}/_support/gitlab-git-test.git-packed-refs $@/packed-refs - git -C $@ fsck --no-progress + ${GIT} -C $@ fsck --no-progress ${GITLAB_SHELL_DIR}/config.yml: ${GITLAB_SHELL_DIR}/config.yml.example cp $< $@ diff --git a/_support/check-mod-tidy b/_support/check-mod-tidy deleted file mode 100755 index 2bce95221..000000000 --- a/_support/check-mod-tidy +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env ruby - -require_relative 'run.rb' - -def main - mod_not_changed! - run!(%w[go mod tidy]) - mod_not_changed! -end - -def mod_not_changed! - %w[go.mod go.sum].each do |f| - unless system(*%W[git diff --quiet --exit-code #{f}]) - abort "error: uncommitted changes in #{f}" - end - end -end - -main diff --git a/cmd/gitaly-debug/simulatehttp.go b/cmd/gitaly-debug/simulatehttp.go index c87b4f5ee..ac9a63fe3 100644 --- a/cmd/gitaly-debug/simulatehttp.go +++ b/cmd/gitaly-debug/simulatehttp.go @@ -9,12 +9,13 @@ import ( "regexp" "time" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/git/pktline" ) func simulateHTTPClone(gitDir string) { msg("Generating server response for HTTP clone. Data goes to /dev/null.") - infoRefs := exec.Command("git", "upload-pack", "--stateless-rpc", "--advertise-refs", gitDir) + infoRefs := exec.Command(command.GitPath(), "upload-pack", "--stateless-rpc", "--advertise-refs", gitDir) infoRefs.Stderr = os.Stderr out, err := infoRefs.StdoutPipe() noError(err) @@ -57,7 +58,7 @@ func simulateHTTPClone(gitDir string) { } fmt.Fprint(request, "00000009done\n") - uploadPack := exec.Command("git", "upload-pack", "--stateless-rpc", gitDir) + uploadPack := exec.Command(command.GitPath(), "upload-pack", "--stateless-rpc", gitDir) uploadPack.Stdin = request uploadPack.Stderr = os.Stderr out, err = uploadPack.StdoutPipe() diff --git a/cmd/gitaly-ssh/auth_test.go b/cmd/gitaly-ssh/auth_test.go index 6206aede4..bc6d55438 100644 --- a/cmd/gitaly-ssh/auth_test.go +++ b/cmd/gitaly-ssh/auth_test.go @@ -12,6 +12,7 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/config" "gitlab.com/gitlab-org/gitaly/internal/rubyserver" "gitlab.com/gitlab-org/gitaly/internal/server" @@ -91,7 +92,7 @@ func TestConnectivity(t *testing.T) { require.NoError(t, err) for _, testcase := range testCases { t.Run(testcase.name, func(t *testing.T) { - cmd := exec.Command("git", "ls-remote", "git@localhost:test/test.git", "refs/heads/master") + cmd := exec.Command(command.GitPath(), "ls-remote", "git@localhost:test/test.git", "refs/heads/master") cmd.Stderr = os.Stderr cmd.Env = []string{ fmt.Sprintf("GITALY_PAYLOAD=%s", payload), diff --git a/internal/config/config.go b/internal/config/config.go index c7aef2f08..c43d4b6a8 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -323,6 +323,11 @@ func SetGitPath() error { return nil } + if path, ok := os.LookupEnv("GITALY_TESTING_GIT_BINARY"); ok { + Config.Git.BinPath = path + return nil + } + resolvedPath, err := exec.LookPath("git") if err != nil { return err diff --git a/internal/config/config_test.go b/internal/config/config_test.go index b747e20a4..383ffb61d 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -438,6 +438,10 @@ func TestValidateHooks(t *testing.T) { } func TestLoadGit(t *testing.T) { + defer func(oldGitSettings Git) { + Config.Git = oldGitSettings + }(Config.Git) + tmpFile := configFileReader(`[git] bin_path = "/my/git/path" catfile_cache_size = 50 @@ -455,10 +459,13 @@ func TestSetGitPath(t *testing.T) { Config.Git = oldGitSettings }(Config.Git) - resolvedGitPath, err := exec.LookPath("git") - - if err != nil { - t.Fatal(err) + var resolvedGitPath string + if path, ok := os.LookupEnv("GITALY_TESTING_GIT_BINARY"); ok { + resolvedGitPath = path + } else { + path, err := exec.LookPath("git") + require.NoError(t, err) + resolvedGitPath = path } testCases := []struct { @@ -479,11 +486,11 @@ func TestSetGitPath(t *testing.T) { } for _, tc := range testCases { - Config.Git.BinPath = tc.gitBinPath - - SetGitPath() - - assert.Equal(t, tc.expected, Config.Git.BinPath, tc.desc) + t.Run(tc.desc, func(t *testing.T) { + Config.Git.BinPath = tc.gitBinPath + SetGitPath() + assert.Equal(t, tc.expected, Config.Git.BinPath, tc.desc) + }) } } diff --git a/internal/git/gittest/http_server.go b/internal/git/gittest/http_server.go index 4e5d1916a..25ff78f08 100644 --- a/internal/git/gittest/http_server.go +++ b/internal/git/gittest/http_server.go @@ -30,7 +30,7 @@ func RemoteUploadPackServer(ctx context.Context, t *testing.T, repoName, httpTok } defer r.Body.Close() - cmd, err := command.New(ctx, exec.Command("git", "-C", repoPath, "upload-pack", "--stateless-rpc", "."), reader, w, nil) + cmd, err := command.New(ctx, exec.Command(command.GitPath(), "-C", repoPath, "upload-pack", "--stateless-rpc", "."), reader, w, nil) require.NoError(t, err) require.NoError(t, cmd.Wait()) case fmt.Sprintf("/%s.git/info/refs?service=git-upload-pack", repoName): @@ -44,7 +44,7 @@ func RemoteUploadPackServer(ctx context.Context, t *testing.T, repoName, httpTok w.Write([]byte("001e# service=git-upload-pack\n")) w.Write([]byte("0000")) - cmd, err := command.New(ctx, exec.Command("git", "-C", repoPath, "upload-pack", "--advertise-refs", "."), nil, w, nil) + cmd, err := command.New(ctx, exec.Command(command.GitPath(), "-C", repoPath, "upload-pack", "--advertise-refs", "."), nil, w, nil) require.NoError(t, err) require.NoError(t, cmd.Wait()) default: diff --git a/internal/git/packfile/index.go b/internal/git/packfile/index.go index 8f61544c3..29640bcb1 100644 --- a/internal/git/packfile/index.go +++ b/internal/git/packfile/index.go @@ -93,7 +93,7 @@ func ReadIndex(idxPath string) (*Index, error) { return nil, err } - showIndex, err := command.New(ctx, exec.Command("git", "show-index"), f, nil, nil) + showIndex, err := command.New(ctx, exec.Command(command.GitPath(), "show-index"), f, nil, nil) if err != nil { return nil, err } diff --git a/internal/linguist/linguist.go b/internal/linguist/linguist.go index 252e36047..523fe9e6a 100644 --- a/internal/linguist/linguist.go +++ b/internal/linguist/linguist.go @@ -74,7 +74,32 @@ func LoadColors(cfg config.Cfg) error { } func startGitLinguist(ctx context.Context, repoPath string, commitID string, linguistCommand string) (*command.Command, error) { - cmd := exec.Command("bundle", "exec", "bin/ruby-cd", repoPath, "git-linguist", "--commit="+commitID, linguistCommand) + args := []string{ + "bundle", + "exec", + "bin/ruby-cd", + repoPath, + "git-linguist", + "--commit=" + commitID, + linguistCommand, + } + + // This is a horrible hack. git-linguist will execute `git rev-parse + // --git-dir` to check whether it is in a Git directory or not. We don't + // want to use the one provided by PATH, but instead the one specified + // via the configuration. git-linguist doesn't specify any way to choose + // a different Git implementation, so we need to prepend the configured + // Git's directory to PATH. But as our internal command interface will + // overwrite PATH even if we pass it in here, we need to work around it + // and instead execute the command with `env PATH=$GITDIR:$PATH`. + gitDir := path.Dir(command.GitPath()) + if path, ok := os.LookupEnv("PATH"); ok && gitDir != "." { + args = append([]string{ + "env", fmt.Sprintf("PATH=%s:%s", gitDir, path), + }, args...) + } + + cmd := exec.Command(args[0], args[1:]...) cmd.Dir = config.Config.Ruby.Dir internalCmd, err := command.New(ctx, cmd, nil, nil, nil, exportEnvironment()...) diff --git a/internal/service/blob/lfs_pointers_test.go b/internal/service/blob/lfs_pointers_test.go index 7126b35f8..9f2c8de4f 100644 --- a/internal/service/blob/lfs_pointers_test.go +++ b/internal/service/blob/lfs_pointers_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" "google.golang.org/grpc/codes" @@ -137,7 +138,7 @@ func TestSuccessfulGetNewLFSPointersRequest(t *testing.T) { revision := []byte("46abbb087fcc0fd02c340f0f2f052bd2c7708da3") commiterArgs := []string{"-c", "user.name=Scrooge McDuck", "-c", "user.email=scrooge@mcduck.com"} cmdArgs := append(commiterArgs, "-C", testRepoPath, "cherry-pick", string(revision)) - cmd := exec.Command("git", cmdArgs...) + cmd := exec.Command(command.GitPath(), cmdArgs...) // Skip smudge since it doesn't work with file:// remotes and we don't need it cmd.Env = append(cmd.Env, "GIT_LFS_SKIP_SMUDGE=1") altDirs := "./alt-objects" diff --git a/internal/service/commit/find_commits_test.go b/internal/service/commit/find_commits_test.go index 8e906a3c9..c94b80173 100644 --- a/internal/service/commit/find_commits_test.go +++ b/internal/service/commit/find_commits_test.go @@ -11,6 +11,7 @@ import ( "github.com/golang/protobuf/ptypes/timestamp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" "google.golang.org/grpc/codes" @@ -455,7 +456,7 @@ func TestSuccessfulFindCommitsRequestWithAltGitObjectDirs(t *testing.T) { testRepoCopy, testRepoCopyPath, cleanupFn := testhelper.NewTestRepoWithWorktree(t) defer cleanupFn() - cmd := exec.Command("git", "-C", testRepoCopyPath, + cmd := exec.Command(command.GitPath(), "-C", testRepoCopyPath, "-c", fmt.Sprintf("user.name=%s", committerName), "-c", fmt.Sprintf("user.email=%s", committerEmail), "commit", "--allow-empty", "-m", "An empty commit") diff --git a/internal/service/commit/isancestor_test.go b/internal/service/commit/isancestor_test.go index 48998d09a..f63b422a8 100644 --- a/internal/service/commit/isancestor_test.go +++ b/internal/service/commit/isancestor_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/helper" "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" @@ -190,7 +191,7 @@ func TestSuccessfulIsAncestorRequestWithAltGitObjectDirs(t *testing.T) { previousHead := testhelper.MustRunCommand(t, nil, "git", "-C", testRepoCopyPath, "show", "--format=format:%H", "--no-patch", "HEAD") - cmd := exec.Command("git", "-C", testRepoCopyPath, + cmd := exec.Command(command.GitPath(), "-C", testRepoCopyPath, "-c", fmt.Sprintf("user.name=%s", committerName), "-c", fmt.Sprintf("user.email=%s", committerEmail), "commit", "--allow-empty", "-m", "An empty commit") diff --git a/internal/service/operations/branches_test.go b/internal/service/operations/branches_test.go index bd235e572..e6879d9f1 100644 --- a/internal/service/operations/branches_test.go +++ b/internal/service/operations/branches_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/config" "gitlab.com/gitlab-org/gitaly/internal/git/log" "gitlab.com/gitlab-org/gitaly/internal/helper" @@ -79,7 +80,7 @@ func TestSuccessfulCreateBranchRequest(t *testing.T) { response, err := client.UserCreateBranch(ctx, request) if testCase.expectedBranch != nil { - defer exec.Command("git", "-C", testRepoPath, "branch", "-D", branchName).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "branch", "-D", branchName).Run() } require.NoError(t, err) @@ -162,7 +163,7 @@ func TestUserCreateBranchWithTransaction(t *testing.T) { for _, tc := range testcases { t.Run(tc.desc, func(t *testing.T) { - defer exec.Command("git", "-C", testRepoPath, "branch", "-D", "new-branch").Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "branch", "-D", "new-branch").Run() client, conn := newOperationClient(t, tc.address) defer conn.Close() @@ -211,7 +212,7 @@ func testSuccessfulGitHooksForUserCreateBranchRequest(t *testing.T, ctx context. for _, hookName := range GitlabHooks { t.Run(hookName, func(t *testing.T) { - defer exec.Command("git", "-C", testRepoPath, "branch", "-D", branchName).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "branch", "-D", branchName).Run() hookOutputTempPath, cleanup := testhelper.WriteEnvToCustomHook(t, testRepoPath, hookName) defer cleanup() @@ -348,7 +349,7 @@ func TestSuccessfulUserDeleteBranchRequest(t *testing.T) { branchNameInput := "to-be-deleted-soon-branch" - defer exec.Command("git", "-C", testRepoPath, "branch", "-d", branchNameInput).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "branch", "-d", branchNameInput).Run() testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "branch", branchNameInput) @@ -378,7 +379,7 @@ func TestSuccessfulGitHooksForUserDeleteBranchRequest(t *testing.T) { defer conn.Close() branchNameInput := "to-be-deleted-soon-branch" - defer exec.Command("git", "-C", testRepoPath, "branch", "-d", branchNameInput).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "branch", "-d", branchNameInput).Run() request := &gitalypb.UserDeleteBranchRequest{ Repository: testRepo, @@ -470,7 +471,7 @@ func TestFailedUserDeleteBranchDueToHooks(t *testing.T) { branchNameInput := "to-be-deleted-soon-branch" testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "branch", branchNameInput) - defer exec.Command("git", "-C", testRepoPath, "branch", "-d", branchNameInput).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "branch", "-d", branchNameInput).Run() request := &gitalypb.UserDeleteBranchRequest{ Repository: testRepo, diff --git a/internal/service/operations/merge_test.go b/internal/service/operations/merge_test.go index 2c60c3718..5a9ad356e 100644 --- a/internal/service/operations/merge_test.go +++ b/internal/service/operations/merge_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" gitlog "gitlab.com/gitlab-org/gitaly/internal/git/log" "gitlab.com/gitlab-org/gitaly/internal/helper/text" "gitlab.com/gitlab-org/gitaly/internal/testhelper" @@ -307,7 +308,7 @@ func TestSuccessfulUserFFBranchRequest(t *testing.T) { } testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "branch", "-f", branchName, "6d394385cf567f80a8fd85055db1ab4c5295806f") - defer exec.Command("git", "-C", testRepoPath, "branch", "-d", branchName).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "branch", "-d", branchName).Run() resp, err := client.UserFFBranch(ctx, request) require.NoError(t, err) @@ -330,7 +331,7 @@ func TestFailedUserFFBranchRequest(t *testing.T) { branchName := "test-ff-target-branch" testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "branch", "-f", branchName, "6d394385cf567f80a8fd85055db1ab4c5295806f") - defer exec.Command("git", "-C", testRepoPath, "branch", "-d", branchName).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "branch", "-d", branchName).Run() testCases := []struct { desc string @@ -431,7 +432,7 @@ func TestFailedUserFFBranchDueToHooks(t *testing.T) { } testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "branch", "-f", branchName, "6d394385cf567f80a8fd85055db1ab4c5295806f") - defer exec.Command("git", "-C", testRepoPath, "branch", "-d", branchName).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "branch", "-d", branchName).Run() hookContent := []byte("#!/bin/sh\necho 'failure'\nexit 1") @@ -469,7 +470,7 @@ func TestSuccessfulUserMergeToRefRequest(t *testing.T) { // Writes in existingTargetRef beforeRefreshCommitSha := "a5391128b0ef5d21df5dd23d98557f4ef12fae20" - out, err := exec.Command("git", "-C", testRepoPath, "update-ref", string(existingTargetRef), beforeRefreshCommitSha).CombinedOutput() + out, err := exec.Command(command.GitPath(), "-C", testRepoPath, "update-ref", string(existingTargetRef), beforeRefreshCommitSha).CombinedOutput() require.NoError(t, err, "give an existing state to the target ref: %s", out) testCases := []struct { @@ -706,12 +707,12 @@ func TestUserMergeToRefIgnoreHooksRequest(t *testing.T) { func prepareMergeBranch(t *testing.T, testRepoPath string) { deleteBranch(testRepoPath, mergeBranchName) - out, err := exec.Command("git", "-C", testRepoPath, "branch", mergeBranchName, mergeBranchHeadBefore).CombinedOutput() + out, err := exec.Command(command.GitPath(), "-C", testRepoPath, "branch", mergeBranchName, mergeBranchHeadBefore).CombinedOutput() require.NoError(t, err, "set up branch to merge into: %s", out) } func deleteBranch(testRepoPath, branchName string) { - exec.Command("git", "-C", testRepoPath, "branch", "-D", branchName).Run() + exec.Command(command.GitPath(), "-C", testRepoPath, "branch", "-D", branchName).Run() } // This error is used as a sentinel value diff --git a/internal/service/operations/tags_test.go b/internal/service/operations/tags_test.go index 549efdad3..8f774f454 100644 --- a/internal/service/operations/tags_test.go +++ b/internal/service/operations/tags_test.go @@ -3,12 +3,14 @@ package operations import ( "context" "fmt" + "io/ioutil" "os" "os/exec" - "path/filepath" + "path" "testing" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/git/log" "gitlab.com/gitlab-org/gitaly/internal/helper/text" "gitlab.com/gitlab-org/gitaly/internal/metadata/featureflag" @@ -39,7 +41,7 @@ func TestSuccessfulUserDeleteTagRequest(t *testing.T) { tagNameInput := "to-be-deleted-soon-tag" - defer exec.Command("git", "-C", testRepoPath, "tag", "-d", tagNameInput).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "tag", "-d", tagNameInput).Run() testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "tag", tagNameInput) @@ -84,7 +86,7 @@ func testSuccessfulGitHooksForUserDeleteTagRequest(t *testing.T, ctx context.Con defer cleanupFn() tagNameInput := "to-be-déleted-soon-tag" - defer exec.Command("git", "-C", testRepoPath, "tag", "-d", tagNameInput).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "tag", "-d", tagNameInput).Run() request := &gitalypb.UserDeleteTagRequest{ Repository: testRepo, @@ -108,6 +110,65 @@ func testSuccessfulGitHooksForUserDeleteTagRequest(t *testing.T, ctx context.Con } } +func writeAssertObjectTypePreReceiveHook(t *testing.T) (string, func()) { + t.Helper() + + hook := fmt.Sprintf(`#!/usr/bin/env ruby + +commands = STDIN.each_line.map(&:chomp) +unless commands.size == 1 + abort "expected 1 ref update command, got #{commands.size}" +end + +new_value = commands[0].split(' ', 3)[1] +abort 'missing new_value' unless new_value + +out = IO.popen(%%W[%s cat-file -t #{new_value}], &:read) +abort 'cat-file failed' unless $?.success? + +unless out.chomp == ARGV[0] + abort "error: expected #{ARGV[0]} object, got #{out}" +end`, command.GitPath()) + + dir, err := ioutil.TempDir("", "gitaly-temp-dir-*") + require.NoError(t, err) + hookPath := path.Join(dir, "pre-receive") + + require.NoError(t, ioutil.WriteFile(hookPath, []byte(hook), 0755)) + + return hookPath, func() { + os.RemoveAll(dir) + } +} + +func writeAssertObjectTypeUpdateHook(t *testing.T) (string, func()) { + t.Helper() + + hook := fmt.Sprintf(`#!/usr/bin/env ruby + +expected_object_type = ARGV.shift +new_value = ARGV[2] + +abort "missing new_value" unless new_value + +out = IO.popen(%%W[%s cat-file -t #{new_value}], &:read) +abort 'cat-file failed' unless $?.success? + +unless out.chomp == expected_object_type + abort "error: expected #{expected_object_type} object, got #{out}" +end`, command.GitPath()) + + dir, err := ioutil.TempDir("", "gitaly-temp-dir-*") + require.NoError(t, err) + hookPath := path.Join(dir, "pre-receive") + + require.NoError(t, ioutil.WriteFile(hookPath, []byte(hook), 0755)) + + return hookPath, func() { + os.RemoveAll(dir) + } +} + func TestSuccessfulUserCreateTagRequest(t *testing.T) { featureSets, err := testhelper.NewFeatureSets([]featureflag.FeatureFlag{featureflag.ReferenceTransactions}) require.NoError(t, err) @@ -134,10 +195,11 @@ func TestSuccessfulUserCreateTagRequest(t *testing.T) { inputTagName := "to-be-créated-soon" - cwd, err := os.Getwd() - require.NoError(t, err) - preReceiveHook := filepath.Join(cwd, "testdata/pre-receive-expect-object-type") - updateHook := filepath.Join(cwd, "testdata/update-expect-object-type") + preReceiveHook, cleanup := writeAssertObjectTypePreReceiveHook(t) + defer cleanup() + + updateHook, cleanup := writeAssertObjectTypeUpdateHook(t) + defer cleanup() testCases := []struct { desc string @@ -195,7 +257,7 @@ func TestSuccessfulUserCreateTagRequest(t *testing.T) { require.NoError(t, err, "error from calling RPC") require.Empty(t, response.PreReceiveError, "PreReceiveError must be empty, signalling the push was accepted") - defer exec.Command("git", "-C", testRepoPath, "tag", "-d", inputTagName).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "tag", "-d", inputTagName).Run() id := testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "rev-parse", inputTagName) testCase.expectedTag.Id = text.ChompBytes(id) @@ -241,7 +303,7 @@ func testSuccessfulGitHooksForUserCreateTagRequest(t *testing.T, ctx context.Con for _, hookName := range GitlabHooks { t.Run(hookName, func(t *testing.T) { - defer exec.Command("git", "-C", testRepoPath, "tag", "-d", tagName).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "tag", "-d", tagName).Run() hookOutputTempPath, cleanup := testhelper.WriteEnvToCustomHook(t, testRepoPath, hookName) defer cleanup() @@ -329,7 +391,7 @@ func testFailedUserDeleteTagDueToHooks(t *testing.T, ctx context.Context) { tagNameInput := "to-be-deleted-soon-tag" testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "tag", tagNameInput) - defer exec.Command("git", "-C", testRepoPath, "tag", "-d", tagNameInput).Run() + defer exec.Command(command.GitPath(), "-C", testRepoPath, "tag", "-d", tagNameInput).Run() request := &gitalypb.UserDeleteTagRequest{ Repository: testRepo, diff --git a/internal/service/operations/testdata/assert_git_object_type.rb b/internal/service/operations/testdata/assert_git_object_type.rb deleted file mode 100644 index 2e1be4b09..000000000 --- a/internal/service/operations/testdata/assert_git_object_type.rb +++ /dev/null @@ -1,8 +0,0 @@ -def assert_git_object_type!(oid, expected_type) - out = IO.popen(%W[git cat-file -t #{oid}], &:read) - abort 'cat-file failed' unless $?.success? - - unless out.chomp == expected_type - abort "error: expected #{expected_type} object, got #{out}" - end -end diff --git a/internal/service/operations/testdata/pre-receive-expect-object-type b/internal/service/operations/testdata/pre-receive-expect-object-type deleted file mode 100755 index 10c55de3a..000000000 --- a/internal/service/operations/testdata/pre-receive-expect-object-type +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env ruby -require_relative 'assert_git_object_type.rb' - -commands = STDIN.each_line.map(&:chomp) -unless commands.size == 1 - abort "expected 1 ref update command, got #{commands.size}" -end - -new_value = commands[0].split(' ', 3)[1] -abort 'missing new_value' unless new_value - -assert_git_object_type!(new_value, ARGV[0]) diff --git a/internal/service/operations/testdata/update-expect-object-type b/internal/service/operations/testdata/update-expect-object-type deleted file mode 100755 index 8889e3e3c..000000000 --- a/internal/service/operations/testdata/update-expect-object-type +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env ruby -require_relative 'assert_git_object_type.rb' - -expected_object_type = ARGV.shift -new_value = ARGV[2] - -abort "missing new_value" unless new_value - -assert_git_object_type!(new_value, expected_object_type) diff --git a/internal/service/ref/refs_test.go b/internal/service/ref/refs_test.go index cb98c6205..72c5070b2 100644 --- a/internal/service/ref/refs_test.go +++ b/internal/service/ref/refs_test.go @@ -13,6 +13,7 @@ import ( "github.com/golang/protobuf/ptypes/timestamp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/git/catfile" "gitlab.com/gitlab-org/gitaly/internal/git/log" "gitlab.com/gitlab-org/gitaly/internal/git/updateref" @@ -770,7 +771,7 @@ func TestFindAllTagNestedTags(t *testing.T) { for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { tags := bytes.NewReader(testhelper.MustRunCommand(t, nil, "git", "-C", testRepoCopyPath, "tag")) - testhelper.MustRunCommand(t, tags, "xargs", "git", "-C", testRepoCopyPath, "tag", "-d") + testhelper.MustRunCommand(t, tags, "xargs", command.GitPath(), "-C", testRepoCopyPath, "tag", "-d") batch, err := catfile.New(ctx, testRepoCopy) require.NoError(t, err) @@ -1756,7 +1757,7 @@ func TestFindTagNestedTag(t *testing.T) { t.Run(tc.description, func(t *testing.T) { tags := bytes.NewReader(testhelper.MustRunCommand(t, nil, "git", "-C", testRepoCopyPath, "tag")) - testhelper.MustRunCommand(t, tags, "xargs", "git", "-C", testRepoCopyPath, "tag", "-d") + testhelper.MustRunCommand(t, tags, "xargs", command.GitPath(), "-C", testRepoCopyPath, "tag", "-d") batch, err := catfile.New(ctx, testRepoCopy) require.NoError(t, err) diff --git a/internal/service/repository/calculate_checksum_test.go b/internal/service/repository/calculate_checksum_test.go index 450127165..949c403b3 100644 --- a/internal/service/repository/calculate_checksum_test.go +++ b/internal/service/repository/calculate_checksum_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" "google.golang.org/grpc/codes" @@ -28,7 +29,7 @@ func TestSuccessfulCalculateChecksum(t *testing.T) { require.NoError(t, os.MkdirAll(path.Join(testRepoPath, d), 0755)) } require.NoError(t, exec.Command("cp", "testdata/checksum-test-packed-refs", path.Join(testRepoPath, "packed-refs")).Run()) - require.NoError(t, exec.Command("git", "-C", testRepoPath, "symbolic-ref", "HEAD", "refs/heads/feature").Run()) + require.NoError(t, exec.Command(command.GitPath(), "-C", testRepoPath, "symbolic-ref", "HEAD", "refs/heads/feature").Run()) request := &gitalypb.CalculateChecksumRequest{Repository: testRepo} testCtx, cancelCtx := testhelper.Context() diff --git a/internal/service/repository/cleanup_test.go b/internal/service/repository/cleanup_test.go index 7b8256c17..d29aeb73a 100644 --- a/internal/service/repository/cleanup_test.go +++ b/internal/service/repository/cleanup_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" @@ -239,7 +240,7 @@ func TestCleanupDisconnectedWorktrees(t *testing.T) { if !pre2_20_0 { err := exec.Command( - "git", + command.GitPath(), testhelper.AddWorktreeArgs(testRepoPath, worktreePath)..., ).Run() require.Error(t, err, diff --git a/internal/service/repository/redirecting_test_server_test.go b/internal/service/repository/redirecting_test_server_test.go index f5a200488..3ae1e37d4 100644 --- a/internal/service/repository/redirecting_test_server_test.go +++ b/internal/service/repository/redirecting_test_server_test.go @@ -44,7 +44,7 @@ func TestRedirectingServerRedirects(t *testing.T) { httpServerState, redirectingServer := StartRedirectingTestServer() // we only test for redirection, this command can fail after that - cmd := exec.Command("git", "-c", "http.followRedirects=true", "clone", "--bare", redirectingServer.URL, dir) + cmd := exec.Command(command.GitPath(), "-c", "http.followRedirects=true", "clone", "--bare", redirectingServer.URL, dir) cmd.Env = append(command.GitEnv, cmd.Env...) cmd.Run() diff --git a/internal/service/repository/repack_test.go b/internal/service/repository/repack_test.go index bd2ec0635..39d89d384 100644 --- a/internal/service/repository/repack_test.go +++ b/internal/service/repository/repack_test.go @@ -14,6 +14,7 @@ import ( "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/git/gittest" "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" @@ -89,7 +90,7 @@ func TestRepackLocal(t *testing.T) { commiterArgs := []string{"-c", "user.name=Scrooge McDuck", "-c", "user.email=scrooge@mcduck.com"} cmdArgs := append(commiterArgs, "-C", repoPath, "commit", "--allow-empty", "-m", "An empty commit") - cmd := exec.Command("git", cmdArgs...) + cmd := exec.Command(command.GitPath(), cmdArgs...) altObjectsDir := "./alt-objects" altDirsCommit := testhelper.CreateCommitInAlternateObjectDirectory(t, repoPath, altObjectsDir, cmd) diff --git a/internal/service/repository/search_files_test.go b/internal/service/repository/search_files_test.go index ffb596196..e3738d0d4 100644 --- a/internal/service/repository/search_files_test.go +++ b/internal/service/repository/search_files_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/config" "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" @@ -128,7 +129,7 @@ func TestSearchFilesByContentSuccessful(t *testing.T) { ref: "many_files", output: contentOutputLines, skip: func(t *testing.T) { - cmd := exec.Command("git", "-C", testRepoPath, "grep", "--perl-regexp", "(*LIMIT_MATCH=1)foobar", "many_files") + cmd := exec.Command(command.GitPath(), "-C", testRepoPath, "grep", "--perl-regexp", "(*LIMIT_MATCH=1)foobar", "many_files") err := cmd.Run() if exitError, ok := err.(*exec.ExitError); ok && exitError.ExitCode() == 128 { t.Skip("Git does not seem to be compiled with support for PCRE2") diff --git a/internal/service/repository/snapshot_test.go b/internal/service/repository/snapshot_test.go index 8659b00b0..4802100fc 100644 --- a/internal/service/repository/snapshot_test.go +++ b/internal/service/repository/snapshot_test.go @@ -16,6 +16,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/internal/archive" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/git/catfile" "gitlab.com/gitlab-org/gitaly/internal/helper" @@ -127,7 +128,7 @@ func TestGetSnapshotWithDedupe(t *testing.T) { const committerName = "Scrooge McDuck" const committerEmail = "scrooge@mcduck.com" - cmd := exec.Command("git", "-C", repoPath, + cmd := exec.Command(command.GitPath(), "-C", repoPath, "-c", fmt.Sprintf("user.name=%s", committerName), "-c", fmt.Sprintf("user.email=%s", committerEmail), "commit", "--allow-empty", "-m", "An empty commit") @@ -147,7 +148,7 @@ func TestGetSnapshotWithDedupe(t *testing.T) { require.NoError(t, ioutil.WriteFile(alternatesPath, []byte(path.Join(repoPath, ".git", fmt.Sprintf("%s\n", alternateObjDir))), 0644)) // write another commit and ensure we can find it - cmd = exec.Command("git", "-C", repoPath, + cmd = exec.Command(command.GitPath(), "-C", repoPath, "-c", fmt.Sprintf("user.name=%s", committerName), "-c", fmt.Sprintf("user.email=%s", committerEmail), "commit", "--allow-empty", "-m", "Another empty commit") @@ -203,7 +204,7 @@ func TestGetSnapshotWithDedupeSoftFailures(t *testing.T) { committerName := "Scrooge McDuck" committerEmail := "scrooge@mcduck.com" - cmd := exec.Command("git", "-C", repoPath, + cmd := exec.Command(command.GitPath(), "-C", repoPath, "-c", fmt.Sprintf("user.name=%s", committerName), "-c", fmt.Sprintf("user.email=%s", committerEmail), "commit", "--allow-empty", "-m", "An empty commit") diff --git a/internal/service/smarthttp/inforefs_test.go b/internal/service/smarthttp/inforefs_test.go index e87b007e6..18efdca10 100644 --- a/internal/service/smarthttp/inforefs_test.go +++ b/internal/service/smarthttp/inforefs_test.go @@ -92,7 +92,7 @@ func TestSuccessfulInfoRefsUploadPackWithGitConfigOptions(t *testing.T) { } func TestSuccessfulInfoRefsUploadPackWithGitProtocol(t *testing.T) { - restore := testhelper.EnableGitProtocolV2Support() + restore := testhelper.EnableGitProtocolV2Support(t) defer restore() serverSocketPath, stop := runSmartHTTPServer(t) @@ -125,7 +125,7 @@ func TestSuccessfulInfoRefsUploadPackWithGitProtocol(t *testing.T) { envData, err := testhelper.GetGitEnvData() require.NoError(t, err) - require.Equal(t, fmt.Sprintf("GIT_PROTOCOL=%s\n", git.ProtocolV2), envData) + require.Contains(t, envData, fmt.Sprintf("GIT_PROTOCOL=%s\n", git.ProtocolV2)) } func makeInfoRefsUploadPackRequest(ctx context.Context, t *testing.T, serverSocketPath string, rpcRequest *gitalypb.InfoRefsRequest) ([]byte, error) { diff --git a/internal/service/smarthttp/receive_pack_test.go b/internal/service/smarthttp/receive_pack_test.go index eeec6e91a..64e472aa0 100644 --- a/internal/service/smarthttp/receive_pack_test.go +++ b/internal/service/smarthttp/receive_pack_test.go @@ -83,7 +83,7 @@ func TestSuccessfulReceivePackRequest(t *testing.T) { } func TestSuccessfulReceivePackRequestWithGitProtocol(t *testing.T) { - restore := testhelper.EnableGitProtocolV2Support() + restore := testhelper.EnableGitProtocolV2Support(t) defer restore() serverSocketPath, stop := runSmartHTTPServer(t) @@ -416,7 +416,8 @@ func testPostReceivePackToHooks(t *testing.T, ctx context.Context) { testhelper.WriteTemporaryGitlabShellConfigFile(t, tempGitlabShellDir, testhelper.GitlabShellConfig{GitlabURL: ts.URL}) testhelper.WriteShellSecretFile(t, tempGitlabShellDir, secretToken) - testhelper.WriteCustomHook(testRepoPath, "pre-receive", []byte(testhelper.CheckNewObjectExists)) + cleanup = testhelper.WriteCheckNewObjectExistsHook(t, testRepoPath) + defer cleanup() config.Config.Gitlab.URL = ts.URL config.Config.Gitlab.SecretFile = filepath.Join(tempGitlabShellDir, ".gitlab_shell_secret") diff --git a/internal/service/smarthttp/testdata/env_git b/internal/service/smarthttp/testdata/env_git deleted file mode 120000 index a01a70012..000000000 --- a/internal/service/smarthttp/testdata/env_git +++ /dev/null @@ -1 +0,0 @@ -../../../testhelper/env_git
\ No newline at end of file diff --git a/internal/service/smarthttp/upload_pack_test.go b/internal/service/smarthttp/upload_pack_test.go index 7b6b6e631..2077904a6 100644 --- a/internal/service/smarthttp/upload_pack_test.go +++ b/internal/service/smarthttp/upload_pack_test.go @@ -168,7 +168,7 @@ func TestUploadPackRequestWithGitConfigOptions(t *testing.T) { } func TestUploadPackRequestWithGitProtocol(t *testing.T) { - restore := testhelper.EnableGitProtocolV2Support() + restore := testhelper.EnableGitProtocolV2Support(t) defer restore() serverSocketPath, stop := runSmartHTTPServer(t) diff --git a/internal/service/ssh/receive_pack_test.go b/internal/service/ssh/receive_pack_test.go index 059ed950b..613adf085 100644 --- a/internal/service/ssh/receive_pack_test.go +++ b/internal/service/ssh/receive_pack_test.go @@ -15,6 +15,7 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/config" "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/git/hooks" @@ -110,7 +111,7 @@ func TestReceivePackPushSuccess(t *testing.T) { } func TestReceivePackPushSuccessWithGitProtocol(t *testing.T) { - restore := testhelper.EnableGitProtocolV2Support() + restore := testhelper.EnableGitProtocolV2Support(t) defer restore() serverSocketPath, stop := runSSHServer(t) @@ -126,7 +127,7 @@ func TestReceivePackPushSuccessWithGitProtocol(t *testing.T) { envData, err := testhelper.GetGitEnvData() require.NoError(t, err) - require.Equal(t, fmt.Sprintf("GIT_PROTOCOL=%s\n", git.ProtocolV2), envData) + require.Contains(t, envData, fmt.Sprintf("GIT_PROTOCOL=%s\n", git.ProtocolV2)) } func TestReceivePackPushFailure(t *testing.T) { @@ -211,7 +212,7 @@ func TestSSHReceivePackToHooks(t *testing.T) { glRepository := "some_repo" glID := "key-123" - restore := testhelper.EnableGitProtocolV2Support() + restore := testhelper.EnableGitProtocolV2Support(t) defer restore() serverSocketPath, stop := runSSHServer(t) @@ -247,7 +248,8 @@ func TestSSHReceivePackToHooks(t *testing.T) { config.Config.Gitlab.URL = ts.URL config.Config.Gitlab.SecretFile = filepath.Join(tempGitlabShellDir, ".gitlab_shell_secret") - testhelper.WriteCustomHook(cloneDetails.RemoteRepoPath, "pre-receive", []byte(testhelper.CheckNewObjectExists)) + cleanup = testhelper.WriteCheckNewObjectExistsHook(t, cloneDetails.RemoteRepoPath) + defer cleanup() lHead, rHead, err := sshPush(t, cloneDetails, serverSocketPath, pushParams{ storageName: testRepo.GetStorageName(), @@ -261,7 +263,7 @@ func TestSSHReceivePackToHooks(t *testing.T) { envData, err := testhelper.GetGitEnvData() require.NoError(t, err) - require.Equal(t, fmt.Sprintf("GIT_PROTOCOL=%s\n", git.ProtocolV2), envData) + require.Contains(t, envData, fmt.Sprintf("GIT_PROTOCOL=%s\n", git.ProtocolV2)) } // SSHCloneDetails encapsulates values relevant for a test clone @@ -317,13 +319,13 @@ func sshPush(t *testing.T, cloneDetails SSHCloneDetails, serverSocketPath string }) require.NoError(t, err) - cmd := exec.Command("git", "-C", cloneDetails.LocalRepoPath, "push", "-v", "git@localhost:test/test.git", "master") + cmd := exec.Command(command.GitPath(), "-C", cloneDetails.LocalRepoPath, "push", "-v", "git@localhost:test/test.git", "master") cmd.Env = []string{ fmt.Sprintf("GITALY_PAYLOAD=%s", payload), fmt.Sprintf("GITALY_ADDRESS=%s", serverSocketPath), - fmt.Sprintf("PATH=%s", ".:"+os.Getenv("PATH")), fmt.Sprintf(`GIT_SSH_COMMAND=%s receive-pack`, gitalySSHPath), } + out, err := cmd.CombinedOutput() if err != nil { return "", "", fmt.Errorf("error pushing: %v: %q", err, out) diff --git a/internal/service/ssh/testdata/env_git b/internal/service/ssh/testdata/env_git deleted file mode 120000 index a01a70012..000000000 --- a/internal/service/ssh/testdata/env_git +++ /dev/null @@ -1 +0,0 @@ -../../../testhelper/env_git
\ No newline at end of file diff --git a/internal/service/ssh/upload_archive_test.go b/internal/service/ssh/upload_archive_test.go index 334e11864..d39f636f2 100644 --- a/internal/service/ssh/upload_archive_test.go +++ b/internal/service/ssh/upload_archive_test.go @@ -9,6 +9,7 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" "google.golang.org/grpc/codes" @@ -101,7 +102,7 @@ func TestUploadArchiveSuccess(t *testing.T) { serverSocketPath, stop := runSSHServer(t) defer stop() - cmd := exec.Command("git", "archive", "master", "--remote=git@localhost:test/test.git") + cmd := exec.Command(command.GitPath(), "archive", "master", "--remote=git@localhost:test/test.git") err := testArchive(t, serverSocketPath, testRepo, cmd) require.NoError(t, err) diff --git a/internal/service/ssh/upload_pack_test.go b/internal/service/ssh/upload_pack_test.go index 351364418..b59ce5b2d 100644 --- a/internal/service/ssh/upload_pack_test.go +++ b/internal/service/ssh/upload_pack_test.go @@ -14,6 +14,7 @@ import ( "github.com/prometheus/client_golang/prometheus" promtest "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/helper/text" "gitlab.com/gitlab-org/gitaly/internal/testhelper" @@ -205,12 +206,12 @@ func TestUploadPackCloneSuccess(t *testing.T) { deepen float64 }{ { - cmd: exec.Command("git", "clone", "git@localhost:test/test.git", localRepoPath), + cmd: exec.Command(command.GitPath(), "clone", "git@localhost:test/test.git", localRepoPath), desc: "full clone", deepen: 0, }, { - cmd: exec.Command("git", "clone", "--depth", "1", "git@localhost:test/test.git", localRepoPath), + cmd: exec.Command(command.GitPath(), "clone", "--depth", "1", "git@localhost:test/test.git", localRepoPath), desc: "shallow clone", deepen: 1, }, @@ -271,7 +272,7 @@ func TestUploadPackCloneWithPartialCloneFilter(t *testing.T) { localPath := path.Join(testRepoRoot, fmt.Sprintf("gitlab-test-upload-pack-local-%s", tc.desc)) cmd := cloneCommand{ repository: testRepo, - command: exec.Command("git", append(tc.cloneArgs, localPath)...), + command: exec.Command(command.GitPath(), append(tc.cloneArgs, localPath)...), server: serverSocketPath, } err := cmd.execute(t) @@ -285,12 +286,6 @@ func TestUploadPackCloneWithPartialCloneFilter(t *testing.T) { } func TestUploadPackCloneSuccessWithGitProtocol(t *testing.T) { - restore := testhelper.EnableGitProtocolV2Support() - defer restore() - - serverSocketPath, stop := runSSHServer(t) - defer stop() - localRepoPath := path.Join(testRepoRoot, "gitlab-test-upload-pack-local") tests := []struct { @@ -298,17 +293,23 @@ func TestUploadPackCloneSuccessWithGitProtocol(t *testing.T) { desc string }{ { - cmd: exec.Command("git", "clone", "git@localhost:test/test.git", localRepoPath), + cmd: exec.Command(command.GitPath(), "clone", "git@localhost:test/test.git", localRepoPath), desc: "full clone", }, { - cmd: exec.Command("git", "clone", "--depth", "1", "git@localhost:test/test.git", localRepoPath), + cmd: exec.Command(command.GitPath(), "clone", "--depth", "1", "git@localhost:test/test.git", localRepoPath), desc: "shallow clone", }, } for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { + restore := testhelper.EnableGitProtocolV2Support(t) + defer restore() + + serverSocketPath, stop := runSSHServer(t) + defer stop() + cmd := cloneCommand{ repository: testRepo, command: tc.cmd, @@ -322,7 +323,7 @@ func TestUploadPackCloneSuccessWithGitProtocol(t *testing.T) { envData, err := testhelper.GetGitEnvData() require.NoError(t, err) - require.Equal(t, fmt.Sprintf("GIT_PROTOCOL=%s\n", git.ProtocolV2), envData) + require.Contains(t, envData, fmt.Sprintf("GIT_PROTOCOL=%s\n", git.ProtocolV2)) }) } } @@ -335,7 +336,7 @@ func TestUploadPackCloneHideTags(t *testing.T) { cmd := cloneCommand{ repository: testRepo, - command: exec.Command("git", "clone", "--mirror", "git@localhost:test/test.git", localRepoPath), + command: exec.Command(command.GitPath(), "clone", "--mirror", "git@localhost:test/test.git", localRepoPath), server: serverSocketPath, gitConfig: "transfer.hideRefs=refs/tags", } @@ -360,7 +361,7 @@ func TestUploadPackCloneFailure(t *testing.T) { StorageName: "foobar", RelativePath: testRepo.GetRelativePath(), }, - command: exec.Command("git", "clone", "git@localhost:test/test.git", localRepoPath), + command: exec.Command(command.GitPath(), "clone", "git@localhost:test/test.git", localRepoPath), server: serverSocketPath, } err := cmd.execute(t) diff --git a/internal/testhelper/commit.go b/internal/testhelper/commit.go index d8199882b..3769f0b66 100644 --- a/internal/testhelper/commit.go +++ b/internal/testhelper/commit.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/helper/text" ) @@ -80,7 +81,7 @@ func CreateCommitInAlternateObjectDirectory(t testing.TB, repoPath, altObjectsDi t.Fatalf("stdout: %s, stderr: %s", output, stderr) } - cmd = exec.Command("git", "-C", repoPath, "rev-parse", "HEAD") + cmd = exec.Command(command.GitPath(), "-C", repoPath, "rev-parse", "HEAD") cmd.Env = gitObjectEnv currentHead, err := cmd.Output() require.NoError(t, err) diff --git a/internal/testhelper/env_git b/internal/testhelper/env_git deleted file mode 100755 index 7739eaeef..000000000 --- a/internal/testhelper/env_git +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -mkdir -p testdata -env | grep ^GIT_PROTOCOL= > testdata/git-env -exec git "$@" diff --git a/internal/testhelper/git_protocol.go b/internal/testhelper/git_protocol.go index ab0377551..a57b85906 100644 --- a/internal/testhelper/git_protocol.go +++ b/internal/testhelper/git_protocol.go @@ -1,20 +1,41 @@ package testhelper import ( + "fmt" + "io/ioutil" + "os" + "path" + "testing" + + "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" "gitlab.com/gitlab-org/gitaly/internal/config" ) -// EnableGitProtocolV2Support replaces the git binary in config with an -// `env_git` wrapper that allows the protocol to be tested. It returns a -// function that restores the given settings. -// -// Because we don't know how to get to that wrapper script from the current -// working directory, callers must create a symbolic link to the `env_git` file -// in their own `testdata` directories. -func EnableGitProtocolV2Support() func() { +// EnableGitProtocolV2Support replaces the git binary in config with a +// wrapper that allows the protocol to be tested. It returns a function that +// restores the given settings as well as an array of environment variables +// which need to be set when invoking Git with this setup. +func EnableGitProtocolV2Support(t *testing.T) func() { + script := fmt.Sprintf(`#!/bin/sh +mkdir -p testdata +env | grep ^GIT_PROTOCOL= >>testdata/git-env +exec "%s" "$@" +`, command.GitPath()) + + dir, err := ioutil.TempDir("", "gitaly-test-*") + require.NoError(t, err) + + path := path.Join(dir, "git") + + cleanup, err := WriteExecutable(path, []byte(script)) + require.NoError(t, err) + oldGitBinPath := config.Config.Git.BinPath - config.Config.Git.BinPath = "testdata/env_git" + config.Config.Git.BinPath = path return func() { + os.Remove("testdata/git-env") config.Config.Git.BinPath = oldGitBinPath + cleanup() } } diff --git a/internal/testhelper/testdata/home/bin/git b/internal/testhelper/testdata/home/bin/git new file mode 100755 index 000000000..78f4de70b --- /dev/null +++ b/internal/testhelper/testdata/home/bin/git @@ -0,0 +1,12 @@ +#!/bin/sh + +# This wrapper has the single intention of catching any Git invocations via +# $PATH instead of via either our Git DSL or via `config.GitPath()`. Our tests +# are thus set up with PATH including this binary. As the binary always prints +# an error message and exits with a weird status code, tests should fail +# quickly and with a hopefully helpful message making the actual error quick to +# spot. + +echo 'Git executable from $PATH was picked up. Please fix code to use `command.GitPath()` instead.' >&2 + +exit 63 diff --git a/internal/testhelper/testhelper.go b/internal/testhelper/testhelper.go index 16084860d..df9545013 100644 --- a/internal/testhelper/testhelper.go +++ b/internal/testhelper/testhelper.go @@ -216,15 +216,17 @@ func MustRunCommand(t testing.TB, stdin io.Reader, name string, args ...string) t.Helper() } - cmd := exec.Command(name, args...) - + var cmd *exec.Cmd if name == "git" { + cmd = exec.Command(command.GitPath(), args...) cmd.Env = os.Environ() cmd.Env = append(command.GitEnv, cmd.Env...) cmd.Env = append(cmd.Env, "GIT_AUTHOR_DATE=1572776879 +0100", "GIT_COMMITTER_DATE=1572776879 +0100", ) + } else { + cmd = exec.Command(name, args...) } if stdin != nil { @@ -678,7 +680,7 @@ func GitObjectMustNotExist(t testing.TB, repoPath, sha string) { } func gitObjectExists(t testing.TB, repoPath, sha string, exists bool) { - cmd := exec.Command("git", "-C", repoPath, "cat-file", "-e", sha) + cmd := exec.Command(command.GitPath(), "-C", repoPath, "cat-file", "-e", sha) cmd.Env = []string{ "GIT_ALLOW_PROTOCOL=", // To prevent partial clone reaching remote repo over SSH } @@ -762,17 +764,26 @@ func WriteExecutable(path string, content []byte) (func(), error) { }, ioutil.WriteFile(path, content, 0755) } -// CheckNewObjectExists is a script meant to be used as a pre-receive custom hook. -// It only succeeds if it can find the object in the quarantine directory. -// if GIT_OBJECT_DIRECTORY and GIT_ALTERNATE_OBJECT_DIRECTORIES were not passed through correctly to the hooks, -// it will fail -const CheckNewObjectExists = `#!/usr/bin/env ruby +// WriteCheckNewObjectExistsHook writes a pre-receive hook which only succeeds +// if it can find the object in the quarantine directory. if +// GIT_OBJECT_DIRECTORY and GIT_ALTERNATE_OBJECT_DIRECTORIES were not passed +// through correctly to the hooks, it will fail +func WriteCheckNewObjectExistsHook(t *testing.T, repoPath string) func() { + hook := fmt.Sprintf(`#!/usr/bin/env ruby STDIN.each_line do |line| new_object = line.split(' ')[1] exit 1 unless new_object - exit 1 unless system(*%W[git cat-file -e #{new_object}]) + exit 1 unless system(*%%W[%s cat-file -e #{new_object}]) end -` +`, command.GitPath()) + + ioutil.WriteFile("/tmp/file", []byte(hook), 0644) + + cleanup, err := WriteCustomHook(repoPath, "pre-receive", []byte(hook)) + require.NoError(t, err) + + return cleanup +} func WriteBlobs(t testing.TB, testRepoPath string, n int) []string { var blobIDs []string diff --git a/ruby/spec/spec_helper.rb b/ruby/spec/spec_helper.rb index 49e956f92..93a600b7f 100644 --- a/ruby/spec/spec_helper.rb +++ b/ruby/spec/spec_helper.rb @@ -12,10 +12,6 @@ require File.join(__dir__, 'support/helpers/gitlab_shell_helper.rb') Dir[File.join(__dir__, 'support/helpers/*.rb')].each { |f| require f } -Gitlab.config.git.test_global_ivar_override(:bin_path, 'git') -Gitlab.config.git.test_global_ivar_override(:hooks_directory, File.join(Gitlab.config.gitlab_shell.path.to_s, "hooks")) -Gitlab.config.gitaly.test_global_ivar_override(:bin_dir, __dir__) - RSpec.configure do |config| config.include FactoryBot::Syntax::Methods diff --git a/ruby/spec/test_repo_helper.rb b/ruby/spec/test_repo_helper.rb index 5250bfaa7..4ae4c6fe9 100644 --- a/ruby/spec/test_repo_helper.rb +++ b/ruby/spec/test_repo_helper.rb @@ -5,6 +5,10 @@ require 'rugged' $:.unshift(File.expand_path('../proto', __dir__)) require 'gitaly' +Gitlab.config.git.test_global_ivar_override(:bin_path, ENV.fetch('GITALY_TESTING_GIT_BINARY', 'git')) +Gitlab.config.git.test_global_ivar_override(:hooks_directory, File.join(Gitlab.config.gitlab_shell.path.to_s, "hooks")) +Gitlab.config.gitaly.test_global_ivar_override(:bin_dir, __dir__) + DEFAULT_STORAGE_DIR = File.expand_path('../tmp/repositories', __dir__) DEFAULT_STORAGE_NAME = 'default'.freeze TEST_REPO_PATH = File.join(DEFAULT_STORAGE_DIR, 'gitlab-test.git') @@ -104,13 +108,13 @@ module TestRepo end def self.clone_new_repo!(origin, destination) - return if system("git", "clone", "--quiet", "--bare", origin.to_s, destination.to_s) + return if system(Gitlab.config.git.bin_path, "clone", "--quiet", "--bare", origin.to_s, destination.to_s) abort "Failed to clone test repo. Try running 'make prepare-tests' and try again." end def self.init_new_repo!(destination) - return if system("git", "init", "--quiet", "--bare", destination.to_s) + return if system(Gitlab.config.git.bin_path, "init", "--quiet", "--bare", destination.to_s) abort "Failed to init test repo." end |