v0.19.0 55a688e

cli_version_test.go RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package app
4
5import (
6	"errors"
7	"strings"
8	"testing"
9
10	"connectrpc.com/connect"
11	"github.com/stretchr/testify/assert"
12	"github.com/stretchr/testify/require"
13
14	"bnema.dev/ermite-api/gen/ermite"
15
16	"bnema.dev/ermite/internal/adapters/client"
17)
18
19// allFeatures are the features this client uses.
20var allFeatures = []string{"repo.update", "events.resume", "merge_requests", "merge_requests.delete_branch", "signing_key", "session", "token.branch_prefixes", "ci.runs", "ci.runners", "ci.secrets", "ci.dispatch", "ci.artifacts", "passkeys"}
21
22// Every feature the client uses needs a sentence for the version warning.
23func TestEveryUsedFeatureExplainsWhatBreaks(t *testing.T) {
24	for _, f := range client.UsedFeatures() {
25		assert.NotEmpty(t, featureUse[f], f)
26	}
27}
28
29func versionFake(features ...string) *fakeAPI {
30	return &fakeAPI{getVersion: func(*ermite.GetVersionRequest) (*ermite.GetVersionResponse, error) {
31		return &ermite.GetVersionResponse{Version: "v0.4.0", Features: features}, nil
32	}}
33}
34
35func TestVersionClientOnlyWithoutURL(t *testing.T) {
36	res := runCLI(t, nil, "", "version").ok(t)
37	assert.Equal(t, "ermite v0.0.1\n", res.stdout)
38	assert.Empty(t, res.stderr)
39
40	res = runCLI(t, nil, "", "version", "--json").ok(t)
41	assert.JSONEq(t, `{"client":{"version":"v0.0.1"},"server":null}`, res.stdout)
42}
43
44func TestVersionWithServer(t *testing.T) {
45	f := versionFake(allFeatures...)
46	url := f.serve(t)
47	res := runCLI(t, envFor(url), "", "version").ok(t)
48	assert.Equal(t, "client    ermite v0.0.1\nserver    v0.4.0 at "+url+"\nfeatures  repo.update, events.resume, merge_requests, merge_requests.delete_branch, signing_key, session, token.branch_prefixes, ci.runs, ci.runners, ci.secrets, ci.dispatch, ci.artifacts, passkeys\n", res.stdout)
49	assert.Empty(t, res.stderr, "no warning when every feature is there")
50
51	res = runCLI(t, envFor(url), "", "version", "--json").ok(t)
52	assert.JSONEq(t, `{"client":{"version":"v0.0.1"},"server":{"url":"`+url+`","version":"v0.4.0","features":["repo.update","events.resume","merge_requests","merge_requests.delete_branch","signing_key","session","token.branch_prefixes","ci.runs","ci.runners","ci.secrets","ci.dispatch","ci.artifacts","passkeys"],"missing_features":[]}}`, res.stdout)
53}
54
55func TestVersionWarnsAboutMissingFeatures(t *testing.T) {
56	f := versionFake("repo.update", "merge_requests", "merge_requests.delete_branch", "signing_key", "session", "token.branch_prefixes", "ci.runs", "ci.runners", "ci.secrets", "ci.dispatch", "ci.artifacts", "passkeys")
57	url := f.serve(t)
58	res := runCLI(t, envFor(url), "", "version").ok(t)
59	assert.Contains(t, res.stdout, "v0.4.0")
60	assert.Contains(t, res.stderr, "ermite: warning: the server does not support events.resume")
61	assert.NotContains(t, res.stderr, "repo.update")
62
63	res = runCLI(t, envFor(url), "", "version", "--json").ok(t)
64	assert.JSONEq(t, `{"client":{"version":"v0.0.1"},"server":{"url":"`+url+`","version":"v0.4.0","features":["repo.update","merge_requests","merge_requests.delete_branch","signing_key","session","token.branch_prefixes","ci.runs","ci.runners","ci.secrets","ci.dispatch","ci.artifacts","passkeys"],"missing_features":["events.resume"]}}`, res.stdout)
65	assert.Contains(t, res.stderr, "events.resume", "the warning also goes to stderr with --json")
66
67	f = versionFake()
68	res = runCLI(t, envFor(f.serve(t)), "", "version").ok(t)
69	assert.Contains(t, res.stderr, "repo.update")
70	assert.Contains(t, res.stderr, "events.resume")
71	assert.Contains(t, res.stderr, "passkeys")
72}
73
74// A server without passkeys (http public URL, or an IP address host) works for
75// everything else: only `ermite web passkey` is warned about.
76func TestVersionWarnsAboutMissingPasskeys(t *testing.T) {
77	f := versionFake(allFeatures[:len(allFeatures)-1]...)
78	res := runCLI(t, envFor(f.serve(t)), "", "version", "--json").ok(t)
79	assert.Contains(t, res.stdout, `"missing_features": [
80      "passkeys"
81    ]`)
82	assert.Equal(t, 1, strings.Count(res.stderr, "warning:"), res.stderr)
83	assert.Contains(t, res.stderr, "the server does not support passkeys, which `ermite web passkey` needs")
84	assert.Contains(t, res.stderr, "https public URL")
85}
86
87func TestVersionServerFailureStillShowsClient(t *testing.T) {
88	f := &fakeAPI{getVersion: func(*ermite.GetVersionRequest) (*ermite.GetVersionResponse, error) {
89		return nil, connect.NewError(connect.CodeInternal, errors.New("boom"))
90	}}
91	res := runCLI(t, envFor(f.serve(t)), "", "version")
92	require.Error(t, res.err)
93	assert.Equal(t, "ermite v0.0.1\n", res.stdout)
94	assert.Contains(t, res.err.Error(), "server error: boom")
95}
96
97func TestVersionWorksWithoutToken(t *testing.T) {
98	f := versionFake(allFeatures...)
99	runCLI(t, map[string]string{"ERMITE_URL": f.serve(t)}, "", "version").ok(t)
100	assert.Empty(t, f.header[0].Values("Authorization"))
101}

Keyboard shortcuts

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

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

Branches 2

Tags 44

↑↓ moveenter openesc close