Skip to content

Commit 490f49b

Browse files
committed
Merge 'main' into add-status-popup-to-issuelist
2 parents 5134f1c + 0dfc2e5 commit 490f49b

File tree

17 files changed

+217
-106
lines changed

17 files changed

+217
-106
lines changed

integrations/pull_merge_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"code.gitea.io/gitea/modules/test"
2727
"code.gitea.io/gitea/modules/translation/i18n"
2828
"code.gitea.io/gitea/services/pull"
29+
repo_service "code.gitea.io/gitea/services/repository"
30+
files_service "code.gitea.io/gitea/services/repository/files"
2931

3032
"github.com/stretchr/testify/assert"
3133
)
@@ -346,3 +348,74 @@ func TestCantMergeUnrelated(t *testing.T) {
346348
gitRepo.Close()
347349
})
348350
}
351+
352+
func TestConflictChecking(t *testing.T) {
353+
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
354+
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
355+
356+
// Create new clean repo to test conflict checking.
357+
baseRepo, err := repo_service.CreateRepository(user, user, models.CreateRepoOptions{
358+
Name: "conflict-checking",
359+
Description: "Tempo repo",
360+
AutoInit: true,
361+
Readme: "Default",
362+
DefaultBranch: "main",
363+
})
364+
assert.NoError(t, err)
365+
assert.NotEmpty(t, baseRepo)
366+
367+
// create a commit on new branch.
368+
_, err = files_service.CreateOrUpdateRepoFile(git.DefaultContext, baseRepo, user, &files_service.UpdateRepoFileOptions{
369+
TreePath: "important_file",
370+
Message: "Add a important file",
371+
Content: "Just a non-important file",
372+
IsNewFile: true,
373+
OldBranch: "main",
374+
NewBranch: "important-secrets",
375+
})
376+
assert.NoError(t, err)
377+
378+
// create a commit on main branch.
379+
_, err = files_service.CreateOrUpdateRepoFile(git.DefaultContext, baseRepo, user, &files_service.UpdateRepoFileOptions{
380+
TreePath: "important_file",
381+
Message: "Add a important file",
382+
Content: "Not the same content :P",
383+
IsNewFile: true,
384+
OldBranch: "main",
385+
NewBranch: "main",
386+
})
387+
assert.NoError(t, err)
388+
389+
// create Pull to merge the important-secrets branch into main branch.
390+
pullIssue := &models.Issue{
391+
RepoID: baseRepo.ID,
392+
Title: "PR with conflict!",
393+
PosterID: user.ID,
394+
Poster: user,
395+
IsPull: true,
396+
}
397+
398+
pullRequest := &models.PullRequest{
399+
HeadRepoID: baseRepo.ID,
400+
BaseRepoID: baseRepo.ID,
401+
HeadBranch: "important-secrets",
402+
BaseBranch: "main",
403+
HeadRepo: baseRepo,
404+
BaseRepo: baseRepo,
405+
Type: models.PullRequestGitea,
406+
}
407+
err = pull.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil)
408+
assert.NoError(t, err)
409+
410+
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{Title: "PR with conflict!"}).(*models.Issue)
411+
conflictingPR, err := models.GetPullRequestByIssueID(issue.ID)
412+
assert.NoError(t, err)
413+
414+
// Ensure conflictedFiles is populated.
415+
assert.Equal(t, 1, len(conflictingPR.ConflictedFiles))
416+
// Check if status is correct.
417+
assert.Equal(t, models.PullRequestStatusConflict, conflictingPR.Status)
418+
// Ensure that mergeable returns false
419+
assert.False(t, conflictingPR.Mergeable())
420+
})
421+
}

