package git import ( "fmt" "log" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "edge-infra.dev/pkg/lib/build/bazel" "edge-infra.dev/pkg/lib/cli/sh" ) var ( dir string shell *sh.Shell git *Git branch = "a-super-real-branch" ) func TestMain(m *testing.M) { var err error // initialize repository dir, err = newTempGitRepoDir() if err != nil { log.Fatal("failed to initialize test repository", err) } defer os.RemoveAll(dir) shell = sh.NewInDir(dir) shell.RunOrDie("git init -q") shell.RunOrDie("git config user.name \"testbot\"") shell.RunOrDie("git config user.email \"testmail@testworld.com\"") shell.RunOrDie(fmt.Sprintf("git checkout -b %s", branch)) err = os.WriteFile(filepath.Join(dir, ".version"), []byte("0.0.1"), 0600) if err != nil { log.Fatal("failed to resolve test tmp dir", err) } shell.RunOrDie("git add .version") shell.RunOrDie("git commit -m \"\"") fmt.Println(shell.RunOrDie("git status")) git = NewInDir(dir) os.Exit(m.Run()) } func TestBranch(t *testing.T) { actual, err := git.Branch() assert.NoError(t, err) assert.Equal(t, branch, actual) } func TestCommit(t *testing.T) { commit, err := git.Commit() assert.NoError(t, err) assert.NotEmpty(t, commit) } func TestCommitForFile(t *testing.T) { current, err := git.Commit() assert.NoError(t, err) assert.NotEmpty(t, current) commitFile(t, "test-file", []byte("this is a very special file")) // get the commit the file we care about was changed in desired, err := git.Commit() assert.NoError(t, err) assert.NotEmpty(t, current) // produce another, unrelated commit, to verify that we are fetching a non-HEAD // commit commitFile(t, "test-file2", []byte("my very special, unrelated, file to commit")) // now get the commit for test-file and check that it matches testFileCommit, err := git.CommitForFile("test-file") assert.NoError(t, err) assert.NotEmpty(t, testFileCommit) assert.Equal(t, desired, testFileCommit) } func TestTimestamp(t *testing.T) { ts, err := git.Timestamp() assert.NoError(t, err) assert.NotEmpty(t, ts) commitFile(t, "timestamped-test-file", []byte("im STAMPED, baby")) desired, err := git.Timestamp() assert.NoError(t, err) assert.NotEmpty(t, desired) previousCommit, err := git.Commit() // try to fetch timestamp of this commit later assert.NoError(t, err) assert.NotEmpty(t, previousCommit) commitFile(t, "timestamped-test-file-2", []byte("im STAMPED, again, baby")) testFileTimestamp, err := git.Timestamp("timestamped-test-file") assert.NoError(t, err) assert.NotEmpty(t, testFileTimestamp) assert.Equal(t, desired, testFileTimestamp) commitTimestamp, err := git.Timestamp(previousCommit) assert.NoError(t, err) assert.NotEmpty(t, commitTimestamp) assert.Equal(t, desired, commitTimestamp) } func TestPath(t *testing.T) { p, err := git.Path() assert.NoError(t, err) assert.Equal(t, dir, p) } func TestRemote(t *testing.T) { assert.NoError(t, shell.RunE("git remote add origin https://foo.git")) r, err := git.Remote() assert.NoError(t, err) assert.Equal(t, "https://foo", r) } func TestRemoteWithUser(t *testing.T) { repo, err := newTempGitRepoDir() if err != nil { t.Fatal(err) } shell := sh.NewInDir(repo) shell.RunOrDie("git init -q") shell.RunOrDie("git config user.name \"testbot\"") shell.RunOrDie("git config user.email \"testmail@testworld.com\"") assert.NoError(t, shell.RunE("git remote add origin https://user:password@thegithub.com")) git := NewInDir(repo) r, err := git.Remote() assert.NoError(t, err) assert.Equal(t, "https://thegithub.com", r) } func TestRemoteWithGithubSshUrl(t *testing.T) { repo, err := newTempGitRepoDir() if err != nil { t.Fatal(err) } shell := sh.NewInDir(repo) shell.RunOrDie("git init -q") shell.RunOrDie("git config user.name \"testbot\"") shell.RunOrDie("git config user.email \"testmail@testworld.com\"") assert.NoError(t, shell.RunE("git remote add origin git@github.com:ncrvoyix-swt-retail/edge-infra.git")) git := NewInDir(repo) r, err := git.Remote() assert.NoError(t, err) assert.Equal(t, "git@github.com:ncrvoyix-swt-retail/edge-infra", r) } func TestDirty(t *testing.T) { // Should begin in a clean state dirty, err := git.IsDirty() assert.NoError(t, err) assert.False(t, dirty) // Create untracked file, shouldnt impact dirty status require.NoError(t, os.WriteFile(filepath.Join(dir, "new-file"), []byte("untracked file"), 0600)) dirty, err = git.IsDirty() assert.NoError(t, err) assert.False(t, dirty) // Create newly tracked file, then modify it t.Log("committing new-tracked-file") commitFile(t, "new-tracked-file", []byte("hi mom")) dirty, err = git.IsDirty() assert.NoError(t, err) assert.False(t, dirty) // Should be dirty after modifying file t.Log("modifying new-tracked-file") require.NoError(t, os.WriteFile(filepath.Join(dir, "new-tracked-file"), []byte("hi dad"), 0600)) dirty, err = git.IsDirty() assert.NoError(t, err) assert.True(t, dirty) } func TestIsRebaseInProgress(t *testing.T) { // Should begin in a clean state rebase, err := git.IsRebaseInProgress() assert.NoError(t, err) assert.False(t, rebase) rmergeDir := filepath.Join(dir, ".git", "rebase-merge") t.Log(rmergeDir) rapplyDir := filepath.Join(dir, ".git", "rebase-apply") t.Log(rapplyDir) assert.Equal(t, dir, git.sh.Getwd()) // Create rebase-merge directory require.NoError(t, os.Mkdir(rmergeDir, 0600)) rebase, err = git.IsRebaseInProgress() assert.NoError(t, err) assert.True(t, rebase) // Create rebase-apply directory require.NoError(t, os.Mkdir(rapplyDir, 0600)) rebase, err = git.IsRebaseInProgress() assert.NoError(t, err) assert.True(t, rebase) // Remove rebase-merge require.NoError(t, os.RemoveAll(rmergeDir)) rebase, err = git.IsRebaseInProgress() assert.NoError(t, err) assert.True(t, rebase) // Remove rebase-apply require.NoError(t, os.RemoveAll(rapplyDir)) rebase, err = git.IsRebaseInProgress() assert.NoError(t, err) assert.False(t, rebase) } func commitFile(t *testing.T, name string, contents []byte) { t.Helper() assert.NoError(t, os.WriteFile( filepath.Join(dir, name), contents, 0600, )) assert.NoError(t, shell.RunE(fmt.Sprintf("git add %s", name))) assert.NoError(t, shell.RunE("git commit -m \"\"")) } func newTempGitRepoDir() (string, error) { dir, err := bazel.NewTestTmpDir("git_test-*") if err != nil { return "", fmt.Errorf("failed to resolve test tmp dir: %w", err) } return dir, nil }