mirror of
https://github.com/go-gitea/gitea
synced 2024-12-22 16:24:06 +01:00
Fix wrong display of recently pushed notification (#25812)
There's a bug in #25715: If user pushed a commit into another repo with same branch name, the no-related repo will display the recently pushed notification incorrectly. It is simple to fix this, we should match the repo id in the sql query. ![image](https://github.com/go-gitea/gitea/assets/18380374/9411a926-16f1-419e-a1b5-e953af38bab1) The latest commit is 2 weeks ago. ![image](https://github.com/go-gitea/gitea/assets/18380374/52f9ab22-4999-43ac-a86f-6d36fb1e0411) The notification comes from another repo with same branch name: ![image](https://github.com/go-gitea/gitea/assets/18380374/a26bc335-8e5b-4b9c-a965-c3dc3fa6f252) After: In forked repo: ![image](https://github.com/go-gitea/gitea/assets/18380374/ce6ffc35-deb7-4be7-8b09-184207392f32) New PR Link will redirect to the original repo: ![image](https://github.com/go-gitea/gitea/assets/18380374/7b98e76f-0c75-494c-9462-80cf9f98e786) In the original repo: ![image](https://github.com/go-gitea/gitea/assets/18380374/5f6a821b-e51a-4bbd-9980-d9eb94a3c847) New PR Link: ![image](https://github.com/go-gitea/gitea/assets/18380374/1ce8c879-9f11-4312-8c32-695d7d9af0df) In the same repo: ![image](https://github.com/go-gitea/gitea/assets/18380374/64b56073-4d0e-40c4-b8a0-80be7a775f69) New PR Link: ![image](https://github.com/go-gitea/gitea/assets/18380374/96e1b6a3-fb98-40ee-b2ee-648039fb0dcf) 08/15 Update: Follow #26257, added permission check and logic fix mentioned in https://github.com/go-gitea/gitea/pull/26257#discussion_r1294085203 2024/04/25 Update: Fix #30611 --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
9c8c9ff6d1
commit
daf2a4c047
26 changed files with 508 additions and 72 deletions
|
@ -45,3 +45,39 @@
|
||||||
is_deleted: false
|
is_deleted: false
|
||||||
deleted_by_id: 0
|
deleted_by_id: 0
|
||||||
deleted_unix: 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
|
||||||
|
|
|
@ -1,27 +1,35 @@
|
||||||
-
|
-
|
||||||
group_id: 1
|
group_id: 1
|
||||||
max_index: 5
|
max_index: 5
|
||||||
|
|
||||||
-
|
-
|
||||||
group_id: 2
|
group_id: 2
|
||||||
max_index: 2
|
max_index: 2
|
||||||
|
|
||||||
-
|
-
|
||||||
group_id: 3
|
group_id: 3
|
||||||
max_index: 2
|
max_index: 2
|
||||||
|
|
||||||
-
|
-
|
||||||
group_id: 10
|
group_id: 10
|
||||||
max_index: 1
|
max_index: 1
|
||||||
|
|
||||||
-
|
-
|
||||||
group_id: 32
|
group_id: 32
|
||||||
max_index: 2
|
max_index: 2
|
||||||
|
|
||||||
-
|
-
|
||||||
group_id: 48
|
group_id: 48
|
||||||
max_index: 1
|
max_index: 1
|
||||||
|
|
||||||
-
|
-
|
||||||
group_id: 42
|
group_id: 42
|
||||||
max_index: 1
|
max_index: 1
|
||||||
|
|
||||||
-
|
-
|
||||||
group_id: 50
|
group_id: 50
|
||||||
max_index: 1
|
max_index: 1
|
||||||
|
|
||||||
-
|
-
|
||||||
group_id: 51
|
group_id: 51
|
||||||
max_index: 1
|
max_index: 1
|
||||||
|
|
|
@ -117,3 +117,15 @@
|
||||||
uid: 40
|
uid: 40
|
||||||
org_id: 41
|
org_id: 41
|
||||||
is_public: true
|
is_public: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 21
|
||||||
|
uid: 12
|
||||||
|
org_id: 25
|
||||||
|
is_public: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 22
|
||||||
|
uid: 2
|
||||||
|
org_id: 35
|
||||||
|
is_public: true
|
||||||
|
|
|
@ -327,7 +327,7 @@
|
||||||
is_archived: false
|
is_archived: false
|
||||||
is_mirror: false
|
is_mirror: false
|
||||||
status: 0
|
status: 0
|
||||||
is_fork: false
|
is_fork: true
|
||||||
fork_id: 10
|
fork_id: 10
|
||||||
is_template: false
|
is_template: false
|
||||||
template_id: 0
|
template_id: 0
|
||||||
|
|
|
@ -239,3 +239,25 @@
|
||||||
num_members: 2
|
num_members: 2
|
||||||
includes_all_repositories: false
|
includes_all_repositories: false
|
||||||
can_create_org_repo: 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
|
||||||
|
|
|
@ -322,3 +322,21 @@
|
||||||
team_id: 22
|
team_id: 22
|
||||||
type: 3
|
type: 3
|
||||||
access_mode: 1
|
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
|
||||||
|
|
|
@ -147,3 +147,15 @@
|
||||||
org_id: 41
|
org_id: 41
|
||||||
team_id: 22
|
team_id: 22
|
||||||
uid: 39
|
uid: 39
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 26
|
||||||
|
org_id: 25
|
||||||
|
team_id: 23
|
||||||
|
uid: 12
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 27
|
||||||
|
org_id: 35
|
||||||
|
team_id: 24
|
||||||
|
uid: 2
|
||||||
|
|
|
@ -918,8 +918,8 @@
|
||||||
num_following: 0
|
num_following: 0
|
||||||
num_stars: 0
|
num_stars: 0
|
||||||
num_repos: 0
|
num_repos: 0
|
||||||
num_teams: 1
|
num_teams: 2
|
||||||
num_members: 1
|
num_members: 2
|
||||||
visibility: 0
|
visibility: 0
|
||||||
repo_admin_change_team_access: false
|
repo_admin_change_team_access: false
|
||||||
theme: ""
|
theme: ""
|
||||||
|
@ -1289,8 +1289,8 @@
|
||||||
num_following: 0
|
num_following: 0
|
||||||
num_stars: 0
|
num_stars: 0
|
||||||
num_repos: 0
|
num_repos: 0
|
||||||
num_teams: 1
|
num_teams: 2
|
||||||
num_members: 1
|
num_members: 2
|
||||||
visibility: 2
|
visibility: 2
|
||||||
repo_admin_change_team_access: false
|
repo_admin_change_team_access: false
|
||||||
theme: ""
|
theme: ""
|
||||||
|
|
|
@ -10,9 +10,11 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
|
@ -102,8 +104,9 @@ func (err ErrBranchesEqual) Unwrap() error {
|
||||||
// for pagination, keyword search and filtering
|
// for pagination, keyword search and filtering
|
||||||
type Branch struct {
|
type Branch struct {
|
||||||
ID int64
|
ID int64
|
||||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
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
|
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
|
CommitID string
|
||||||
CommitMessage string `xorm:"TEXT"` // it only stores the message summary (the first line)
|
CommitMessage string `xorm:"TEXT"` // it only stores the message summary (the first line)
|
||||||
PusherID int64
|
PusherID int64
|
||||||
|
@ -139,6 +142,14 @@ func (b *Branch) LoadPusher(ctx context.Context) (err error) {
|
||||||
return err
|
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() {
|
func init() {
|
||||||
db.RegisterModel(new(Branch))
|
db.RegisterModel(new(Branch))
|
||||||
db.RegisterModel(new(RenamedBranch))
|
db.RegisterModel(new(RenamedBranch))
|
||||||
|
@ -400,24 +411,111 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindRecentlyPushedNewBranches return at most 2 new branches pushed by the user in 6 hours which has no opened PRs created
|
type FindRecentlyPushedNewBranchesOptions struct {
|
||||||
// except the indicate branch
|
Repo *repo_model.Repository
|
||||||
func FindRecentlyPushedNewBranches(ctx context.Context, repoID, userID int64, excludeBranchName string) (BranchList, error) {
|
BaseRepo *repo_model.Repository
|
||||||
branches := make(BranchList, 0, 2)
|
CommitAfterUnix int64
|
||||||
subQuery := builder.Select("head_branch").From("pull_request").
|
MaxCount int
|
||||||
InnerJoin("issue", "issue.id = pull_request.issue_id").
|
}
|
||||||
Where(builder.Eq{
|
|
||||||
"pull_request.head_repo_id": repoID,
|
type RecentlyPushedNewBranch struct {
|
||||||
"issue.is_closed": false,
|
BranchDisplayName string
|
||||||
})
|
BranchLink string
|
||||||
err := db.GetEngine(ctx).
|
BranchCompareURL string
|
||||||
Where("pusher_id=? AND is_deleted=?", userID, false).
|
CommitTime timeutil.TimeStamp
|
||||||
And("name <> ?", excludeBranchName).
|
}
|
||||||
And("repo_id = ?", repoID).
|
|
||||||
And("commit_time >= ?", time.Now().Add(-time.Hour*6).Unix()).
|
// FindRecentlyPushedNewBranches return at most 2 new branches pushed by the user in 2 hours which has no opened PRs created
|
||||||
NotIn("name", subQuery).
|
// if opts.CommitAfterUnix is 0, we will find the branches that were committed to in the last 2 hours
|
||||||
OrderBy("branch.commit_time DESC").
|
// if opts.ListOptions is not set, we will only display top 2 latest branch
|
||||||
Limit(2).
|
func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, opts *FindRecentlyPushedNewBranchesOptions) ([]*RecentlyPushedNewBranch, error) {
|
||||||
Find(&branches)
|
if doer == nil {
|
||||||
return branches, err
|
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
|
||||||
|
var branches []*Branch
|
||||||
|
if err := db.GetEngine(ctx).
|
||||||
|
Where(builder.And(
|
||||||
|
builder.Eq{
|
||||||
|
"pusher_id": doer.ID,
|
||||||
|
"is_deleted": false,
|
||||||
|
},
|
||||||
|
builder.Gte{"commit_time": opts.CommitAfterUnix},
|
||||||
|
builder.In("repo_id", repoIDs),
|
||||||
|
// newly created branch have no changes, so skip them
|
||||||
|
builder.Neq{"commit_id": baseBranch.CommitID},
|
||||||
|
)).
|
||||||
|
OrderBy(db.SearchOrderByRecentUpdated.String()).
|
||||||
|
Find(&branches); 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
|
@ -59,6 +60,24 @@ func (branches BranchList) LoadPusher(ctx context.Context) error {
|
||||||
return nil
|
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 {
|
type FindBranchOptions struct {
|
||||||
db.ListOptions
|
db.ListOptions
|
||||||
RepoID int64
|
RepoID int64
|
||||||
|
|
|
@ -81,7 +81,7 @@ func TestUserListIsPublicMember(t *testing.T) {
|
||||||
{3, map[int64]bool{2: true, 4: false, 28: true}},
|
{3, map[int64]bool{2: true, 4: false, 28: true}},
|
||||||
{6, map[int64]bool{5: true, 28: true}},
|
{6, map[int64]bool{5: true, 28: true}},
|
||||||
{7, map[int64]bool{5: false}},
|
{7, map[int64]bool{5: false}},
|
||||||
{25, map[int64]bool{24: true}},
|
{25, map[int64]bool{12: true, 24: true}},
|
||||||
{22, map[int64]bool{}},
|
{22, map[int64]bool{}},
|
||||||
}
|
}
|
||||||
for _, v := range tt {
|
for _, v := range tt {
|
||||||
|
@ -108,8 +108,8 @@ func TestUserListIsUserOrgOwner(t *testing.T) {
|
||||||
{3, map[int64]bool{2: true, 4: false, 28: false}},
|
{3, map[int64]bool{2: true, 4: false, 28: false}},
|
||||||
{6, map[int64]bool{5: true, 28: false}},
|
{6, map[int64]bool{5: true, 28: false}},
|
||||||
{7, map[int64]bool{5: true}},
|
{7, map[int64]bool{5: true}},
|
||||||
{25, map[int64]bool{24: false}}, // ErrTeamNotExist
|
{25, map[int64]bool{12: true, 24: false}}, // ErrTeamNotExist
|
||||||
{22, map[int64]bool{}}, // No member
|
{22, map[int64]bool{}}, // No member
|
||||||
}
|
}
|
||||||
for _, v := range tt {
|
for _, v := range tt {
|
||||||
t.Run(fmt.Sprintf("IsUserOrgOwnerOfOrgId%d", v.orgid), func(t *testing.T) {
|
t.Run(fmt.Sprintf("IsUserOrgOwnerOfOrgId%d", v.orgid), func(t *testing.T) {
|
||||||
|
|
|
@ -175,6 +175,8 @@ type SearchRepoOptions struct {
|
||||||
// True -> include just forks
|
// True -> include just forks
|
||||||
// False -> include just non-forks
|
// False -> include just non-forks
|
||||||
Fork optional.Option[bool]
|
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
|
// None -> include templates AND non-templates
|
||||||
// True -> include just templates
|
// True -> include just templates
|
||||||
// False -> include just non-templates
|
// False -> include just non-templates
|
||||||
|
@ -514,6 +516,10 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
|
||||||
cond = cond.And(builder.Eq{"is_fork": false})
|
cond = cond.And(builder.Eq{"is_fork": false})
|
||||||
} else {
|
} else {
|
||||||
cond = cond.And(builder.Eq{"is_fork": opts.Fork.Value()})
|
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})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
issue_model "code.gitea.io/gitea/models/issues"
|
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"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
unit_model "code.gitea.io/gitea/models/unit"
|
unit_model "code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -1027,15 +1028,26 @@ func renderHomeCode(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
showRecentlyPushedNewBranches := true
|
opts := &git_model.FindRecentlyPushedNewBranchesOptions{
|
||||||
if ctx.Repo.Repository.IsMirror ||
|
Repo: ctx.Repo.Repository,
|
||||||
!ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypePullRequests) {
|
BaseRepo: ctx.Repo.Repository,
|
||||||
showRecentlyPushedNewBranches = false
|
|
||||||
}
|
}
|
||||||
if showRecentlyPushedNewBranches {
|
if ctx.Repo.Repository.IsFork {
|
||||||
ctx.Data["RecentlyPushedNewBranches"], err = git_model.FindRecentlyPushedNewBranches(ctx, ctx.Repo.Repository.ID, ctx.Doer.ID, ctx.Repo.Repository.DefaultBranch)
|
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 {
|
if err != nil {
|
||||||
ctx.ServerError("GetRecentlyPushedBranches", err)
|
ctx.ServerError("FindRecentlyPushedNewBranches", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<div class="ui positive message tw-flex tw-items-center">
|
<div class="ui positive message tw-flex tw-items-center">
|
||||||
<div class="tw-flex-1">
|
<div class="tw-flex-1">
|
||||||
{{$timeSince := TimeSince .CommitTime.AsTime ctx.Locale}}
|
{{$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}}
|
{{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" $branchLink $timeSince}}
|
||||||
</div>
|
</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"}}
|
{{ctx.Locale.Tr "repo.pulls.compare_changes"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -29,6 +29,7 @@ func TestUserOrgs(t *testing.T) {
|
||||||
|
|
||||||
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"})
|
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"})
|
||||||
org17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org17"})
|
org17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org17"})
|
||||||
|
org35 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "private_org35"})
|
||||||
|
|
||||||
assert.Equal(t, []*api.Organization{
|
assert.Equal(t, []*api.Organization{
|
||||||
{
|
{
|
||||||
|
@ -55,6 +56,18 @@ func TestUserOrgs(t *testing.T) {
|
||||||
Location: "",
|
Location: "",
|
||||||
Visibility: "public",
|
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)
|
}, orgs)
|
||||||
|
|
||||||
// user itself should get it's org's he is a member of
|
// 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)
|
DecodeJSON(t, resp, &orgs)
|
||||||
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"})
|
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"})
|
||||||
org17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org17"})
|
org17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org17"})
|
||||||
|
org35 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "private_org35"})
|
||||||
|
|
||||||
assert.Equal(t, []*api.Organization{
|
assert.Equal(t, []*api.Organization{
|
||||||
{
|
{
|
||||||
|
@ -128,5 +142,17 @@ func TestMyOrgs(t *testing.T) {
|
||||||
Location: "",
|
Location: "",
|
||||||
Visibility: "public",
|
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)
|
}, orgs)
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ func TestCompareCodeExpand(t *testing.T) {
|
||||||
|
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
session = loginUser(t, user2.Name)
|
session = loginUser(t, user2.Name)
|
||||||
testRepoFork(t, session, user1.Name, repo.Name, user2.Name, "test_blob_excerpt-fork")
|
testRepoFork(t, session, user1.Name, repo.Name, user2.Name, "test_blob_excerpt-fork", "")
|
||||||
testCreateBranch(t, session, user2.Name, "test_blob_excerpt-fork", "branch/main", "forked-branch", http.StatusSeeOther)
|
testCreateBranch(t, session, user2.Name, "test_blob_excerpt-fork", "branch/main", "forked-branch", http.StatusSeeOther)
|
||||||
testEditFile(t, session, user2.Name, "test_blob_excerpt-fork", "forked-branch", "README.md", strings.Repeat("a\n", 15)+"CHANGED\n"+strings.Repeat("a\n", 15))
|
testEditFile(t, session, user2.Name, "test_blob_excerpt-fork", "forked-branch", "README.md", strings.Repeat("a\n", 15)+"CHANGED\n"+strings.Repeat("a\n", 15))
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,11 @@ package integration
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
|
@ -24,6 +26,17 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"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) {
|
func TestEmptyRepo(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
subPaths := []string{
|
subPaths := []string{
|
||||||
|
|
|
@ -485,6 +485,7 @@ func VerifyJSONSchema(t testing.TB, resp *httptest.ResponseRecorder, schemaFile
|
||||||
assert.True(t, result.Valid())
|
assert.True(t, result.Valid())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCSRF returns CSRF token from body
|
||||||
func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
|
func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
req := NewRequest(t, "GET", urlStr)
|
req := NewRequest(t, "GET", urlStr)
|
||||||
|
@ -492,3 +493,11 @@ func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
|
||||||
doc := NewHTMLParser(t, resp.Body)
|
doc := NewHTMLParser(t, resp.Body)
|
||||||
return doc.GetCSRF()
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ func TestPullCompare(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
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)
|
testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther)
|
||||||
testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n")
|
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")
|
testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title")
|
||||||
|
|
|
@ -85,7 +85,7 @@ func testPullCreateDirectly(t *testing.T, session *TestSession, baseRepoOwner, b
|
||||||
func TestPullCreate(t *testing.T) {
|
func TestPullCreate(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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")
|
||||||
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
|
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) {
|
func TestPullCreate_TitleEscape(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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")
|
||||||
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "<i>XSS PR</i>")
|
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)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
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)
|
testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther)
|
||||||
testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n")
|
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")
|
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title")
|
||||||
|
|
|
@ -95,7 +95,7 @@ func TestPullMerge(t *testing.T) {
|
||||||
hookTasksLenBefore := len(hookTasks)
|
hookTasksLenBefore := len(hookTasks)
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
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")
|
||||||
|
|
||||||
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
|
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
|
||||||
|
@ -117,7 +117,7 @@ func TestPullRebase(t *testing.T) {
|
||||||
hookTasksLenBefore := len(hookTasks)
|
hookTasksLenBefore := len(hookTasks)
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
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")
|
||||||
|
|
||||||
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
|
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
|
||||||
|
@ -139,7 +139,7 @@ func TestPullRebaseMerge(t *testing.T) {
|
||||||
hookTasksLenBefore := len(hookTasks)
|
hookTasksLenBefore := len(hookTasks)
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
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")
|
||||||
|
|
||||||
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
|
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
|
||||||
|
@ -161,7 +161,7 @@ func TestPullSquash(t *testing.T) {
|
||||||
hookTasksLenBefore := len(hookTasks)
|
hookTasksLenBefore := len(hookTasks)
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
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")
|
||||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n")
|
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n")
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ func TestPullSquash(t *testing.T) {
|
||||||
func TestPullCleanUpAfterMerge(t *testing.T) {
|
func TestPullCleanUpAfterMerge(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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")
|
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")
|
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "feature/test", "This is a pull title")
|
||||||
|
@ -215,7 +215,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
|
||||||
func TestCantMergeWorkInProgress(t *testing.T) {
|
func TestCantMergeWorkInProgress(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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")
|
||||||
|
|
||||||
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "[wip] This is a pull title")
|
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "[wip] This is a pull title")
|
||||||
|
@ -234,7 +234,7 @@ func TestCantMergeWorkInProgress(t *testing.T) {
|
||||||
func TestCantMergeConflict(t *testing.T) {
|
func TestCantMergeConflict(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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", "conflict", "README.md", "Hello, World (Edited Once)\n")
|
||||||
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n")
|
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n")
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ func TestCantMergeConflict(t *testing.T) {
|
||||||
func TestCantMergeUnrelated(t *testing.T) {
|
func TestCantMergeUnrelated(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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")
|
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
|
// Now we want to create a commit on a branch that is totally unrelated to our current head
|
||||||
|
@ -375,7 +375,7 @@ func TestCantMergeUnrelated(t *testing.T) {
|
||||||
func TestFastForwardOnlyMerge(t *testing.T) {
|
func TestFastForwardOnlyMerge(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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")
|
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "update", "README.md", "Hello, World 2\n")
|
||||||
|
|
||||||
// Use API to create a pr from update to master
|
// Use API to create a pr from update to master
|
||||||
|
@ -416,7 +416,7 @@ func TestFastForwardOnlyMerge(t *testing.T) {
|
||||||
func TestCantFastForwardOnlyMergeDiverging(t *testing.T) {
|
func TestCantFastForwardOnlyMergeDiverging(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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")
|
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")
|
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World 2\n")
|
||||||
|
|
||||||
|
@ -539,7 +539,7 @@ func TestPullRetargetChildOnBranchDelete(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
session := loginUser(t, "user1")
|
||||||
testEditFileToNewBranch(t, session, "user2", "repo1", "master", "base-pr", "README.md", "Hello, World\n(Edited - TestPullRetargetOnCleanup - base PR)\n")
|
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)")
|
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")
|
respBasePR := testPullCreate(t, session, "user2", "repo1", true, "master", "base-pr", "Base Pull Request")
|
||||||
|
@ -568,7 +568,7 @@ func TestPullRetargetChildOnBranchDelete(t *testing.T) {
|
||||||
func TestPullDontRetargetChildOnWrongRepo(t *testing.T) {
|
func TestPullDontRetargetChildOnWrongRepo(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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", "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)")
|
testEditFileToNewBranch(t, session, "user1", "repo1", "base-pr", "child-pr", "README.md", "Hello, World\n(Edited - TestPullDontRetargetChildOnWrongRepo - base PR)\n(Edited - TestPullDontRetargetChildOnWrongRepo - child PR)")
|
||||||
|
|
||||||
|
@ -599,7 +599,7 @@ func TestPullMergeIndexerNotifier(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
// create a pull request
|
// create a pull request
|
||||||
session := loginUser(t, "user1")
|
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")
|
||||||
createPullResp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "Indexer notifier test pull")
|
createPullResp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "Indexer notifier test pull")
|
||||||
|
|
||||||
|
@ -676,7 +676,7 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
|
||||||
session := loginUser(t, "user1")
|
session := loginUser(t, "user1")
|
||||||
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
forkedName := "repo1-1"
|
forkedName := "repo1-1"
|
||||||
testRepoFork(t, session, "user2", "repo1", "user1", forkedName)
|
testRepoFork(t, session, "user2", "repo1", "user1", forkedName, "")
|
||||||
defer func() {
|
defer func() {
|
||||||
testDeleteRepository(t, session, "user1", forkedName)
|
testDeleteRepository(t, session, "user1", forkedName)
|
||||||
}()
|
}()
|
||||||
|
@ -759,7 +759,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
|
||||||
session := loginUser(t, "user1")
|
session := loginUser(t, "user1")
|
||||||
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
forkedName := "repo1-2"
|
forkedName := "repo1-2"
|
||||||
testRepoFork(t, session, "user2", "repo1", "user1", forkedName)
|
testRepoFork(t, session, "user2", "repo1", "user1", forkedName, "")
|
||||||
defer func() {
|
defer func() {
|
||||||
testDeleteRepository(t, session, "user1", forkedName)
|
testDeleteRepository(t, session, "user1", forkedName)
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -186,7 +186,7 @@ func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) {
|
||||||
user2Session := loginUser(t, "user2")
|
user2Session := loginUser(t, "user2")
|
||||||
|
|
||||||
// Have user1 create a fork of repo1.
|
// 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) {
|
t.Run("Submit approve/reject review on merged PR", func(t *testing.T) {
|
||||||
// Create a merged PR (made by user1) in the upstream repo1.
|
// Create a merged PR (made by user1) in the upstream repo1.
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestPullCreate_CommitStatus(t *testing.T) {
|
func TestPullCreate_CommitStatus(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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", "master", "status1", "README.md", "status1")
|
||||||
|
|
||||||
url := path.Join("user1", "repo1", "compare", "master...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.
|
// so we need to have this meta commit also in develop branch.
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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", "master", "status1", "README.md", "status1")
|
||||||
testEditFileToNewBranch(t, session, "user1", "repo1", "status1", "status1", "README.md", "# repo1\n\nDescription for repo1")
|
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) {
|
func TestPullCreate_EmptyChangesWithSameCommits(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
session := loginUser(t, "user1")
|
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)
|
testCreateBranch(t, session, "user1", "repo1", "branch/master", "status1", http.StatusSeeOther)
|
||||||
url := path.Join("user1", "repo1", "compare", "master...status1")
|
url := path.Join("user1", "repo1", "compare", "master...status1")
|
||||||
req := NewRequestWithValues(t, "POST", url,
|
req := NewRequestWithValues(t, "POST", url,
|
||||||
|
|
|
@ -20,7 +20,7 @@ func TestRepoActivity(t *testing.T) {
|
||||||
session := loginUser(t, "user1")
|
session := loginUser(t, "user1")
|
||||||
|
|
||||||
// Create PRs (1 merged & 2 proposed)
|
// 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")
|
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")
|
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
|
||||||
elem := strings.Split(test.RedirectURL(resp), "/")
|
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||||
|
|
|
@ -4,26 +4,37 @@
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"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"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/test"
|
"code.gitea.io/gitea/modules/test"
|
||||||
"code.gitea.io/gitea/modules/translation"
|
"code.gitea.io/gitea/modules/translation"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testCreateBranch(t testing.TB, session *TestSession, user, repo, oldRefSubURL, newBranchName string, expectedStatus int) string {
|
func testCreateBranch(t testing.TB, session *TestSession, user, repo, oldRefSubURL, newBranchName string, expectedStatus int) string {
|
||||||
var csrf string
|
var csrf string
|
||||||
if expectedStatus == http.StatusNotFound {
|
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 {
|
} 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{
|
req := NewRequestWithValues(t, "POST", path.Join(user, repo, "branches/_new", oldRefSubURL), map[string]string{
|
||||||
"_csrf": csrf,
|
"_csrf": csrf,
|
||||||
|
@ -145,3 +156,136 @@ func TestCreateBranchInvalidCSRF(t *testing.T) {
|
||||||
strings.TrimSpace(htmlDoc.doc.Find(".ui.message").Text()),
|
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})
|
||||||
|
testCtx := NewAPITestContext(t, repo10.OwnerName, repo10.Name, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
t.Run("AddUser13AsCollaborator", doAPIAddCollaborator(testCtx, "user13", perm.AccessModeWrite))
|
||||||
|
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"})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"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})
|
forkOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: forkOwnerName})
|
||||||
|
|
||||||
// Step0: check the existence of the to-fork repo
|
// 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")
|
_, 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))
|
assert.True(t, exists, fmt.Sprintf("Fork owner '%s' is not present in select box", forkOwnerName))
|
||||||
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
||||||
"_csrf": htmlDoc.GetCSRF(),
|
"_csrf": htmlDoc.GetCSRF(),
|
||||||
"uid": fmt.Sprintf("%d", forkOwner.ID),
|
"uid": fmt.Sprintf("%d", forkOwner.ID),
|
||||||
"repo_name": forkRepoName,
|
"repo_name": forkRepoName,
|
||||||
|
"fork_single_branch": forkBranch,
|
||||||
})
|
})
|
||||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
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) {
|
func TestRepoFork(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
session := loginUser(t, "user1")
|
session := loginUser(t, "user1")
|
||||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRepoForkToOrg(t *testing.T) {
|
func TestRepoForkToOrg(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
session := loginUser(t, "user2")
|
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
|
// Check that no more forking is allowed as user2 owns repository
|
||||||
// and org3 organization that owner user2 is also now has forked this repository
|
// and org3 organization that owner user2 is also now has forked this repository
|
||||||
|
|
Loading…
Reference in a new issue