diff --git a/appview/db/pipeline.go b/appview/db/pipeline.go index bd5e19c3..b643628c 100644 --- a/appview/db/pipeline.go +++ b/appview/db/pipeline.go @@ -170,11 +170,13 @@ func AddPipelineStatus(e Execer, status models.PipelineStatus) error { // this is a mega query, but the most useful one: // get N pipelines, for each one get the latest status of its N workflows +// +// the pipelines table is aliased to `p` +// the triggers table is aliased to `t` func GetPipelineStatuses(e Execer, limit int, filters ...orm.Filter) ([]models.Pipeline, error) { var conditions []string var args []any for _, filter := range filters { - filter.Key = "p." + filter.Key // the table is aliased in the query to `p` conditions = append(conditions, filter.Condition()) args = append(args, filter.Arg()...) } @@ -366,3 +368,48 @@ func GetPipelineStatuses(e Execer, limit int, filters ...orm.Filter) ([]models.P return all, nil } + +// the pipelines table is aliased to `p` +// the triggers table is aliased to `t` +func GetTotalPipelineStatuses(e Execer, filters ...orm.Filter) (int64, error) { + var conditions []string + var args []any + for _, filter := range filters { + conditions = append(conditions, filter.Condition()) + args = append(args, filter.Arg()...) + } + + whereClause := "" + if conditions != nil { + whereClause = " where " + strings.Join(conditions, " and ") + } + + query := fmt.Sprintf(` + select + count(1) + from + pipelines p + join + triggers t ON p.trigger_id = t.id + %s + `, whereClause) + + rows, err := e.Query(query, args...) + if err != nil { + return 0, err + } + defer rows.Close() + + for rows.Next() { + var count int64 + err := rows.Scan(&count) + if err != nil { + return 0, err + } + + return count, nil + } + + // unreachable + return 0, nil +} diff --git a/appview/pages/pages.go b/appview/pages/pages.go index c7fa9ff9..0b758f31 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -1348,12 +1348,12 @@ func (p *Pages) EditLabelPanel(w io.Writer, params EditLabelPanelParams) error { } type PipelinesParams struct { - LoggedInUser *oauth.MultiAccountUser - RepoInfo repoinfo.RepoInfo - Pipelines []models.Pipeline - Active string - FilteringByPush bool - FilteringByPR bool + LoggedInUser *oauth.MultiAccountUser + RepoInfo repoinfo.RepoInfo + Pipelines []models.Pipeline + Active string + FilterKind string + Total int64 } func (p *Pages) Pipelines(w io.Writer, params PipelinesParams) error { diff --git a/appview/pages/templates/repo/pipelines/pipelines.html b/appview/pages/templates/repo/pipelines/pipelines.html index 5d02564d..0a51048f 100644 --- a/appview/pages/templates/repo/pipelines/pipelines.html +++ b/appview/pages/templates/repo/pipelines/pipelines.html @@ -7,12 +7,7 @@ {{ end }} {{ define "repoContent" }} - {{ $active := "all" }} - {{ if .FilteringByPush }} - {{ $active = "push" }} - {{ else if .FilteringByPR }} - {{ $active = "pr" }} - {{ end }} + {{ $active := .FilterKind }} {{ $all := (dict @@ -28,7 +23,7 @@ "Meta" "") }} {{ $pr := (dict - "Key" "pr" + "Key" "pull_request" "Value" "pull request" "Icon" "git-pull-request" "Meta" "") }} @@ -36,10 +31,10 @@
- {{ template "fragments/tabSelector" (dict "Name" "trigger" "Values" $values "Active" $active) }} + {{ template "fragments/tabSelector" (dict "Name" "trigger" "Values" $values "Active" .FilterKind) }}
- {{ len .Pipelines }} pipeline run{{ if ne (len .Pipelines) 1 }}s{{ end }} + {{ .Total }} pipeline run{{ if ne .Total 1 }}s{{ end }}
{{ end }} @@ -52,7 +47,7 @@ {{ end }} {{ else }} -
+
{{ i "package" "size-16 text-gray-300 dark:text-gray-700" }}
diff --git a/appview/pipelines/pipelines.go b/appview/pipelines/pipelines.go index a3d36fe0..094c40bc 100644 --- a/appview/pipelines/pipelines.go +++ b/appview/pipelines/pipelines.go @@ -86,40 +86,44 @@ func (p *Pipelines) Index(w http.ResponseWriter, r *http.Request) { return } + filterKind := r.URL.Query().Get("trigger") + filters := []orm.Filter{ + orm.FilterEq("p.repo_owner", f.Did), + orm.FilterEq("p.repo_name", f.Name), + orm.FilterEq("p.knot", f.Knot), + } + switch filterKind { + case "push": + filters = append(filters, orm.FilterEq("t.kind", "push")) + case "pull_request": + filters = append(filters, orm.FilterEq("t.kind", "pull_request")) + default: + // no filters otherwise, default to "all" + filterKind = "all" + } + ps, err := db.GetPipelineStatuses( p.db, 30, - orm.FilterEq("repo_owner", f.Did), - orm.FilterEq("repo_name", f.Name), - orm.FilterEq("knot", f.Knot), + filters..., ) if err != nil { l.Error("failed to query db", "err", err) return } - // Filter by trigger - filterTrigger := r.URL.Query().Get("trigger") - var filtered []models.Pipeline - for _, pipeline := range ps { - if filterTrigger == "push" && pipeline.Trigger != nil && pipeline.Trigger.IsPush() { - filtered = append(filtered, pipeline) - } else if filterTrigger == "pr" && pipeline.Trigger != nil && pipeline.Trigger.IsPullRequest() { - filtered = append(filtered, pipeline) - } else if filterTrigger == "" || filterTrigger == "all" { - filtered = append(filtered, pipeline) - } + total, err := db.GetTotalPipelineStatuses(p.db, filters...) + if err != nil { + l.Error("failed to query db", "err", err) + return } - filteringByPush := filterTrigger == "push" - filteringByPR := filterTrigger == "pr" - p.pages.Pipelines(w, pages.PipelinesParams{ - LoggedInUser: user, - RepoInfo: p.repoResolver.GetRepoInfo(r, user), - Pipelines: filtered, - FilteringByPush: filteringByPush, - FilteringByPR: filteringByPR, + LoggedInUser: user, + RepoInfo: p.repoResolver.GetRepoInfo(r, user), + Pipelines: ps, + FilterKind: filterKind, + Total: total, }) } @@ -148,10 +152,10 @@ func (p *Pipelines) Workflow(w http.ResponseWriter, r *http.Request) { ps, err := db.GetPipelineStatuses( p.db, 1, - orm.FilterEq("repo_owner", f.Did), - orm.FilterEq("repo_name", f.Name), - orm.FilterEq("knot", f.Knot), - orm.FilterEq("id", pipelineId), + orm.FilterEq("p.repo_owner", f.Did), + orm.FilterEq("p.repo_name", f.Name), + orm.FilterEq("p.knot", f.Knot), + orm.FilterEq("p.id", pipelineId), ) if err != nil { l.Error("failed to query db", "err", err) @@ -215,10 +219,10 @@ func (p *Pipelines) Logs(w http.ResponseWriter, r *http.Request) { ps, err := db.GetPipelineStatuses( p.db, 1, - orm.FilterEq("repo_owner", f.Did), - orm.FilterEq("repo_name", f.Name), - orm.FilterEq("knot", f.Knot), - orm.FilterEq("id", pipelineId), + orm.FilterEq("p.repo_owner", f.Did), + orm.FilterEq("p.repo_name", f.Name), + orm.FilterEq("p.knot", f.Knot), + orm.FilterEq("p.id", pipelineId), ) if err != nil || len(ps) != 1 { l.Error("pipeline query failed", "err", err, "count", len(ps)) @@ -364,10 +368,10 @@ func (p *Pipelines) Cancel(w http.ResponseWriter, r *http.Request) { ps, err := db.GetPipelineStatuses( p.db, 1, - orm.FilterEq("repo_owner", f.Did), - orm.FilterEq("repo_name", f.Name), - orm.FilterEq("knot", f.Knot), - orm.FilterEq("id", pipelineId), + orm.FilterEq("p.repo_owner", f.Did), + orm.FilterEq("p.repo_name", f.Name), + orm.FilterEq("p.knot", f.Knot), + orm.FilterEq("p.id", pipelineId), ) if err != nil { return models.Pipeline{}, err diff --git a/appview/pulls/pulls.go b/appview/pulls/pulls.go index 441a9dd7..f037636b 100644 --- a/appview/pulls/pulls.go +++ b/appview/pulls/pulls.go @@ -214,10 +214,10 @@ func (s *Pulls) repoPullHelper(w http.ResponseWriter, r *http.Request, interdiff ps, err := db.GetPipelineStatuses( s.db, len(shas), - orm.FilterEq("repo_owner", f.Did), - orm.FilterEq("repo_name", f.Name), - orm.FilterEq("knot", f.Knot), - orm.FilterIn("sha", shas), + orm.FilterEq("p.repo_owner", f.Did), + orm.FilterEq("p.repo_name", f.Name), + orm.FilterEq("p.knot", f.Knot), + orm.FilterIn("p.sha", shas), ) if err != nil { log.Printf("failed to fetch pipeline statuses: %s", err) @@ -636,10 +636,10 @@ func (s *Pulls) RepoPulls(w http.ResponseWriter, r *http.Request) { ps, err := db.GetPipelineStatuses( s.db, len(shas), - orm.FilterEq("repo_owner", f.Did), - orm.FilterEq("repo_name", f.Name), - orm.FilterEq("knot", f.Knot), - orm.FilterIn("sha", shas), + orm.FilterEq("p.repo_owner", f.Did), + orm.FilterEq("p.repo_name", f.Name), + orm.FilterEq("p.knot", f.Knot), + orm.FilterIn("p.sha", shas), ) if err != nil { log.Printf("failed to fetch pipeline statuses: %s", err) diff --git a/appview/repo/repo_util.go b/appview/repo/repo_util.go index 7d40fc67..8bf020b8 100644 --- a/appview/repo/repo_util.go +++ b/appview/repo/repo_util.go @@ -103,10 +103,10 @@ func getPipelineStatuses( ps, err := db.GetPipelineStatuses( d, len(shas), - orm.FilterEq("repo_owner", repo.Did), - orm.FilterEq("repo_name", repo.Name), - orm.FilterEq("knot", repo.Knot), - orm.FilterIn("sha", shas), + orm.FilterEq("p.repo_owner", repo.Did), + orm.FilterEq("p.repo_name", repo.Name), + orm.FilterEq("p.knot", repo.Knot), + orm.FilterIn("p.sha", shas), ) if err != nil { return nil, err