feat: vendor gitea 1.16.2

This commit is contained in:
2026-06-02 08:36:01 +00:00
parent 247cd60f69
commit 54798b4615
2145 changed files with 162965 additions and 126447 deletions
@@ -0,0 +1,160 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package actions
import (
"net/http"
"slices"
"strconv"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
)
const (
tplOrgSettingsActionsGeneral templates.TplName = "org/settings/actions_general"
tplUserSettingsActionsGeneral templates.TplName = "user/settings/actions_general"
)
// ParseMaxTokenPermissions parses the maximum token permissions from form values
func ParseMaxTokenPermissions(ctx *context.Context) *repo_model.ActionsTokenPermissions {
parseMaxPerm := func(unitType unit.Type) perm.AccessMode {
value := ctx.FormString("max_unit_access_mode_" + strconv.Itoa(int(unitType)))
switch value {
case "write":
return perm.AccessModeWrite
case "read":
return perm.AccessModeRead
default:
return perm.AccessModeNone
}
}
ret := new(repo_model.MakeActionsTokenPermissions(perm.AccessModeNone))
for _, ut := range repo_model.ActionsTokenUnitTypes {
ret.UnitAccessModes[ut] = parseMaxPerm(ut)
}
return ret
}
// GeneralSettings renders the actions general settings page
func GeneralSettings(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("actions.actions")
rCtx, err := getRunnersCtx(ctx)
if err != nil {
ctx.ServerError("getRunnersCtx", err)
return
}
if rCtx.IsOrg {
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsOrgSettingsActionsGeneral"] = true
} else if rCtx.IsUser {
ctx.Data["PageIsUserSettings"] = true
ctx.Data["PageIsUserSettingsActionsGeneral"] = true
} else {
ctx.NotFound(nil)
return
}
// Load User/Org Actions Config
actionsCfg, err := actions_model.GetOwnerActionsConfig(ctx, rCtx.OwnerID)
if err != nil {
ctx.ServerError("GetOwnerActionsConfig", err)
return
}
ctx.Data["TokenPermissionMode"] = actionsCfg.TokenPermissionMode
ctx.Data["TokenPermissionModePermissive"] = repo_model.ActionsTokenPermissionModePermissive
ctx.Data["TokenPermissionModeRestricted"] = repo_model.ActionsTokenPermissionModeRestricted
ctx.Data["MaxTokenPermissions"] = actionsCfg.MaxTokenPermissions
if actionsCfg.MaxTokenPermissions == nil {
ctx.Data["MaxTokenPermissions"] = (&repo_model.ActionsConfig{}).GetMaxTokenPermissions()
}
ctx.Data["EnableMaxTokenPermissions"] = actionsCfg.MaxTokenPermissions != nil
// Load Allowed Repositories
allowedRepos, err := repo_model.GetOwnerRepositoriesByIDs(ctx, rCtx.OwnerID, actionsCfg.AllowedCrossRepoIDs)
if err != nil {
ctx.ServerError("GetOwnerRepositoriesByIDs", err)
return
}
ctx.Data["AllowedRepos"] = allowedRepos
ctx.Data["OwnerID"] = rCtx.OwnerID
if rCtx.IsOrg {
ctx.HTML(http.StatusOK, tplOrgSettingsActionsGeneral)
} else {
ctx.HTML(http.StatusOK, tplUserSettingsActionsGeneral)
}
}
// UpdateGeneralSettings responses for actions general settings page
func UpdateGeneralSettings(ctx *context.Context) {
rCtx, err := getRunnersCtx(ctx)
if err != nil {
ctx.ServerError("getRunnersCtx", err)
return
}
if !rCtx.IsOrg && !rCtx.IsUser {
ctx.NotFound(nil)
return
}
actionsCfg, err := actions_model.GetOwnerActionsConfig(ctx, rCtx.OwnerID)
if err != nil {
ctx.ServerError("GetOwnerActionsConfig", err)
return
}
if ctx.FormBool("cross_repo_add_target") {
targetRepoName := ctx.FormString("cross_repo_add_target_name")
if targetRepoName != "" {
targetRepo, err := repo_model.GetRepositoryByName(ctx, rCtx.OwnerID, targetRepoName)
if err != nil {
if repo_model.IsErrRepoNotExist(err) {
ctx.JSONError("Repository doesn't exist")
return
}
ctx.ServerError("GetRepositoryByName", err)
return
}
if !slices.Contains(actionsCfg.AllowedCrossRepoIDs, targetRepo.ID) {
actionsCfg.AllowedCrossRepoIDs = append(actionsCfg.AllowedCrossRepoIDs, targetRepo.ID)
}
}
}
if crossRepoRemoveTargetID := ctx.FormInt64("cross_repo_remove_target_id"); crossRepoRemoveTargetID != 0 {
actionsCfg.AllowedCrossRepoIDs = util.SliceRemoveAll(actionsCfg.AllowedCrossRepoIDs, crossRepoRemoveTargetID)
}
// Update Token Permission Mode
tokenPermissionMode, tokenPermissionModeValid := util.EnumValue(repo_model.ActionsTokenPermissionMode(ctx.FormString("token_permission_mode")))
if tokenPermissionModeValid {
actionsCfg.TokenPermissionMode = tokenPermissionMode
enableMaxPermissions := ctx.FormBool("enable_max_permissions")
// Update Maximum Permissions (radio buttons: none/read/write)
if enableMaxPermissions {
actionsCfg.MaxTokenPermissions = ParseMaxTokenPermissions(ctx)
} else {
actionsCfg.MaxTokenPermissions = nil
}
}
if err := actions_model.SetOwnerActionsConfig(ctx, rCtx.OwnerID, actionsCfg); err != nil {
ctx.ServerError("SetOwnerActionsConfig", err)
return
}
ctx.Flash.Success(ctx.Tr("settings.saved_successfully"))
ctx.JSONRedirect("") // use JSONRedirect because frontend uses form-fetch-action
}
@@ -5,6 +5,7 @@ package actions
import (
"errors"
"fmt"
"net/http"
"net/url"
@@ -58,8 +59,7 @@ func getRunnersCtx(ctx *context.Context) (*runnersCtx, error) {
if ctx.Data["PageIsOrgSettings"] == true {
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
return nil, nil
return nil, fmt.Errorf("RenderUserOrgHeader: %w", err)
}
return &runnersCtx{
RepoID: 0,
@@ -159,7 +159,7 @@ func Runners(ctx *context.Context) {
ctx.Data["RunnerRepoID"] = opts.RepoID
ctx.Data["SortType"] = opts.Sort
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
pager := context.NewPagination(count, opts.PageSize, opts.Page, 5)
ctx.Data["Page"] = pager
@@ -220,7 +220,7 @@ func RunnersEdit(ctx *context.Context) {
}
ctx.Data["Tasks"] = tasks
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
pager := context.NewPagination(count, opts.PageSize, opts.Page, 5)
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, rCtx.RunnerEditTemplate)
@@ -321,6 +321,47 @@ func RunnerDeletePost(ctx *context.Context) {
ctx.JSONRedirect(successRedirectTo)
}
func RunnerUpdatePost(ctx *context.Context) {
rCtx, err := getRunnersCtx(ctx)
if err != nil {
ctx.ServerError("getRunnersCtx", err)
return
}
runner := findActionsRunner(ctx, rCtx)
if ctx.Written() {
return
}
if !runner.EditableInContext(rCtx.OwnerID, rCtx.RepoID) {
ctx.NotFound(util.NewPermissionDeniedErrorf("no permission to edit this runner"))
return
}
isDisabled := ctx.FormOptionalBool("disabled")
if !isDisabled.Has() {
ctx.HTTPError(http.StatusBadRequest, "missing 'disabled' parameter")
return
}
successKey := "actions.runners.enable_runner_success"
failedKey := "actions.runners.enable_runner_failed"
if isDisabled.Value() {
successKey = "actions.runners.disable_runner_success"
failedKey = "actions.runners.disable_runner_failed"
}
if err := actions_model.SetRunnerDisabled(ctx, runner, isDisabled.Value()); err != nil {
log.Warn("RunnerUpdatePost.SetRunnerDisabled failed: %v, url: %s", err, ctx.Req.URL)
ctx.Flash.Error(ctx.Tr(failedKey))
ctx.JSONRedirect("")
return
}
ctx.Flash.Success(ctx.Tr(successKey))
ctx.JSONRedirect("")
}
func RedirectToDefaultSetting(ctx *context.Context) {
ctx.Redirect(ctx.Repo.RepoLink + "/settings/actions/runners")
}
@@ -51,7 +51,7 @@ func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
if ctx.Data["PageIsOrgSettings"] == true {
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
return nil, nil
return nil, nil //nolint:nilnil // error is already handled by ctx.ServerError
}
return &variablesCtx{
OwnerID: ctx.ContextUser.ID,
@@ -0,0 +1,89 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package mention
import (
"context"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user"
)
// Mention is the JSON structure returned by mention autocomplete endpoints.
type Mention struct {
Key string `json:"key"`
Value string `json:"value"`
Name string `json:"name"`
FullName string `json:"fullname"`
Avatar string `json:"avatar"`
}
// Collector builds a deduplicated list of Mention entries.
type Collector struct {
seen map[string]bool
Result []Mention
}
// NewCollector creates a new Collector.
func NewCollector() *Collector {
return &Collector{seen: make(map[string]bool)}
}
// AddUsers adds user mentions, skipping duplicates.
func (c *Collector) AddUsers(ctx context.Context, users []*user_model.User) {
for _, u := range users {
if !c.seen[u.Name] {
c.seen[u.Name] = true
c.Result = append(c.Result, Mention{
Key: u.Name + " " + u.FullName,
Value: u.Name,
Name: u.Name,
FullName: u.FullName,
Avatar: u.AvatarLink(ctx),
})
}
}
}
// AddMentionableTeams loads and adds team mentions for the given owner (if it's an org).
func (c *Collector) AddMentionableTeams(ctx context.Context, doer, owner *user_model.User) error {
if doer == nil || !owner.IsOrganization() {
return nil
}
org := organization.OrgFromUser(owner)
isAdmin := doer.IsAdmin
if !isAdmin {
var err error
isAdmin, err = org.IsOwnedBy(ctx, doer.ID)
if err != nil {
return err
}
}
var teams []*organization.Team
var err error
if isAdmin {
teams, err = org.LoadTeams(ctx)
} else {
teams, err = org.GetUserTeams(ctx, doer.ID)
}
if err != nil {
return err
}
for _, team := range teams {
key := owner.Name + "/" + team.Name
if !c.seen[key] {
c.seen[key] = true
c.Result = append(c.Result, Mention{
Key: key,
Value: key,
Name: key,
Avatar: owner.AvatarLink(ctx),
})
}
}
return nil
}
@@ -29,7 +29,7 @@ func SetSecretsContext(ctx *context.Context, ownerID, repoID int64) {
func PerformSecretsPost(ctx *context.Context, ownerID, repoID int64, redirectURL string) {
form := web.GetForm(ctx).(*forms.AddSecretForm)
s, _, err := secret_service.CreateOrUpdateSecret(ctx, ownerID, repoID, form.Name, util.ReserveLineBreakForTextarea(form.Data), form.Description)
s, _, err := secret_service.CreateOrUpdateSecret(ctx, ownerID, repoID, form.Name, util.NormalizeStringEOL(form.Data), form.Description)
if err != nil {
log.Error("CreateOrUpdateSecret failed: %v", err)
ctx.JSONError(ctx.Tr("secrets.save_failed"))
@@ -101,7 +101,7 @@ func FindOwnerProfileReadme(ctx *context.Context, doer *user_model.User, optProf
return nil, nil
}
perm, err := access_model.GetUserRepoPermission(ctx, profileDbRepo, doer)
perm, err := access_model.GetDoerRepoPermission(ctx, profileDbRepo, doer)
if err != nil {
log.Error("FindOwnerProfileReadme failed to GetRepositoryByName: %v", err)
return nil, nil