diff --git a/models/actions/run_list.go b/models/actions/run_list.go index 7294991b0b..a940b829b1 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -132,6 +132,20 @@ func GetStatusInfoList(ctx context.Context, lang translation.Locale) []StatusInf return statusInfoList } +// GetRunBranches returns branch names for the run-list "Branch" filter. +// Sourced from the `branch` table (indexed by repo_id) rather than DISTINCT-ing +// `action_run.ref`, which is wildcard-matched and slow on large repos; as a side +// effect the list reflects existing branches, not only ones that produced a run. +func GetRunBranches(ctx context.Context, repoID int64) ([]string, error) { + branches := make([]string, 0, 10) + return branches, db.GetEngine(ctx).Table("branch"). + Where("repo_id = ?", repoID). + And("is_deleted = ?", false). + Cols("name"). + OrderBy("name ASC"). + Find(&branches) +} + // GetRunWorkflowIDs returns all distinct WorkflowIDs that have at least // one ActionRun in the given repo. func GetRunWorkflowIDs(ctx context.Context, repoID int64) ([]string, error) { diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index de75131c19..1ba431c5ea 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -3776,6 +3776,8 @@ "actions.runs.status": "Status", "actions.runs.actors_no_select": "All actors", "actions.runs.status_no_select": "All status", + "actions.runs.branch": "Branch", + "actions.runs.branches_no_select": "All branches", "actions.runs.no_results": "No results matched.", "actions.runs.no_workflows": "There are no workflows yet.", "actions.runs.no_workflows.quick_start": "Don't know how to start with Gitea Actions? See the quick start guide.", diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go index 45d81fb7fe..9c632a0d7b 100644 --- a/routers/web/repo/actions/actions.go +++ b/routers/web/repo/actions/actions.go @@ -7,7 +7,9 @@ import ( "bytes" stdCtx "context" "errors" + "fmt" "net/http" + "net/url" "slices" "strings" @@ -286,6 +288,7 @@ func prepareWorkflowList(ctx *context.Context, workflows []WorkflowInfo, otherWo actorID := ctx.FormInt64("actor") status := ctx.FormInt("status") workflowID := ctx.FormString("workflow") + branch := ctx.FormString("branch") page := ctx.FormInt("page") if page <= 0 { page = 1 @@ -295,7 +298,8 @@ func prepareWorkflowList(ctx *context.Context, workflows []WorkflowInfo, otherWo // they will be 0 by default, which indicates get all status or actors ctx.Data["CurActor"] = actorID ctx.Data["CurStatus"] = status - if actorID > 0 || status > int(actions_model.StatusUnknown) { + ctx.Data["CurBranch"] = branch + if actorID > 0 || status > int(actions_model.StatusUnknown) || branch != "" { ctx.Data["IsFiltered"] = true } @@ -313,6 +317,9 @@ func prepareWorkflowList(ctx *context.Context, workflows []WorkflowInfo, otherWo if actions_model.Status(status) != actions_model.StatusUnknown { opts.Status = []actions_model.Status{actions_model.Status(status)} } + if branch != "" { + opts.Ref = string(git.RefNameFromBranch(branch)) + } runs, total, err := db.FindAndCount[actions_model.ActionRun](ctx, opts) if err != nil { @@ -393,6 +400,13 @@ func prepareWorkflowList(ctx *context.Context, workflows []WorkflowInfo, otherWo ctx.Data["StatusInfoList"] = actions_model.GetStatusInfoList(ctx, ctx.Locale) + runBranches, err := actions_model.GetRunBranches(ctx, ctx.Repo.Repository.ID) + if err != nil { + ctx.ServerError("GetRunBranches", err) + return + } + ctx.Data["RunBranches"] = runBranches + pager := context.NewPagination(total, opts.PageSize, opts.Page, 5) pager.AddParamFromRequest(ctx.Req) ctx.Data["Page"] = pager @@ -509,3 +523,13 @@ func decodeNode(node yaml.Node, out any) bool { } return true } + +func actionsListRedirectURL(repoLink, workflow, actor, status, branch string) string { + return fmt.Sprintf("%s/actions?workflow=%s&actor=%s&status=%s&branch=%s", + repoLink, + url.QueryEscape(workflow), + url.QueryEscape(actor), + url.QueryEscape(status), + url.QueryEscape(branch), + ) +} diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 2e6efc691f..931163c38f 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -1103,14 +1103,14 @@ func disableOrEnableWorkflowFile(ctx *context_module.Context, isEnable bool) { ctx.Flash.Success(ctx.Tr("actions.workflow.disable_success", workflow)) } - redirectURL := fmt.Sprintf("%s/actions?workflow=%s&actor=%s&status=%s", ctx.Repo.RepoLink, url.QueryEscape(workflow), - url.QueryEscape(ctx.FormString("actor")), url.QueryEscape(ctx.FormString("status"))) + redirectURL := actionsListRedirectURL(ctx.Repo.RepoLink, workflow, + ctx.FormString("actor"), ctx.FormString("status"), ctx.FormString("branch")) ctx.JSONRedirect(redirectURL) } func Run(ctx *context_module.Context) { - redirectURL := fmt.Sprintf("%s/actions?workflow=%s&actor=%s&status=%s", ctx.Repo.RepoLink, url.QueryEscape(ctx.FormString("workflow")), - url.QueryEscape(ctx.FormString("actor")), url.QueryEscape(ctx.FormString("status"))) + redirectURL := actionsListRedirectURL(ctx.Repo.RepoLink, ctx.FormString("workflow"), + ctx.FormString("actor"), ctx.FormString("status"), ctx.FormString("branch")) workflowID := ctx.FormString("workflow") if len(workflowID) == 0 { diff --git a/templates/repo/actions/list.tmpl b/templates/repo/actions/list.tmpl index 4870559ce0..1eec365cef 100644 --- a/templates/repo/actions/list.tmpl +++ b/templates/repo/actions/list.tmpl @@ -8,9 +8,9 @@
- + {{ctx.Locale.Tr "actions.runs.actors_no_select"}} {{range .Actors}} - + {{ctx.AvatarUtils.Avatar . 20}} {{.GetDisplayName}} {{end}} @@ -73,22 +73,41 @@ {{svg "octicon-search"}}
- + {{ctx.Locale.Tr "actions.runs.status_no_select"}} {{range .StatusInfoList}} - + {{.DisplayedStatus}} {{end}}
+ + {{if and .AllowDisableOrEnableWorkflow .CurWorkflowIsListed $.CurWorkflow}}