Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve and fix bugs in runner management page #24366

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 59 additions & 6 deletions models/actions/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/timeutil"
Expand Down Expand Up @@ -52,6 +53,30 @@ type ActionRunner struct {
Deleted timeutil.TimeStamp `xorm:"deleted"`
}

// RunnerType defines the runner type
type RunnerType int //revive:disable-line:exported

const (
// RunnerTypeGlobal defines a global runner
RunnerTypeGlobal RunnerType = iota

// RunnerTypeOrganization defines an organization runner
RunnerTypeOrganization

// RunnerTypeRepository defines a repository runner
RunnerTypeRepository
)

func (r *ActionRunner) Type() RunnerType {
if r.RepoID != 0 {
return RunnerTypeRepository
}
if r.OwnerID != 0 {
return RunnerTypeOrganization
}
return RunnerTypeGlobal
}

func (r *ActionRunner) OwnType() string {
if r.RepoID != 0 {
return fmt.Sprintf("Repo(%s)", r.Repo.FullName())
Expand Down Expand Up @@ -94,14 +119,40 @@ func (r *ActionRunner) AllLabels() []string {
}

// Editable checks if the runner is editable by the user
func (r *ActionRunner) Editable(ownerID, repoID int64) bool {
if ownerID == 0 && repoID == 0 {
return true
func (r *ActionRunner) Editable(doer, owner *user_model.User, repo *repo_model.Repository) (bool, error) {
if doer == nil {
return false, nil
}
if ownerID > 0 && r.OwnerID == ownerID {
return true

// global runner in admin settings
if doer.IsAdmin {
return true, nil
}

if repo != nil {
// repo runner in repo runners list
if r.Type() == RunnerTypeRepository && r.RepoID == repo.ID {
return true, nil
}

if err := repo.LoadOwner(db.DefaultContext); err != nil {
yp05327 marked this conversation as resolved.
Show resolved Hide resolved
return false, err
}
// org runner in repo runners list
if r.Type() == RunnerTypeOrganization && repo.Owner.IsOrganization() {
isOrgOwner, err := (*organization.Organization)(repo.Owner).IsOwnedBy(doer.ID)
if err != nil {
return false, err
}
return repo.OwnerID == r.OwnerID && isOrgOwner, nil
}
}

if owner == nil {
return false, nil
}
return repoID > 0 && r.RepoID == repoID
// org runner in org runners list
return r.Type() == RunnerTypeOrganization && r.OwnerID == owner.ID && owner.IsOrganization(), nil
}

// LoadAttributes loads the attributes of the runner
Expand Down Expand Up @@ -141,7 +192,9 @@ func init() {
type FindRunnerOptions struct {
db.ListOptions
RepoID int64
Repo *repo_model.Repository
OwnerID int64
Owner *user_model.User
Sort string
Filter string
WithAvailable bool // not only runners belong to, but also runners can be used
Expand Down
2 changes: 2 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3397,6 +3397,7 @@ runners.owner_type = Type
runners.description = Description
runners.labels = Labels
runners.last_online = Last Online Time
runners.no_permission_to_edit = You don't have permission to edit this runner.
runners.agent_labels = Agent Labels
runners.custom_labels = Custom Labels
runners.custom_labels_helper = Custom labels are labels that are added manually by an administrator. A comma separates labels, whitespace at the start and end of each label is ignored.
Expand All @@ -3407,6 +3408,7 @@ runners.task_list.status = Status
runners.task_list.repository = Repository
runners.task_list.commit = Commit
runners.task_list.done_at = Done At
runners.task_list.no_tasks = No tasks
runners.edit_runner = Edit Runner
runners.update_runner = Update Changes
runners.update_runner_success = Runner updated successfully
Expand Down
19 changes: 16 additions & 3 deletions routers/web/repo/setting/runners.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import (

actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"

actions_shared "code.gitea.io/gitea/routers/web/shared/actions"
)

Expand All @@ -28,7 +31,9 @@ const (

type runnersCtx struct {
OwnerID int64
Owner *user_model.User
RepoID int64
Repo *repo_model.Repository
IsRepo bool
IsOrg bool
IsAdmin bool
Expand All @@ -41,7 +46,9 @@ func getRunnersCtx(ctx *context.Context) (*runnersCtx, error) {
if ctx.Data["PageIsRepoSettings"] == true {
return &runnersCtx{
RepoID: ctx.Repo.Repository.ID,
Repo: ctx.Repo.Repository,
OwnerID: 0,
Owner: nil,
IsRepo: true,
RunnersTemplate: tplRepoRunners,
RunnerEditTemplate: tplRepoRunnerEdit,
Expand All @@ -52,7 +59,9 @@ func getRunnersCtx(ctx *context.Context) (*runnersCtx, error) {
if ctx.Data["PageIsOrgSettings"] == true {
return &runnersCtx{
RepoID: 0,
Repo: nil,
OwnerID: ctx.Org.Organization.ID,
Owner: ctx.Org.Organization.AsUser(),
IsOrg: true,
RunnersTemplate: tplOrgRunners,
RunnerEditTemplate: tplOrgRunnerEdit,
Expand All @@ -63,7 +72,9 @@ func getRunnersCtx(ctx *context.Context) (*runnersCtx, error) {
if ctx.Data["PageIsAdmin"] == true {
return &runnersCtx{
RepoID: 0,
Repo: nil,
OwnerID: 0,
Owner: nil,
IsAdmin: true,
RunnersTemplate: tplAdminRunners,
RunnerEditTemplate: tplAdminRunnerEdit,
Expand Down Expand Up @@ -101,9 +112,11 @@ func Runners(ctx *context.Context) {
}
if rCtx.IsRepo {
opts.RepoID = rCtx.RepoID
opts.Repo = rCtx.Repo
opts.WithAvailable = true
} else if rCtx.IsOrg {
opts.OwnerID = rCtx.OwnerID
opts.Owner = rCtx.Owner
opts.WithAvailable = true
}
actions_shared.RunnersList(ctx, opts)
Expand All @@ -127,7 +140,7 @@ func RunnersEdit(ctx *context.Context) {
}

actions_shared.RunnerDetails(ctx, page,
ctx.ParamsInt64(":runnerid"), rCtx.OwnerID, rCtx.RepoID,
ctx.ParamsInt64(":runnerid"), rCtx.Owner, rCtx.Repo,
)
ctx.HTML(http.StatusOK, rCtx.RunnerEditTemplate)
}
Expand All @@ -139,8 +152,8 @@ func RunnersEditPost(ctx *context.Context) {
return
}
actions_shared.RunnerDetailsEditPost(ctx, ctx.ParamsInt64(":runnerid"),
rCtx.OwnerID, rCtx.RepoID,
rCtx.RedirectLink+url.PathEscape(ctx.Params(":runnerid")))
rCtx.RedirectLink+url.PathEscape(ctx.Params(":runnerid")),
rCtx.Owner, rCtx.Repo)
}

func ResetRunnerRegistrationToken(ctx *context.Context) {
Expand Down
20 changes: 14 additions & 6 deletions routers/web/shared/actions/runners.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (

actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
Expand Down Expand Up @@ -53,16 +55,16 @@ func RunnersList(ctx *context.Context, opts actions_model.FindRunnerOptions) {
ctx.Data["Runners"] = runners
ctx.Data["Total"] = count
ctx.Data["RegistrationToken"] = token.Token
ctx.Data["RunnerOnwerID"] = opts.OwnerID
ctx.Data["RunnerRepoID"] = opts.RepoID
ctx.Data["RunnerOwner"] = opts.Owner
ctx.Data["RunnerRepo"] = opts.Repo

pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)

ctx.Data["Page"] = pager
}

// RunnerDetails prepares data for runners edit page
func RunnerDetails(ctx *context.Context, page int, runnerID, ownerID, repoID int64) {
func RunnerDetails(ctx *context.Context, page int, runnerID int64, owner *user.User, repo *repo.Repository) {
runner, err := actions_model.GetRunnerByID(ctx, runnerID)
if err != nil {
ctx.ServerError("GetRunnerByID", err)
Expand All @@ -72,7 +74,10 @@ func RunnerDetails(ctx *context.Context, page int, runnerID, ownerID, repoID int
ctx.ServerError("LoadAttributes", err)
return
}
if !runner.Editable(ownerID, repoID) {
if editable, err := runner.Editable(ctx.Doer, owner, repo); err != nil {
ctx.ServerError("Editable", err)
return
} else if !editable {
err = errors.New("no permission to edit this runner")
ctx.NotFound("RunnerDetails", err)
return
Expand Down Expand Up @@ -112,14 +117,17 @@ func RunnerDetails(ctx *context.Context, page int, runnerID, ownerID, repoID int
}

// RunnerDetailsEditPost response for edit runner details
func RunnerDetailsEditPost(ctx *context.Context, runnerID, ownerID, repoID int64, redirectTo string) {
func RunnerDetailsEditPost(ctx *context.Context, runnerID int64, redirectTo string, owner *user.User, repo *repo.Repository) {
runner, err := actions_model.GetRunnerByID(ctx, runnerID)
if err != nil {
log.Warn("RunnerDetailsEditPost.GetRunnerByID failed: %v, url: %s", err, ctx.Req.URL)
ctx.ServerError("RunnerDetailsEditPost.GetRunnerByID", err)
return
}
if !runner.Editable(ownerID, repoID) {
if editable, err := runner.Editable(ctx.Doer, owner, repo); err != nil {
ctx.ServerError("Editable", err)
return
} else if !editable {
ctx.NotFound("RunnerDetailsEditPost.Editable", util.NewPermissionDeniedErrorf("no permission to edit this runner"))
return
}
Expand Down
4 changes: 2 additions & 2 deletions templates/shared/actions/runner_edit.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<h4 class="ui top attached header">
{{.locale.Tr "actions.runners.task_list"}}
</h4>
<div class="ui attached segment">
<div class="ui attached table segment">
<table class="ui very basic striped table unstackable">
<thead>
<tr>
Expand All @@ -81,7 +81,7 @@
{{end}}
{{if not .Tasks}}
<tr>
<td colspan="5">{{.locale.Tr "runners.task_list.no_tasks"}}</td>
<td colspan="5">{{.locale.Tr "actions.runners.task_list.no_tasks"}}</td>
</tr>
{{end}}
</tbody>
Expand Down
4 changes: 3 additions & 1 deletion templates/shared/actions/runner_list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@
</td>
<td>{{if .LastOnline}}{{TimeSinceUnix .LastOnline $.locale}}{{else}}{{$.locale.Tr "never"}}{{end}}</td>
<td class="runner-ops">
{{if .Editable $.RunnerOnwerID $.RunnerRepoID}}
{{if .Editable $.Context.Doer $.RunnerOwner $.RunnerRepo}}
<a href="{{$.Link}}/{{.ID}}">{{svg "octicon-pencil"}}</a>
{{else}}
<div data-tooltip-content="{{$.locale.Tr "actions.runners.no_permission_to_edit"}}">{{svg "octicon-x"}}</div>
{{end}}
</td>
</tr>
Expand Down
4 changes: 4 additions & 0 deletions web_src/css/runner.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
margin-left: 0.5em;
}

.runner-container .runner-ops > div {
yp05327 marked this conversation as resolved.
Show resolved Hide resolved
margin-left: 0.5em;
}

.runner-container .runner-ops-delete {
color: var(--color-red-light);
}
Expand Down