Skip to content

Commit f30e1b3

Browse files
committed
feat: clone repository with tea cli
Signed-off-by: Quentin Guidée <[email protected]>
1 parent b35a9da commit f30e1b3

File tree

7 files changed

+69
-32
lines changed

7 files changed

+69
-32
lines changed

models/repo/repo.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -646,14 +646,16 @@ func (repo *Repository) DescriptionHTML(ctx context.Context) template.HTML {
646646
type CloneLink struct {
647647
SSH string
648648
HTTPS string
649+
Tea string
649650
}
650651

651-
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
652-
func ComposeHTTPSCloneURL(ctx context.Context, owner, repo string) string {
652+
// ComposeHTTPSCloneLink returns HTTPS clone URL based on the given owner and repository name.
653+
func ComposeHTTPSCloneLink(ctx context.Context, owner, repo string) string {
653654
return fmt.Sprintf("%s%s/%s.git", httplib.GuessCurrentAppURL(ctx), url.PathEscape(owner), url.PathEscape(repo))
654655
}
655656

656-
func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) string {
657+
// ComposeSSHCloneLink returns SSH clone URL based on the given owner and repository name.
658+
func ComposeSSHCloneLink(doer *user_model.User, ownerName, repoName string) string {
657659
sshUser := setting.SSH.User
658660
sshDomain := setting.SSH.Domain
659661

@@ -686,11 +688,17 @@ func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) strin
686688
return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
687689
}
688690

691+
// ComposeTeaCloneLink returns Tea CLI clone command based on the given owner and repository name.
692+
func ComposeTeaCloneLink(ctx context.Context, owner, repo string) string {
693+
return fmt.Sprintf("tea clone %s/%s", url.PathEscape(owner), url.PathEscape(repo))
694+
}
695+
689696
func (repo *Repository) cloneLink(ctx context.Context, doer *user_model.User, repoPathName string) *CloneLink {
690-
cl := new(CloneLink)
691-
cl.SSH = ComposeSSHCloneURL(doer, repo.OwnerName, repoPathName)
692-
cl.HTTPS = ComposeHTTPSCloneURL(ctx, repo.OwnerName, repoPathName)
693-
return cl
697+
return &CloneLink{
698+
SSH: ComposeSSHCloneLink(doer, repo.OwnerName, repoPathName),
699+
HTTPS: ComposeHTTPSCloneLink(ctx, repo.OwnerName, repoPathName),
700+
Tea: ComposeTeaCloneLink(ctx, repo.OwnerName, repoPathName),
701+
}
694702
}
695703

696704
// CloneLink returns clone URLs of repository.

models/repo/repo_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,30 +183,30 @@ func TestComposeSSHCloneURL(t *testing.T) {
183183
setting.SSH.Domain = "domain"
184184
setting.SSH.Port = 22
185185
setting.Repository.UseCompatSSHURI = false
186-
assert.Equal(t, "git@domain:user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
186+
assert.Equal(t, "git@domain:user/repo.git", ComposeSSHCloneLink(&user_model.User{Name: "doer"}, "user", "repo"))
187187
setting.Repository.UseCompatSSHURI = true
188-
assert.Equal(t, "ssh://git@domain/user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
188+
assert.Equal(t, "ssh://git@domain/user/repo.git", ComposeSSHCloneLink(&user_model.User{Name: "doer"}, "user", "repo"))
189189
// test SSH_DOMAIN while use non-standard SSH port
190190
setting.SSH.Port = 123
191191
setting.Repository.UseCompatSSHURI = false
192-
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
192+
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneLink(nil, "user", "repo"))
193193
setting.Repository.UseCompatSSHURI = true
194-
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
194+
assert.Equal(t, "ssh://git@domain:123/user/repo.git", ComposeSSHCloneLink(nil, "user", "repo"))
195195

196196
// test IPv6 SSH_DOMAIN
197197
setting.Repository.UseCompatSSHURI = false
198198
setting.SSH.Domain = "::1"
199199
setting.SSH.Port = 22
200-
assert.Equal(t, "git@[::1]:user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
200+
assert.Equal(t, "git@[::1]:user/repo.git", ComposeSSHCloneLink(nil, "user", "repo"))
201201
setting.SSH.Port = 123
202-
assert.Equal(t, "ssh://git@[::1]:123/user/repo.git", ComposeSSHCloneURL(nil, "user", "repo"))
202+
assert.Equal(t, "ssh://git@[::1]:123/user/repo.git", ComposeSSHCloneLink(nil, "user", "repo"))
203203

204204
setting.SSH.User = "(DOER_USERNAME)"
205205
setting.SSH.Domain = "domain"
206206
setting.SSH.Port = 22
207-
assert.Equal(t, "doer@domain:user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
207+
assert.Equal(t, "doer@domain:user/repo.git", ComposeSSHCloneLink(&user_model.User{Name: "doer"}, "user", "repo"))
208208
setting.SSH.Port = 123
209-
assert.Equal(t, "ssh://doer@domain:123/user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
209+
assert.Equal(t, "ssh://doer@domain:123/user/repo.git", ComposeSSHCloneLink(&user_model.User{Name: "doer"}, "user", "repo"))
210210
}
211211

212212
func TestIsUsableRepoName(t *testing.T) {

routers/web/goget.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ func goGet(ctx *context.Context) {
6969

7070
var cloneURL string
7171
if setting.Repository.GoGetCloneURLProtocol == "ssh" {
72-
cloneURL = repo_model.ComposeSSHCloneURL(ctx.Doer, ownerName, repoName)
72+
cloneURL = repo_model.ComposeSSHCloneLink(ctx.Doer, ownerName, repoName)
7373
} else {
74-
cloneURL = repo_model.ComposeHTTPSCloneURL(ctx, ownerName, repoName)
74+
cloneURL = repo_model.ComposeHTTPSCloneLink(ctx, ownerName, repoName)
7575
}
7676
goImportContent := fmt.Sprintf("%s git %s", goGetImport, cloneURL /*CloneLink*/)
7777
goSourceContent := fmt.Sprintf("%s _ %s %s", goGetImport, prefix+"{/dir}" /*GoDocDirectory*/, prefix+"{/dir}/{file}#L{line}" /*GoDocFile*/)

services/context/repo.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,9 @@ func EarlyResponseForGoGetMeta(ctx *Context) {
298298

299299
var cloneURL string
300300
if setting.Repository.GoGetCloneURLProtocol == "ssh" {
301-
cloneURL = repo_model.ComposeSSHCloneURL(ctx.Doer, username, reponame)
301+
cloneURL = repo_model.ComposeSSHCloneLink(ctx.Doer, username, reponame)
302302
} else {
303-
cloneURL = repo_model.ComposeHTTPSCloneURL(ctx, username, reponame)
303+
cloneURL = repo_model.ComposeHTTPSCloneLink(ctx, username, reponame)
304304
}
305305
goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(ctx, username, reponame), cloneURL)
306306
htmlMeta := fmt.Sprintf(`<meta name="go-import" content="%s">`, html.EscapeString(goImportContent))

templates/repo/clone_panel.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
{{if $.CloneButtonShowSSH}}
1515
<button class="item repo-clone-ssh" data-link="{{$.CloneButtonOriginLink.SSH}}">SSH</button>
1616
{{end}}
17+
<button class="item repo-clone-tea" data-link="{{$.CloneButtonOriginLink.Tea}}">Tea CLI</button>
1718
</div>
1819
<div class="divider"></div>
1920

tests/integration/repo_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,13 @@ func TestViewRepo1CloneLinkAnonymous(t *testing.T) {
130130
link, exists := htmlDoc.doc.Find(".repo-clone-https").Attr("data-link")
131131
assert.True(t, exists, "The template has changed")
132132
assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
133+
133134
_, exists = htmlDoc.doc.Find(".repo-clone-ssh").Attr("data-link")
134135
assert.False(t, exists)
136+
137+
link, exists = htmlDoc.doc.Find(".repo-clone-tea").Attr("data-link")
138+
assert.True(t, exists, "The template has changed")
139+
assert.Equal(t, "tea clone user2/repo1", link)
135140
}
136141

137142
func TestViewRepo1CloneLinkAuthorized(t *testing.T) {
@@ -146,10 +151,15 @@ func TestViewRepo1CloneLinkAuthorized(t *testing.T) {
146151
link, exists := htmlDoc.doc.Find(".repo-clone-https").Attr("data-link")
147152
assert.True(t, exists, "The template has changed")
148153
assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
154+
149155
link, exists = htmlDoc.doc.Find(".repo-clone-ssh").Attr("data-link")
150156
assert.True(t, exists, "The template has changed")
151157
sshURL := fmt.Sprintf("ssh://%s@%s:%d/user2/repo1.git", setting.SSH.User, setting.SSH.Domain, setting.SSH.Port)
152158
assert.Equal(t, sshURL, link)
159+
160+
link, exists = htmlDoc.doc.Find(".repo-clone-tea").Attr("data-link")
161+
assert.True(t, exists, "The template has changed")
162+
assert.Equal(t, "tea clone user2/repo1", link)
153163
}
154164

155165
func TestViewRepoWithSymlinks(t *testing.T) {

web_src/js/features/repo-common.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,34 @@ export function substituteRepoOpenWithUrl(tmpl: string, url: string): string {
5353
function initCloneSchemeUrlSelection(parent: Element) {
5454
const elCloneUrlInput = parent.querySelector<HTMLInputElement>('.repo-clone-url');
5555

56-
const tabSsh = parent.querySelector('.repo-clone-ssh');
57-
const tabHttps = parent.querySelector('.repo-clone-https');
56+
const tabHTTPS = parent.querySelector('.repo-clone-https');
57+
const tabSSH = parent.querySelector('.repo-clone-ssh');
58+
const tabTea = parent.querySelector('.repo-clone-tea');
5859
const updateClonePanelUi = function() {
5960
const scheme = localStorage.getItem('repo-clone-protocol') || 'https';
60-
const isSSH = scheme === 'ssh' && Boolean(tabSsh) || scheme !== 'ssh' && !tabHttps;
61-
if (tabHttps) {
62-
tabHttps.textContent = window.origin.split(':')[0].toUpperCase(); // show "HTTP" or "HTTPS"
63-
tabHttps.classList.toggle('active', !isSSH);
61+
const isHTTPS = scheme === 'https' && Boolean(tabHTTPS) || scheme !== 'https' && !tabHTTPS;
62+
const isSSH = scheme === 'ssh' && Boolean(tabSSH) || scheme !== 'ssh' && !tabSSH;
63+
const isTea = scheme === 'tea' && Boolean(tabTea) || scheme !== 'tea' && !tabTea;
64+
if (tabHTTPS) {
65+
tabHTTPS.textContent = window.origin.split(':')[0].toUpperCase(); // show "HTTP" or "HTTPS"
66+
tabHTTPS.classList.toggle('active', isHTTPS);
6467
}
65-
if (tabSsh) {
66-
tabSsh.classList.toggle('active', isSSH);
68+
if (tabSSH) {
69+
tabSSH.classList.toggle('active', isSSH);
70+
}
71+
if (tabTea) {
72+
tabTea.classList.toggle('active', isTea);
73+
}
74+
75+
let tab: Element;
76+
if (isHTTPS) {
77+
tab = tabHTTPS;
78+
} else if (isSSH) {
79+
tab = tabSSH;
80+
} else if (isTea) {
81+
tab = tabTea;
6782
}
6883

69-
const tab = isSSH ? tabSsh : tabHttps;
7084
if (!tab) return;
7185
const link = toOriginUrl(tab.getAttribute('data-link'));
7286

@@ -83,13 +97,17 @@ function initCloneSchemeUrlSelection(parent: Element) {
8397
};
8498

8599
updateClonePanelUi();
86-
// tabSsh or tabHttps might not both exist, eg: guest view, or one is disabled by the server
87-
tabSsh?.addEventListener('click', () => {
100+
// tabSSH or tabHttps might not both exist, eg: guest view, or one is disabled by the server
101+
tabHTTPS?.addEventListener('click', () => {
102+
localStorage.setItem('repo-clone-protocol', 'https');
103+
updateClonePanelUi();
104+
});
105+
tabSSH?.addEventListener('click', () => {
88106
localStorage.setItem('repo-clone-protocol', 'ssh');
89107
updateClonePanelUi();
90108
});
91-
tabHttps?.addEventListener('click', () => {
92-
localStorage.setItem('repo-clone-protocol', 'https');
109+
tabTea?.addEventListener('click', () => {
110+
localStorage.setItem('repo-clone-protocol', 'tea');
93111
updateClonePanelUi();
94112
});
95113
elCloneUrlInput.addEventListener('focus', () => {

0 commit comments

Comments
 (0)