diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7958632f0a88b6be20a076a17e1ababfb2b0cdb1..21537348aa6613a9110e3f4fadf4e24667ecd370 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -136,7 +136,7 @@ workflow: # But the actual tests should run unprivileged. This assures that we pay # proper attention to permission bits and that we don't modify the source # directory. - - setpriv --reuid=${TEST_UID} --regid=${TEST_UID} --clear-groups --no-new-privs make ${TEST_TARGET} $(test "${GIT_VERSION}" = default && echo WITH_BUNDLED_GIT=YesPlease) + - setpriv --reuid=${TEST_UID} --regid=${TEST_UID} --clear-groups --no-new-privs make ${TEST_TARGET} coverage: /^total:\t+\(statements\)\t+\d+\.\d+%$/ after_script: &test_after_script - go run "${CI_PROJECT_DIR}/tools/panic-parser" diff --git a/.gitlab/issue_templates/Git Version Upgrade.md b/.gitlab/issue_templates/Git Version Upgrade.md index d179aebc645911094e99da281f384c4dccf71a31..e569ffc515e5b9e031ee7ad547531d7ba4aa2ef2 100644 --- a/.gitlab/issue_templates/Git Version Upgrade.md +++ b/.gitlab/issue_templates/Git Version Upgrade.md @@ -11,20 +11,19 @@ Would be really nice to point out contributions made by the Gitaly team, if any. - [ ] Introduce the new Git version behind a feature flag ([Reference](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5587)). - [ ] Introduce the new bundled Git version in the [Makefile](/Makefile). - - [ ] Introduce the new bundled Git execution environment in the [Git package](/internal/git/version.go) behind a feature flag. -- [ ] Roll out the feature flag. + - [ ] Introduce the new bundled Git execution environment in the [Git package](/internal/git/execution_environment.go) behind a feature flag. - [ ] Create an issue for the rollout of the feature flag ([Reference](https://gitlab.com/gitlab-org/gitaly/-/issues/5030)). - [ ] Optional: Create a [change request](https://about.gitlab.com/handbook/engineering/infrastructure/change-management/#change-request-workflows) in case the new Git version contains changes that may cause issues. - [ ] Roll out the feature flag. - - [ ] After a release containing feature flag, remove the feature flag. -- [ ] Update the default Git version. This must happen in a release after the feature flag has been removed to avoid issues with zero-downtime upgrades. + - [ ] Once the upgrade is deemed stable, remove the feature flag. You can do this in any release, including the release that adds the feature flag. +- [ ] Update the default Git version. - [ ] Remove the old bundled Git execution environment. - [ ] Remove the old bundled Git version in the [Makefile](/Makefile). - [ ] Update the default Git distribution by updating `GIT_VERSION` to the new Git version in the [Makefile](/Makefile). - [ ] Optional: Upgrade the minimum required Git version. This is only needed when we want to start using features that have been introduced with the new Git version. - [ ] Update the minimum required Git version in the [Git package](/internal/git/version.go). ([Reference](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5705)) - [ ] Update the minimum required Git version in the [README.md](/README.md). - - [ ] Update the GitLab release notes to reflect the new minimum required Git version. ([Reference](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107565). - + - [ ] Update the GitLab release notes to reflect the new minimum required Git version. ([Reference](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107565). + /label ~"Category:Gitaly" ~"group::gitaly" ~"group::gitaly::git" ~"section::enablement" ~"devops::systems" ~"type::maintenance" ~"maintenance::dependency" /label ~"workflow::ready for development" diff --git a/Makefile b/Makefile index bbf400327f80d4db7db131853f503dbc31d1c43c..163dee1ffa2a60ba51e8da36ab31b7e30a33e623 100644 --- a/Makefile +++ b/Makefile @@ -140,6 +140,7 @@ OVERRIDE_GIT_VERSION ?= ${GIT_VERSION} # if it is either set to the empty string or "default". ifeq (${GIT_VERSION:default=},) override GIT_VERSION := ${GIT_VERSION_2_45} + export WITH_BUNDLED_GIT = YesPlease else # Support both vX.Y.Z and X.Y.Z version patterns, since callers across GitLab # use both. @@ -204,10 +205,16 @@ BUILD_GEM_OPTIONS ?= ## Options to override the name of Gitaly gem BUILD_GEM_NAME ?= gitaly +# Git binaries that are eventually embedded into the Gitaly binary. +GIT_PACKED_EXECUTABLES = $(addprefix ${BUILD_DIR}/bin/gitaly-, \ + $(addsuffix -v2.45, ${GIT_EXECUTABLES})) + # All executables provided by Gitaly. GITALY_EXECUTABLES = $(addprefix ${BUILD_DIR}/bin/,$(notdir $(shell find ${SOURCE_DIR}/cmd -mindepth 1 -maxdepth 1 -type d -print))) # All executables packed inside the Gitaly binary. -GITALY_PACKED_EXECUTABLES = $(filter %gitaly-hooks %gitaly-gpg %gitaly-ssh %gitaly-lfs-smudge, ${GITALY_EXECUTABLES}) +GITALY_PACKED_EXECUTABLES = $(filter %gitaly-hooks %gitaly-gpg %gitaly-ssh %gitaly-lfs-smudge, ${GITALY_EXECUTABLES}) \ + ${GIT_PACKED_EXECUTABLES} + # All executables that should be installed. GITALY_INSTALLED_EXECUTABLES = $(filter-out ${GITALY_PACKED_EXECUTABLES}, ${GITALY_EXECUTABLES}) # Find all Go source files. @@ -304,7 +311,6 @@ build: build-bundled-git prepare-tests: build-bundled-git install: install-bundled-git -export GITALY_TESTING_BUNDLED_GIT_PATH ?= ${BUILD_DIR}/bin else prepare-tests: ${DEPENDENCY_DIR}/git-distribution/git @@ -583,6 +589,7 @@ ${BUILD_DIR}/bin/%: ${BUILD_DIR}/intermediate/% | ${BUILD_DIR}/bin clear-go-build-cache-if-needed: ${Q}if [ -d ${GOCACHE} ] && [ $$(du -sk ${GOCACHE} | cut -f 1) -gt ${GOCACHE_MAX_SIZE_KB} ]; then go clean --cache; fi +${BUILD_DIR}/intermediate/gitaly: build-bundled-git ${BUILD_DIR}/intermediate/gitaly: GO_BUILD_TAGS = ${SERVER_BUILD_TAGS} ${BUILD_DIR}/intermediate/gitaly: ${GITALY_PACKED_EXECUTABLES} ${BUILD_DIR}/intermediate/praefect: GO_BUILD_TAGS = ${SERVER_BUILD_TAGS} diff --git a/_support/benchmarking/roles/gitaly/tasks/setup_gitaly.yml b/_support/benchmarking/roles/gitaly/tasks/setup_gitaly.yml index 42f9a5e67fdadf2da4c65f3372714e8df5408ad5..a4a8d39f3bfbe8af7f06b7e0ef2ad1b802d7f697 100644 --- a/_support/benchmarking/roles/gitaly/tasks/setup_gitaly.yml +++ b/_support/benchmarking/roles/gitaly/tasks/setup_gitaly.yml @@ -66,8 +66,6 @@ - name: Build Gitaly make: target: build - params: - WITH_BUNDLED_GIT: YesPlease jobs: "{{ ansible_processor_nproc }}" chdir: /src/gitaly environment: @@ -78,7 +76,6 @@ make: target: install params: - WITH_BUNDLED_GIT: YesPlease PREFIX: /opt/gitaly jobs: "{{ ansible_processor_nproc }}" chdir: /src/gitaly diff --git a/cmd/gitaly-ssh/main.go b/cmd/gitaly-ssh/main.go index e8a86997f2c07eb202283d3afe245b81e8d6f6e0..6ce3b729429e7b762db1a652ce26262efb503c90 100644 --- a/cmd/gitaly-ssh/main.go +++ b/cmd/gitaly-ssh/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "errors" "fmt" "os" "strconv" @@ -89,7 +90,7 @@ func main() { os.Exit(code) } -func (cmd gitalySSHCommand) run(logger log.Logger) (int, error) { +func (cmd gitalySSHCommand) run(logger log.Logger) (_ int, returnedErr error) { // Configure distributed tracing closer := tracing.Initialize(tracing.WithServiceName("gitaly-ssh")) defer closer.Close() @@ -114,6 +115,17 @@ func (cmd gitalySSHCommand) run(logger log.Logger) (int, error) { } if cmd.workingDir != "" { + originalWD, err := os.Getwd() + if err != nil { + return 0, fmt.Errorf("getwd: %w", err) + } + + defer func() { + if err := os.Chdir(originalWD); err != nil { + returnedErr = errors.Join(err, fmt.Errorf("restore working directory: %w", err)) + } + }() + if err := os.Chdir(cmd.workingDir); err != nil { return 1, fmt.Errorf("unable to chdir to %v", cmd.workingDir) } diff --git a/cmd/gitaly/check_test.go b/cmd/gitaly/check_test.go index 596367051721c6b286dc14545f8b6b3fb6127a61..f1fbdf28874ccff546d31fb54c9ec4d82df2b8c4 100644 --- a/cmd/gitaly/check_test.go +++ b/cmd/gitaly/check_test.go @@ -36,7 +36,7 @@ func TestCheckOK(t *testing.T) { }, SecretFile: gitlab.WriteShellSecretFile(t, testhelper.TempDir(t), "the secret"), }, - })) + }), testcfg.WithDisableBundledGitSymlinking()) testcfg.BuildGitaly(t, cfg) configPath := testcfg.WriteTemporaryGitalyConfigFile(t, cfg) @@ -81,7 +81,7 @@ func TestCheckBadCreds(t *testing.T) { }, SecretFile: gitlab.WriteShellSecretFile(t, testhelper.TempDir(t), "the secret"), }, - })) + }), testcfg.WithDisableBundledGitSymlinking()) testcfg.BuildGitaly(t, cfg) configPath := testcfg.WriteTemporaryGitalyConfigFile(t, cfg) diff --git a/doc/PROCESS.md b/doc/PROCESS.md index 505759b3292dcf45332db0c527cdd7ed60e6e50e..87add5fdc0a1f6edf9555eb8cb07fc3feafc3e72 100644 --- a/doc/PROCESS.md +++ b/doc/PROCESS.md @@ -513,39 +513,18 @@ that we have no such issues with zero-downtime upgrades: 1. We remove the old bundled Git binaries. -Note that because we cannot remove the old Git binaries at the same time when we -add the new ones. We must ensure that both sets exist in parallel for at least -one release. +Note that it is no longer required to wait one release before removing the old +bundled Git binaries. This is because the binaries are now embedded into the +Gitaly binary, thus an upgrade can be performed atomically. A Gitaly process +is in complete control of its Git execution environment when using bundled Git. [bundled-git]: git-execution-environments.md#bundled-git-recommended ### Detailed Process -The following detailed steps need to be done to upgrade to a new Git version: - -1. Add the new bundled Git distribution to the `Makefile`. See - c0d05650be681c2accb4cec5aac74a6dd77a2fa6. - -1. Add a new bundled Git execution environment with a feature flag. See - b547b368c8f584e9aabe8eef9342f99440b0c248. Please note that execution - environments are ordered by decreasing priority: the first environment - whose feature flags are all turned on will be picked. You thus have to - add your new environment to the top. - -1. Roll out the feature flag by following our feature flag process. You may - decide to remove the feature flag before the feature flag is removed in - case it is a low-risk upgrade of the Git version (e.g. when you perform a - patch-release upgrade, only). - -1. Remove the feature flag. See 888e6233fd85691f0852ae6c4a3656da9bf3d8e4. - -1. Remove the execution environment of the old bundled Git version. See - af1a3fe7b536d22a6db9ba6591d222b23d01d83f. - -1. Remove the old set of bundled Git binaries from the `Makefile`. See - 9c700ea473d781eea50eab685d643d95e9c4ffee. Note that this must only happen - _after_ both old and new bundled Git binaries have been installed in - parallel in a release already. +The process is detailed in the +[Git Version Upgrade](https://gitlab.com/gitlab-org/gitaly/-/blob/master/.gitlab/issue_templates/Git%20Version%20Upgrade.md) +issue template. ## Gitaly Releases diff --git a/doc/git-execution-environments.md b/doc/git-execution-environments.md index 76f68053aa6f90648a18a5338e7c5ecce3af95bc..7be7dbe02317274f514e16af554ddf5622870e27 100644 --- a/doc/git-execution-environments.md +++ b/doc/git-execution-environments.md @@ -5,7 +5,8 @@ must have access to Git. Gitaly supports three ways of accessing Git: - Bundled Git (recommended): Gitaly accesses bundled Git binaries. Unlike the other two ways of accessing Git, this is not a complete Git installation but - only contains a subset of binaries that are required at runtime. + only contains a subset of binaries that are required at runtime. Bundled Git + binaries are directly embedded into the Gitaly binary during compilation. - External Git distribution (not recommended): Gitaly accesses Git provided by the operating system or manually installed by the administrator. - Gitaly Git distribution (not recommended): Gitaly accesses it's own version of @@ -19,30 +20,29 @@ The bundled Git execution environment is the recommended way to set up Gitaly. Instead of using a full Git distribution, you can use a bundled Git execution environment. -To install bundled Git binaries, run `make install-bundled-git`. This Make -target installs the bundled Git binaries in the `bin` directory of a location -set with the `PREFIX` environment variable. For example: +Bundled Git binaries are compiled whenever Gitaly is compiled. There's no +need to explicitly build and install them. If you're running a test without +using the `make test...` Makefile target, you must run `make build-bundled-git` +to ensure the binaries are present in the `_build/bin` directory. -```shell -make install-bundled-git PREFIX=/usr/local -``` +When Gitaly is compiled for production, the bundled Git binaries are embedded +into the Gitaly binary using the go:embed feature. See `packed_binaries.go`. Bundled Git binaries all have a `gitaly-` prefix so they do not clash with normal Git executables. Furthermore, bundled Git binaries may have a version -suffix which allows Gitaly to install multiple different versions of Git at the -same time. For example, `make install-bundled-git PREFIX=/usr/local` may install -`gitaly-git-v2.35.1` and `gitaly-git-v2.36.0` into `/usr/local/bin`. +suffix which allows Gitaly to use multiple different versions of Git at the +same time. + +Bundled Git solves two important problems: -Being able to install multiple Git versions in parallel solves two important -issues: +- Being able to use multiple Git versions in parallel allows us roll out new + Git versions with the help of feature flags. This means we can roll back to + old versions of Git if a new version is exhibiting faulty behavior. -- When doing zero-downtime upgrades, a new Gitaly package can avoid replacing - Git binaries that are used by the currently running version of Gitaly. Gitaly - doesn't need to run in an intermediate state where the old version of Gitaly - is unexpectedly using newer Git binaries. -- Gitaly can roll out new Git versions with the help of feature flags. This - means we can roll back to old versions of Git if a new version is exhibiting - faulty behavior. +- Embedding the Git binaries allows seamless zero-downtime upgrades, as Gitaly + and Git can be upgraded as an atomic unit. Gitaly doesn't need to run in an + intermediate state where the old version of Gitaly is unexpectedly using newer + Git binaries. Git binaries expect to be able to locate helper binaries at runtime. However, because the bundled Git binaries all have a `gitaly-` prefix, the mechanisms Git @@ -60,10 +60,6 @@ environment. Gitaly can be configured to use bundled binaries by setting the following keys: ```toml -# The binary directory where Gitaly's own binaries are installed. This directory -# will also contain the bundled Git binaries. -bin_dir = "/usr/local/bin" - [git] use_bundled_binaries = true ``` diff --git a/internal/cli/gitaly/serve.go b/internal/cli/gitaly/serve.go index fb2bc9422fa30c9b59bc1d6f1ad69b272993550a..696eb41e08e3b70e784e2193b0aecff5a9882571 100644 --- a/internal/cli/gitaly/serve.go +++ b/internal/cli/gitaly/serve.go @@ -243,6 +243,8 @@ func run(appCtx *cli.Context, cfg config.Cfg, logger log.Logger) error { defer cleanup() logger.WithField("duration_ms", time.Since(began).Milliseconds()).Info("finished initializing command factory") + logger.WithField("binary_path", gitCmdFactory.GetExecutionEnvironment(ctx).BinaryPath).Info("using Git binary") + began = time.Now() gitVersion, err := gitCmdFactory.GitVersion(ctx) if err != nil { @@ -254,6 +256,8 @@ func run(appCtx *cli.Context, cfg config.Cfg, logger log.Logger) error { return fmt.Errorf("unsupported Git version: %q", gitVersion) } + logger.WithField("version", gitVersion.String()).Info("using Git version") + registry := backchannel.NewRegistry() transactionManager := transaction.NewManager(cfg, logger, registry) prometheus.MustRegister(transactionManager) diff --git a/internal/cli/gitaly/subcmd_check.go b/internal/cli/gitaly/subcmd_check.go index 9be414ad8012049eb3a77d5c3e036787100038b6..31ab8adc92fecd9f057c77b8c440a7c46b049367 100644 --- a/internal/cli/gitaly/subcmd_check.go +++ b/internal/cli/gitaly/subcmd_check.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/urfave/cli/v2" + "gitlab.com/gitlab-org/gitaly/v16" "gitlab.com/gitlab-org/gitaly/v16/internal/git" "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config" "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config/prometheus" @@ -45,6 +46,12 @@ func checkAction(ctx *cli.Context) error { return fmt.Errorf("loading configuration %q: %w", configPath, err) } + // Since this subcommand invokes a Git command, we need to unpack the bundled Git binaries + // from the Gitaly binary. + if err := gitaly.UnpackAuxiliaryBinaries(cfg.RuntimeDir); err != nil { + return fmt.Errorf("unpack auxiliary binaries: %w", err) + } + fmt.Fprint(ctx.App.Writer, "Checking GitLab API access: ") info, err := checkAPI(cfg, logger) if err != nil { diff --git a/internal/git/command_factory_test.go b/internal/git/command_factory_test.go index 9942a3b24637c78d8e1dd8f0849b017e8ed8b687..45a3659d876122717b5e86818b4ccf80d85a3417 100644 --- a/internal/git/command_factory_test.go +++ b/internal/git/command_factory_test.go @@ -3,9 +3,7 @@ package git_test import ( "bytes" "context" - "errors" "fmt" - "io/fs" "math/rand" "net/http" "net/http/httptest" @@ -13,7 +11,6 @@ import ( "os/exec" "path/filepath" "strings" - "syscall" "testing" "time" @@ -411,7 +408,6 @@ func TestExecCommandFactory_addAttrTree(t *testing.T) { func TestCommandFactory_ExecutionEnvironment(t *testing.T) { testhelper.Unsetenv(t, "GITALY_TESTING_GIT_BINARY") - testhelper.Unsetenv(t, "GITALY_TESTING_BUNDLED_GIT_PATH") ctx := testhelper.Context(t) @@ -461,161 +457,33 @@ func TestCommandFactory_ExecutionEnvironment(t *testing.T) { }) }) - t.Run("set using GITALY_TESTING_BUNDLED_GIT_PATH", func(t *testing.T) { - writeExecutables := func(t *testing.T, dir string, executables ...string) { - for _, executable := range executables { - testhelper.WriteExecutable(t, filepath.Join(dir, executable), nil) - } - } - - missingBinaryError := func(dir, binary string) error { - return fmt.Errorf("setting up Git execution environment: %w", - fmt.Errorf("constructing Git environment: %w", - fmt.Errorf("statting %q: %w", binary, - &fs.PathError{ - Op: "stat", - Path: filepath.Join(dir, binary), - Err: syscall.ENOENT, - }, - ), - ), - ) - } + t.Run("set with the default bundled Git environment", func(t *testing.T) { + suffix := git.BundledGitConstructors[0].Suffix - type setupData struct { - binaryDir string - bundledGitDir string - expectedErr error - } + cfg := testcfg.Build(t) - for _, tc := range []struct { - desc string - setup func(t *testing.T) setupData - }{ - { - desc: "unset binary directory", - setup: func(t *testing.T) setupData { - return setupData{ - binaryDir: "", - bundledGitDir: "/does/not/exist", - expectedErr: fmt.Errorf("setting up Git execution environment: %w", - fmt.Errorf("constructing Git environment: %w", - errors.New("cannot use bundled binaries without bin path being set"), - ), - ), - } - }, - }, - { - desc: "missing directory", - setup: func(t *testing.T) setupData { - return setupData{ - binaryDir: testhelper.TempDir(t), - bundledGitDir: "/does/not/exist", - expectedErr: missingBinaryError("/does/not/exist", "gitaly-git-v2.38"), - } - }, - }, - { - desc: "missing gitaly-git", - setup: func(t *testing.T) setupData { - bundledGitDir := testhelper.TempDir(t) - - return setupData{ - binaryDir: testhelper.TempDir(t), - bundledGitDir: bundledGitDir, - expectedErr: missingBinaryError(bundledGitDir, "gitaly-git-v2.38"), - } - }, - }, - { - desc: "missing gitaly-git-remote-http", - setup: func(t *testing.T) setupData { - bundledGitDir := testhelper.TempDir(t) - - writeExecutables(t, bundledGitDir, "gitaly-git-v2.38") - - return setupData{ - binaryDir: testhelper.TempDir(t), - bundledGitDir: bundledGitDir, - expectedErr: missingBinaryError(bundledGitDir, "gitaly-git-remote-http-v2.38"), - } - }, - }, - { - desc: "missing gitaly-git-http-backend", - setup: func(t *testing.T) setupData { - bundledGitDir := testhelper.TempDir(t) - - writeExecutables(t, bundledGitDir, - "gitaly-git-v2.38", - "gitaly-git-remote-http-v2.38", - ) - - return setupData{ - binaryDir: testhelper.TempDir(t), - bundledGitDir: bundledGitDir, - expectedErr: missingBinaryError(bundledGitDir, "gitaly-git-http-backend-v2.38"), - } + gitCmdFactory, cleanup, err := git.NewExecCommandFactory( + cfg, + testhelper.SharedLogger(t), + git.WithSkipHooks(), + git.WithExecutionEnvironmentConstructors( + git.BundledGitEnvironmentConstructor{ + Suffix: suffix, }, - }, - { - desc: "successful", - setup: func(t *testing.T) setupData { - bundledGitDir := testhelper.TempDir(t) - writeExecutables(t, bundledGitDir, "gitaly-git-v2.38", "gitaly-git-remote-http-v2.38", "gitaly-git-http-backend-v2.38") - - return setupData{ - binaryDir: testhelper.TempDir(t), - bundledGitDir: bundledGitDir, - } - }, - }, - } { - t.Run(tc.desc, func(t *testing.T) { - setupData := tc.setup(t) - t.Setenv("GITALY_TESTING_BUNDLED_GIT_PATH", setupData.bundledGitDir) - - gitCmdFactory, cleanup, err := git.NewExecCommandFactory( - config.Cfg{ - BinDir: setupData.binaryDir, - }, - testhelper.SharedLogger(t), - git.WithSkipHooks(), - // Override the constructors so that we don't have to change - // tests every time we're upgrading our bundled Git version. - git.WithExecutionEnvironmentConstructors( - git.BundledGitEnvironmentConstructor{ - Suffix: "-v2.38", - }, - ), - ) - require.Equal(t, setupData.expectedErr, err) - if err != nil { - return - } - defer cleanup() + ), + ) + require.NoError(t, err) + defer cleanup() - // When the command factory has been successfully created then we - // verify that the symlink that it has created match what we expect. - gitBinPath := gitCmdFactory.GetExecutionEnvironment(ctx).BinaryPath - for _, executable := range []string{"git", "git-remote-http", "git-http-backend"} { - symlinkPath := filepath.Join(filepath.Dir(gitBinPath), executable) - - // The symlink in Git's temporary BinPath points to the Git - // executable in Gitaly's BinDir. - target, err := os.Readlink(symlinkPath) - require.NoError(t, err) - require.Equal(t, filepath.Join(setupData.binaryDir, "gitaly-"+executable+"-v2.38"), target) - - // And in a test setup, the symlink in Gitaly's BinDir must point to - // the Git binary pointed to by the GITALY_TESTING_BUNDLED_GIT_PATH - // environment variable. - target, err = os.Readlink(target) - require.NoError(t, err) - require.Equal(t, filepath.Join(setupData.bundledGitDir, "gitaly-"+executable+"-v2.38"), target) - } - }) + // When the command factory has been successfully created then we + // verify that the symlink that it has created match what we expect. + gitBinPath := gitCmdFactory.GetExecutionEnvironment(ctx).BinaryPath + for _, binary := range []string{"git", "git-remote-http", "git-http-backend"} { + symlinkPath := filepath.Join(filepath.Dir(gitBinPath), binary) + + target, err := os.Readlink(symlinkPath) + require.NoError(t, err) + require.Equal(t, filepath.Join(cfg.RuntimeDir, fmt.Sprintf("gitaly-%s%s", binary, suffix)), target) } }) diff --git a/internal/git/command_options_test.go b/internal/git/command_options_test.go index e5e19b090b77f0db402b82f58f780ac04fb87fb9..fa4354c31e312a754f8b63bc32ec9760e1fb6aef 100644 --- a/internal/git/command_options_test.go +++ b/internal/git/command_options_test.go @@ -11,6 +11,7 @@ import ( "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config" "gitlab.com/gitlab-org/gitaly/v16/internal/helper/text" "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper" + "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg" "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb" "gitlab.com/gitlab-org/labkit/correlation" "google.golang.org/grpc/metadata" @@ -192,10 +193,7 @@ func TestGlobalOption(t *testing.T) { } func TestWithConfig(t *testing.T) { - cfg := config.Cfg{ - BinDir: testhelper.TempDir(t), - } - + cfg := testcfg.Build(t) ctx := testhelper.Context(t) gitCmdFactory := newCommandFactory(t, cfg, WithSkipHooks()) @@ -265,14 +263,14 @@ func TestWithConfig(t *testing.T) { } func TestExecCommandFactoryGitalyConfigOverrides(t *testing.T) { - cfg := config.Cfg{ - BinDir: testhelper.TempDir(t), - Git: config.Git{ - Config: []config.GitConfig{ - {Key: "foo.bar", Value: "from-gitaly-config"}, + cfg := testcfg.Build(t, testcfg.WithBase( + config.Cfg{ + Git: config.Git{ + Config: []config.GitConfig{ + {Key: "foo.bar", Value: "from-gitaly-config"}, + }, }, - }, - } + })) ctx := testhelper.Context(t) @@ -294,10 +292,7 @@ func TestExecCommandFactoryGitalyConfigOverrides(t *testing.T) { } func TestWithConfigEnv(t *testing.T) { - cfg := config.Cfg{ - BinDir: testhelper.TempDir(t), - } - + cfg := testcfg.Build(t) ctx := testhelper.Context(t) gitCmdFactory := newCommandFactory(t, cfg, WithSkipHooks()) diff --git a/internal/git/execution_environment.go b/internal/git/execution_environment.go index a44755d5cbc43b261117dedf380f4534eeb2e3d3..65ba714d54ae429906af298e90668c683445103e 100644 --- a/internal/git/execution_environment.go +++ b/internal/git/execution_environment.go @@ -18,17 +18,28 @@ var ( // environment was not configured. ErrNotConfigured = errors.New("execution environment is not configured") + // BundledGitConstructors defines the versions of Git that we embed into the Gitaly + // binary. + BundledGitConstructors = []BundledGitEnvironmentConstructor{ + { + Suffix: "-v2.45", + }, + } + // defaultExecutionEnvironmentConstructors is the list of Git environments supported by the // Git command factory. The order is important and signifies the priority in which the // environments will be used: the environment created by the first constructor is the one // that will be preferred when executing Git commands. Later environments may be used in // case `IsEnabled()` returns `false` though. - defaultExecutionEnvironmentConstructors = []ExecutionEnvironmentConstructor{ - BundledGitEnvironmentConstructor{ - Suffix: "-v2.45", - }, - DistributedGitEnvironmentConstructor{}, - } + defaultExecutionEnvironmentConstructors = func() (constructors []ExecutionEnvironmentConstructor) { + for _, c := range BundledGitConstructors { + constructors = append(constructors, c) + } + + constructors = append(constructors, DistributedGitEnvironmentConstructor{}) + + return constructors + }() ) // ExecutionEnvironmentConstructor is an interface for constructors of Git execution environments. @@ -126,52 +137,11 @@ type BundledGitEnvironmentConstructor struct { // binaries with their usual names as expected by Git. Furthermore, we configure the GIT_EXEC_PATH // environment variable to point to that directory such that Git is able to locate its auxiliary // binaries. -// -// For testing purposes, this function will automatically enable use of bundled Git in case the -// `GITALY_TESTING_BUNDLED_GIT_PATH` environment variable is set. func (c BundledGitEnvironmentConstructor) Construct(cfg config.Cfg) (_ ExecutionEnvironment, returnedErr error) { - useBundledBinaries := cfg.Git.UseBundledBinaries - - if bundledGitPath := os.Getenv("GITALY_TESTING_BUNDLED_GIT_PATH"); bundledGitPath != "" { - if cfg.BinDir == "" { - return ExecutionEnvironment{}, errors.New("cannot use bundled binaries without bin path being set") - } - - // We need to symlink pre-built Git binaries into Gitaly's binary directory. - // Normally they would of course already exist there, but in tests we create a new - // binary directory for each server and thus need to populate it first. - for _, binary := range []string{"gitaly-git", "gitaly-git-remote-http", "gitaly-git-http-backend"} { - binary := binary + c.Suffix - - bundledGitBinary := filepath.Join(bundledGitPath, binary) - if _, err := os.Stat(bundledGitBinary); err != nil { - return ExecutionEnvironment{}, fmt.Errorf("statting %q: %w", binary, err) - } - - if err := os.Symlink(bundledGitBinary, filepath.Join(cfg.BinDir, binary)); err != nil { - // Multiple Git command factories might be created for the same configuration. - // Each of them will create the execution environment every time, - // therefore these symlinks might already exist. - // It would be nice if we could fix this, but gracefully handling the error is a - // more boring solution. - if errors.Is(err, os.ErrExist) { - continue - } - return ExecutionEnvironment{}, fmt.Errorf("symlinking bundled %q: %w", binary, err) - } - } - - useBundledBinaries = true - } - - if !useBundledBinaries { + if !cfg.Git.UseBundledBinaries { return ExecutionEnvironment{}, ErrNotConfigured } - if cfg.BinDir == "" { - return ExecutionEnvironment{}, errors.New("cannot use bundled binaries without bin path being set") - } - // In order to support having a single Git binary only as compared to a complete Git // installation, we create our own GIT_EXEC_PATH which contains symlinks to the Git // binary for executables which Git expects to be present. @@ -205,7 +175,7 @@ func (c BundledGitEnvironmentConstructor) Construct(cfg config.Cfg) (_ Execution "git-remote-ftps": "gitaly-git-remote-http", } { target := target + c.Suffix - targetPath := filepath.Join(cfg.BinDir, target) + targetPath := filepath.Join(cfg.RuntimeDir, target) if err := unix.Access(targetPath, unix.X_OK); err != nil { return ExecutionEnvironment{}, fmt.Errorf("checking bundled Git binary %q: %w", target, err) diff --git a/internal/git/execution_environment_test.go b/internal/git/execution_environment_test.go index 8dbf5b8de28d8d0e67e455407dee2016c00e5a15..773df99885cb3df493eae1f5bd7af7647fa5feaa 100644 --- a/internal/git/execution_environment_test.go +++ b/internal/git/execution_environment_test.go @@ -1,7 +1,6 @@ package git_test import ( - "errors" "fmt" "os" "path/filepath" @@ -12,6 +11,7 @@ import ( "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config" "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage/mode" "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper" + "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg" ) func TestDistributedGitEnvironmentConstructor(t *testing.T) { @@ -67,52 +67,18 @@ func TestDistributedGitEnvironmentConstructor(t *testing.T) { } func TestBundledGitEnvironmentConstructor(t *testing.T) { - testhelper.Unsetenv(t, "GITALY_TESTING_BUNDLED_GIT_PATH") - - constructor := git.BundledGitEnvironmentConstructor{} + testhelper.Unsetenv(t, "GITALY_TESTING_GIT_BINARY") - seedDirWithExecutables := func(t *testing.T, executableNames ...string) string { - dir := testhelper.TempDir(t) - for _, executableName := range executableNames { - require.NoError(t, os.WriteFile(filepath.Join(dir, executableName), nil, mode.Executable)) - } - return dir - } + constructor := git.BundledGitConstructors[0] t.Run("disabled bundled Git fails", func(t *testing.T) { _, err := constructor.Construct(config.Cfg{}) require.Equal(t, git.ErrNotConfigured, err) }) - t.Run("bundled Git without binary directory fails", func(t *testing.T) { - _, err := constructor.Construct(config.Cfg{ - Git: config.Git{ - UseBundledBinaries: true, - }, - }) - require.Equal(t, errors.New("cannot use bundled binaries without bin path being set"), err) - }) - - t.Run("incomplete binary directory succeeds", func(t *testing.T) { - _, err := constructor.Construct(config.Cfg{ - BinDir: seedDirWithExecutables(t, "gitaly-git", "gitaly-git-remote-http"), - Git: config.Git{ - UseBundledBinaries: true, - }, - }) - require.Error(t, err) - require.Equal(t, "checking bundled Git binary \"gitaly-git-http-backend\": no such file or directory", err.Error()) - }) - t.Run("complete binary directory succeeds", func(t *testing.T) { - binDir := seedDirWithExecutables(t, "gitaly-git", "gitaly-git-remote-http", "gitaly-git-http-backend") - - execEnv, err := constructor.Construct(config.Cfg{ - BinDir: binDir, - Git: config.Git{ - UseBundledBinaries: true, - }, - }) + cfg := testcfg.Build(t) + execEnv, err := constructor.Construct(cfg) require.NoError(t, err) defer func() { require.NoError(t, execEnv.Cleanup()) }() @@ -128,103 +94,7 @@ func TestBundledGitEnvironmentConstructor(t *testing.T) { for _, binary := range []string{"git", "git-remote-http", "git-http-backend"} { target, err := filepath.EvalSymlinks(filepath.Join(execPrefix, binary)) require.NoError(t, err) - require.Equal(t, filepath.Join(binDir, "gitaly-"+binary), target) - } - }) - - t.Run("cleanup removes temporary directory", func(t *testing.T) { - execEnv, err := constructor.Construct(config.Cfg{ - BinDir: seedDirWithExecutables(t, "gitaly-git", "gitaly-git-remote-http", "gitaly-git-http-backend"), - Git: config.Git{ - UseBundledBinaries: true, - }, - }) - require.NoError(t, err) - - execPrefix := filepath.Dir(execEnv.BinaryPath) - require.DirExists(t, execPrefix) - - require.NoError(t, execEnv.Cleanup()) - - require.NoDirExists(t, execPrefix) - }) - - t.Run("bundled Git path without binary directory fails", func(t *testing.T) { - t.Setenv("GITALY_TESTING_BUNDLED_GIT_PATH", "/does/not/exist") - _, err := constructor.Construct(config.Cfg{}) - require.Equal(t, errors.New("cannot use bundled binaries without bin path being set"), err) - }) - - t.Run("nonexistent bundled Git path via environment fails", func(t *testing.T) { - t.Setenv("GITALY_TESTING_BUNDLED_GIT_PATH", "/does/not/exist") - _, err := constructor.Construct(config.Cfg{ - BinDir: testhelper.TempDir(t), - }) - require.Error(t, err) - require.Equal(t, err.Error(), "statting \"gitaly-git\": stat /does/not/exist/gitaly-git: no such file or directory") - }) - - t.Run("incomplete bundled Git environment fails", func(t *testing.T) { - bundledGitPath := seedDirWithExecutables(t, "gitaly-git", "gitaly-git-remote-http") - t.Setenv("GITALY_TESTING_BUNDLED_GIT_PATH", bundledGitPath) - - _, err := constructor.Construct(config.Cfg{ - BinDir: testhelper.TempDir(t), - }) - require.Error(t, err) - require.Contains(t, err.Error(), "statting \"gitaly-git-http-backend\": ") - }) - - t.Run("complete bundled Git environment populates binary directory", func(t *testing.T) { - bundledGitPath := seedDirWithExecutables(t, "gitaly-git", "gitaly-git-remote-http", "gitaly-git-http-backend") - t.Setenv("GITALY_TESTING_BUNDLED_GIT_PATH", bundledGitPath) - - execEnv, err := constructor.Construct(config.Cfg{ - BinDir: testhelper.TempDir(t), - }) - require.NoError(t, err) - defer func() { require.NoError(t, execEnv.Cleanup()) }() - - require.Equal(t, "git", filepath.Base(execEnv.BinaryPath)) - execPrefix := filepath.Dir(execEnv.BinaryPath) - - require.Equal(t, []string{ - "GIT_EXEC_PATH=" + execPrefix, - }, execEnv.EnvironmentVariables) - - for _, binary := range []string{"git", "git-remote-http", "git-http-backend"} { - target, err := filepath.EvalSymlinks(filepath.Join(execPrefix, binary)) - require.NoError(t, err) - require.Equal(t, filepath.Join(bundledGitPath, "gitaly-"+binary), target) - } - }) - - t.Run("with version suffix", func(t *testing.T) { - constructor := git.BundledGitEnvironmentConstructor{ - Suffix: "-v2.35.1", - } - - binDir := seedDirWithExecutables(t, "gitaly-git-v2.35.1", "gitaly-git-remote-http-v2.35.1", "gitaly-git-http-backend-v2.35.1") - - execEnv, err := constructor.Construct(config.Cfg{ - BinDir: binDir, - Git: config.Git{ - UseBundledBinaries: true, - }, - }) - require.NoError(t, err) - defer func() { require.NoError(t, execEnv.Cleanup()) }() - - require.Equal(t, "git", filepath.Base(execEnv.BinaryPath)) - execPrefix := filepath.Dir(execEnv.BinaryPath) - require.Equal(t, []string{ - "GIT_EXEC_PATH=" + execPrefix, - }, execEnv.EnvironmentVariables) - - for _, binary := range []string{"git", "git-remote-http", "git-http-backend"} { - target, err := filepath.EvalSymlinks(filepath.Join(execPrefix, binary)) - require.NoError(t, err) - require.Equal(t, filepath.Join(binDir, "gitaly-"+binary+"-v2.35.1"), target) + require.Equal(t, filepath.Join(testhelper.SourceRoot(t), "_build", "bin", fmt.Sprintf("gitaly-%s%s", binary, constructor.Suffix)), target) } }) } diff --git a/internal/git/gittest/command_factory.go b/internal/git/gittest/command_factory.go index 8c4af980f81886b519456aec74e52033b9dcd553..2cfb48901f00251859cdb2c0f200fd45bdb4178e 100644 --- a/internal/git/gittest/command_factory.go +++ b/internal/git/gittest/command_factory.go @@ -1,6 +1,7 @@ package gittest import ( + "strings" "testing" "github.com/stretchr/testify/require" @@ -13,6 +14,11 @@ import ( func NewCommandFactory(tb testing.TB, cfg config.Cfg, opts ...git.ExecCommandFactoryOption) *git.ExecCommandFactory { tb.Helper() factory, cleanup, err := git.NewExecCommandFactory(cfg, testhelper.SharedLogger(tb), opts...) + if err != nil { + if strings.Contains(err.Error(), "no such file or directory") { + require.FailNowf(tb, "Gitaly tests execute against the bundled Git environment. Have you run `make build-bundled-git`? Error: %s", err.Error()) + } + } require.NoError(tb, err) tb.Cleanup(cleanup) return factory diff --git a/internal/git/gittest/testhelper_test.go b/internal/git/gittest/testhelper_test.go index 6bc92c9dccd2c1ca424d0fcb6dd25b58cb615632..029fbbdeca277e7e6f51d765d6bc7a6179457956 100644 --- a/internal/git/gittest/testhelper_test.go +++ b/internal/git/gittest/testhelper_test.go @@ -1,14 +1,11 @@ package gittest import ( - "os" - "path/filepath" "testing" - "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config" - "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage/mode" "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper" + "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg" "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb" ) @@ -21,32 +18,8 @@ func TestMain(m *testing.M) { func setup(tb testing.TB) (config.Cfg, *gitalypb.Repository, string) { tb.Helper() - rootDir := testhelper.TempDir(tb) - ctx := testhelper.Context(tb) - var cfg config.Cfg - - cfg.SocketPath = "it is a stub to bypass Validate method" - - cfg.Storages = []config.Storage{ - { - Name: "default", - Path: filepath.Join(rootDir, "storage.d"), - }, - } - require.NoError(tb, os.Mkdir(cfg.Storages[0].Path, mode.Directory)) - - cfg.GitlabShell.Dir = filepath.Join(rootDir, "shell.d") - require.NoError(tb, os.Mkdir(cfg.GitlabShell.Dir, mode.Directory)) - - cfg.BinDir = filepath.Join(rootDir, "bin.d") - require.NoError(tb, os.Mkdir(cfg.BinDir, mode.Directory)) - - cfg.RuntimeDir = filepath.Join(rootDir, "run.d") - require.NoError(tb, os.Mkdir(cfg.RuntimeDir, mode.Directory)) - require.NoError(tb, os.Mkdir(cfg.InternalSocketDir(), mode.Directory)) - - require.NoError(tb, cfg.Validate()) + cfg := testcfg.Build(tb) repo, repoPath := CreateRepository(tb, ctx, cfg, CreateRepositoryConfig{ SkipCreationViaService: true, diff --git a/internal/gitaly/config/config.go b/internal/gitaly/config/config.go index ae7e1f282ca85a0d7b2b5ca1df5d92458b01f3d8..72526a14a4f4d6e2e895b2c8ef0a324359e63817 100644 --- a/internal/gitaly/config/config.go +++ b/internal/gitaly/config/config.go @@ -945,7 +945,8 @@ func validateIsDirectory(path, name string) error { } // packedBinaries are the binaries that are packed in the main Gitaly binary. This should always match -// the actual list in /packed_binaries.go so the binaries are correctly located. +// the actual list in /packed_binaries.go so the binaries are correctly located. Git binaries are +// excepted, as they are wired up using a separate mechanism. // // Resolving the names automatically from the packed binaries is not possible at the moment due to how // the packed binaries themselves depend on this config package. If this config package inspected the diff --git a/internal/gitaly/service/smarthttp/upload_pack_test.go b/internal/gitaly/service/smarthttp/upload_pack_test.go index 944268aee543b4938740fb062642fd6205900423..a6359d08d0a07ec535152f212cc1e0af30903cbe 100644 --- a/internal/gitaly/service/smarthttp/upload_pack_test.go +++ b/internal/gitaly/service/smarthttp/upload_pack_test.go @@ -277,7 +277,6 @@ func testServerPostUploadPackWithSidechannelUsesPackObjectsHook(t *testing.T, ct func testServerPostUploadPackUsesPackObjectsHook(t *testing.T, ctx context.Context, makeRequest requestMaker, opts ...testcfg.Option) { cfg := testcfg.Build(t, append(opts, testcfg.WithPackObjectsCacheEnabled())...) - cfg.BinDir = testhelper.TempDir(t) outputPath := filepath.Join(cfg.BinDir, "output") //nolint:gitaly-linters diff --git a/internal/gitaly/service/ssh/upload_pack_test.go b/internal/gitaly/service/ssh/upload_pack_test.go index 949bcad1cddf0741983d5ab2177534a3ab82055b..26c1aab6fdd3a502643e9baa4911745dbfa79865 100644 --- a/internal/gitaly/service/ssh/upload_pack_test.go +++ b/internal/gitaly/service/ssh/upload_pack_test.go @@ -693,11 +693,13 @@ func TestUploadPack_packObjectsHook(t *testing.T) { ctx := testhelper.Context(t) - cfg := testcfg.Build(t, testcfg.WithPackObjectsCacheEnabled()) - filterDir := testhelper.TempDir(t) outputPath := filepath.Join(filterDir, "output") - cfg.BinDir = filterDir + cfg := testcfg.Build(t, testcfg.WithPackObjectsCacheEnabled(), testcfg.WithBase( + config.Cfg{ + BinDir: filterDir, + }, + )) testcfg.BuildGitalySSH(t, cfg) diff --git a/internal/testhelper/testcfg/gitaly.go b/internal/testhelper/testcfg/gitaly.go index 088ec82449a94b2e7fcceeac2bc2991186f4a6d6..0e1a910c1835c662b2d61cf307e263806b1d2057 100644 --- a/internal/testhelper/testcfg/gitaly.go +++ b/internal/testhelper/testcfg/gitaly.go @@ -48,6 +48,19 @@ func WithPackObjectsCacheEnabled() Option { } } +// WithDisableBundledGitSymlinking stops the builder from symlinking the +// compiled bundled Git binaries in _build/bin to cfg.RuntimeDir. This is +// useful for tests like cmd/gitaly/check_test.go which executes a test +// against a compiled Gitaly binary. If this option is not supplied, both +// the test and the Gitaly process it spawns will try to populate RuntimeDir +// with the same binaries, which causes a "file exists" exception in +// packed_binaries.go +func WithDisableBundledGitSymlinking() Option { + return func(builder *GitalyCfgBuilder) { + builder.disableBundledGitSymlinking = true + } +} + // NewGitalyCfgBuilder returns gitaly configuration builder with configured set of options. func NewGitalyCfgBuilder(opts ...Option) GitalyCfgBuilder { cfgBuilder := GitalyCfgBuilder{} @@ -63,8 +76,9 @@ func NewGitalyCfgBuilder(opts ...Option) GitalyCfgBuilder { type GitalyCfgBuilder struct { cfg config.Cfg - storages []string - packObjectsCacheEnabled bool + storages []string + packObjectsCacheEnabled bool + disableBundledGitSymlinking bool } // Build setups required filesystem structure, creates and returns configuration of the gitaly service. @@ -102,6 +116,26 @@ func (gc *GitalyCfgBuilder) Build(tb testing.TB) config.Cfg { cfg.RuntimeDir = filepath.Join(root, "runtime.d") require.NoError(tb, os.Mkdir(cfg.RuntimeDir, mode.Directory)) require.NoError(tb, os.Mkdir(cfg.InternalSocketDir(), mode.Directory)) + + if !gc.disableBundledGitSymlinking { + // We do this symlinking to emulate what happens with the Git binaries in production: + // - In production, the Git binaries get unpacked by packed_binaries.go into Gitaly's RuntimeDir, which for + // Omnibus is something like /var/opt/gitlab/gitaly/run/gitaly-. + // - In testing, the binaries remain in the _build/bin directory of the repository root. + bundledGitBins, err := filepath.Glob(filepath.Join(testhelper.SourceRoot(tb), "_build", "bin", "gitaly-git-*")) + require.NoError(tb, err) + + for _, targetPath := range bundledGitBins { + destinationPath := filepath.Join(cfg.RuntimeDir, filepath.Base(targetPath)) + + // It's possible that the same RuntimeDir is used across multiple invocations of + // testcfg.Build(), so we simply remove any existing symlinks. + if _, err := os.Lstat(destinationPath); err == nil { + require.NoError(tb, os.Remove(destinationPath)) + } + require.NoError(tb, os.Symlink(targetPath, destinationPath)) + } + } } if len(cfg.Storages) != 0 && len(gc.storages) != 0 { @@ -149,6 +183,10 @@ func (gc *GitalyCfgBuilder) Build(tb testing.TB) config.Cfg { cfg.Transactions.Enabled = testhelper.IsWALEnabled() + // We force the use of bundled (embedded) binaries unless we're specifically executing tests + // against a custom version of Git. + cfg.Git.UseBundledBinaries = os.Getenv("GITALY_TESTING_GIT_BINARY") == "" + require.NoError(tb, cfg.Sanitize()) require.NoError(tb, cfg.ValidateV2()) diff --git a/internal/testhelper/testhelper.go b/internal/testhelper/testhelper.go index b95d3b32607bba558b4f9203c33b1dc666b2a41a..e9f29b8a52a595653a4b804a89d62ea28a6b738e 100644 --- a/internal/testhelper/testhelper.go +++ b/internal/testhelper/testhelper.go @@ -457,3 +457,10 @@ func TestdataAbsolutePath(t *testing.T) string { return filepath.Join(filepath.Dir(currentFile), "testdata") } + +// SourceRoot returns the root directory of the Gitaly repository. +func SourceRoot(tb testing.TB) string { + output, err := exec.Command("go", "env", "GOMOD").CombinedOutput() + require.NoError(tb, err, output) + return filepath.Dir(string(output)) +} diff --git a/packed_binaries.go b/packed_binaries.go index cb9dc3a7ae4d550f05e9266452f449c93b18fa36..28f2785ba9bdebe8c1f5ce60c93cc893f70b00e8 100644 --- a/packed_binaries.go +++ b/packed_binaries.go @@ -14,10 +14,11 @@ import ( // buildDir is the directory path where our build target places the built binaries. const buildDir = "_build/bin" -// packedBinariesFS contains embedded binaries. If you modify the above embeddings, you must also update +// packedBinariesFS contains embedded binaries. If you modify the below embeddings, you must also update // GITALY_PACKED_EXECUTABLES in Makefile and packedBinaries in internal/gitaly/config/config.go. // //go:embed _build/bin/gitaly-hooks _build/bin/gitaly-ssh _build/bin/gitaly-lfs-smudge _build/bin/gitaly-gpg +//go:embed _build/bin/gitaly-git-* var packedBinariesFS embed.FS // UnpackAuxiliaryBinaries unpacks the packed auxiliary binaries of Gitaly into destination directory.