github.com/nektos/act@v0.2.63/pkg/common/git/git_test.go (about)

     1  package git
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"syscall"
    10  	"testing"
    11  
    12  	log "github.com/sirupsen/logrus"
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/nektos/act/pkg/common"
    17  )
    18  
    19  func TestFindGitSlug(t *testing.T) {
    20  	assert := assert.New(t)
    21  
    22  	var slugTests = []struct {
    23  		url      string // input
    24  		provider string // expected result
    25  		slug     string // expected result
    26  	}{
    27  		{"https://git-codecommit.us-east-1.amazonaws.com/v1/repos/my-repo-name", "CodeCommit", "my-repo-name"},
    28  		{"ssh://git-codecommit.us-west-2.amazonaws.com/v1/repos/my-repo", "CodeCommit", "my-repo"},
    29  		{"git@github.com:nektos/act.git", "GitHub", "nektos/act"},
    30  		{"git@github.com:nektos/act", "GitHub", "nektos/act"},
    31  		{"https://github.com/nektos/act.git", "GitHub", "nektos/act"},
    32  		{"http://github.com/nektos/act.git", "GitHub", "nektos/act"},
    33  		{"https://github.com/nektos/act", "GitHub", "nektos/act"},
    34  		{"http://github.com/nektos/act", "GitHub", "nektos/act"},
    35  		{"git+ssh://git@github.com/owner/repo.git", "GitHub", "owner/repo"},
    36  		{"http://myotherrepo.com/act.git", "", "http://myotherrepo.com/act.git"},
    37  	}
    38  
    39  	for _, tt := range slugTests {
    40  		provider, slug, err := findGitSlug(tt.url, "github.com")
    41  
    42  		assert.NoError(err)
    43  		assert.Equal(tt.provider, provider)
    44  		assert.Equal(tt.slug, slug)
    45  	}
    46  }
    47  
    48  func testDir(t *testing.T) string {
    49  	basedir, err := os.MkdirTemp("", "act-test")
    50  	require.NoError(t, err)
    51  	t.Cleanup(func() { _ = os.RemoveAll(basedir) })
    52  	return basedir
    53  }
    54  
    55  func cleanGitHooks(dir string) error {
    56  	hooksDir := filepath.Join(dir, ".git", "hooks")
    57  	files, err := os.ReadDir(hooksDir)
    58  	if err != nil {
    59  		if os.IsNotExist(err) {
    60  			return nil
    61  		}
    62  		return err
    63  	}
    64  	for _, f := range files {
    65  		if f.IsDir() {
    66  			continue
    67  		}
    68  		relName := filepath.Join(hooksDir, f.Name())
    69  		if err := os.Remove(relName); err != nil {
    70  			return err
    71  		}
    72  	}
    73  	return nil
    74  }
    75  
    76  func TestFindGitRemoteURL(t *testing.T) {
    77  	assert := assert.New(t)
    78  
    79  	basedir := testDir(t)
    80  	gitConfig()
    81  	err := gitCmd("init", basedir)
    82  	assert.NoError(err)
    83  	err = cleanGitHooks(basedir)
    84  	assert.NoError(err)
    85  
    86  	remoteURL := "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/my-repo-name"
    87  	err = gitCmd("-C", basedir, "remote", "add", "origin", remoteURL)
    88  	assert.NoError(err)
    89  
    90  	u, err := findGitRemoteURL(context.Background(), basedir, "origin")
    91  	assert.NoError(err)
    92  	assert.Equal(remoteURL, u)
    93  
    94  	remoteURL = "git@github.com/AwesomeOwner/MyAwesomeRepo.git"
    95  	err = gitCmd("-C", basedir, "remote", "add", "upstream", remoteURL)
    96  	assert.NoError(err)
    97  	u, err = findGitRemoteURL(context.Background(), basedir, "upstream")
    98  	assert.NoError(err)
    99  	assert.Equal(remoteURL, u)
   100  }
   101  
   102  func TestGitFindRef(t *testing.T) {
   103  	basedir := testDir(t)
   104  	gitConfig()
   105  
   106  	for name, tt := range map[string]struct {
   107  		Prepare func(t *testing.T, dir string)
   108  		Assert  func(t *testing.T, ref string, err error)
   109  	}{
   110  		"new_repo": {
   111  			Prepare: func(t *testing.T, dir string) {},
   112  			Assert: func(t *testing.T, ref string, err error) {
   113  				require.Error(t, err)
   114  			},
   115  		},
   116  		"new_repo_with_commit": {
   117  			Prepare: func(t *testing.T, dir string) {
   118  				require.NoError(t, gitCmd("-C", dir, "commit", "--allow-empty", "-m", "msg"))
   119  			},
   120  			Assert: func(t *testing.T, ref string, err error) {
   121  				require.NoError(t, err)
   122  				require.Equal(t, "refs/heads/master", ref)
   123  			},
   124  		},
   125  		"current_head_is_tag": {
   126  			Prepare: func(t *testing.T, dir string) {
   127  				require.NoError(t, gitCmd("-C", dir, "commit", "--allow-empty", "-m", "commit msg"))
   128  				require.NoError(t, gitCmd("-C", dir, "tag", "v1.2.3"))
   129  				require.NoError(t, gitCmd("-C", dir, "checkout", "v1.2.3"))
   130  			},
   131  			Assert: func(t *testing.T, ref string, err error) {
   132  				require.NoError(t, err)
   133  				require.Equal(t, "refs/tags/v1.2.3", ref)
   134  			},
   135  		},
   136  		"current_head_is_same_as_tag": {
   137  			Prepare: func(t *testing.T, dir string) {
   138  				require.NoError(t, gitCmd("-C", dir, "commit", "--allow-empty", "-m", "1.4.2 release"))
   139  				require.NoError(t, gitCmd("-C", dir, "tag", "v1.4.2"))
   140  			},
   141  			Assert: func(t *testing.T, ref string, err error) {
   142  				require.NoError(t, err)
   143  				require.Equal(t, "refs/tags/v1.4.2", ref)
   144  			},
   145  		},
   146  		"current_head_is_not_tag": {
   147  			Prepare: func(t *testing.T, dir string) {
   148  				require.NoError(t, gitCmd("-C", dir, "commit", "--allow-empty", "-m", "msg"))
   149  				require.NoError(t, gitCmd("-C", dir, "tag", "v1.4.2"))
   150  				require.NoError(t, gitCmd("-C", dir, "commit", "--allow-empty", "-m", "msg2"))
   151  			},
   152  			Assert: func(t *testing.T, ref string, err error) {
   153  				require.NoError(t, err)
   154  				require.Equal(t, "refs/heads/master", ref)
   155  			},
   156  		},
   157  		"current_head_is_another_branch": {
   158  			Prepare: func(t *testing.T, dir string) {
   159  				require.NoError(t, gitCmd("-C", dir, "checkout", "-b", "mybranch"))
   160  				require.NoError(t, gitCmd("-C", dir, "commit", "--allow-empty", "-m", "msg"))
   161  			},
   162  			Assert: func(t *testing.T, ref string, err error) {
   163  				require.NoError(t, err)
   164  				require.Equal(t, "refs/heads/mybranch", ref)
   165  			},
   166  		},
   167  	} {
   168  		tt := tt
   169  		name := name
   170  		t.Run(name, func(t *testing.T) {
   171  			dir := filepath.Join(basedir, name)
   172  			require.NoError(t, os.MkdirAll(dir, 0o755))
   173  			require.NoError(t, gitCmd("-C", dir, "init", "--initial-branch=master"))
   174  			require.NoError(t, cleanGitHooks(dir))
   175  			tt.Prepare(t, dir)
   176  			ref, err := FindGitRef(context.Background(), dir)
   177  			tt.Assert(t, ref, err)
   178  		})
   179  	}
   180  }
   181  
   182  func TestGitCloneExecutor(t *testing.T) {
   183  	for name, tt := range map[string]struct {
   184  		Err      error
   185  		URL, Ref string
   186  	}{
   187  		"tag": {
   188  			Err: nil,
   189  			URL: "https://github.com/actions/checkout",
   190  			Ref: "v2",
   191  		},
   192  		"branch": {
   193  			Err: nil,
   194  			URL: "https://github.com/anchore/scan-action",
   195  			Ref: "act-fails",
   196  		},
   197  		"sha": {
   198  			Err: nil,
   199  			URL: "https://github.com/actions/checkout",
   200  			Ref: "5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f", // v2
   201  		},
   202  		"short-sha": {
   203  			Err: &Error{ErrShortRef, "5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f"},
   204  			URL: "https://github.com/actions/checkout",
   205  			Ref: "5a4ac90", // v2
   206  		},
   207  	} {
   208  		t.Run(name, func(t *testing.T) {
   209  			clone := NewGitCloneExecutor(NewGitCloneExecutorInput{
   210  				URL: tt.URL,
   211  				Ref: tt.Ref,
   212  				Dir: testDir(t),
   213  			})
   214  
   215  			err := clone(context.Background())
   216  			if tt.Err != nil {
   217  				assert.Error(t, err)
   218  				assert.Equal(t, tt.Err, err)
   219  			} else {
   220  				assert.Empty(t, err)
   221  			}
   222  		})
   223  	}
   224  }
   225  
   226  func gitConfig() {
   227  	if os.Getenv("GITHUB_ACTIONS") == "true" {
   228  		var err error
   229  		if err = gitCmd("config", "--global", "user.email", "test@test.com"); err != nil {
   230  			log.Error(err)
   231  		}
   232  		if err = gitCmd("config", "--global", "user.name", "Unit Test"); err != nil {
   233  			log.Error(err)
   234  		}
   235  	}
   236  }
   237  
   238  func gitCmd(args ...string) error {
   239  	cmd := exec.Command("git", args...)
   240  	cmd.Stdout = os.Stdout
   241  	cmd.Stderr = os.Stderr
   242  
   243  	err := cmd.Run()
   244  	if exitError, ok := err.(*exec.ExitError); ok {
   245  		if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok {
   246  			return fmt.Errorf("Exit error %d", waitStatus.ExitStatus())
   247  		}
   248  		return exitError
   249  	}
   250  	return nil
   251  }
   252  
   253  func TestCloneIfRequired(t *testing.T) {
   254  	tempDir := t.TempDir()
   255  	ctx := context.Background()
   256  
   257  	t.Run("clone", func(t *testing.T) {
   258  		repo, err := CloneIfRequired(ctx, "refs/heads/main", NewGitCloneExecutorInput{
   259  			URL: "https://github.com/actions/checkout",
   260  			Dir: tempDir,
   261  		}, common.Logger(ctx))
   262  		assert.NoError(t, err)
   263  		assert.NotNil(t, repo)
   264  	})
   265  
   266  	t.Run("clone different remote", func(t *testing.T) {
   267  		repo, err := CloneIfRequired(ctx, "refs/heads/main", NewGitCloneExecutorInput{
   268  			URL: "https://github.com/actions/setup-go",
   269  			Dir: tempDir,
   270  		}, common.Logger(ctx))
   271  		require.NoError(t, err)
   272  		require.NotNil(t, repo)
   273  
   274  		remote, err := repo.Remote("origin")
   275  		require.NoError(t, err)
   276  		require.Len(t, remote.Config().URLs, 1)
   277  		assert.Equal(t, "https://github.com/actions/setup-go", remote.Config().URLs[0])
   278  	})
   279  }