models/pull.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,3 +701,14 @@ func (pr *PullRequest) GetHeadBranchHTMLURL() string {
701701
}
702702
return pr.HeadRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch)
703703
}
704+
705+
// Mergeable returns if the pullrequest is mergeable.
706+
func (pr *PullRequest) Mergeable() bool {
707+
// If a pull request isn't mergable if it's:
708+
// - Being conflict checked.
709+
// - Has a conflict.
710+
// - Received a error while being conflict checked.
711+
// - Is a work-in-progress pull request.
712+
return pr.Status != PullRequestStatusChecking && pr.Status != PullRequestStatusConflict &&
713+
pr.Status != PullRequestStatusError && !pr.IsWorkInProgress()
714+
}

modules/context/api.go

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -285,36 +285,6 @@ func APIContexter() func(http.Handler) http.Handler {
285285
}
286286
}
287287

288-
// ReferencesGitRepo injects the GitRepo into the Context
289-
func ReferencesGitRepo(allowEmpty bool) func(ctx *APIContext) (cancel context.CancelFunc) {
290-
return func(ctx *APIContext) (cancel context.CancelFunc) {
291-
// Empty repository does not have reference information.
292-
if !allowEmpty && ctx.Repo.Repository.IsEmpty {
293-
return
294-
}
295-
296-
// For API calls.
297-
if ctx.Repo.GitRepo == nil {
298-
repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
299-
gitRepo, err := git.OpenRepository(ctx, repoPath)
300-
if err != nil {
301-
ctx.Error(http.StatusInternalServerError, "RepoRef Invalid repo "+repoPath, err)
302-
return
303-
}
304-
ctx.Repo.GitRepo = gitRepo
305-
// We opened it, we should close it
306-
return func() {
307-
// If it's been set to nil then assume someone else has closed it.
308-
if ctx.Repo.GitRepo != nil {
309-
ctx.Repo.GitRepo.Close()
310-
}
311-
}
312-
}
313-
314-
return
315-
}
316-
}
317-
318288
// NotFound handles 404s for APIContext
319289
// String will replace message, errors will be added to a slice
320290
func (ctx *APIContext) NotFound(objs ...interface{}) {
@@ -340,33 +310,62 @@ func (ctx *APIContext) NotFound(objs ...interface{}) {
340310
})
341311
}
342312

