feat: scope-specific headings for list of recent tasks (#11690)
As requested in https://codeberg.org/forgejo/forgejo/pulls/11516#issuecomment-11430034, the headings of the list of recent tasks that were executed on a particular runner now indicate that only tasks are listed that originated in the current scope. ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests for Go changes (can be removed for JavaScript changes) - I added test coverage for Go changes... - [ ] in their respective `*_test.go` for unit tests. - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I ran... - [x] `make pr-go` before pushing ### Tests for JavaScript changes (can be removed for Go changes) - I added test coverage for JavaScript changes... - [ ] in `web_src/js/*.test.js` if it can be unit tested. - [x] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [ ] I did not document these changes and I do not expect someone else to do it. ### Release notes - [x] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change. - [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change. *The decision if the pull request will be shown in the release notes is up to the mergers / release team.* The content of the `release-notes/<pull request number>.md` file will serve as the basis for the release notes. If the file does not exist, the title of the pull request will be used instead. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11690 Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org> Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch> Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
This commit is contained in:
committed by
Mathieu Fenniak
parent
120f97a914
commit
d8534ba123
@@ -442,7 +442,10 @@
|
||||
"actions.runners.runner_title": "Runner %s",
|
||||
"actions.runners.ephemeral.yes": "yes",
|
||||
"actions.runners.ephemeral.no": "no",
|
||||
"actions.runners.task_list": "Recent tasks on this runner",
|
||||
"actions.runners.task_list_repo": "Recent tasks of this repository on this runner",
|
||||
"actions.runners.task_list_org": "Recent tasks on this runner within this organization",
|
||||
"actions.runners.task_list_admin": "Recent tasks on this runner",
|
||||
"actions.runners.task_list_user": "Recent tasks of this user on this runner",
|
||||
"actions.runners.task_list.no_tasks": "There are no tasks yet.",
|
||||
"actions.runners.task_list.run": "Run",
|
||||
"actions.runners.task_list.status": "Status",
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package setting
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
actions_model "forgejo.org/models/actions"
|
||||
"forgejo.org/models/db"
|
||||
"forgejo.org/modules/base"
|
||||
"forgejo.org/modules/setting"
|
||||
actions_shared "forgejo.org/routers/web/shared/actions"
|
||||
shared_user "forgejo.org/routers/web/shared/user"
|
||||
"forgejo.org/services/context"
|
||||
)
|
||||
|
||||
const (
|
||||
tplAdminRunnerCreate base.TplName = "admin/runners/create"
|
||||
tplAdminRunnerDetails base.TplName = "admin/runners/details"
|
||||
tplAdminRunnerEdit base.TplName = "admin/runners/edit"
|
||||
tplAdminRunnerSetup base.TplName = "admin/runners/setup"
|
||||
tplAdminRunners base.TplName = "admin/actions"
|
||||
tplOrgRunnerCreate base.TplName = "org/settings/runners_create"
|
||||
tplOrgRunnerDetails base.TplName = "org/settings/runners_details"
|
||||
tplOrgRunnerEdit base.TplName = "org/settings/runners_edit"
|
||||
tplOrgRunnerSetup base.TplName = "org/settings/runners_setup"
|
||||
tplOrgRunners base.TplName = "org/settings/actions"
|
||||
tplRepoRunnerCreate base.TplName = "repo/settings/runner_create"
|
||||
tplRepoRunnerDetails base.TplName = "repo/settings/runner_details"
|
||||
tplRepoRunnerEdit base.TplName = "repo/settings/runner_edit"
|
||||
tplRepoRunnerSetup base.TplName = "repo/settings/runner_setup"
|
||||
tplRepoRunners base.TplName = "repo/settings/actions"
|
||||
tplUserRunnerCreate base.TplName = "user/settings/runner_create"
|
||||
tplUserRunnerDetails base.TplName = "user/settings/runner_details"
|
||||
tplUserRunnerEdit base.TplName = "user/settings/runner_edit"
|
||||
tplUserRunnerSetup base.TplName = "user/settings/runner_setup"
|
||||
tplUserRunners base.TplName = "user/settings/actions"
|
||||
)
|
||||
|
||||
type runnersCtx struct {
|
||||
OwnerID int64
|
||||
RepoID int64
|
||||
IsRepo bool
|
||||
IsOrg bool
|
||||
IsAdmin bool
|
||||
IsUser bool
|
||||
RunnerCreateTemplate base.TplName
|
||||
RunnerDetailsTemplate base.TplName
|
||||
RunnerEditTemplate base.TplName
|
||||
RunnerSetupTemplate base.TplName
|
||||
RunnersTemplate 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,
|
||||
RunnerCreateTemplate: tplRepoRunnerCreate,
|
||||
RunnerDetailsTemplate: tplRepoRunnerDetails,
|
||||
RunnerEditTemplate: tplRepoRunnerEdit,
|
||||
RunnerSetupTemplate: tplRepoRunnerSetup,
|
||||
RunnersTemplate: tplRepoRunners,
|
||||
RedirectLink: ctx.Repo.RepoLink + "/settings/actions/runners/",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if ctx.Data["PageIsOrgSettings"] == true {
|
||||
err := shared_user.LoadHeaderCount(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load project and package counts: %w", err)
|
||||
}
|
||||
return &runnersCtx{
|
||||
RepoID: 0,
|
||||
OwnerID: ctx.Org.Organization.ID,
|
||||
IsOrg: true,
|
||||
RunnerCreateTemplate: tplOrgRunnerCreate,
|
||||
RunnerDetailsTemplate: tplOrgRunnerDetails,
|
||||
RunnerEditTemplate: tplOrgRunnerEdit,
|
||||
RunnerSetupTemplate: tplOrgRunnerSetup,
|
||||
RunnersTemplate: tplOrgRunners,
|
||||
RedirectLink: ctx.Org.OrgLink + "/settings/actions/runners/",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if ctx.Data["PageIsAdmin"] == true {
|
||||
return &runnersCtx{
|
||||
RepoID: 0,
|
||||
OwnerID: 0,
|
||||
IsAdmin: true,
|
||||
RunnerCreateTemplate: tplAdminRunnerCreate,
|
||||
RunnerDetailsTemplate: tplAdminRunnerDetails,
|
||||
RunnerEditTemplate: tplAdminRunnerEdit,
|
||||
RunnerSetupTemplate: tplAdminRunnerSetup,
|
||||
RunnersTemplate: tplAdminRunners,
|
||||
RedirectLink: setting.AppSubURL + "/admin/actions/runners/",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if ctx.Data["PageIsUserSettings"] == true {
|
||||
return &runnersCtx{
|
||||
OwnerID: ctx.Doer.ID,
|
||||
RepoID: 0,
|
||||
IsUser: true,
|
||||
RunnerCreateTemplate: tplUserRunnerCreate,
|
||||
RunnerDetailsTemplate: tplUserRunnerDetails,
|
||||
RunnerEditTemplate: tplUserRunnerEdit,
|
||||
RunnerSetupTemplate: tplUserRunnerSetup,
|
||||
RunnersTemplate: tplUserRunners,
|
||||
RedirectLink: setting.AppSubURL + "/user/settings/actions/runners/",
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("unable to set Runners context")
|
||||
}
|
||||
|
||||
// Runners renders the list of all available runners.
|
||||
func Runners(ctx *context.Context) {
|
||||
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,
|
||||
},
|
||||
WithVisible: true,
|
||||
Sort: ctx.Req.URL.Query().Get("sort"),
|
||||
Filter: ctx.Req.URL.Query().Get("q"),
|
||||
}
|
||||
if rCtx.IsRepo {
|
||||
opts.RepoID = rCtx.RepoID
|
||||
} else if rCtx.IsOrg || rCtx.IsUser {
|
||||
opts.OwnerID = rCtx.OwnerID
|
||||
}
|
||||
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
actions_shared.RunnersList(ctx, rCtx.RunnersTemplate, opts)
|
||||
}
|
||||
|
||||
// RunnersDetails renders a read-only view of the most important properties of a runner. It is accessible to every user
|
||||
// that can use that particular runner.
|
||||
func RunnersDetails(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
runnerID := ctx.ParamsInt64(":runnerid")
|
||||
page := ctx.FormInt("page")
|
||||
if page <= 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
actions_shared.RunnerDetails(ctx, runnerID, rCtx.OwnerID, rCtx.RepoID, rCtx.RunnerDetailsTemplate, page)
|
||||
}
|
||||
|
||||
// RunnersCreate renders the form for creating a new runner.
|
||||
func RunnersCreate(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
actions_shared.RunnerCreate(ctx, rCtx.RunnerCreateTemplate)
|
||||
}
|
||||
|
||||
// RunnersCreatePost handles the form submitted by RunnersCreate.
|
||||
func RunnersCreatePost(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
actions_shared.RunnerCreatePost(ctx, rCtx.OwnerID, rCtx.RepoID, rCtx.RunnerCreateTemplate, rCtx.RunnerSetupTemplate)
|
||||
}
|
||||
|
||||
// RunnersEdit renders the form for changing an existing runner.
|
||||
func RunnersEdit(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
actions_shared.RunnerEdit(ctx, ctx.ParamsInt64(":runnerid"), rCtx.OwnerID, rCtx.RepoID, rCtx.RunnerEditTemplate)
|
||||
}
|
||||
|
||||
// RunnersEditPost handles the form submitted by RunnersEdit.
|
||||
func RunnersEditPost(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
runnerID := ctx.ParamsInt64(":runnerid")
|
||||
redirectURL := rCtx.RedirectLink + url.PathEscape(ctx.Params(":runnerid"))
|
||||
actions_shared.RunnerEditPost(ctx, runnerID, rCtx.OwnerID, rCtx.RepoID, rCtx.RunnerEditTemplate,
|
||||
rCtx.RunnerSetupTemplate, redirectURL)
|
||||
}
|
||||
|
||||
// ResetRunnerRegistrationToken handles the request to reset the runner registration token.
|
||||
func ResetRunnerRegistrationToken(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
actions_shared.RunnerResetRegistrationToken(ctx, rCtx.OwnerID, rCtx.RepoID, rCtx.RedirectLink)
|
||||
}
|
||||
|
||||
// RunnerDeletePost handles the request to delete a runner.
|
||||
func RunnerDeletePost(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
runnerID := ctx.ParamsInt64(":runnerid")
|
||||
successRedirectURL := rCtx.RedirectLink
|
||||
failureRedirectURL := rCtx.RedirectLink
|
||||
actions_shared.RunnerDeletePost(ctx, runnerID, rCtx.OwnerID, rCtx.RepoID, successRedirectURL, failureRedirectURL)
|
||||
}
|
||||
|
||||
func RedirectToDefaultSetting(ctx *context.Context) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/actions/runners")
|
||||
}
|
||||
@@ -5,7 +5,9 @@ package actions
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
actions_model "forgejo.org/models/actions"
|
||||
"forgejo.org/models/db"
|
||||
@@ -15,14 +17,143 @@ import (
|
||||
"forgejo.org/modules/setting"
|
||||
"forgejo.org/modules/util"
|
||||
"forgejo.org/modules/web"
|
||||
shared_user "forgejo.org/routers/web/shared/user"
|
||||
"forgejo.org/services/context"
|
||||
"forgejo.org/services/forms"
|
||||
|
||||
gouuid "github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
tplAdminRunnerCreate base.TplName = "admin/runners/create"
|
||||
tplAdminRunnerDetails base.TplName = "admin/runners/details"
|
||||
tplAdminRunnerEdit base.TplName = "admin/runners/edit"
|
||||
tplAdminRunnerSetup base.TplName = "admin/runners/setup"
|
||||
tplAdminRunners base.TplName = "admin/actions"
|
||||
tplOrgRunnerCreate base.TplName = "org/settings/runners_create"
|
||||
tplOrgRunnerDetails base.TplName = "org/settings/runners_details"
|
||||
tplOrgRunnerEdit base.TplName = "org/settings/runners_edit"
|
||||
tplOrgRunnerSetup base.TplName = "org/settings/runners_setup"
|
||||
tplOrgRunners base.TplName = "org/settings/actions"
|
||||
tplRepoRunnerCreate base.TplName = "repo/settings/runner_create"
|
||||
tplRepoRunnerDetails base.TplName = "repo/settings/runner_details"
|
||||
tplRepoRunnerEdit base.TplName = "repo/settings/runner_edit"
|
||||
tplRepoRunnerSetup base.TplName = "repo/settings/runner_setup"
|
||||
tplRepoRunners base.TplName = "repo/settings/actions"
|
||||
tplUserRunnerCreate base.TplName = "user/settings/runner_create"
|
||||
tplUserRunnerDetails base.TplName = "user/settings/runner_details"
|
||||
tplUserRunnerEdit base.TplName = "user/settings/runner_edit"
|
||||
tplUserRunnerSetup base.TplName = "user/settings/runner_setup"
|
||||
tplUserRunners base.TplName = "user/settings/actions"
|
||||
)
|
||||
|
||||
type runnersCtx struct {
|
||||
OwnerID int64
|
||||
RepoID int64
|
||||
IsRepo bool
|
||||
IsOrg bool
|
||||
IsAdmin bool
|
||||
IsUser bool
|
||||
RunnerCreateTemplate base.TplName
|
||||
RunnerDetailsTemplate base.TplName
|
||||
RunnerEditTemplate base.TplName
|
||||
RunnerSetupTemplate base.TplName
|
||||
RunnersTemplate 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,
|
||||
RunnerCreateTemplate: tplRepoRunnerCreate,
|
||||
RunnerDetailsTemplate: tplRepoRunnerDetails,
|
||||
RunnerEditTemplate: tplRepoRunnerEdit,
|
||||
RunnerSetupTemplate: tplRepoRunnerSetup,
|
||||
RunnersTemplate: tplRepoRunners,
|
||||
RedirectLink: ctx.Repo.RepoLink + "/settings/actions/runners/",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if ctx.Data["PageIsOrgSettings"] == true {
|
||||
err := shared_user.LoadHeaderCount(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load project and package counts: %w", err)
|
||||
}
|
||||
return &runnersCtx{
|
||||
RepoID: 0,
|
||||
OwnerID: ctx.Org.Organization.ID,
|
||||
IsOrg: true,
|
||||
RunnerCreateTemplate: tplOrgRunnerCreate,
|
||||
RunnerDetailsTemplate: tplOrgRunnerDetails,
|
||||
RunnerEditTemplate: tplOrgRunnerEdit,
|
||||
RunnerSetupTemplate: tplOrgRunnerSetup,
|
||||
RunnersTemplate: tplOrgRunners,
|
||||
RedirectLink: ctx.Org.OrgLink + "/settings/actions/runners/",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if ctx.Data["PageIsAdmin"] == true {
|
||||
return &runnersCtx{
|
||||
RepoID: 0,
|
||||
OwnerID: 0,
|
||||
IsAdmin: true,
|
||||
RunnerCreateTemplate: tplAdminRunnerCreate,
|
||||
RunnerDetailsTemplate: tplAdminRunnerDetails,
|
||||
RunnerEditTemplate: tplAdminRunnerEdit,
|
||||
RunnerSetupTemplate: tplAdminRunnerSetup,
|
||||
RunnersTemplate: tplAdminRunners,
|
||||
RedirectLink: setting.AppSubURL + "/admin/actions/runners/",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if ctx.Data["PageIsUserSettings"] == true {
|
||||
return &runnersCtx{
|
||||
OwnerID: ctx.Doer.ID,
|
||||
RepoID: 0,
|
||||
IsUser: true,
|
||||
RunnerCreateTemplate: tplUserRunnerCreate,
|
||||
RunnerDetailsTemplate: tplUserRunnerDetails,
|
||||
RunnerEditTemplate: tplUserRunnerEdit,
|
||||
RunnerSetupTemplate: tplUserRunnerSetup,
|
||||
RunnersTemplate: tplUserRunners,
|
||||
RedirectLink: setting.AppSubURL + "/user/settings/actions/runners/",
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("unable to set Runners context")
|
||||
}
|
||||
|
||||
// RunnersList renders the list of runners.
|
||||
func RunnersList(ctx *context.Context, template base.TplName, opts actions_model.FindRunnerOptions) {
|
||||
func RunnersList(ctx *context.Context) {
|
||||
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,
|
||||
},
|
||||
WithVisible: true,
|
||||
Sort: ctx.Req.URL.Query().Get("sort"),
|
||||
Filter: ctx.Req.URL.Query().Get("q"),
|
||||
}
|
||||
if rCtx.IsRepo {
|
||||
opts.RepoID = rCtx.RepoID
|
||||
} else if rCtx.IsOrg || rCtx.IsUser {
|
||||
opts.OwnerID = rCtx.OwnerID
|
||||
}
|
||||
|
||||
runners, count, err := db.FindAndCount[actions_model.ActionRunner](ctx, opts)
|
||||
if err != nil {
|
||||
ctx.ServerError("CountRunners", err)
|
||||
@@ -67,17 +198,30 @@ func RunnersList(ctx *context.Context, template base.TplName, opts actions_model
|
||||
ctx.Data["RunnerOwnerID"] = opts.OwnerID
|
||||
ctx.Data["RunnerRepoID"] = opts.RepoID
|
||||
ctx.Data["SortType"] = opts.Sort
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
|
||||
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.HTML(http.StatusOK, template)
|
||||
ctx.HTML(http.StatusOK, rCtx.RunnersTemplate)
|
||||
}
|
||||
|
||||
// RunnerDetails displays detail information about each runner. The page is purely informational and visible to everyone
|
||||
// who is allowed to use a runner.
|
||||
func RunnerDetails(ctx *context.Context, runnerID, ownerID, repoID int64, template base.TplName, page int) {
|
||||
runner, err := actions_model.GetVisibleRunnerByID(ctx, runnerID, ownerID, repoID)
|
||||
func RunnerDetails(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
runnerID := ctx.ParamsInt64(":runnerid")
|
||||
page := ctx.FormInt("page")
|
||||
if page <= 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
runner, err := actions_model.GetVisibleRunnerByID(ctx, runnerID, rCtx.OwnerID, rCtx.RepoID)
|
||||
if errors.Is(err, util.ErrNotExist) {
|
||||
ctx.NotFound("GetVisibleRunnerByID", err)
|
||||
return
|
||||
@@ -96,8 +240,8 @@ func RunnerDetails(ctx *context.Context, runnerID, ownerID, repoID int64, templa
|
||||
PageSize: 30,
|
||||
},
|
||||
RunnerID: runner.ID,
|
||||
OwnerID: ownerID,
|
||||
RepoID: repoID,
|
||||
OwnerID: rCtx.OwnerID,
|
||||
RepoID: rCtx.RepoID,
|
||||
}
|
||||
|
||||
tasks, count, err := db.FindAndCount[actions_model.ActionTask](ctx, opts)
|
||||
@@ -112,32 +256,51 @@ func RunnerDetails(ctx *context.Context, runnerID, ownerID, repoID int64, templa
|
||||
}
|
||||
|
||||
ctx.Data["PageIsSharedSettingsRunners"] = true
|
||||
ctx.Data["RunnerOwnerID"] = ownerID
|
||||
ctx.Data["RunnerRepoID"] = repoID
|
||||
ctx.Data["RunnerOwnerID"] = rCtx.OwnerID
|
||||
ctx.Data["RunnerRepoID"] = rCtx.RepoID
|
||||
ctx.Data["Title"] = ctx.Tr("actions.runners.runner_details.page_title", runner.Name)
|
||||
ctx.Data["Runner"] = runner
|
||||
ctx.Data["Tasks"] = tasks
|
||||
ctx.Data["IsRepo"] = rCtx.IsRepo
|
||||
ctx.Data["IsOrg"] = rCtx.IsOrg
|
||||
ctx.Data["IsAdmin"] = rCtx.IsAdmin
|
||||
ctx.Data["IsUser"] = rCtx.IsUser
|
||||
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.HTML(http.StatusOK, template)
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
ctx.HTML(http.StatusOK, rCtx.RunnerDetailsTemplate)
|
||||
}
|
||||
|
||||
// RunnerCreate displays a form for creating a new runner.
|
||||
func RunnerCreate(ctx *context.Context, template base.TplName) {
|
||||
func RunnerCreate(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["PageIsSharedSettingsRunners"] = true
|
||||
ctx.Data["Title"] = ctx.Tr("actions.runners.create_runner.page_title")
|
||||
ctx.HTML(http.StatusOK, template)
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
ctx.HTML(http.StatusOK, rCtx.RunnerCreateTemplate)
|
||||
}
|
||||
|
||||
// RunnerCreatePost handles the form submitted by RunnerCreate.
|
||||
func RunnerCreatePost(ctx *context.Context, ownerID, repoID int64, template, successTemplate base.TplName) {
|
||||
func RunnerCreatePost(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
form := web.GetForm(ctx).(*forms.CreateRunnerForm)
|
||||
|
||||
runner := actions_model.ActionRunner{
|
||||
UUID: gouuid.New().String(),
|
||||
Name: form.RunnerName,
|
||||
OwnerID: ownerID,
|
||||
RepoID: repoID,
|
||||
OwnerID: rCtx.OwnerID,
|
||||
RepoID: rCtx.RepoID,
|
||||
Description: form.RunnerDescription,
|
||||
Ephemeral: false,
|
||||
}
|
||||
@@ -147,26 +310,33 @@ func RunnerCreatePost(ctx *context.Context, ownerID, repoID int64, template, suc
|
||||
ctx.Data["Title"] = ctx.Tr("actions.runners.runner_setup.page_title", runner.Name)
|
||||
ctx.Data["AppURL"] = setting.AppURL
|
||||
ctx.Data["Runner"] = runner
|
||||
ctx.Data["RunnerOwnerID"] = ownerID
|
||||
ctx.Data["RunnerRepoID"] = repoID
|
||||
ctx.Data["RunnerOwnerID"] = rCtx.OwnerID
|
||||
ctx.Data["RunnerRepoID"] = rCtx.RepoID
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(http.StatusOK, template)
|
||||
ctx.HTML(http.StatusOK, rCtx.RunnerCreateTemplate)
|
||||
return
|
||||
}
|
||||
|
||||
err := actions_model.CreateRunner(ctx, &runner)
|
||||
err = actions_model.CreateRunner(ctx, &runner)
|
||||
if err != nil {
|
||||
ctx.ServerError("CreateRunner", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.HTML(http.StatusOK, successTemplate)
|
||||
ctx.HTML(http.StatusOK, rCtx.RunnerSetupTemplate)
|
||||
}
|
||||
|
||||
// RunnerEdit displays a form to modify the given runner.
|
||||
func RunnerEdit(ctx *context.Context, runnerID, ownerID, repoID int64, template base.TplName) {
|
||||
runner, err := actions_model.GetVisibleRunnerByID(ctx, runnerID, ownerID, repoID)
|
||||
func RunnerEdit(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
runner, err := actions_model.GetVisibleRunnerByID(ctx, ctx.ParamsInt64(":runnerid"), rCtx.OwnerID, rCtx.RepoID)
|
||||
if errors.Is(err, util.ErrNotExist) {
|
||||
ctx.NotFound("GetVisibleRunnerByID", err)
|
||||
return
|
||||
@@ -178,7 +348,7 @@ func RunnerEdit(ctx *context.Context, runnerID, ownerID, repoID int64, template
|
||||
ctx.ServerError("LoadAttributes", err)
|
||||
return
|
||||
}
|
||||
if !runner.Editable(ownerID, repoID) {
|
||||
if !runner.Editable(rCtx.OwnerID, rCtx.RepoID) {
|
||||
err = errors.New("no permission to edit this runner")
|
||||
ctx.NotFound("RunnerDetails", err)
|
||||
return
|
||||
@@ -187,14 +357,26 @@ func RunnerEdit(ctx *context.Context, runnerID, ownerID, repoID int64, template
|
||||
ctx.Data["PageIsSharedSettingsRunners"] = true
|
||||
ctx.Data["Title"] = ctx.Tr("actions.runners.edit_runner.page_title", runner.Name)
|
||||
ctx.Data["Runner"] = runner
|
||||
ctx.Data["RunnerOwnerID"] = ownerID
|
||||
ctx.Data["RunnerRepoID"] = repoID
|
||||
ctx.HTML(http.StatusOK, template)
|
||||
ctx.Data["RunnerOwnerID"] = rCtx.OwnerID
|
||||
ctx.Data["RunnerRepoID"] = rCtx.RepoID
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
ctx.HTML(http.StatusOK, rCtx.RunnerEditTemplate)
|
||||
}
|
||||
|
||||
// RunnerEditPost handles the form submitted by RunnerEdit.
|
||||
func RunnerEditPost(ctx *context.Context, runnerID, ownerID, repoID int64, template, successTemplate base.TplName, redirectTo string) {
|
||||
runner, err := actions_model.GetVisibleRunnerByID(ctx, runnerID, ownerID, repoID)
|
||||
func RunnerEditPost(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
runnerID := ctx.ParamsInt64(":runnerid")
|
||||
redirectURL := rCtx.RedirectLink + url.PathEscape(ctx.Params(":runnerid"))
|
||||
|
||||
runner, err := actions_model.GetVisibleRunnerByID(ctx, runnerID, rCtx.OwnerID, rCtx.RepoID)
|
||||
if errors.Is(err, util.ErrNotExist) {
|
||||
ctx.NotFound("GetVisibleRunnerByID", err)
|
||||
return
|
||||
@@ -202,7 +384,7 @@ func RunnerEditPost(ctx *context.Context, runnerID, ownerID, repoID int64, templ
|
||||
ctx.ServerError("GetVisibleRunnerByID", err)
|
||||
return
|
||||
}
|
||||
if !runner.Editable(ownerID, repoID) {
|
||||
if !runner.Editable(rCtx.OwnerID, rCtx.RepoID) {
|
||||
ctx.NotFound("RunnerEditPost.Editable", util.NewPermissionDeniedErrorf("no permission to edit this runner"))
|
||||
return
|
||||
}
|
||||
@@ -211,15 +393,16 @@ func RunnerEditPost(ctx *context.Context, runnerID, ownerID, repoID int64, templ
|
||||
ctx.Data["Title"] = ctx.Tr("actions.runners.runner_setup.page_title", runner.Name)
|
||||
ctx.Data["AppURL"] = setting.AppURL
|
||||
ctx.Data["Runner"] = runner
|
||||
ctx.Data["RunnerOwnerID"] = ownerID
|
||||
ctx.Data["RunnerRepoID"] = repoID
|
||||
ctx.Data["RunnerOwnerID"] = rCtx.OwnerID
|
||||
ctx.Data["RunnerRepoID"] = rCtx.RepoID
|
||||
ctx.Data["RunnersListLink"] = rCtx.RedirectLink
|
||||
|
||||
form := web.GetForm(ctx).(*forms.EditRunnerForm)
|
||||
runner.Name = form.RunnerName
|
||||
runner.Description = form.RunnerDescription
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(http.StatusOK, template)
|
||||
ctx.HTML(http.StatusOK, rCtx.RunnerEditTemplate)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -228,14 +411,14 @@ func RunnerEditPost(ctx *context.Context, runnerID, ownerID, repoID int64, templ
|
||||
if err != nil {
|
||||
log.Warn("RunnerEditPost.UpdateRunner failed: %v, url: %s", err, ctx.Req.URL)
|
||||
ctx.Flash.Warning(ctx.Tr("actions.runners.update_runner.failed"))
|
||||
ctx.Redirect(redirectTo)
|
||||
ctx.Redirect(redirectURL)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debug("RunnerEditPost success: %s", ctx.Req.URL)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("actions.runners.update_runner.success"))
|
||||
ctx.Redirect(redirectTo)
|
||||
ctx.Redirect(redirectURL)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -244,43 +427,55 @@ func RunnerEditPost(ctx *context.Context, runnerID, ownerID, repoID int64, templ
|
||||
if err != nil {
|
||||
log.Warn("RunnerEditPost.UpdateRunner failed: %v, url: %s", err, ctx.Req.URL)
|
||||
ctx.Flash.Warning(ctx.Tr("actions.runners.update_runner.failed"))
|
||||
ctx.Redirect(redirectTo)
|
||||
ctx.Redirect(redirectURL)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.HTML(http.StatusOK, successTemplate)
|
||||
ctx.HTML(http.StatusOK, rCtx.RunnerSetupTemplate)
|
||||
}
|
||||
|
||||
// RunnerResetRegistrationToken resets the runner registration token.
|
||||
func RunnerResetRegistrationToken(ctx *context.Context, ownerID, repoID int64, redirectTo string) {
|
||||
optOwnerID := optional.None[int64]()
|
||||
if ownerID != 0 {
|
||||
optOwnerID = optional.Some(ownerID)
|
||||
}
|
||||
optRepoID := optional.None[int64]()
|
||||
if repoID != 0 {
|
||||
optRepoID = optional.Some(repoID)
|
||||
func RunnerResetRegistrationToken(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := actions_model.NewRunnerToken(ctx, optOwnerID, optRepoID)
|
||||
optOwnerID := optional.None[int64]()
|
||||
if rCtx.OwnerID != 0 {
|
||||
optOwnerID = optional.Some(rCtx.OwnerID)
|
||||
}
|
||||
optRepoID := optional.None[int64]()
|
||||
if rCtx.RepoID != 0 {
|
||||
optRepoID = optional.Some(rCtx.RepoID)
|
||||
}
|
||||
|
||||
_, err = actions_model.NewRunnerToken(ctx, optOwnerID, optRepoID)
|
||||
if err != nil {
|
||||
ctx.ServerError("ResetRunnerRegistrationToken", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("actions.runners.reset_registration_token.success"))
|
||||
ctx.Redirect(redirectTo)
|
||||
ctx.Redirect(rCtx.RedirectLink)
|
||||
}
|
||||
|
||||
// RunnerDeletePost handles the request for deleting a particular runner.
|
||||
func RunnerDeletePost(ctx *context.Context, runnerID, ownerID, repoID int64, successRedirectTo, failedRedirectTo string) {
|
||||
runner, err := actions_model.GetRunnerByID(ctx, runnerID)
|
||||
func RunnerDeletePost(ctx *context.Context) {
|
||||
rCtx, err := getRunnersCtx(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getRunnersCtx", err)
|
||||
return
|
||||
}
|
||||
|
||||
runner, err := actions_model.GetRunnerByID(ctx, ctx.ParamsInt64(":runnerid"))
|
||||
if err != nil {
|
||||
ctx.ServerError("GetRunnerByID", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !runner.Editable(ownerID, repoID) {
|
||||
if !runner.Editable(rCtx.OwnerID, rCtx.RepoID) {
|
||||
ctx.NotFound("Editable", util.NewPermissionDeniedErrorf("no permission to edit this runner"))
|
||||
return
|
||||
}
|
||||
@@ -290,7 +485,7 @@ func RunnerDeletePost(ctx *context.Context, runnerID, ownerID, repoID int64, suc
|
||||
|
||||
ctx.Flash.Warning(ctx.Tr("actions.runners.delete_runner.failed"))
|
||||
|
||||
ctx.JSONRedirect(failedRedirectTo)
|
||||
ctx.JSONRedirect(rCtx.RedirectLink)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -298,5 +493,9 @@ func RunnerDeletePost(ctx *context.Context, runnerID, ownerID, repoID int64, suc
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("actions.runners.delete_runner.success"))
|
||||
|
||||
ctx.JSONRedirect(successRedirectTo)
|
||||
ctx.JSONRedirect(rCtx.RedirectLink)
|
||||
}
|
||||
|
||||
func RedirectToDefaultSetting(ctx *context.Context) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/actions/runners")
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2025 The Forgejo Authors.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
actions_model "forgejo.org/models/actions"
|
||||
"forgejo.org/models/unittest"
|
||||
user_model "forgejo.org/models/user"
|
||||
"forgejo.org/services/contexttest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRunnerDetails(t *testing.T) {
|
||||
defer unittest.OverrideFixtures("routers/web/shared/actions/fixtures/TestRunnerDetails")()
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
runner := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: 1004})
|
||||
|
||||
t.Run("permission denied", func(t *testing.T) {
|
||||
ctx, resp := contexttest.MockContext(t, "/admin/actions/runners")
|
||||
RunnerDetails(ctx, runner.ID, user.ID, 0, "admin/runners/details", 1)
|
||||
assert.Equal(t, http.StatusOK, resp.Code)
|
||||
assert.Empty(t, ctx.GetData()["Tasks"])
|
||||
})
|
||||
|
||||
t.Run("first page", func(t *testing.T) {
|
||||
ctx, resp := contexttest.MockContext(t, "/admin/actions/runners")
|
||||
page := 1
|
||||
RunnerDetails(ctx, runner.ID, 0, 0, "admin/runners/details", page)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
assert.Len(t, ctx.GetData()["Tasks"], 30)
|
||||
})
|
||||
|
||||
t.Run("second and last page", func(t *testing.T) {
|
||||
ctx, resp := contexttest.MockContext(t, "/admin/actions/runners")
|
||||
page := 2
|
||||
RunnerDetails(ctx, runner.ID, 0, 0, "admin/runners/details", page)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
assert.Len(t, ctx.GetData()["Tasks"], 10)
|
||||
})
|
||||
}
|
||||
+10
-9
@@ -42,6 +42,7 @@ import (
|
||||
"forgejo.org/routers/web/repo/badges"
|
||||
repo_flags "forgejo.org/routers/web/repo/flags"
|
||||
repo_setting "forgejo.org/routers/web/repo/setting"
|
||||
shared_actions "forgejo.org/routers/web/shared/actions"
|
||||
"forgejo.org/routers/web/shared/project"
|
||||
"forgejo.org/routers/web/user"
|
||||
user_setting "forgejo.org/routers/web/user/setting"
|
||||
@@ -460,16 +461,16 @@ func registerRoutes(m *web.Route) {
|
||||
|
||||
addSettingsRunnersRoutes := func() {
|
||||
m.Group("/runners", func() {
|
||||
m.Get("", repo_setting.Runners)
|
||||
m.Get("", shared_actions.RunnersList)
|
||||
m.Combo("/new").
|
||||
Get(repo_setting.RunnersCreate).
|
||||
Post(web.Bind(forms.CreateRunnerForm{}), repo_setting.RunnersCreatePost)
|
||||
m.Get("/{runnerid}", repo_setting.RunnersDetails)
|
||||
Get(shared_actions.RunnerCreate).
|
||||
Post(web.Bind(forms.CreateRunnerForm{}), shared_actions.RunnerCreatePost)
|
||||
m.Get("/{runnerid}", shared_actions.RunnerDetails)
|
||||
m.Combo("/{runnerid}/edit").
|
||||
Get(repo_setting.RunnersEdit).
|
||||
Post(web.Bind(forms.EditRunnerForm{}), repo_setting.RunnersEditPost)
|
||||
m.Post("/{runnerid}/delete", repo_setting.RunnerDeletePost)
|
||||
m.Get("/reset_registration_token", repo_setting.ResetRunnerRegistrationToken)
|
||||
Get(shared_actions.RunnerEdit).
|
||||
Post(web.Bind(forms.EditRunnerForm{}), shared_actions.RunnerEditPost)
|
||||
m.Post("/{runnerid}/delete", shared_actions.RunnerDeletePost)
|
||||
m.Get("/reset_registration_token", shared_actions.RunnerResetRegistrationToken)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1158,7 +1159,7 @@ func registerRoutes(m *web.Route) {
|
||||
})
|
||||
})
|
||||
m.Group("/actions", func() {
|
||||
m.Get("", repo_setting.RedirectToDefaultSetting)
|
||||
m.Get("", shared_actions.RedirectToDefaultSetting)
|
||||
addSettingsRunnersRoutes()
|
||||
addSettingsSecretsRoutes()
|
||||
addSettingsVariablesRoutes()
|
||||
|
||||
@@ -93,7 +93,15 @@
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{ctx.Locale.Tr "actions.runners.task_list"}}
|
||||
{{if .IsRepo}}
|
||||
{{ctx.Locale.Tr "actions.runners.task_list_repo"}}
|
||||
{{else if .IsOrg}}
|
||||
{{ctx.Locale.Tr "actions.runners.task_list_org"}}
|
||||
{{else if .IsAdmin}}
|
||||
{{ctx.Locale.Tr "actions.runners.task_list_admin"}}
|
||||
{{else if .IsUser}}
|
||||
{{ctx.Locale.Tr "actions.runners.task_list_user"}}
|
||||
{{end}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<table class="ui very basic striped table unstackable">
|
||||
|
||||
@@ -1,3 +1,251 @@
|
||||
- id: 88899
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: d553d4419a9232b8eb49f9ba5396be9b5c742b3a
|
||||
|
||||
- id: 88900
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: aa06c3e9601797fc929e6d53d921fc025ed86d97
|
||||
|
||||
- id: 88901
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 2 # StatusFailure
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: d7bccf4e23daf00ecce0c63770a861f2f6efa1fc
|
||||
|
||||
- id: 88902
|
||||
attempt: 2
|
||||
runner_id: 719931
|
||||
status: 3 # StatusCancelled
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: d7bccf4e23daf00ecce0c63770a861f2f6efa1fc
|
||||
|
||||
- id: 88903
|
||||
attempt: 3
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: d7bccf4e23daf00ecce0c63770a861f2f6efa1fc
|
||||
|
||||
- id: 88904
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: f0a6cb54b000f0259005598d41c36912412fd1a1
|
||||
|
||||
- id: 88905
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: f8efc8f98a79121043493a6a5022bc03a7ddd1e6
|
||||
|
||||
- id: 88906
|
||||
attempt: 2
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: f8efc8f98a79121043493a6a5022bc03a7ddd1e6
|
||||
|
||||
- id: 88907
|
||||
attempt: 2
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: f8efc8f98a79121043493a6a5022bc03a7ddd1e6
|
||||
|
||||
- id: 88908
|
||||
attempt: 3
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: f8efc8f98a79121043493a6a5022bc03a7ddd1e6
|
||||
|
||||
- id: 88909
|
||||
attempt: 4
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: f8efc8f98a79121043493a6a5022bc03a7ddd1e6
|
||||
|
||||
- id: 88910
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: b96d11edc82815c5daf8aeab5455a633810772c8
|
||||
|
||||
- id: 88911
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 3 # StatusCancelled
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: f19005ba22ab1eb48809e6990853fd370fd00247
|
||||
|
||||
- id: 88912
|
||||
attempt: 2
|
||||
runner_id: 719931
|
||||
status: 3 # StatusCancelled
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: f19005ba22ab1eb48809e6990853fd370fd00247
|
||||
|
||||
- id: 88913
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 0766efdd387a2db415a2df3dd9db2b9ea9bc9286
|
||||
|
||||
- id: 88914
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 0766efdd387a2db415a2df3dd9db2b9ea9bc9286
|
||||
|
||||
- id: 88915
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: e5251733cc20c2350ebe30f0d6ad7f04aa6f996e
|
||||
|
||||
- id: 88916
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: d2374bac709f30cd2eeb11f985dea1c0f5b97282
|
||||
|
||||
- id: 88917
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 95d900ad932e9285039d20db5ebeaca52dd0528b
|
||||
|
||||
- id: 88918
|
||||
attempt: 2
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 95d900ad932e9285039d20db5ebeaca52dd0528b
|
||||
|
||||
- id: 88919
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 95d900ad932e9285039d20db5ebeaca52dd0528b
|
||||
|
||||
- id: 88920
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 8ea3698775cb332b310041187602584d0507d580
|
||||
|
||||
- id: 88921
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: a597d91f7580dacc95afd7658b078837ae15c02a
|
||||
|
||||
- id: 88922
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 206732455acefbbf2be33f673b8a475df48e1227
|
||||
|
||||
- id: 88923
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 8c07db7db9fb0d6a96dfb76ca3cff91e678eb4e6
|
||||
|
||||
- id: 88924
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: d8269eb5270bfa079a2fc6a94a7d171a487264ce
|
||||
|
||||
- id: 88925
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: fd449592611ee8689c81635bd030e9db1a18869a
|
||||
|
||||
- id: 88926
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 459cc09582b7767ad1b93fcbde536690bbd1b48a
|
||||
|
||||
- id: 88927
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 0d30b6df8041379690bec9a3bcd4710a76f3188c
|
||||
|
||||
- id: 88929
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 1 # StatusSuccess
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: 14d98a4d090d40358193ce2d14b5947c551fa8ec
|
||||
|
||||
- id: 88930
|
||||
attempt: 1
|
||||
runner_id: 719931
|
||||
status: 3 # StatusCancelled
|
||||
repo_id: 32
|
||||
owner_id: 3 # org3
|
||||
commit_sha: ed4df76f868ac8a9a8406f2606208bb42ed8b9c7
|
||||
|
||||
- id: 88931
|
||||
attempt: 1
|
||||
runner_id: 719934
|
||||
|
||||
@@ -84,7 +84,7 @@ test.describe('Runners of user2', () => {
|
||||
- definition: A runner for everyone
|
||||
`);
|
||||
|
||||
await expect(page.getByRole('heading', {name: 'Recent tasks on this runner '})).toBeVisible();
|
||||
await expect(page.getByRole('heading', {name: 'Recent tasks of this user on this runner'})).toBeVisible();
|
||||
|
||||
const rows = page.getByRole('row');
|
||||
|
||||
@@ -374,7 +374,7 @@ test.describe('Global runners', () => {
|
||||
- definition: A runner for everyone
|
||||
`);
|
||||
|
||||
await expect(page.getByRole('heading', {name: 'Recent tasks on this runner '})).toBeVisible();
|
||||
await expect(page.getByRole('heading', {name: 'Recent tasks on this runner'})).toBeVisible();
|
||||
|
||||
const rows = page.getByRole('row');
|
||||
|
||||
@@ -598,7 +598,7 @@ test.describe('Organization runners', () => {
|
||||
- definition: A runner for everyone
|
||||
`);
|
||||
|
||||
await expect(page.getByRole('heading', {name: 'Recent tasks on this runner '})).toBeVisible();
|
||||
await expect(page.getByRole('heading', {name: 'Recent tasks on this runner within this organization'})).toBeVisible();
|
||||
|
||||
const rows = page.getByRole('row');
|
||||
|
||||
@@ -607,6 +607,38 @@ test.describe('Organization runners', () => {
|
||||
await expect(rows.nth(0)).toHaveAccessibleName('Run Status Repository Commit Done at');
|
||||
await expect(rows.nth(1)).toHaveAccessibleName('88931 Running ed38c5a46c -');
|
||||
});
|
||||
|
||||
test('runner details with multiple pages of tasks', async ({page}) => {
|
||||
await page.goto('/org/org3/settings/actions/runners');
|
||||
|
||||
await page.getByRole('link', {name: 'Show details of runner-1', exact: true}).click();
|
||||
|
||||
await expect(page).toHaveTitle(/^Runner runner-1 .*/);
|
||||
await expect(page.getByRole('heading', {name: 'Runner runner-1'})).toBeVisible();
|
||||
|
||||
await expect(page.getByRole('heading', {name: 'Recent tasks on this runner within this organization'})).toBeVisible();
|
||||
|
||||
const rows = page.getByRole('row');
|
||||
|
||||
await expect(rows).toHaveCount(31); // 30 runners plus table header
|
||||
await expect(rows.nth(0)).toHaveAccessibleName('Run Status Repository Commit Done at');
|
||||
await expect(rows.nth(1)).toHaveAccessibleName('88930 Canceled ed4df76f86 -');
|
||||
await expect(rows.nth(30)).toHaveAccessibleName('88900 Success aa06c3e960 -');
|
||||
|
||||
await page.getByRole('link', {name: 'Next', exact: true}).click();
|
||||
|
||||
await expect(rows).toHaveCount(2);
|
||||
await expect(rows.nth(0)).toHaveAccessibleName('Run Status Repository Commit Done at');
|
||||
await expect(rows.nth(1)).toHaveAccessibleName('88899 Success d553d4419a -');
|
||||
|
||||
// Go back to the first page and verify that nothing has changed.
|
||||
await page.getByRole('link', {name: 'Previous', exact: true}).click();
|
||||
|
||||
await expect(rows).toHaveCount(31); // 30 runners plus table header
|
||||
await expect(rows.nth(0)).toHaveAccessibleName('Run Status Repository Commit Done at');
|
||||
await expect(rows.nth(1)).toHaveAccessibleName('88930 Canceled ed4df76f86 -');
|
||||
await expect(rows.nth(30)).toHaveAccessibleName('88900 Success aa06c3e960 -');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Repository runners', () => {
|
||||
@@ -694,7 +726,7 @@ test.describe('Repository runners', () => {
|
||||
- definition: A runner for everyone
|
||||
`);
|
||||
|
||||
await expect(page.getByRole('heading', {name: 'Recent tasks on this runner '})).toBeVisible();
|
||||
await expect(page.getByRole('heading', {name: 'Recent tasks of this repository on this runner'})).toBeVisible();
|
||||
|
||||
const rows = page.getByRole('row');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user