Make git clone URL could use current signed-in user (#33091)
close #33086 * Add a special value for "SSH_USER" setting: `(DOER_USERNAME)` * Improve parseRepositoryURL and add tests (now it doesn't have hard dependency on some setting values) Many changes are just adding "ctx" and "doer" argument to functions. By the way, improve app.example.ini, remove all `%(key)s` syntax, it only makes messy and no user really cares about it. Document: https://gitea.com/gitea/docs/pulls/138
This commit is contained in:
parent
98637fe76e
commit
34dfc25b83
21 changed files with 273 additions and 143 deletions
|
@ -172,7 +172,7 @@ func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) {
|
|||
return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err)
|
||||
}
|
||||
|
||||
u, err := giturl.Parse(remoteURL)
|
||||
u, err := giturl.ParseGitURL(remoteURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
giturl "code.gitea.io/gitea/modules/git/url"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
|
@ -637,14 +638,26 @@ type CloneLink struct {
|
|||
}
|
||||
|
||||
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
|
||||
func ComposeHTTPSCloneURL(owner, repo string) string {
|
||||
return fmt.Sprintf("%s%s/%s.git", setting.AppURL, url.PathEscape(owner), url.PathEscape(repo))
|
||||
func ComposeHTTPSCloneURL(ctx context.Context, owner, repo string) string {
|
||||
return fmt.Sprintf("%s%s/%s.git", httplib.GuessCurrentAppURL(ctx), url.PathEscape(owner), url.PathEscape(repo))
|
||||
}
|
||||
|
||||
func ComposeSSHCloneURL(ownerName, repoName string) string {
|
||||
func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) string {
|
||||
sshUser := setting.SSH.User
|
||||
sshDomain := setting.SSH.Domain
|
||||
|
||||
if sshUser == "(DOER_USERNAME)" {
|
||||
// Some users use SSH reverse-proxy and need to use the current signed-in username as the SSH user
|
||||
// to make the SSH reverse-proxy could prepare the user's public keys ahead.
|
||||
// For most cases we have the correct "doer", then use it as the SSH user.
|
||||
// If we can't get the doer, then use the built-in SSH user.
|
||||
if doer != nil {
|
||||
sshUser = doer.Name
|
||||
} else {
|
||||
sshUser = setting.SSH.BuiltinServerUser
|
||||
}
|
||||
}
|
||||
|
||||
// non-standard port, it must use full URI
|
||||
if setting.SSH.Port != 22 {
|
||||
sshHost := net.JoinHostPort(sshDomain, strconv.Itoa(setting.SSH.Port))
|
||||
|
@ -662,21 +675,20 @@ func ComposeSSHCloneURL(ownerName, repoName string) string {
|
|||
return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||
}
|
||||
|
||||
func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
|
||||
repoName := repo.Name
|
||||
if isWiki {
|
||||
repoName += ".wiki"
|
||||
}
|
||||
|
||||
func (repo *Repository) cloneLink(ctx context.Context, doer *user_model.User, repoPathName string) *CloneLink {
|
||||
cl := new(CloneLink)
|
||||
cl.SSH = ComposeSSHCloneURL(repo.OwnerName, repoName)
|
||||
cl.HTTPS = ComposeHTTPSCloneURL(repo.OwnerName, repoName)
|
||||
cl.SSH = ComposeSSHCloneURL(doer, repo.OwnerName, repoPathName)
|
||||
cl.HTTPS = ComposeHTTPSCloneURL(ctx, repo.OwnerName, repoPathName)
|
||||
return cl
|
||||
}
|
||||
|
||||
// CloneLink returns clone URLs of repository.
|
||||
func (repo *Repository) CloneLink() (cl *CloneLink) {
|
||||
return repo.cloneLink(false)
|
||||
func (repo *Repository) CloneLink(ctx context.Context, doer *user_model.User) (cl *CloneLink) {
|
||||
return repo.cloneLink(ctx, doer, repo.Name)
|
||||
}
|
||||
|
||||
func (repo *Repository) CloneLinkGeneral(ctx context.Context) (cl *CloneLink) {
|
||||
return repo.cloneLink(ctx, nil /* no doer, use a general git user */, repo.Name)
|
||||
}
|
||||
|
||||
// GetOriginalURLHostname returns the hostname of a URL or the URL
|
||||
|
@ -772,47 +784,75 @@ func GetRepositoryByName(ctx context.Context, ownerID int64, name string) (*Repo
|
|||
return &repo, err
|
||||
}
|
||||
|
||||
// getRepositoryURLPathSegments returns segments (owner, reponame) extracted from a url
|
||||
func getRepositoryURLPathSegments(repoURL string) []string {
|
||||
if strings.HasPrefix(repoURL, setting.AppURL) {
|
||||
return strings.Split(strings.TrimPrefix(repoURL, setting.AppURL), "/")
|
||||
}
|
||||
func parseRepositoryURL(ctx context.Context, repoURL string) (ret struct {
|
||||
OwnerName, RepoName, RemainingPath string
|
||||
},
|
||||
) {
|
||||
// possible urls for git:
|
||||
// https://my.domain/sub-path/<owner>/<repo>[.git]
|
||||
// git+ssh://user@my.domain/<owner>/<repo>[.git]
|
||||
// ssh://user@my.domain/<owner>/<repo>[.git]
|
||||
// user@my.domain:<owner>/<repo>[.git]
|
||||
|
||||
sshURLVariants := [4]string{
|
||||
setting.SSH.Domain + ":",
|
||||
setting.SSH.User + "@" + setting.SSH.Domain + ":",
|
||||
"git+ssh://" + setting.SSH.Domain + "/",
|
||||
"git+ssh://" + setting.SSH.User + "@" + setting.SSH.Domain + "/",
|
||||
}
|
||||
|
||||
for _, sshURL := range sshURLVariants {
|
||||
if strings.HasPrefix(repoURL, sshURL) {
|
||||
return strings.Split(strings.TrimPrefix(repoURL, sshURL), "/")
|
||||
fillPathParts := func(s string) {
|
||||
s = strings.TrimPrefix(s, "/")
|
||||
fields := strings.SplitN(s, "/", 3)
|
||||
if len(fields) >= 2 {
|
||||
ret.OwnerName = fields[0]
|
||||
ret.RepoName = strings.TrimSuffix(fields[1], ".git")
|
||||
if len(fields) == 3 {
|
||||
ret.RemainingPath = "/" + fields[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
parsed, err := giturl.ParseGitURL(repoURL)
|
||||
if err != nil {
|
||||
return ret
|
||||
}
|
||||
if parsed.URL.Scheme == "http" || parsed.URL.Scheme == "https" {
|
||||
if !httplib.IsCurrentGiteaSiteURL(ctx, repoURL) {
|
||||
return ret
|
||||
}
|
||||
fillPathParts(strings.TrimPrefix(parsed.URL.Path, setting.AppSubURL))
|
||||
} else if parsed.URL.Scheme == "ssh" || parsed.URL.Scheme == "git+ssh" {
|
||||
domainSSH := setting.SSH.Domain
|
||||
domainCur := httplib.GuessCurrentHostDomain(ctx)
|
||||
urlDomain, _, _ := net.SplitHostPort(parsed.URL.Host)
|
||||
urlDomain = util.IfZero(urlDomain, parsed.URL.Host)
|
||||
if urlDomain == "" {
|
||||
return ret
|
||||
}
|
||||
// check whether URL domain is the App domain
|
||||
domainMatches := domainSSH == urlDomain
|
||||
// check whether URL domain is current domain from context
|
||||
domainMatches = domainMatches || (domainCur != "" && domainCur == urlDomain)
|
||||
if domainMatches {
|
||||
fillPathParts(parsed.URL.Path)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// GetRepositoryByURL returns the repository by given url
|
||||
func GetRepositoryByURL(ctx context.Context, repoURL string) (*Repository, error) {
|
||||
// possible urls for git:
|
||||
// https://my.domain/sub-path/<owner>/<repo>.git
|
||||
// https://my.domain/sub-path/<owner>/<repo>
|
||||
// git+ssh://user@my.domain/<owner>/<repo>.git
|
||||
// git+ssh://user@my.domain/<owner>/<repo>
|
||||
// user@my.domain:<owner>/<repo>.git
|
||||
// user@my.domain:<owner>/<repo>
|
||||
|
||||
pathSegments := getRepositoryURLPathSegments(repoURL)
|
||||
|
||||
if len(pathSegments) != 2 {
|
||||
ret := parseRepositoryURL(ctx, repoURL)
|
||||
if ret.OwnerName == "" {
|
||||
return nil, fmt.Errorf("unknown or malformed repository URL")
|
||||
}
|
||||
return GetRepositoryByOwnerAndName(ctx, ret.OwnerName, ret.RepoName)
|
||||
}
|
||||
|
||||
ownerName := pathSegments[0]
|
||||
repoName := strings.TrimSuffix(pathSegments[1], ".git")
|
||||
return GetRepositoryByOwnerAndName(ctx, ownerName, repoName)
|
||||
// GetRepositoryByURLRelax also accepts an SSH clone URL without user part
|
||||
func GetRepositoryByURLRelax(ctx context.Context, repoURL string) (*Repository, error) {
|
||||
if !strings.Contains(repoURL, "://") && !strings.Contains(repoURL, "@") {
|
||||
// convert "example.com:owner/repo" to "@example.com:owner/repo"
|
||||
p1, p2, p3 := strings.Index(repoURL, "."), strings.Index(repoURL, ":"), strings.Index(repoURL, "/")
|
||||
if 0 < p1 && p1 < p2 && p2 < p3 {
|
||||
repoURL = "@" + repoURL
|
||||
}
|
||||
}
|
||||
return GetRepositoryByURL(ctx, repoURL)
|
||||
}
|
||||
|
||||
// GetRepositoryByID returns the repository by given id if exists.
|
||||
|
|
|
@ -4,18 +4,23 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -127,65 +132,121 @@ func TestMetas(t *testing.T) {
|
|||
assert.Equal(t, ",owners,team1,", metas["teams"])
|
||||
}
|
||||
|
||||
func TestParseRepositoryURLPathSegments(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.AppURL, "https://localhost:3000")()
|
||||
|
||||
ctxURL, _ := url.Parse("https://gitea")
|
||||
ctxReq := &http.Request{URL: ctxURL, Header: http.Header{}}
|
||||
ctxReq.Host = ctxURL.Host
|
||||
ctxReq.Header.Add("X-Forwarded-Proto", ctxURL.Scheme)
|
||||
ctx := context.WithValue(context.Background(), httplib.RequestContextKey, ctxReq)
|
||||
cases := []struct {
|
||||
input string
|
||||
ownerName, repoName, remaining string
|
||||
}{
|
||||
{input: "/user/repo"},
|
||||
|
||||
{input: "https://localhost:3000/user/repo", ownerName: "user", repoName: "repo"},
|
||||
{input: "https://external:3000/user/repo"},
|
||||
|
||||
{input: "https://localhost:3000/user/repo.git/other", ownerName: "user", repoName: "repo", remaining: "/other"},
|
||||
|
||||
{input: "https://gitea/user/repo", ownerName: "user", repoName: "repo"},
|
||||
{input: "https://gitea:3333/user/repo"},
|
||||
|
||||
{input: "ssh://try.gitea.io:2222/user/repo", ownerName: "user", repoName: "repo"},
|
||||
{input: "ssh://external:2222/user/repo"},
|
||||
|
||||
{input: "git+ssh://user@try.gitea.io/user/repo.git", ownerName: "user", repoName: "repo"},
|
||||
{input: "git+ssh://user@external/user/repo.git"},
|
||||
|
||||
{input: "root@try.gitea.io:user/repo.git", ownerName: "user", repoName: "repo"},
|
||||
{input: "root@gitea:user/repo.git", ownerName: "user", repoName: "repo"},
|
||||
{input: "root@external:user/repo.git"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.input, func(t *testing.T) {
|
||||
ret := parseRepositoryURL(ctx, c.input)
|
||||
assert.Equal(t, c.ownerName, ret.OwnerName)
|
||||
assert.Equal(t, c.repoName, ret.RepoName)
|
||||
assert.Equal(t, c.remaining, ret.RemainingPath)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("WithSubpath", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.AppURL, "https://localhost:3000/subpath")()
|
||||
defer test.MockVariableValue(&setting.AppSubURL, "/subpath")()
|
||||
cases = []struct {
|
||||
input string
|
||||
ownerName, repoName, remaining string
|
||||
}{
|
||||
{input: "https://localhost:3000/user/repo"},
|
||||
{input: "https://localhost:3000/subpath/user/repo.git/other", ownerName: "user", repoName: "repo", remaining: "/other"},
|
||||
|
||||
{input: "ssh://try.gitea.io:2222/user/repo", ownerName: "user", repoName: "repo"},
|
||||
{input: "ssh://external:2222/user/repo"},
|
||||
|
||||
{input: "git+ssh://user@try.gitea.io/user/repo.git", ownerName: "user", repoName: "repo"},
|
||||
{input: "git+ssh://user@external/user/repo.git"},
|
||||
|
||||
{input: "root@try.gitea.io:user/repo.git", ownerName: "user", repoName: "repo"},
|
||||
{input: "root@external:user/repo.git"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.input, func(t *testing.T) {
|
||||
ret := parseRepositoryURL(ctx, c.input)
|
||||
assert.Equal(t, c.ownerName, ret.OwnerName)
|
||||
assert.Equal(t, c.repoName, ret.RepoName)
|
||||
assert.Equal(t, c.remaining, ret.RemainingPath)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetRepositoryByURL(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
t.Run("InvalidPath", func(t *testing.T) {
|
||||
repo, err := GetRepositoryByURL(db.DefaultContext, "something")
|
||||
|
||||
assert.Nil(t, repo)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
testRepo2 := func(t *testing.T, url string) {
|
||||
repo, err := GetRepositoryByURL(db.DefaultContext, url)
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(t, 2, repo.ID)
|
||||
assert.EqualValues(t, 2, repo.OwnerID)
|
||||
}
|
||||
|
||||
t.Run("ValidHttpURL", func(t *testing.T) {
|
||||
test := func(t *testing.T, url string) {
|
||||
repo, err := GetRepositoryByURL(db.DefaultContext, url)
|
||||
|
||||
assert.NotNil(t, repo)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, int64(2), repo.ID)
|
||||
assert.Equal(t, int64(2), repo.OwnerID)
|
||||
}
|
||||
|
||||
test(t, "https://try.gitea.io/user2/repo2")
|
||||
test(t, "https://try.gitea.io/user2/repo2.git")
|
||||
testRepo2(t, "https://try.gitea.io/user2/repo2")
|
||||
testRepo2(t, "https://try.gitea.io/user2/repo2.git")
|
||||
})
|
||||
|
||||
t.Run("ValidGitSshURL", func(t *testing.T) {
|
||||
test := func(t *testing.T, url string) {
|
||||
repo, err := GetRepositoryByURL(db.DefaultContext, url)
|
||||
testRepo2(t, "git+ssh://sshuser@try.gitea.io/user2/repo2")
|
||||
testRepo2(t, "git+ssh://sshuser@try.gitea.io/user2/repo2.git")
|
||||
|
||||
assert.NotNil(t, repo)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, int64(2), repo.ID)
|
||||
assert.Equal(t, int64(2), repo.OwnerID)
|
||||
}
|
||||
|
||||
test(t, "git+ssh://sshuser@try.gitea.io/user2/repo2")
|
||||
test(t, "git+ssh://sshuser@try.gitea.io/user2/repo2.git")
|
||||
|
||||
test(t, "git+ssh://try.gitea.io/user2/repo2")
|
||||
test(t, "git+ssh://try.gitea.io/user2/repo2.git")
|
||||
testRepo2(t, "git+ssh://try.gitea.io/user2/repo2")
|
||||
testRepo2(t, "git+ssh://try.gitea.io/user2/repo2.git")
|
||||
})
|
||||
|
||||
t.Run("ValidImplicitSshURL", func(t *testing.T) {
|
||||
test := func(t *testing.T, url string) {
|
||||
repo, err := GetRepositoryByURL(db.DefaultContext, url)
|
||||
|
||||
assert.NotNil(t, repo)
|
||||
assert.NoError(t, err)
|
||||
testRepo2(t, "sshuser@try.gitea.io:user2/repo2")
|
||||
testRepo2(t, "sshuser@try.gitea.io:user2/repo2.git")
|
||||
|
||||
testRelax := func(t *testing.T, url string) {
|
||||
repo, err := GetRepositoryByURLRelax(db.DefaultContext, url)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(2), repo.ID)
|
||||
assert.Equal(t, int64(2), repo.OwnerID)
|
||||
}
|
||||
|
||||
test(t, "sshuser@try.gitea.io:user2/repo2")
|
||||
test(t, "sshuser@try.gitea.io:user2/repo2.git")
|
||||
|
||||
test(t, "try.gitea.io:user2/repo2")
|
||||
test(t, "try.gitea.io:user2/repo2.git")
|
||||
// TODO: it doesn't seem to be common git ssh URL, should we really support this?
|
||||
testRelax(t, "try.gitea.io:user2/repo2")
|
||||
testRelax(t, "try.gitea.io:user2/repo2.git")
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -199,23 +260,30 @@ func TestComposeSSHCloneURL(t *testing.T) {
|
|||
setting.SSH.Domain = "domain"
|
||||
setting.SSH.Port = 22
|
||||
setting.Repository.UseCompatSSHURI = false
|
||||
assert.Equal(t, "git@domain:user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
||||
assert.Equal(t, "git@domain:user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
|
||||
setting.Repository.UseCompatSSHURI = true
|
||||
assert.Equal(t, "ssh://git@domain/user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
||||
assert.Equal(t, "ssh://git@domain/user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
|
||||
// test SSH_DOMAIN while use non-standard SSH port
|
||||
setting.SSH.Port = 123
|
||||
setting.Repository.UseCompatSSHURI = false
|
||||
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
||||
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
|
||||
setting.Repository.UseCompatSSHURI = true
|
||||
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
||||
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
|
||||
|
||||
// test IPv6 SSH_DOMAIN
|
||||
setting.Repository.UseCompatSSHURI = false
|
||||
setting.SSH.Domain = "::1"
|
||||
setting.SSH.Port = 22
|
||||
assert.Equal(t, "git@[::1]:user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
||||
assert.Equal(t, "git@[::1]:user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
|
||||
setting.SSH.Port = 123
|
||||
assert.Equal(t, "ssh://git@[::1]:123/user/repo.git", ComposeSSHCloneURL("user", "repo"))
|
||||
assert.Equal(t, "ssh://git@[::1]:123/user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
|
||||
|
||||
setting.SSH.User = "(DOER_USERNAME)"
|
||||
setting.SSH.Domain = "domain"
|
||||
setting.SSH.Port = 22
|
||||
assert.Equal(t, "doer@domain:user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
|
||||
setting.SSH.Port = 123
|
||||
assert.Equal(t, "ssh://doer@domain:123/user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
|
||||
}
|
||||
|
||||
func TestIsUsableRepoName(t *testing.T) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
@ -72,8 +73,8 @@ func (err ErrWikiInvalidFileName) Unwrap() error {
|
|||
}
|
||||
|
||||
// WikiCloneLink returns clone URLs of repository wiki.
|
||||
func (repo *Repository) WikiCloneLink() *CloneLink {
|
||||
return repo.cloneLink(true)
|
||||
func (repo *Repository) WikiCloneLink(ctx context.Context, doer *user_model.User) *CloneLink {
|
||||
return repo.cloneLink(ctx, doer, repo.Name+".wiki")
|
||||
}
|
||||
|
||||
// WikiPath returns wiki data path by given user and repository name.
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package repo_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
|
@ -18,7 +19,7 @@ func TestRepository_WikiCloneLink(t *testing.T) {
|
|||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
cloneLink := repo.WikiCloneLink()
|
||||
cloneLink := repo.WikiCloneLink(context.Background(), nil)
|
||||
assert.Equal(t, "ssh://sshuser@try.gitea.io:3000/user2/repo1.wiki.git", cloneLink.SSH)
|
||||
assert.Equal(t, "https://try.gitea.io/user2/repo1.wiki.git", cloneLink.HTTPS)
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
|
|||
|
||||
setting.IsInTesting = true
|
||||
setting.AppURL = "https://try.gitea.io/"
|
||||
setting.Domain = "try.gitea.io"
|
||||
setting.RunUser = "runuser"
|
||||
setting.SSH.User = "sshuser"
|
||||
setting.SSH.BuiltinServerUser = "builtinuser"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue