1// Copyright 2019 The Gitea Authors. All rights reserved. 2// Use of this source code is governed by a MIT-style 3// license that can be found in the LICENSE file. 4 5package integrations 6 7import ( 8 "context" 9 "fmt" 10 "net" 11 "net/http" 12 "net/url" 13 "os" 14 "path" 15 "path/filepath" 16 "strconv" 17 "strings" 18 "testing" 19 "time" 20 21 "code.gitea.io/gitea/modules/git" 22 "code.gitea.io/gitea/modules/setting" 23 "code.gitea.io/gitea/modules/ssh" 24 "code.gitea.io/gitea/modules/util" 25 26 "github.com/stretchr/testify/assert" 27) 28 29func withKeyFile(t *testing.T, keyname string, callback func(string)) { 30 31 tmpDir, err := os.MkdirTemp("", "key-file") 32 assert.NoError(t, err) 33 defer util.RemoveAll(tmpDir) 34 35 err = os.Chmod(tmpDir, 0700) 36 assert.NoError(t, err) 37 38 keyFile := filepath.Join(tmpDir, keyname) 39 err = ssh.GenKeyPair(keyFile) 40 assert.NoError(t, err) 41 42 err = os.WriteFile(path.Join(tmpDir, "ssh"), []byte("#!/bin/bash\n"+ 43 "ssh -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -o \"IdentitiesOnly=yes\" -i \""+keyFile+"\" \"$@\""), 0700) 44 assert.NoError(t, err) 45 46 //Setup ssh wrapper 47 os.Setenv("GIT_SSH", path.Join(tmpDir, "ssh")) 48 os.Setenv("GIT_SSH_COMMAND", 49 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i \""+keyFile+"\"") 50 os.Setenv("GIT_SSH_VARIANT", "ssh") 51 52 callback(keyFile) 53} 54 55func createSSHUrl(gitPath string, u *url.URL) *url.URL { 56 u2 := *u 57 u2.Scheme = "ssh" 58 u2.User = url.User("git") 59 u2.Host = net.JoinHostPort(setting.SSH.ListenHost, strconv.Itoa(setting.SSH.ListenPort)) 60 u2.Path = gitPath 61 return &u2 62} 63 64func allowLFSFilters() []string { 65 // Now here we should explicitly allow lfs filters to run 66 filteredLFSGlobalArgs := make([]string, len(git.GlobalCommandArgs)) 67 j := 0 68 for _, arg := range git.GlobalCommandArgs { 69 if strings.Contains(arg, "lfs") { 70 j-- 71 } else { 72 filteredLFSGlobalArgs[j] = arg 73 j++ 74 } 75 } 76 return filteredLFSGlobalArgs[:j] 77} 78 79func onGiteaRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ...bool) { 80 if len(prepare) == 0 || prepare[0] { 81 defer prepareTestEnv(t, 1)() 82 } 83 s := http.Server{ 84 Handler: c, 85 } 86 87 u, err := url.Parse(setting.AppURL) 88 assert.NoError(t, err) 89 listener, err := net.Listen("tcp", u.Host) 90 i := 0 91 for err != nil && i <= 10 { 92 time.Sleep(100 * time.Millisecond) 93 listener, err = net.Listen("tcp", u.Host) 94 i++ 95 } 96 assert.NoError(t, err) 97 u.Host = listener.Addr().String() 98 99 defer func() { 100 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) 101 s.Shutdown(ctx) 102 cancel() 103 }() 104 105 go s.Serve(listener) 106 //Started by config go ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs) 107 108 callback(t, u) 109} 110 111func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) { 112 onGiteaRunTB(t, func(t testing.TB, u *url.URL) { 113 callback(t.(*testing.T), u) 114 }, prepare...) 115} 116 117func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) { 118 return func(t *testing.T) { 119 assert.NoError(t, git.CloneWithArgs(context.Background(), u.String(), dstLocalPath, allowLFSFilters(), git.CloneRepoOptions{})) 120 exist, err := util.IsExist(filepath.Join(dstLocalPath, "README.md")) 121 assert.NoError(t, err) 122 assert.True(t, exist) 123 } 124} 125 126func doPartialGitClone(dstLocalPath string, u *url.URL) func(*testing.T) { 127 return func(t *testing.T) { 128 assert.NoError(t, git.CloneWithArgs(context.Background(), u.String(), dstLocalPath, allowLFSFilters(), git.CloneRepoOptions{ 129 Filter: "blob:none", 130 })) 131 exist, err := util.IsExist(filepath.Join(dstLocalPath, "README.md")) 132 assert.NoError(t, err) 133 assert.True(t, exist) 134 } 135} 136 137func doGitCloneFail(u *url.URL) func(*testing.T) { 138 return func(t *testing.T) { 139 tmpDir, err := os.MkdirTemp("", "doGitCloneFail") 140 assert.NoError(t, err) 141 defer util.RemoveAll(tmpDir) 142 assert.Error(t, git.Clone(u.String(), tmpDir, git.CloneRepoOptions{})) 143 exist, err := util.IsExist(filepath.Join(tmpDir, "README.md")) 144 assert.NoError(t, err) 145 assert.False(t, exist) 146 } 147} 148 149func doGitInitTestRepository(dstPath string) func(*testing.T) { 150 return func(t *testing.T) { 151 // Init repository in dstPath 152 assert.NoError(t, git.InitRepository(dstPath, false)) 153 // forcibly set default branch to master 154 _, err := git.NewCommand("symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(dstPath) 155 assert.NoError(t, err) 156 assert.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", dstPath)), 0644)) 157 assert.NoError(t, git.AddChanges(dstPath, true)) 158 signature := git.Signature{ 159 Email: "test@example.com", 160 Name: "test", 161 When: time.Now(), 162 } 163 assert.NoError(t, git.CommitChanges(dstPath, git.CommitChangesOptions{ 164 Committer: &signature, 165 Author: &signature, 166 Message: "Initial Commit", 167 })) 168 } 169} 170 171func doGitAddRemote(dstPath, remoteName string, u *url.URL) func(*testing.T) { 172 return func(t *testing.T) { 173 _, err := git.NewCommand("remote", "add", remoteName, u.String()).RunInDir(dstPath) 174 assert.NoError(t, err) 175 } 176} 177 178func doGitPushTestRepository(dstPath string, args ...string) func(*testing.T) { 179 return func(t *testing.T) { 180 _, err := git.NewCommand(append([]string{"push", "-u"}, args...)...).RunInDir(dstPath) 181 assert.NoError(t, err) 182 } 183} 184 185func doGitPushTestRepositoryFail(dstPath string, args ...string) func(*testing.T) { 186 return func(t *testing.T) { 187 _, err := git.NewCommand(append([]string{"push"}, args...)...).RunInDir(dstPath) 188 assert.Error(t, err) 189 } 190} 191 192func doGitCreateBranch(dstPath, branch string) func(*testing.T) { 193 return func(t *testing.T) { 194 _, err := git.NewCommand("checkout", "-b", branch).RunInDir(dstPath) 195 assert.NoError(t, err) 196 } 197} 198 199func doGitCheckoutBranch(dstPath string, args ...string) func(*testing.T) { 200 return func(t *testing.T) { 201 _, err := git.NewCommandNoGlobals(append(append(allowLFSFilters(), "checkout"), args...)...).RunInDir(dstPath) 202 assert.NoError(t, err) 203 } 204} 205 206func doGitMerge(dstPath string, args ...string) func(*testing.T) { 207 return func(t *testing.T) { 208 _, err := git.NewCommand(append([]string{"merge"}, args...)...).RunInDir(dstPath) 209 assert.NoError(t, err) 210 } 211} 212 213func doGitPull(dstPath string, args ...string) func(*testing.T) { 214 return func(t *testing.T) { 215 _, err := git.NewCommandNoGlobals(append(append(allowLFSFilters(), "pull"), args...)...).RunInDir(dstPath) 216 assert.NoError(t, err) 217 } 218} 219