appview: add CI status component to pulls view #278

merged
opened by oppi.li targeting master from push-vquoltwpkuny
Changed files
+89 -20
appview
db
pages
templates
repo
pulls
+4 -3
appview/db/pipeline.go
··· 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 "github.com/go-git/go-git/v5/plumbing" 11 spindle "tangled.sh/tangled.sh/core/spindle/models" 12 ) 13 14 type Pipeline struct { ··· 85 86 type Trigger struct { 87 Id int 88 - Kind string 89 90 // push trigger fields 91 PushRef *string ··· 100 } 101 102 func (t *Trigger) IsPush() bool { 103 - return t != nil && t.Kind == "push" 104 } 105 106 func (t *Trigger) IsPullRequest() bool { 107 - return t != nil && t.Kind == "pull_request" 108 } 109 110 func (t *Trigger) TargetRef() string {
··· 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 "github.com/go-git/go-git/v5/plumbing" 11 spindle "tangled.sh/tangled.sh/core/spindle/models" 12 + "tangled.sh/tangled.sh/core/workflow" 13 ) 14 15 type Pipeline struct { ··· 86 87 type Trigger struct { 88 Id int 89 + Kind workflow.TriggerKind 90 91 // push trigger fields 92 PushRef *string ··· 101 } 102 103 func (t *Trigger) IsPush() bool { 104 + return t != nil && t.Kind == workflow.TriggerKindPush 105 } 106 107 func (t *Trigger) IsPullRequest() bool { 108 + return t != nil && t.Kind == workflow.TriggerKindPullRequest 109 } 110 111 func (t *Trigger) TargetRef() string {
+1
appview/pages/pages.go
··· 797 AbandonedPulls []*db.Pull 798 MergeCheck types.MergeCheckResponse 799 ResubmitCheck ResubmitResult 800 } 801 802 func (p *Pages) RepoSinglePull(w io.Writer, params RepoSinglePullParams) error {
··· 797 AbandonedPulls []*db.Pull 798 MergeCheck types.MergeCheckResponse 799 ResubmitCheck ResubmitResult 800 + Pipelines map[string]db.Pipeline 801 } 802 803 func (p *Pages) RepoSinglePull(w io.Writer, params RepoSinglePullParams) error {
+3 -4
appview/pages/templates/repo/pipelines/fragments/logBlock.html
··· 1 {{ define "repo/pipelines/fragments/logBlock" }} 2 <div id="lines" hx-swap-oob="beforeend"> 3 - <details id="step-{{ .Id }}" {{if not .Collapsed}}open{{end}} class="group bg-gray-100 px-2 dark:bg-gray-900"> 4 - <summary class="sticky top-0 py-1 list-none cursor-pointer py-2 bg-gray-100 dark:bg-gray-900 hover:text-gray-500 hover:dark:text-gray-400"> 5 <div class="group-open:hidden flex items-center gap-1"> 6 {{ i "chevron-right" "w-4 h-4" }} {{ .Name }} 7 </div> ··· 9 {{ i "chevron-down" "w-4 h-4" }} {{ .Name }} 10 </div> 11 </summary> 12 - <div class="text-blue-600 dark:text-blue-300 font-mono">{{ .Command }}</div> 13 - <div id="step-body-{{ .Id }}" class="font-mono"></div> 14 </details> 15 </div> 16 {{ end }}
··· 1 {{ define "repo/pipelines/fragments/logBlock" }} 2 <div id="lines" hx-swap-oob="beforeend"> 3 + <details id="step-{{ .Id }}" {{if not .Collapsed}}open{{end}} class="group bg-gray-100 pb-2 px-2 dark:bg-gray-900"> 4 + <summary class="sticky top-0 pt-2 group-open:pb-2 list-none cursor-pointer bg-gray-100 dark:bg-gray-900 hover:text-gray-500 hover:dark:text-gray-400"> 5 <div class="group-open:hidden flex items-center gap-1"> 6 {{ i "chevron-right" "w-4 h-4" }} {{ .Name }} 7 </div> ··· 9 {{ i "chevron-down" "w-4 h-4" }} {{ .Name }} 10 </div> 11 </summary> 12 + <div class="font-mono whitespace-pre overflow-x-auto"><div class="text-blue-600 dark:text-blue-300">{{ .Command }}</div><div id="step-body-{{ .Id }}"></div></div> 13 </details> 14 </div> 15 {{ end }}
+1 -3
appview/pages/templates/repo/pipelines/fragments/logLine.html
··· 1 {{ define "repo/pipelines/fragments/logLine" }} 2 - <div id="step-body-{{ .Id }}" hx-swap-oob="beforeend"> 3 - <p>{{ .Content }}</p> 4 - </div> 5 {{ end }} 6
··· 1 {{ define "repo/pipelines/fragments/logLine" }} 2 + <div id="step-body-{{ .Id }}" hx-swap-oob="beforeend" class="whitespace-pre"><p>{{ .Content }}</p></div> 3 {{ end }} 4
+13 -8
appview/pages/templates/repo/pipelines/pipelines.html
··· 34 {{ $p := index . 1 }} 35 {{ with $p }} 36 <div class="grid grid-cols-6 md:grid-cols-12 gap-2 items-center w-full"> 37 - <div class="col-span-2 md:col-span-8 flex items-center gap-4"> 38 {{ $target := .Trigger.TargetRef }} 39 {{ $workflows := .Workflows }} 40 {{ $link := "" }} ··· 43 {{ end }} 44 {{ if .Trigger.IsPush }} 45 <span class="font-bold">{{ $target }}</span> 46 - <span>push</span> 47 <span class="hidden md:inline-flex gap-2 items-center font-mono text-sm"> 48 {{ $old := deref .Trigger.PushOldSha }} 49 {{ $new := deref .Trigger.PushNewSha }} ··· 53 <a href="/{{ $root.RepoInfo.FullName }}/commit/{{ $old }}">{{ slice $old 0 8 }}</a> 54 </span> 55 {{ else if .Trigger.IsPullRequest }} 56 - <span> 57 - pull request 58 - <span class="inline-flex gap-2 items-center"> 59 - {{ $target }} 60 - {{ i "arrow-left" "size-4" }} 61 - {{ .Trigger.PRSourceBranch }} 62 </span> 63 </span> 64 {{ end }}
··· 34 {{ $p := index . 1 }} 35 {{ with $p }} 36 <div class="grid grid-cols-6 md:grid-cols-12 gap-2 items-center w-full"> 37 + <div class="text-sm md:text-base col-span-1"> 38 + {{ .Trigger.Kind.String }} 39 + </div> 40 + 41 + <div class="col-span-2 md:col-span-7 flex items-center gap-4"> 42 {{ $target := .Trigger.TargetRef }} 43 {{ $workflows := .Workflows }} 44 {{ $link := "" }} ··· 47 {{ end }} 48 {{ if .Trigger.IsPush }} 49 <span class="font-bold">{{ $target }}</span> 50 <span class="hidden md:inline-flex gap-2 items-center font-mono text-sm"> 51 {{ $old := deref .Trigger.PushOldSha }} 52 {{ $new := deref .Trigger.PushNewSha }} ··· 56 <a href="/{{ $root.RepoInfo.FullName }}/commit/{{ $old }}">{{ slice $old 0 8 }}</a> 57 </span> 58 {{ else if .Trigger.IsPullRequest }} 59 + {{ $sha := deref .Trigger.PRSourceSha }} 60 + <span class="inline-flex gap-2 items-center"> 61 + <span class="font-bold">{{ $target }}</span> 62 + {{ i "arrow-left" "size-4" }} 63 + {{ .Trigger.PRSourceBranch }} 64 + <span class="text-sm font-mono"> 65 + @ 66 + <a href="/{{ $root.RepoInfo.FullName }}/commit/{{ $sha }}">{{ slice $sha 0 8 }}</a> 67 </span> 68 </span> 69 {{ end }}
+40 -1
appview/pages/templates/repo/pulls/pull.html
··· 162 </div> 163 {{ end }} 164 165 {{ if eq $lastIdx .RoundNumber }} 166 {{ block "mergeStatus" $ }} {{ end }} 167 {{ block "resubmitStatus" $ }} {{ end }} ··· 260 {{ end }} 261 {{ end }} 262 263 - {{ define "commits" }} 264 {{ end }}
··· 162 </div> 163 {{ end }} 164 165 + {{ block "pipelineStatus" (list $ .) }} {{ end }} 166 + 167 {{ if eq $lastIdx .RoundNumber }} 168 {{ block "mergeStatus" $ }} {{ end }} 169 {{ block "resubmitStatus" $ }} {{ end }} ··· 262 {{ end }} 263 {{ end }} 264 265 + {{ define "pipelineStatus" }} 266 + {{ $root := index . 0 }} 267 + {{ $submission := index . 1 }} 268 + {{ $pipeline := index $root.Pipelines $submission.SourceRev }} 269 + {{ with $pipeline }} 270 + {{ $id := .Id }} 271 + {{ if .Statuses }} 272 + <div class="max-w-80 grid grid-cols-1 bg-white dark:bg-gray-800 rounded border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700"> 273 + {{ range $name, $all := .Statuses }} 274 + <a href="/{{ $root.RepoInfo.FullName }}/pipelines/{{ $id }}/workflow/{{ $name }}" class="no-underline hover:no-underline hover:bg-gray-100/25 hover:dark:bg-gray-700/25"> 275 + <div 276 + class="flex gap-2 items-center justify-between p-2"> 277 + {{ $lastStatus := $all.Latest }} 278 + {{ $kind := $lastStatus.Status.String }} 279 + 280 + {{ $t := .TimeTaken }} 281 + {{ $time := "" }} 282 + 283 + {{ if $t }} 284 + {{ $time = durationFmt $t }} 285 + {{ else }} 286 + {{ $time = printf "%s ago" (shortTimeFmt $lastStatus.Created) }} 287 + {{ end }} 288 + 289 + <div id="left" class="flex items-center gap-2 flex-shrink-0"> 290 + {{ template "repo/pipelines/fragments/workflowSymbol" $all }} 291 + {{ $name }} 292 + </div> 293 + <div id="right" class="flex items-center gap-2 flex-shrink-0"> 294 + <span class="font-bold">{{ $kind }}</span> 295 + <time>{{ $time }}</time> 296 + </div> 297 + </div> 298 + </a> 299 + {{ end }} 300 + </div> 301 + {{ end }} 302 + {{ end }} 303 {{ end }}
+27 -1
appview/pulls/pulls.go
··· 167 resubmitResult = s.resubmitCheck(f, pull, stack) 168 } 169 170 s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{ 171 LoggedInUser: user, 172 - RepoInfo: f.RepoInfo(user), 173 DidHandleMap: didHandleMap, 174 Pull: pull, 175 Stack: stack, 176 AbandonedPulls: abandonedPulls, 177 MergeCheck: mergeCheckResponse, 178 ResubmitCheck: resubmitResult, 179 }) 180 } 181
··· 167 resubmitResult = s.resubmitCheck(f, pull, stack) 168 } 169 170 + repoInfo := f.RepoInfo(user) 171 + 172 + m := make(map[string]db.Pipeline) 173 + 174 + var shas []string 175 + for _, s := range pull.Submissions { 176 + shas = append(shas, s.SourceRev) 177 + } 178 + 179 + ps, err := db.GetPipelineStatuses( 180 + s.db, 181 + db.FilterEq("repo_owner", repoInfo.OwnerDid), 182 + db.FilterEq("repo_name", repoInfo.Name), 183 + db.FilterEq("knot", repoInfo.Knot), 184 + db.FilterIn("sha", shas), 185 + ) 186 + if err != nil { 187 + log.Printf("failed to fetch pipeline statuses: %s", err) 188 + // non-fatal 189 + } 190 + 191 + for _, p := range ps { 192 + m[p.Sha] = p 193 + } 194 + 195 s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{ 196 LoggedInUser: user, 197 + RepoInfo: repoInfo, 198 DidHandleMap: didHandleMap, 199 Pull: pull, 200 Stack: stack, 201 AbandonedPulls: abandonedPulls, 202 MergeCheck: mergeCheckResponse, 203 ResubmitCheck: resubmitResult, 204 + Pipelines: m, 205 }) 206 } 207