From 7dec8de9147b20c014d68bb1020afe28a263b95a Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Sun, 28 Jul 2024 23:11:40 +0800 Subject: [PATCH 01/12] Hide the "Details" link of commit status when the user cannot access actions (#30156) Fix #26685 If a commit status comes from Gitea Actions and the user cannot access the repo's actions unit (the user does not have the permission or the actions unit is disabled), a 404 page will occur after clicking the "Details" link. We should hide the "Details" link in this case. --- models/git/commit_status.go | 40 +++++++++++++++++++++++++++++++- models/git/commit_status_test.go | 25 ++++++++++++++++++++ routers/web/repo/branch.go | 5 ++++ routers/web/repo/commit.go | 21 ++++++++++++++--- routers/web/repo/compare.go | 2 +- routers/web/repo/issue.go | 11 +++++++++ routers/web/repo/pull.go | 14 ++++++++++- routers/web/repo/repo.go | 3 +++ routers/web/repo/view.go | 3 +++ routers/web/user/home.go | 6 +++++ routers/web/user/notification.go | 7 ++++++ 11 files changed, 131 insertions(+), 6 deletions(-) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index d12afc42c5..f80de9679f 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -171,13 +171,17 @@ func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (in return newIdx, nil } -func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) { +func (status *CommitStatus) loadRepository(ctx context.Context) (err error) { if status.Repo == nil { status.Repo, err = repo_model.GetRepositoryByID(ctx, status.RepoID) if err != nil { return fmt.Errorf("getRepositoryByID [%d]: %w", status.RepoID, err) } } + return nil +} + +func (status *CommitStatus) loadCreator(ctx context.Context) (err error) { if status.Creator == nil && status.CreatorID > 0 { status.Creator, err = user_model.GetUserByID(ctx, status.CreatorID) if err != nil { @@ -187,6 +191,13 @@ func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) { return nil } +func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) { + if err := status.loadRepository(ctx); err != nil { + return err + } + return status.loadCreator(ctx) +} + // APIURL returns the absolute APIURL to this commit-status. func (status *CommitStatus) APIURL(ctx context.Context) string { _ = status.loadAttributes(ctx) @@ -198,6 +209,21 @@ func (status *CommitStatus) LocaleString(lang translation.Locale) string { return lang.TrString("repo.commitstatus." + status.State.String()) } +// HideActionsURL set `TargetURL` to an empty string if the status comes from Gitea Actions +func (status *CommitStatus) HideActionsURL(ctx context.Context) { + if status.Repo == nil { + if err := status.loadRepository(ctx); err != nil { + log.Error("loadRepository: %v", err) + return + } + } + + prefix := fmt.Sprintf("%s/actions", status.Repo.Link()) + if strings.HasPrefix(status.TargetURL, prefix) { + status.TargetURL = "" + } +} + // CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus { var lastStatus *CommitStatus @@ -506,3 +532,15 @@ func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo repo, ) } + +// CommitStatusesHideActionsURL hide Gitea Actions urls +func CommitStatusesHideActionsURL(ctx context.Context, statuses []*CommitStatus) { + idToRepos := make(map[int64]*repo_model.Repository) + for _, status := range statuses { + if status.Repo == nil { + status.Repo = idToRepos[status.RepoID] + } + status.HideActionsURL(ctx) + idToRepos[status.RepoID] = status.Repo + } +} diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go index 08eba6e293..7ac4da6810 100644 --- a/models/git/commit_status_test.go +++ b/models/git/commit_status_test.go @@ -4,9 +4,11 @@ package git_test import ( + "fmt" "testing" "time" + actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" @@ -231,3 +233,26 @@ func TestFindRepoRecentCommitStatusContexts(t *testing.T) { assert.Equal(t, "compliance/lint-backend", contexts[0]) } } + +func TestCommitStatusesHideActionsURL(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) + run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 791, RepoID: repo.ID}) + assert.NoError(t, run.LoadAttributes(db.DefaultContext)) + + statuses := []*git_model.CommitStatus{ + { + RepoID: repo.ID, + TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), run.Index), + }, + { + RepoID: repo.ID, + TargetURL: "https://mycicd.org/1", + }, + } + + git_model.CommitStatusesHideActionsURL(db.DefaultContext, statuses) + assert.Empty(t, statuses[0].TargetURL) + assert.Equal(t, "https://mycicd.org/1", statuses[1].TargetURL) +} diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index f879a98786..4897a5f4fc 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -70,6 +70,11 @@ func Branches(ctx *context.Context) { ctx.ServerError("LoadBranches", err) return } + if !ctx.Repo.CanRead(unit.TypeActions) { + for key := range commitStatuses { + git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key]) + } + } commitStatus := make(map[string]*git_model.CommitStatus) for commitID, cs := range commitStatuses { diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index dae6063908..e5d84db617 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" + unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" @@ -81,7 +82,7 @@ func Commits(ctx *context.Context) { ctx.ServerError("CommitsByRange", err) return } - ctx.Data["Commits"] = git_model.ConvertFromGitCommit(ctx, commits, ctx.Repo.Repository) + ctx.Data["Commits"] = processGitCommits(ctx, commits) ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name @@ -199,7 +200,7 @@ func SearchCommits(ctx *context.Context) { return } ctx.Data["CommitCount"] = len(commits) - ctx.Data["Commits"] = git_model.ConvertFromGitCommit(ctx, commits, ctx.Repo.Repository) + ctx.Data["Commits"] = processGitCommits(ctx, commits) ctx.Data["Keyword"] = query if all { @@ -242,7 +243,7 @@ func FileHistory(ctx *context.Context) { ctx.ServerError("CommitsByFileAndRange", err) return } - ctx.Data["Commits"] = git_model.ConvertFromGitCommit(ctx, commits, ctx.Repo.Repository) + ctx.Data["Commits"] = processGitCommits(ctx, commits) ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name @@ -353,6 +354,9 @@ func Diff(ctx *context.Context) { if err != nil { log.Error("GetLatestCommitStatus: %v", err) } + if !ctx.Repo.CanRead(unit_model.TypeActions) { + git_model.CommitStatusesHideActionsURL(ctx, statuses) + } ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses) ctx.Data["CommitStatuses"] = statuses @@ -433,3 +437,14 @@ func RawDiff(ctx *context.Context) { return } } + +func processGitCommits(ctx *context.Context, gitCommits []*git.Commit) []*git_model.SignCommitWithStatuses { + commits := git_model.ConvertFromGitCommit(ctx, gitCommits, ctx.Repo.Repository) + if !ctx.Repo.CanRead(unit_model.TypeActions) { + for _, commit := range commits { + commit.Status.HideActionsURL(ctx) + git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses) + } + } + return commits +} diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 65e23bf751..e6a04782e5 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -643,7 +643,7 @@ func PrepareCompareDiff( return false } - commits := git_model.ConvertFromGitCommit(ctx, ci.CompareInfo.Commits, ci.HeadRepo) + commits := processGitCommits(ctx, ci.CompareInfo.Commits) ctx.Data["Commits"] = commits ctx.Data["CommitCount"] = len(commits) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 7c4e3e36f3..ed2664db17 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -339,6 +339,11 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt ctx.ServerError("GetIssuesAllCommitStatus", err) return } + if !ctx.Repo.CanRead(unit.TypeActions) { + for key := range commitStatuses { + git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key]) + } + } if err := issues.LoadAttributes(ctx); err != nil { ctx.ServerError("issues.LoadAttributes", err) @@ -1757,6 +1762,12 @@ func ViewIssue(ctx *context.Context) { ctx.ServerError("LoadPushCommits", err) return } + if !ctx.Repo.CanRead(unit.TypeActions) { + for _, commit := range comment.Commits { + commit.Status.HideActionsURL(ctx) + git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses) + } + } } else if comment.Type == issues_model.CommentTypeAddTimeManual || comment.Type == issues_model.CommentTypeStopTracking || comment.Type == issues_model.CommentTypeDeleteTimeManual { diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 4522099460..f9642d44d4 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -283,6 +283,10 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue) ctx.ServerError("GetLatestCommitStatus", err) return nil } + if !ctx.Repo.CanRead(unit.TypeActions) { + git_model.CommitStatusesHideActionsURL(ctx, commitStatuses) + } + if len(commitStatuses) != 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) @@ -345,6 +349,10 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C ctx.ServerError("GetLatestCommitStatus", err) return nil } + if !ctx.Repo.CanRead(unit.TypeActions) { + git_model.CommitStatusesHideActionsURL(ctx, commitStatuses) + } + if len(commitStatuses) > 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) @@ -437,6 +445,10 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C ctx.ServerError("GetLatestCommitStatus", err) return nil } + if !ctx.Repo.CanRead(unit.TypeActions) { + git_model.CommitStatusesHideActionsURL(ctx, commitStatuses) + } + if len(commitStatuses) > 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) @@ -603,7 +615,7 @@ func ViewPullCommits(ctx *context.Context) { ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name - commits := git_model.ConvertFromGitCommit(ctx, prInfo.Commits, ctx.Repo.Repository) + commits := processGitCommits(ctx, prInfo.Commits) ctx.Data["Commits"] = commits ctx.Data["CommitCount"] = len(commits) diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 2ef548b5b2..f7a7cb5d38 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -656,6 +656,9 @@ func SearchRepo(ctx *context.Context) { ctx.JSON(http.StatusInternalServerError, nil) return } + if !ctx.Repo.CanRead(unit.TypeActions) { + git_model.CommitStatusesHideActionsURL(ctx, latestCommitStatuses) + } results := make([]*repo_service.WebSearchRepository, len(repos)) for i, repo := range repos { diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 203dac7439..dfc33ff36d 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -363,6 +363,9 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool { if err != nil { log.Error("GetLatestCommitStatus: %v", err) } + if !ctx.Repo.CanRead(unit_model.TypeActions) { + git_model.CommitStatusesHideActionsURL(ctx, statuses) + } ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses) ctx.Data["LatestCommitStatuses"] = statuses diff --git a/routers/web/user/home.go b/routers/web/user/home.go index e94433b3c5..2ecc2cc8d1 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -17,6 +17,7 @@ import ( activities_model "code.gitea.io/gitea/models/activities" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" @@ -568,6 +569,11 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { ctx.ServerError("GetIssuesLastCommitStatus", err) return } + if !ctx.Repo.CanRead(unit.TypeActions) { + for key := range commitStatuses { + git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key]) + } + } // ------------------------------- // Fill stats to post to ctx.Data. diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index ae0132e6e2..833a9c049c 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -13,8 +13,10 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" @@ -303,6 +305,11 @@ func NotificationSubscriptions(ctx *context.Context) { ctx.ServerError("GetIssuesAllCommitStatus", err) return } + if !ctx.Repo.CanRead(unit.TypeActions) { + for key := range commitStatuses { + git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key]) + } + } ctx.Data["CommitLastStatus"] = lastStatus ctx.Data["CommitStatuses"] = commitStatuses ctx.Data["Issues"] = issues From 5f526d7d3dc7b63c8f6b689952b6a7039c2b7c99 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 28 Jul 2024 19:27:24 +0200 Subject: [PATCH 02/12] Run `go-install` in `deps-tools` in parallel (#31711) `go install` is far too conservative in regards to parallel HTTP requests, so we can run the commands in parallel to achieve a speedup. --- Makefile | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 05d0d61a97..378de6e8f4 100644 --- a/Makefile +++ b/Makefile @@ -858,18 +858,19 @@ deps-backend: .PHONY: deps-tools deps-tools: - $(GO) install $(AIR_PACKAGE) - $(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) - $(GO) install $(GOFUMPT_PACKAGE) - $(GO) install $(GOLANGCI_LINT_PACKAGE) - $(GO) install $(GXZ_PACKAGE) - $(GO) install $(MISSPELL_PACKAGE) - $(GO) install $(SWAGGER_PACKAGE) - $(GO) install $(XGO_PACKAGE) - $(GO) install $(GO_LICENSES_PACKAGE) - $(GO) install $(GOVULNCHECK_PACKAGE) - $(GO) install $(ACTIONLINT_PACKAGE) - $(GO) install $(GOPLS_PACKAGE) + $(GO) install $(AIR_PACKAGE) & \ + $(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \ + $(GO) install $(GOFUMPT_PACKAGE) & \ + $(GO) install $(GOLANGCI_LINT_PACKAGE) & \ + $(GO) install $(GXZ_PACKAGE) & \ + $(GO) install $(MISSPELL_PACKAGE) & \ + $(GO) install $(SWAGGER_PACKAGE) & \ + $(GO) install $(XGO_PACKAGE) & \ + $(GO) install $(GO_LICENSES_PACKAGE) & \ + $(GO) install $(GOVULNCHECK_PACKAGE) & \ + $(GO) install $(ACTIONLINT_PACKAGE) & \ + $(GO) install $(GOPLS_PACKAGE) & \ + wait node_modules: package-lock.json npm install --no-save From 88decb6913554c490d68c0443be2fa68e2591853 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 29 Jul 2024 00:28:39 +0000 Subject: [PATCH 03/12] [skip ci] Updated licenses and gitignores --- options/license/HIDAPI | 2 ++ options/license/Ruby-pty | 10 ++++++++++ options/license/X11-swapped | 23 +++++++++++++++++++++++ options/license/romic-exception | 6 ++++++ 4 files changed, 41 insertions(+) create mode 100644 options/license/HIDAPI create mode 100644 options/license/Ruby-pty create mode 100644 options/license/X11-swapped create mode 100644 options/license/romic-exception diff --git a/options/license/HIDAPI b/options/license/HIDAPI new file mode 100644 index 0000000000..e0b5d70c04 --- /dev/null +++ b/options/license/HIDAPI @@ -0,0 +1,2 @@ +This software may be used by anyone for any reason so long +as the copyright notice in the source files remains intact. diff --git a/options/license/Ruby-pty b/options/license/Ruby-pty new file mode 100644 index 0000000000..c817762f84 --- /dev/null +++ b/options/license/Ruby-pty @@ -0,0 +1,10 @@ +(c) Copyright 1998 by Akinori Ito. + +This software may be redistributed freely for this purpose, in full +or in part, provided that this entire copyright notice is included +on any copies of this software and applications and derivations thereof. + +This software is provided on an "as is" basis, without warranty of any +kind, either expressed or implied, as to any matter including, but not +limited to warranty of fitness of purpose, or merchantability, or +results obtained from use of this software. diff --git a/options/license/X11-swapped b/options/license/X11-swapped new file mode 100644 index 0000000000..b023bd546e --- /dev/null +++ b/options/license/X11-swapped @@ -0,0 +1,23 @@ +Copyright (c) 2008-2010 Derick Eddington. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Except as contained in this notice, the name(s) of the above copyright +holders shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written authorization. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/options/license/romic-exception b/options/license/romic-exception new file mode 100644 index 0000000000..57def44818 --- /dev/null +++ b/options/license/romic-exception @@ -0,0 +1,6 @@ +Additional permission under the GNU Affero GPL version 3 section 7: + +If you modify this Program, or any covered work, by linking or +combining it with other code, such other code is not for that reason +alone subject to any of the requirements of the GNU Affero GPL +version 3. From d109923ed8e58bce0ad26b47385edbc79403803d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 29 Jul 2024 09:32:54 +0800 Subject: [PATCH 04/12] Make GetRepositoryByName more safer (#31712) Fix #31708 --- models/repo/repo.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/models/repo/repo.go b/models/repo/repo.go index a5b36dd8a1..68f8e16a21 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -745,17 +745,18 @@ func GetRepositoryByOwnerAndName(ctx context.Context, ownerName, repoName string // GetRepositoryByName returns the repository by given name under user if exists. func GetRepositoryByName(ctx context.Context, ownerID int64, name string) (*Repository, error) { - repo := &Repository{ - OwnerID: ownerID, - LowerName: strings.ToLower(name), - } - has, err := db.GetEngine(ctx).Get(repo) + var repo Repository + has, err := db.GetEngine(ctx). + Where("`owner_id`=?", ownerID). + And("`lower_name`=?", strings.ToLower(name)). + NoAutoCondition(). + Get(&repo) if err != nil { return nil, err } else if !has { return nil, ErrRepoNotExist{0, ownerID, "", name} } - return repo, err + return &repo, err } // getRepositoryURLPathSegments returns segments (owner, reponame) extracted from a url From e0a408e6f374352a4b4ed06c727b1d5777ca6ea8 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 29 Jul 2024 11:21:22 +0900 Subject: [PATCH 05/12] Add permission check when creating PR (#31033) user should be a collaborator of the base repo to create a PR --- models/issues/pull.go | 8 +++ options/locale/locale_en-US.ini | 1 + routers/api/v1/repo/pull.go | 2 + routers/web/repo/pull.go | 10 ++++ services/pull/pull.go | 24 +++++++++ tests/integration/actions_trigger_test.go | 38 ++++++++------ tests/integration/api_pull_test.go | 60 +++++++++++++++++++++++ 7 files changed, 127 insertions(+), 16 deletions(-) diff --git a/models/issues/pull.go b/models/issues/pull.go index ef49a51045..a4e6147619 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -27,6 +27,8 @@ import ( "xorm.io/builder" ) +var ErrMustCollaborator = util.NewPermissionDeniedErrorf("user must be a collaborator") + // ErrPullRequestNotExist represents a "PullRequestNotExist" kind of error. type ErrPullRequestNotExist struct { ID int64 @@ -572,6 +574,12 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *Iss return nil } +// ErrUserMustCollaborator represents an error that the user must be a collaborator to a given repo. +type ErrUserMustCollaborator struct { + UserID int64 + RepoName string +} + // GetUnmergedPullRequest returns a pull request that is open and has not been merged // by given head/base and repo/branch. func GetUnmergedPullRequest(ctx context.Context, headRepoID, baseRepoID int64, headBranch, baseBranch string, flow PullRequestFlow) (*PullRequest, error) { diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 6a748aed00..53d746ef12 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1765,6 +1765,7 @@ compare.compare_head = compare pulls.desc = Enable pull requests and code reviews. pulls.new = New Pull Request pulls.new.blocked_user = Cannot create pull request because you are blocked by the repository owner. +pulls.new.must_collaborator = You must be a collaborator to create pull request. pulls.edit.already_changed = Unable to save changes to the pull request. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes pulls.view = View Pull Request pulls.compare_changes = New Pull Request diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index ebe876da64..148b6ed637 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -535,6 +535,8 @@ func CreatePullRequest(ctx *context.APIContext) { ctx.Error(http.StatusBadRequest, "UserDoesNotHaveAccessToRepo", err) } else if errors.Is(err, user_model.ErrBlockedUser) { ctx.Error(http.StatusForbidden, "BlockedUser", err) + } else if errors.Is(err, issues_model.ErrMustCollaborator) { + ctx.Error(http.StatusForbidden, "MustCollaborator", err) } else { ctx.Error(http.StatusInternalServerError, "NewPullRequest", err) } diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index f9642d44d4..9531482bee 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1337,6 +1337,16 @@ func CompareAndPullRequestPost(ctx *context.Context) { return } ctx.JSONError(flashError) + } else if errors.Is(err, issues_model.ErrMustCollaborator) { + flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{ + "Message": ctx.Tr("repo.pulls.push_rejected"), + "Summary": ctx.Tr("repo.pulls.new.must_collaborator"), + }) + if err != nil { + ctx.ServerError("CompareAndPullRequest.HTMLString", err) + return + } + ctx.JSONError(flashError) } return } diff --git a/services/pull/pull.go b/services/pull/pull.go index 5c0ea42d77..e69c842a2d 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -17,7 +17,9 @@ import ( "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" @@ -48,6 +50,28 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *iss return user_model.ErrBlockedUser } + // user should be a collaborator or a member of the organization for base repo + if !issue.Poster.IsAdmin { + canCreate, err := repo_model.IsOwnerMemberCollaborator(ctx, repo, issue.Poster.ID) + if err != nil { + return err + } + + if !canCreate { + // or user should have write permission in the head repo + if err := pr.LoadHeadRepo(ctx); err != nil { + return err + } + perm, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, issue.Poster) + if err != nil { + return err + } + if !perm.CanWrite(unit.TypeCode) { + return issues_model.ErrMustCollaborator + } + } + } + prCtx, cancel, err := createTemporaryRepoForPR(ctx, pr) if err != nil { if !git_model.IsErrBranchNotExist(err) { diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index 2a2fdceb61..ed0c607374 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -11,9 +11,11 @@ import ( "time" actions_model "code.gitea.io/gitea/models/actions" + auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unittest" @@ -34,7 +36,7 @@ import ( func TestPullRequestTargetEvent(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the base repo - org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the forked repo + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of the forked repo // create the base repo baseRepo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{ @@ -57,8 +59,12 @@ func TestPullRequestTargetEvent(t *testing.T) { }}, nil) assert.NoError(t, err) + // add user4 as the collaborator + ctx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository) + t.Run("AddUser4AsCollaboratorWithReadAccess", doAPIAddCollaborator(ctx, "user4", perm.AccessModeRead)) + // create the forked repo - forkedRepo, err := repo_service.ForkRepository(git.DefaultContext, user2, org3, repo_service.ForkRepoOptions{ + forkedRepo, err := repo_service.ForkRepository(git.DefaultContext, user2, user4, repo_service.ForkRepoOptions{ BaseRepo: baseRepo, Name: "forked-repo-pull-request-target", Description: "test pull-request-target event", @@ -95,7 +101,7 @@ func TestPullRequestTargetEvent(t *testing.T) { assert.NotEmpty(t, addWorkflowToBaseResp) // add a new file to the forked repo - addFileToForkedResp, err := files_service.ChangeRepoFiles(git.DefaultContext, forkedRepo, org3, &files_service.ChangeRepoFilesOptions{ + addFileToForkedResp, err := files_service.ChangeRepoFiles(git.DefaultContext, forkedRepo, user4, &files_service.ChangeRepoFilesOptions{ Files: []*files_service.ChangeRepoFile{ { Operation: "create", @@ -107,12 +113,12 @@ func TestPullRequestTargetEvent(t *testing.T) { OldBranch: "main", NewBranch: "fork-branch-1", Author: &files_service.IdentityOptions{ - Name: org3.Name, - Email: org3.Email, + Name: user4.Name, + Email: user4.Email, }, Committer: &files_service.IdentityOptions{ - Name: org3.Name, - Email: org3.Email, + Name: user4.Name, + Email: user4.Email, }, Dates: &files_service.CommitDateOptions{ Author: time.Now(), @@ -126,8 +132,8 @@ func TestPullRequestTargetEvent(t *testing.T) { pullIssue := &issues_model.Issue{ RepoID: baseRepo.ID, Title: "Test pull-request-target-event", - PosterID: org3.ID, - Poster: org3, + PosterID: user4.ID, + Poster: user4, IsPull: true, } pullRequest := &issues_model.PullRequest{ @@ -149,7 +155,7 @@ func TestPullRequestTargetEvent(t *testing.T) { assert.Equal(t, actions_module.GithubEventPullRequestTarget, actionRun.TriggerEvent) // add another file whose name cannot match the specified path - addFileToForkedResp, err = files_service.ChangeRepoFiles(git.DefaultContext, forkedRepo, org3, &files_service.ChangeRepoFilesOptions{ + addFileToForkedResp, err = files_service.ChangeRepoFiles(git.DefaultContext, forkedRepo, user4, &files_service.ChangeRepoFilesOptions{ Files: []*files_service.ChangeRepoFile{ { Operation: "create", @@ -161,12 +167,12 @@ func TestPullRequestTargetEvent(t *testing.T) { OldBranch: "main", NewBranch: "fork-branch-2", Author: &files_service.IdentityOptions{ - Name: org3.Name, - Email: org3.Email, + Name: user4.Name, + Email: user4.Email, }, Committer: &files_service.IdentityOptions{ - Name: org3.Name, - Email: org3.Email, + Name: user4.Name, + Email: user4.Email, }, Dates: &files_service.CommitDateOptions{ Author: time.Now(), @@ -180,8 +186,8 @@ func TestPullRequestTargetEvent(t *testing.T) { pullIssue = &issues_model.Issue{ RepoID: baseRepo.ID, Title: "A mismatched path cannot trigger pull-request-target-event", - PosterID: org3.ID, - Poster: org3, + PosterID: user4.ID, + Poster: user4, IsPull: true, } pullRequest = &issues_model.PullRequest{ diff --git a/tests/integration/api_pull_test.go b/tests/integration/api_pull_test.go index 9bf0d3d745..8239878d2b 100644 --- a/tests/integration/api_pull_test.go +++ b/tests/integration/api_pull_test.go @@ -12,6 +12,7 @@ import ( auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -126,6 +127,65 @@ func TestAPICreatePullSuccess(t *testing.T) { MakeRequest(t, req, http.StatusUnprocessableEntity) // second request should fail } +func TestAPICreatePullBasePermission(t *testing.T) { + defer tests.PrepareTestEnv(t)() + repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) + // repo10 have code, pulls units. + repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11}) + // repo11 only have code unit but should still create pulls + owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID}) + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + + session := loginUser(t, user4.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + opts := &api.CreatePullRequestOption{ + Head: fmt.Sprintf("%s:master", repo11.OwnerName), + Base: "master", + Title: "create a failure pr", + } + req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner10.Name, repo10.Name), &opts).AddTokenAuth(token) + MakeRequest(t, req, http.StatusForbidden) + + // add user4 to be a collaborator to base repo + ctx := NewAPITestContext(t, repo10.OwnerName, repo10.Name, auth_model.AccessTokenScopeWriteRepository) + t.Run("AddUser4AsCollaborator", doAPIAddCollaborator(ctx, user4.Name, perm.AccessModeRead)) + + // create again + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner10.Name, repo10.Name), &opts).AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) +} + +func TestAPICreatePullHeadPermission(t *testing.T) { + defer tests.PrepareTestEnv(t)() + repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) + // repo10 have code, pulls units. + repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11}) + // repo11 only have code unit but should still create pulls + owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID}) + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + + session := loginUser(t, user4.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + opts := &api.CreatePullRequestOption{ + Head: fmt.Sprintf("%s:master", repo11.OwnerName), + Base: "master", + Title: "create a failure pr", + } + req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner10.Name, repo10.Name), &opts).AddTokenAuth(token) + MakeRequest(t, req, http.StatusForbidden) + + // add user4 to be a collaborator to head repo with read permission + ctx := NewAPITestContext(t, repo11.OwnerName, repo11.Name, auth_model.AccessTokenScopeWriteRepository) + t.Run("AddUser4AsCollaboratorWithRead", doAPIAddCollaborator(ctx, user4.Name, perm.AccessModeRead)) + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner10.Name, repo10.Name), &opts).AddTokenAuth(token) + MakeRequest(t, req, http.StatusForbidden) + + // add user4 to be a collaborator to head repo with write permission + t.Run("AddUser4AsCollaboratorWithWrite", doAPIAddCollaborator(ctx, user4.Name, perm.AccessModeWrite)) + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner10.Name, repo10.Name), &opts).AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) +} + func TestAPICreatePullSameRepoSuccess(t *testing.T) { defer tests.PrepareTestEnv(t)() repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) From 7b388630ecb4537f9bb04e55cbb10eb7cf83b9c5 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 29 Jul 2024 15:51:02 +0900 Subject: [PATCH 06/12] Fix loadRepository error when access user dashboard (#31719) --- models/git/commit_status.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index f80de9679f..deec21e38b 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -211,6 +211,10 @@ func (status *CommitStatus) LocaleString(lang translation.Locale) string { // HideActionsURL set `TargetURL` to an empty string if the status comes from Gitea Actions func (status *CommitStatus) HideActionsURL(ctx context.Context) { + if status.RepoID == 0 { + return + } + if status.Repo == nil { if err := status.loadRepository(ctx); err != nil { log.Error("loadRepository: %v", err) From bf5ae79c5163b8dd6a3185711ad11893b1270f62 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 30 Jul 2024 00:45:24 +0800 Subject: [PATCH 07/12] Fix API endpoint for registration-token (#31722) Partially fix #31707. Related to #30656 --- routers/api/v1/repo/action.go | 2 +- templates/swagger/v1_json.tmpl | 66 +++++++++++++++++----------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 48ba35ac21..a777779b24 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -486,7 +486,7 @@ func (Action) ListVariables(ctx *context.APIContext) { // GetRegistrationToken returns the token to register repo runners func (Action) GetRegistrationToken(ctx *context.APIContext) { - // swagger:operation GET /repos/{owner}/{repo}/runners/registration-token repository repoGetRunnerRegistrationToken + // swagger:operation GET /repos/{owner}/{repo}/actions/runners/registration-token repository repoGetRunnerRegistrationToken // --- // summary: Get a repository's actions runner registration token // produces: diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index e7c6761606..18b9cdab3a 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -3843,6 +3843,39 @@ } } }, + "/repos/{owner}/{repo}/actions/runners/registration-token": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Get a repository's actions runner registration token", + "operationId": "repoGetRunnerRegistrationToken", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/RegistrationToken" + } + } + } + }, "/repos/{owner}/{repo}/actions/secrets": { "get": { "produces": [ @@ -13408,39 +13441,6 @@ } } }, - "/repos/{owner}/{repo}/runners/registration-token": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "repository" - ], - "summary": "Get a repository's actions runner registration token", - "operationId": "repoGetRunnerRegistrationToken", - "parameters": [ - { - "type": "string", - "description": "owner of the repo", - "name": "owner", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "name of the repo", - "name": "repo", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "$ref": "#/responses/RegistrationToken" - } - } - } - }, "/repos/{owner}/{repo}/signing-key.gpg": { "get": { "produces": [ From d39bce7f003cf2137a5a561ed488c7b638e52275 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 30 Jul 2024 01:15:02 +0800 Subject: [PATCH 08/12] fix(api): owner ID should be zero when created repo secret (#31715) - Change condition to include `RepoID` equal to 0 for organization secrets --------- Signed-off-by: Bo-Yi Wu Co-authored-by: Giteabot --- routers/api/v1/repo/action.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index a777779b24..8add076c0e 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -117,12 +117,11 @@ func (Action) CreateOrUpdateSecret(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - owner := ctx.Repo.Owner repo := ctx.Repo.Repository opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption) - _, created, err := secret_service.CreateOrUpdateSecret(ctx, owner.ID, repo.ID, ctx.PathParam("secretname"), opt.Data) + _, created, err := secret_service.CreateOrUpdateSecret(ctx, 0, repo.ID, ctx.PathParam("secretname"), opt.Data) if err != nil { if errors.Is(err, util.ErrInvalidArgument) { ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err) @@ -174,10 +173,9 @@ func (Action) DeleteSecret(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - owner := ctx.Repo.Owner repo := ctx.Repo.Repository - err := secret_service.DeleteSecretByName(ctx, owner.ID, repo.ID, ctx.PathParam("secretname")) + err := secret_service.DeleteSecretByName(ctx, 0, repo.ID, ctx.PathParam("secretname")) if err != nil { if errors.Is(err, util.ErrInvalidArgument) { ctx.Error(http.StatusBadRequest, "DeleteSecret", err) From 81fa471119a6733d257f63f8c2c1f4acc583d21b Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 30 Jul 2024 02:46:45 +0800 Subject: [PATCH 09/12] Set owner id to zero when GetRegistrationToken for repo (#31725) Fix #31707. It's split from #31724. Although #31724 could also fix #31707, it has change a lot so it's not a good idea to backport it. --- routers/api/v1/repo/action.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 8add076c0e..d27e8d2427 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -504,7 +504,7 @@ func (Action) GetRegistrationToken(ctx *context.APIContext) { // "200": // "$ref": "#/responses/RegistrationToken" - shared.GetRegistrationToken(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID) + shared.GetRegistrationToken(ctx, 0, ctx.Repo.Repository.ID) } var _ actions_service.API = new(Action) From f989f464386139592b6911cad1be4c901eb97fe5 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 30 Jul 2024 10:27:28 +0800 Subject: [PATCH 10/12] Move `registerActionsCleanup` to `initActionsTasks` (#31721) There's already `initActionsTasks`; it will avoid additional check for if Actions enabled to move `registerActionsCleanup` into it. And we don't really need `OlderThanConfig`. --- services/actions/cleanup.go | 3 +-- services/cron/tasks_actions.go | 11 +++++++++++ services/cron/tasks_basic.go | 18 ------------------ 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/services/actions/cleanup.go b/services/actions/cleanup.go index 5376c2624c..6ccc8dd198 100644 --- a/services/actions/cleanup.go +++ b/services/actions/cleanup.go @@ -5,7 +5,6 @@ package actions import ( "context" - "time" "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/modules/log" @@ -13,7 +12,7 @@ import ( ) // Cleanup removes expired actions logs, data and artifacts -func Cleanup(taskCtx context.Context, olderThan time.Duration) error { +func Cleanup(taskCtx context.Context) error { // TODO: clean up expired actions logs // clean up expired artifacts diff --git a/services/cron/tasks_actions.go b/services/cron/tasks_actions.go index 0875792503..9b5e0b9f41 100644 --- a/services/cron/tasks_actions.go +++ b/services/cron/tasks_actions.go @@ -19,6 +19,7 @@ func initActionsTasks() { registerStopEndlessTasks() registerCancelAbandonedJobs() registerScheduleTasks() + registerActionsCleanup() } func registerStopZombieTasks() { @@ -63,3 +64,13 @@ func registerScheduleTasks() { return actions_service.StartScheduleTasks(ctx) }) } + +func registerActionsCleanup() { + RegisterTaskFatal("cleanup_actions", &BaseConfig{ + Enabled: true, + RunAtStart: true, + Schedule: "@midnight", + }, func(ctx context.Context, _ *user_model.User, _ Config) error { + return actions_service.Cleanup(ctx) + }) +} diff --git a/services/cron/tasks_basic.go b/services/cron/tasks_basic.go index 3869382d22..2a213ae515 100644 --- a/services/cron/tasks_basic.go +++ b/services/cron/tasks_basic.go @@ -13,7 +13,6 @@ import ( "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/auth" "code.gitea.io/gitea/services/migrations" mirror_service "code.gitea.io/gitea/services/mirror" @@ -157,20 +156,6 @@ func registerCleanupPackages() { }) } -func registerActionsCleanup() { - RegisterTaskFatal("cleanup_actions", &OlderThanConfig{ - BaseConfig: BaseConfig{ - Enabled: true, - RunAtStart: true, - Schedule: "@midnight", - }, - OlderThan: 24 * time.Hour, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - realConfig := config.(*OlderThanConfig) - return actions.Cleanup(ctx, realConfig.OlderThan) - }) -} - func initBasicTasks() { if setting.Mirror.Enabled { registerUpdateMirrorTask() @@ -187,7 +172,4 @@ func initBasicTasks() { if setting.Packages.Enabled { registerCleanupPackages() } - if setting.Actions.Enabled { - registerActionsCleanup() - } } From 0a11bce87f07233d5f02554b8f3b4a2aabd37769 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 30 Jul 2024 11:56:25 +0900 Subject: [PATCH 11/12] Fix Null Pointer error for CommitStatusesHideActionsURL (#31731) Fix https://github.com/go-gitea/gitea/pull/30156#discussion_r1695247028 Forgot fixing it in #31719 --- models/git/commit_status.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index deec21e38b..0579a41209 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -541,6 +541,10 @@ func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo func CommitStatusesHideActionsURL(ctx context.Context, statuses []*CommitStatus) { idToRepos := make(map[int64]*repo_model.Repository) for _, status := range statuses { + if status == nil { + continue + } + if status.Repo == nil { status.Repo = idToRepos[status.RepoID] } From 75d0b61546e00390afdd850149de525dd64336a5 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 30 Jul 2024 13:37:43 +0900 Subject: [PATCH 12/12] Fix the display of project type for deleted projects (#31732) Fix: #31727 After: ![image](https://github.com/user-attachments/assets/1dfb4b31-3bd6-47f7-b126-650f33f453e2) --- models/project/project.go | 7 +++++++ options/locale/locale_en-US.ini | 1 + routers/web/repo/issue.go | 2 +- templates/repo/issue/view_content/comments.tmpl | 14 ++++++++++---- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/models/project/project.go b/models/project/project.go index fe5d408f64..8cebf34b5e 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -103,6 +103,13 @@ type Project struct { ClosedDateUnix timeutil.TimeStamp } +// Ghost Project is a project which has been deleted +const GhostProjectID = -1 + +func (p *Project) IsGhost() bool { + return p.ID == GhostProjectID +} + func (p *Project) LoadOwner(ctx context.Context) (err error) { if p.Owner != nil { return nil diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 53d746ef12..ca7b42fa0a 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3705,6 +3705,7 @@ variables.update.failed = Failed to edit variable. variables.update.success = The variable has been edited. [projects] +deleted.display_name = Deleted Project type-1.display_name = Individual Project type-2.display_name = Repository Project type-3.display_name = Organization Project diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index ed2664db17..1018e88f1b 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1676,7 +1676,7 @@ func ViewIssue(ctx *context.Context) { } ghostProject := &project_model.Project{ - ID: -1, + ID: project_model.GhostProjectID, Title: ctx.Locale.TrString("repo.issues.deleted_project"), } diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index d8ca9de7bd..804cd6a2f9 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -581,13 +581,19 @@ {{template "shared/user/authorlink" .Poster}} {{$oldProjectDisplayHtml := "Unknown Project"}} {{if .OldProject}} - {{$trKey := printf "projects.type-%d.display_name" .OldProject.Type}} - {{$oldProjectDisplayHtml = HTMLFormat `%s` (ctx.Locale.Tr $trKey) .OldProject.Title}} + {{$tooltip := ctx.Locale.Tr "projects.deleted.display_name"}} + {{if not .OldProject.IsGhost}} + {{$tooltip = ctx.Locale.Tr (printf "projects.type-%d.display_name" .OldProject.Type)}} + {{end}} + {{$oldProjectDisplayHtml = HTMLFormat `%s` $tooltip .OldProject.Title}} {{end}} {{$newProjectDisplayHtml := "Unknown Project"}} {{if .Project}} - {{$trKey := printf "projects.type-%d.display_name" .Project.Type}} - {{$newProjectDisplayHtml = HTMLFormat `%s` (ctx.Locale.Tr $trKey) .Project.Title}} + {{$tooltip := ctx.Locale.Tr "projects.deleted.display_name"}} + {{if not .Project.IsGhost}} + {{$tooltip = ctx.Locale.Tr (printf "projects.type-%d.display_name" .Project.Type)}} + {{end}} + {{$newProjectDisplayHtml = HTMLFormat `%s` $tooltip .Project.Title}} {{end}} {{if and (gt .OldProjectID 0) (gt .ProjectID 0)}} {{ctx.Locale.Tr "repo.issues.change_project_at" $oldProjectDisplayHtml $newProjectDisplayHtml $createdStr}}