343-
// RepoRefForAPI handles repository reference names when the ref name is not explicitly given
344-
func RepoRefForAPI(next http.Handler) http.Handler {
345-
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
346-
ctx := GetAPIContext(req)
313+
// ReferencesGitRepo injects the GitRepo into the Context
314+
// you can optional skip the IsEmpty check
315+
func ReferencesGitRepo(allowEmpty ...bool) func(ctx *APIContext) (cancel context.CancelFunc) {
316+
return func(ctx *APIContext) (cancel context.CancelFunc) {
347317
// Empty repository does not have reference information.
348-
if ctx.Repo.Repository.IsEmpty {
318+
if ctx.Repo.Repository.IsEmpty && !(len(allowEmpty) != 0 && allowEmpty[0]) {
349319
return
350320
}
351321

352-
var err error
353-
322+
// For API calls.
354323
if ctx.Repo.GitRepo == nil {
355324
repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
356-
ctx.Repo.GitRepo, err = git.OpenRepository(ctx, repoPath)
325+
gitRepo, err := git.OpenRepository(ctx, repoPath)
357326
if err != nil {
358-
ctx.InternalServerError(err)
327+
ctx.Error(http.StatusInternalServerError, "RepoRef Invalid repo "+repoPath, err)
359328
return
360329
}
330+
ctx.Repo.GitRepo = gitRepo
361331
// We opened it, we should close it
362-
defer func() {
332+
return func() {
363333
// If it's been set to nil then assume someone else has closed it.
364334
if ctx.Repo.GitRepo != nil {
365335
ctx.Repo.GitRepo.Close()
366336
}
367-
}()
337+
}
338+
}
339+
340+
return
341+
}
342+
}
343+
344+
// RepoRefForAPI handles repository reference names when the ref name is not explicitly given
345+
func RepoRefForAPI(next http.Handler) http.Handler {
346+
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
347+
ctx := GetAPIContext(req)
348+
349+
if ctx.Repo.GitRepo == nil {
350+
ctx.InternalServerError(fmt.Errorf("no open git repo"))
351+
return
352+
}
353+
354+
if ref := ctx.FormTrim("ref"); len(ref) > 0 {
355+
commit, err := ctx.Repo.GitRepo.GetCommit(ref)
356+
if err != nil {
357+
if git.IsErrNotExist(err) {
358+
ctx.NotFound()
359+
} else {
360+
ctx.Error(http.StatusInternalServerError, "GetBlobByPath", err)
361+
}
362+
return
363+
}
364+
ctx.Repo.Commit = commit
365+
return
368366
}
369367

368+
var err error
370369
refName := getRefName(ctx.Context, RepoRefAny)
371370

372371
if ctx.Repo.GitRepo.IsBranchExist(refName) {

modules/context/repo.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,21 @@ func (r *Repository) FileExists(path, branch string) (bool, error) {
221221

222222
// GetEditorconfig returns the .editorconfig definition if found in the
223223
// HEAD of the default repo branch.
224-
func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) {
224+
func (r *Repository) GetEditorconfig(optCommit ...*git.Commit) (*editorconfig.Editorconfig, error) {
225225
if r.GitRepo == nil {
226226
return nil, nil
227227
}
228-
commit, err := r.GitRepo.GetBranchCommit(r.Repository.DefaultBranch)
229-
if err != nil {
230-
return nil, err
228+
var (
229+
err error
230+
commit *git.Commit
231+
)
232+
if len(optCommit) != 0 {
233+
commit = optCommit[0]
234+
} else {
235+
commit, err = r.GitRepo.GetBranchCommit(r.Repository.DefaultBranch)
236+
if err != nil {
237+
return nil, err
238+
}
231239
}
232240
treeEntry, err := commit.GetTreeEntryByPath(".editorconfig")
233241
if err != nil {
@@ -407,6 +415,12 @@ func RepoIDAssignment() func(ctx *Context) {
407415

408416
// RepoAssignment returns a middleware to handle repository assignment
409417
func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
418+
if _, repoAssignmentOnce := ctx.Data["repoAssignmentExecuted"]; repoAssignmentOnce {
419+
log.Trace("RepoAssignment was exec already, skipping second call ...")
420+
return
421+
}
422+
ctx.Data["repoAssignmentExecuted"] = true
423+
410424
var (
411425
owner *user_model.User
412426
err error
@@ -602,6 +616,9 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
602616
ctx.ServerError("RepoAssignment Invalid repo "+repo_model.RepoPath(userName, repoName), err)
603617
return
604618
}
619+
if ctx.Repo.GitRepo != nil {
620+
ctx.Repo.GitRepo.Close()
621+
}
605622
ctx.Repo.GitRepo = gitRepo
606623

607624
// We opened it, we should close it

modules/convert/pull.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_mo
6868
PatchURL: pr.Issue.PatchURL(),
6969
HasMerged: pr.HasMerged,
7070
MergeBase: pr.MergeBase,
71+
Mergeable: pr.Mergeable(),
7172
Deadline: apiIssue.Deadline,
7273
Created: pr.Issue.CreatedUnix.AsTimePtr(),
7374
Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
@@ -191,10 +192,6 @@ func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_mo
191192
}
192193
}
193194

194-
if pr.Status != models.PullRequestStatusChecking {
195-
mergeable := !(pr.Status == models.PullRequestStatusConflict || pr.Status == models.PullRequestStatusError) && !pr.IsWorkInProgress()
196-
apiPullRequest.Mergeable = mergeable
197-
}
198195
if pr.HasMerged {
199196
apiPullRequest.Merged = pr.MergedUnix.AsTimePtr()
200197
apiPullRequest.MergedCommitID = &pr.MergedCommitID

options/locale/locale_pt-BR.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,6 +1944,7 @@ settings.event_pull_request_review_desc=Pull request aprovado, rejeitado ou revi
19441944
settings.event_pull_request_sync=Pull Request Sincronizado
19451945
settings.event_pull_request_sync_desc=Pull request sincronizado.
19461946
settings.event_package=Pacote
1947+
settings.event_package_desc=Pacote criado ou excluído em um repositório.
19471948
settings.branch_filter=Filtro de branch
19481949
settings.branch_filter_desc=Lista dos branches a serem considerados nos eventos push, criação de branch e exclusão de branch, especificados como padrão glob. Se estiver vazio ou for <code>*</code>, eventos para todos os branches serão relatados. Veja <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> documentação da sintaxe. Exemplos: <code>master</code>, <code>{master,release*}</code>.
19491950
settings.active=Ativo

routers/api/v1/api.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ func Routes() *web.Route {
796796
m.Combo("").Get(repo.GetHook).
797797
Patch(bind(api.EditHookOption{}), repo.EditHook).
798798
Delete(repo.DeleteHook)
799-
m.Post("/tests", context.RepoRefForAPI, repo.TestHook)
799+
m.Post("/tests", context.ReferencesGitRepo(), context.RepoRefForAPI, repo.TestHook)
800800
})
801801
}, reqToken(), reqAdmin(), reqWebhooksEnabled())
802802
m.Group("/collaborators", func() {
@@ -813,16 +813,16 @@ func Routes() *web.Route {
813813
Put(reqAdmin(), repo.AddTeam).
814814
Delete(reqAdmin(), repo.DeleteTeam)
815815
}, reqToken())
816-
m.Get("/raw/*", context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFile)
816+
m.Get("/raw/*", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFile)
817817
m.Get("/archive/*", reqRepoReader(unit.TypeCode), repo.GetArchive)
818818
m.Combo("/forks").Get(repo.ListForks).
819819
Post(reqToken(), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
820820
m.Group("/branches", func() {
821-
m.Get("", context.ReferencesGitRepo(false), repo.ListBranches)
822-
m.Get("/*", context.ReferencesGitRepo(false), repo.GetBranch)
823-
m.Delete("/*", reqRepoWriter(unit.TypeCode), context.ReferencesGitRepo(false), repo.DeleteBranch)
824-
m.Post("", reqRepoWriter(unit.TypeCode), context.ReferencesGitRepo(false), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
825-
}, reqRepoReader(unit.TypeCode))
821+
m.Get("", repo.ListBranches)
822+
m.Get("/*", repo.GetBranch)
823+
m.Delete("/*", reqRepoWriter(unit.TypeCode), repo.DeleteBranch)
824+
m.Post("", reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
825+
}, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode))
826826
m.Group("/branch_protections", func() {
827827
m.Get("", repo.ListBranchProtections)
828828
m.Post("", bind(api.CreateBranchProtectionOption{}), repo.CreateBranchProtection)
@@ -941,10 +941,10 @@ func Routes() *web.Route {
941941
})
942942
m.Group("/releases", func() {
943943
m.Combo("").Get(repo.ListReleases).
944-
Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(false), bind(api.CreateReleaseOption{}), repo.CreateRelease)
944+
Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
945945
m.Group("/{id}", func() {
946946
m.Combo("").Get(repo.GetRelease).
947-
Patch(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(false), bind(api.EditReleaseOption{}), repo.EditRelease).
947+
Patch(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease).
948948
Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteRelease)
949949
m.Group("/assets", func() {
950950
m.Combo("").Get(repo.ListReleaseAttachments).
@@ -961,7 +961,7 @@ func Routes() *web.Route {
961961
})
962962
}, reqRepoReader(unit.TypeReleases))
963963
m.Post("/mirror-sync", reqToken(), reqRepoWriter(unit.TypeCode), repo.MirrorSync)
964-
m.Get("/editorconfig/{filename}", context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetEditorconfig)
964+
m.Get("/editorconfig/{filename}", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetEditorconfig)
965965
m.Group("/pulls", func() {
966966
m.Combo("").Get(repo.ListPullRequests).
967967
Post(reqToken(), mustNotBeArchived, bind(api.CreatePullRequestOption{}), repo.CreatePullRequest)
@@ -992,30 +992,30 @@ func Routes() *web.Route {
992992
Delete(reqToken(), bind(api.PullReviewRequestOptions{}), repo.DeleteReviewRequests).
993993
Post(reqToken(), bind(api.PullReviewRequestOptions{}), repo.CreateReviewRequests)
994994
})
995-
}, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(false))
995+
}, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo())
996996
m.Group("/statuses", func() {
997997
m.Combo("/{sha}").Get(repo.GetCommitStatuses).
998998
Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
999999
}, reqRepoReader(unit.TypeCode))
10001000
m.Group("/commits", func() {
1001-
m.Get("", context.ReferencesGitRepo(false), repo.GetAllCommits)
1001+
m.Get("", context.ReferencesGitRepo(), repo.GetAllCommits)
10021002
m.Group("/{ref}", func() {
10031003
m.Get("/status", repo.GetCombinedCommitStatusByRef)
10041004
m.Get("/statuses", repo.GetCommitStatusesByRef)
10051005
})
10061006
}, reqRepoReader(unit.TypeCode))
10071007
m.Group("/git", func() {
10081008
m.Group("/commits", func() {
1009-
m.Get("/{sha}", context.ReferencesGitRepo(false), repo.GetSingleCommit)
1009+
m.Get("/{sha}", repo.GetSingleCommit)
10101010
m.Get("/{sha}.{diffType:diff|patch}", repo.DownloadCommitDiffOrPatch)
10111011
})
10121012
m.Get("/refs", repo.GetGitAllRefs)
10131013
m.Get("/refs/*", repo.GetGitRefs)
1014-
m.Get("/trees/{sha}", context.RepoRefForAPI, repo.GetTree)
1015-
m.Get("/blobs/{sha}", context.RepoRefForAPI, repo.GetBlob)
1016-
m.Get("/tags/{sha}", context.RepoRefForAPI, repo.GetAnnotatedTag)
1014+
m.Get("/trees/{sha}", repo.GetTree)
1015+
m.Get("/blobs/{sha}", repo.GetBlob)
1016+
m.Get("/tags/{sha}", repo.GetAnnotatedTag)
10171017
m.Get("/notes/{sha}", repo.GetNote)
1018-
}, reqRepoReader(unit.TypeCode))
1018+
}, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode))
10191019
m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), repo.ApplyDiffPatch)
10201020
m.Group("/contents", func() {
10211021
m.Get("", repo.GetContentsList)
@@ -1035,7 +1035,7 @@ func Routes() *web.Route {
10351035
Delete(reqToken(), repo.DeleteTopic)
10361036
}, reqAdmin())
10371037
}, reqAnyRepoReader())
1038-
m.Get("/issue_templates", context.ReferencesGitRepo(false), repo.GetIssueTemplates)
1038+
m.Get("/issue_templates", context.ReferencesGitRepo(), repo.GetIssueTemplates)
10391039
m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages)
10401040
}, repoAssignment())
10411041
})

routers/api/v1/repo/blob.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ func GetBlob(ctx *context.APIContext) {
4545
ctx.Error(http.StatusBadRequest, "", "sha not provided")
4646
return
4747
}
48-
if blob, err := files_service.GetBlobBySHA(ctx, ctx.Repo.Repository, sha); err != nil {
48+
49+
if blob, err := files_service.GetBlobBySHA(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, sha); err != nil {
4950
ctx.Error(http.StatusBadRequest, "", err)
5051
} else {
5152
ctx.JSON(http.StatusOK, blob)

0 commit comments

Comments
 (0)