mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-29 00:59:39 +09:00
fix: resolve actions commit status permission per repository (#38977)
Various pages did not display the correct action run list tooltips. Fix those tooltips like here on the `/pulls` page: `ctx.Repo.Permission` is the zero value outside a repository route, so on `/pulls`, `/issues`, `/notifications/subscriptions` and the dashboard repo list the commit status "Details" link was always stripped. The live job status is looked up from that target URL, so running checks also rendered as a static pending dot instead of a spinner. Resolve the Actions unit permission per repository instead. Also drops the releases page's gate on *loading* statuses, which hid external CI results from anyone without Actions read; it now loads them and hides only the URL, like every other page. Co-authored-by: bircni <bircni@icloud.com>
This commit is contained in:
+37
-13
@@ -15,8 +15,12 @@ import (
|
|||||||
|
|
||||||
asymkey_model "gitea.dev/models/asymkey"
|
asymkey_model "gitea.dev/models/asymkey"
|
||||||
"gitea.dev/models/db"
|
"gitea.dev/models/db"
|
||||||
|
access_model "gitea.dev/models/perm/access"
|
||||||
repo_model "gitea.dev/models/repo"
|
repo_model "gitea.dev/models/repo"
|
||||||
|
"gitea.dev/models/unit"
|
||||||
user_model "gitea.dev/models/user"
|
user_model "gitea.dev/models/user"
|
||||||
|
"gitea.dev/modules/cache"
|
||||||
|
"gitea.dev/modules/cachegroup"
|
||||||
"gitea.dev/modules/commitstatus"
|
"gitea.dev/modules/commitstatus"
|
||||||
"gitea.dev/modules/git"
|
"gitea.dev/modules/git"
|
||||||
"gitea.dev/modules/log"
|
"gitea.dev/modules/log"
|
||||||
@@ -213,8 +217,8 @@ func (status *CommitStatus) LocaleString(lang translation.Locale) string {
|
|||||||
return lang.TrString("repo.commitstatus." + status.State.String())
|
return lang.TrString("repo.commitstatus." + status.State.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// HideActionsURL set `TargetURL` to an empty string if the status comes from Gitea Actions
|
// hideActionsURL set `TargetURL` to an empty string if the status comes from Gitea Actions
|
||||||
func (status *CommitStatus) HideActionsURL(ctx context.Context) {
|
func (status *CommitStatus) hideActionsURL(ctx context.Context) {
|
||||||
if _, ok := status.cutTargetURLGiteaActionsPrefix(ctx); ok {
|
if _, ok := status.cutTargetURLGiteaActionsPrefix(ctx); ok {
|
||||||
status.TargetURL = ""
|
status.TargetURL = ""
|
||||||
}
|
}
|
||||||
@@ -544,18 +548,38 @@ func HashCommitStatusContext(context string) string {
|
|||||||
return fmt.Sprintf("%x", sha1.Sum([]byte(context)))
|
return fmt.Sprintf("%x", sha1.Sum([]byte(context)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitStatusesHideActionsURL hide Gitea Actions urls
|
// CommitStatusesApplyDoerPermission hides the Gitea Actions url of every status whose repository
|
||||||
func CommitStatusesHideActionsURL(ctx context.Context, statuses []*CommitStatus) {
|
// the doer cannot read the Actions unit of, so the "Details" link does not lead to a 404.
|
||||||
idToRepos := make(map[int64]*repo_model.Repository)
|
func CommitStatusesApplyDoerPermission(ctx context.Context, doer *user_model.User, statuses []*CommitStatus) {
|
||||||
for _, status := range statuses {
|
for _, status := range statuses {
|
||||||
if status == nil {
|
if status != nil && !statusRepoCanReadActions(ctx, doer, status) {
|
||||||
continue
|
status.hideActionsURL(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if status.Repo == nil {
|
|
||||||
status.Repo = idToRepos[status.RepoID]
|
|
||||||
}
|
|
||||||
status.HideActionsURL(ctx)
|
|
||||||
idToRepos[status.RepoID] = status.Repo
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignCommitsApplyDoerPermission is CommitStatusesApplyDoerPermission for a list of commits.
|
||||||
|
func SignCommitsApplyDoerPermission(ctx context.Context, doer *user_model.User, commits []*SignCommitWithStatuses) {
|
||||||
|
var statuses []*CommitStatus
|
||||||
|
for _, commit := range commits {
|
||||||
|
statuses = append(statuses, commit.Status)
|
||||||
|
statuses = append(statuses, commit.Statuses...)
|
||||||
|
}
|
||||||
|
CommitStatusesApplyDoerPermission(ctx, doer, statuses)
|
||||||
|
}
|
||||||
|
|
||||||
|
func statusRepoCanReadActions(ctx context.Context, doer *user_model.User, status *CommitStatus) bool {
|
||||||
|
perm, err := cache.GetWithContextCache(ctx, cachegroup.RepoUserPermission, access_model.RepoUserPermissionCacheKey(status.RepoID, doer),
|
||||||
|
func(ctx context.Context, _ string) (access_model.Permission, error) { // only runs on a cache miss
|
||||||
|
if err := status.loadRepository(ctx); err != nil {
|
||||||
|
return access_model.Permission{}, err
|
||||||
|
}
|
||||||
|
return access_model.GetDoerRepoPermission(ctx, status.Repo, doer)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("GetDoerRepoPermission[%d]: %v", status.RepoID, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return perm.CanRead(unit.TypeActions)
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,11 +4,9 @@
|
|||||||
package git_test
|
package git_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
actions_model "gitea.dev/models/actions"
|
|
||||||
"gitea.dev/models/db"
|
"gitea.dev/models/db"
|
||||||
git_model "gitea.dev/models/git"
|
git_model "gitea.dev/models/git"
|
||||||
repo_model "gitea.dev/models/repo"
|
repo_model "gitea.dev/models/repo"
|
||||||
@@ -233,17 +231,23 @@ func TestFindRepoRecentCommitStatusContexts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommitStatusesHideActionsURL(t *testing.T) {
|
func TestCommitStatusesApplyDoerPermission(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
// repo4 is public and has the actions unit, repo2 is private and owned by someone else
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 791, RepoID: repo.ID})
|
otherRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||||
assert.NoError(t, run.LoadAttributes(t.Context()))
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
visibleURL := repo.Link() + "/actions/runs/1/jobs/1"
|
||||||
statuses := []*git_model.CommitStatus{
|
statuses := []*git_model.CommitStatus{
|
||||||
{
|
{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), run.ID),
|
TargetURL: visibleURL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RepoID: otherRepo.ID,
|
||||||
|
TargetURL: otherRepo.Link() + "/actions/runs/1/jobs/1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
@@ -251,9 +255,10 @@ func TestCommitStatusesHideActionsURL(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
git_model.CommitStatusesHideActionsURL(t.Context(), statuses)
|
git_model.CommitStatusesApplyDoerPermission(t.Context(), doer, statuses)
|
||||||
assert.Empty(t, statuses[0].TargetURL)
|
assert.Equal(t, visibleURL, statuses[0].TargetURL)
|
||||||
assert.Equal(t, "https://mycicd.org/1", statuses[1].TargetURL)
|
assert.Empty(t, statuses[1].TargetURL)
|
||||||
|
assert.Equal(t, "https://mycicd.org/1", statuses[2].TargetURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetCountLatestCommitStatus(t *testing.T) {
|
func TestGetCountLatestCommitStatus(t *testing.T) {
|
||||||
|
|||||||
@@ -658,6 +658,16 @@ func PermissionNoAccess() Permission {
|
|||||||
return Permission{AccessMode: perm_model.AccessModeNone}
|
return Permission{AccessMode: perm_model.AccessModeNone}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepoUserPermissionCacheKey is the cachegroup.RepoUserPermission key of a doer's
|
||||||
|
// permission on a repository. Producers and consumers must agree on it, so it lives here.
|
||||||
|
func RepoUserPermissionCacheKey(repoID int64, doer *user_model.User) string {
|
||||||
|
var doerID int64
|
||||||
|
if doer != nil {
|
||||||
|
doerID = doer.ID
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d-%d", repoID, doerID)
|
||||||
|
}
|
||||||
|
|
||||||
// CanReadWorkflowCrossRepo checks whether the run can read workflow files from targetRepo.
|
// CanReadWorkflowCrossRepo checks whether the run can read workflow files from targetRepo.
|
||||||
func CanReadWorkflowCrossRepo(ctx context.Context, targetRepo *repo_model.Repository, run *actions_model.ActionRun) (bool, error) {
|
func CanReadWorkflowCrossRepo(ctx context.Context, targetRepo *repo_model.Repository, run *actions_model.ActionRun) (bool, error) {
|
||||||
if err := run.LoadRepo(ctx); err != nil {
|
if err := run.LoadRepo(ctx); err != nil {
|
||||||
|
|||||||
@@ -70,14 +70,10 @@ func Branches(ctx *context.Context) {
|
|||||||
ctx.ServerError("LoadBranches", err)
|
ctx.ServerError("LoadBranches", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
|
|
||||||
for key := range commitStatuses {
|
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
commitStatus := make(map[string]*git_model.CommitStatus)
|
commitStatus := make(map[string]*git_model.CommitStatus)
|
||||||
for commitID, cs := range commitStatuses {
|
for commitID, cs := range commitStatuses {
|
||||||
|
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, cs)
|
||||||
commitStatus[commitID] = git_model.CalcCommitStatus(cs)
|
commitStatus[commitID] = git_model.CalcCommitStatus(cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
issues_model "gitea.dev/models/issues"
|
issues_model "gitea.dev/models/issues"
|
||||||
"gitea.dev/models/renderhelper"
|
"gitea.dev/models/renderhelper"
|
||||||
repo_model "gitea.dev/models/repo"
|
repo_model "gitea.dev/models/repo"
|
||||||
unit_model "gitea.dev/models/unit"
|
|
||||||
user_model "gitea.dev/models/user"
|
user_model "gitea.dev/models/user"
|
||||||
"gitea.dev/modules/base"
|
"gitea.dev/modules/base"
|
||||||
"gitea.dev/modules/fileicon"
|
"gitea.dev/modules/fileicon"
|
||||||
@@ -388,9 +387,7 @@ func Diff(ctx *context.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetLatestCommitStatus: %v", err)
|
log.Error("GetLatestCommitStatus: %v", err)
|
||||||
}
|
}
|
||||||
if !ctx.Repo.Permission.CanRead(unit_model.TypeActions) {
|
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, statuses)
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, statuses)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses)
|
ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses)
|
||||||
ctx.Data["CommitStatuses"] = statuses
|
ctx.Data["CommitStatuses"] = statuses
|
||||||
@@ -466,14 +463,6 @@ func processGitCommits(ctx *context.Context, gitCommits []*git.Commit) ([]*git_m
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !ctx.Repo.Permission.CanRead(unit_model.TypeActions) {
|
git_model.SignCommitsApplyDoerPermission(ctx, ctx.Doer, commits)
|
||||||
for _, commit := range commits {
|
|
||||||
if commit.Status == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
commit.Status.HideActionsURL(ctx)
|
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return commits, nil
|
return commits, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/models/db"
|
"gitea.dev/models/db"
|
||||||
git_model "gitea.dev/models/git"
|
|
||||||
issues_model "gitea.dev/models/issues"
|
issues_model "gitea.dev/models/issues"
|
||||||
"gitea.dev/models/organization"
|
"gitea.dev/models/organization"
|
||||||
repo_model "gitea.dev/models/repo"
|
repo_model "gitea.dev/models/repo"
|
||||||
"gitea.dev/models/unit"
|
|
||||||
user_model "gitea.dev/models/user"
|
user_model "gitea.dev/models/user"
|
||||||
issue_indexer "gitea.dev/modules/indexer/issues"
|
issue_indexer "gitea.dev/modules/indexer/issues"
|
||||||
db_indexer "gitea.dev/modules/indexer/issues/db"
|
db_indexer "gitea.dev/modules/indexer/issues/db"
|
||||||
@@ -640,16 +638,11 @@ func prepareIssueFilterAndList(ctx *context.Context, milestoneID int64, projectI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues)
|
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, ctx.Doer, issues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetIssuesAllCommitStatus", err)
|
ctx.ServerError("GetIssuesAllCommitStatus", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
|
|
||||||
for key := range commitStatuses {
|
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := issues.LoadAttributes(ctx); err != nil {
|
if err := issues.LoadAttributes(ctx); err != nil {
|
||||||
ctx.ServerError("issues.LoadAttributes", err)
|
ctx.ServerError("issues.LoadAttributes", err)
|
||||||
|
|||||||
@@ -794,15 +794,7 @@ func prepareIssueViewCommentsAndSidebarParticipants(ctx *context.Context, issue
|
|||||||
ctx.ServerError("LoadCommentPushCommits", err)
|
ctx.ServerError("LoadCommentPushCommits", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
|
git_model.SignCommitsApplyDoerPermission(ctx, ctx.Doer, comment.Commits)
|
||||||
for _, commit := range comment.Commits {
|
|
||||||
if commit.Status == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
commit.Status.HideActionsURL(ctx)
|
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if comment.Type == issues_model.CommentTypeAddTimeManual ||
|
} else if comment.Type == issues_model.CommentTypeAddTimeManual ||
|
||||||
comment.Type == issues_model.CommentTypeStopTracking ||
|
comment.Type == issues_model.CommentTypeStopTracking ||
|
||||||
comment.Type == issues_model.CommentTypeDeleteTimeManual {
|
comment.Type == issues_model.CommentTypeDeleteTimeManual {
|
||||||
|
|||||||
@@ -432,9 +432,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBoxStatusCheckData(ctx *context.C
|
|||||||
}
|
}
|
||||||
data.hasRequiredStatusContexts = len(requiredContexts) > 0
|
data.hasRequiredStatusContexts = len(requiredContexts) > 0
|
||||||
|
|
||||||
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
|
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, commitStatuses)
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses)
|
|
||||||
}
|
|
||||||
combinedCommitStatus := git_model.CalcCommitStatus(commitStatuses)
|
combinedCommitStatus := git_model.CalcCommitStatus(commitStatuses)
|
||||||
statusCheckData.ApproveLink = fmt.Sprintf("%s/actions/approve-all-checks?commit_id=%s", ctx.Repo.Repository.Link(), headCommitID)
|
statusCheckData.ApproveLink = fmt.Sprintf("%s/actions/approve-all-checks?commit_id=%s", ctx.Repo.Repository.Link(), headCommitID)
|
||||||
statusCheckData.PullCommitStatuses = commitStatuses
|
statusCheckData.PullCommitStatuses = commitStatuses
|
||||||
|
|||||||
@@ -97,11 +97,12 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions)
|
|||||||
}
|
}
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
canReadActions := ctx.Repo.Permission.CanRead(unit.TypeActions)
|
// statuses describe the tagged code, and unlike the other pages showing them this one is not behind the code unit
|
||||||
|
canReadCode := ctx.Repo.Permission.CanRead(unit.TypeCode)
|
||||||
|
|
||||||
// Bulk-load commit statuses for all releases in one query.
|
// Bulk-load commit statuses for all releases in one query.
|
||||||
var commitStatusMap map[string][]*git_model.CommitStatus
|
var commitStatusMap map[string][]*git_model.CommitStatus
|
||||||
if canReadActions && len(releases) > 0 {
|
if canReadCode && len(releases) > 0 {
|
||||||
shas := make([]string, 0, len(releases))
|
shas := make([]string, 0, len(releases))
|
||||||
for _, r := range releases {
|
for _, r := range releases {
|
||||||
shas = append(shas, r.Sha1)
|
shas = append(shas, r.Sha1)
|
||||||
@@ -140,8 +141,9 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions)
|
|||||||
Release: r,
|
Release: r,
|
||||||
}
|
}
|
||||||
|
|
||||||
if canReadActions {
|
if canReadCode {
|
||||||
statuses := commitStatusMap[r.Sha1]
|
statuses := commitStatusMap[r.Sha1]
|
||||||
|
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, statuses)
|
||||||
info.CommitStatus = git_model.CalcCommitStatus(statuses)
|
info.CommitStatus = git_model.CalcCommitStatus(statuses)
|
||||||
info.CommitStatuses = statuses
|
info.CommitStatuses = statuses
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -526,9 +526,7 @@ func SearchRepo(ctx *context.Context) {
|
|||||||
ctx.JSON(http.StatusInternalServerError, nil)
|
ctx.JSON(http.StatusInternalServerError, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
|
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, latestCommitStatuses)
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, latestCommitStatuses)
|
|
||||||
}
|
|
||||||
|
|
||||||
results := make([]*repo_service.WebSearchRepository, len(repos))
|
results := make([]*repo_service.WebSearchRepository, len(repos))
|
||||||
for i, repo := range repos {
|
for i, repo := range repos {
|
||||||
|
|||||||
@@ -143,9 +143,7 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetLatestCommitStatus: %v", err)
|
log.Error("GetLatestCommitStatus: %v", err)
|
||||||
}
|
}
|
||||||
if !ctx.Repo.Permission.CanRead(unit_model.TypeActions) {
|
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, statuses)
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, statuses)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses)
|
ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses)
|
||||||
ctx.Data["LatestCommitStatuses"] = statuses
|
ctx.Data["LatestCommitStatuses"] = statuses
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
activities_model "gitea.dev/models/activities"
|
activities_model "gitea.dev/models/activities"
|
||||||
asymkey_model "gitea.dev/models/asymkey"
|
asymkey_model "gitea.dev/models/asymkey"
|
||||||
"gitea.dev/models/db"
|
"gitea.dev/models/db"
|
||||||
git_model "gitea.dev/models/git"
|
|
||||||
issues_model "gitea.dev/models/issues"
|
issues_model "gitea.dev/models/issues"
|
||||||
"gitea.dev/models/organization"
|
"gitea.dev/models/organization"
|
||||||
"gitea.dev/models/renderhelper"
|
"gitea.dev/models/renderhelper"
|
||||||
@@ -554,16 +553,11 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues)
|
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, ctx.Doer, issues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetIssuesLastCommitStatus", err)
|
ctx.ServerError("GetIssuesLastCommitStatus", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
|
|
||||||
for key := range commitStatuses {
|
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Fill stats to post to ctx.Data.
|
// Fill stats to post to ctx.Data.
|
||||||
|
|||||||
@@ -11,11 +11,9 @@ import (
|
|||||||
|
|
||||||
activities_model "gitea.dev/models/activities"
|
activities_model "gitea.dev/models/activities"
|
||||||
"gitea.dev/models/db"
|
"gitea.dev/models/db"
|
||||||
git_model "gitea.dev/models/git"
|
|
||||||
issues_model "gitea.dev/models/issues"
|
issues_model "gitea.dev/models/issues"
|
||||||
access_model "gitea.dev/models/perm/access"
|
access_model "gitea.dev/models/perm/access"
|
||||||
repo_model "gitea.dev/models/repo"
|
repo_model "gitea.dev/models/repo"
|
||||||
"gitea.dev/models/unit"
|
|
||||||
user_model "gitea.dev/models/user"
|
user_model "gitea.dev/models/user"
|
||||||
"gitea.dev/modules/base"
|
"gitea.dev/modules/base"
|
||||||
"gitea.dev/modules/container"
|
"gitea.dev/modules/container"
|
||||||
@@ -268,16 +266,11 @@ func NotificationSubscriptions(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues)
|
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, ctx.Doer, issues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetIssuesAllCommitStatus", err)
|
ctx.ServerError("GetIssuesAllCommitStatus", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
|
|
||||||
for key := range commitStatuses {
|
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.Data["CommitLastStatus"] = lastStatus
|
ctx.Data["CommitLastStatus"] = lastStatus
|
||||||
ctx.Data["CommitStatuses"] = commitStatuses
|
ctx.Data["CommitStatuses"] = commitStatuses
|
||||||
ctx.Data["Issues"] = issues
|
ctx.Data["Issues"] = issues
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
user_model "gitea.dev/models/user"
|
user_model "gitea.dev/models/user"
|
||||||
"gitea.dev/modules/base"
|
"gitea.dev/modules/base"
|
||||||
"gitea.dev/modules/cache"
|
"gitea.dev/modules/cache"
|
||||||
|
"gitea.dev/modules/cachegroup"
|
||||||
"gitea.dev/modules/git"
|
"gitea.dev/modules/git"
|
||||||
"gitea.dev/modules/httplib"
|
"gitea.dev/modules/httplib"
|
||||||
code_indexer "gitea.dev/modules/indexer/code"
|
code_indexer "gitea.dev/modules/indexer/code"
|
||||||
@@ -427,6 +428,10 @@ func repoAssignmentLegacy(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// publish it so code resolving the same permission later in this request reuses it
|
||||||
|
if c := cache.GetContextCache(ctx); c != nil {
|
||||||
|
c.Put(cachegroup.RepoUserPermission, access_model.RepoUserPermissionCacheKey(repo.ID, ctx.Doer), ctx.Repo.Permission)
|
||||||
|
}
|
||||||
|
|
||||||
if !ctx.Repo.Permission.HasAnyUnitAccessOrPublicAccess() && !canWriteAsMaintainer(ctx) {
|
if !ctx.Repo.Permission.HasAnyUnitAccessOrPublicAccess() && !canWriteAsMaintainer(ctx) {
|
||||||
if ctx.FormString("go-get") == "1" {
|
if ctx.FormString("go-get") == "1" {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package convert
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
git_model "gitea.dev/models/git"
|
git_model "gitea.dev/models/git"
|
||||||
issues_model "gitea.dev/models/issues"
|
issues_model "gitea.dev/models/issues"
|
||||||
@@ -55,12 +54,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var doerID int64
|
repoUserPerm, err := cache.GetWithContextCache(ctx, cachegroup.RepoUserPermission, access_model.RepoUserPermissionCacheKey(pr.BaseRepoID, doer),
|
||||||
if doer != nil {
|
|
||||||
doerID = doer.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
repoUserPerm, err := cache.GetWithContextCache(ctx, cachegroup.RepoUserPermission, fmt.Sprintf("%d-%d", pr.BaseRepoID, doerID),
|
|
||||||
func(ctx context.Context, _ string) (access_model.Permission, error) {
|
func(ctx context.Context, _ string) (access_model.Permission, error) {
|
||||||
return access_model.GetDoerRepoPermission(ctx, pr.BaseRepo, doer)
|
return access_model.GetDoerRepoPermission(ctx, pr.BaseRepo, doer)
|
||||||
},
|
},
|
||||||
|
|||||||
+10
-4
@@ -931,8 +931,9 @@ func formatSquashMergeCommitMessages(commits []*git.Commit) string {
|
|||||||
return util.UnsafeBytesToString(buf)
|
return util.UnsafeBytesToString(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssuesAllCommitStatus returns a map of issue ID to a list of all statuses for the most recent commit as well as a map of issue ID to only the commit's latest status
|
// GetIssuesAllCommitStatus returns a map of issue ID to a list of all statuses for the most recent commit as well as a map of issue ID to only the commit's latest status.
|
||||||
func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64][]*git_model.CommitStatus, map[int64]*git_model.CommitStatus, error) {
|
// The returned statuses are redacted for doer.
|
||||||
|
func GetIssuesAllCommitStatus(ctx context.Context, doer *user_model.User, issues issues_model.IssueList) (map[int64][]*git_model.CommitStatus, map[int64]*git_model.CommitStatus, error) {
|
||||||
if err := issues.LoadPullRequests(ctx); err != nil {
|
if err := issues.LoadPullRequests(ctx); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -966,7 +967,7 @@ func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList
|
|||||||
gitRepos[issue.RepoID] = gitRepo
|
gitRepos[issue.RepoID] = gitRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
statuses, lastStatus, err := getAllCommitStatus(ctx, gitRepo, issue.PullRequest)
|
statuses, lastStatus, err := getAllCommitStatus(ctx, doer, gitRepo, issue.PullRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("getAllCommitStatus: cant get commit statuses of pull [%d]: %v", issue.PullRequest.ID, err)
|
log.Error("getAllCommitStatus: cant get commit statuses of pull [%d]: %v", issue.PullRequest.ID, err)
|
||||||
continue
|
continue
|
||||||
@@ -978,13 +979,18 @@ func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getAllCommitStatus get pr's commit statuses.
|
// getAllCommitStatus get pr's commit statuses.
|
||||||
func getAllCommitStatus(ctx context.Context, gitRepo *git.Repository, pr *issues_model.PullRequest) (statuses []*git_model.CommitStatus, lastStatus *git_model.CommitStatus, err error) {
|
func getAllCommitStatus(ctx context.Context, doer *user_model.User, gitRepo *git.Repository, pr *issues_model.PullRequest) (statuses []*git_model.CommitStatus, lastStatus *git_model.CommitStatus, err error) {
|
||||||
sha, shaErr := gitRepo.GetRefCommitID(ctx, pr.GetGitHeadRefName())
|
sha, shaErr := gitRepo.GetRefCommitID(ctx, pr.GetGitHeadRefName())
|
||||||
if shaErr != nil {
|
if shaErr != nil {
|
||||||
return nil, nil, shaErr
|
return nil, nil, shaErr
|
||||||
}
|
}
|
||||||
|
|
||||||
statuses, err = git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll)
|
statuses, err = git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll)
|
||||||
|
for _, status := range statuses {
|
||||||
|
status.Repo = pr.BaseRepo // the repo is already loaded, spare the permission lookup a query
|
||||||
|
}
|
||||||
|
// CalcCommitStatus copies a TargetURL out of the statuses, so hide before combining
|
||||||
|
git_model.CommitStatusesApplyDoerPermission(ctx, doer, statuses)
|
||||||
lastStatus = git_model.CalcCommitStatus(statuses)
|
lastStatus = git_model.CalcCommitStatus(statuses)
|
||||||
return statuses, lastStatus, err
|
return statuses, lastStatus, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,6 +124,8 @@ func FindReposLatestCommitStatuses(ctx context.Context, repos []*repo_model.Repo
|
|||||||
for i, repo := range repos {
|
for i, repo := range repos {
|
||||||
if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil {
|
if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil {
|
||||||
results[i] = &git_model.CommitStatus{
|
results[i] = &git_model.CommitStatus{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Repo: repo,
|
||||||
State: commitstatus.CommitStatusState(cv.State),
|
State: commitstatus.CommitStatusState(cv.State),
|
||||||
TargetURL: cv.TargetURL,
|
TargetURL: cv.TargetURL,
|
||||||
}
|
}
|
||||||
@@ -163,6 +165,7 @@ func FindReposLatestCommitStatuses(ctx context.Context, repos []*repo_model.Repo
|
|||||||
for _, summary := range summaryResults {
|
for _, summary := range summaryResults {
|
||||||
for i, repo := range repos {
|
for i, repo := range repos {
|
||||||
if repo.ID == summary.RepoID {
|
if repo.ID == summary.RepoID {
|
||||||
|
summary.Repo = repo
|
||||||
results[i] = summary
|
results[i] = summary
|
||||||
repoSHAs = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool {
|
repoSHAs = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool {
|
||||||
return repoSHA.RepoID == repo.ID
|
return repoSHA.RepoID == repo.ID
|
||||||
@@ -190,6 +193,7 @@ func FindReposLatestCommitStatuses(ctx context.Context, repos []*repo_model.Repo
|
|||||||
if results[i] == nil {
|
if results[i] == nil {
|
||||||
results[i] = git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID])
|
results[i] = git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID])
|
||||||
if results[i] != nil {
|
if results[i] != nil {
|
||||||
|
results[i].Repo = repo
|
||||||
if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil {
|
if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil {
|
||||||
log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err)
|
log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="tippy-target">
|
<div class="tippy-target">
|
||||||
<div class="flex-divided-list items-px-default">
|
<div class="commit-status-list flex-divided-list items-px-default">
|
||||||
{{template "repo/pulls/status_items" (dict "CommitStatuses" .Statuses)}}
|
{{template "repo/pulls/status_items" (dict "CommitStatuses" .Statuses)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1826,7 +1826,7 @@ tbody.commit-list {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commit-status-item { /* the item can be used at 2 places: PR's merge box (commit-status-list), commit's status popup (no commit-status-list) */
|
.commit-status-item { /* the item is used in the PR merge box and the commit status popup, both are commit-status-list */
|
||||||
height: 40px;
|
height: 40px;
|
||||||
padding-top: 0 !important; /* use "height" + "align items center", don't use padding-y (from the list container) to layout */
|
padding-top: 0 !important; /* use "height" + "align items center", don't use padding-y (from the list container) to layout */
|
||||||
padding-bottom: 0 !important;
|
padding-bottom: 0 !important;
|
||||||
|
|||||||
Reference in New Issue
Block a user