Add API to manage issue dependencies (#17935)

Adds API endpoints to manage issue/PR dependencies
* `GET /repos/{owner}/{repo}/issues/{index}/blocks` List issues that are
blocked by this issue
* `POST /repos/{owner}/{repo}/issues/{index}/blocks` Block the issue
given in the body by the issue in path
* `DELETE /repos/{owner}/{repo}/issues/{index}/blocks` Unblock the issue
given in the body by the issue in path
* `GET /repos/{owner}/{repo}/issues/{index}/dependencies` List an
issue's dependencies
* `POST /repos/{owner}/{repo}/issues/{index}/dependencies` Create a new
issue dependencies
* `DELETE /repos/{owner}/{repo}/issues/{index}/dependencies` Remove an
issue dependency

Closes https://github.com/go-gitea/gitea/issues/15393
Closes #22115

Co-authored-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
qwerty287 2023-03-28 19:23:25 +02:00 committed by GitHub
parent 85e8c837b8
commit 3cab9c6b0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 1074 additions and 34 deletions

View file

@ -1812,17 +1812,27 @@ func ViewIssue(ctx *context.Context) {
}
// Get Dependencies
ctx.Data["BlockedByDependencies"], err = issue.BlockedByDependencies(ctx)
blockedBy, err := issue.BlockedByDependencies(ctx, db.ListOptions{})
if err != nil {
ctx.ServerError("BlockedByDependencies", err)
return
}
ctx.Data["BlockingDependencies"], err = issue.BlockingDependencies(ctx)
ctx.Data["BlockedByDependencies"], ctx.Data["BlockedByDependenciesNotPermitted"] = checkBlockedByIssues(ctx, blockedBy)
if ctx.Written() {
return
}
blocking, err := issue.BlockingDependencies(ctx)
if err != nil {
ctx.ServerError("BlockingDependencies", err)
return
}
ctx.Data["BlockingDependencies"], ctx.Data["BlockingByDependenciesNotPermitted"] = checkBlockedByIssues(ctx, blocking)
if ctx.Written() {
return
}
ctx.Data["Participants"] = participants
ctx.Data["NumParticipants"] = len(participants)
ctx.Data["Issue"] = issue
@ -1851,6 +1861,48 @@ func ViewIssue(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplIssueView)
}
func checkBlockedByIssues(ctx *context.Context, blockers []*issues_model.DependencyInfo) (canRead, notPermitted []*issues_model.DependencyInfo) {
var lastRepoID int64
var lastPerm access_model.Permission
for i, blocker := range blockers {
// Get the permissions for this repository
perm := lastPerm
if lastRepoID != blocker.Repository.ID {
if blocker.Repository.ID == ctx.Repo.Repository.ID {
perm = ctx.Repo.Permission
} else {
var err error
perm, err = access_model.GetUserRepoPermission(ctx, &blocker.Repository, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return
}
}
lastRepoID = blocker.Repository.ID
}
// check permission
if !perm.CanReadIssuesOrPulls(blocker.Issue.IsPull) {
blockers[len(notPermitted)], blockers[i] = blocker, blockers[len(notPermitted)]
notPermitted = blockers[:len(notPermitted)+1]
}
}
blockers = blockers[len(notPermitted):]
sortDependencyInfo(blockers)
sortDependencyInfo(notPermitted)
return blockers, notPermitted
}
func sortDependencyInfo(blockers []*issues_model.DependencyInfo) {
sort.Slice(blockers, func(i, j int) bool {
if blockers[i].RepoID == blockers[j].RepoID {
return blockers[i].Issue.CreatedUnix < blockers[j].Issue.CreatedUnix
}
return blockers[i].RepoID < blockers[j].RepoID
})
}
// GetActionIssue will return the issue which is used in the context.
func GetActionIssue(ctx *context.Context) *issues_model.Issue {
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))