detached 5278df2

cli_mirror_test.go RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package app
4
5import (
6	"strings"
7	"testing"
8
9	"github.com/stretchr/testify/assert"
10	"github.com/stretchr/testify/require"
11)
12
13func TestMirrorCLIArguments(t *testing.T) {
14	for _, args := range [][]string{
15		{"mirror", "sync"}, {"mirror", "sync", "repo", "--all"}, {"mirror", "sync", "a", "b"},
16		{"mirror", "add", "repo"}, {"mirror", "remove"}, {"mirror", "exclude"}, {"mirror", "include"},
17		{"mirror", "key", "show", "extra"}, {"mirror", "key", "rotate", "extra"}, {"mirror", "status", "a", "b"},
18	} {
19		t.Run(strings.Join(args, " "), func(t *testing.T) {
20			r := runCLI(t, nil, "", args...)
21			require.Error(t, r.err)
22			assert.NotContains(t, r.err.Error(), "ERMITE_URL", "arguments must be rejected before loading credentials")
23		})
24	}
25	r := runCLI(t, nil, "", "mirror", "sync", "--help").ok(t)
26	assert.Contains(t, r.stdout, "never force-pushes")
27	assert.Contains(t, r.stdout, "lifts a pause")
28}
29
30func TestMirrorCLIConfiguration(t *testing.T) {
31	h := newSecretsCLI(t)
32	run := func(args ...string) result { return h.cli(t, adminToken, append([]string{"mirror"}, args...)...) }
33	run("config", "--enabled", "--url", "git@example.test:owner/{repo}.git", "--cron", "*/5 * * * *", "--all-branches").ok(t)
34	r := run("config", "show", "--json").ok(t)
35	g := decode[map[string]any](t, r.stdout)
36	assert.Equal(t, true, g["enabled"])
37	assert.Equal(t, true, g["all_branches"])
38	assert.Equal(t, "git@example.test:owner/{repo}.git", g["url_template"])
39	run("config", "--enabled=false", "--all-branches=false").ok(t)
40	g = decode[map[string]any](t, run("config", "show", "--json").ok(t).stdout)
41	assert.Equal(t, false, g["enabled"])
42	assert.Equal(t, false, g["all_branches"])
43	assert.Equal(t, "*/5 * * * *", g["cron"], "omitted fields are not cleared")
44	run("add", "proj", "git@example.test:owner/proj.git", "--cron", "*/10 * * * *", "--all-branches=false").ok(t)
45	r = run("status", "proj", "--json").ok(t)
46	s := decode[map[string]any](t, r.stdout)
47	assert.Equal(t, "override", s["source"])
48	assert.Equal(t, false, s["all_branches"])
49	assert.Equal(t, "ok", s["state"])
50	assert.Equal(t, "proj", s["repo"])
51	assert.Contains(t, run("status").ok(t).stdout, "FAILURES")
52	assert.Len(t, decode[[]any](t, run("status", "--json").ok(t).stdout), 1)
53	run("remove", "proj").ok(t)
54	run("exclude", "proj").ok(t)
55	s = decode[map[string]any](t, run("status", "proj", "--json").ok(t).stdout)
56	assert.Equal(t, "excluded", s["source"])
57	run("include", "proj").ok(t)
58	first := run("key", "show").ok(t)
59	assert.Empty(t, first.stderr)
60	firstFingerprint := decode[map[string]any](t, run("key", "show", "--json").ok(t).stdout)["fingerprint"].(string)
61	rotated := run("key", "rotate").ok(t)
62	assert.Contains(t, rotated.stderr, "replaced key "+firstFingerprint)
63	assert.NotEqual(t, first.stdout, rotated.stdout)
64	assert.Contains(t, rotated.stderr, "remotes refuse pushes until this key is added")
65	assert.Equal(t, rotated.stdout, run("key", "show").ok(t).stdout)
66	assert.Equal(t, []string{"authorized_key", "created_at", "fingerprint"}, keys(t, run("key", "show", "--json").ok(t).stdout))
67}

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 45

↑↓ moveenter openesc close