diff --git a/devcontainer/devcontainer_test.go b/devcontainer/devcontainer_test.go index d2276d35..fe573433 100644 --- a/devcontainer/devcontainer_test.go +++ b/devcontainer/devcontainer_test.go @@ -12,7 +12,7 @@ import ( "github.com/coder/envbuilder/devcontainer" "github.com/coder/envbuilder/devcontainer/features" - "github.com/coder/envbuilder/registrytest" + "github.com/coder/envbuilder/testutil/registrytest" "github.com/go-git/go-billy/v5/memfs" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" diff --git a/devcontainer/features/features_test.go b/devcontainer/features/features_test.go index 03a073b8..b4d2fe85 100644 --- a/devcontainer/features/features_test.go +++ b/devcontainer/features/features_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/coder/envbuilder/devcontainer/features" - "github.com/coder/envbuilder/registrytest" + "github.com/coder/envbuilder/testutil/registrytest" "github.com/go-git/go-billy/v5/memfs" "github.com/stretchr/testify/require" ) diff --git a/git_test.go b/git_test.go index c4e98281..0d034728 100644 --- a/git_test.go +++ b/git_test.go @@ -9,14 +9,11 @@ import ( "os" "regexp" "testing" - "time" "github.com/coder/envbuilder" - "github.com/coder/envbuilder/gittest" + "github.com/coder/envbuilder/testutil/gittest" "github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/memfs" - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing/object" githttp "github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/stretchr/testify/require" ) @@ -77,13 +74,16 @@ func TestCloneRepo(t *testing.T) { // We do not overwrite a repo if one is already present. t.Run("AlreadyCloned", func(t *testing.T) { - srvURL := setupGit(t, tc.srvUsername, tc.srvPassword) + srvFS := memfs.New() + _ = gittest.NewRepo(t, srvFS, gittest.Commit(t, "README.md", "Hello, world!", "Wow!")) + authMW := gittest.BasicAuthMW(tc.srvUsername, tc.srvPassword) + srv := httptest.NewServer(authMW(gittest.NewServer(srvFS))) clientFS := memfs.New() // A repo already exists! _ = gittest.NewRepo(t, clientFS) cloned, err := envbuilder.CloneRepo(context.Background(), envbuilder.CloneRepoOptions{ Path: "/", - RepoURL: srvURL, + RepoURL: srv.URL, Storage: clientFS, }) require.NoError(t, err) @@ -93,12 +93,15 @@ func TestCloneRepo(t *testing.T) { // Basic Auth t.Run("BasicAuth", func(t *testing.T) { t.Parallel() - srvURL := setupGit(t, tc.srvUsername, tc.srvPassword) + srvFS := memfs.New() + _ = gittest.NewRepo(t, srvFS, gittest.Commit(t, "README.md", "Hello, world!", "Wow!")) + authMW := gittest.BasicAuthMW(tc.srvUsername, tc.srvPassword) + srv := httptest.NewServer(authMW(gittest.NewServer(srvFS))) clientFS := memfs.New() cloned, err := envbuilder.CloneRepo(context.Background(), envbuilder.CloneRepoOptions{ Path: "/workspace", - RepoURL: srvURL, + RepoURL: srv.URL, Storage: clientFS, RepoAuth: &githttp.BasicAuth{ Username: tc.username, @@ -117,14 +120,18 @@ func TestCloneRepo(t *testing.T) { require.Equal(t, "Hello, world!", readme) gitConfig := mustRead(t, clientFS, "/workspace/.git/config") // Ensure we do not modify the git URL that folks pass in. - require.Regexp(t, fmt.Sprintf(`(?m)^\s+url\s+=\s+%s\s*$`, regexp.QuoteMeta(srvURL)), gitConfig) + require.Regexp(t, fmt.Sprintf(`(?m)^\s+url\s+=\s+%s\s*$`, regexp.QuoteMeta(srv.URL)), gitConfig) }) // In-URL-style auth e.g. http://user:password@host:port t.Run("InURL", func(t *testing.T) { t.Parallel() - srvURL := setupGit(t, tc.srvUsername, tc.srvPassword) - authURL, err := url.Parse(srvURL) + srvFS := memfs.New() + _ = gittest.NewRepo(t, srvFS, gittest.Commit(t, "README.md", "Hello, world!", "Wow!")) + authMW := gittest.BasicAuthMW(tc.srvUsername, tc.srvPassword) + srv := httptest.NewServer(authMW(gittest.NewServer(srvFS))) + + authURL, err := url.Parse(srv.URL) require.NoError(t, err) authURL.User = url.UserPassword(tc.username, tc.password) clientFS := memfs.New() @@ -160,28 +167,3 @@ func mustRead(t *testing.T, fs billy.Filesystem, path string) string { require.NoError(t, err) return string(content) } - -func setupGit(t *testing.T, user, pass string) (url string) { - serverFS := memfs.New() - repo := gittest.NewRepo(t, serverFS) - tree, err := repo.Worktree() - require.NoError(t, err) - - gittest.WriteFile(t, serverFS, "README.md", "Hello, world!") - _, err = tree.Add("README.md") - require.NoError(t, err) - commit, err := tree.Commit("Wow!", &git.CommitOptions{ - Author: &object.Signature{ - Name: "Example", - Email: "in@tests.com", - When: time.Now(), - }, - }) - require.NoError(t, err) - _, err = repo.CommitObject(commit) - require.NoError(t, err) - - authMW := gittest.BasicAuthMW(user, pass) - srv := httptest.NewServer(authMW(gittest.NewServer(serverFS))) - return srv.URL -} diff --git a/integration/integration_test.go b/integration/integration_test.go index 2b51abde..869e4e67 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -19,12 +19,11 @@ import ( "path/filepath" "strings" "testing" - "time" "github.com/coder/envbuilder" "github.com/coder/envbuilder/devcontainer/features" - "github.com/coder/envbuilder/gittest" - "github.com/coder/envbuilder/registrytest" + "github.com/coder/envbuilder/testutil/gittest" + "github.com/coder/envbuilder/testutil/registrytest" clitypes "github.com/docker/cli/cli/config/types" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" @@ -32,8 +31,6 @@ import ( "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" "github.com/go-git/go-billy/v5/memfs" - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing/object" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote/transport" @@ -49,7 +46,7 @@ const ( func TestFailsGitAuth(t *testing.T) { t.Parallel() - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + testImageAlpine, }, @@ -57,14 +54,14 @@ func TestFailsGitAuth(t *testing.T) { password: "testing", }) _, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, }}) require.ErrorContains(t, err, "authentication required") } func TestSucceedsGitAuth(t *testing.T) { t.Parallel() - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + testImageAlpine, }, @@ -72,19 +69,19 @@ func TestSucceedsGitAuth(t *testing.T) { password: "testing", }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", "GIT_USERNAME=kyle", "GIT_PASSWORD=testing", }}) require.NoError(t, err) gitConfig := execContainer(t, ctr, "cat /workspaces/.git/config") - require.Contains(t, gitConfig, url) + require.Contains(t, gitConfig, srv.URL) } func TestSucceedsGitAuthInURL(t *testing.T) { t.Parallel() - gitURL := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + testImageAlpine, }, @@ -92,7 +89,7 @@ func TestSucceedsGitAuthInURL(t *testing.T) { password: "testing", }) - u, err := url.Parse(gitURL) + u, err := url.Parse(srv.URL) require.NoError(t, err) u.User = url.UserPassword("kyle", "testing") ctr, err := runEnvbuilder(t, options{env: []string{ @@ -149,7 +146,7 @@ func TestBuildFromDevcontainerWithFeatures(t *testing.T) { require.NoError(t, err) // Ensures that a Git repository with a devcontainer.json is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ ".devcontainer/devcontainer.json": `{ "name": "Test", @@ -174,7 +171,7 @@ func TestBuildFromDevcontainerWithFeatures(t *testing.T) { }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, }}) require.NoError(t, err) @@ -190,13 +187,13 @@ func TestBuildFromDevcontainerWithFeatures(t *testing.T) { func TestBuildFromDockerfile(t *testing.T) { // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + testImageAlpine, }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", }}) require.NoError(t, err) @@ -207,13 +204,13 @@ func TestBuildFromDockerfile(t *testing.T) { func TestBuildPrintBuildOutput(t *testing.T) { // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + testImageAlpine + "\nRUN echo hello", }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", }}) require.NoError(t, err) @@ -235,7 +232,7 @@ func TestBuildPrintBuildOutput(t *testing.T) { func TestBuildIgnoreVarRunSecrets(t *testing.T) { // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + testImageAlpine, }, @@ -245,7 +242,7 @@ func TestBuildIgnoreVarRunSecrets(t *testing.T) { require.NoError(t, err) ctr, err := runEnvbuilder(t, options{ env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", }, binds: []string{fmt.Sprintf("%s:/var/run/secrets", dir)}, @@ -258,13 +255,13 @@ func TestBuildIgnoreVarRunSecrets(t *testing.T) { func TestBuildWithSetupScript(t *testing.T) { // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + testImageAlpine, }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", "SETUP_SCRIPT=echo \"INIT_ARGS=-c 'echo hi > /wow && sleep infinity'\" >> $ENVBUILDER_ENV", }}) @@ -278,7 +275,7 @@ func TestBuildFromDevcontainerInCustomPath(t *testing.T) { t.Parallel() // Ensures that a Git repository with a devcontainer.json is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ ".devcontainer/custom/devcontainer.json": `{ "name": "Test", @@ -290,7 +287,7 @@ func TestBuildFromDevcontainerInCustomPath(t *testing.T) { }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DEVCONTAINER_DIR=.devcontainer/custom", }}) require.NoError(t, err) @@ -303,7 +300,7 @@ func TestBuildFromDevcontainerInSubfolder(t *testing.T) { t.Parallel() // Ensures that a Git repository with a devcontainer.json is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ ".devcontainer/subfolder/devcontainer.json": `{ "name": "Test", @@ -315,7 +312,7 @@ func TestBuildFromDevcontainerInSubfolder(t *testing.T) { }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, }}) require.NoError(t, err) @@ -326,7 +323,7 @@ func TestBuildFromDevcontainerInRoot(t *testing.T) { t.Parallel() // Ensures that a Git repository with a devcontainer.json is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "devcontainer.json": `{ "name": "Test", @@ -338,7 +335,7 @@ func TestBuildFromDevcontainerInRoot(t *testing.T) { }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, }}) require.NoError(t, err) @@ -347,11 +344,12 @@ func TestBuildFromDevcontainerInRoot(t *testing.T) { } func TestBuildCustomCertificates(t *testing.T) { - srv := httptest.NewTLSServer(createGitHandler(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + testImageAlpine, }, - })) + tls: true, + }) ctr, err := runEnvbuilder(t, options{env: []string{ "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", @@ -368,13 +366,13 @@ func TestBuildCustomCertificates(t *testing.T) { func TestBuildStopStartCached(t *testing.T) { // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + testImageAlpine, }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", "SKIP_REBUILD=true", }}) @@ -416,13 +414,13 @@ func TestBuildFailsFallback(t *testing.T) { t.Run("BadDockerfile", func(t *testing.T) { t.Parallel() // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "bad syntax", }, }) _, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", }}) require.ErrorContains(t, err, envbuilder.ErrNoFallbackImage.Error()) @@ -431,14 +429,14 @@ func TestBuildFailsFallback(t *testing.T) { t.Run("FailsBuild", func(t *testing.T) { t.Parallel() // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": `FROM ` + testImageAlpine + ` RUN exit 1`, }, }) _, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", }}) require.ErrorContains(t, err, envbuilder.ErrNoFallbackImage.Error()) @@ -446,25 +444,25 @@ RUN exit 1`, t.Run("BadDevcontainer", func(t *testing.T) { t.Parallel() // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ ".devcontainer/devcontainer.json": "not json", }, }) _, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, }}) require.ErrorContains(t, err, envbuilder.ErrNoFallbackImage.Error()) }) t.Run("NoImageOrDockerfile", func(t *testing.T) { t.Parallel() - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ ".devcontainer/devcontainer.json": "{}", }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "FALLBACK_IMAGE=" + testImageAlpine, }}) require.NoError(t, err) @@ -476,13 +474,13 @@ RUN exit 1`, func TestExitBuildOnFailure(t *testing.T) { t.Parallel() - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "bad syntax", }, }) _, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", "FALLBACK_IMAGE=" + testImageAlpine, // Ensures that the fallback doesn't work when an image is specified. @@ -495,7 +493,7 @@ func TestContainerEnv(t *testing.T) { t.Parallel() // Ensures that a Git repository with a devcontainer.json is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ ".devcontainer/devcontainer.json": `{ "name": "Test", @@ -516,7 +514,7 @@ func TestContainerEnv(t *testing.T) { }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "EXPORT_ENV_FILE=/env", }}) require.NoError(t, err) @@ -534,7 +532,7 @@ func TestLifecycleScripts(t *testing.T) { t.Parallel() // Ensures that a Git repository with a devcontainer.json is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ ".devcontainer/devcontainer.json": `{ "name": "Test", @@ -553,7 +551,7 @@ func TestLifecycleScripts(t *testing.T) { }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, }}) require.NoError(t, err) @@ -570,7 +568,7 @@ func TestPostStartScript(t *testing.T) { t.Parallel() // Ensures that a Git repository with a devcontainer.json is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ ".devcontainer/devcontainer.json": `{ "name": "Test", @@ -592,7 +590,7 @@ USER nobody`, }, }) ctr, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "POST_START_SCRIPT_PATH=/tmp/post-start.sh", "INIT_COMMAND=/bin/init.sh", }}) @@ -620,13 +618,13 @@ func TestPrivateRegistry(t *testing.T) { }) // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + image, }, }) _, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", }}) require.ErrorContains(t, err, "Unauthorized") @@ -639,7 +637,7 @@ func TestPrivateRegistry(t *testing.T) { }) // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + image, }, @@ -655,7 +653,7 @@ func TestPrivateRegistry(t *testing.T) { require.NoError(t, err) _, err = runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", "DOCKER_CONFIG_BASE64=" + base64.StdEncoding.EncodeToString(config), }}) @@ -671,7 +669,7 @@ func TestPrivateRegistry(t *testing.T) { }) // Ensures that a Git repository with a Dockerfile is cloned and built. - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: map[string]string{ "Dockerfile": "FROM " + image, }, @@ -687,7 +685,7 @@ func TestPrivateRegistry(t *testing.T) { require.NoError(t, err) _, err = runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=Dockerfile", "DOCKER_CONFIG_BASE64=" + base64.StdEncoding.EncodeToString(config), }}) @@ -810,11 +808,11 @@ COPY %s .`, testImageAlpine, inclFile) tc := tc t.Run(tc.name, func(t *testing.T) { - url := createGitServer(t, gitServerOptions{ + srv := createGitServer(t, gitServerOptions{ files: tc.files, }) _, err := runEnvbuilder(t, options{env: []string{ - "GIT_URL=" + url, + "GIT_URL=" + srv.URL, "DOCKERFILE_PATH=" + tc.dockerfilePath, "BUILD_CONTEXT_PATH=" + tc.buildContextPath, }}) @@ -858,41 +856,26 @@ type gitServerOptions struct { username string password string authMW func(http.Handler) http.Handler + tls bool } // createGitServer creates a git repository with an in-memory filesystem // and serves it over HTTP using a httptest.Server. -func createGitServer(t *testing.T, opts gitServerOptions) string { +func createGitServer(t *testing.T, opts gitServerOptions) *httptest.Server { t.Helper() if opts.authMW == nil { opts.authMW = gittest.BasicAuthMW(opts.username, opts.password) } - srv := httptest.NewServer(opts.authMW(createGitHandler(t, opts))) - return srv.URL -} - -func createGitHandler(t *testing.T, opts gitServerOptions) http.Handler { - t.Helper() + commits := make([]gittest.CommitFunc, 0) + for path, content := range opts.files { + commits = append(commits, gittest.Commit(t, path, content, "my test commit")) + } fs := memfs.New() - repo := gittest.NewRepo(t, fs) - w, err := repo.Worktree() - require.NoError(t, err) - for key, value := range opts.files { - gittest.WriteFile(t, fs, key, value) - _, err = w.Add(key) - require.NoError(t, err) + _ = gittest.NewRepo(t, fs, commits...) + if opts.tls { + return httptest.NewTLSServer(opts.authMW(gittest.NewServer(fs))) } - commit, err := w.Commit("my test commit", &git.CommitOptions{ - Author: &object.Signature{ - Name: "Example", - Email: "in@tests.com", - When: time.Now(), - }, - }) - require.NoError(t, err) - _, err = repo.CommitObject(commit) - require.NoError(t, err) - return gittest.NewServer(fs) + return httptest.NewServer(opts.authMW(gittest.NewServer(fs))) } // cleanOldEnvbuilders removes any old envbuilder containers. diff --git a/gittest/gittest.go b/testutil/gittest/gittest.go similarity index 79% rename from gittest/gittest.go rename to testutil/gittest/gittest.go index f1ec7a22..28629fee 100644 --- a/gittest/gittest.go +++ b/testutil/gittest/gittest.go @@ -5,12 +5,14 @@ import ( "net/http" "os" "testing" + "time" "github.com/go-git/go-billy/v5" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/cache" "github.com/go-git/go-git/v5/plumbing/format/pktline" + "github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/protocol/packp" "github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/plumbing/transport/server" @@ -95,8 +97,34 @@ func NewServer(fs billy.Filesystem) http.Handler { return mux } +// CommitFunc commits to a repo. +type CommitFunc func(billy.Filesystem, *git.Repository) + +// Commit is a test helper for committing a single file to a repo. +func Commit(t *testing.T, path, content, msg string) CommitFunc { + return func(fs billy.Filesystem, repo *git.Repository) { + t.Helper() + tree, err := repo.Worktree() + require.NoError(t, err) + WriteFile(t, fs, path, content) + _, err = tree.Add(path) + require.NoError(t, err) + commit, err := tree.Commit(msg, &git.CommitOptions{ + Author: &object.Signature{ + Name: "Example", + Email: "test@example.com", + When: time.Now(), + }, + }) + require.NoError(t, err) + _, err = repo.CommitObject(commit) + require.NoError(t, err) + } +} + // NewRepo returns a new Git repository. -func NewRepo(t *testing.T, fs billy.Filesystem) *git.Repository { +func NewRepo(t *testing.T, fs billy.Filesystem, commits ...CommitFunc) *git.Repository { + t.Helper() storage := filesystem.NewStorage(fs, cache.NewObjectLRU(cache.DefaultMaxSize)) repo, err := git.Init(storage, fs) require.NoError(t, err) @@ -106,11 +134,15 @@ func NewRepo(t *testing.T, fs billy.Filesystem) *git.Repository { err = storage.SetReference(h) require.NoError(t, err) + for _, commit := range commits { + commit(fs, repo) + } return repo } // WriteFile writes a file to the filesystem. func WriteFile(t *testing.T, fs billy.Filesystem, path, content string) { + t.Helper() file, err := fs.OpenFile(path, os.O_CREATE|os.O_RDWR, 0644) require.NoError(t, err) _, err = file.Write([]byte(content)) diff --git a/registrytest/registrytest.go b/testutil/registrytest/registrytest.go similarity index 100% rename from registrytest/registrytest.go rename to testutil/registrytest/registrytest.go