cli prints license warnings (#3716)

* cli prints license warnings

Signed-off-by: Spike Curtis <spike@coder.com>

* Satisfy the linter

Signed-off-by: Spike Curtis <spike@coder.com>

Signed-off-by: Spike Curtis <spike@coder.com>
This commit is contained in:
Spike Curtis 2022-08-29 11:30:06 -07:00 committed by GitHub
parent 62f686c003
commit 779c446a6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 66 additions and 32 deletions

View File

@ -35,18 +35,20 @@ var (
)
const (
varURL = "url"
varToken = "token"
varAgentToken = "agent-token"
varAgentURL = "agent-url"
varGlobalConfig = "global-config"
varNoOpen = "no-open"
varNoVersionCheck = "no-version-warning"
varForceTty = "force-tty"
varVerbose = "verbose"
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
varURL = "url"
varToken = "token"
varAgentToken = "agent-token"
varAgentURL = "agent-url"
varGlobalConfig = "global-config"
varNoOpen = "no-open"
varNoVersionCheck = "no-version-warning"
varNoFeatureWarning = "no-feature-warning"
varForceTty = "force-tty"
varVerbose = "verbose"
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
envNoVersionCheck = "CODER_NO_VERSION_WARNING"
envNoVersionCheck = "CODER_NO_VERSION_WARNING"
envNoFeatureWarning = "CODER_NO_FEATURE_WARNING"
)
var (
@ -103,29 +105,25 @@ func Root(subcommands []*cobra.Command) *cobra.Command {
Long: `Coder A tool for provisioning self-hosted development environments.
`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
err := func() error {
if cliflag.IsSetBool(cmd, varNoVersionCheck) {
return nil
}
if cliflag.IsSetBool(cmd, varNoVersionCheck) &&
cliflag.IsSetBool(cmd, varNoFeatureWarning) {
return
}
// Login handles checking the versions itself since it
// has a handle to an unauthenticated client.
// Server is skipped for obvious reasons.
if cmd.Name() == "login" || cmd.Name() == "server" || cmd.Name() == "gitssh" {
return nil
}
// Login handles checking the versions itself since it
// has a handle to an unauthenticated client.
// Server is skipped for obvious reasons.
if cmd.Name() == "login" || cmd.Name() == "server" || cmd.Name() == "gitssh" {
return
}
client, err := CreateClient(cmd)
// If the client is unauthenticated we can ignore the check.
// The child commands should handle an unauthenticated client.
if xerrors.Is(err, errUnauthenticated) {
return nil
}
if err != nil {
return xerrors.Errorf("create client: %w", err)
}
return checkVersions(cmd, client)
}()
client, err := CreateClient(cmd)
// If we are unable to create a client, presumably the subcommand will fail as well
// so we can bail out here.
if err != nil {
return
}
err = checkVersions(cmd, client)
if err != nil {
// Just log the error here. We never want to fail a command
// due to a pre-run.
@ -133,6 +131,7 @@ func Root(subcommands []*cobra.Command) *cobra.Command {
cliui.Styles.Warn.Render("check versions error: %s"), err)
_, _ = fmt.Fprintln(cmd.ErrOrStderr())
}
checkWarnings(cmd, client)
},
Example: formatExamples(
example{
@ -152,6 +151,7 @@ func Root(subcommands []*cobra.Command) *cobra.Command {
cmd.PersistentFlags().String(varURL, "", "Specify the URL to your deployment.")
cliflag.Bool(cmd.PersistentFlags(), varNoVersionCheck, "", envNoVersionCheck, false, "Suppress warning when client and server versions do not match.")
cliflag.Bool(cmd.PersistentFlags(), varNoFeatureWarning, "", envNoFeatureWarning, false, "Suppress warnings about unlicensed features.")
cliflag.String(cmd.PersistentFlags(), varToken, "", envSessionToken, "", fmt.Sprintf("Specify an authentication token. For security reasons setting %s is preferred.", envSessionToken))
cliflag.String(cmd.PersistentFlags(), varAgentToken, "", "CODER_AGENT_TOKEN", "", "Specify an agent authentication token.")
_ = cmd.PersistentFlags().MarkHidden(varAgentToken)
@ -493,3 +493,16 @@ download the server version with: 'curl -L https://coder.com/install.sh | sh -s
return nil
}
func checkWarnings(cmd *cobra.Command, client *codersdk.Client) {
if cliflag.IsSetBool(cmd, varNoFeatureWarning) {
return
}
entitlements, err := client.Entitlements(cmd.Context())
if err != nil {
return
}
for _, w := range entitlements.Warnings {
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), cliui.Styles.Warn.Render(w))
}
}

View File

@ -20,6 +20,7 @@ import (
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/coderd/httpapi"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/enterprise/cli"
"github.com/coder/coder/enterprise/coderd"
@ -28,6 +29,7 @@ import (
)
const fakeLicenseJWT = "test.jwt.sig"
const testWarning = "This is a test warning"
func TestLicensesAddFake(t *testing.T) {
t.Parallel()
@ -179,6 +181,8 @@ func TestLicensesListReal(t *testing.T) {
"licenses", "list")
stdout := new(bytes.Buffer)
cmd.SetOut(stdout)
stderr := new(bytes.Buffer)
cmd.SetErr(stderr)
clitest.SetupConfig(t, client, root)
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
@ -188,6 +192,7 @@ func TestLicensesListReal(t *testing.T) {
}()
require.NoError(t, <-errC)
assert.Equal(t, "[]\n", stdout.String())
assert.Contains(t, testWarning, stderr.String())
})
}
@ -260,6 +265,7 @@ func newFakeLicenseAPI(t *testing.T) http.Handler {
r.Get("/api/v2/licenses", a.licenses)
r.Get("/api/v2/buildinfo", a.noop)
r.Delete("/api/v2/licenses/{id}", a.deleteLicense)
r.Get("/api/v2/entitlements", a.entitlements)
return r
}
@ -330,3 +336,18 @@ func (s *fakeLicenseAPI) deleteLicense(rw http.ResponseWriter, r *http.Request)
assert.Equal(s.t, "55", chi.URLParam(r, "id"))
rw.WriteHeader(200)
}
func (*fakeLicenseAPI) entitlements(rw http.ResponseWriter, _ *http.Request) {
features := make(map[string]codersdk.Feature)
for _, f := range codersdk.FeatureNames {
features[f] = codersdk.Feature{
Entitlement: codersdk.EntitlementEntitled,
Enabled: true,
}
}
httpapi.Write(rw, http.StatusOK, codersdk.Entitlements{
Features: features,
Warnings: []string{testWarning},
HasLicense: true,
})
}