Skip to content

Commit 2361ec5

Browse files
committed
Improvements for creating branch model
1 parent 62fda25 commit 2361ec5

File tree

11 files changed

+149
-53
lines changed

11 files changed

+149
-53
lines changed

models/issues/issue_dev_link.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ type IssueDevLink struct {
2828
LinkIndex string // branch name, pull request number or commit sha
2929
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
3030

31-
LinkedRepo *repo_model.Repository `xorm:"-"`
32-
PullRequest *PullRequest `xorm:"-"`
33-
Branch *git_model.Branch `xorm:"-"`
31+
LinkedRepo *repo_model.Repository `xorm:"-"`
32+
PullRequest *PullRequest `xorm:"-"`
33+
Branch *git_model.Branch `xorm:"-"`
34+
DisplayBranch bool `xorm:"-"`
3435
}
3536

3637
func init() {

models/migrations/v1_23/v305.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ import (
1111

1212
func CreateTableIssueDevLink(x *xorm.Engine) error {
1313
type IssueDevLink struct {
14-
ID int64 `xorm:"pk autoincr"`
15-
IssueID int64 `xorm:"INDEX"`
16-
LinkType int
17-
LinkIndex string // branch name, pull request number or commit sha
18-
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
14+
ID int64 `xorm:"pk autoincr"`
15+
IssueID int64 `xorm:"INDEX"`
16+
LinkType int
17+
LinkedRepoID int64 `xorm:"INDEX"` // it can link to self repo or other repo
18+
LinkIndex string // branch name, pull request number or commit sha
19+
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
1920
}
2021
return x.Sync(new(IssueDevLink))
2122
}

options/locale/locale_en-US.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,8 @@ issues.label.filter_sort.reverse_alphabetically = Reverse alphabetically
16231623
issues.label.filter_sort.by_size = Smallest size
16241624
issues.label.filter_sort.reverse_by_size = Largest size
16251625
issues.development = Development
1626+
issues.maybefixed = May be fixed by %s
1627+
issues.create_branch_from_issue_success = Create branch %s from issue successfully
16261628
issues.num_participants = %d Participants
16271629
issues.attachment.open_tab = `Click to see "%s" in a new tab`
16281630
issues.attachment.download = `Click to download "%s"`

routers/web/repo/issue.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2085,10 +2085,18 @@ func ViewIssue(ctx *context.Context) {
20852085

20862086
devLinks, err := issue_service.FindIssueDevLinksByIssue(ctx, issue)
20872087
if err != nil {
2088-
ctx.ServerError("FindIssueDevLinksByIssueID", err)
2088+
ctx.ServerError("FindIssueDevLinksByIssue", err)
20892089
return
20902090
}
20912091
ctx.Data["DevLinks"] = devLinks
2092+
for _, link := range devLinks {
2093+
if link.LinkType == issues_model.IssueDevLinkTypePullRequest {
2094+
if !(link.PullRequest.Issue.IsClosed && !link.PullRequest.HasMerged) {
2095+
ctx.Data["MaybeFixed"] = link.PullRequest
2096+
break
2097+
}
2098+
}
2099+
}
20922100

20932101
ctx.HTML(http.StatusOK, tplIssueView)
20942102
}

routers/web/repo/issue_dev.go

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
package repo
55

66
import (
7-
"net/http"
8-
7+
git_model "code.gitea.io/gitea/models/git"
98
issues_model "code.gitea.io/gitea/models/issues"
9+
access_model "code.gitea.io/gitea/models/perm/access"
10+
repo_model "code.gitea.io/gitea/models/repo"
11+
unit_model "code.gitea.io/gitea/models/unit"
12+
"code.gitea.io/gitea/modules/git"
13+
"code.gitea.io/gitea/modules/gitrepo"
1014
"code.gitea.io/gitea/modules/web"
15+
"code.gitea.io/gitea/routers/utils"
1116
"code.gitea.io/gitea/services/context"
1217
"code.gitea.io/gitea/services/forms"
1318
repo_service "code.gitea.io/gitea/services/repository"
@@ -21,36 +26,84 @@ func CreateBranchFromIssue(ctx *context.Context) {
2126

2227
if issue.IsPull {
2328
ctx.Flash.Error(ctx.Tr("repo.issues.create_branch_from_issue_error_is_pull"))
24-
ctx.Redirect(issue.Link(), http.StatusSeeOther)
29+
ctx.JSONRedirect(issue.Link())
2530
return
2631
}
2732

2833
form := web.GetForm(ctx).(*forms.NewBranchForm)
29-
if !ctx.Repo.CanCreateBranch() {
34+
repo := ctx.Repo.Repository
35+
gitRepo := ctx.Repo.GitRepo
36+
if form.RepoID > 0 {
37+
var err error
38+
repo, err = repo_model.GetRepositoryByID(ctx, form.RepoID)
39+
if err != nil {
40+
ctx.ServerError("GetRepositoryByID", err)
41+
return
42+
}
43+
gitRepo, err = gitrepo.OpenRepository(ctx, repo)
44+
if err != nil {
45+
ctx.ServerError("GetRepositoryByID", err)
46+
return
47+
}
48+
defer gitRepo.Close()
49+
}
50+
51+
perm, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
52+
if err != nil {
53+
ctx.ServerError("GetRepositoryByID", err)
54+
return
55+
}
56+
57+
canCreateBranch := perm.CanWrite(unit_model.TypeCode) && repo.CanCreateBranch()
58+
if !canCreateBranch {
3059
ctx.NotFound("CreateBranch", nil)
3160
return
3261
}
3362

3463
if ctx.HasError() {
35-
ctx.Flash.Error(ctx.GetErrMsg())
36-
ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
64+
ctx.JSONError(ctx.GetErrMsg())
3765
return
3866
}
3967

40-
if err := repo_service.CreateNewBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, form.SourceBranchName, form.NewBranchName); err != nil {
41-
handleCreateBranchError(ctx, err, form)
68+
if err := repo_service.CreateNewBranch(ctx, ctx.Doer, repo, gitRepo, form.SourceBranchName, form.NewBranchName); err != nil {
69+
switch {
70+
case git_model.IsErrBranchAlreadyExists(err) || git.IsErrPushOutOfDate(err):
71+
ctx.JSONError(ctx.Tr("repo.branch.branch_already_exists", form.NewBranchName))
72+
case git_model.IsErrBranchNameConflict(err):
73+
e := err.(git_model.ErrBranchNameConflict)
74+
ctx.JSONError(ctx.Tr("repo.branch.branch_name_conflict", form.NewBranchName, e.BranchName))
75+
case git.IsErrPushRejected(err):
76+
e := err.(*git.ErrPushRejected)
77+
if len(e.Message) == 0 {
78+
ctx.Flash.Error(ctx.Tr("repo.editor.push_rejected_no_message"))
79+
} else {
80+
flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
81+
"Message": ctx.Tr("repo.editor.push_rejected"),
82+
"Summary": ctx.Tr("repo.editor.push_rejected_summary"),
83+
"Details": utils.SanitizeFlashErrorString(e.Message),
84+
})
85+
if err != nil {
86+
ctx.ServerError("UpdatePullRequest.HTMLString", err)
87+
return
88+
}
89+
ctx.JSONError(flashError)
90+
}
91+
default:
92+
ctx.ServerError("CreateNewBranch", err)
93+
}
4294
return
4395
}
4496

4597
if err := issues_model.CreateIssueDevLink(ctx, &issues_model.IssueDevLink{
4698
IssueID: issue.ID,
4799
LinkType: issues_model.IssueDevLinkTypeBranch,
100+
LinkedRepoID: repo.ID,
48101
LinkIndex: form.NewBranchName,
49102
}); err != nil {
50103
ctx.ServerError("CreateIssueDevLink", err)
51104
return
52105
}
53106

54107
ctx.Flash.Success(ctx.Tr("repo.issues.create_branch_from_issue_success", ctx.Repo.BranchName))
55-
ctx.Redirect(issue.Link())
108+
ctx.JSONRedirect(issue.Link())
56109
}

services/forms/repo_branch_form.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
// NewBranchForm form for creating a new branch
1616
type NewBranchForm struct {
1717
NewBranchName string `binding:"Required;MaxSize(100);GitRefName"`
18+
RepoID int64
1819
SourceBranchName string
1920
CurrentPath string
2021
CreateTag bool

services/issue/dev_link.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ package issue
55

66
import (
77
"context"
8+
"fmt"
9+
"sort"
810
"strconv"
911

1012
git_model "code.gitea.io/gitea/models/git"
1113
issues_model "code.gitea.io/gitea/models/issues"
1214
repo_model "code.gitea.io/gitea/models/repo"
15+
"code.gitea.io/gitea/modules/container"
1316
)
1417

1518
func FindIssueDevLinksByIssue(ctx context.Context, issue *issues_model.Issue) (issues_model.IssueDevLinks, error) {
@@ -22,6 +25,17 @@ func FindIssueDevLinksByIssue(ctx context.Context, issue *issues_model.Issue) (i
2225
return nil, err
2326
}
2427

28+
sort.Slice(devLinks, func(i, j int) bool {
29+
switch {
30+
case devLinks[j].LinkType == issues_model.IssueDevLinkTypePullRequest:
31+
return false
32+
default:
33+
return true
34+
}
35+
})
36+
37+
branchPRExists := make(container.Set[string])
38+
2539
for _, link := range devLinks {
2640
if link.LinkedRepoID == 0 {
2741
link.LinkedRepoID = issue.RepoID
@@ -47,16 +61,22 @@ func FindIssueDevLinksByIssue(ctx context.Context, issue *issues_model.Issue) (i
4761
if err != nil {
4862
return nil, err
4963
}
64+
pull.BaseRepo = issue.Repo
65+
pull.HeadRepo = link.LinkedRepo
66+
if err := pull.LoadIssue(ctx); err != nil {
67+
return nil, err
68+
}
69+
pull.Issue.Repo = issue.Repo
5070
link.PullRequest = pull
51-
link.PullRequest.Issue = issue
52-
link.PullRequest.BaseRepo = issue.Repo
71+
branchPRExists.Add(fmt.Sprintf("%d-%s", link.LinkedRepoID, pull.HeadBranch))
5372
case issues_model.IssueDevLinkTypeBranch:
5473
branch, err := git_model.GetBranch(ctx, link.LinkedRepoID, link.LinkIndex)
5574
if err != nil {
5675
return nil, err
5776
}
5877
link.Branch = branch
5978
link.Branch.Repo = link.LinkedRepo
79+
link.DisplayBranch = !branchPRExists.Contains(fmt.Sprintf("%d-%s", link.LinkedRepoID, link.LinkIndex))
6080
}
6181
}
6282

services/pull/pull.go

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,31 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *iss
128128
return err
129129
}
130130

131+
if !pr.IsWorkInProgress(ctx) {
132+
reviewNotifiers, err = issue_service.PullRequestCodeOwnersReview(ctx, issue, pr)
133+
if err != nil {
134+
return err
135+
}
136+
}
137+
138+
if pr.Flow == issues_model.PullRequestFlowGithub {
139+
devLinks, err := issues_model.FindDevLinksByBranch(ctx, issue.RepoID, pr.HeadRepoID, pr.HeadBranch)
140+
if err != nil {
141+
return err
142+
}
143+
for _, link := range devLinks {
144+
if err := issues_model.CreateIssueDevLink(ctx, &issues_model.IssueDevLink{
145+
IssueID: link.IssueID,
146+
LinkType: issues_model.IssueDevLinkTypePullRequest,
147+
LinkedRepoID: pr.HeadRepoID,
148+
LinkIndex: strconv.FormatInt(pr.ID, 10),
149+
}); err != nil {
150+
return err
151+
}
152+
}
153+
}
154+
155+
// leave creating comment last
131156
compareInfo, err := baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(),
132157
git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName(), false, false)
133158
if err != nil {
@@ -161,30 +186,6 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *iss
161186
return err
162187
}
163188

164-
if !pr.IsWorkInProgress(ctx) {
165-
reviewNotifiers, err = issue_service.PullRequestCodeOwnersReview(ctx, issue, pr)
166-
if err != nil {
167-
return err
168-
}
169-
}
170-
171-
if pr.Flow == issues_model.PullRequestFlowGithub {
172-
devLinks, err := issues_model.FindDevLinksByBranch(ctx, issue.RepoID, pr.HeadRepoID, pr.HeadBranch)
173-
if err != nil {
174-
return err
175-
}
176-
for _, link := range devLinks {
177-
if err := issues_model.CreateIssueDevLink(ctx, &issues_model.IssueDevLink{
178-
IssueID: link.IssueID,
179-
LinkType: issues_model.IssueDevLinkTypePullRequest,
180-
LinkedRepoID: pr.HeadRepoID,
181-
LinkIndex: strconv.FormatInt(pr.ID, 10),
182-
}); err != nil {
183-
return err
184-
}
185-
}
186-
}
187-
188189
return nil
189190
}); err != nil {
190191
// cleanup: this will only remove the reference, the real commit will be clean up when next GC

templates/repo/issue/view_content/sidebar.tmpl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,10 @@
253253
</div>
254254
</div>
255255

256-
<div class="divider"></div>
257-
258-
{{template "repo/issue/view_content/sidebar_development" .}}
256+
{{if not .Issue.IsPull}}
257+
<div class="divider"></div>
258+
{{template "repo/issue/view_content/sidebar_development" .}}
259+
{{end}}
259260

260261
<div class="divider"></div>
261262

templates/repo/issue/view_content/sidebar_development.tmpl

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,30 @@
55
{{end}}
66
{{range .DevLinks}}
77
{{if .PullRequest}}
8+
<span>{{template "shared/issueicon" .PullRequest.Issue}}
89
<a href="{{.PullRequest.Issue.Link}}" class="item">
910
{{.PullRequest.Issue.Title}}
1011
</a>
11-
Created {{.PullRequest.Issue.CreatedAt}}
12+
</span>
13+
<div>
14+
Created {{DateTime "short" .PullRequest.Issue.CreatedUnix}}
1215
{{if .PullRequest.HasMerged}}
1316
Completed
1417
{{.PullRequest.MergedCommitID}}
1518
Created {{.PullRequest.MergedUnix}}
1619
{{else if .PullRequest.ChangedProtectedFiles}}
1720
Merge conflicts
1821
{{end}}
19-
{{else if .Branch}}
22+
</div>
23+
{{else if and .Branch .DisplayBranch}}
2024
<span>
2125
{{svg "octicon-git-branch" 14}}
22-
<a href="{{.Branch}}" class="item">
26+
<a href="{{.Branch.Repo.Link}}/src/branch/{{.Branch.Name}}" class="item">
2327
<span class="gt-ellipsis">{{.Branch.Name}}</span>
2428
</a>
2529
</span>
2630
<div>Latest commit {{DateTime "short" .Branch.CommitTime}}</div>
27-
<a href="{{$.Issue.Repo.Link}}/compare/main...{{.Branch.Name}}">{{ctx.Locale.Tr "repo.pulls.new"}}</a>
31+
<a href="{{$.Issue.Repo.Link}}/compare/{{$.Issue.Repo.DefaultBranch}}...{{.Branch.Repo.FullName}}:{{.Branch.Name}}">{{ctx.Locale.Tr "repo.pulls.new"}}</a>
2832
{{end}}
2933
{{end}}
3034
</div>
@@ -45,7 +49,7 @@
4549
<div class="field">
4650
<label for="source_repository">{{ctx.Locale.Tr "repository"}}</label>
4751
<div class="ui fluid dropdown selection">
48-
<select name="source_repository">
52+
<select name="repo_id">
4953
<option value=""> </option>
5054
{{range .AllowedRepos}}
5155
<option value="{{.ID}}">{{.FullName}}</option>
@@ -86,7 +90,7 @@
8690

8791
<div class="text right actions">
8892
<button class="ui cancel button">{{ctx.Locale.Tr "settings.cancel"}}</button>
89-
<button class="ui red button">{{ctx.Locale.Tr "repo.branch.new_branch"}}</button>
93+
<button class="ui primary button">{{ctx.Locale.Tr "repo.branch.new_branch"}}</button>
9094
</div>
9195
</form>
9296
</div>

0 commit comments

Comments
 (0)