Skip to content

Commit 602c741

Browse files
Merge branch 'main' into feature-jwt-asymmetric
2 parents a6c42be + 3d99131 commit 602c741

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+2731
-978
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@ Norwin Roosen <[email protected]> (@noerw)
4242
Kyle Dumont <[email protected]> (@kdumontnu)
4343
Patrick Schratz <[email protected]> (@pat-s)
4444
Janis Estelmann <[email protected]> (@KN4CK3R)
45+
Steven Kriegler <[email protected]> (@justusbunsi)

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
270270
- `SSH_AUTHORIZED_PRINCIPALS_ALLOW`: **off** or **username, email**: \[off, username, email, anything\]: Specify the principals values that users are allowed to use as principal. When set to `anything` no checks are done on the principal string. When set to `off` authorized principal are not allowed to be set.
271271
- `SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE`: **false/true**: Gitea will create a authorized_principals file by default when it is not using the internal ssh server and `SSH_AUTHORIZED_PRINCIPALS_ALLOW` is not `off`.
272272
- `SSH_AUTHORIZED_PRINCIPALS_BACKUP`: **false/true**: Enable SSH Authorized Principals Backup when rewriting all keys, default is true if `SSH_AUTHORIZED_PRINCIPALS_ALLOW` is not `off`.
273+
- `SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE`: **{{.AppPath}} --config={{.CustomConf}} serv key-{{.Key.ID}}**: Set the template for the command to passed on authorized keys. Possible keys are: AppPath, AppWorkPath, CustomConf, CustomPath, Key - where Key is a `models.PublicKey` and the others are strings which are shellquoted.
273274
- `SSH_SERVER_CIPHERS`: **aes128-ctr, aes192-ctr, aes256-ctr, [email protected], arcfour256, arcfour128**: For the built-in SSH server, choose the ciphers to support for SSH connections, for system SSH this setting has no effect.
274275
- `SSH_SERVER_KEY_EXCHANGES`: **diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, [email protected]**: For the built-in SSH server, choose the key exchange algorithms to support for SSH connections, for system SSH this setting has no effect.
275276
- `SSH_SERVER_MACS`: **[email protected], hmac-sha2-256, hmac-sha1, hmac-sha1-96**: For the built-in SSH server, choose the MACs to support for SSH connections, for system SSH this setting has no effect
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
date: "2021-05-13T00:00:00-00:00"
3+
title: "Repository Mirror"
4+
slug: "repo-mirror"
5+
weight: 45
6+
toc: false
7+
draft: false
8+
menu:
9+
sidebar:
10+
parent: "advanced"
11+
name: "Repository Mirror"
12+
weight: 45
13+
identifier: "repo-mirror"
14+
---
15+
16+
# Repository Mirror
17+
18+
Repository mirroring allows for the mirroring of repositories to and from external sources. You can use it to mirror branches, tags, and commits between repositories.
19+
20+
**Table of Contents**
21+
22+
{{< toc >}}
23+
24+
## Use cases
25+
26+
The following are some possible use cases for repository mirroring:
27+
28+
- You migrated to Gitea but still need to keep your project in another source. In that case, you can simply set it up to mirror to Gitea (pull) and all the essential history of commits, tags, and branches are available in your Gitea instance.
29+
- You have old projects in another source that you don’t use actively anymore, but don’t want to remove for archiving purposes. In that case, you can create a push mirror so that your active Gitea repository can push its changes to the old location.
30+
31+
## Pulling from a remote repository
32+
33+
For an existing remote repository, you can set up pull mirroring as follows:
34+
35+
1. Select **New Migration** in the **Create...** menu on the top right.
36+
2. Select the remote repository service.
37+
3. Enter a repository URL.
38+
4. If the repository needs authentication fill in your authentication information.
39+
5. Check the box **This repository will be a mirror**.
40+
5. Select **Migrate repository** to save the configuration.
41+
42+
The repository now gets mirrored periodically from the remote repository. You can force a sync by selecting **Synchronize Now** in the repository settings.
43+
44+
## Pushing to a remote repository
45+
46+
For an existing repository, you can set up push mirroring as follows:
47+
48+
1. In your repository, go to **Settings** > **Repository**, and then the **Mirror Settings** section.
49+
2. Enter a repository URL.
50+
3. If the repository needs authentication expand the **Authorization** section and fill in your authentication information.
51+
4. Select **Add Push Mirror** to save the configuration.
52+
53+
The repository now gets mirrored periodically to the remote repository. You can force a sync by selecting **Synchronize Now**. In case of an error a message displayed to help you resolve it.
54+
55+
:exclamation::exclamation: **NOTE:** This will force push to the remote repository. This will overwrite any changes in the remote repository! :exclamation::exclamation:
56+
57+
### Setting up a push mirror from Gitea to GitHub
58+
59+
To set up a mirror from Gitea to GitHub, you need to follow these steps:
60+
61+
1. Create a [GitHub personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with the *public_repo* box checked.
62+
2. Fill in the **Git Remote Repository URL**: `https://github.com/<your_github_group>/<your_github_project>.git`.
63+
3. Fill in the **Authorization** fields with your GitHub username and the personal access token.
64+
4. Select **Add Push Mirror** to save the configuration.
65+
66+
The repository pushes shortly thereafter. To force a push, select the **Synchronize Now** button.
67+
68+
### Setting up a push mirror from Gitea to GitLab
69+
70+
To set up a mirror from Gitea to GitLab, you need to follow these steps:
71+
72+
1. Create a [GitLab personal access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) with *write_repository* scope.
73+
2. Fill in the **Git Remote Repository URL**: `https://<destination host>/<your_gitlab_group_or_name>/<your_gitlab_project>.git`.
74+
3. Fill in the **Authorization** fields with `oauth2` as **Username** and your GitLab personal access token as **Password**.
75+
4. Select **Add Push Mirror** to save the configuration.
76+
77+
The repository pushes shortly thereafter. To force a push, select the **Synchronize Now** button.
78+
79+
### Setting up a push mirror from Gitea to Bitbucket
80+
81+
To set up a mirror from Gitea to Bitbucket, you need to follow these steps:
82+
83+
1. Create a [Bitbucket app password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/) with the *Repository Write* box checked.
84+
2. Fill in the **Git Remote Repository URL**: `https://bitbucket.org/<your_bitbucket_group_or_name>/<your_bitbucket_project>.git`.
85+
3. Fill in the **Authorization** fields with your Bitbucket username and the app password as **Password**.
86+
4. Select **Add Push Mirror** to save the configuration.
87+
88+
The repository pushes shortly thereafter. To force a push, select the **Synchronize Now** button.

services/mirror/mirror_test.go renamed to integrations/mirror_pull_test.go

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,24 @@
22
// Use of this source code is governed by a MIT-style
33
// license that can be found in the LICENSE file.
44

5-
package mirror
5+
package integrations
66

77
import (
88
"context"
9-
"path/filepath"
109
"testing"
1110

1211
"code.gitea.io/gitea/models"
1312
"code.gitea.io/gitea/modules/git"
1413
migration "code.gitea.io/gitea/modules/migrations/base"
1514
"code.gitea.io/gitea/modules/repository"
15+
mirror_service "code.gitea.io/gitea/services/mirror"
1616
release_service "code.gitea.io/gitea/services/release"
1717

1818
"github.com/stretchr/testify/assert"
1919
)
2020

21-
func TestMain(m *testing.M) {
22-
models.MainTest(m, filepath.Join("..", ".."))
23-
}
24-
25-
func TestRelease_MirrorDelete(t *testing.T) {
26-
assert.NoError(t, models.PrepareTestDatabase())
21+
func TestMirrorPull(t *testing.T) {
22+
defer prepareTestEnv(t)()
2723

2824
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
2925
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
@@ -76,7 +72,7 @@ func TestRelease_MirrorDelete(t *testing.T) {
7672
err = mirror.GetMirror()
7773
assert.NoError(t, err)
7874

79-
_, ok := runSync(ctx, mirror.Mirror)
75+
ok := mirror_service.SyncPullMirror(ctx, mirror.ID)
8076
assert.True(t, ok)
8177

8278
count, err := models.GetReleaseCountByRepoID(mirror.ID, findOptions)
@@ -87,7 +83,7 @@ func TestRelease_MirrorDelete(t *testing.T) {
8783
assert.NoError(t, err)
8884
assert.NoError(t, release_service.DeleteReleaseByID(release.ID, user, true))
8985

90-
_, ok = runSync(ctx, mirror.Mirror)
86+
ok = mirror_service.SyncPullMirror(ctx, mirror.ID)
9187
assert.True(t, ok)
9288

9389
count, err = models.GetReleaseCountByRepoID(mirror.ID, findOptions)

integrations/mirror_push_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright 2021 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+
5+
package integrations
6+
7+
import (
8+
"context"
9+
"fmt"
10+
"net/http"
11+
"net/url"
12+
"testing"
13+
14+
"code.gitea.io/gitea/models"
15+
"code.gitea.io/gitea/modules/git"
16+
"code.gitea.io/gitea/modules/repository"
17+
"code.gitea.io/gitea/modules/setting"
18+
mirror_service "code.gitea.io/gitea/services/mirror"
19+
20+
"github.com/stretchr/testify/assert"
21+
)
22+
23+
func TestMirrorPush(t *testing.T) {
24+
onGiteaRun(t, testMirrorPush)
25+
}
26+
27+
func testMirrorPush(t *testing.T, u *url.URL) {
28+
defer prepareTestEnv(t)()
29+
30+
setting.Migrations.AllowLocalNetworks = true
31+
32+
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
33+
srcRepo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
34+
35+
mirrorRepo, err := repository.CreateRepository(user, user, models.CreateRepoOptions{
36+
Name: "test-push-mirror",
37+
})
38+
assert.NoError(t, err)
39+
40+
ctx := NewAPITestContext(t, user.LowerName, srcRepo.Name)
41+
42+
doCreatePushMirror(ctx, fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(ctx.Username), url.PathEscape(mirrorRepo.Name)), user.LowerName, userPassword)(t)
43+
44+
mirrors, err := models.GetPushMirrorsByRepoID(srcRepo.ID)
45+
assert.NoError(t, err)
46+
assert.Len(t, mirrors, 1)
47+
48+
ok := mirror_service.SyncPushMirror(context.Background(), mirrors[0].ID)
49+
assert.True(t, ok)
50+
51+
srcGitRepo, err := git.OpenRepository(srcRepo.RepoPath())
52+
assert.NoError(t, err)
53+
defer srcGitRepo.Close()
54+
55+
srcCommit, err := srcGitRepo.GetBranchCommit("master")
56+
assert.NoError(t, err)
57+
58+
mirrorGitRepo, err := git.OpenRepository(mirrorRepo.RepoPath())
59+
assert.NoError(t, err)
60+
defer mirrorGitRepo.Close()
61+
62+
mirrorCommit, err := mirrorGitRepo.GetBranchCommit("master")
63+
assert.NoError(t, err)
64+
65+
assert.Equal(t, srcCommit.ID, mirrorCommit.ID)
66+
}
67+
68+
func doCreatePushMirror(ctx APITestContext, address, username, password string) func(t *testing.T) {
69+
return func(t *testing.T) {
70+
csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/settings", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame)))
71+
72+
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame)), map[string]string{
73+
"_csrf": csrf,
74+
"action": "push-mirror-add",
75+
"push_mirror_address": address,
76+
"push_mirror_username": username,
77+
"push_mirror_password": password,
78+
"push_mirror_interval": "0",
79+
})
80+
ctx.Session.MakeRequest(t, req, http.StatusFound)
81+
82+
flashCookie := ctx.Session.GetCookie("macaron_flash")
83+
assert.NotNil(t, flashCookie)
84+
assert.Contains(t, flashCookie.Value, "success")
85+
}
86+
}

models/issue.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,9 +1127,18 @@ func sortIssuesSession(sess *xorm.Session, sortType string, priorityRepoID int64
11271127
sess.Desc("issue.priority")
11281128
case "nearduedate":
11291129
// 253370764800 is 01/01/9999 @ 12:00am (UTC)
1130-
sess.OrderBy("CASE WHEN issue.deadline_unix = 0 THEN 253370764800 ELSE issue.deadline_unix END ASC")
1130+
sess.Join("LEFT", "milestone", "issue.milestone_id = milestone.id").
1131+
OrderBy("CASE " +
1132+
"WHEN issue.deadline_unix = 0 AND (milestone.deadline_unix = 0 OR milestone.deadline_unix IS NULL) THEN 253370764800 " +
1133+
"WHEN milestone.deadline_unix = 0 OR milestone.deadline_unix IS NULL THEN issue.deadline_unix " +
1134+
"WHEN milestone.deadline_unix < issue.deadline_unix OR issue.deadline_unix = 0 THEN milestone.deadline_unix " +
1135+
"ELSE issue.deadline_unix END ASC")
11311136
case "farduedate":
1132-
sess.Desc("issue.deadline_unix")
1137+
sess.Join("LEFT", "milestone", "issue.milestone_id = milestone.id").
1138+
OrderBy("CASE " +
1139+
"WHEN milestone.deadline_unix IS NULL THEN issue.deadline_unix " +
1140+
"WHEN milestone.deadline_unix < issue.deadline_unix OR issue.deadline_unix = 0 THEN milestone.deadline_unix " +
1141+
"ELSE issue.deadline_unix END DESC")
11331142
case "priorityrepo":
11341143
sess.OrderBy("CASE WHEN issue.repo_id = " + strconv.FormatInt(priorityRepoID, 10) + " THEN 1 ELSE 2 END, issue.created_unix DESC")
11351144
default:

models/issue_comment.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,8 @@ func updateCommentInfos(e *xorm.Session, opts *CreateCommentOptions, comment *Co
762762
}
763763
}
764764
fallthrough
765+
case CommentTypeReview:
766+
fallthrough
765767
case CommentTypeComment:
766768
if _, err = e.Exec("UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil {
767769
return err

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,8 @@ var migrations = []Migration{
315315
NewMigration("Always save primary email on email address table", addPrimaryEmail2EmailAddress),
316316
// v182 -> v183
317317
NewMigration("Add issue resource index table", addIssueResourceIndexTable),
318+
// v183 -> v184
319+
NewMigration("Create PushMirror table", createPushMirrorTable),
318320
}
319321

320322
// GetCurrentDBVersion returns the current db version

models/migrations/v180.go

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
package migrations
66

77
import (
8-
"code.gitea.io/gitea/models"
9-
"code.gitea.io/gitea/modules/migrations/base"
10-
"code.gitea.io/gitea/modules/structs"
118
"code.gitea.io/gitea/modules/util"
129

1310
jsoniter "github.com/json-iterator/go"
@@ -16,20 +13,38 @@ import (
1613
)
1714

1815
func deleteMigrationCredentials(x *xorm.Engine) (err error) {
16+
// Task represents a task
17+
type Task struct {
18+
ID int64
19+
DoerID int64 `xorm:"index"` // operator
20+
OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero
21+
RepoID int64 `xorm:"index"`
22+
Type int
23+
Status int `xorm:"index"`
24+
StartTime int64
25+
EndTime int64
26+
PayloadContent string `xorm:"TEXT"`
27+
Errors string `xorm:"TEXT"` // if task failed, saved the error reason
28+
Created int64 `xorm:"created"`
29+
}
30+
31+
const TaskTypeMigrateRepo = 0
32+
const TaskStatusStopped = 2
33+
1934
const batchSize = 100
2035

2136
// only match migration tasks, that are not pending or running
2237
cond := builder.Eq{
23-
"type": structs.TaskTypeMigrateRepo,
38+
"type": TaskTypeMigrateRepo,
2439
}.And(builder.Gte{
25-
"status": structs.TaskStatusStopped,
40+
"status": TaskStatusStopped,
2641
})
2742

2843
sess := x.NewSession()
2944
defer sess.Close()
3045

3146
for start := 0; ; start += batchSize {
32-
tasks := make([]*models.Task, 0, batchSize)
47+
tasks := make([]*Task, 0, batchSize)
3348
if err = sess.Limit(batchSize, start).Where(cond, 0).Find(&tasks); err != nil {
3449
return
3550
}
@@ -55,7 +70,41 @@ func deleteMigrationCredentials(x *xorm.Engine) (err error) {
5570
}
5671

5772
func removeCredentials(payload string) (string, error) {
58-
var opts base.MigrateOptions
73+
// MigrateOptions defines the way a repository gets migrated
74+
// this is for internal usage by migrations module and func who interact with it
75+
type MigrateOptions struct {
76+
// required: true
77+
CloneAddr string `json:"clone_addr" binding:"Required"`
78+
CloneAddrEncrypted string `json:"clone_addr_encrypted,omitempty"`
79+
AuthUsername string `json:"auth_username"`
80+
AuthPassword string `json:"-"`
81+
AuthPasswordEncrypted string `json:"auth_password_encrypted,omitempty"`
82+
AuthToken string `json:"-"`
83+
AuthTokenEncrypted string `json:"auth_token_encrypted,omitempty"`
84+
// required: true
85+
UID int `json:"uid" binding:"Required"`
86+
// required: true
87+
RepoName string `json:"repo_name" binding:"Required"`
88+
Mirror bool `json:"mirror"`
89+
LFS bool `json:"lfs"`
90+
LFSEndpoint string `json:"lfs_endpoint"`
91+
Private bool `json:"private"`
92+
Description string `json:"description"`
93+
OriginalURL string
94+
GitServiceType int
95+
Uncyclo bool
96+
Issues bool
97+
Milestones bool
98+
Labels bool
99+
Releases bool
100+
Comments bool
101+
PullRequests bool
102+
ReleaseAssets bool
103+
MigrateToRepoID int64
104+
MirrorInterval string `json:"mirror_interval"`
105+
}
106+
107+
var opts MigrateOptions
59108
json := jsoniter.ConfigCompatibleWithStandardLibrary
60109
err := json.Unmarshal([]byte(payload), &opts)
61110
if err != nil {
@@ -64,7 +113,7 @@ func removeCredentials(payload string) (string, error) {
64113

65114
opts.AuthPassword = ""
66115
opts.AuthToken = ""
67-
opts.CloneAddr = util.SanitizeURLCredentials(opts.CloneAddr, true)
116+
opts.CloneAddr = util.NewStringURLSanitizer(opts.CloneAddr, true).Replace(opts.CloneAddr)
68117

69118
confBytes, err := json.Marshal(opts)
70119
if err != nil {

0 commit comments

Comments
 (0)