mirror of
https://github.com/go-gitea/gitea
synced 2025-02-26 23:04:18 +00:00
Backport #33549 - Find the runner before deleting - Move the main logic from `routers/web/repo/setting/runners.go` to `routers/web/shared/actions/runners.go`. Co-authored-by: Jason Song <i@wolfogre.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
7c17d0a73e
commit
7794ff0874
@ -167,6 +167,7 @@ func init() {
|
|||||||
|
|
||||||
type FindRunnerOptions struct {
|
type FindRunnerOptions struct {
|
||||||
db.ListOptions
|
db.ListOptions
|
||||||
|
IDs []int64
|
||||||
RepoID int64
|
RepoID int64
|
||||||
OwnerID int64 // it will be ignored if RepoID is set
|
OwnerID int64 // it will be ignored if RepoID is set
|
||||||
Sort string
|
Sort string
|
||||||
@ -178,6 +179,14 @@ type FindRunnerOptions struct {
|
|||||||
func (opts FindRunnerOptions) ToConds() builder.Cond {
|
func (opts FindRunnerOptions) ToConds() builder.Cond {
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
|
|
||||||
|
if len(opts.IDs) > 0 {
|
||||||
|
if len(opts.IDs) == 1 {
|
||||||
|
cond = cond.And(builder.Eq{"id": opts.IDs[0]})
|
||||||
|
} else {
|
||||||
|
cond = cond.And(builder.In("id", opts.IDs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if opts.RepoID > 0 {
|
if opts.RepoID > 0 {
|
||||||
c := builder.NewCond().And(builder.Eq{"repo_id": opts.RepoID})
|
c := builder.NewCond().And(builder.Eq{"repo_id": opts.RepoID})
|
||||||
if opts.WithAvailable {
|
if opts.WithAvailable {
|
||||||
|
@ -1,187 +0,0 @@
|
|||||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package setting
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
actions_model "code.gitea.io/gitea/models/actions"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
"code.gitea.io/gitea/modules/base"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
actions_shared "code.gitea.io/gitea/routers/web/shared/actions"
|
|
||||||
shared_user "code.gitea.io/gitea/routers/web/shared/user"
|
|
||||||
"code.gitea.io/gitea/services/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// TODO: Separate secrets from runners when layout is ready
|
|
||||||
tplRepoRunners base.TplName = "repo/settings/actions"
|
|
||||||
tplOrgRunners base.TplName = "org/settings/actions"
|
|
||||||
tplAdminRunners base.TplName = "admin/actions"
|
|
||||||
tplUserRunners base.TplName = "user/settings/actions"
|
|
||||||
tplRepoRunnerEdit base.TplName = "repo/settings/runner_edit"
|
|
||||||
tplOrgRunnerEdit base.TplName = "org/settings/runners_edit"
|
|
||||||
tplAdminRunnerEdit base.TplName = "admin/runners/edit"
|
|
||||||
tplUserRunnerEdit base.TplName = "user/settings/runner_edit"
|
|
||||||
)
|
|
||||||
|
|
||||||
type runnersCtx struct {
|
|
||||||
OwnerID int64
|
|
||||||
RepoID int64
|
|
||||||
IsRepo bool
|
|
||||||
IsOrg bool
|
|
||||||
IsAdmin bool
|
|
||||||
IsUser bool
|
|
||||||
RunnersTemplate base.TplName
|
|
||||||
RunnerEditTemplate base.TplName
|
|
||||||
RedirectLink string
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRunnersCtx(ctx *context.Context) (*runnersCtx, error) {
|
|
||||||
if ctx.Data["PageIsRepoSettings"] == true {
|
|
||||||
return &runnersCtx{
|
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
|
||||||
OwnerID: 0,
|
|
||||||
IsRepo: true,
|
|
||||||
RunnersTemplate: tplRepoRunners,
|
|
||||||
RunnerEditTemplate: tplRepoRunnerEdit,
|
|
||||||
RedirectLink: ctx.Repo.RepoLink + "/settings/actions/runners/",
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.Data["PageIsOrgSettings"] == true {
|
|
||||||
err := shared_user.LoadHeaderCount(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("LoadHeaderCount", err)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return &runnersCtx{
|
|
||||||
RepoID: 0,
|
|
||||||
OwnerID: ctx.Org.Organization.ID,
|
|
||||||
IsOrg: true,
|
|
||||||
RunnersTemplate: tplOrgRunners,
|
|
||||||
RunnerEditTemplate: tplOrgRunnerEdit,
|
|
||||||
RedirectLink: ctx.Org.OrgLink + "/settings/actions/runners/",
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.Data["PageIsAdmin"] == true {
|
|
||||||
return &runnersCtx{
|
|
||||||
RepoID: 0,
|
|
||||||
OwnerID: 0,
|
|
||||||
IsAdmin: true,
|
|
||||||
RunnersTemplate: tplAdminRunners,
|
|
||||||
RunnerEditTemplate: tplAdminRunnerEdit,
|
|
||||||
RedirectLink: setting.AppSubURL + "/-/admin/actions/runners/",
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.Data["PageIsUserSettings"] == true {
|
|
||||||
return &runnersCtx{
|
|
||||||
OwnerID: ctx.Doer.ID,
|
|
||||||
RepoID: 0,
|
|
||||||
IsUser: true,
|
|
||||||
RunnersTemplate: tplUserRunners,
|
|
||||||
RunnerEditTemplate: tplUserRunnerEdit,
|
|
||||||
RedirectLink: setting.AppSubURL + "/user/settings/actions/runners/",
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("unable to set Runners context")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Runners render settings/actions/runners page for repo level
|
|
||||||
func Runners(ctx *context.Context) {
|
|
||||||
ctx.Data["PageIsSharedSettingsRunners"] = true
|
|
||||||
ctx.Data["Title"] = ctx.Tr("actions.actions")
|
|
||||||
ctx.Data["PageType"] = "runners"
|
|
||||||
|
|
||||||
rCtx, err := getRunnersCtx(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("getRunnersCtx", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page := ctx.FormInt("page")
|
|
||||||
if page <= 1 {
|
|
||||||
page = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := actions_model.FindRunnerOptions{
|
|
||||||
ListOptions: db.ListOptions{
|
|
||||||
Page: page,
|
|
||||||
PageSize: 100,
|
|
||||||
},
|
|
||||||
Sort: ctx.Req.URL.Query().Get("sort"),
|
|
||||||
Filter: ctx.Req.URL.Query().Get("q"),
|
|
||||||
}
|
|
||||||
if rCtx.IsRepo {
|
|
||||||
opts.RepoID = rCtx.RepoID
|
|
||||||
opts.WithAvailable = true
|
|
||||||
} else if rCtx.IsOrg || rCtx.IsUser {
|
|
||||||
opts.OwnerID = rCtx.OwnerID
|
|
||||||
opts.WithAvailable = true
|
|
||||||
}
|
|
||||||
actions_shared.RunnersList(ctx, opts)
|
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, rCtx.RunnersTemplate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunnersEdit renders runner edit page for repository level
|
|
||||||
func RunnersEdit(ctx *context.Context) {
|
|
||||||
ctx.Data["PageIsSharedSettingsRunners"] = true
|
|
||||||
ctx.Data["Title"] = ctx.Tr("actions.runners.edit_runner")
|
|
||||||
rCtx, err := getRunnersCtx(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("getRunnersCtx", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page := ctx.FormInt("page")
|
|
||||||
if page <= 1 {
|
|
||||||
page = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
actions_shared.RunnerDetails(ctx, page,
|
|
||||||
ctx.PathParamInt64(":runnerid"), rCtx.OwnerID, rCtx.RepoID,
|
|
||||||
)
|
|
||||||
ctx.HTML(http.StatusOK, rCtx.RunnerEditTemplate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunnersEditPost(ctx *context.Context) {
|
|
||||||
rCtx, err := getRunnersCtx(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("getRunnersCtx", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
actions_shared.RunnerDetailsEditPost(ctx, ctx.PathParamInt64(":runnerid"),
|
|
||||||
rCtx.OwnerID, rCtx.RepoID,
|
|
||||||
rCtx.RedirectLink+url.PathEscape(ctx.PathParam(":runnerid")))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResetRunnerRegistrationToken(ctx *context.Context) {
|
|
||||||
rCtx, err := getRunnersCtx(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("getRunnersCtx", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
actions_shared.RunnerResetRegistrationToken(ctx, rCtx.OwnerID, rCtx.RepoID, rCtx.RedirectLink)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunnerDeletePost response for deleting runner
|
|
||||||
func RunnerDeletePost(ctx *context.Context) {
|
|
||||||
rCtx, err := getRunnersCtx(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("getRunnersCtx", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
actions_shared.RunnerDeletePost(ctx, ctx.PathParamInt64(":runnerid"), rCtx.RedirectLink, rCtx.RedirectLink+url.PathEscape(ctx.PathParam(":runnerid")))
|
|
||||||
}
|
|
||||||
|
|
||||||
func RedirectToDefaultSetting(ctx *context.Context) {
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/actions/runners")
|
|
||||||
}
|
|
@ -5,18 +5,131 @@ package actions
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
actions_model "code.gitea.io/gitea/models/actions"
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
shared_user "code.gitea.io/gitea/routers/web/shared/user"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunnersList prepares data for runners list
|
const (
|
||||||
func RunnersList(ctx *context.Context, opts actions_model.FindRunnerOptions) {
|
// TODO: Separate secrets from runners when layout is ready
|
||||||
|
tplRepoRunners base.TplName = "repo/settings/actions"
|
||||||
|
tplOrgRunners base.TplName = "org/settings/actions"
|
||||||
|
tplAdminRunners base.TplName = "admin/actions"
|
||||||
|
tplUserRunners base.TplName = "user/settings/actions"
|
||||||
|
tplRepoRunnerEdit base.TplName = "repo/settings/runner_edit"
|
||||||
|
tplOrgRunnerEdit base.TplName = "org/settings/runners_edit"
|
||||||
|
tplAdminRunnerEdit base.TplName = "admin/runners/edit"
|
||||||
|
tplUserRunnerEdit base.TplName = "user/settings/runner_edit"
|
||||||
|
)
|
||||||
|
|
||||||
|
type runnersCtx struct {
|
||||||
|
OwnerID int64
|
||||||
|
RepoID int64
|
||||||
|
IsRepo bool
|
||||||
|
IsOrg bool
|
||||||
|
IsAdmin bool
|
||||||
|
IsUser bool
|
||||||
|
RunnersTemplate base.TplName
|
||||||
|
RunnerEditTemplate base.TplName
|
||||||
|
RedirectLink string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRunnersCtx(ctx *context.Context) (*runnersCtx, error) {
|
||||||
|
if ctx.Data["PageIsRepoSettings"] == true {
|
||||||
|
return &runnersCtx{
|
||||||
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
OwnerID: 0,
|
||||||
|
IsRepo: true,
|
||||||
|
RunnersTemplate: tplRepoRunners,
|
||||||
|
RunnerEditTemplate: tplRepoRunnerEdit,
|
||||||
|
RedirectLink: ctx.Repo.RepoLink + "/settings/actions/runners/",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Data["PageIsOrgSettings"] == true {
|
||||||
|
err := shared_user.LoadHeaderCount(ctx)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("LoadHeaderCount", err)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &runnersCtx{
|
||||||
|
RepoID: 0,
|
||||||
|
OwnerID: ctx.Org.Organization.ID,
|
||||||
|
IsOrg: true,
|
||||||
|
RunnersTemplate: tplOrgRunners,
|
||||||
|
RunnerEditTemplate: tplOrgRunnerEdit,
|
||||||
|
RedirectLink: ctx.Org.OrgLink + "/settings/actions/runners/",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Data["PageIsAdmin"] == true {
|
||||||
|
return &runnersCtx{
|
||||||
|
RepoID: 0,
|
||||||
|
OwnerID: 0,
|
||||||
|
IsAdmin: true,
|
||||||
|
RunnersTemplate: tplAdminRunners,
|
||||||
|
RunnerEditTemplate: tplAdminRunnerEdit,
|
||||||
|
RedirectLink: setting.AppSubURL + "/-/admin/actions/runners/",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Data["PageIsUserSettings"] == true {
|
||||||
|
return &runnersCtx{
|
||||||
|
OwnerID: ctx.Doer.ID,
|
||||||
|
RepoID: 0,
|
||||||
|
IsUser: true,
|
||||||
|
RunnersTemplate: tplUserRunners,
|
||||||
|
RunnerEditTemplate: tplUserRunnerEdit,
|
||||||
|
RedirectLink: setting.AppSubURL + "/user/settings/actions/runners/",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("unable to set Runners context")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runners render settings/actions/runners page for repo level
|
||||||
|
func Runners(ctx *context.Context) {
|
||||||
|
ctx.Data["PageIsSharedSettingsRunners"] = true
|
||||||
|
ctx.Data["Title"] = ctx.Tr("actions.actions")
|
||||||
|
ctx.Data["PageType"] = "runners"
|
||||||
|
|
||||||
|
rCtx, err := getRunnersCtx(ctx)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("getRunnersCtx", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
page := ctx.FormInt("page")
|
||||||
|
if page <= 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := actions_model.FindRunnerOptions{
|
||||||
|
ListOptions: db.ListOptions{
|
||||||
|
Page: page,
|
||||||
|
PageSize: 100,
|
||||||
|
},
|
||||||
|
Sort: ctx.Req.URL.Query().Get("sort"),
|
||||||
|
Filter: ctx.Req.URL.Query().Get("q"),
|
||||||
|
}
|
||||||
|
if rCtx.IsRepo {
|
||||||
|
opts.RepoID = rCtx.RepoID
|
||||||
|
opts.WithAvailable = true
|
||||||
|
} else if rCtx.IsOrg || rCtx.IsUser {
|
||||||
|
opts.OwnerID = rCtx.OwnerID
|
||||||
|
opts.WithAvailable = true
|
||||||
|
}
|
||||||
|
|
||||||
runners, count, err := db.FindAndCount[actions_model.ActionRunner](ctx, opts)
|
runners, count, err := db.FindAndCount[actions_model.ActionRunner](ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("CountRunners", err)
|
ctx.ServerError("CountRunners", err)
|
||||||
@ -53,10 +166,29 @@ func RunnersList(ctx *context.Context, opts actions_model.FindRunnerOptions) {
|
|||||||
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
|
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
|
||||||
|
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
|
||||||
|
ctx.HTML(http.StatusOK, rCtx.RunnersTemplate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunnerDetails prepares data for runners edit page
|
// RunnersEdit renders runner edit page for repository level
|
||||||
func RunnerDetails(ctx *context.Context, page int, runnerID, ownerID, repoID int64) {
|
func RunnersEdit(ctx *context.Context) {
|
||||||
|
ctx.Data["PageIsSharedSettingsRunners"] = true
|
||||||
|
ctx.Data["Title"] = ctx.Tr("actions.runners.edit_runner")
|
||||||
|
rCtx, err := getRunnersCtx(ctx)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("getRunnersCtx", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
page := ctx.FormInt("page")
|
||||||
|
if page <= 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
runnerID := ctx.PathParamInt64("runnerid")
|
||||||
|
ownerID := rCtx.OwnerID
|
||||||
|
repoID := rCtx.RepoID
|
||||||
|
|
||||||
runner, err := actions_model.GetRunnerByID(ctx, runnerID)
|
runner, err := actions_model.GetRunnerByID(ctx, runnerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetRunnerByID", err)
|
ctx.ServerError("GetRunnerByID", err)
|
||||||
@ -97,10 +229,22 @@ func RunnerDetails(ctx *context.Context, page int, runnerID, ownerID, repoID int
|
|||||||
ctx.Data["Tasks"] = tasks
|
ctx.Data["Tasks"] = tasks
|
||||||
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
|
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
|
||||||
|
ctx.HTML(http.StatusOK, rCtx.RunnerEditTemplate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunnerDetailsEditPost response for edit runner details
|
func RunnersEditPost(ctx *context.Context) {
|
||||||
func RunnerDetailsEditPost(ctx *context.Context, runnerID, ownerID, repoID int64, redirectTo string) {
|
rCtx, err := getRunnersCtx(ctx)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("getRunnersCtx", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
runnerID := ctx.PathParamInt64("runnerid")
|
||||||
|
ownerID := rCtx.OwnerID
|
||||||
|
repoID := rCtx.RepoID
|
||||||
|
redirectTo := rCtx.RedirectLink
|
||||||
|
|
||||||
runner, err := actions_model.GetRunnerByID(ctx, runnerID)
|
runner, err := actions_model.GetRunnerByID(ctx, runnerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("RunnerDetailsEditPost.GetRunnerByID failed: %v, url: %s", err, ctx.Req.URL)
|
log.Warn("RunnerDetailsEditPost.GetRunnerByID failed: %v, url: %s", err, ctx.Req.URL)
|
||||||
@ -129,10 +273,18 @@ func RunnerDetailsEditPost(ctx *context.Context, runnerID, ownerID, repoID int64
|
|||||||
ctx.Redirect(redirectTo)
|
ctx.Redirect(redirectTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunnerResetRegistrationToken reset registration token
|
func ResetRunnerRegistrationToken(ctx *context.Context) {
|
||||||
func RunnerResetRegistrationToken(ctx *context.Context, ownerID, repoID int64, redirectTo string) {
|
rCtx, err := getRunnersCtx(ctx)
|
||||||
_, err := actions_model.NewRunnerToken(ctx, ownerID, repoID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ctx.ServerError("getRunnersCtx", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ownerID := rCtx.OwnerID
|
||||||
|
repoID := rCtx.RepoID
|
||||||
|
redirectTo := rCtx.RedirectLink
|
||||||
|
|
||||||
|
if _, err := actions_model.NewRunnerToken(ctx, ownerID, repoID); err != nil {
|
||||||
ctx.ServerError("ResetRunnerRegistrationToken", err)
|
ctx.ServerError("ResetRunnerRegistrationToken", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -140,11 +292,28 @@ func RunnerResetRegistrationToken(ctx *context.Context, ownerID, repoID int64, r
|
|||||||
ctx.JSONRedirect(redirectTo)
|
ctx.JSONRedirect(redirectTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunnerDeletePost response for deleting a runner
|
// RunnerDeletePost response for deleting runner
|
||||||
func RunnerDeletePost(ctx *context.Context, runnerID int64,
|
func RunnerDeletePost(ctx *context.Context) {
|
||||||
successRedirectTo, failedRedirectTo string,
|
rCtx, err := getRunnersCtx(ctx)
|
||||||
) {
|
if err != nil {
|
||||||
if err := actions_model.DeleteRunner(ctx, runnerID); err != nil {
|
ctx.ServerError("getRunnersCtx", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
runner := findActionsRunner(ctx, rCtx)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !runner.Editable(rCtx.OwnerID, rCtx.RepoID) {
|
||||||
|
ctx.NotFound("RunnerDeletePost", util.NewPermissionDeniedErrorf("no permission to delete this runner"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
successRedirectTo := rCtx.RedirectLink
|
||||||
|
failedRedirectTo := rCtx.RedirectLink + url.PathEscape(ctx.PathParam("runnerid"))
|
||||||
|
|
||||||
|
if err := actions_model.DeleteRunner(ctx, runner.ID); err != nil {
|
||||||
log.Warn("DeleteRunnerPost.UpdateRunner failed: %v, url: %s", err, ctx.Req.URL)
|
log.Warn("DeleteRunnerPost.UpdateRunner failed: %v, url: %s", err, ctx.Req.URL)
|
||||||
ctx.Flash.Warning(ctx.Tr("actions.runners.delete_runner_failed"))
|
ctx.Flash.Warning(ctx.Tr("actions.runners.delete_runner_failed"))
|
||||||
|
|
||||||
@ -158,3 +327,41 @@ func RunnerDeletePost(ctx *context.Context, runnerID int64,
|
|||||||
|
|
||||||
ctx.JSONRedirect(successRedirectTo)
|
ctx.JSONRedirect(successRedirectTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RedirectToDefaultSetting(ctx *context.Context) {
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings/actions/runners")
|
||||||
|
}
|
||||||
|
|
||||||
|
func findActionsRunner(ctx *context.Context, rCtx *runnersCtx) *actions_model.ActionRunner {
|
||||||
|
runnerID := ctx.PathParamInt64("runnerid")
|
||||||
|
opts := &actions_model.FindRunnerOptions{
|
||||||
|
IDs: []int64{runnerID},
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case rCtx.IsRepo:
|
||||||
|
opts.RepoID = rCtx.RepoID
|
||||||
|
if opts.RepoID == 0 {
|
||||||
|
panic("repoID is 0")
|
||||||
|
}
|
||||||
|
case rCtx.IsOrg, rCtx.IsUser:
|
||||||
|
opts.OwnerID = rCtx.OwnerID
|
||||||
|
if opts.OwnerID == 0 {
|
||||||
|
panic("ownerID is 0")
|
||||||
|
}
|
||||||
|
case rCtx.IsAdmin:
|
||||||
|
// do nothing
|
||||||
|
default:
|
||||||
|
panic("invalid actions runner context")
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := db.Find[actions_model.ActionRunner](ctx, opts)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("FindRunner", err)
|
||||||
|
return nil
|
||||||
|
} else if len(got) == 0 {
|
||||||
|
ctx.NotFound("FindRunner", errors.New("runner not found"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return got[0]
|
||||||
|
}
|
||||||
|
@ -460,11 +460,11 @@ func registerRoutes(m *web.Router) {
|
|||||||
|
|
||||||
addSettingsRunnersRoutes := func() {
|
addSettingsRunnersRoutes := func() {
|
||||||
m.Group("/runners", func() {
|
m.Group("/runners", func() {
|
||||||
m.Get("", repo_setting.Runners)
|
m.Get("", shared_actions.Runners)
|
||||||
m.Combo("/{runnerid}").Get(repo_setting.RunnersEdit).
|
m.Combo("/{runnerid}").Get(shared_actions.RunnersEdit).
|
||||||
Post(web.Bind(forms.EditRunnerForm{}), repo_setting.RunnersEditPost)
|
Post(web.Bind(forms.EditRunnerForm{}), shared_actions.RunnersEditPost)
|
||||||
m.Post("/{runnerid}/delete", repo_setting.RunnerDeletePost)
|
m.Post("/{runnerid}/delete", shared_actions.RunnerDeletePost)
|
||||||
m.Post("/reset_registration_token", repo_setting.ResetRunnerRegistrationToken)
|
m.Post("/reset_registration_token", shared_actions.ResetRunnerRegistrationToken)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1133,7 +1133,7 @@ func registerRoutes(m *web.Router) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
m.Group("/actions", func() {
|
m.Group("/actions", func() {
|
||||||
m.Get("", repo_setting.RedirectToDefaultSetting)
|
m.Get("", shared_actions.RedirectToDefaultSetting)
|
||||||
addSettingsRunnersRoutes()
|
addSettingsRunnersRoutes()
|
||||||
addSettingsSecretsRoutes()
|
addSettingsSecretsRoutes()
|
||||||
addSettingsVariablesRoutes()
|
addSettingsVariablesRoutes()
|
||||||
|
151
tests/integration/actions_runner_modify_test.go
Normal file
151
tests/integration/actions_runner_modify_test.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestActionsRunnerModify(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
require.NoError(t, db.DeleteAllRecords("action_runner"))
|
||||||
|
|
||||||
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
_ = actions_model.CreateRunner(ctx, &actions_model.ActionRunner{OwnerID: user2.ID, Name: "user2-runner", TokenHash: "a", UUID: "a"})
|
||||||
|
user2Runner := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{OwnerID: user2.ID, Name: "user2-runner"})
|
||||||
|
userWebURL := "/user/settings/actions/runners"
|
||||||
|
|
||||||
|
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3, Type: user_model.UserTypeOrganization})
|
||||||
|
require.NoError(t, actions_model.CreateRunner(ctx, &actions_model.ActionRunner{OwnerID: org3.ID, Name: "org3-runner", TokenHash: "b", UUID: "b"}))
|
||||||
|
org3Runner := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{OwnerID: org3.ID, Name: "org3-runner"})
|
||||||
|
orgWebURL := "/org/org3/settings/actions/runners"
|
||||||
|
|
||||||
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
|
_ = actions_model.CreateRunner(ctx, &actions_model.ActionRunner{RepoID: repo1.ID, Name: "repo1-runner", TokenHash: "c", UUID: "c"})
|
||||||
|
repo1Runner := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{RepoID: repo1.ID, Name: "repo1-runner"})
|
||||||
|
repoWebURL := "/user2/repo1/settings/actions/runners"
|
||||||
|
|
||||||
|
_ = actions_model.CreateRunner(ctx, &actions_model.ActionRunner{Name: "global-runner", TokenHash: "d", UUID: "d"})
|
||||||
|
globalRunner := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{Name: "global-runner"})
|
||||||
|
adminWebURL := "/-/admin/actions/runners"
|
||||||
|
|
||||||
|
sessionAdmin := loginUser(t, "user1")
|
||||||
|
sessionUser2 := loginUser(t, user2.Name)
|
||||||
|
|
||||||
|
doUpdate := func(t *testing.T, sess *TestSession, baseURL string, id int64, description string, expectedStatus int) {
|
||||||
|
req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/%d", baseURL, id), map[string]string{
|
||||||
|
"_csrf": GetUserCSRFToken(t, sess),
|
||||||
|
"description": description,
|
||||||
|
})
|
||||||
|
sess.MakeRequest(t, req, expectedStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
doDelete := func(t *testing.T, sess *TestSession, baseURL string, id int64, expectedStatus int) {
|
||||||
|
req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/%d/delete", baseURL, id), map[string]string{
|
||||||
|
"_csrf": GetUserCSRFToken(t, sess),
|
||||||
|
})
|
||||||
|
sess.MakeRequest(t, req, expectedStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertDenied := func(t *testing.T, sess *TestSession, baseURL string, id int64) {
|
||||||
|
doUpdate(t, sess, baseURL, id, "ChangedDescription", http.StatusNotFound)
|
||||||
|
doDelete(t, sess, baseURL, id, http.StatusNotFound)
|
||||||
|
v := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: id})
|
||||||
|
assert.Empty(t, v.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSuccess := func(t *testing.T, sess *TestSession, baseURL string, id int64) {
|
||||||
|
doUpdate(t, sess, baseURL, id, "ChangedDescription", http.StatusSeeOther)
|
||||||
|
v := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: id})
|
||||||
|
assert.Equal(t, "ChangedDescription", v.Description)
|
||||||
|
doDelete(t, sess, baseURL, id, http.StatusOK)
|
||||||
|
unittest.AssertNotExistsBean(t, &actions_model.ActionRunner{ID: id})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("UpdateUserRunner", func(t *testing.T) {
|
||||||
|
theRunner := user2Runner
|
||||||
|
t.Run("FromOrg", func(t *testing.T) {
|
||||||
|
assertDenied(t, sessionAdmin, orgWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
t.Run("FromRepo", func(t *testing.T) {
|
||||||
|
assertDenied(t, sessionAdmin, repoWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
t.Run("FromAdmin", func(t *testing.T) {
|
||||||
|
t.Skip("Admin can update any runner (not right but not too bad)")
|
||||||
|
assertDenied(t, sessionAdmin, adminWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("UpdateOrgRunner", func(t *testing.T) {
|
||||||
|
theRunner := org3Runner
|
||||||
|
t.Run("FromRepo", func(t *testing.T) {
|
||||||
|
assertDenied(t, sessionAdmin, repoWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
t.Run("FromUser", func(t *testing.T) {
|
||||||
|
assertDenied(t, sessionAdmin, userWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
t.Run("FromAdmin", func(t *testing.T) {
|
||||||
|
t.Skip("Admin can update any runner (not right but not too bad)")
|
||||||
|
assertDenied(t, sessionAdmin, adminWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("UpdateRepoRunner", func(t *testing.T) {
|
||||||
|
theRunner := repo1Runner
|
||||||
|
t.Run("FromOrg", func(t *testing.T) {
|
||||||
|
assertDenied(t, sessionAdmin, orgWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
t.Run("FromUser", func(t *testing.T) {
|
||||||
|
assertDenied(t, sessionAdmin, userWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
t.Run("FromAdmin", func(t *testing.T) {
|
||||||
|
t.Skip("Admin can update any runner (not right but not too bad)")
|
||||||
|
assertDenied(t, sessionAdmin, adminWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("UpdateGlobalRunner", func(t *testing.T) {
|
||||||
|
theRunner := globalRunner
|
||||||
|
t.Run("FromOrg", func(t *testing.T) {
|
||||||
|
assertDenied(t, sessionAdmin, orgWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
t.Run("FromUser", func(t *testing.T) {
|
||||||
|
assertDenied(t, sessionAdmin, userWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
t.Run("FromRepo", func(t *testing.T) {
|
||||||
|
assertDenied(t, sessionAdmin, repoWebURL, theRunner.ID)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("UpdateSuccess", func(t *testing.T) {
|
||||||
|
t.Run("User", func(t *testing.T) {
|
||||||
|
assertSuccess(t, sessionUser2, userWebURL, user2Runner.ID)
|
||||||
|
})
|
||||||
|
t.Run("Org", func(t *testing.T) {
|
||||||
|
assertSuccess(t, sessionAdmin, orgWebURL, org3Runner.ID)
|
||||||
|
})
|
||||||
|
t.Run("Repo", func(t *testing.T) {
|
||||||
|
assertSuccess(t, sessionUser2, repoWebURL, repo1Runner.ID)
|
||||||
|
})
|
||||||
|
t.Run("Admin", func(t *testing.T) {
|
||||||
|
assertSuccess(t, sessionAdmin, adminWebURL, globalRunner.ID)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user