github.com/bitrise-io/bitrise-step-update-gitops-repository@v0.0.0-20240426081835-1466be593380/pkg/gitops/local_repository_test.go (about)

     1  package gitops
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"path"
    10  	"testing"
    11  
    12  	"github.com/bitrise-io/go-steputils/stepconf"
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  var gitRepoCases = map[string]struct {
    18  	upstreamBranch string
    19  	repoURL        string
    20  }{
    21  	"master of testhub.assert/test/foo": {
    22  		upstreamBranch: "master",
    23  		repoURL:        "testhub.assert/test/foo",
    24  	},
    25  	"staging of testhub.assert/test/bar": {
    26  		upstreamBranch: "staging",
    27  		repoURL:        "testhub.assert/test/bar",
    28  	},
    29  }
    30  
    31  func TestGitRepo(t *testing.T) {
    32  	ctx := context.Background()
    33  
    34  	for name, tc := range gitRepoCases {
    35  		t.Run(name, func(t *testing.T) {
    36  			upstreamPath, close := localUpstreamRepo(t, tc.upstreamBranch)
    37  			defer close()
    38  
    39  			// Initialize mock Github client.
    40  			wantPullRequestURL := fmt.Sprintf("https://%s/pr/15", tc.repoURL)
    41  			var gotHead, gotBase string
    42  			pr := &pullRequestOpenerMock{
    43  				OpenPullRequestFunc: func(_ context.Context, p openPullRequestParams) (string, error) {
    44  					gotHead = p.head
    45  					gotBase = p.base
    46  					return wantPullRequestURL, nil
    47  				},
    48  			}
    49  
    50  			repo, err := NewGitRepo(ctx, NewGitRepoParams{
    51  				PullRequestOpener: pr,
    52  				GithubRepo: &githubRepo{
    53  					url: stepconf.Secret(upstreamPath),
    54  				},
    55  				Branch: tc.upstreamBranch,
    56  			})
    57  			t.Run("create new local repository clone", func(t *testing.T) {
    58  				require.NoError(t, err, "newRepository")
    59  			})
    60  
    61  			t.Run("repository is clean without changes", func(t *testing.T) {
    62  				clean, err := repo.workingDirectoryClean()
    63  				require.NoError(t, err)
    64  				require.True(t, clean)
    65  			})
    66  
    67  			t.Run("repository is dirty after changes", func(t *testing.T) {
    68  				changePath := path.Join(repo.localPath(), "empty.go")
    69  				write(t, changePath, "package empty")
    70  
    71  				clean, err := repo.workingDirectoryClean()
    72  				require.NoError(t, err)
    73  				require.False(t, clean)
    74  			})
    75  
    76  			t.Run("commit and push changes to upstream", func(t *testing.T) {
    77  				err := repo.gitCommitAndPush("test commit")
    78  				require.NoError(t, err, "commit and push")
    79  
    80  				clean, err := repo.workingDirectoryClean()
    81  				require.NoError(t, err, "working directory clean")
    82  				require.True(t, clean)
    83  			})
    84  
    85  			t.Run("open pull request from a new branch", func(t *testing.T) {
    86  				require.NoError(t, repo.gitCheckoutNewBranch(), "new branch")
    87  				changePath := path.Join(repo.localPath(), "another.go")
    88  				write(t, changePath, "package another")
    89  
    90  				err := repo.gitCommitAndPush("another commit")
    91  				require.NoError(t, err, "commit and push another")
    92  
    93  				gotPullRequestURL, err := repo.openPullRequest(ctx, "", "")
    94  				require.NoError(t, err, "open pull request")
    95  				assert.Equal(t, wantPullRequestURL, gotPullRequestURL, "pr url")
    96  
    97  				assert.Equal(t, tc.upstreamBranch, gotBase, "pr base")
    98  
    99  				assert.NotEqual(t, gotBase, gotHead, "pr head != base")
   100  				wantHead, err := repo.currentBranch()
   101  				require.NoError(t, err, "current branch")
   102  				assert.Equal(t, wantHead, gotHead, "pr head = current branch")
   103  			})
   104  		})
   105  	}
   106  }
   107  
   108  func localUpstreamRepo(t *testing.T, branch string) (string, func()) {
   109  	repoPath, err := ioutil.TempDir("", "")
   110  	require.NoError(t, err, "new temp directory for local upstream")
   111  	readmePath := path.Join(repoPath, "README.md")
   112  
   113  	git(t, repoPath, "init")
   114  	git(t, repoPath, "checkout", "-b", branch)
   115  	write(t, readmePath, "A local upstream repository for testing.")
   116  	git(t, repoPath, "add", "--all")
   117  	git(t, repoPath, "commit", "-m", "initial commit")
   118  	// allow push from another git repository
   119  	git(t, repoPath, "config", "receive.denyCurrentBranch", "ignore")
   120  
   121  	return repoPath, func() {
   122  		os.RemoveAll(repoPath)
   123  	}
   124  }
   125  
   126  func write(t *testing.T, path, content string) {
   127  	err := ioutil.WriteFile(path, []byte(content), 0600)
   128  	require.NoError(t, err, "ioutil.WriteFile(%s)", path)
   129  }
   130  
   131  func git(t *testing.T, repoPath string, args ...string) {
   132  	// Change current directory to the repositorys local clone.
   133  	originalDir, err := os.Getwd()
   134  	require.NoError(t, err, "get current dir")
   135  	require.NoError(t, os.Chdir(repoPath), "change to upstream repo")
   136  	// Defer a revert of the current directory to the original one.
   137  	defer func() {
   138  		require.NoError(t, os.Chdir(originalDir), "change to original dir")
   139  	}()
   140  
   141  	cmd := exec.Command("git", args...)
   142  	require.NoError(t, cmd.Run(), "git %+v", args)
   143  }