v0.20.0 032b9ef

cli_version.go RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package app
4
5import (
6	"fmt"
7	"strings"
8
9	"connectrpc.com/connect"
10	"github.com/spf13/cobra"
11
12	"bnema.dev/ermite-api/gen/ermite"
13	"bnema.dev/ermite/internal/adapters/client"
14)
15
16// jsonVersion is the stable JSON shape of `ermite version --json`.
17type jsonVersion struct {
18	Client jsonClientVersion  `json:"client"`
19	Server *jsonServerVersion `json:"server"`
20}
21
22type jsonClientVersion struct {
23	Version string `json:"version"`
24}
25
26type jsonServerVersion struct {
27	URL             string   `json:"url"`
28	Version         string   `json:"version"`
29	Features        []string `json:"features"`
30	MissingFeatures []string `json:"missing_features"`
31}
32
33func newVersionCmd(env *cliEnv) *cobra.Command {
34	cmd := &cobra.Command{
35		Use:   "version",
36		Short: "Print the client version and, when a server URL is configured, the server's",
37		Long: "Print the version of this client and, when a server URL is configured (ERMITE_URL or the url\n" +
38			"of the config file, see `ermite config`), the version of the server and the optional features\n" +
39			"of the API it implements. A warning on standard error says which of the features this client\n" +
40			"uses the server lacks. Without a URL only the client is shown. The token command of the config\n" +
41			"file is not run.\n\n" +
42			"JSON fields (--json): client.version; server, null without a URL, with url, version,\n" +
43			"features (array of identifiers) and missing_features (the ones this client uses that the\n" +
44			"server lacks).",
45		Args: cobra.NoArgs,
46	}
47	asJSON := addJSONFlag(cmd)
48	cmd.RunE = func(cmd *cobra.Command, _ []string) error {
49		out := cmd.OutOrStdout()
50		clientLine := "ermite " + env.version
51		url, err := env.resolveURL(cmd, true)
52		if err != nil {
53			// The client version does not depend on the file: say what is wrong
54			// and go on as if no URL were configured.
55			warnf(cmd, "%s", err)
56			url = ""
57		}
58		if url == "" {
59			if *asJSON {
60				return writeJSON(out, jsonVersion{Client: jsonClientVersion{Version: env.version}})
61			}
62			_, err := fmt.Fprintln(out, clientLine)
63			return err
64		}
65
66		// GetVersion is anonymous: token.cmd is not run for it.
67		c, err := env.clientNoTokenCmd(cmd, true)
68		if err != nil {
69			return err
70		}
71		res, err := c.Server().GetVersion(env.ctx(cmd), connect.NewRequest(&ermite.GetVersionRequest{}))
72		if err != nil {
73			// Still show what is known locally before failing.
74			if !*asJSON {
75				_, _ = fmt.Fprintln(out, clientLine)
76			}
77			return c.Describe(err)
78		}
79		features := res.Msg.GetFeatures()
80		if features == nil {
81			features = []string{}
82		}
83		missing := client.MissingFeatures(features)
84		if *asJSON {
85			if missing == nil {
86				missing = []string{}
87			}
88			err = writeJSON(out, jsonVersion{
89				Client: jsonClientVersion{Version: env.version},
90				Server: &jsonServerVersion{URL: c.URL(), Version: res.Msg.GetVersion(), Features: features, MissingFeatures: missing},
91			})
92		} else {
93			err = fields(out, [][2]string{
94				{"client", clientLine},
95				{"server", res.Msg.GetVersion() + " at " + c.URL()},
96				{"features", strings.Join(features, ", ")},
97			})
98		}
99		if err != nil {
100			return err
101		}
102		for _, f := range missing {
103			warnf(cmd, "the server does not support %s, which %s", f, featureUse[f])
104		}
105		return nil
106	}
107	return cmd
108}
109
110// featureUse says what breaks without a feature, for the version warning.
111var featureUse = map[string]string{
112	client.FeatureRepoUpdate:          "`ermite repo edit` needs: the command will fail on this server",
113	client.FeatureEventsResume:        "`ermite watch` uses to resume after a reconnection: events during an outage may be missed",
114	client.FeatureMergeRequests:       "`ermite mr` needs: the commands will fail on this server",
115	client.FeatureMergeDeleteBranch:   "`ermite mr merge --delete-branch` needs: the merge works but the branch is kept",
116	client.FeatureSigningKey:          "`ermite signing-key show` needs: the command will fail on this server",
117	client.FeatureSession:             "`ermite web login` needs: the command will fail on this server",
118	client.FeatureTokenBranchPrefixes: "`ermite token create --branch-prefix` needs: the command is refused, and `token list` does not show the limits",
119	client.FeatureCIRuns:              "`ermite run` needs: the commands will fail on this server",
120	client.FeatureCIRunners:           "`ermite runner` needs: the commands will fail on this server",
121	client.FeatureCISecrets:           "`ermite secret`, `variable` and `environment` need: the commands will fail on this server",
122	client.FeatureCIDispatch:          "`ermite workflow run` needs: the command will fail on this server",
123	client.FeatureCIArtifacts:         "`ermite run artifacts` and `run download` need: the commands will fail on this server",
124	client.FeaturePasskeys:            "`ermite web passkey` needs: the commands will fail on this server (passkeys need an https public URL with a DNS host name)",
125}

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