detached 5dbd27f

#24 feat(releases): GitHub-like releases and S3 blob storage

state
merged · 5dbd27f · fast-forward
branch
feat/releases → main
opened
bnema ·
updated

GitHub-like releases for ermite, plus a pluggable blob store (ADR 0034).

What it adds

  • Releases bound to a Git tag: title, Markdown notes, assets, draft/prerelease, latest (make_latest pin). Deleting the tag turns the release back into a draft.
  • Interfaces: GitHub-compatible REST under /-/github/api (also /api/v3 for go-github/GoReleaser), ConnectRPC ReleaseService, ermite release CLI, read-only web pages.
  • Stable links: //releases/latest/download/ and //releases/download//. Downloads are always relayed by ermite (Range/If-Range supported).
  • Scope release:write (in the cli preset), or a job token with contents: write. Branch-limited tokens are refused.
  • Blob store: disk ($ERMITE_DATA_DIR/blobs) or any S3-compatible provider via ERMITE_S3_* (common S3 subset, ermite never creates buckets). CI artifacts move onto it; legacy disk artifacts stay readable.
  • Storage schema 6: unrestricted tokens holding every schema-5 scope gain release:write.
  • Requires ermite-api v0.16.0 (SCOPE_RELEASE_WRITE = 13, release events 27-30).

Checks

  • go build, vet, hexcheck, go test -race ./... green.
  • e2e on the local dev stack: disk and MinIO backends, Firecracker runner with action-gh-release and upload-artifact (20 MiB), Playwright on the web pages. S3 contract suite against MinIO and a real Scaleway bucket.
  • Wrap-up review: 13 findings, all fixed with regression tests.

Deployment (after merge): Gordon secrets and S3 config for staging then prod, re-enable release.yml workflows.

CommitSubjectAuthorDateSignatureStatus
5dbd27ffix(lint): check ignored close and remove errors, simplify release conditionsbriceGPG Verified
b869944chore(deps): require ermite-api v0.16.0 and drop the local replacebriceGPG Verified
1428b20fix(releases): hide draft events and cursors, honour update targets, share range handlingbriceGPG Verified
97e2b33fix(blobs): reclaim crashed temp files, skip broken multipart entries, sync new directoriesbriceGPG Verified
8361f60fix(ci): bound concurrent artifact block uploads and reuse their buffersbriceGPG Verified
6abe390test(blobs): run the blob contract on MinIO, which lists unfinished uploads by keybriceGPG Verified
27d9aa4fix(githubapi): accept the api/v3 base that GoReleaser appends to the API URLbriceGPG Verified
d50b7cdfeat(app): wire releases and the blob store, S3 configuration, MinIO compose profile and docsbriceGPG Verified
0933a48feat(cli): ermite release commands and release:write in the cli presetbriceGPG Verified
f67dc6afeat(githubapi): GitHub-compatible REST API for releases and assetsbriceGPG Verified
eab40eefeat(web): releases tab, release pages and stable asset download linksbriceGPG Verified
bfabb0cfeat(rpc): ConnectRPC ReleaseService with streamed asset upload and downloadbriceGPG Verified
b8fe0a4fix(rpc): map the release:write scope to the contractbriceGPG Verified
f9e6941feat(ci): store CI artifacts on the blob store, keep legacy disk artifacts readablebriceGPG Verified
eb72c2ffeat(releases): release, asset and sweep use casesbriceGPG Verified
0c4e1e3feat(releases): git tag writer and release hooks on pushes and repository deletionbriceGPG Verified
8fd2b19feat(blobs): blob store port with disk and provider-agnostic S3 adaptersbriceGPG Verified
c57f9ecfeat(releases): release domain, kv storage, ports and schema 6 with release:writebriceGPG Verified

Checks 8

