detached d5e0505

Merge branch 'fix/main-e2e-tests' into main (!21)

test(app): fix the end-to-end tests failing on main
commit
d5e05051ad53ec339fe415696d1b993cbc0c7948
author
ermite · · 2026-10-21 05:14 UTC
merge of
b51d6ad + 7f66fd8 · diff against the first parent
signature
SSH VerifiedSHA256:lY9fILbB/A+hln6Vh/iHoiiog74bbw/4qWrf/lrTU3U · ermite instance key Verified for the committer email
checks
4/4
refs
tag: v0.31.0
3 files · +27 -4
M internal/app/ci_permissions_test.go +25 -2
@@ -239,13 +239,36 @@ func TestJobTokenWithContentsWritePushesButNotWorkflows(t *testing.T) {
239239 // None of the pushes of the job token started a run; a push of the owner
240240 // does, and queues after them.
241241 c.push("sentinel", map[string]string{"s.txt": "s"}, "")
242- c.waitFor("the owner's runs", func() bool { return len(c.runs()) >= runsBefore+4 })
242+ // rworkflow carries both p.yml and moved.yml, each on push and create.
243+ // sentinel branches from ok (p.yml only), so adds two more runs. Wait for
244+ // its create run: planning is queued, and a total alone can be reached
245+ // before the owner's pushes have finished being planned.
246+ c.waitFor("the sentinel's create run", func() bool {
247+ for _, r := range c.runs() {
248+ if r.GetRef() == "refs/heads/sentinel" && r.GetEvent() == "create" {
249+ return true
250+ }
251+ }
252+ return false
253+ })
254+ var ownerRuns []string
243255 for _, r := range c.runs() {
256+ if r.GetRef() == "refs/heads/rworkflow" || r.GetRef() == "refs/heads/sentinel" {
257+ ownerRuns = append(ownerRuns, r.GetRef()+" "+r.GetWorkflowPath()+" "+r.GetEvent())
258+ }
244259 assert.NotEqual(t, "refs/heads/orphan", r.GetRef(), "no run for a job token's push")
245260 assert.NotEqual(t, "refs/tags/v0", r.GetRef())
246261 assert.NotEqual(t, "delete", r.GetEvent(), "no run for a job token's deletes")
247262 }
248- assert.Len(t, c.runs(), runsBefore+4, "push and create of the owner's rworkflow and sentinel only")
263+ assert.ElementsMatch(t, []string{
264+ "refs/heads/rworkflow .github/workflows/p.yml push",
265+ "refs/heads/rworkflow .github/workflows/p.yml create",
266+ "refs/heads/rworkflow .github/workflows/moved.yml push",
267+ "refs/heads/rworkflow .github/workflows/moved.yml create",
268+ "refs/heads/sentinel .github/workflows/p.yml push",
269+ "refs/heads/sentinel .github/workflows/p.yml create",
270+ }, ownerRuns)
271+ assert.Len(t, c.runs(), runsBefore+6, "only the owner's two workflows on rworkflow and one on sentinel, each on push and create")
249272 }
250273
251274 func TestJobTokenCannotPushToAnotherRepository(t *testing.T) {
@@ -239,13 +239,36 @@ func TestJobTokenWithContentsWritePushesButNotWorkflows(t *testing.T) {
239 // None of the pushes of the job token started a run; a push of the owner239 // None of the pushes of the job token started a run; a push of the owner
240 // does, and queues after them.240 // does, and queues after them.
241 c.push("sentinel", map[string]string{"s.txt": "s"}, "")241 c.push("sentinel", map[string]string{"s.txt": "s"}, "")
242- c.waitFor("the owner's runs", func() bool { return len(c.runs()) >= runsBefore+4 })242+ // rworkflow carries both p.yml and moved.yml, each on push and create.
243+ // sentinel branches from ok (p.yml only), so adds two more runs. Wait for
244+ // its create run: planning is queued, and a total alone can be reached
245+ // before the owner's pushes have finished being planned.
246+ c.waitFor("the sentinel's create run", func() bool {
247+ for _, r := range c.runs() {
248+ if r.GetRef() == "refs/heads/sentinel" && r.GetEvent() == "create" {
249+ return true
250+ }
251+ }
252+ return false
253+ })
254+ var ownerRuns []string
243 for _, r := range c.runs() {255 for _, r := range c.runs() {
256+ if r.GetRef() == "refs/heads/rworkflow" || r.GetRef() == "refs/heads/sentinel" {
257+ ownerRuns = append(ownerRuns, r.GetRef()+" "+r.GetWorkflowPath()+" "+r.GetEvent())
258+ }
244 assert.NotEqual(t, "refs/heads/orphan", r.GetRef(), "no run for a job token's push")259 assert.NotEqual(t, "refs/heads/orphan", r.GetRef(), "no run for a job token's push")
245 assert.NotEqual(t, "refs/tags/v0", r.GetRef())260 assert.NotEqual(t, "refs/tags/v0", r.GetRef())
246 assert.NotEqual(t, "delete", r.GetEvent(), "no run for a job token's deletes")261 assert.NotEqual(t, "delete", r.GetEvent(), "no run for a job token's deletes")
247 }262 }
248- assert.Len(t, c.runs(), runsBefore+4, "push and create of the owner's rworkflow and sentinel only")263+ assert.ElementsMatch(t, []string{
264+ "refs/heads/rworkflow .github/workflows/p.yml push",
265+ "refs/heads/rworkflow .github/workflows/p.yml create",
266+ "refs/heads/rworkflow .github/workflows/moved.yml push",
267+ "refs/heads/rworkflow .github/workflows/moved.yml create",
268+ "refs/heads/sentinel .github/workflows/p.yml push",
269+ "refs/heads/sentinel .github/workflows/p.yml create",
270+ }, ownerRuns)
271+ assert.Len(t, c.runs(), runsBefore+6, "only the owner's two workflows on rworkflow and one on sentinel, each on push and create")
249 }272 }
250 273
251 func TestJobTokenCannotPushToAnotherRepository(t *testing.T) {274 func TestJobTokenCannotPushToAnotherRepository(t *testing.T) {
M internal/app/testdata/web/blob-markdown.html +1 -1
@@ -116,7 +116,7 @@
116116 <h1 id="md-guide">Guide</h1>
117117 <h2 id="md-steps">Steps</h2>
118118 <p>Run it.</p>
119-<pre>
119+<pre class="chroma">
120120 <code class="language-sh">make all
121121 </code>
122122 </pre>
@@ -116,7 +116,7 @@
116 <h1 id="md-guide">Guide</h1>116 <h1 id="md-guide">Guide</h1>
117 <h2 id="md-steps">Steps</h2>117 <h2 id="md-steps">Steps</h2>
118 <p>Run it.</p>118 <p>Run it.</p>
119-<pre>119+<pre class="chroma">
120 <code class="language-sh">make all120 <code class="language-sh">make all
121 </code>121 </code>
122 </pre>122 </pre>
M internal/app/testdata/web/summary.html +1 -1
@@ -103,7 +103,7 @@
103103 <h1 id="md-demo">Demo</h1>
104104 <p>A small <em>demo</em> with a <a href="/demo/blob/main/docs/guide.md">guide</a> and <a href="https://example.org/x" rel="nofollow noopener noreferrer">the site</a>.</p>
105105 <h2 id="md-install">Install</h2>
106-<pre>
106+<pre class="chroma">
107107 <code class="language-sh">go install example.org/demo@latest
108108 </code>
109109 </pre>
@@ -103,7 +103,7 @@
103 <h1 id="md-demo">Demo</h1>103 <h1 id="md-demo">Demo</h1>
104 <p>A small <em>demo</em> with a <a href="/demo/blob/main/docs/guide.md">guide</a> and <a href="https://example.org/x" rel="nofollow noopener noreferrer">the site</a>.</p>104 <p>A small <em>demo</em> with a <a href="/demo/blob/main/docs/guide.md">guide</a> and <a href="https://example.org/x" rel="nofollow noopener noreferrer">the site</a>.</p>
105 <h2 id="md-install">Install</h2>105 <h2 id="md-install">Install</h2>
106-<pre>106+<pre class="chroma">
107 <code class="language-sh">go install example.org/demo@latest107 <code class="language-sh">go install example.org/demo@latest
108 </code>108 </code>
109 </pre>109 </pre>

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 42

↑↓ moveenter openesc close