Compare commits

...

112 Commits

Author SHA1 Message Date
yp05327
2ed18ee8d1
Merge 4ed9e41766 into 821d2fc2a3 2024-05-18 01:18:50 +09:00
wxiaoguang
821d2fc2a3
Simplify mirror repository API logic (#30963)
Fix #30921
2024-05-17 16:07:41 +00:00
yp05327
4ed9e41766 fix test 2024-05-15 23:52:16 +00:00
yp05327
c6edde19ff when doer is nil, return empty branch 2024-05-15 00:37:31 +00:00
yp05327
9fb523c689 fix access 2024-05-14 07:07:24 +00:00
yp05327
71556edade fix test 2024-05-14 06:30:05 +00:00
yp05327
d99cf1abde revert permission change 2024-05-14 06:27:55 +00:00
yp05327
41a2bb2530 fix tests 2024-05-14 04:38:56 +00:00
yp05327
1f7b93cc79 fix lint 2024-05-14 04:13:18 +00:00
yp05327
73233221ff create pr should have write permission 2024-05-14 04:05:42 +00:00
yp05327
1263116ed2 improve test 2024-05-14 02:59:20 +00:00
yp05327
b1a5d9e97d fix tests 2024-05-14 02:11:42 +00:00
yp05327
b65bad01d1 remove unused fixture 2024-05-14 02:04:21 +00:00
yp05327
3a96038f71 pre auto generate test data 2024-05-14 00:50:24 +00:00
yp05327
3798d95b9d
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2024-05-09 17:30:51 +09:00
yp05327
fb7abfe792 fix misspelling 2024-05-08 08:59:00 +00:00
yp05327
0596a132e2
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2024-05-08 17:57:39 +09:00
Lunny Xiao
67ce9ca110
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2024-05-07 17:10:10 +08:00
yp05327
db0bfbb3ea
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2024-04-25 19:14:10 +09:00
yp05327
f1784504da
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2024-04-22 15:38:40 +09:00
yp05327
43495eb81a improve 2024-04-18 12:07:13 +00:00
yp05327
7031377e1e fix 2024-04-18 11:02:35 +00:00
yp05327
c397f08812 improve 2024-04-12 05:58:32 +00:00
yp05327
ed19b8bdd7 use container.FilterSlice 2024-04-12 05:54:45 +00:00
yp05327
58147c14f7
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2024-04-12 14:52:53 +09:00
yp05327
a8a5de2cdf fix test 2024-04-09 02:49:26 +00:00
yp05327
263a4438e4 fix test 2024-04-09 02:04:38 +00:00
yp05327
eed8b07efd fix 2024-04-09 01:57:46 +00:00
yp05327
c4386f0532 fix 2024-04-09 01:45:47 +00:00
yp05327
7b06c463e6 fix 2024-04-09 01:44:02 +00:00
yp05327
17ad1f6835
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2024-04-09 10:39:09 +09:00
yp05327
5af46f7ce9 fix 2024-04-09 00:59:02 +00:00
yp05327
66f96761e8 fix conflict 2024-04-09 00:55:32 +00:00
yp05327
01088a9f41
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2024-02-22 11:29:04 +09:00
yp05327
ba4406ff2c use db.Find instead of FindBranch 2024-01-24 08:43:53 +00:00
yp05327
58dbb670b0
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2024-01-24 17:36:31 +09:00
yp05327
2e860edbd4 fix fixture 2024-01-24 08:35:53 +00:00
yp05327
6f5f65ee79
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-12-07 11:08:24 +09:00
yp05327
4bd9cdba22
Update models/git/branch.go
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2023-11-20 08:35:29 +09:00
yp05327
b3d6bed21d fix lint 2023-11-17 01:36:20 +00:00
yp05327
3922011044 fix lint 2023-11-17 01:26:07 +00:00
yp05327
e44cec43f6 fix indexer test 2023-11-17 01:20:31 +00:00
yp05327
3d98673fd6 fix api user orgs test 2023-11-17 01:03:30 +00:00
yp05327
bff0db2601
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-11-16 16:47:21 +09:00
yp05327
2d53287c89
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-11-10 13:08:24 +09:00
yp05327
2b677fc2ae
Update models/git/branch.go
Co-authored-by: silverwind <me@silverwind.io>
2023-11-10 11:40:53 +09:00
yp05327
2549c33632
Update models/git/branch.go
Co-authored-by: silverwind <me@silverwind.io>
2023-11-10 11:40:44 +09:00
yp05327
a2425ce6ac
Update models/git/branch.go
Co-authored-by: silverwind <me@silverwind.io>
2023-11-10 11:40:36 +09:00
yp05327
7fa0362d36 remove ignore no repo error 2023-09-06 07:22:48 +00:00
yp05327
34734c2265 fix comment 2023-08-28 07:49:42 +00:00
yp05327
e79c8e0b58 fix ci 2023-08-28 07:49:32 +00:00
yp05327
8f3d5c9bc3 fix 2023-08-28 05:23:28 +00:00
yp05327
330c3f8f5d rewrite test 2023-08-28 04:48:12 +00:00
yp05327
38f4b6680b remove test repo meta data 2023-08-28 01:26:18 +00:00
yp05327
60fd886265
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-08-28 10:22:05 +09:00
yp05327
44c80aed15 remove unnecessary file 2023-08-22 23:50:50 +00:00
yp05327
bb53d5756d
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-08-21 13:35:58 +09:00
yp05327
6248701203 add permission check 2023-08-15 01:11:39 +00:00
yp05327
2e93f87122 follow 26257 2023-08-15 00:50:58 +00:00
yp05327
a641d84bb1
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-08-15 09:48:53 +09:00
yp05327
5bfa11ba03 follow 26257 2023-08-15 00:43:35 +00:00
yp05327
aa2b8c4855 fix conflicts 2023-08-15 00:16:42 +00:00
yp05327
d7cb37c8ba improve 2023-08-01 01:28:15 +00:00
yp05327
08b0159874 fix test 2023-07-31 23:47:25 +00:00
yp05327
8e96323ef0 fix test 2023-07-31 08:59:43 +00:00
yp05327
7559311bae
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-07-31 11:02:43 +09:00
yp05327
4df1529e2e fix conflicts 2023-07-31 01:58:30 +00:00
yp05327
dcc91fbb70 fix 2023-07-27 06:14:59 +00:00
yp05327
9a9dd060b0 improve test 2023-07-27 06:12:54 +00:00
yp05327
fb3afac3e5 fix TestSearchIssues 2023-07-27 02:56:28 +00:00
yp05327
64ece1cbe5 fix TestTeam_AddRepository 2023-07-27 02:19:12 +00:00
yp05327
5cf3d9e505 fix TestIssue_DeleteIssue 2023-07-27 02:14:50 +00:00
yp05327
3b6ff9ba0a improve test 2023-07-27 01:49:52 +00:00
yp05327
a583c64fd0 fix test 2023-07-26 23:55:46 +00:00
yp05327
b57883c31c improve 2023-07-26 08:44:47 +00:00
yp05327
76f472dba8 move ListOptions 2023-07-26 08:40:20 +00:00
yp05327
d60c75883b
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-07-26 17:32:35 +09:00
yp05327
66071ac97b remove test code 2023-07-26 08:31:38 +00:00
yp05327
86892d458d fix tests 2023-07-25 02:05:43 +00:00
yp05327
f9b4085b57 fix test 2023-07-24 08:22:39 +00:00
yp05327
274e5abdac fix test 2023-07-24 08:17:54 +00:00
yp05327
94025efd44 improve 2023-07-24 08:09:29 +00:00
yp05327
4de1b0514c revert RepoIDs 2023-07-24 02:40:50 +00:00
yp05327
9a33437cd6 improve 2023-07-24 02:34:06 +00:00
yp05327
6517ad975f fix 2023-07-24 00:20:01 +00:00
yp05327
17876b4e89
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-07-24 09:17:19 +09:00
yp05327
e263227a88 fix TestFixtureGeneration 2023-07-21 08:29:22 +00:00
yp05327
4d42a63805 fix TestFindOrgs 2023-07-21 08:20:20 +00:00
yp05327
63562c31b8 fix TestSearchRepository 2023-07-21 08:04:38 +00:00
yp05327
5449bc139a fix TestSearchUsers 2023-07-21 08:01:15 +00:00
yp05327
d848876744 fix repo size 2023-07-21 07:56:14 +00:00
yp05327
f06e09151d fix test 2023-07-21 06:45:23 +00:00
yp05327
1ecb6fbc3e fix org_user 2023-07-21 05:34:56 +00:00
yp05327
f7295177bd use searchrepo 2023-07-21 02:48:42 +00:00
yp05327
0bfec1a3e8 add test 2023-07-21 01:19:13 +00:00
yp05327
69b76246b0 fix bug 2023-07-21 00:08:45 +00:00
yp05327
a7fc27917c
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-07-21 08:51:55 +09:00
yp05327
c704332d23 fix 2023-07-20 08:56:50 +00:00
yp05327
5c3f7aa231 add test 1 2023-07-20 08:53:31 +00:00
yp05327
d93b2bcc80 use findbranch to search branch 2023-07-20 05:19:56 +00:00
yp05327
e74709ed15
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-07-20 13:16:53 +09:00
yp05327
d3f72aac2f remove PathEscapeSegments 2023-07-13 07:52:58 +00:00
yp05327
bc176bb1bc improve 2023-07-13 06:20:33 +00:00
yp05327
172ceebf14 fix lint 2023-07-11 05:04:24 +00:00
yp05327
54f4fd56cd improve TODO 2023-07-11 05:02:20 +00:00
yp05327
4c116821fa allow forked repo from forked repo 2023-07-11 04:25:41 +00:00
yp05327
2b0abf9331 use branch.id instead of branch.name 2023-07-11 04:18:36 +00:00
yp05327
71dd740416 avoid attach already created pr branch 2023-07-11 02:35:36 +00:00
yp05327
266d07fdd9
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check 2023-07-11 10:47:59 +09:00
yp05327
df97530659 support show notification in forked repo 2023-07-11 01:39:58 +00:00
yp05327
b3e3b7311c support show notification in origin repo 2023-07-11 01:10:12 +00:00
yp05327
c8f707b890 fix 2023-07-10 08:30:09 +00:00
30 changed files with 567 additions and 105 deletions

View File

@ -54,120 +54,126 @@
-
id: 10
user_id: 15
repo_id: 21
user_id: 13
repo_id: 10
mode: 2
-
id: 11
user_id: 15
repo_id: 22
repo_id: 21
mode: 2
-
id: 12
user_id: 15
repo_id: 23
mode: 4
repo_id: 22
mode: 2
-
id: 13
user_id: 15
repo_id: 24
repo_id: 23
mode: 4
-
id: 14
user_id: 15
repo_id: 32
mode: 2
repo_id: 24
mode: 4
-
id: 15
user_id: 18
repo_id: 21
user_id: 15
repo_id: 32
mode: 2
-
id: 16
user_id: 18
repo_id: 22
repo_id: 21
mode: 2
-
id: 17
user_id: 18
repo_id: 22
mode: 2
-
id: 18
user_id: 18
repo_id: 23
mode: 4
-
id: 18
id: 19
user_id: 18
repo_id: 24
mode: 4
-
id: 19
id: 20
user_id: 20
repo_id: 24
mode: 1
-
id: 20
id: 21
user_id: 20
repo_id: 27
mode: 4
-
id: 21
id: 22
user_id: 20
repo_id: 28
mode: 4
-
id: 22
id: 23
user_id: 29
repo_id: 4
mode: 2
-
id: 23
id: 24
user_id: 29
repo_id: 24
mode: 1
-
id: 24
id: 25
user_id: 31
repo_id: 27
mode: 4
-
id: 25
id: 26
user_id: 31
repo_id: 28
mode: 4
-
id: 26
id: 27
user_id: 38
repo_id: 60
mode: 2
-
id: 27
id: 28
user_id: 38
repo_id: 61
mode: 1
-
id: 28
id: 29
user_id: 39
repo_id: 61
mode: 1
-
id: 29
id: 30
user_id: 40
repo_id: 61
mode: 4

View File

@ -45,3 +45,39 @@
is_deleted: false
deleted_by_id: 0
deleted_unix: 0
-
id: 5
repo_id: 10
name: 'master'
commit_id: '65f1bf27bc3bf70f64657658635e66094edbcb4d'
commit_message: 'Initial commit'
commit_time: 1489927679
pusher_id: 12
is_deleted: false
deleted_by_id: 0
deleted_unix: 0
-
id: 6
repo_id: 10
name: 'outdated-new-branch'
commit_id: 'cb24c347e328d83c1e0c3c908a6b2c0a2fcb8a3d'
commit_message: 'add'
commit_time: 1489927679
pusher_id: 12
is_deleted: false
deleted_by_id: 0
deleted_unix: 0
-
id: 14
repo_id: 11
name: 'master'
commit_id: '65f1bf27bc3bf70f64657658635e66094edbcb4d'
commit_message: 'Initial commit'
commit_time: 1489927679
pusher_id: 13
is_deleted: false
deleted_by_id: 0
deleted_unix: 0

View File

@ -63,3 +63,9 @@
repo_id: 32
user_id: 10
mode: 2 # write
-
id: 12
repo_id: 10
user_id: 13
mode: 2 # write

View File

@ -1,27 +1,35 @@
-
group_id: 1
max_index: 5
-
group_id: 2
max_index: 2
-
group_id: 3
max_index: 2
-
group_id: 10
max_index: 1
-
group_id: 32
max_index: 2
-
group_id: 48
max_index: 1
-
group_id: 42
max_index: 1
-
group_id: 50
max_index: 1
-
group_id: 51
max_index: 1

View File

@ -117,3 +117,15 @@
uid: 40
org_id: 41
is_public: true
-
id: 21
uid: 12
org_id: 25
is_public: true
-
id: 22
uid: 2
org_id: 35
is_public: true

View File

@ -327,7 +327,7 @@
is_archived: false
is_mirror: false
status: 0
is_fork: false
is_fork: true
fork_id: 10
is_template: false
template_id: 0

View File

@ -239,3 +239,25 @@
num_members: 2
includes_all_repositories: false
can_create_org_repo: false
-
id: 23
org_id: 25
lower_name: owners
name: Owners
authorize: 4 # owner
num_repos: 0
num_members: 1
includes_all_repositories: false
can_create_org_repo: true
-
id: 24
org_id: 35
lower_name: team24
name: team24
authorize: 2 # write
num_repos: 0
num_members: 1
includes_all_repositories: true
can_create_org_repo: false

View File

@ -322,3 +322,21 @@
team_id: 22
type: 3
access_mode: 1
-
id: 55
team_id: 18
type: 1 # code
access_mode: 4
-
id: 56
team_id: 23
type: 1 # code
access_mode: 4
-
id: 57
team_id: 24
type: 1 # code
access_mode: 2

View File

@ -147,3 +147,15 @@
org_id: 41
team_id: 22
uid: 39
-
id: 26
org_id: 25
team_id: 23
uid: 12
-
id: 27
org_id: 35
team_id: 24
uid: 2

View File

@ -918,8 +918,8 @@
num_following: 0
num_stars: 0
num_repos: 0
num_teams: 1
num_members: 1
num_teams: 2
num_members: 2
visibility: 0
repo_admin_change_team_access: false
theme: ""
@ -1289,8 +1289,8 @@
num_following: 0
num_stars: 0
num_repos: 0
num_teams: 1
num_members: 1
num_teams: 2
num_members: 2
visibility: 2
repo_admin_change_team_access: false
theme: ""

View File

@ -10,9 +10,11 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@ -102,8 +104,9 @@ func (err ErrBranchesEqual) Unwrap() error {
// for pagination, keyword search and filtering
type Branch struct {
ID int64
RepoID int64 `xorm:"UNIQUE(s)"`
Name string `xorm:"UNIQUE(s) NOT NULL"` // git's ref-name is case-sensitive internally, however, in some databases (mssql, mysql, by default), it's case-insensitive at the moment
RepoID int64 `xorm:"UNIQUE(s)"`
Repo *repo_model.Repository `xorm:"-"`
Name string `xorm:"UNIQUE(s) NOT NULL"` // git's ref-name is case-sensitive internally, however, in some databases (mssql, mysql, by default), it's case-insensitive at the moment
CommitID string
CommitMessage string `xorm:"TEXT"` // it only stores the message summary (the first line)
PusherID int64
@ -139,6 +142,14 @@ func (b *Branch) LoadPusher(ctx context.Context) (err error) {
return err
}
func (b *Branch) LoadRepo(ctx context.Context) (err error) {
if b.Repo != nil || b.RepoID == 0 {
return nil
}
b.Repo, err = repo_model.GetRepositoryByID(ctx, b.RepoID)
return err
}
func init() {
db.RegisterModel(new(Branch))
db.RegisterModel(new(RenamedBranch))
@ -400,24 +411,107 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
return committer.Commit()
}
// FindRecentlyPushedNewBranches return at most 2 new branches pushed by the user in 6 hours which has no opened PRs created
// except the indicate branch
func FindRecentlyPushedNewBranches(ctx context.Context, repoID, userID int64, excludeBranchName string) (BranchList, error) {
branches := make(BranchList, 0, 2)
subQuery := builder.Select("head_branch").From("pull_request").
InnerJoin("issue", "issue.id = pull_request.issue_id").
Where(builder.Eq{
"pull_request.head_repo_id": repoID,
"issue.is_closed": false,
})
err := db.GetEngine(ctx).
Where("pusher_id=? AND is_deleted=?", userID, false).
And("name <> ?", excludeBranchName).
And("repo_id = ?", repoID).
And("commit_time >= ?", time.Now().Add(-time.Hour*6).Unix()).
NotIn("name", subQuery).
OrderBy("branch.commit_time DESC").
Limit(2).
Find(&branches)
return branches, err
type FindRecentlyPushedNewBranchesOptions struct {
Repo *repo_model.Repository
BaseRepo *repo_model.Repository
CommitAfterUnix int64
MaxCount int
}
type RecentlyPushedNewBranch struct {
BranchDisplayName string
BranchLink string
BranchCompareURL string
CommitTime timeutil.TimeStamp
}
// FindRecentlyPushedNewBranches return at most 2 new branches pushed by the user in 2 hours which has no opened PRs created
// if opts.CommitAfterUnix is 0, we will find the branches that were committed to in the last 2 hours
// if opts.ListOptions is not set, we will only display top 2 latest branch
func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, opts *FindRecentlyPushedNewBranchesOptions) ([]*RecentlyPushedNewBranch, error) {
if doer == nil {
return []*RecentlyPushedNewBranch{}, nil
}
// find all related repo ids
repoOpts := repo_model.SearchRepoOptions{
Actor: doer,
Private: true,
AllPublic: false, // Include also all public repositories of users and public organisations
AllLimited: false, // Include also all public repositories of limited organisations
Fork: optional.Some(true),
ForkFrom: opts.BaseRepo.ID,
Archived: optional.Some(false),
}
repoCond := repo_model.SearchRepositoryCondition(&repoOpts).And(repo_model.AccessibleRepositoryCondition(doer, unit.TypeCode))
if opts.Repo.ID == opts.BaseRepo.ID {
// should also include the base repo's branches
repoCond = repoCond.Or(builder.Eq{"id": opts.BaseRepo.ID})
} else {
// in fork repo, we only detect the fork repo's branch
repoCond = repoCond.And(builder.Eq{"id": opts.Repo.ID})
}
repoIDs := builder.Select("id").From("repository").Where(repoCond)
if opts.CommitAfterUnix == 0 {
opts.CommitAfterUnix = time.Now().Add(-time.Hour * 2).Unix()
}
baseBranch, err := GetBranch(ctx, opts.BaseRepo.ID, opts.BaseRepo.DefaultBranch)
if err != nil {
return nil, err
}
// find all related branches, these branches may already created PRs, we will check later
branches, err := db.Find[Branch](ctx, FindBranchOptions{
RepoCond: builder.In("branch.repo_id", repoIDs),
CommitCond: builder.Neq{"branch.commit_id": baseBranch.CommitID}, // newly created branch have no changes, so skip them,
PusherID: doer.ID,
IsDeletedBranch: optional.Some(false),
CommitAfterUnix: opts.CommitAfterUnix,
OrderBy: "branch.updated_unix DESC",
ListOptions: db.ListOptionsAll,
})
if err != nil {
return nil, err
}
newBranches := make([]*RecentlyPushedNewBranch, 0, len(branches))
if opts.MaxCount == 0 {
// by default we display 2 recently pushed new branch
opts.MaxCount = 2
}
for _, branch := range branches {
// whether branch have already created PR
count, err := db.GetEngine(ctx).Table("pull_request").
// we should not only use branch name here, because if there are branches with same name in other repos,
// we can not detect them correctly
Where(builder.Eq{"head_repo_id": branch.RepoID, "head_branch": branch.Name}).Count()
if err != nil {
return nil, err
}
// if no PR, we add to the result
if count == 0 {
if err := branch.LoadRepo(ctx); err != nil {
return nil, err
}
branchDisplayName := branch.Name
if branch.Repo.ID != opts.BaseRepo.ID && branch.Repo.ID != opts.Repo.ID {
branchDisplayName = fmt.Sprintf("%s:%s", branch.Repo.FullName(), branchDisplayName)
}
newBranches = append(newBranches, &RecentlyPushedNewBranch{
BranchDisplayName: branchDisplayName,
BranchLink: fmt.Sprintf("%s/src/branch/%s", branch.Repo.Link(), util.PathEscapeSegments(branch.Name)),
BranchCompareURL: branch.Repo.ComposeBranchCompareURL(opts.BaseRepo, branch.Name),
CommitTime: branch.CommitTime,
})
}
if len(newBranches) == opts.MaxCount {
break
}
}
return newBranches, nil
}

View File

@ -7,6 +7,7 @@ import (
"context"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/optional"
@ -59,30 +60,74 @@ func (branches BranchList) LoadPusher(ctx context.Context) error {
return nil
}
func (branches BranchList) LoadRepo(ctx context.Context) error {
ids := container.FilterSlice(branches, func(branch *Branch) (int64, bool) {
return branch.RepoID, branch.RepoID > 0 && branch.Repo == nil
})
reposMap := make(map[int64]*repo_model.Repository, len(ids))
if err := db.GetEngine(ctx).In("id", ids).Find(&reposMap); err != nil {
return err
}
for _, branch := range branches {
if branch.RepoID <= 0 || branch.Repo != nil {
continue
}
branch.Repo = reposMap[branch.RepoID]
}
return nil
}
type FindBranchOptions struct {
db.ListOptions
RepoID int64
RepoCond builder.Cond
ExcludeBranchNames []string
CommitCond builder.Cond
PusherID int64
IsDeletedBranch optional.Option[bool]
CommitAfterUnix int64
CommitBeforeUnix int64
OrderBy string
Keyword string
}
func (opts FindBranchOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}
if opts.RepoCond != nil {
cond = cond.And(opts.RepoCond)
}
if len(opts.ExcludeBranchNames) > 0 {
cond = cond.And(builder.NotIn("name", opts.ExcludeBranchNames))
cond = cond.And(builder.NotIn("branch.name", opts.ExcludeBranchNames))
}
if opts.CommitCond != nil {
cond = cond.And(opts.CommitCond)
}
if opts.PusherID > 0 {
cond = cond.And(builder.Eq{"branch.pusher_id": opts.PusherID})
}
if opts.IsDeletedBranch.Has() {
cond = cond.And(builder.Eq{"is_deleted": opts.IsDeletedBranch.Value()})
cond = cond.And(builder.Eq{"branch.is_deleted": opts.IsDeletedBranch.Value()})
}
if opts.Keyword != "" {
cond = cond.And(builder.Like{"name", opts.Keyword})
}
if opts.CommitAfterUnix != 0 {
cond = cond.And(builder.Gte{"branch.commit_time": opts.CommitAfterUnix})
}
if opts.CommitBeforeUnix != 0 {
cond = cond.And(builder.Lte{"branch.commit_time": opts.CommitBeforeUnix})
}
return cond
}

View File

@ -81,7 +81,7 @@ func TestUserListIsPublicMember(t *testing.T) {
{3, map[int64]bool{2: true, 4: false, 28: true}},
{6, map[int64]bool{5: true, 28: true}},
{7, map[int64]bool{5: false}},
{25, map[int64]bool{24: true}},
{25, map[int64]bool{12: true, 24: true}},
{22, map[int64]bool{}},
}
for _, v := range tt {
@ -108,8 +108,8 @@ func TestUserListIsUserOrgOwner(t *testing.T) {
{3, map[int64]bool{2: true, 4: false, 28: false}},
{6, map[int64]bool{5: true, 28: false}},
{7, map[int64]bool{5: true}},
{25, map[int64]bool{24: false}}, // ErrTeamNotExist
{22, map[int64]bool{}}, // No member
{25, map[int64]bool{12: true, 24: false}}, // ErrTeamNotExist
{22, map[int64]bool{}}, // No member
}
for _, v := range tt {
t.Run(fmt.Sprintf("IsUserOrgOwnerOfOrgId%d", v.orgid), func(t *testing.T) {

View File

@ -175,6 +175,8 @@ type SearchRepoOptions struct {
// True -> include just forks
// False -> include just non-forks
Fork optional.Option[bool]
// If Fork option is True, you can use this option to limit the forks of a special repo by repo id.
ForkFrom int64
// None -> include templates AND non-templates
// True -> include just templates
// False -> include just non-templates
@ -514,6 +516,10 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
cond = cond.And(builder.Eq{"is_fork": false})
} else {
cond = cond.And(builder.Eq{"is_fork": opts.Fork.Value()})
if opts.ForkFrom > 0 && opts.Fork.Value() {
cond = cond.And(builder.Eq{"fork_id": opts.ForkFrom})
}
}
}

View File

@ -217,7 +217,7 @@ type EditRepoOption struct {
Archived *bool `json:"archived,omitempty"`
// set to a string like `8h30m0s` to set the mirror interval time
MirrorInterval *string `json:"mirror_interval,omitempty"`
// enable prune - remove obsolete remote-tracking references
// enable prune - remove obsolete remote-tracking references when mirroring
EnablePrune *bool `json:"enable_prune,omitempty"`
}

View File

@ -1062,16 +1062,10 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e
func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error {
repo := ctx.Repo.Repository
// only update mirror if interval or enable prune are provided
if opts.MirrorInterval == nil && opts.EnablePrune == nil {
return nil
}
// these values only make sense if the repo is a mirror
// Skip this update if the repo is not a mirror, do not return error.
// Because reporting errors only makes the logic more complex&fragile, it doesn't really help end users.
if !repo.IsMirror {
err := fmt.Errorf("repo is not a mirror, can not change mirror interval")
ctx.Error(http.StatusUnprocessableEntity, err.Error(), err)
return err
return nil
}
// get the mirror from the repo

View File

@ -29,6 +29,7 @@ import (
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issue_model "code.gitea.io/gitea/models/issues"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
@ -1027,15 +1028,26 @@ func renderHomeCode(ctx *context.Context) {
return
}
showRecentlyPushedNewBranches := true
if ctx.Repo.Repository.IsMirror ||
!ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypePullRequests) {
showRecentlyPushedNewBranches = false
opts := &git_model.FindRecentlyPushedNewBranchesOptions{
Repo: ctx.Repo.Repository,
BaseRepo: ctx.Repo.Repository,
}
if showRecentlyPushedNewBranches {
ctx.Data["RecentlyPushedNewBranches"], err = git_model.FindRecentlyPushedNewBranches(ctx, ctx.Repo.Repository.ID, ctx.Doer.ID, ctx.Repo.Repository.DefaultBranch)
if ctx.Repo.Repository.IsFork {
opts.BaseRepo = ctx.Repo.Repository.BaseRepo
}
baseRepoPerm, err := access_model.GetUserRepoPermission(ctx, opts.BaseRepo, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return
}
if !opts.Repo.IsMirror && !opts.BaseRepo.IsMirror &&
opts.BaseRepo.UnitEnabled(ctx, unit_model.TypePullRequests) &&
baseRepoPerm.CanRead(unit_model.TypePullRequests) {
ctx.Data["RecentlyPushedNewBranches"], err = git_model.FindRecentlyPushedNewBranches(ctx, ctx.Doer, opts)
if err != nil {
ctx.ServerError("GetRecentlyPushedBranches", err)
ctx.ServerError("FindRecentlyPushedNewBranches", err)
return
}
}

View File

@ -2,10 +2,10 @@
<div class="ui positive message tw-flex tw-items-center">
<div class="tw-flex-1">
{{$timeSince := TimeSince .CommitTime.AsTime ctx.Locale}}
{{$branchLink := HTMLFormat `<a href="%s/src/branch/%s">%s</a>` $.RepoLink (PathEscapeSegments .Name) .Name}}
{{$branchLink := HTMLFormat `<a href="%s">%s</a>` .BranchLink .BranchDisplayName}}
{{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" $branchLink $timeSince}}
</div>
<a role="button" class="ui compact green button tw-m-0" href="{{$.Repository.ComposeBranchCompareURL $.Repository.BaseRepo .Name}}">
<a role="button" class="ui compact green button tw-m-0" href="{{.BranchCompareURL}}">
{{ctx.Locale.Tr "repo.pulls.compare_changes"}}
</a>
</div>

View File

@ -20753,7 +20753,7 @@
"x-go-name": "Description"
},
"enable_prune": {
"description": "enable prune - remove obsolete remote-tracking references",
"description": "enable prune - remove obsolete remote-tracking references when mirroring",
"type": "boolean",
"x-go-name": "EnablePrune"
},

View File

@ -29,6 +29,7 @@ func TestUserOrgs(t *testing.T) {
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"})
org17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org17"})
org35 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "private_org35"})
assert.Equal(t, []*api.Organization{
{
@ -55,6 +56,18 @@ func TestUserOrgs(t *testing.T) {
Location: "",
Visibility: "public",
},
{
ID: 35,
Name: org35.Name,
UserName: org35.Name,
FullName: org35.FullName,
Email: org35.Email,
AvatarURL: org35.AvatarLink(db.DefaultContext),
Description: "",
Website: "",
Location: "",
Visibility: "private",
},
}, orgs)
// user itself should get it's org's he is a member of
@ -102,6 +115,7 @@ func TestMyOrgs(t *testing.T) {
DecodeJSON(t, resp, &orgs)
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"})
org17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org17"})
org35 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "private_org35"})
assert.Equal(t, []*api.Organization{
{
@ -128,5 +142,17 @@ func TestMyOrgs(t *testing.T) {
Location: "",
Visibility: "public",
},
{
ID: 35,
Name: org35.Name,
UserName: org35.Name,
FullName: org35.FullName,
Email: org35.Email,
AvatarURL: org35.AvatarLink(db.DefaultContext),
Description: "",
Website: "",
Location: "",
Visibility: "private",
},
}, orgs)
}

View File

@ -6,9 +6,11 @@ package integration
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
@ -24,6 +26,17 @@ import (
"github.com/stretchr/testify/assert"
)
func testAPINewFile(t *testing.T, session *TestSession, user, repo, branch, treePath, content string) *httptest.ResponseRecorder {
url := fmt.Sprintf("/%s/%s/_new/%s", user, repo, branch)
req := NewRequestWithValues(t, "POST", url, map[string]string{
"_csrf": GetCSRF(t, session, "/user/settings"),
"commit_choice": "direct",
"tree_path": treePath,
"content": content,
})
return session.MakeRequest(t, req, http.StatusSeeOther)
}
func TestEmptyRepo(t *testing.T) {
defer tests.PrepareTestEnv(t)()
subPaths := []string{

View File

@ -485,6 +485,7 @@ func VerifyJSONSchema(t testing.TB, resp *httptest.ResponseRecorder, schemaFile
assert.True(t, result.Valid())
}
// GetCSRF returns CSRF token from body
func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
t.Helper()
req := NewRequest(t, "GET", urlStr)
@ -492,3 +493,11 @@ func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
doc := NewHTMLParser(t, resp.Body)
return doc.GetCSRF()
}
// GetCSRFFrom returns CSRF token from body
func GetCSRFFromCookie(t testing.TB, session *TestSession, urlStr string) string {
t.Helper()
req := NewRequest(t, "GET", urlStr)
session.MakeRequest(t, req, http.StatusOK)
return session.GetCookie("_csrf").Value
}

View File

@ -45,7 +45,7 @@ func TestPullCompare(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther)
testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n")
testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title")

View File

@ -85,7 +85,7 @@ func testPullCreateDirectly(t *testing.T, session *TestSession, baseRepoOwner, b
func TestPullCreate(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
@ -113,7 +113,7 @@ func TestPullCreate(t *testing.T) {
func TestPullCreate_TitleEscape(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "<i>XSS PR</i>")
@ -177,7 +177,7 @@ func TestPullBranchDelete(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther)
testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title")

View File

@ -89,7 +89,7 @@ func TestPullMerge(t *testing.T) {
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
@ -111,7 +111,7 @@ func TestPullRebase(t *testing.T) {
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
@ -133,7 +133,7 @@ func TestPullRebaseMerge(t *testing.T) {
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
@ -155,7 +155,7 @@ func TestPullSquash(t *testing.T) {
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n")
@ -174,7 +174,7 @@ func TestPullSquash(t *testing.T) {
func TestPullCleanUpAfterMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited - TestPullCleanUpAfterMerge)\n")
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "feature/test", "This is a pull title")
@ -209,7 +209,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
func TestCantMergeWorkInProgress(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "[wip] This is a pull title")
@ -228,7 +228,7 @@ func TestCantMergeWorkInProgress(t *testing.T) {
func TestCantMergeConflict(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n")
@ -274,7 +274,7 @@ func TestCantMergeConflict(t *testing.T) {
func TestCantMergeUnrelated(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n")
// Now we want to create a commit on a branch that is totally unrelated to our current head
@ -369,7 +369,7 @@ func TestCantMergeUnrelated(t *testing.T) {
func TestFastForwardOnlyMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "update", "README.md", "Hello, World 2\n")
// Use API to create a pr from update to master
@ -410,7 +410,7 @@ func TestFastForwardOnlyMerge(t *testing.T) {
func TestCantFastForwardOnlyMergeDiverging(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "diverging", "README.md", "Hello, World diverged\n")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World 2\n")
@ -533,7 +533,7 @@ func TestPullRetargetChildOnBranchDelete(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
testEditFileToNewBranch(t, session, "user2", "repo1", "master", "base-pr", "README.md", "Hello, World\n(Edited - TestPullRetargetOnCleanup - base PR)\n")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "base-pr", "child-pr", "README.md", "Hello, World\n(Edited - TestPullRetargetOnCleanup - base PR)\n(Edited - TestPullRetargetOnCleanup - child PR)")
respBasePR := testPullCreate(t, session, "user2", "repo1", true, "master", "base-pr", "Base Pull Request")
@ -562,7 +562,7 @@ func TestPullRetargetChildOnBranchDelete(t *testing.T) {
func TestPullDontRetargetChildOnWrongRepo(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base-pr", "README.md", "Hello, World\n(Edited - TestPullDontRetargetChildOnWrongRepo - base PR)\n")
testEditFileToNewBranch(t, session, "user1", "repo1", "base-pr", "child-pr", "README.md", "Hello, World\n(Edited - TestPullDontRetargetChildOnWrongRepo - base PR)\n(Edited - TestPullDontRetargetChildOnWrongRepo - child PR)")
@ -593,7 +593,7 @@ func TestPullMergeIndexerNotifier(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// create a pull request
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
createPullResp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "Indexer notifier test pull")

View File

@ -186,7 +186,7 @@ func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) {
user2Session := loginUser(t, "user2")
// Have user1 create a fork of repo1.
testRepoFork(t, user1Session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, user1Session, "user2", "repo1", "user1", "repo1", "")
t.Run("Submit approve/reject review on merged PR", func(t *testing.T) {
// Create a merged PR (made by user1) in the upstream repo1.

View File

@ -23,7 +23,7 @@ import (
func TestPullCreate_CommitStatus(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
url := path.Join("user1", "repo1", "compare", "master...status1")
@ -122,7 +122,7 @@ func TestPullCreate_EmptyChangesWithDifferentCommits(t *testing.T) {
// so we need to have this meta commit also in develop branch.
onGiteaRun(t, func(t *testing.T, u *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
testEditFileToNewBranch(t, session, "user1", "repo1", "status1", "status1", "README.md", "# repo1\n\nDescription for repo1")
@ -147,7 +147,7 @@ func TestPullCreate_EmptyChangesWithDifferentCommits(t *testing.T) {
func TestPullCreate_EmptyChangesWithSameCommits(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testCreateBranch(t, session, "user1", "repo1", "branch/master", "status1", http.StatusSeeOther)
url := path.Join("user1", "repo1", "compare", "master...status1")
req := NewRequestWithValues(t, "POST", url,

View File

@ -20,7 +20,7 @@ func TestRepoActivity(t *testing.T) {
session := loginUser(t, "user1")
// Create PRs (1 merged & 2 proposed)
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
elem := strings.Split(test.RedirectURL(resp), "/")

View File

@ -4,26 +4,37 @@
package integration
import (
"fmt"
"net/http"
"net/url"
"path"
"strings"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
org_model "code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/tests"
"github.com/PuerkitoBio/goquery"
"github.com/stretchr/testify/assert"
)
func testCreateBranch(t testing.TB, session *TestSession, user, repo, oldRefSubURL, newBranchName string, expectedStatus int) string {
var csrf string
if expectedStatus == http.StatusNotFound {
csrf = GetCSRF(t, session, path.Join(user, repo, "src/branch/master"))
// src/branch/branch_name may not container "_csrf" input,
// so we need to get it from cookies not from body
csrf = GetCSRFFromCookie(t, session, path.Join(user, repo, "src/branch/master"))
} else {
csrf = GetCSRF(t, session, path.Join(user, repo, "src", oldRefSubURL))
csrf = GetCSRFFromCookie(t, session, path.Join(user, repo, "src", oldRefSubURL))
}
req := NewRequestWithValues(t, "POST", path.Join(user, repo, "branches/_new", oldRefSubURL), map[string]string{
"_csrf": csrf,
@ -145,3 +156,134 @@ func TestCreateBranchInvalidCSRF(t *testing.T) {
strings.TrimSpace(htmlDoc.doc.Find(".ui.message").Text()),
)
}
func prepareBranch(t *testing.T, session *TestSession, repo *repo_model.Repository) {
baseRefSubURL := fmt.Sprintf("branch/%s", repo.DefaultBranch)
// create branch with no new commit
testCreateBranch(t, session, repo.OwnerName, repo.Name, baseRefSubURL, "no-commit", http.StatusSeeOther)
// create branch with commit
testCreateBranch(t, session, repo.OwnerName, repo.Name, baseRefSubURL, "new-commit", http.StatusSeeOther)
testAPINewFile(t, session, repo.OwnerName, repo.Name, "new-commit", "new-commit.txt", "new-commit")
// create deleted branch
testCreateBranch(t, session, repo.OwnerName, repo.Name, "branch/new-commit", "deleted-branch", http.StatusSeeOther)
testUIDeleteBranch(t, session, repo.OwnerName, repo.Name, "deleted-branch")
}
func testCreatePullToDefaultBranch(t *testing.T, session *TestSession, baseRepo, headRepo *repo_model.Repository, headBranch, title string) string {
srcRef := headBranch
if baseRepo.ID != headRepo.ID {
srcRef = fmt.Sprintf("%s/%s:%s", headRepo.OwnerName, headRepo.Name, headBranch)
}
resp := testPullCreate(t, session, baseRepo.OwnerName, baseRepo.Name, false, baseRepo.DefaultBranch, srcRef, title)
elem := strings.Split(test.RedirectURL(resp), "/")
// return pull request ID
return elem[4]
}
func prepareRepoPR(t *testing.T, baseSession, headSession *TestSession, baseRepo, headRepo *repo_model.Repository) {
// create opening PR
testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "opening-pr", http.StatusSeeOther)
testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "opening-pr", "opening pr")
// create closed PR
testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "closed-pr", http.StatusSeeOther)
prID := testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "closed-pr", "closed pr")
testIssueClose(t, baseSession, baseRepo.OwnerName, baseRepo.Name, prID)
// create closed PR with deleted branch
testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "closed-pr-deleted", http.StatusSeeOther)
prID = testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "closed-pr-deleted", "closed pr with deleted branch")
testIssueClose(t, baseSession, baseRepo.OwnerName, baseRepo.Name, prID)
testUIDeleteBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "closed-pr-deleted")
// create merged PR
testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "merged-pr", http.StatusSeeOther)
prID = testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "merged-pr", "merged pr")
testAPINewFile(t, headSession, headRepo.OwnerName, headRepo.Name, "merged-pr", fmt.Sprintf("new-commit-%s.txt", headRepo.Name), "new-commit")
testPullMerge(t, baseSession, baseRepo.OwnerName, baseRepo.Name, prID, repo_model.MergeStyleRebaseMerge, false)
// create merged PR with deleted branch
testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "merged-pr-deleted", http.StatusSeeOther)
prID = testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "merged-pr-deleted", "merged pr with deleted branch")
testAPINewFile(t, headSession, headRepo.OwnerName, headRepo.Name, "merged-pr-deleted", fmt.Sprintf("new-commit-%s-2.txt", headRepo.Name), "new-commit")
testPullMerge(t, baseSession, baseRepo.OwnerName, baseRepo.Name, prID, repo_model.MergeStyleRebaseMerge, true)
}
func checkRecentlyPushedNewBranches(t *testing.T, session *TestSession, repoPath string, expected []string) {
branches := make([]string, 0, 2)
req := NewRequest(t, "GET", repoPath)
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
doc.doc.Find(".ui.positive.message div a").Each(func(index int, branch *goquery.Selection) {
branches = append(branches, branch.Text())
})
assert.Equal(t, expected, branches)
}
func TestRecentlyPushedNewBranches(t *testing.T) {
defer tests.PrepareTestEnv(t)()
onGiteaRun(t, func(t *testing.T, u *url.URL) {
user1Session := loginUser(t, "user1")
user2Session := loginUser(t, "user2")
user12Session := loginUser(t, "user12")
user13Session := loginUser(t, "user13")
// prepare branch and PRs in original repo
repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10})
prepareBranch(t, user12Session, repo10)
prepareRepoPR(t, user12Session, user12Session, repo10, repo10)
// outdated new branch should not be displayed
checkRecentlyPushedNewBranches(t, user12Session, "user12/repo10", []string{"new-commit"})
// create a fork repo in public org
testRepoFork(t, user12Session, repo10.OwnerName, repo10.Name, "org25", "org25_fork_repo10", "new-commit")
orgPublicForkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 25, Name: "org25_fork_repo10"})
prepareRepoPR(t, user12Session, user12Session, repo10, orgPublicForkRepo)
// user12 is the owner of the repo10 and the organization org25
// in repo10, user12 has opening/closed/merged pr and closed/merged pr with deleted branch
checkRecentlyPushedNewBranches(t, user12Session, "user12/repo10", []string{"org25/org25_fork_repo10:new-commit", "new-commit"})
userForkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11})
prepareBranch(t, user13Session, userForkRepo)
prepareRepoPR(t, user13Session, user13Session, repo10, userForkRepo)
// create branch with same name in different repo by user13
testCreateBranch(t, user13Session, repo10.OwnerName, repo10.Name, "branch/new-commit", "same-name-branch", http.StatusSeeOther)
testCreateBranch(t, user13Session, userForkRepo.OwnerName, userForkRepo.Name, "branch/new-commit", "same-name-branch", http.StatusSeeOther)
testCreatePullToDefaultBranch(t, user13Session, repo10, userForkRepo, "same-name-branch", "same name branch pr")
// user13 pushed 2 branches with the same name in repo10 and repo11
// and repo11's branch has a pr, but repo10's branch doesn't
// in this case, we should get repo10's branch but not repo11's branch
checkRecentlyPushedNewBranches(t, user13Session, "user12/repo10", []string{"same-name-branch", "user13/repo11:new-commit"})
// create a fork repo in private org
testRepoFork(t, user1Session, repo10.OwnerName, repo10.Name, "private_org35", "org35_fork_repo10", "new-commit")
orgPrivateForkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 35, Name: "org35_fork_repo10"})
prepareRepoPR(t, user1Session, user1Session, repo10, orgPrivateForkRepo)
// user1 is the owner of private_org35 and no write permission to repo10
// so user1 can only see the branch in org35_fork_repo10
checkRecentlyPushedNewBranches(t, user1Session, "user12/repo10", []string{"private_org35/org35_fork_repo10:new-commit"})
// user2 push a branch in private_org35
testCreateBranch(t, user2Session, orgPrivateForkRepo.OwnerName, orgPrivateForkRepo.Name, "branch/new-commit", "user-read-permission", http.StatusSeeOther)
// convert write permission to read permission for code unit
token := getTokenForLoggedInUser(t, user1Session, auth_model.AccessTokenScopeWriteOrganization)
req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", 24), &api.EditTeamOption{
Name: "team24",
UnitsMap: map[string]string{"repo.code": "read"},
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusOK)
teamUnit := unittest.AssertExistsAndLoadBean(t, &org_model.TeamUnit{TeamID: 24, Type: unit.TypeCode})
assert.Equal(t, perm.AccessModeRead, teamUnit.AccessMode)
// user2 can see the branch as it is created by user2
checkRecentlyPushedNewBranches(t, user2Session, "user12/repo10", []string{"private_org35/org35_fork_repo10:user-read-permission"})
})
}

View File

@ -16,7 +16,7 @@ import (
"github.com/stretchr/testify/assert"
)
func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkOwnerName, forkRepoName string) *httptest.ResponseRecorder {
func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkOwnerName, forkRepoName, forkBranch string) *httptest.ResponseRecorder {
forkOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: forkOwnerName})
// Step0: check the existence of the to-fork repo
@ -41,9 +41,10 @@ func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkO
_, exists = htmlDoc.doc.Find(fmt.Sprintf(".owner.dropdown .item[data-value=\"%d\"]", forkOwner.ID)).Attr("data-value")
assert.True(t, exists, fmt.Sprintf("Fork owner '%s' is not present in select box", forkOwnerName))
req = NewRequestWithValues(t, "POST", link, map[string]string{
"_csrf": htmlDoc.GetCSRF(),
"uid": fmt.Sprintf("%d", forkOwner.ID),
"repo_name": forkRepoName,
"_csrf": htmlDoc.GetCSRF(),
"uid": fmt.Sprintf("%d", forkOwner.ID),
"repo_name": forkRepoName,
"fork_single_branch": forkBranch,
})
session.MakeRequest(t, req, http.StatusSeeOther)
@ -57,13 +58,13 @@ func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkO
func TestRepoFork(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
}
func TestRepoForkToOrg(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
testRepoFork(t, session, "user2", "repo1", "org3", "repo1")
testRepoFork(t, session, "user2", "repo1", "org3", "repo1", "")
// Check that no more forking is allowed as user2 owns repository
// and org3 organization that owner user2 is also now has forked this repository