149 files · +17035 -809
8/8
M .hexcheck.yaml +12 -2
M README.md +1 -0
M compose.yaml +39 -0
M docs/ci-artifacts.md +2 -1
M docs/cli.md +45 -0
M docs/configuration.md +29 -1
A docs/releases.md +99 -0
A docs/storage.md +92 -0
M docs/tokens.md +9 -0
M gen/ermite/storage/ci_artifact.pb.go +15 -5
A gen/ermite/storage/release.pb.go +463 -0
M go.mod +16 -1
M go.sum +40 -2
A internal/adapters/blobdisk/blobdisk.go +572 -0
A internal/adapters/blobdisk/blobdisk_internal_test.go +87 -0
A internal/adapters/blobdisk/blobdisk_test.go +29 -0
A internal/adapters/blobs3/blobs3.go +461 -0
A internal/adapters/blobs3/blobs3_test.go +85 -0
A internal/adapters/blobs3/config.go +13 -0
A internal/adapters/blobs3/integration_test.go +44 -0
A internal/adapters/blobtest/suite.go +256 -0
M internal/adapters/ciartifacts/ciartifacts.go +5 -171
M internal/adapters/ciartifacts/ciartifacts_test.go +8 -105
M internal/adapters/client/client.go +5 -0
M internal/adapters/client/client_test.go +3 -3
M internal/adapters/client/features.go +3 -1
A internal/adapters/client/release_test.go +43 -0
M internal/adapters/client/scopes_test.go +1 -0
A internal/adapters/gitcli/tags.go +42 -0
A internal/adapters/gitcli/tags_test.go +31 -0
M internal/adapters/githubapi/handler.go +23 -2
A internal/adapters/githubapi/releases.go +413 -0
A internal/adapters/githubapi/releases_test.go +466 -0
A internal/adapters/githubapi/testdata/releases/draft.json +40 -0
A internal/adapters/githubapi/testdata/releases/release.json +113 -0
M internal/adapters/kvstore/ci_artifact.go +2 -1
M internal/adapters/kvstore/ci_artifact_test.go +5 -0
M internal/adapters/kvstore/issues_test.go +16 -8
A internal/adapters/kvstore/releases.go +408 -0
A internal/adapters/kvstore/releases_test.go +131 -0
M internal/adapters/kvstore/repos.go +1 -0
M internal/adapters/kvstore/store.go +25 -4
M internal/adapters/kvstore/store_test.go +57 -0
M internal/adapters/rpc/api.go +9 -0
M internal/adapters/rpc/convert.go +28 -3
M internal/adapters/rpc/errors.go +2 -0
M internal/adapters/rpc/event.go +26 -0
A internal/adapters/rpc/release.go +358 -0
A internal/adapters/rpc/release_test.go +472 -0
M internal/adapters/web/fragments.go +8 -2
M internal/adapters/web/fragments_test.go +20 -0
A internal/adapters/web/releases.go +244 -0
A internal/adapters/web/releases.templ +67 -0
A internal/adapters/web/releases_templ.go +439 -0
A internal/adapters/web/releases_test.go +298 -0
M internal/adapters/web/repo.go +3 -0
M internal/adapters/web/web.go +11 -0
M internal/app/api_test.go +1 -1
M internal/app/ci_artifacts_test.go +110 -12
M internal/app/ci_e2e_test.go +2 -0
M internal/app/cli_e2e_test.go +4 -3
A internal/app/cli_release.go +603 -0
A internal/app/cli_release_e2e_test.go +65 -0
A internal/app/cli_release_test.go +388 -0
M internal/app/cli_token.go +9 -0
M internal/app/cli_token_test.go +40 -1
M internal/app/cli_version.go +1 -0
M internal/app/cli_version_test.go +5 -5
M internal/app/forge.go +49 -4
A internal/app/release_e2e_test.go +160 -0
M internal/app/root.go +1 -1
M internal/app/testdata/web/blob-binary.html +15 -5
M internal/app/testdata/web/blob-code.html +15 -5
M internal/app/testdata/web/blob-empty.html +15 -5
M internal/app/testdata/web/blob-image.html +15 -5
M internal/app/testdata/web/blob-markdown.html +15 -5
@@ -96,6 +96,10 @@
9696 </a>
9797 </li>
9898 <li>
99+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
100+</a>
101+</li>
102+<li>
99103 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
100104 </a>
101105 </li>
@@ -425,31 +429,37 @@
425429 <span class="k">section</span>
426430 </a>
427431 </li>
428-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
432+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
433+<a href="/files/releases" tabindex="-1">
434+<span class="lbl">releases</span>
435+<span class="k">section</span>
436+</a>
437+</li>
438+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
429439 <a href="/files/actions" tabindex="-1">
430440 <span class="lbl">actions</span>
431441 <span class="k">section</span>
432442 </a>
433443 </li>
434-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
444+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
435445 <a href="/files/tree/feature/x" tabindex="-1">
436446 <span class="lbl">feature/x</span>
437447 <span class="k">branch</span>
438448 </a>
439449 </li>
440-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
450+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
441451 <a href="/files/tree/main" tabindex="-1">
442452 <span class="lbl">main</span>
443453 <span class="k">branch</span>
444454 </a>
445455 </li>
446-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">
456+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
447457 <a href="/files/tree/v1.0" tabindex="-1">
448458 <span class="lbl">v1.0</span>
449459 <span class="k">tag</span>
450460 </a>
451461 </li>
452-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
462+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
453463 <a href="#" data-fire="keys" tabindex="-1">
454464 <span class="lbl">turn single-key shortcuts off</span>
455465 <span class="k">action</span>
@@ -96,6 +96,10 @@
96 </a>96 </a>
97 </li>97 </li>
98 <li>98 <li>
99+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
100+</a>
101+</li>
102+<li>
99 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>103 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
100 </a>104 </a>
101 </li>105 </li>
@@ -425,31 +429,37 @@
425 <span class="k">section</span>429 <span class="k">section</span>
426 </a>430 </a>
427 </li>431 </li>
428-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">432+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
433+<a href="/files/releases" tabindex="-1">
434+<span class="lbl">releases</span>
435+<span class="k">section</span>
436+</a>
437+</li>
438+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
429 <a href="/files/actions" tabindex="-1">439 <a href="/files/actions" tabindex="-1">
430 <span class="lbl">actions</span>440 <span class="lbl">actions</span>
431 <span class="k">section</span>441 <span class="k">section</span>
432 </a>442 </a>
433 </li>443 </li>
434-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">444+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
435 <a href="/files/tree/feature/x" tabindex="-1">445 <a href="/files/tree/feature/x" tabindex="-1">
436 <span class="lbl">feature/x</span>446 <span class="lbl">feature/x</span>
437 <span class="k">branch</span>447 <span class="k">branch</span>
438 </a>448 </a>
439 </li>449 </li>
440-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">450+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
441 <a href="/files/tree/main" tabindex="-1">451 <a href="/files/tree/main" tabindex="-1">
442 <span class="lbl">main</span>452 <span class="lbl">main</span>
443 <span class="k">branch</span>453 <span class="k">branch</span>
444 </a>454 </a>
445 </li>455 </li>
446-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">456+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
447 <a href="/files/tree/v1.0" tabindex="-1">457 <a href="/files/tree/v1.0" tabindex="-1">
448 <span class="lbl">v1.0</span>458 <span class="lbl">v1.0</span>
449 <span class="k">tag</span>459 <span class="k">tag</span>
450 </a>460 </a>
451 </li>461 </li>
452-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">462+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
453 <a href="#" data-fire="keys" tabindex="-1">463 <a href="#" data-fire="keys" tabindex="-1">
454 <span class="lbl">turn single-key shortcuts off</span>464 <span class="lbl">turn single-key shortcuts off</span>
455 <span class="k">action</span>465 <span class="k">action</span>
M internal/app/testdata/web/blob-svg.html +15 -5
@@ -93,6 +93,10 @@
9393 </a>
9494 </li>
9595 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97101 </a>
98102 </li>
@@ -383,31 +387,37 @@
383387 <span class="k">section</span>
384388 </a>
385389 </li>
386-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
390+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
391+<a href="/files/releases" tabindex="-1">
392+<span class="lbl">releases</span>
393+<span class="k">section</span>
394+</a>
395+</li>
396+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
387397 <a href="/files/actions" tabindex="-1">
388398 <span class="lbl">actions</span>
389399 <span class="k">section</span>
390400 </a>
391401 </li>
392-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
402+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
393403 <a href="/files/tree/feature/x" tabindex="-1">
394404 <span class="lbl">feature/x</span>
395405 <span class="k">branch</span>
396406 </a>
397407 </li>
398-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
408+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
399409 <a href="/files/tree/main" tabindex="-1">
400410 <span class="lbl">main</span>
401411 <span class="k">branch</span>
402412 </a>
403413 </li>
404-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">
414+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
405415 <a href="/files/tree/v1.0" tabindex="-1">
406416 <span class="lbl">v1.0</span>
407417 <span class="k">tag</span>
408418 </a>
409419 </li>
410-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
420+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
411421 <a href="#" data-fire="keys" tabindex="-1">
412422 <span class="lbl">turn single-key shortcuts off</span>
413423 <span class="k">action</span>
@@ -93,6 +93,10 @@
93 </a>93 </a>
94 </li>94 </li>
95 <li>95 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97 </a>101 </a>
98 </li>102 </li>
@@ -383,31 +387,37 @@
383 <span class="k">section</span>387 <span class="k">section</span>
384 </a>388 </a>
385 </li>389 </li>
386-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">390+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
391+<a href="/files/releases" tabindex="-1">
392+<span class="lbl">releases</span>
393+<span class="k">section</span>
394+</a>
395+</li>
396+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
387 <a href="/files/actions" tabindex="-1">397 <a href="/files/actions" tabindex="-1">
388 <span class="lbl">actions</span>398 <span class="lbl">actions</span>
389 <span class="k">section</span>399 <span class="k">section</span>
390 </a>400 </a>
391 </li>401 </li>
392-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">402+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
393 <a href="/files/tree/feature/x" tabindex="-1">403 <a href="/files/tree/feature/x" tabindex="-1">
394 <span class="lbl">feature/x</span>404 <span class="lbl">feature/x</span>
395 <span class="k">branch</span>405 <span class="k">branch</span>
396 </a>406 </a>
397 </li>407 </li>
398-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">408+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
399 <a href="/files/tree/main" tabindex="-1">409 <a href="/files/tree/main" tabindex="-1">
400 <span class="lbl">main</span>410 <span class="lbl">main</span>
401 <span class="k">branch</span>411 <span class="k">branch</span>
402 </a>412 </a>
403 </li>413 </li>
404-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">414+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
405 <a href="/files/tree/v1.0" tabindex="-1">415 <a href="/files/tree/v1.0" tabindex="-1">
406 <span class="lbl">v1.0</span>416 <span class="lbl">v1.0</span>
407 <span class="k">tag</span>417 <span class="k">tag</span>
408 </a>418 </a>
409 </li>419 </li>
410-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">420+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
411 <a href="#" data-fire="keys" tabindex="-1">421 <a href="#" data-fire="keys" tabindex="-1">
412 <span class="lbl">turn single-key shortcuts off</span>422 <span class="lbl">turn single-key shortcuts off</span>
413 <span class="k">action</span>423 <span class="k">action</span>
M internal/app/testdata/web/blob-text.html +15 -5
@@ -93,6 +93,10 @@
9393 </a>
9494 </li>
9595 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97101 </a>
98102 </li>
@@ -378,31 +382,37 @@
378382 <span class="k">section</span>
379383 </a>
380384 </li>
381-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
385+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
386+<a href="/files/releases" tabindex="-1">
387+<span class="lbl">releases</span>
388+<span class="k">section</span>
389+</a>
390+</li>
391+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
382392 <a href="/files/actions" tabindex="-1">
383393 <span class="lbl">actions</span>
384394 <span class="k">section</span>
385395 </a>
386396 </li>
387-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
397+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
388398 <a href="/files/tree/feature/x" tabindex="-1">
389399 <span class="lbl">feature/x</span>
390400 <span class="k">branch</span>
391401 </a>
392402 </li>
393-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
403+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
394404 <a href="/files/tree/main" tabindex="-1">
395405 <span class="lbl">main</span>
396406 <span class="k">branch</span>
397407 </a>
398408 </li>
399-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">
409+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
400410 <a href="/files/tree/v1.0" tabindex="-1">
401411 <span class="lbl">v1.0</span>
402412 <span class="k">tag</span>
403413 </a>
404414 </li>
405-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
415+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
406416 <a href="#" data-fire="keys" tabindex="-1">
407417 <span class="lbl">turn single-key shortcuts off</span>
408418 <span class="k">action</span>
@@ -93,6 +93,10 @@
93 </a>93 </a>
94 </li>94 </li>
95 <li>95 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97 </a>101 </a>
98 </li>102 </li>
@@ -378,31 +382,37 @@
378 <span class="k">section</span>382 <span class="k">section</span>
379 </a>383 </a>
380 </li>384 </li>
381-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">385+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
386+<a href="/files/releases" tabindex="-1">
387+<span class="lbl">releases</span>
388+<span class="k">section</span>
389+</a>
390+</li>
391+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
382 <a href="/files/actions" tabindex="-1">392 <a href="/files/actions" tabindex="-1">
383 <span class="lbl">actions</span>393 <span class="lbl">actions</span>
384 <span class="k">section</span>394 <span class="k">section</span>
385 </a>395 </a>
386 </li>396 </li>
387-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">397+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
388 <a href="/files/tree/feature/x" tabindex="-1">398 <a href="/files/tree/feature/x" tabindex="-1">
389 <span class="lbl">feature/x</span>399 <span class="lbl">feature/x</span>
390 <span class="k">branch</span>400 <span class="k">branch</span>
391 </a>401 </a>
392 </li>402 </li>
393-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">403+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
394 <a href="/files/tree/main" tabindex="-1">404 <a href="/files/tree/main" tabindex="-1">
395 <span class="lbl">main</span>405 <span class="lbl">main</span>
396 <span class="k">branch</span>406 <span class="k">branch</span>
397 </a>407 </a>
398 </li>408 </li>
399-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">409+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
400 <a href="/files/tree/v1.0" tabindex="-1">410 <a href="/files/tree/v1.0" tabindex="-1">
401 <span class="lbl">v1.0</span>411 <span class="lbl">v1.0</span>
402 <span class="k">tag</span>412 <span class="k">tag</span>
403 </a>413 </a>
404 </li>414 </li>
405-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">415+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
406 <a href="#" data-fire="keys" tabindex="-1">416 <a href="#" data-fire="keys" tabindex="-1">
407 <span class="lbl">turn single-key shortcuts off</span>417 <span class="lbl">turn single-key shortcuts off</span>
408 <span class="k">action</span>418 <span class="k">action</span>
M internal/app/testdata/web/blob-too-large.html +15 -5
@@ -93,6 +93,10 @@
9393 </a>
9494 </li>
9595 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97101 </a>
98102 </li>
@@ -358,31 +362,37 @@
358362 <span class="k">section</span>
359363 </a>
360364 </li>
361-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
365+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
366+<a href="/files/releases" tabindex="-1">
367+<span class="lbl">releases</span>
368+<span class="k">section</span>
369+</a>
370+</li>
371+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
362372 <a href="/files/actions" tabindex="-1">
363373 <span class="lbl">actions</span>
364374 <span class="k">section</span>
365375 </a>
366376 </li>
367-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
377+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
368378 <a href="/files/tree/feature/x" tabindex="-1">
369379 <span class="lbl">feature/x</span>
370380 <span class="k">branch</span>
371381 </a>
372382 </li>
373-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
383+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
374384 <a href="/files/tree/main" tabindex="-1">
375385 <span class="lbl">main</span>
376386 <span class="k">branch</span>
377387 </a>
378388 </li>
379-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">
389+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
380390 <a href="/files/tree/v1.0" tabindex="-1">
381391 <span class="lbl">v1.0</span>
382392 <span class="k">tag</span>
383393 </a>
384394 </li>
385-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
395+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
386396 <a href="#" data-fire="keys" tabindex="-1">
387397 <span class="lbl">turn single-key shortcuts off</span>
388398 <span class="k">action</span>
@@ -93,6 +93,10 @@
93 </a>93 </a>
94 </li>94 </li>
95 <li>95 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97 </a>101 </a>
98 </li>102 </li>
@@ -358,31 +362,37 @@
358 <span class="k">section</span>362 <span class="k">section</span>
359 </a>363 </a>
360 </li>364 </li>
361-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">365+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
366+<a href="/files/releases" tabindex="-1">
367+<span class="lbl">releases</span>
368+<span class="k">section</span>
369+</a>
370+</li>
371+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
362 <a href="/files/actions" tabindex="-1">372 <a href="/files/actions" tabindex="-1">
363 <span class="lbl">actions</span>373 <span class="lbl">actions</span>
364 <span class="k">section</span>374 <span class="k">section</span>
365 </a>375 </a>
366 </li>376 </li>
367-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">377+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
368 <a href="/files/tree/feature/x" tabindex="-1">378 <a href="/files/tree/feature/x" tabindex="-1">
369 <span class="lbl">feature/x</span>379 <span class="lbl">feature/x</span>
370 <span class="k">branch</span>380 <span class="k">branch</span>
371 </a>381 </a>
372 </li>382 </li>
373-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">383+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
374 <a href="/files/tree/main" tabindex="-1">384 <a href="/files/tree/main" tabindex="-1">
375 <span class="lbl">main</span>385 <span class="lbl">main</span>
376 <span class="k">branch</span>386 <span class="k">branch</span>
377 </a>387 </a>
378 </li>388 </li>
379-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">389+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
380 <a href="/files/tree/v1.0" tabindex="-1">390 <a href="/files/tree/v1.0" tabindex="-1">
381 <span class="lbl">v1.0</span>391 <span class="lbl">v1.0</span>
382 <span class="k">tag</span>392 <span class="k">tag</span>
383 </a>393 </a>
384 </li>394 </li>
385-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">395+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
386 <a href="#" data-fire="keys" tabindex="-1">396 <a href="#" data-fire="keys" tabindex="-1">
387 <span class="lbl">turn single-key shortcuts off</span>397 <span class="lbl">turn single-key shortcuts off</span>
388 <span class="k">action</span>398 <span class="k">action</span>
M internal/app/testdata/web/blob-trojan.html +15 -5
@@ -93,6 +93,10 @@
9393 </a>
9494 </li>
9595 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97101 </a>
98102 </li>
@@ -425,31 +429,37 @@
425429 <span class="k">section</span>
426430 </a>
427431 </li>
428-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
432+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
433+<a href="/files/releases" tabindex="-1">
434+<span class="lbl">releases</span>
435+<span class="k">section</span>
436+</a>
437+</li>
438+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
429439 <a href="/files/actions" tabindex="-1">
430440 <span class="lbl">actions</span>
431441 <span class="k">section</span>
432442 </a>
433443 </li>
434-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
444+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
435445 <a href="/files/tree/feature/x" tabindex="-1">
436446 <span class="lbl">feature/x</span>
437447 <span class="k">branch</span>
438448 </a>
439449 </li>
440-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
450+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
441451 <a href="/files/tree/main" tabindex="-1">
442452 <span class="lbl">main</span>
443453 <span class="k">branch</span>
444454 </a>
445455 </li>
446-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">
456+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
447457 <a href="/files/tree/v1.0" tabindex="-1">
448458 <span class="lbl">v1.0</span>
449459 <span class="k">tag</span>
450460 </a>
451461 </li>
452-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
462+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
453463 <a href="#" data-fire="keys" tabindex="-1">
454464 <span class="lbl">turn single-key shortcuts off</span>
455465 <span class="k">action</span>
@@ -93,6 +93,10 @@
93 </a>93 </a>
94 </li>94 </li>
95 <li>95 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97 </a>101 </a>
98 </li>102 </li>
@@ -425,31 +429,37 @@
425 <span class="k">section</span>429 <span class="k">section</span>
426 </a>430 </a>
427 </li>431 </li>
428-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">432+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
433+<a href="/files/releases" tabindex="-1">
434+<span class="lbl">releases</span>
435+<span class="k">section</span>
436+</a>
437+</li>
438+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
429 <a href="/files/actions" tabindex="-1">439 <a href="/files/actions" tabindex="-1">
430 <span class="lbl">actions</span>440 <span class="lbl">actions</span>
431 <span class="k">section</span>441 <span class="k">section</span>
432 </a>442 </a>
433 </li>443 </li>
434-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">444+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
435 <a href="/files/tree/feature/x" tabindex="-1">445 <a href="/files/tree/feature/x" tabindex="-1">
436 <span class="lbl">feature/x</span>446 <span class="lbl">feature/x</span>
437 <span class="k">branch</span>447 <span class="k">branch</span>
438 </a>448 </a>
439 </li>449 </li>
440-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">450+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
441 <a href="/files/tree/main" tabindex="-1">451 <a href="/files/tree/main" tabindex="-1">
442 <span class="lbl">main</span>452 <span class="lbl">main</span>
443 <span class="k">branch</span>453 <span class="k">branch</span>
444 </a>454 </a>
445 </li>455 </li>
446-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">456+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
447 <a href="/files/tree/v1.0" tabindex="-1">457 <a href="/files/tree/v1.0" tabindex="-1">
448 <span class="lbl">v1.0</span>458 <span class="lbl">v1.0</span>
449 <span class="k">tag</span>459 <span class="k">tag</span>
450 </a>460 </a>
451 </li>461 </li>
452-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">462+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
453 <a href="#" data-fire="keys" tabindex="-1">463 <a href="#" data-fire="keys" tabindex="-1">
454 <span class="lbl">turn single-key shortcuts off</span>464 <span class="lbl">turn single-key shortcuts off</span>
455 <span class="k">action</span>465 <span class="k">action</span>
M internal/app/testdata/web/commit-big.html +15 -5
@@ -92,6 +92,10 @@
9292 </a>
9393 </li>
9494 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
9599 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96100 </a>
97101 </li>
@@ -410,31 +414,37 @@
410414 <span class="k">section</span>
411415 </a>
412416 </li>
413-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
417+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
418+<a href="/diffs/releases" tabindex="-1">
419+<span class="lbl">releases</span>
420+<span class="k">section</span>
421+</a>
422+</li>
423+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
414424 <a href="/diffs/actions" tabindex="-1">
415425 <span class="lbl">actions</span>
416426 <span class="k">section</span>
417427 </a>
418428 </li>
419-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
429+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
420430 <a href="/diffs/tree/main" tabindex="-1">
421431 <span class="lbl">main</span>
422432 <span class="k">branch</span>
423433 </a>
424434 </li>
425-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">
435+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
426436 <a href="/diffs/tree/side" tabindex="-1">
427437 <span class="lbl">side</span>
428438 <span class="k">branch</span>
429439 </a>
430440 </li>
431-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">
441+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
432442 <a href="/diffs/tree/v1.0.0" tabindex="-1">
433443 <span class="lbl">v1.0.0</span>
434444 <span class="k">tag</span>
435445 </a>
436446 </li>
437-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
447+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
438448 <a href="#" data-fire="keys" tabindex="-1">
439449 <span class="lbl">turn single-key shortcuts off</span>
440450 <span class="k">action</span>
@@ -92,6 +92,10 @@
92 </a>92 </a>
93 </li>93 </li>
94 <li>94 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
95 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>99 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96 </a>100 </a>
97 </li>101 </li>
@@ -410,31 +414,37 @@
410 <span class="k">section</span>414 <span class="k">section</span>
411 </a>415 </a>
412 </li>416 </li>
413-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">417+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
418+<a href="/diffs/releases" tabindex="-1">
419+<span class="lbl">releases</span>
420+<span class="k">section</span>
421+</a>
422+</li>
423+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
414 <a href="/diffs/actions" tabindex="-1">424 <a href="/diffs/actions" tabindex="-1">
415 <span class="lbl">actions</span>425 <span class="lbl">actions</span>
416 <span class="k">section</span>426 <span class="k">section</span>
417 </a>427 </a>
418 </li>428 </li>
419-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">429+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
420 <a href="/diffs/tree/main" tabindex="-1">430 <a href="/diffs/tree/main" tabindex="-1">
421 <span class="lbl">main</span>431 <span class="lbl">main</span>
422 <span class="k">branch</span>432 <span class="k">branch</span>
423 </a>433 </a>
424 </li>434 </li>
425-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">435+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
426 <a href="/diffs/tree/side" tabindex="-1">436 <a href="/diffs/tree/side" tabindex="-1">
427 <span class="lbl">side</span>437 <span class="lbl">side</span>
428 <span class="k">branch</span>438 <span class="k">branch</span>
429 </a>439 </a>
430 </li>440 </li>
431-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">441+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
432 <a href="/diffs/tree/v1.0.0" tabindex="-1">442 <a href="/diffs/tree/v1.0.0" tabindex="-1">
433 <span class="lbl">v1.0.0</span>443 <span class="lbl">v1.0.0</span>
434 <span class="k">tag</span>444 <span class="k">tag</span>
435 </a>445 </a>
436 </li>446 </li>
437-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">447+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
438 <a href="#" data-fire="keys" tabindex="-1">448 <a href="#" data-fire="keys" tabindex="-1">
439 <span class="lbl">turn single-key shortcuts off</span>449 <span class="lbl">turn single-key shortcuts off</span>
440 <span class="k">action</span>450 <span class="k">action</span>
M internal/app/testdata/web/commit-binary.html +15 -5
@@ -92,6 +92,10 @@
9292 </a>
9393 </li>
9494 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
9599 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96100 </a>
97101 </li>
@@ -401,31 +405,37 @@
401405 <span class="k">section</span>
402406 </a>
403407 </li>
404-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
408+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
409+<a href="/diffs/releases" tabindex="-1">
410+<span class="lbl">releases</span>
411+<span class="k">section</span>
412+</a>
413+</li>
414+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
405415 <a href="/diffs/actions" tabindex="-1">
406416 <span class="lbl">actions</span>
407417 <span class="k">section</span>
408418 </a>
409419 </li>
410-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
420+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
411421 <a href="/diffs/tree/main" tabindex="-1">
412422 <span class="lbl">main</span>
413423 <span class="k">branch</span>
414424 </a>
415425 </li>
416-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">
426+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
417427 <a href="/diffs/tree/side" tabindex="-1">
418428 <span class="lbl">side</span>
419429 <span class="k">branch</span>
420430 </a>
421431 </li>
422-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">
432+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
423433 <a href="/diffs/tree/v1.0.0" tabindex="-1">
424434 <span class="lbl">v1.0.0</span>
425435 <span class="k">tag</span>
426436 </a>
427437 </li>
428-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
438+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
429439 <a href="#" data-fire="keys" tabindex="-1">
430440 <span class="lbl">turn single-key shortcuts off</span>
431441 <span class="k">action</span>
@@ -92,6 +92,10 @@
92 </a>92 </a>
93 </li>93 </li>
94 <li>94 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
95 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>99 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96 </a>100 </a>
97 </li>101 </li>
@@ -401,31 +405,37 @@
401 <span class="k">section</span>405 <span class="k">section</span>
402 </a>406 </a>
403 </li>407 </li>
404-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">408+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
409+<a href="/diffs/releases" tabindex="-1">
410+<span class="lbl">releases</span>
411+<span class="k">section</span>
412+</a>
413+</li>
414+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
405 <a href="/diffs/actions" tabindex="-1">415 <a href="/diffs/actions" tabindex="-1">
406 <span class="lbl">actions</span>416 <span class="lbl">actions</span>
407 <span class="k">section</span>417 <span class="k">section</span>
408 </a>418 </a>
409 </li>419 </li>
410-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">420+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
411 <a href="/diffs/tree/main" tabindex="-1">421 <a href="/diffs/tree/main" tabindex="-1">
412 <span class="lbl">main</span>422 <span class="lbl">main</span>
413 <span class="k">branch</span>423 <span class="k">branch</span>
414 </a>424 </a>
415 </li>425 </li>
416-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">426+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
417 <a href="/diffs/tree/side" tabindex="-1">427 <a href="/diffs/tree/side" tabindex="-1">
418 <span class="lbl">side</span>428 <span class="lbl">side</span>
419 <span class="k">branch</span>429 <span class="k">branch</span>
420 </a>430 </a>
421 </li>431 </li>
422-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">432+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
423 <a href="/diffs/tree/v1.0.0" tabindex="-1">433 <a href="/diffs/tree/v1.0.0" tabindex="-1">
424 <span class="lbl">v1.0.0</span>434 <span class="lbl">v1.0.0</span>
425 <span class="k">tag</span>435 <span class="k">tag</span>
426 </a>436 </a>
427 </li>437 </li>
428-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">438+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
429 <a href="#" data-fire="keys" tabindex="-1">439 <a href="#" data-fire="keys" tabindex="-1">
430 <span class="lbl">turn single-key shortcuts off</span>440 <span class="lbl">turn single-key shortcuts off</span>
431 <span class="k">action</span>441 <span class="k">action</span>
M internal/app/testdata/web/commit-merge.html +15 -5
@@ -92,6 +92,10 @@
9292 </a>
9393 </li>
9494 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
9599 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96100 </a>
97101 </li>
@@ -443,31 +447,37 @@
443447 <span class="k">section</span>
444448 </a>
445449 </li>
446-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
450+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
451+<a href="/diffs/releases" tabindex="-1">
452+<span class="lbl">releases</span>
453+<span class="k">section</span>
454+</a>
455+</li>
456+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
447457 <a href="/diffs/actions" tabindex="-1">
448458 <span class="lbl">actions</span>
449459 <span class="k">section</span>
450460 </a>
451461 </li>
452-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
462+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
453463 <a href="/diffs/tree/main" tabindex="-1">
454464 <span class="lbl">main</span>
455465 <span class="k">branch</span>
456466 </a>
457467 </li>
458-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">
468+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
459469 <a href="/diffs/tree/side" tabindex="-1">
460470 <span class="lbl">side</span>
461471 <span class="k">branch</span>
462472 </a>
463473 </li>
464-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">
474+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
465475 <a href="/diffs/tree/v1.0.0" tabindex="-1">
466476 <span class="lbl">v1.0.0</span>
467477 <span class="k">tag</span>
468478 </a>
469479 </li>
470-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
480+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
471481 <a href="#" data-fire="keys" tabindex="-1">
472482 <span class="lbl">turn single-key shortcuts off</span>
473483 <span class="k">action</span>
@@ -92,6 +92,10 @@
92 </a>92 </a>
93 </li>93 </li>
94 <li>94 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
95 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>99 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96 </a>100 </a>
97 </li>101 </li>
@@ -443,31 +447,37 @@
443 <span class="k">section</span>447 <span class="k">section</span>
444 </a>448 </a>
445 </li>449 </li>
446-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">450+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
451+<a href="/diffs/releases" tabindex="-1">
452+<span class="lbl">releases</span>
453+<span class="k">section</span>
454+</a>
455+</li>
456+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
447 <a href="/diffs/actions" tabindex="-1">457 <a href="/diffs/actions" tabindex="-1">
448 <span class="lbl">actions</span>458 <span class="lbl">actions</span>
449 <span class="k">section</span>459 <span class="k">section</span>
450 </a>460 </a>
451 </li>461 </li>
452-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">462+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
453 <a href="/diffs/tree/main" tabindex="-1">463 <a href="/diffs/tree/main" tabindex="-1">
454 <span class="lbl">main</span>464 <span class="lbl">main</span>
455 <span class="k">branch</span>465 <span class="k">branch</span>
456 </a>466 </a>
457 </li>467 </li>
458-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">468+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
459 <a href="/diffs/tree/side" tabindex="-1">469 <a href="/diffs/tree/side" tabindex="-1">
460 <span class="lbl">side</span>470 <span class="lbl">side</span>
461 <span class="k">branch</span>471 <span class="k">branch</span>
462 </a>472 </a>
463 </li>473 </li>
464-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">474+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
465 <a href="/diffs/tree/v1.0.0" tabindex="-1">475 <a href="/diffs/tree/v1.0.0" tabindex="-1">
466 <span class="lbl">v1.0.0</span>476 <span class="lbl">v1.0.0</span>
467 <span class="k">tag</span>477 <span class="k">tag</span>
468 </a>478 </a>
469 </li>479 </li>
470-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">480+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
471 <a href="#" data-fire="keys" tabindex="-1">481 <a href="#" data-fire="keys" tabindex="-1">
472 <span class="lbl">turn single-key shortcuts off</span>482 <span class="lbl">turn single-key shortcuts off</span>
473 <span class="k">action</span>483 <span class="k">action</span>
M internal/app/testdata/web/commit-modify-split.html +15 -5
@@ -92,6 +92,10 @@
9292 </a>
9393 </li>
9494 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
9599 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96100 </a>
97101 </li>
@@ -566,31 +570,37 @@ And &lt;b&gt;html&lt;/b&gt; &amp; &#34;quotes&#34;.</pre>
566570 <span class="k">section</span>
567571 </a>
568572 </li>
569-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
573+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
574+<a href="/diffs/releases" tabindex="-1">
575+<span class="lbl">releases</span>
576+<span class="k">section</span>
577+</a>
578+</li>
579+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
570580 <a href="/diffs/actions" tabindex="-1">
571581 <span class="lbl">actions</span>
572582 <span class="k">section</span>
573583 </a>
574584 </li>
575-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
585+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
576586 <a href="/diffs/tree/main" tabindex="-1">
577587 <span class="lbl">main</span>
578588 <span class="k">branch</span>
579589 </a>
580590 </li>
581-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">
591+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
582592 <a href="/diffs/tree/side" tabindex="-1">
583593 <span class="lbl">side</span>
584594 <span class="k">branch</span>
585595 </a>
586596 </li>
587-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">
597+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
588598 <a href="/diffs/tree/v1.0.0" tabindex="-1">
589599 <span class="lbl">v1.0.0</span>
590600 <span class="k">tag</span>
591601 </a>
592602 </li>
593-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
603+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
594604 <a href="#" data-fire="keys" tabindex="-1">
595605 <span class="lbl">turn single-key shortcuts off</span>
596606 <span class="k">action</span>
@@ -92,6 +92,10 @@
92 </a>92 </a>
93 </li>93 </li>
94 <li>94 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
95 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>99 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96 </a>100 </a>
97 </li>101 </li>
@@ -566,31 +570,37 @@ And &lt;b&gt;html&lt;/b&gt; &amp; &#34;quotes&#34;.</pre>
566 <span class="k">section</span>570 <span class="k">section</span>
567 </a>571 </a>
568 </li>572 </li>
569-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">573+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
574+<a href="/diffs/releases" tabindex="-1">
575+<span class="lbl">releases</span>
576+<span class="k">section</span>
577+</a>
578+</li>
579+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
570 <a href="/diffs/actions" tabindex="-1">580 <a href="/diffs/actions" tabindex="-1">
571 <span class="lbl">actions</span>581 <span class="lbl">actions</span>
572 <span class="k">section</span>582 <span class="k">section</span>
573 </a>583 </a>
574 </li>584 </li>
575-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">585+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
576 <a href="/diffs/tree/main" tabindex="-1">586 <a href="/diffs/tree/main" tabindex="-1">
577 <span class="lbl">main</span>587 <span class="lbl">main</span>
578 <span class="k">branch</span>588 <span class="k">branch</span>
579 </a>589 </a>
580 </li>590 </li>
581-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">591+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
582 <a href="/diffs/tree/side" tabindex="-1">592 <a href="/diffs/tree/side" tabindex="-1">
583 <span class="lbl">side</span>593 <span class="lbl">side</span>
584 <span class="k">branch</span>594 <span class="k">branch</span>
585 </a>595 </a>
586 </li>596 </li>
587-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">597+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
588 <a href="/diffs/tree/v1.0.0" tabindex="-1">598 <a href="/diffs/tree/v1.0.0" tabindex="-1">
589 <span class="lbl">v1.0.0</span>599 <span class="lbl">v1.0.0</span>
590 <span class="k">tag</span>600 <span class="k">tag</span>
591 </a>601 </a>
592 </li>602 </li>
593-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">603+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
594 <a href="#" data-fire="keys" tabindex="-1">604 <a href="#" data-fire="keys" tabindex="-1">
595 <span class="lbl">turn single-key shortcuts off</span>605 <span class="lbl">turn single-key shortcuts off</span>
596 <span class="k">action</span>606 <span class="k">action</span>
M internal/app/testdata/web/commit-modify.html +15 -5
@@ -92,6 +92,10 @@
9292 </a>
9393 </li>
9494 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
9599 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96100 </a>
97101 </li>
@@ -566,31 +570,37 @@ And &lt;b&gt;html&lt;/b&gt; &amp; &#34;quotes&#34;.</pre>
566570 <span class="k">section</span>
567571 </a>
568572 </li>
569-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
573+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
574+<a href="/diffs/releases" tabindex="-1">
575+<span class="lbl">releases</span>
576+<span class="k">section</span>
577+</a>
578+</li>
579+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
570580 <a href="/diffs/actions" tabindex="-1">
571581 <span class="lbl">actions</span>
572582 <span class="k">section</span>
573583 </a>
574584 </li>
575-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
585+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
576586 <a href="/diffs/tree/main" tabindex="-1">
577587 <span class="lbl">main</span>
578588 <span class="k">branch</span>
579589 </a>
580590 </li>
581-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">
591+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
582592 <a href="/diffs/tree/side" tabindex="-1">
583593 <span class="lbl">side</span>
584594 <span class="k">branch</span>
585595 </a>
586596 </li>
587-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">
597+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
588598 <a href="/diffs/tree/v1.0.0" tabindex="-1">
589599 <span class="lbl">v1.0.0</span>
590600 <span class="k">tag</span>
591601 </a>
592602 </li>
593-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
603+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
594604 <a href="#" data-fire="keys" tabindex="-1">
595605 <span class="lbl">turn single-key shortcuts off</span>
596606 <span class="k">action</span>
@@ -92,6 +92,10 @@
92 </a>92 </a>
93 </li>93 </li>
94 <li>94 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
95 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>99 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96 </a>100 </a>
97 </li>101 </li>
@@ -566,31 +570,37 @@ And &lt;b&gt;html&lt;/b&gt; &amp; &#34;quotes&#34;.</pre>
566 <span class="k">section</span>570 <span class="k">section</span>
567 </a>571 </a>
568 </li>572 </li>
569-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">573+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
574+<a href="/diffs/releases" tabindex="-1">
575+<span class="lbl">releases</span>
576+<span class="k">section</span>
577+</a>
578+</li>
579+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
570 <a href="/diffs/actions" tabindex="-1">580 <a href="/diffs/actions" tabindex="-1">
571 <span class="lbl">actions</span>581 <span class="lbl">actions</span>
572 <span class="k">section</span>582 <span class="k">section</span>
573 </a>583 </a>
574 </li>584 </li>
575-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">585+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
576 <a href="/diffs/tree/main" tabindex="-1">586 <a href="/diffs/tree/main" tabindex="-1">
577 <span class="lbl">main</span>587 <span class="lbl">main</span>
578 <span class="k">branch</span>588 <span class="k">branch</span>
579 </a>589 </a>
580 </li>590 </li>
581-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">591+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
582 <a href="/diffs/tree/side" tabindex="-1">592 <a href="/diffs/tree/side" tabindex="-1">
583 <span class="lbl">side</span>593 <span class="lbl">side</span>
584 <span class="k">branch</span>594 <span class="k">branch</span>
585 </a>595 </a>
586 </li>596 </li>
587-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">597+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
588 <a href="/diffs/tree/v1.0.0" tabindex="-1">598 <a href="/diffs/tree/v1.0.0" tabindex="-1">
589 <span class="lbl">v1.0.0</span>599 <span class="lbl">v1.0.0</span>
590 <span class="k">tag</span>600 <span class="k">tag</span>
591 </a>601 </a>
592 </li>602 </li>
593-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">603+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
594 <a href="#" data-fire="keys" tabindex="-1">604 <a href="#" data-fire="keys" tabindex="-1">
595 <span class="lbl">turn single-key shortcuts off</span>605 <span class="lbl">turn single-key shortcuts off</span>
596 <span class="k">action</span>606 <span class="k">action</span>
M internal/app/testdata/web/commit-rename.html +15 -5
@@ -92,6 +92,10 @@
9292 </a>
9393 </li>
9494 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
9599 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96100 </a>
97101 </li>
@@ -470,31 +474,37 @@
470474 <span class="k">section</span>
471475 </a>
472476 </li>
473-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
477+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
478+<a href="/diffs/releases" tabindex="-1">
479+<span class="lbl">releases</span>
480+<span class="k">section</span>
481+</a>
482+</li>
483+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
474484 <a href="/diffs/actions" tabindex="-1">
475485 <span class="lbl">actions</span>
476486 <span class="k">section</span>
477487 </a>
478488 </li>
479-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
489+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
480490 <a href="/diffs/tree/main" tabindex="-1">
481491 <span class="lbl">main</span>
482492 <span class="k">branch</span>
483493 </a>
484494 </li>
485-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">
495+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
486496 <a href="/diffs/tree/side" tabindex="-1">
487497 <span class="lbl">side</span>
488498 <span class="k">branch</span>
489499 </a>
490500 </li>
491-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">
501+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
492502 <a href="/diffs/tree/v1.0.0" tabindex="-1">
493503 <span class="lbl">v1.0.0</span>
494504 <span class="k">tag</span>
495505 </a>
496506 </li>
497-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
507+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
498508 <a href="#" data-fire="keys" tabindex="-1">
499509 <span class="lbl">turn single-key shortcuts off</span>
500510 <span class="k">action</span>
@@ -92,6 +92,10 @@
92 </a>92 </a>
93 </li>93 </li>
94 <li>94 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
95 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>99 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96 </a>100 </a>
97 </li>101 </li>
@@ -470,31 +474,37 @@
470 <span class="k">section</span>474 <span class="k">section</span>
471 </a>475 </a>
472 </li>476 </li>
473-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">477+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
478+<a href="/diffs/releases" tabindex="-1">
479+<span class="lbl">releases</span>
480+<span class="k">section</span>
481+</a>
482+</li>
483+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
474 <a href="/diffs/actions" tabindex="-1">484 <a href="/diffs/actions" tabindex="-1">
475 <span class="lbl">actions</span>485 <span class="lbl">actions</span>
476 <span class="k">section</span>486 <span class="k">section</span>
477 </a>487 </a>
478 </li>488 </li>
479-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">489+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
480 <a href="/diffs/tree/main" tabindex="-1">490 <a href="/diffs/tree/main" tabindex="-1">
481 <span class="lbl">main</span>491 <span class="lbl">main</span>
482 <span class="k">branch</span>492 <span class="k">branch</span>
483 </a>493 </a>
484 </li>494 </li>
485-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">495+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
486 <a href="/diffs/tree/side" tabindex="-1">496 <a href="/diffs/tree/side" tabindex="-1">
487 <span class="lbl">side</span>497 <span class="lbl">side</span>
488 <span class="k">branch</span>498 <span class="k">branch</span>
489 </a>499 </a>
490 </li>500 </li>
491-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">501+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
492 <a href="/diffs/tree/v1.0.0" tabindex="-1">502 <a href="/diffs/tree/v1.0.0" tabindex="-1">
493 <span class="lbl">v1.0.0</span>503 <span class="lbl">v1.0.0</span>
494 <span class="k">tag</span>504 <span class="k">tag</span>
495 </a>505 </a>
496 </li>506 </li>
497-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">507+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
498 <a href="#" data-fire="keys" tabindex="-1">508 <a href="#" data-fire="keys" tabindex="-1">
499 <span class="lbl">turn single-key shortcuts off</span>509 <span class="lbl">turn single-key shortcuts off</span>
500 <span class="k">action</span>510 <span class="k">action</span>
M internal/app/testdata/web/commit-root.html +15 -5
@@ -92,6 +92,10 @@
9292 </a>
9393 </li>
9494 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
9599 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96100 </a>
97101 </li>
@@ -789,31 +793,37 @@
789793 <span class="k">section</span>
790794 </a>
791795 </li>
792-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
796+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
797+<a href="/diffs/releases" tabindex="-1">
798+<span class="lbl">releases</span>
799+<span class="k">section</span>
800+</a>
801+</li>
802+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
793803 <a href="/diffs/actions" tabindex="-1">
794804 <span class="lbl">actions</span>
795805 <span class="k">section</span>
796806 </a>
797807 </li>
798-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
808+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
799809 <a href="/diffs/tree/main" tabindex="-1">
800810 <span class="lbl">main</span>
801811 <span class="k">branch</span>
802812 </a>
803813 </li>
804-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">
814+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
805815 <a href="/diffs/tree/side" tabindex="-1">
806816 <span class="lbl">side</span>
807817 <span class="k">branch</span>
808818 </a>
809819 </li>
810-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">
820+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
811821 <a href="/diffs/tree/v1.0.0" tabindex="-1">
812822 <span class="lbl">v1.0.0</span>
813823 <span class="k">tag</span>
814824 </a>
815825 </li>
816-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
826+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
817827 <a href="#" data-fire="keys" tabindex="-1">
818828 <span class="lbl">turn single-key shortcuts off</span>
819829 <span class="k">action</span>
@@ -92,6 +92,10 @@
92 </a>92 </a>
93 </li>93 </li>
94 <li>94 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
95 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>99 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96 </a>100 </a>
97 </li>101 </li>
@@ -789,31 +793,37 @@
789 <span class="k">section</span>793 <span class="k">section</span>
790 </a>794 </a>
791 </li>795 </li>
792-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">796+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
797+<a href="/diffs/releases" tabindex="-1">
798+<span class="lbl">releases</span>
799+<span class="k">section</span>
800+</a>
801+</li>
802+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
793 <a href="/diffs/actions" tabindex="-1">803 <a href="/diffs/actions" tabindex="-1">
794 <span class="lbl">actions</span>804 <span class="lbl">actions</span>
795 <span class="k">section</span>805 <span class="k">section</span>
796 </a>806 </a>
797 </li>807 </li>
798-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">808+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
799 <a href="/diffs/tree/main" tabindex="-1">809 <a href="/diffs/tree/main" tabindex="-1">
800 <span class="lbl">main</span>810 <span class="lbl">main</span>
801 <span class="k">branch</span>811 <span class="k">branch</span>
802 </a>812 </a>
803 </li>813 </li>
804-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">814+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
805 <a href="/diffs/tree/side" tabindex="-1">815 <a href="/diffs/tree/side" tabindex="-1">
806 <span class="lbl">side</span>816 <span class="lbl">side</span>
807 <span class="k">branch</span>817 <span class="k">branch</span>
808 </a>818 </a>
809 </li>819 </li>
810-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">820+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
811 <a href="/diffs/tree/v1.0.0" tabindex="-1">821 <a href="/diffs/tree/v1.0.0" tabindex="-1">
812 <span class="lbl">v1.0.0</span>822 <span class="lbl">v1.0.0</span>
813 <span class="k">tag</span>823 <span class="k">tag</span>
814 </a>824 </a>
815 </li>825 </li>
816-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">826+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
817 <a href="#" data-fire="keys" tabindex="-1">827 <a href="#" data-fire="keys" tabindex="-1">
818 <span class="lbl">turn single-key shortcuts off</span>828 <span class="lbl">turn single-key shortcuts off</span>
819 <span class="k">action</span>829 <span class="k">action</span>
M internal/app/testdata/web/commit-trojan.html +15 -5
@@ -92,6 +92,10 @@
9292 </a>
9393 </li>
9494 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
9599 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96100 </a>
97101 </li>
@@ -618,31 +622,37 @@
618622 <span class="k">section</span>
619623 </a>
620624 </li>
621-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
625+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
626+<a href="/diffs/releases" tabindex="-1">
627+<span class="lbl">releases</span>
628+<span class="k">section</span>
629+</a>
630+</li>
631+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
622632 <a href="/diffs/actions" tabindex="-1">
623633 <span class="lbl">actions</span>
624634 <span class="k">section</span>
625635 </a>
626636 </li>
627-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
637+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
628638 <a href="/diffs/tree/main" tabindex="-1">
629639 <span class="lbl">main</span>
630640 <span class="k">branch</span>
631641 </a>
632642 </li>
633-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">
643+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
634644 <a href="/diffs/tree/side" tabindex="-1">
635645 <span class="lbl">side</span>
636646 <span class="k">branch</span>
637647 </a>
638648 </li>
639-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">
649+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
640650 <a href="/diffs/tree/v1.0.0" tabindex="-1">
641651 <span class="lbl">v1.0.0</span>
642652 <span class="k">tag</span>
643653 </a>
644654 </li>
645-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
655+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
646656 <a href="#" data-fire="keys" tabindex="-1">
647657 <span class="lbl">turn single-key shortcuts off</span>
648658 <span class="k">action</span>
@@ -92,6 +92,10 @@
92 </a>92 </a>
93 </li>93 </li>
94 <li>94 <li>
95+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
96+</a>
97+</li>
98+<li>
95 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>99 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
96 </a>100 </a>
97 </li>101 </li>
@@ -618,31 +622,37 @@
618 <span class="k">section</span>622 <span class="k">section</span>
619 </a>623 </a>
620 </li>624 </li>
621-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">625+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
626+<a href="/diffs/releases" tabindex="-1">
627+<span class="lbl">releases</span>
628+<span class="k">section</span>
629+</a>
630+</li>
631+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
622 <a href="/diffs/actions" tabindex="-1">632 <a href="/diffs/actions" tabindex="-1">
623 <span class="lbl">actions</span>633 <span class="lbl">actions</span>
624 <span class="k">section</span>634 <span class="k">section</span>
625 </a>635 </a>
626 </li>636 </li>
627-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">637+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
628 <a href="/diffs/tree/main" tabindex="-1">638 <a href="/diffs/tree/main" tabindex="-1">
629 <span class="lbl">main</span>639 <span class="lbl">main</span>
630 <span class="k">branch</span>640 <span class="k">branch</span>
631 </a>641 </a>
632 </li>642 </li>
633-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">643+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
634 <a href="/diffs/tree/side" tabindex="-1">644 <a href="/diffs/tree/side" tabindex="-1">
635 <span class="lbl">side</span>645 <span class="lbl">side</span>
636 <span class="k">branch</span>646 <span class="k">branch</span>
637 </a>647 </a>
638 </li>648 </li>
639-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">649+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
640 <a href="/diffs/tree/v1.0.0" tabindex="-1">650 <a href="/diffs/tree/v1.0.0" tabindex="-1">
641 <span class="lbl">v1.0.0</span>651 <span class="lbl">v1.0.0</span>
642 <span class="k">tag</span>652 <span class="k">tag</span>
643 </a>653 </a>
644 </li>654 </li>
645-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">655+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
646 <a href="#" data-fire="keys" tabindex="-1">656 <a href="#" data-fire="keys" tabindex="-1">
647 <span class="lbl">turn single-key shortcuts off</span>657 <span class="lbl">turn single-key shortcuts off</span>
648 <span class="k">action</span>658 <span class="k">action</span>
M internal/app/testdata/web/commits-page2.html +14 -4
@@ -90,6 +90,10 @@
9090 </a>
9191 </li>
9292 <li>
93+<a href="/long/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
94+</a>
95+</li>
96+<li>
9397 <a href="/long/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
9498 </a>
9599 </li>
@@ -377,25 +381,31 @@
377381 <span class="k">section</span>
378382 </a>
379383 </li>
380-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
384+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
385+<a href="/long/releases" tabindex="-1">
386+<span class="lbl">releases</span>
387+<span class="k">section</span>
388+</a>
389+</li>
390+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
381391 <a href="/long/actions" tabindex="-1">
382392 <span class="lbl">actions</span>
383393 <span class="k">section</span>
384394 </a>
385395 </li>
386-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
396+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
387397 <a href="/long/tree/main" tabindex="-1">
388398 <span class="lbl">main</span>
389399 <span class="k">branch</span>
390400 </a>
391401 </li>
392-<li id="cmd-o8" role="option" aria-selected="false" data-k="repo diffs">
402+<li id="cmd-o9" role="option" aria-selected="false" data-k="repo diffs">
393403 <a href="/diffs" tabindex="-1">
394404 <span class="lbl">diffs</span>
395405 <span class="k">repo</span>
396406 </a>
397407 </li>
398-<li id="cmd-o9" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
408+<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
399409 <a href="#" data-fire="keys" tabindex="-1">
400410 <span class="lbl">turn single-key shortcuts off</span>
401411 <span class="k">action</span>
@@ -90,6 +90,10 @@
90 </a>90 </a>
91 </li>91 </li>
92 <li>92 <li>
93+<a href="/long/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
94+</a>
95+</li>
96+<li>
93 <a href="/long/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>97 <a href="/long/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
94 </a>98 </a>
95 </li>99 </li>
@@ -377,25 +381,31 @@
377 <span class="k">section</span>381 <span class="k">section</span>
378 </a>382 </a>
379 </li>383 </li>
380-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">384+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
385+<a href="/long/releases" tabindex="-1">
386+<span class="lbl">releases</span>
387+<span class="k">section</span>
388+</a>
389+</li>
390+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
381 <a href="/long/actions" tabindex="-1">391 <a href="/long/actions" tabindex="-1">
382 <span class="lbl">actions</span>392 <span class="lbl">actions</span>
383 <span class="k">section</span>393 <span class="k">section</span>
384 </a>394 </a>
385 </li>395 </li>
386-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">396+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
387 <a href="/long/tree/main" tabindex="-1">397 <a href="/long/tree/main" tabindex="-1">
388 <span class="lbl">main</span>398 <span class="lbl">main</span>
389 <span class="k">branch</span>399 <span class="k">branch</span>
390 </a>400 </a>
391 </li>401 </li>
392-<li id="cmd-o8" role="option" aria-selected="false" data-k="repo diffs">402+<li id="cmd-o9" role="option" aria-selected="false" data-k="repo diffs">
393 <a href="/diffs" tabindex="-1">403 <a href="/diffs" tabindex="-1">
394 <span class="lbl">diffs</span>404 <span class="lbl">diffs</span>
395 <span class="k">repo</span>405 <span class="k">repo</span>
396 </a>406 </a>
397 </li>407 </li>
398-<li id="cmd-o9" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">408+<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
399 <a href="#" data-fire="keys" tabindex="-1">409 <a href="#" data-fire="keys" tabindex="-1">
400 <span class="lbl">turn single-key shortcuts off</span>410 <span class="lbl">turn single-key shortcuts off</span>
401 <span class="k">action</span>411 <span class="k">action</span>
M internal/app/testdata/web/commits-path.html +14 -4
@@ -93,6 +93,10 @@
9393 </a>
9494 </li>
9595 <li>
96+<a href="/long/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96100 <a href="/long/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97101 </a>
98102 </li>
@@ -392,25 +396,31 @@
392396 <span class="k">section</span>
393397 </a>
394398 </li>
395-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
399+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
400+<a href="/long/releases" tabindex="-1">
401+<span class="lbl">releases</span>
402+<span class="k">section</span>
403+</a>
404+</li>
405+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
396406 <a href="/long/actions" tabindex="-1">
397407 <span class="lbl">actions</span>
398408 <span class="k">section</span>
399409 </a>
400410 </li>
401-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
411+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
402412 <a href="/long/tree/main" tabindex="-1">
403413 <span class="lbl">main</span>
404414 <span class="k">branch</span>
405415 </a>
406416 </li>
407-<li id="cmd-o8" role="option" aria-selected="false" data-k="repo diffs">
417+<li id="cmd-o9" role="option" aria-selected="false" data-k="repo diffs">
408418 <a href="/diffs" tabindex="-1">
409419 <span class="lbl">diffs</span>
410420 <span class="k">repo</span>
411421 </a>
412422 </li>
413-<li id="cmd-o9" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
423+<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
414424 <a href="#" data-fire="keys" tabindex="-1">
415425 <span class="lbl">turn single-key shortcuts off</span>
416426 <span class="k">action</span>
@@ -93,6 +93,10 @@
93 </a>93 </a>
94 </li>94 </li>
95 <li>95 <li>
96+<a href="/long/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96 <a href="/long/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>100 <a href="/long/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97 </a>101 </a>
98 </li>102 </li>
@@ -392,25 +396,31 @@
392 <span class="k">section</span>396 <span class="k">section</span>
393 </a>397 </a>
394 </li>398 </li>
395-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">399+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
400+<a href="/long/releases" tabindex="-1">
401+<span class="lbl">releases</span>
402+<span class="k">section</span>
403+</a>
404+</li>
405+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
396 <a href="/long/actions" tabindex="-1">406 <a href="/long/actions" tabindex="-1">
397 <span class="lbl">actions</span>407 <span class="lbl">actions</span>
398 <span class="k">section</span>408 <span class="k">section</span>
399 </a>409 </a>
400 </li>410 </li>
401-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">411+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
402 <a href="/long/tree/main" tabindex="-1">412 <a href="/long/tree/main" tabindex="-1">
403 <span class="lbl">main</span>413 <span class="lbl">main</span>
404 <span class="k">branch</span>414 <span class="k">branch</span>
405 </a>415 </a>
406 </li>416 </li>
407-<li id="cmd-o8" role="option" aria-selected="false" data-k="repo diffs">417+<li id="cmd-o9" role="option" aria-selected="false" data-k="repo diffs">
408 <a href="/diffs" tabindex="-1">418 <a href="/diffs" tabindex="-1">
409 <span class="lbl">diffs</span>419 <span class="lbl">diffs</span>
410 <span class="k">repo</span>420 <span class="k">repo</span>
411 </a>421 </a>
412 </li>422 </li>
413-<li id="cmd-o9" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">423+<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
414 <a href="#" data-fire="keys" tabindex="-1">424 <a href="#" data-fire="keys" tabindex="-1">
415 <span class="lbl">turn single-key shortcuts off</span>425 <span class="lbl">turn single-key shortcuts off</span>
416 <span class="k">action</span>426 <span class="k">action</span>
M internal/app/testdata/web/commits-root.html +14 -4
@@ -90,6 +90,10 @@
9090 </a>
9191 </li>
9292 <li>
93+<a href="/long/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
94+</a>
95+</li>
96+<li>
9397 <a href="/long/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
9498 </a>
9599 </li>
@@ -1182,25 +1186,31 @@
11821186 <span class="k">section</span>
11831187 </a>
11841188 </li>
1185-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
1189+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
1190+<a href="/long/releases" tabindex="-1">
1191+<span class="lbl">releases</span>
1192+<span class="k">section</span>
1193+</a>
1194+</li>
1195+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
11861196 <a href="/long/actions" tabindex="-1">
11871197 <span class="lbl">actions</span>
11881198 <span class="k">section</span>
11891199 </a>
11901200 </li>
1191-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
1201+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
11921202 <a href="/long/tree/main" tabindex="-1">
11931203 <span class="lbl">main</span>
11941204 <span class="k">branch</span>
11951205 </a>
11961206 </li>
1197-<li id="cmd-o8" role="option" aria-selected="false" data-k="repo diffs">
1207+<li id="cmd-o9" role="option" aria-selected="false" data-k="repo diffs">
11981208 <a href="/diffs" tabindex="-1">
11991209 <span class="lbl">diffs</span>
12001210 <span class="k">repo</span>
12011211 </a>
12021212 </li>
1203-<li id="cmd-o9" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
1213+<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
12041214 <a href="#" data-fire="keys" tabindex="-1">
12051215 <span class="lbl">turn single-key shortcuts off</span>
12061216 <span class="k">action</span>
@@ -90,6 +90,10 @@
90 </a>90 </a>
91 </li>91 </li>
92 <li>92 <li>
93+<a href="/long/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
94+</a>
95+</li>
96+<li>
93 <a href="/long/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>97 <a href="/long/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
94 </a>98 </a>
95 </li>99 </li>
@@ -1182,25 +1186,31 @@
1182 <span class="k">section</span>1186 <span class="k">section</span>
1183 </a>1187 </a>
1184 </li>1188 </li>
1185-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">1189+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
1190+<a href="/long/releases" tabindex="-1">
1191+<span class="lbl">releases</span>
1192+<span class="k">section</span>
1193+</a>
1194+</li>
1195+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
1186 <a href="/long/actions" tabindex="-1">1196 <a href="/long/actions" tabindex="-1">
1187 <span class="lbl">actions</span>1197 <span class="lbl">actions</span>
1188 <span class="k">section</span>1198 <span class="k">section</span>
1189 </a>1199 </a>
1190 </li>1200 </li>
1191-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">1201+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
1192 <a href="/long/tree/main" tabindex="-1">1202 <a href="/long/tree/main" tabindex="-1">
1193 <span class="lbl">main</span>1203 <span class="lbl">main</span>
1194 <span class="k">branch</span>1204 <span class="k">branch</span>
1195 </a>1205 </a>
1196 </li>1206 </li>
1197-<li id="cmd-o8" role="option" aria-selected="false" data-k="repo diffs">1207+<li id="cmd-o9" role="option" aria-selected="false" data-k="repo diffs">
1198 <a href="/diffs" tabindex="-1">1208 <a href="/diffs" tabindex="-1">
1199 <span class="lbl">diffs</span>1209 <span class="lbl">diffs</span>
1200 <span class="k">repo</span>1210 <span class="k">repo</span>
1201 </a>1211 </a>
1202 </li>1212 </li>
1203-<li id="cmd-o9" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">1213+<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
1204 <a href="#" data-fire="keys" tabindex="-1">1214 <a href="#" data-fire="keys" tabindex="-1">
1205 <span class="lbl">turn single-key shortcuts off</span>1215 <span class="lbl">turn single-key shortcuts off</span>
1206 <span class="k">action</span>1216 <span class="k">action</span>
M internal/app/testdata/web/commits-small.html +16 -6
@@ -90,6 +90,10 @@
9090 </a>
9191 </li>
9292 <li>
93+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
94+</a>
95+</li>
96+<li>
9397 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
9498 </a>
9599 </li>
@@ -535,37 +539,43 @@
535539 <span class="k">section</span>
536540 </a>
537541 </li>
538-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
542+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
543+<a href="/diffs/releases" tabindex="-1">
544+<span class="lbl">releases</span>
545+<span class="k">section</span>
546+</a>
547+</li>
548+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
539549 <a href="/diffs/actions" tabindex="-1">
540550 <span class="lbl">actions</span>
541551 <span class="k">section</span>
542552 </a>
543553 </li>
544-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">
554+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
545555 <a href="/diffs/tree/main" tabindex="-1">
546556 <span class="lbl">main</span>
547557 <span class="k">branch</span>
548558 </a>
549559 </li>
550-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">
560+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
551561 <a href="/diffs/tree/side" tabindex="-1">
552562 <span class="lbl">side</span>
553563 <span class="k">branch</span>
554564 </a>
555565 </li>
556-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">
566+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
557567 <a href="/diffs/tree/v1.0.0" tabindex="-1">
558568 <span class="lbl">v1.0.0</span>
559569 <span class="k">tag</span>
560570 </a>
561571 </li>
562-<li id="cmd-o10" role="option" aria-selected="false" data-k="repo long">
572+<li id="cmd-o11" role="option" aria-selected="false" data-k="repo long">
563573 <a href="/long" tabindex="-1">
564574 <span class="lbl">long</span>
565575 <span class="k">repo</span>
566576 </a>
567577 </li>
568-<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
578+<li id="cmd-o12" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
569579 <a href="#" data-fire="keys" tabindex="-1">
570580 <span class="lbl">turn single-key shortcuts off</span>
571581 <span class="k">action</span>
@@ -90,6 +90,10 @@
90 </a>90 </a>
91 </li>91 </li>
92 <li>92 <li>
93+<a href="/diffs/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
94+</a>
95+</li>
96+<li>
93 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>97 <a href="/diffs/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
94 </a>98 </a>
95 </li>99 </li>
@@ -535,37 +539,43 @@
535 <span class="k">section</span>539 <span class="k">section</span>
536 </a>540 </a>
537 </li>541 </li>
538-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">542+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
543+<a href="/diffs/releases" tabindex="-1">
544+<span class="lbl">releases</span>
545+<span class="k">section</span>
546+</a>
547+</li>
548+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
539 <a href="/diffs/actions" tabindex="-1">549 <a href="/diffs/actions" tabindex="-1">
540 <span class="lbl">actions</span>550 <span class="lbl">actions</span>
541 <span class="k">section</span>551 <span class="k">section</span>
542 </a>552 </a>
543 </li>553 </li>
544-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch main">554+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
545 <a href="/diffs/tree/main" tabindex="-1">555 <a href="/diffs/tree/main" tabindex="-1">
546 <span class="lbl">main</span>556 <span class="lbl">main</span>
547 <span class="k">branch</span>557 <span class="k">branch</span>
548 </a>558 </a>
549 </li>559 </li>
550-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch side">560+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch side">
551 <a href="/diffs/tree/side" tabindex="-1">561 <a href="/diffs/tree/side" tabindex="-1">
552 <span class="lbl">side</span>562 <span class="lbl">side</span>
553 <span class="k">branch</span>563 <span class="k">branch</span>
554 </a>564 </a>
555 </li>565 </li>
556-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0.0">566+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0.0">
557 <a href="/diffs/tree/v1.0.0" tabindex="-1">567 <a href="/diffs/tree/v1.0.0" tabindex="-1">
558 <span class="lbl">v1.0.0</span>568 <span class="lbl">v1.0.0</span>
559 <span class="k">tag</span>569 <span class="k">tag</span>
560 </a>570 </a>
561 </li>571 </li>
562-<li id="cmd-o10" role="option" aria-selected="false" data-k="repo long">572+<li id="cmd-o11" role="option" aria-selected="false" data-k="repo long">
563 <a href="/long" tabindex="-1">573 <a href="/long" tabindex="-1">
564 <span class="lbl">long</span>574 <span class="lbl">long</span>
565 <span class="k">repo</span>575 <span class="k">repo</span>
566 </a>576 </a>
567 </li>577 </li>
568-<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">578+<li id="cmd-o12" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
569 <a href="#" data-fire="keys" tabindex="-1">579 <a href="#" data-fire="keys" tabindex="-1">
570 <span class="lbl">turn single-key shortcuts off</span>580 <span class="lbl">turn single-key shortcuts off</span>
571 <span class="k">action</span>581 <span class="k">action</span>
M internal/app/testdata/web/refs.html +17 -7
@@ -87,6 +87,10 @@
8787 </a>
8888 </li>
8989 <li>
90+<a href="/demo/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
91+</a>
92+</li>
93+<li>
9094 <a href="/demo/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
9195 </a>
9296 </li>
@@ -421,43 +425,49 @@
421425 <span class="k">section</span>
422426 </a>
423427 </li>
424-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
428+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
429+<a href="/demo/releases" tabindex="-1">
430+<span class="lbl">releases</span>
431+<span class="k">section</span>
432+</a>
433+</li>
434+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
425435 <a href="/demo/actions" tabindex="-1">
426436 <span class="lbl">actions</span>
427437 <span class="k">section</span>
428438 </a>
429439 </li>
430-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
440+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
431441 <a href="/demo/tree/feature/x" tabindex="-1">
432442 <span class="lbl">feature/x</span>
433443 <span class="k">branch</span>
434444 </a>
435445 </li>
436-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
446+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
437447 <a href="/demo/tree/main" tabindex="-1">
438448 <span class="lbl">main</span>
439449 <span class="k">branch</span>
440450 </a>
441451 </li>
442-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v0.1.0">
452+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.1.0">
443453 <a href="/demo/tree/v0.1.0" tabindex="-1">
444454 <span class="lbl">v0.1.0</span>
445455 <span class="k">tag</span>
446456 </a>
447457 </li>
448-<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.2.0">
458+<li id="cmd-o11" role="option" aria-selected="false" data-k="tag v0.2.0">
449459 <a href="/demo/tree/v0.2.0" tabindex="-1">
450460 <span class="lbl">v0.2.0</span>
451461 <span class="k">tag</span>
452462 </a>
453463 </li>
454-<li id="cmd-o11" role="option" aria-selected="false" data-k="repo quiet">
464+<li id="cmd-o12" role="option" aria-selected="false" data-k="repo quiet">
455465 <a href="/quiet" tabindex="-1">
456466 <span class="lbl">quiet</span>
457467 <span class="k">repo</span>
458468 </a>
459469 </li>
460-<li id="cmd-o12" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
470+<li id="cmd-o13" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
461471 <a href="#" data-fire="keys" tabindex="-1">
462472 <span class="lbl">turn single-key shortcuts off</span>
463473 <span class="k">action</span>
@@ -87,6 +87,10 @@
87 </a>87 </a>
88 </li>88 </li>
89 <li>89 <li>
90+<a href="/demo/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
91+</a>
92+</li>
93+<li>
90 <a href="/demo/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>94 <a href="/demo/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
91 </a>95 </a>
92 </li>96 </li>
@@ -421,43 +425,49 @@
421 <span class="k">section</span>425 <span class="k">section</span>
422 </a>426 </a>
423 </li>427 </li>
424-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">428+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
429+<a href="/demo/releases" tabindex="-1">
430+<span class="lbl">releases</span>
431+<span class="k">section</span>
432+</a>
433+</li>
434+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
425 <a href="/demo/actions" tabindex="-1">435 <a href="/demo/actions" tabindex="-1">
426 <span class="lbl">actions</span>436 <span class="lbl">actions</span>
427 <span class="k">section</span>437 <span class="k">section</span>
428 </a>438 </a>
429 </li>439 </li>
430-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">440+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
431 <a href="/demo/tree/feature/x" tabindex="-1">441 <a href="/demo/tree/feature/x" tabindex="-1">
432 <span class="lbl">feature/x</span>442 <span class="lbl">feature/x</span>
433 <span class="k">branch</span>443 <span class="k">branch</span>
434 </a>444 </a>
435 </li>445 </li>
436-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">446+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
437 <a href="/demo/tree/main" tabindex="-1">447 <a href="/demo/tree/main" tabindex="-1">
438 <span class="lbl">main</span>448 <span class="lbl">main</span>
439 <span class="k">branch</span>449 <span class="k">branch</span>
440 </a>450 </a>
441 </li>451 </li>
442-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v0.1.0">452+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.1.0">
443 <a href="/demo/tree/v0.1.0" tabindex="-1">453 <a href="/demo/tree/v0.1.0" tabindex="-1">
444 <span class="lbl">v0.1.0</span>454 <span class="lbl">v0.1.0</span>
445 <span class="k">tag</span>455 <span class="k">tag</span>
446 </a>456 </a>
447 </li>457 </li>
448-<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.2.0">458+<li id="cmd-o11" role="option" aria-selected="false" data-k="tag v0.2.0">
449 <a href="/demo/tree/v0.2.0" tabindex="-1">459 <a href="/demo/tree/v0.2.0" tabindex="-1">
450 <span class="lbl">v0.2.0</span>460 <span class="lbl">v0.2.0</span>
451 <span class="k">tag</span>461 <span class="k">tag</span>
452 </a>462 </a>
453 </li>463 </li>
454-<li id="cmd-o11" role="option" aria-selected="false" data-k="repo quiet">464+<li id="cmd-o12" role="option" aria-selected="false" data-k="repo quiet">
455 <a href="/quiet" tabindex="-1">465 <a href="/quiet" tabindex="-1">
456 <span class="lbl">quiet</span>466 <span class="lbl">quiet</span>
457 <span class="k">repo</span>467 <span class="k">repo</span>
458 </a>468 </a>
459 </li>469 </li>
460-<li id="cmd-o12" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">470+<li id="cmd-o13" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
461 <a href="#" data-fire="keys" tabindex="-1">471 <a href="#" data-fire="keys" tabindex="-1">
462 <span class="lbl">turn single-key shortcuts off</span>472 <span class="lbl">turn single-key shortcuts off</span>
463 <span class="k">action</span>473 <span class="k">action</span>
M internal/app/testdata/web/summary.html +17 -7
@@ -84,6 +84,10 @@
8484 </a>
8585 </li>
8686 <li>
87+<a href="/demo/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
88+</a>
89+</li>
90+<li>
8791 <a href="/demo/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
8892 </a>
8993 </li>
@@ -447,43 +451,49 @@
447451 <span class="k">section</span>
448452 </a>
449453 </li>
450-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
454+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
455+<a href="/demo/releases" tabindex="-1">
456+<span class="lbl">releases</span>
457+<span class="k">section</span>
458+</a>
459+</li>
460+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
451461 <a href="/demo/actions" tabindex="-1">
452462 <span class="lbl">actions</span>
453463 <span class="k">section</span>
454464 </a>
455465 </li>
456-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
466+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
457467 <a href="/demo/tree/feature/x" tabindex="-1">
458468 <span class="lbl">feature/x</span>
459469 <span class="k">branch</span>
460470 </a>
461471 </li>
462-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
472+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
463473 <a href="/demo/tree/main" tabindex="-1">
464474 <span class="lbl">main</span>
465475 <span class="k">branch</span>
466476 </a>
467477 </li>
468-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v0.1.0">
478+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.1.0">
469479 <a href="/demo/tree/v0.1.0" tabindex="-1">
470480 <span class="lbl">v0.1.0</span>
471481 <span class="k">tag</span>
472482 </a>
473483 </li>
474-<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.2.0">
484+<li id="cmd-o11" role="option" aria-selected="false" data-k="tag v0.2.0">
475485 <a href="/demo/tree/v0.2.0" tabindex="-1">
476486 <span class="lbl">v0.2.0</span>
477487 <span class="k">tag</span>
478488 </a>
479489 </li>
480-<li id="cmd-o11" role="option" aria-selected="false" data-k="repo quiet">
490+<li id="cmd-o12" role="option" aria-selected="false" data-k="repo quiet">
481491 <a href="/quiet" tabindex="-1">
482492 <span class="lbl">quiet</span>
483493 <span class="k">repo</span>
484494 </a>
485495 </li>
486-<li id="cmd-o12" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
496+<li id="cmd-o13" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
487497 <a href="#" data-fire="keys" tabindex="-1">
488498 <span class="lbl">turn single-key shortcuts off</span>
489499 <span class="k">action</span>
@@ -84,6 +84,10 @@
84 </a>84 </a>
85 </li>85 </li>
86 <li>86 <li>
87+<a href="/demo/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
88+</a>
89+</li>
90+<li>
87 <a href="/demo/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>91 <a href="/demo/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
88 </a>92 </a>
89 </li>93 </li>
@@ -447,43 +451,49 @@
447 <span class="k">section</span>451 <span class="k">section</span>
448 </a>452 </a>
449 </li>453 </li>
450-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">454+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
455+<a href="/demo/releases" tabindex="-1">
456+<span class="lbl">releases</span>
457+<span class="k">section</span>
458+</a>
459+</li>
460+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
451 <a href="/demo/actions" tabindex="-1">461 <a href="/demo/actions" tabindex="-1">
452 <span class="lbl">actions</span>462 <span class="lbl">actions</span>
453 <span class="k">section</span>463 <span class="k">section</span>
454 </a>464 </a>
455 </li>465 </li>
456-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">466+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
457 <a href="/demo/tree/feature/x" tabindex="-1">467 <a href="/demo/tree/feature/x" tabindex="-1">
458 <span class="lbl">feature/x</span>468 <span class="lbl">feature/x</span>
459 <span class="k">branch</span>469 <span class="k">branch</span>
460 </a>470 </a>
461 </li>471 </li>
462-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">472+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
463 <a href="/demo/tree/main" tabindex="-1">473 <a href="/demo/tree/main" tabindex="-1">
464 <span class="lbl">main</span>474 <span class="lbl">main</span>
465 <span class="k">branch</span>475 <span class="k">branch</span>
466 </a>476 </a>
467 </li>477 </li>
468-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v0.1.0">478+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.1.0">
469 <a href="/demo/tree/v0.1.0" tabindex="-1">479 <a href="/demo/tree/v0.1.0" tabindex="-1">
470 <span class="lbl">v0.1.0</span>480 <span class="lbl">v0.1.0</span>
471 <span class="k">tag</span>481 <span class="k">tag</span>
472 </a>482 </a>
473 </li>483 </li>
474-<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.2.0">484+<li id="cmd-o11" role="option" aria-selected="false" data-k="tag v0.2.0">
475 <a href="/demo/tree/v0.2.0" tabindex="-1">485 <a href="/demo/tree/v0.2.0" tabindex="-1">
476 <span class="lbl">v0.2.0</span>486 <span class="lbl">v0.2.0</span>
477 <span class="k">tag</span>487 <span class="k">tag</span>
478 </a>488 </a>
479 </li>489 </li>
480-<li id="cmd-o11" role="option" aria-selected="false" data-k="repo quiet">490+<li id="cmd-o12" role="option" aria-selected="false" data-k="repo quiet">
481 <a href="/quiet" tabindex="-1">491 <a href="/quiet" tabindex="-1">
482 <span class="lbl">quiet</span>492 <span class="lbl">quiet</span>
483 <span class="k">repo</span>493 <span class="k">repo</span>
484 </a>494 </a>
485 </li>495 </li>
486-<li id="cmd-o12" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">496+<li id="cmd-o13" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
487 <a href="#" data-fire="keys" tabindex="-1">497 <a href="#" data-fire="keys" tabindex="-1">
488 <span class="lbl">turn single-key shortcuts off</span>498 <span class="lbl">turn single-key shortcuts off</span>
489 <span class="k">action</span>499 <span class="k">action</span>
M internal/app/testdata/web/tree-nested.html +15 -5
@@ -96,6 +96,10 @@
9696 </a>
9797 </li>
9898 <li>
99+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
100+</a>
101+</li>
102+<li>
99103 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
100104 </a>
101105 </li>
@@ -373,31 +377,37 @@
373377 <span class="k">section</span>
374378 </a>
375379 </li>
376-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
380+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
381+<a href="/files/releases" tabindex="-1">
382+<span class="lbl">releases</span>
383+<span class="k">section</span>
384+</a>
385+</li>
386+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
377387 <a href="/files/actions" tabindex="-1">
378388 <span class="lbl">actions</span>
379389 <span class="k">section</span>
380390 </a>
381391 </li>
382-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
392+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
383393 <a href="/files/tree/feature/x" tabindex="-1">
384394 <span class="lbl">feature/x</span>
385395 <span class="k">branch</span>
386396 </a>
387397 </li>
388-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
398+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
389399 <a href="/files/tree/main" tabindex="-1">
390400 <span class="lbl">main</span>
391401 <span class="k">branch</span>
392402 </a>
393403 </li>
394-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">
404+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
395405 <a href="/files/tree/v1.0" tabindex="-1">
396406 <span class="lbl">v1.0</span>
397407 <span class="k">tag</span>
398408 </a>
399409 </li>
400-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
410+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
401411 <a href="#" data-fire="keys" tabindex="-1">
402412 <span class="lbl">turn single-key shortcuts off</span>
403413 <span class="k">action</span>
@@ -96,6 +96,10 @@
96 </a>96 </a>
97 </li>97 </li>
98 <li>98 <li>
99+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
100+</a>
101+</li>
102+<li>
99 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>103 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
100 </a>104 </a>
101 </li>105 </li>
@@ -373,31 +377,37 @@
373 <span class="k">section</span>377 <span class="k">section</span>
374 </a>378 </a>
375 </li>379 </li>
376-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">380+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
381+<a href="/files/releases" tabindex="-1">
382+<span class="lbl">releases</span>
383+<span class="k">section</span>
384+</a>
385+</li>
386+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
377 <a href="/files/actions" tabindex="-1">387 <a href="/files/actions" tabindex="-1">
378 <span class="lbl">actions</span>388 <span class="lbl">actions</span>
379 <span class="k">section</span>389 <span class="k">section</span>
380 </a>390 </a>
381 </li>391 </li>
382-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">392+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
383 <a href="/files/tree/feature/x" tabindex="-1">393 <a href="/files/tree/feature/x" tabindex="-1">
384 <span class="lbl">feature/x</span>394 <span class="lbl">feature/x</span>
385 <span class="k">branch</span>395 <span class="k">branch</span>
386 </a>396 </a>
387 </li>397 </li>
388-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">398+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
389 <a href="/files/tree/main" tabindex="-1">399 <a href="/files/tree/main" tabindex="-1">
390 <span class="lbl">main</span>400 <span class="lbl">main</span>
391 <span class="k">branch</span>401 <span class="k">branch</span>
392 </a>402 </a>
393 </li>403 </li>
394-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">404+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
395 <a href="/files/tree/v1.0" tabindex="-1">405 <a href="/files/tree/v1.0" tabindex="-1">
396 <span class="lbl">v1.0</span>406 <span class="lbl">v1.0</span>
397 <span class="k">tag</span>407 <span class="k">tag</span>
398 </a>408 </a>
399 </li>409 </li>
400-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">410+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
401 <a href="#" data-fire="keys" tabindex="-1">411 <a href="#" data-fire="keys" tabindex="-1">
402 <span class="lbl">turn single-key shortcuts off</span>412 <span class="lbl">turn single-key shortcuts off</span>
403 <span class="k">action</span>413 <span class="k">action</span>
M internal/app/testdata/web/tree-root.html +15 -5
@@ -90,6 +90,10 @@
9090 </a>
9191 </li>
9292 <li>
93+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
94+</a>
95+</li>
96+<li>
9397 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
9498 </a>
9599 </li>
@@ -594,31 +598,37 @@
594598 <span class="k">section</span>
595599 </a>
596600 </li>
597-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
601+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
602+<a href="/files/releases" tabindex="-1">
603+<span class="lbl">releases</span>
604+<span class="k">section</span>
605+</a>
606+</li>
607+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
598608 <a href="/files/actions" tabindex="-1">
599609 <span class="lbl">actions</span>
600610 <span class="k">section</span>
601611 </a>
602612 </li>
603-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
613+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
604614 <a href="/files/tree/feature/x" tabindex="-1">
605615 <span class="lbl">feature/x</span>
606616 <span class="k">branch</span>
607617 </a>
608618 </li>
609-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
619+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
610620 <a href="/files/tree/main" tabindex="-1">
611621 <span class="lbl">main</span>
612622 <span class="k">branch</span>
613623 </a>
614624 </li>
615-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">
625+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
616626 <a href="/files/tree/v1.0" tabindex="-1">
617627 <span class="lbl">v1.0</span>
618628 <span class="k">tag</span>
619629 </a>
620630 </li>
621-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
631+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
622632 <a href="#" data-fire="keys" tabindex="-1">
623633 <span class="lbl">turn single-key shortcuts off</span>
624634 <span class="k">action</span>
@@ -90,6 +90,10 @@
90 </a>90 </a>
91 </li>91 </li>
92 <li>92 <li>
93+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
94+</a>
95+</li>
96+<li>
93 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>97 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
94 </a>98 </a>
95 </li>99 </li>
@@ -594,31 +598,37 @@
594 <span class="k">section</span>598 <span class="k">section</span>
595 </a>599 </a>
596 </li>600 </li>
597-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">601+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
602+<a href="/files/releases" tabindex="-1">
603+<span class="lbl">releases</span>
604+<span class="k">section</span>
605+</a>
606+</li>
607+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
598 <a href="/files/actions" tabindex="-1">608 <a href="/files/actions" tabindex="-1">
599 <span class="lbl">actions</span>609 <span class="lbl">actions</span>
600 <span class="k">section</span>610 <span class="k">section</span>
601 </a>611 </a>
602 </li>612 </li>
603-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">613+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
604 <a href="/files/tree/feature/x" tabindex="-1">614 <a href="/files/tree/feature/x" tabindex="-1">
605 <span class="lbl">feature/x</span>615 <span class="lbl">feature/x</span>
606 <span class="k">branch</span>616 <span class="k">branch</span>
607 </a>617 </a>
608 </li>618 </li>
609-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">619+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
610 <a href="/files/tree/main" tabindex="-1">620 <a href="/files/tree/main" tabindex="-1">
611 <span class="lbl">main</span>621 <span class="lbl">main</span>
612 <span class="k">branch</span>622 <span class="k">branch</span>
613 </a>623 </a>
614 </li>624 </li>
615-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">625+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
616 <a href="/files/tree/v1.0" tabindex="-1">626 <a href="/files/tree/v1.0" tabindex="-1">
617 <span class="lbl">v1.0</span>627 <span class="lbl">v1.0</span>
618 <span class="k">tag</span>628 <span class="k">tag</span>
619 </a>629 </a>
620 </li>630 </li>
621-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">631+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
622 <a href="#" data-fire="keys" tabindex="-1">632 <a href="#" data-fire="keys" tabindex="-1">
623 <span class="lbl">turn single-key shortcuts off</span>633 <span class="lbl">turn single-key shortcuts off</span>
624 <span class="k">action</span>634 <span class="k">action</span>
M internal/app/testdata/web/tree-slash-ref.html +15 -5
@@ -93,6 +93,10 @@
9393 </a>
9494 </li>
9595 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97101 </a>
98102 </li>
@@ -370,31 +374,37 @@
370374 <span class="k">section</span>
371375 </a>
372376 </li>
373-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
377+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
378+<a href="/files/releases" tabindex="-1">
379+<span class="lbl">releases</span>
380+<span class="k">section</span>
381+</a>
382+</li>
383+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
374384 <a href="/files/actions" tabindex="-1">
375385 <span class="lbl">actions</span>
376386 <span class="k">section</span>
377387 </a>
378388 </li>
379-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
389+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
380390 <a href="/files/tree/feature/x" tabindex="-1">
381391 <span class="lbl">feature/x</span>
382392 <span class="k">branch</span>
383393 </a>
384394 </li>
385-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
395+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
386396 <a href="/files/tree/main" tabindex="-1">
387397 <span class="lbl">main</span>
388398 <span class="k">branch</span>
389399 </a>
390400 </li>
391-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">
401+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
392402 <a href="/files/tree/v1.0" tabindex="-1">
393403 <span class="lbl">v1.0</span>
394404 <span class="k">tag</span>
395405 </a>
396406 </li>
397-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
407+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
398408 <a href="#" data-fire="keys" tabindex="-1">
399409 <span class="lbl">turn single-key shortcuts off</span>
400410 <span class="k">action</span>
@@ -93,6 +93,10 @@
93 </a>93 </a>
94 </li>94 </li>
95 <li>95 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97 </a>101 </a>
98 </li>102 </li>
@@ -370,31 +374,37 @@
370 <span class="k">section</span>374 <span class="k">section</span>
371 </a>375 </a>
372 </li>376 </li>
373-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">377+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
378+<a href="/files/releases" tabindex="-1">
379+<span class="lbl">releases</span>
380+<span class="k">section</span>
381+</a>
382+</li>
383+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
374 <a href="/files/actions" tabindex="-1">384 <a href="/files/actions" tabindex="-1">
375 <span class="lbl">actions</span>385 <span class="lbl">actions</span>
376 <span class="k">section</span>386 <span class="k">section</span>
377 </a>387 </a>
378 </li>388 </li>
379-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">389+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
380 <a href="/files/tree/feature/x" tabindex="-1">390 <a href="/files/tree/feature/x" tabindex="-1">
381 <span class="lbl">feature/x</span>391 <span class="lbl">feature/x</span>
382 <span class="k">branch</span>392 <span class="k">branch</span>
383 </a>393 </a>
384 </li>394 </li>
385-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">395+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
386 <a href="/files/tree/main" tabindex="-1">396 <a href="/files/tree/main" tabindex="-1">
387 <span class="lbl">main</span>397 <span class="lbl">main</span>
388 <span class="k">branch</span>398 <span class="k">branch</span>
389 </a>399 </a>
390 </li>400 </li>
391-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">401+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
392 <a href="/files/tree/v1.0" tabindex="-1">402 <a href="/files/tree/v1.0" tabindex="-1">
393 <span class="lbl">v1.0</span>403 <span class="lbl">v1.0</span>
394 <span class="k">tag</span>404 <span class="k">tag</span>
395 </a>405 </a>
396 </li>406 </li>
397-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">407+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
398 <a href="#" data-fire="keys" tabindex="-1">408 <a href="#" data-fire="keys" tabindex="-1">
399 <span class="lbl">turn single-key shortcuts off</span>409 <span class="lbl">turn single-key shortcuts off</span>
400 <span class="k">action</span>410 <span class="k">action</span>
M internal/app/testdata/web/tree-subdir.html +15 -5
@@ -93,6 +93,10 @@
9393 </a>
9494 </li>
9595 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97101 </a>
98102 </li>
@@ -386,31 +390,37 @@
386390 <span class="k">section</span>
387391 </a>
388392 </li>
389-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">
393+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
394+<a href="/files/releases" tabindex="-1">
395+<span class="lbl">releases</span>
396+<span class="k">section</span>
397+</a>
398+</li>
399+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
390400 <a href="/files/actions" tabindex="-1">
391401 <span class="lbl">actions</span>
392402 <span class="k">section</span>
393403 </a>
394404 </li>
395-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">
405+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
396406 <a href="/files/tree/feature/x" tabindex="-1">
397407 <span class="lbl">feature/x</span>
398408 <span class="k">branch</span>
399409 </a>
400410 </li>
401-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">
411+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
402412 <a href="/files/tree/main" tabindex="-1">
403413 <span class="lbl">main</span>
404414 <span class="k">branch</span>
405415 </a>
406416 </li>
407-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">
417+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
408418 <a href="/files/tree/v1.0" tabindex="-1">
409419 <span class="lbl">v1.0</span>
410420 <span class="k">tag</span>
411421 </a>
412422 </li>
413-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
423+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
414424 <a href="#" data-fire="keys" tabindex="-1">
415425 <span class="lbl">turn single-key shortcuts off</span>
416426 <span class="k">action</span>
@@ -93,6 +93,10 @@
93 </a>93 </a>
94 </li>94 </li>
95 <li>95 <li>
96+<a href="/files/releases" data-key="l" aria-keyshortcuts="l">Releases <kbd aria-hidden="true">l</kbd>
97+</a>
98+</li>
99+<li>
96 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>100 <a href="/files/actions" data-key="a" aria-keyshortcuts="a">Actions <kbd aria-hidden="true">a</kbd>
97 </a>101 </a>
98 </li>102 </li>
@@ -386,31 +390,37 @@
386 <span class="k">section</span>390 <span class="k">section</span>
387 </a>391 </a>
388 </li>392 </li>
389-<li id="cmd-o6" role="option" aria-selected="false" data-k="section actions">393+<li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
394+<a href="/files/releases" tabindex="-1">
395+<span class="lbl">releases</span>
396+<span class="k">section</span>
397+</a>
398+</li>
399+<li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
390 <a href="/files/actions" tabindex="-1">400 <a href="/files/actions" tabindex="-1">
391 <span class="lbl">actions</span>401 <span class="lbl">actions</span>
392 <span class="k">section</span>402 <span class="k">section</span>
393 </a>403 </a>
394 </li>404 </li>
395-<li id="cmd-o7" role="option" aria-selected="false" data-k="branch feature/x">405+<li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
396 <a href="/files/tree/feature/x" tabindex="-1">406 <a href="/files/tree/feature/x" tabindex="-1">
397 <span class="lbl">feature/x</span>407 <span class="lbl">feature/x</span>
398 <span class="k">branch</span>408 <span class="k">branch</span>
399 </a>409 </a>
400 </li>410 </li>
401-<li id="cmd-o8" role="option" aria-selected="false" data-k="branch main">411+<li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
402 <a href="/files/tree/main" tabindex="-1">412 <a href="/files/tree/main" tabindex="-1">
403 <span class="lbl">main</span>413 <span class="lbl">main</span>
404 <span class="k">branch</span>414 <span class="k">branch</span>
405 </a>415 </a>
406 </li>416 </li>
407-<li id="cmd-o9" role="option" aria-selected="false" data-k="tag v1.0">417+<li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
408 <a href="/files/tree/v1.0" tabindex="-1">418 <a href="/files/tree/v1.0" tabindex="-1">
409 <span class="lbl">v1.0</span>419 <span class="lbl">v1.0</span>
410 <span class="k">tag</span>420 <span class="k">tag</span>
411 </a>421 </a>
412 </li>422 </li>
413-<li id="cmd-o10" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">423+<li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
414 <a href="#" data-fire="keys" tabindex="-1">424 <a href="#" data-fire="keys" tabindex="-1">
415 <span class="lbl">turn single-key shortcuts off</span>425 <span class="lbl">turn single-key shortcuts off</span>
416 <span class="k">action</span>426 <span class="k">action</span>
M internal/app/web.go +1 -0
@@ -57,6 +57,7 @@ func newWeb(cfg config.Config, f *forge, limiter *clientlimit.Limiter) (http.Han
5757 SigningKey: signing,
5858 Runs: f.CI,
5959 Artifacts: artifacts,
60+ Releases: f.Releases,
6061 Events: f.EventLog,
6162 Mirrors: f.Mirrors,
6263 Owner: cfg.Owner,
@@ -57,6 +57,7 @@ func newWeb(cfg config.Config, f *forge, limiter *clientlimit.Limiter) (http.Han
57 SigningKey: signing,57 SigningKey: signing,
58 Runs: f.CI,58 Runs: f.CI,
59 Artifacts: artifacts,59 Artifacts: artifacts,
60+ Releases: f.Releases,
60 Events: f.EventLog,61 Events: f.EventLog,
61 Mirrors: f.Mirrors,62 Mirrors: f.Mirrors,
62 Owner: cfg.Owner,63 Owner: cfg.Owner,
A internal/app/web_release_test.go +111 -0
@@ -0,0 +1,111 @@
1+// SPDX-License-Identifier: AGPL-3.0-or-later
2+
3+package app
4+
5+import (
6+ "context"
7+ "encoding/json"
8+ "io"
9+ "net/http"
10+ "strconv"
11+ "strings"
12+ "testing"
13+
14+ "github.com/stretchr/testify/assert"
15+ "github.com/stretchr/testify/require"
16+
17+ "bnema.dev/ermite/internal/domain"
18+ "bnema.dev/ermite/internal/ports"
19+ "bnema.dev/ermite/internal/usecase"
20+)
21+
22+// Releases and web use the production forge wiring.
23+func TestWebRelease(t *testing.T) {
24+ h := newHarness(t, harnessOpts{})
25+ h.webRepo("demo")
26+ blobs, releases := h.forge.Blobs, h.forge.Releases
27+ repo := h.name("demo")
28+ rel, err := releases.CreateRelease(h.ctx, domain.Root(), repo, ports.CreateReleaseParams{Tag: "v0.2.0", Title: "Demo release", Notes: "## Install\n\n**Download** the binary. <script>alert(1)</script>"})
29+ require.NoError(t, err)
30+ payload := "binary release data\x00\xff\n"
31+ asset, err := releases.UploadAsset(h.ctx, domain.Root(), repo, ports.UploadAssetParams{ReleaseID: rel.ID, Name: "demo.bin", ContentType: "application/octet-stream", Size: int64(len(payload))}, strings.NewReader(payload))
32+ require.NoError(t, err)
33+ draft, err := releases.CreateRelease(h.ctx, domain.Root(), repo, ports.CreateReleaseParams{Tag: "draft", Title: "Hidden draft", Draft: true})
34+ require.NoError(t, err)
35+ draftAsset, err := releases.UploadAsset(h.ctx, domain.Root(), repo, ports.UploadAssetParams{ReleaseID: draft.ID, Name: "hidden.bin", Size: 1}, strings.NewReader("x"))
36+ require.NoError(t, err)
37+ ts := h.srv
38+ get := func(method, path, byteRange string) (int, http.Header, string) {
39+ t.Helper()
40+ req, err := http.NewRequestWithContext(t.Context(), method, ts.URL+path, nil)
41+ require.NoError(t, err)
42+ if byteRange != "" {
43+ req.Header.Set("Range", byteRange)
44+ }
45+ res, err := ts.Client().Do(req)
46+ require.NoError(t, err)
47+ defer func() { _ = res.Body.Close() }()
48+ body, err := io.ReadAll(res.Body)
49+ require.NoError(t, err)
50+ return res.StatusCode, res.Header, string(body)
51+ }
52+ status, _, body := get("GET", "/demo/releases", "")
53+ require.Equal(t, 200, status)
54+ assert.Contains(t, body, "Demo release")
55+ assert.NotContains(t, body, "Hidden draft")
56+ status, _, body = get("GET", "/demo/releases/tag/v0.2.0", "")
57+ require.Equal(t, 200, status)
58+ assert.Contains(t, body, "<strong>Download</strong>")
59+ assert.NotContains(t, body, "<script>alert")
60+ assert.Contains(t, body, "demo.bin")
61+ assert.Contains(t, body, "/demo/releases/assets/"+strconv.FormatInt(asset.ID, 10))
62+ for _, path := range []string{"/demo/releases/download/v0.2.0/demo.bin", "/demo/releases/latest/download/demo.bin", "/demo/releases/assets/" + strconv.FormatInt(asset.ID, 10)} {
63+ status, headers, body := get("GET", path, "")
64+ require.Equal(t, 200, status)
65+ assert.Equal(t, payload, body)
66+ assert.Equal(t, strconv.Itoa(len(payload)), headers.Get("Content-Length"))
67+ assert.Equal(t, "bytes", headers.Get("Accept-Ranges"))
68+ assert.Contains(t, headers.Get("Content-Disposition"), "attachment")
69+ status, headers, body = get("GET", path, "bytes=2-6")
70+ require.Equal(t, 206, status)
71+ assert.Equal(t, payload[2:7], body)
72+ assert.Equal(t, "bytes 2-6/"+strconv.Itoa(len(payload)), headers.Get("Content-Range"))
73+ assert.Equal(t, "5", headers.Get("Content-Length"))
74+ status, headers, body = get("HEAD", path, "")
75+ require.Equal(t, 200, status)
76+ assert.Empty(t, body)
77+ assert.Equal(t, strconv.Itoa(len(payload)), headers.Get("Content-Length"))
78+ }
79+ for _, path := range []string{"/demo/releases/tag/draft", "/demo/releases/download/draft/hidden.bin", "/demo/releases/assets/" + strconv.FormatInt(draftAsset.ID, 10)} {
80+ status, _, _ := get("GET", path, "")
81+ assert.Equal(t, 404, status)
82+ }
83+ // Slash-tag page and asset-id download remain unambiguous.
84+ slash, err := releases.CreateRelease(h.ctx, domain.Root(), repo, ports.CreateReleaseParams{Tag: "series/v1", TargetCommitish: "main", Title: "Slash tag"})
85+ require.NoError(t, err)
86+ status, _, body = get("GET", "/demo/releases/tag/series/v1", "")
87+ assert.Equal(t, 200, status)
88+ assert.Contains(t, body, slash.Title)
89+ // The browser_download_url of the REST API for a slash tag is served by
90+ // the web route.
91+ slashAsset, err := releases.UploadAsset(h.ctx, domain.Root(), repo, ports.UploadAssetParams{ReleaseID: slash.ID, Name: "s.bin", Size: 5}, strings.NewReader("slash"))
92+ require.NoError(t, err)
93+ gh := usecase.NewReleasesGitHub(releases, "owner", ts.URL)
94+ raw, err := gh.GetAsset(h.ctx, domain.Root(), "owner", "demo", slashAsset.ID)
95+ require.NoError(t, err)
96+ var obj struct {
97+ URL string `json:"browser_download_url"`
98+ }
99+ require.NoError(t, json.Unmarshal(raw, &obj))
100+ require.Equal(t, ts.URL+"/demo/releases/download/series%2Fv1/s.bin", obj.URL)
101+ status, _, body = get("GET", strings.TrimPrefix(obj.URL, ts.URL), "")
102+ assert.Equal(t, 200, status)
103+ assert.Equal(t, "slash", body)
104+ // A missing blob is a 404 page before any binary headers are written.
105+ require.NoError(t, blobs.Delete(context.Background(), asset.BlobKey()))
106+ status, headers, body := get("GET", "/demo/releases/assets/"+strconv.FormatInt(asset.ID, 10), "")
107+ assert.Equal(t, 404, status)
108+ assert.Contains(t, headers.Get("Content-Type"), "text/html")
109+ assert.Contains(t, body, "no such page")
110+ assert.Empty(t, headers.Get("Content-Disposition"))
111+}
@@ -0,0 +1,111 @@
1+// SPDX-License-Identifier: AGPL-3.0-or-later
2+
3+package app
4+
5+import (
6+ "context"
7+ "encoding/json"
8+ "io"
9+ "net/http"
10+ "strconv"
11+ "strings"
12+ "testing"
13+
14+ "github.com/stretchr/testify/assert"
15+ "github.com/stretchr/testify/require"
16+
17+ "bnema.dev/ermite/internal/domain"
18+ "bnema.dev/ermite/internal/ports"
19+ "bnema.dev/ermite/internal/usecase"
20+)
21+
22+// Releases and web use the production forge wiring.
23+func TestWebRelease(t *testing.T) {
24+ h := newHarness(t, harnessOpts{})
25+ h.webRepo("demo")
26+ blobs, releases := h.forge.Blobs, h.forge.Releases
27+ repo := h.name("demo")
28+ rel, err := releases.CreateRelease(h.ctx, domain.Root(), repo, ports.CreateReleaseParams{Tag: "v0.2.0", Title: "Demo release", Notes: "## Install\n\n**Download** the binary. <script>alert(1)</script>"})
29+ require.NoError(t, err)
30+ payload := "binary release data\x00\xff\n"
31+ asset, err := releases.UploadAsset(h.ctx, domain.Root(), repo, ports.UploadAssetParams{ReleaseID: rel.ID, Name: "demo.bin", ContentType: "application/octet-stream", Size: int64(len(payload))}, strings.NewReader(payload))
32+ require.NoError(t, err)
33+ draft, err := releases.CreateRelease(h.ctx, domain.Root(), repo, ports.CreateReleaseParams{Tag: "draft", Title: "Hidden draft", Draft: true})
34+ require.NoError(t, err)
35+ draftAsset, err := releases.UploadAsset(h.ctx, domain.Root(), repo, ports.UploadAssetParams{ReleaseID: draft.ID, Name: "hidden.bin", Size: 1}, strings.NewReader("x"))
36+ require.NoError(t, err)
37+ ts := h.srv
38+ get := func(method, path, byteRange string) (int, http.Header, string) {
39+ t.Helper()
40+ req, err := http.NewRequestWithContext(t.Context(), method, ts.URL+path, nil)
41+ require.NoError(t, err)
42+ if byteRange != "" {
43+ req.Header.Set("Range", byteRange)
44+ }
45+ res, err := ts.Client().Do(req)
46+ require.NoError(t, err)
47+ defer func() { _ = res.Body.Close() }()
48+ body, err := io.ReadAll(res.Body)
49+ require.NoError(t, err)
50+ return res.StatusCode, res.Header, string(body)
51+ }
52+ status, _, body := get("GET", "/demo/releases", "")
53+ require.Equal(t, 200, status)
54+ assert.Contains(t, body, "Demo release")
55+ assert.NotContains(t, body, "Hidden draft")
56+ status, _, body = get("GET", "/demo/releases/tag/v0.2.0", "")
57+ require.Equal(t, 200, status)
58+ assert.Contains(t, body, "<strong>Download</strong>")
59+ assert.NotContains(t, body, "<script>alert")
60+ assert.Contains(t, body, "demo.bin")
61+ assert.Contains(t, body, "/demo/releases/assets/"+strconv.FormatInt(asset.ID, 10))
62+ for _, path := range []string{"/demo/releases/download/v0.2.0/demo.bin", "/demo/releases/latest/download/demo.bin", "/demo/releases/assets/" + strconv.FormatInt(asset.ID, 10)} {
63+ status, headers, body := get("GET", path, "")
64+ require.Equal(t, 200, status)
65+ assert.Equal(t, payload, body)
66+ assert.Equal(t, strconv.Itoa(len(payload)), headers.Get("Content-Length"))
67+ assert.Equal(t, "bytes", headers.Get("Accept-Ranges"))
68+ assert.Contains(t, headers.Get("Content-Disposition"), "attachment")
69+ status, headers, body = get("GET", path, "bytes=2-6")
70+ require.Equal(t, 206, status)
71+ assert.Equal(t, payload[2:7], body)
72+ assert.Equal(t, "bytes 2-6/"+strconv.Itoa(len(payload)), headers.Get("Content-Range"))
73+ assert.Equal(t, "5", headers.Get("Content-Length"))
74+ status, headers, body = get("HEAD", path, "")
75+ require.Equal(t, 200, status)
76+ assert.Empty(t, body)
77+ assert.Equal(t, strconv.Itoa(len(payload)), headers.Get("Content-Length"))
78+ }
79+ for _, path := range []string{"/demo/releases/tag/draft", "/demo/releases/download/draft/hidden.bin", "/demo/releases/assets/" + strconv.FormatInt(draftAsset.ID, 10)} {
80+ status, _, _ := get("GET", path, "")
81+ assert.Equal(t, 404, status)
82+ }
83+ // Slash-tag page and asset-id download remain unambiguous.
84+ slash, err := releases.CreateRelease(h.ctx, domain.Root(), repo, ports.CreateReleaseParams{Tag: "series/v1", TargetCommitish: "main", Title: "Slash tag"})
85+ require.NoError(t, err)
86+ status, _, body = get("GET", "/demo/releases/tag/series/v1", "")
87+ assert.Equal(t, 200, status)
88+ assert.Contains(t, body, slash.Title)
89+ // The browser_download_url of the REST API for a slash tag is served by
90+ // the web route.
91+ slashAsset, err := releases.UploadAsset(h.ctx, domain.Root(), repo, ports.UploadAssetParams{ReleaseID: slash.ID, Name: "s.bin", Size: 5}, strings.NewReader("slash"))
92+ require.NoError(t, err)
93+ gh := usecase.NewReleasesGitHub(releases, "owner", ts.URL)
94+ raw, err := gh.GetAsset(h.ctx, domain.Root(), "owner", "demo", slashAsset.ID)
95+ require.NoError(t, err)
96+ var obj struct {
97+ URL string `json:"browser_download_url"`
98+ }
99+ require.NoError(t, json.Unmarshal(raw, &obj))
100+ require.Equal(t, ts.URL+"/demo/releases/download/series%2Fv1/s.bin", obj.URL)
101+ status, _, body = get("GET", strings.TrimPrefix(obj.URL, ts.URL), "")
102+ assert.Equal(t, 200, status)
103+ assert.Equal(t, "slash", body)
104+ // A missing blob is a 404 page before any binary headers are written.
105+ require.NoError(t, blobs.Delete(context.Background(), asset.BlobKey()))
106+ status, headers, body := get("GET", "/demo/releases/assets/"+strconv.FormatInt(asset.ID, 10), "")
107+ assert.Equal(t, 404, status)
108+ assert.Contains(t, headers.Get("Content-Type"), "text/html")
109+ assert.Contains(t, body, "no such page")
110+ assert.Empty(t, headers.Get("Content-Disposition"))
111+}
M internal/boundary/boundary_test.go +14 -2
M internal/config/config.go +117 -0
A internal/config/storage_test.go +111 -0
M internal/domain/ci_artifact.go +21 -0
M internal/domain/ci_artifact_test.go +7 -0
M internal/domain/event.go +44 -0
A internal/domain/release.go +165 -0
A internal/domain/release_test.go +59 -0
M internal/domain/token.go +4 -2
M internal/domain/token_test.go +5 -1
A internal/httprange/httprange.go +77 -0
A internal/httprange/httprange_test.go +72 -0
A internal/ports/blob.go +72 -0
A internal/ports/blob_test.go +19 -0
M internal/ports/ci_artifact.go +3 -13
A internal/ports/mocks/BlobStore.go +644 -0
M internal/ports/mocks/CIArtifactFiles.go +0 -276
A internal/ports/mocks/GitHubReleaseAPI.go +1044 -0
A internal/ports/mocks/MultipartUpload.go +273 -0
A internal/ports/mocks/ReleaseRepoCleaner.go +168 -0
A internal/ports/mocks/ReleaseService.go +997 -0
A internal/ports/mocks/ReleaseStore.go +796 -0
A internal/ports/mocks/ReleaseSweeper.go +87 -0
A internal/ports/mocks/ReleaseTagTrigger.go +100 -0
A internal/ports/mocks/ReleaseTagWriter.go +117 -0
A internal/ports/release.go +119 -0
M internal/ports/services.go +17 -0
M internal/usecase/ci.go +15 -7
M internal/usecase/ci_artifacts.go +325 -12
A internal/usecase/ci_artifacts_blob_test.go +301 -0
A internal/usecase/ci_artifacts_slots_test.go +179 -0
M internal/usecase/ci_watch.go +4 -3
M internal/usecase/events.go +25 -0
M internal/usecase/events_test.go +95 -0
M internal/usecase/pushes.go +21 -14
A internal/usecase/releases.go +494 -0
A internal/usecase/releases_assets.go +441 -0
A internal/usecase/releases_assets_test.go +308 -0
A internal/usecase/releases_github.go +387 -0
A internal/usecase/releases_github_test.go +360 -0
A internal/usecase/releases_integration_test.go +336 -0
A internal/usecase/releases_sweep.go +106 -0
A internal/usecase/releases_sweep_test.go +147 -0
A internal/usecase/releases_test.go +57 -0
M internal/usecase/repos.go +9 -1
M internal/usecase/repos_write.go +11 -0
M proto/ermite/storage/ci_artifact.proto +4 -2
A proto/ermite/storage/release.proto +46 -0
M skills/ermite/CLI.md +20 -0

Comments0 open / 0

no comments yet.

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
l
merge request: the list of files (j k move, enter opens, esc back)
M
merge request: the merge menu; there 1–3 pick the mode, D deletes the branch, enter merges
R
merge request: mark the head read
esc
close a dialog, leave a field

Branches 3

Tags 41

↑↓ moveenter openesc close