From 442125d2a8055158f98497cf0cd1aeeff453ca83 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Thu, 11 Jan 2024 22:35:47 +0000 Subject: [PATCH 01/17] feat: add customizable upgrade message on client/server version mismatch --- cli/login.go | 2 +- cli/root.go | 28 ++++++++++++++---- cli/root_internal_test.go | 45 +++++++++++++++++++++++++++++ cli/root_test.go | 25 ++++++++++++++++ coderd/coderd.go | 1 + coderd/deployment.go | 7 +++++ coderd/externalauth/externalauth.go | 2 +- coderd/httpapi/websocket.go | 3 +- coderd/promoauth/github.go | 5 ++-- codersdk/deployment.go | 33 +++++++++++++++++++++ 10 files changed, 140 insertions(+), 11 deletions(-) diff --git a/cli/login.go b/cli/login.go index 1bf8d97297dba..8da78c7d44040 100644 --- a/cli/login.go +++ b/cli/login.go @@ -175,7 +175,7 @@ func (r *RootCmd) login() *clibase.Cmd { // Try to check the version of the server prior to logging in. // It may be useful to warn the user if they are trying to login // on a very old client. - err = r.checkVersions(inv, client) + err = r.checkVersions(inv, client, false) if err != nil { // Checking versions isn't a fatal error so we print a warning // and proceed. diff --git a/cli/root.go b/cli/root.go index cef7df19b366d..d4959089f0945 100644 --- a/cli/root.go +++ b/cli/root.go @@ -600,7 +600,7 @@ func (r *RootCmd) PrintWarnings(client *codersdk.Client) clibase.MiddlewareFunc warningErr = make(chan error) ) go func() { - versionErr <- r.checkVersions(inv, client) + versionErr <- r.checkVersions(inv, client, false) close(versionErr) }() @@ -810,7 +810,12 @@ func formatExamples(examples ...example) string { return sb.String() } -func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client) error { +// checkVersions checks to see if there's a version mismatch between the client +// and server and prints a message nudging the user to upgrade if a mismatch +// is detected. forceCheck is a test flag and should always be false in production. +// +//nolint:revive +func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client, forceCheck bool) error { if r.noVersionCheck { return nil } @@ -824,11 +829,15 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client) if isConnectionError(err) { return nil } - if err != nil { return xerrors.Errorf("build info: %w", err) } + dconfig, err := client.UnprivilegedDeploymentConfig(ctx) + if err != nil { + return xerrors.Errorf("deployment config: %w", err) + } + fmtWarningText := `version mismatch: client %s, server %s ` // Our installation script doesn't work on Windows, so instead we direct the user @@ -838,10 +847,17 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client) } else { fmtWarningText += `download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version %s'` } + warn := cliui.DefaultStyles.Warn + warning := fmt.Sprintf(pretty.Sprint(warn, fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v")) + + // If a custom upgrade message has been set, override the default that we + // display. + if msg := dconfig.CLIUpgradeMessage; msg != "" { + warning = fmt.Sprint(pretty.Sprint(warn, msg)) + } - if !buildinfo.VersionsMatch(clientVersion, info.Version) { - warn := cliui.DefaultStyles.Warn - _, _ = fmt.Fprintf(i.Stderr, pretty.Sprint(warn, fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v")) + if !buildinfo.VersionsMatch(clientVersion, info.Version) || forceCheck { + _, _ = fmt.Fprint(i.Stderr, warning) _, _ = fmt.Fprintln(i.Stderr) } diff --git a/cli/root_internal_test.go b/cli/root_internal_test.go index 2d99ab8247518..d6c95a82f2827 100644 --- a/cli/root_internal_test.go +++ b/cli/root_internal_test.go @@ -1,12 +1,19 @@ package cli import ( + "bytes" + "fmt" "os" "runtime" "testing" "github.com/stretchr/testify/require" "go.uber.org/goleak" + + "github.com/coder/coder/v2/cli/clibase" + "github.com/coder/coder/v2/cli/cliui" + "github.com/coder/coder/v2/coderd/coderdtest" + "github.com/coder/pretty" ) func Test_formatExamples(t *testing.T) { @@ -84,3 +91,41 @@ func TestMain(m *testing.M) { goleak.IgnoreTopFunction("github.com/lib/pq.NewDialListener"), ) } + +func Test_checkVersions(t *testing.T) { + t.Parallel() + + t.Run("CustomInstallMessage", func(t *testing.T) { + t.Parallel() + + var ( + expectedUpgradeMessage = "My custom upgrade message" + dv = coderdtest.DeploymentValues(t) + ) + dv.CLIUpgradeMessage = clibase.String(expectedUpgradeMessage) + + ownerClient := coderdtest.New(t, &coderdtest.Options{ + DeploymentValues: dv, + }) + owner := coderdtest.CreateFirstUser(t, ownerClient) + + // Create an unprivileged user to ensure the message can be printed + // to any Coder user. + memberClient, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) + + r := &RootCmd{} + + cmd, err := r.Command(nil) + require.NoError(t, err) + + var buf bytes.Buffer + inv := cmd.Invoke() + inv.Stderr = &buf + + err = r.checkVersions(inv, memberClient, true) + require.NoError(t, err) + + expectedOutput := fmt.Sprintln(pretty.Sprint(cliui.DefaultStyles.Warn, expectedUpgradeMessage)) + require.Equal(t, expectedOutput, buf.String()) + }) +} diff --git a/cli/root_test.go b/cli/root_test.go index ff564e5858529..aeaa7399d06b3 100644 --- a/cli/root_test.go +++ b/cli/root_test.go @@ -105,6 +105,31 @@ func TestRoot(t *testing.T) { require.ErrorContains(t, err, "unexpected status code 410") require.EqualValues(t, 1, atomic.LoadInt64(&called), "called exactly once") }) + + t.Run("VersionMismatchWarning", func(t *testing.T) { + t.Parallel() + + var ( + expectedUpgradeMessage = "My custom upgrade message" + dv = coderdtest.DeploymentValues(t) + ) + dv.CLIUpgradeMessage = clibase.String(expectedUpgradeMessage) + + client := coderdtest.New(t, &coderdtest.Options{ + DeploymentValues: dv, + }) + + _ = coderdtest.CreateFirstUser(t, client) + + inv, root := clitest.New(t, "ls") + clitest.SetupConfig(t, client, root) + + var buf bytes.Buffer + inv.Stderr = &buf + err := inv.Run() + require.NoError(t, err) + fmt.Println("output: ", buf.String()) + }) } // TestDERPHeaders ensures that the client sends the global `--header`s and diff --git a/coderd/coderd.go b/coderd/coderd.go index 3e04e6a7dbd88..15b7ec573f4e3 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -653,6 +653,7 @@ func New(options *Options) *API { r.Get("/config", api.deploymentValues) r.Get("/stats", api.deploymentStats) r.Get("/ssh", api.sshConfig) + r.Get("/unprivileged", api.unprivilegedConfig) }) r.Route("/experiments", func(r chi.Router) { r.Use(apiKeyMiddleware) diff --git a/coderd/deployment.go b/coderd/deployment.go index af6955cef0828..894563d5d83d2 100644 --- a/coderd/deployment.go +++ b/coderd/deployment.go @@ -90,3 +90,10 @@ func buildInfo(accessURL *url.URL) http.HandlerFunc { func (api *API) sshConfig(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, api.SSHConfig) } + +func (api *API) unprivilegedConfig(rw http.ResponseWriter, r *http.Request) { + httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.UnprivilegedDeploymentConfig{ + SSHConfig: api.SSHConfig, + CLIUpgradeMessage: api.DeploymentValues.CLIUpgradeMessage.String(), + }) +} diff --git a/coderd/externalauth/externalauth.go b/coderd/externalauth/externalauth.go index 5472025d93291..e73e35259a9ad 100644 --- a/coderd/externalauth/externalauth.go +++ b/coderd/externalauth/externalauth.go @@ -325,7 +325,7 @@ func (c *DeviceAuth) AuthorizeDevice(ctx context.Context) (*codersdk.ExternalAut // return a better error. switch resp.StatusCode { case http.StatusTooManyRequests: - return nil, fmt.Errorf("rate limit hit, unable to authorize device. please try again later") + return nil, xerrors.New("rate limit hit, unable to authorize device. please try again later") default: return nil, err } diff --git a/coderd/httpapi/websocket.go b/coderd/httpapi/websocket.go index ad3b4b277dff4..629dcac8131f3 100644 --- a/coderd/httpapi/websocket.go +++ b/coderd/httpapi/websocket.go @@ -4,8 +4,9 @@ import ( "context" "time" - "cdr.dev/slog" "nhooyr.io/websocket" + + "cdr.dev/slog" ) // Heartbeat loops to ping a WebSocket to keep it alive. diff --git a/coderd/promoauth/github.go b/coderd/promoauth/github.go index 7acbdb725592c..3f2a97d241b7f 100644 --- a/coderd/promoauth/github.go +++ b/coderd/promoauth/github.go @@ -1,10 +1,11 @@ package promoauth import ( - "fmt" "net/http" "strconv" "time" + + "golang.org/x/xerrors" ) type rateLimits struct { @@ -81,7 +82,7 @@ func (p *headerParser) string(key string) string { v := p.header.Get(key) if v == "" { - p.errors[key] = fmt.Errorf("missing header %q", key) + p.errors[key] = xerrors.Errorf("missing header %q", key) } return v } diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 5ee0ce478ca8a..6941b8bc00484 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -187,6 +187,7 @@ type DeploymentValues struct { WebTerminalRenderer clibase.String `json:"web_terminal_renderer,omitempty" typescript:",notnull"` AllowWorkspaceRenames clibase.Bool `json:"allow_workspace_renames,omitempty" typescript:",notnull"` Healthcheck HealthcheckConfig `json:"healthcheck,omitempty" typescript:",notnull"` + CLIUpgradeMessage clibase.String `json:"cli_upgrade_message,omitempty" typescript:",notnull"` Config clibase.YAMLConfigPath `json:"config,omitempty" typescript:",notnull"` WriteConfig clibase.Bool `json:"write_config,omitempty" typescript:",notnull"` @@ -1767,6 +1768,16 @@ when required by your organization's security policy.`, Value: &c.SSHConfig.SSHConfigOptions, Hidden: false, }, + { + Name: "CLI Upgrade Message", + Description: "The upgrade message to display to users when a client/server mismatch is detected. By default it instructs users to update using 'curl -L https://coder.com/install.sh | sh'.", + Flag: "cli-upgrade-messsage", + Env: "CODER_CLI_UPGRADE_MESSAGE", + YAML: "cliUpgradeMessage", + Group: &deploymentGroupClient, + Value: &c.CLIUpgradeMessage, + Hidden: false, + }, { Name: "Write Config", Description: ` @@ -2073,6 +2084,28 @@ func (c *Client) BuildInfo(ctx context.Context) (BuildInfoResponse, error) { return buildInfo, json.NewDecoder(res.Body).Decode(&buildInfo) } +type UnprivilegedDeploymentConfig struct { + SSHConfig SSHConfigResponse `json:"ssh_config"` + CLIUpgradeMessage string `json:"cli_upgrade_message"` +} + +// UnprivilegedDeploymentConfig returns unsensitive config values +// accessible by an ordinary, unprivileged user. +func (c *Client) UnprivilegedDeploymentConfig(ctx context.Context) (UnprivilegedDeploymentConfig, error) { + res, err := c.Request(ctx, http.MethodGet, "/api/v2/deployment/unprivileged", nil) + if err != nil { + return UnprivilegedDeploymentConfig{}, err + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return UnprivilegedDeploymentConfig{}, ReadBodyAsError(res) + } + + var config UnprivilegedDeploymentConfig + return config, json.NewDecoder(res.Body).Decode(&config) +} + type Experiment string const ( From b2a0b8bd7233fbd1e9b7716fee8e7558d8e47d3f Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Fri, 12 Jan 2024 00:20:36 +0000 Subject: [PATCH 02/17] make gen --- coderd/apidoc/docs.go | 39 ++++++++++++++++++++++++++++++++++ coderd/apidoc/swagger.json | 35 ++++++++++++++++++++++++++++++ coderd/deployment.go | 7 ++++++ docs/api/general.md | 39 ++++++++++++++++++++++++++++++++++ docs/api/schemas.md | 25 ++++++++++++++++++++++ docs/cli/server.md | 10 +++++++++ site/src/api/typesGenerated.ts | 7 ++++++ 7 files changed, 162 insertions(+) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 1fcdd45da7381..66ce19d721312 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -648,6 +648,31 @@ const docTemplate = `{ } } }, + "/deployment/unprivileged": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "General" + ], + "summary": "Unprivileged deployment config.", + "operationId": "unprivileged-deployment-config", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.UnprivilegedDeploymentConfig" + } + } + } + } + }, "/derp-map": { "get": { "security": [ @@ -8874,6 +8899,9 @@ const docTemplate = `{ "cache_directory": { "type": "string" }, + "cli_upgrade_message": { + "type": "string" + }, "config": { "type": "string" }, @@ -11354,6 +11382,17 @@ const docTemplate = `{ } } }, + "codersdk.UnprivilegedDeploymentConfig": { + "type": "object", + "properties": { + "cli_upgrade_message": { + "type": "string" + }, + "ssh_config": { + "$ref": "#/definitions/codersdk.SSHConfigResponse" + } + } + }, "codersdk.UpdateActiveTemplateVersion": { "type": "object", "required": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index cbf49d80568b6..e5c23dbfc06ff 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -552,6 +552,27 @@ } } }, + "/deployment/unprivileged": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["General"], + "summary": "Unprivileged deployment config.", + "operationId": "unprivileged-deployment-config", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.UnprivilegedDeploymentConfig" + } + } + } + } + }, "/derp-map": { "get": { "security": [ @@ -7924,6 +7945,9 @@ "cache_directory": { "type": "string" }, + "cli_upgrade_message": { + "type": "string" + }, "config": { "type": "string" }, @@ -10273,6 +10297,17 @@ } } }, + "codersdk.UnprivilegedDeploymentConfig": { + "type": "object", + "properties": { + "cli_upgrade_message": { + "type": "string" + }, + "ssh_config": { + "$ref": "#/definitions/codersdk.SSHConfigResponse" + } + } + }, "codersdk.UpdateActiveTemplateVersion": { "type": "object", "required": ["id"], diff --git a/coderd/deployment.go b/coderd/deployment.go index 894563d5d83d2..c095985b51fb4 100644 --- a/coderd/deployment.go +++ b/coderd/deployment.go @@ -91,6 +91,13 @@ func (api *API) sshConfig(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, api.SSHConfig) } +// @Summary Unprivileged deployment config. +// @ID unprivileged-deployment-config +// @Security CoderSessionToken +// @Produce json +// @Tags General +// @Success 200 {object} codersdk.UnprivilegedDeploymentConfig +// @Router /deployment/unprivileged [get] func (api *API) unprivilegedConfig(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.UnprivilegedDeploymentConfig{ SSHConfig: api.SSHConfig, diff --git a/docs/api/general.md b/docs/api/general.md index 303b36a1a26d6..d8134f5f06f24 100644 --- a/docs/api/general.md +++ b/docs/api/general.md @@ -157,6 +157,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ "autobuild_poll_interval": 0, "browser_only": true, "cache_directory": "string", + "cli_upgrade_message": "string", "config": "string", "config_ssh": { "deploymentName": "string", @@ -545,6 +546,44 @@ curl -X GET http://coder-server:8080/api/v2/deployment/stats \ To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Unprivileged deployment config. + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/deployment/unprivileged \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /deployment/unprivileged` + +### Example responses + +> 200 Response + +```json +{ + "cli_upgrade_message": "string", + "ssh_config": { + "hostname_prefix": "string", + "ssh_config_options": { + "property1": "string", + "property2": "string" + } + } +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.UnprivilegedDeploymentConfig](schemas.md#codersdkunprivilegeddeploymentconfig) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## Get enabled experiments ### Code samples diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 6e4df6d796cdc..d5382590e316b 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -2091,6 +2091,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "autobuild_poll_interval": 0, "browser_only": true, "cache_directory": "string", + "cli_upgrade_message": "string", "config": "string", "config_ssh": { "deploymentName": "string", @@ -2469,6 +2470,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "autobuild_poll_interval": 0, "browser_only": true, "cache_directory": "string", + "cli_upgrade_message": "string", "config": "string", "config_ssh": { "deploymentName": "string", @@ -2742,6 +2744,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `autobuild_poll_interval` | integer | false | | | | `browser_only` | boolean | false | | | | `cache_directory` | string | false | | | +| `cli_upgrade_message` | string | false | | | | `config` | string | false | | | | `config_ssh` | [codersdk.SSHConfig](#codersdksshconfig) | false | | | | `dangerous` | [codersdk.DangerousConfig](#codersdkdangerousconfig) | false | | | @@ -5278,6 +5281,28 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `p50` | integer | false | | | | `p95` | integer | false | | | +## codersdk.UnprivilegedDeploymentConfig + +```json +{ + "cli_upgrade_message": "string", + "ssh_config": { + "hostname_prefix": "string", + "ssh_config_options": { + "property1": "string", + "property2": "string" + } + } +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| --------------------- | -------------------------------------------------------- | -------- | ------------ | ----------- | +| `cli_upgrade_message` | string | false | | | +| `ssh_config` | [codersdk.SSHConfigResponse](#codersdksshconfigresponse) | false | | | + ## codersdk.UpdateActiveTemplateVersion ```json diff --git a/docs/cli/server.md b/docs/cli/server.md index a0c4aad6e97ba..8e3828701b686 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -73,6 +73,16 @@ Block peer-to-peer (aka. direct) workspace connections. All workspace connection Whether Coder only allows connections to workspaces via the browser. +### --cli-upgrade-messsage + +| | | +| ----------- | --------------------------------------- | +| Type | string | +| Environment | $CODER_CLI_UPGRADE_MESSAGE | +| YAML | client.cliUpgradeMessage | + +The upgrade message to display to users when a client/server mismatch is detected. By default it instructs users to update using 'curl -L https://coder.com/install.sh | sh'. + ### --cache-dir | | | diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index a5a7663d0de9f..7b7ebfe5d469e 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -426,6 +426,7 @@ export interface DeploymentValues { readonly web_terminal_renderer?: string; readonly allow_workspace_renames?: boolean; readonly healthcheck?: HealthcheckConfig; + readonly cli_upgrade_message?: string; readonly config?: string; readonly write_config?: boolean; readonly address?: string; @@ -1210,6 +1211,12 @@ export interface TransitionStats { readonly P95?: number; } +// From codersdk/deployment.go +export interface UnprivilegedDeploymentConfig { + readonly ssh_config: SSHConfigResponse; + readonly cli_upgrade_message: string; +} + // From codersdk/templates.go export interface UpdateActiveTemplateVersion { readonly id: string; From d3fb0b8be797b41c6e4128f3320c3a867bb53de9 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Fri, 12 Jan 2024 00:33:03 +0000 Subject: [PATCH 03/17] typo --- codersdk/deployment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 6941b8bc00484..d462115b6290d 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -1771,7 +1771,7 @@ when required by your organization's security policy.`, { Name: "CLI Upgrade Message", Description: "The upgrade message to display to users when a client/server mismatch is detected. By default it instructs users to update using 'curl -L https://coder.com/install.sh | sh'.", - Flag: "cli-upgrade-messsage", + Flag: "cli-upgrade-message", Env: "CODER_CLI_UPGRADE_MESSAGE", YAML: "cliUpgradeMessage", Group: &deploymentGroupClient, From d5cf4e196ad0b447787998ff82b5f7ac6991f1da Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Fri, 12 Jan 2024 00:34:22 +0000 Subject: [PATCH 04/17] golden --- cli/testdata/coder_server_--help.golden | 5 +++++ cli/testdata/server-config.yaml.golden | 5 +++++ enterprise/cli/testdata/coder_server_--help.golden | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden index 5f8cd85a84e2f..67ed443566a22 100644 --- a/cli/testdata/coder_server_--help.golden +++ b/cli/testdata/coder_server_--help.golden @@ -62,6 +62,11 @@ CLIENT OPTIONS: These options change the behavior of how clients interact with the Coder. Clients include the coder cli, vs code extension, and the web UI. + --cli-upgrade-message string, $CODER_CLI_UPGRADE_MESSAGE + The upgrade message to display to users when a client/server mismatch + is detected. By default it instructs users to update using 'curl -L + https://coder.com/install.sh | sh'. + --ssh-config-options string-array, $CODER_SSH_CONFIG_OPTIONS These SSH config options will override the default SSH config options. Provide options in "key=value" or "key value" format separated by diff --git a/cli/testdata/server-config.yaml.golden b/cli/testdata/server-config.yaml.golden index af026023f634a..818d62c854915 100644 --- a/cli/testdata/server-config.yaml.golden +++ b/cli/testdata/server-config.yaml.golden @@ -433,6 +433,11 @@ client: # incorrectly can break SSH to your deployment, use cautiously. # (default: , type: string-array) sshConfigOptions: [] + # The upgrade message to display to users when a client/server mismatch is + # detected. By default it instructs users to update using 'curl -L + # https://coder.com/install.sh | sh'. + # (default: , type: string) + cliUpgradeMessage: "" # The renderer to use when opening a web terminal. Valid values are 'canvas', # 'webgl', or 'dom'. # (default: canvas, type: string) diff --git a/enterprise/cli/testdata/coder_server_--help.golden b/enterprise/cli/testdata/coder_server_--help.golden index 0df1bec5bb35d..eaf24bf345758 100644 --- a/enterprise/cli/testdata/coder_server_--help.golden +++ b/enterprise/cli/testdata/coder_server_--help.golden @@ -63,6 +63,11 @@ CLIENT OPTIONS: These options change the behavior of how clients interact with the Coder. Clients include the coder cli, vs code extension, and the web UI. + --cli-upgrade-message string, $CODER_CLI_UPGRADE_MESSAGE + The upgrade message to display to users when a client/server mismatch + is detected. By default it instructs users to update using 'curl -L + https://coder.com/install.sh | sh'. + --ssh-config-options string-array, $CODER_SSH_CONFIG_OPTIONS These SSH config options will override the default SSH config options. Provide options in "key=value" or "key value" format separated by From 8e6385a98c74c332bd53f244a1708a8303c5c96a Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Fri, 12 Jan 2024 00:36:05 +0000 Subject: [PATCH 05/17] delete cruft --- cli/root_test.go | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/cli/root_test.go b/cli/root_test.go index aeaa7399d06b3..ff564e5858529 100644 --- a/cli/root_test.go +++ b/cli/root_test.go @@ -105,31 +105,6 @@ func TestRoot(t *testing.T) { require.ErrorContains(t, err, "unexpected status code 410") require.EqualValues(t, 1, atomic.LoadInt64(&called), "called exactly once") }) - - t.Run("VersionMismatchWarning", func(t *testing.T) { - t.Parallel() - - var ( - expectedUpgradeMessage = "My custom upgrade message" - dv = coderdtest.DeploymentValues(t) - ) - dv.CLIUpgradeMessage = clibase.String(expectedUpgradeMessage) - - client := coderdtest.New(t, &coderdtest.Options{ - DeploymentValues: dv, - }) - - _ = coderdtest.CreateFirstUser(t, client) - - inv, root := clitest.New(t, "ls") - clitest.SetupConfig(t, client, root) - - var buf bytes.Buffer - inv.Stderr = &buf - err := inv.Run() - require.NoError(t, err) - fmt.Println("output: ", buf.String()) - }) } // TestDERPHeaders ensures that the client sends the global `--header`s and From d1612872a68706a8194d2f8c0180d20331279f32 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 16 Jan 2024 21:11:07 +0000 Subject: [PATCH 06/17] make gen --- docs/cli/server.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli/server.md b/docs/cli/server.md index 8e3828701b686..e2b701df1aaac 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -73,7 +73,7 @@ Block peer-to-peer (aka. direct) workspace connections. All workspace connection Whether Coder only allows connections to workspaces via the browser. -### --cli-upgrade-messsage +### --cli-upgrade-message | | | | ----------- | --------------------------------------- | From 61bef0aa3be673a9670beeb4af2b0baa26add1da Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Mon, 29 Jan 2024 22:55:08 +0000 Subject: [PATCH 07/17] pr comments --- cli/root.go | 13 +++---------- coderd/agentapi/servicebanner_internal_test.go | 3 ++- coderd/coderd.go | 3 +-- coderd/deployment.go | 17 ++--------------- codersdk/deployment.go | 17 +++++++++++++++++ 5 files changed, 25 insertions(+), 28 deletions(-) diff --git a/cli/root.go b/cli/root.go index 4f84b5abb3499..95f7481dc5089 100644 --- a/cli/root.go +++ b/cli/root.go @@ -840,17 +840,10 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client, return xerrors.Errorf("deployment config: %w", err) } - fmtWarningText := `version mismatch: client %s, server %s -` - // Our installation script doesn't work on Windows, so instead we direct the user - // to the GitHub release page to download the latest installer. - if runtime.GOOS == "windows" { - fmtWarningText += `download the server version from: https://github.com/coder/coder/releases/v%s` - } else { - fmtWarningText += `download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version %s'` - } + fmtWarningText := "version mismatch: client %s, server %s\n%s" + warn := cliui.DefaultStyles.Warn - warning := fmt.Sprintf(pretty.Sprint(warn, fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v")) + warning := fmt.Sprintf(pretty.Sprint(warn, fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v"), info.UpgradeMessage) // If a custom upgrade message has been set, override the default that we // display. diff --git a/coderd/agentapi/servicebanner_internal_test.go b/coderd/agentapi/servicebanner_internal_test.go index d559bf08604b2..c7b14f6383975 100644 --- a/coderd/agentapi/servicebanner_internal_test.go +++ b/coderd/agentapi/servicebanner_internal_test.go @@ -7,10 +7,11 @@ import ( "golang.org/x/xerrors" + "github.com/stretchr/testify/require" + agentproto "github.com/coder/coder/v2/agent/proto" "github.com/coder/coder/v2/coderd/appearance" "github.com/coder/coder/v2/codersdk" - "github.com/stretchr/testify/require" ) func TestGetServiceBanner(t *testing.T) { diff --git a/coderd/coderd.go b/coderd/coderd.go index 0181724138d1f..59cf69716cbf0 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -647,7 +647,7 @@ func New(options *Options) *API { // All CSP errors will be logged r.Post("/csp/reports", api.logReportCSPViolations) - r.Get("/buildinfo", buildInfo(api.AccessURL)) + r.Get("/buildinfo", buildInfo(api.AccessURL, api.DeploymentValues.CLIUpgradeMessage.String())) // /regions is overridden in the enterprise version r.Group(func(r chi.Router) { r.Use(apiKeyMiddleware) @@ -662,7 +662,6 @@ func New(options *Options) *API { r.Get("/config", api.deploymentValues) r.Get("/stats", api.deploymentStats) r.Get("/ssh", api.sshConfig) - r.Get("/unprivileged", api.unprivilegedConfig) }) r.Route("/experiments", func(r chi.Router) { r.Use(apiKeyMiddleware) diff --git a/coderd/deployment.go b/coderd/deployment.go index c095985b51fb4..22bd555b28f45 100644 --- a/coderd/deployment.go +++ b/coderd/deployment.go @@ -68,7 +68,7 @@ func (api *API) deploymentStats(rw http.ResponseWriter, r *http.Request) { // @Tags General // @Success 200 {object} codersdk.BuildInfoResponse // @Router /buildinfo [get] -func buildInfo(accessURL *url.URL) http.HandlerFunc { +func buildInfo(accessURL *url.URL, upgradeMessage string) http.HandlerFunc { return func(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.BuildInfoResponse{ ExternalURL: buildinfo.ExternalURL(), @@ -76,6 +76,7 @@ func buildInfo(accessURL *url.URL) http.HandlerFunc { AgentAPIVersion: AgentAPIVersionREST, DashboardURL: accessURL.String(), WorkspaceProxy: false, + UpgradeMessage: upgradeMessage, }) } } @@ -90,17 +91,3 @@ func buildInfo(accessURL *url.URL) http.HandlerFunc { func (api *API) sshConfig(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, api.SSHConfig) } - -// @Summary Unprivileged deployment config. -// @ID unprivileged-deployment-config -// @Security CoderSessionToken -// @Produce json -// @Tags General -// @Success 200 {object} codersdk.UnprivilegedDeploymentConfig -// @Router /deployment/unprivileged [get] -func (api *API) unprivilegedConfig(rw http.ResponseWriter, r *http.Request) { - httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.UnprivilegedDeploymentConfig{ - SSHConfig: api.SSHConfig, - CLIUpgradeMessage: api.DeploymentValues.CLIUpgradeMessage.String(), - }) -} diff --git a/codersdk/deployment.go b/codersdk/deployment.go index e1eb0ac1da24a..f1da535ea2bc6 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -4,9 +4,11 @@ import ( "context" "encoding/json" "flag" + "fmt" "net/http" "os" "path/filepath" + "runtime" "strconv" "strings" "time" @@ -1789,6 +1791,7 @@ when required by your organization's security policy.`, YAML: "cliUpgradeMessage", Group: &deploymentGroupClient, Value: &c.CLIUpgradeMessage, + Default: defaultUpgradeMessage(), Hidden: false, }, { @@ -2063,6 +2066,10 @@ type BuildInfoResponse struct { // AgentAPIVersion is the current version of the Agent API (back versions // MAY still be supported). AgentAPIVersion string `json:"agent_api_version"` + + // UpgradeMessage is the message displayed to users when an outdated client + // is detected. + UpgradeMessage string `json:"upgrade_message"` } type WorkspaceProxyBuildInfo struct { @@ -2320,3 +2327,13 @@ func (c *Client) SSHConfiguration(ctx context.Context) (SSHConfigResponse, error var sshConfig SSHConfigResponse return sshConfig, json.NewDecoder(res.Body).Decode(&sshConfig) } + +func defaultUpgradeMessage() string { + // Our installation script doesn't work on Windows, so instead we direct the user + // to the GitHub release page to download the latest installer. + version := buildinfo.Version() + if runtime.GOOS == "windows" { + return fmt.Sprintf("download the server version from: https://github.com/coder/coder/releases/v%s", version) + } + return fmt.Sprintf("download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version %s'", version) +} From 460f8cf2cd164175eafc025223005d067e3c68b4 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Mon, 29 Jan 2024 22:56:28 +0000 Subject: [PATCH 08/17] make gen --- cli/testdata/coder_list_--output_json.golden | 1 + cli/testdata/coder_server_--help.golden | 2 +- .../coder_users_list_--output_json.golden | 1 + cli/testdata/server-config.yaml.golden | 5 ++- coderd/apidoc/docs.go | 40 ++----------------- coderd/apidoc/swagger.json | 36 ++--------------- docs/api/general.md | 39 +----------------- docs/api/schemas.md | 24 +---------- docs/cli/server.md | 11 ++--- .../cli/testdata/coder_server_--help.golden | 2 +- site/src/api/typesGenerated.ts | 1 + 11 files changed, 25 insertions(+), 137 deletions(-) diff --git a/cli/testdata/coder_list_--output_json.golden b/cli/testdata/coder_list_--output_json.golden index 319ac80c1554c..a3a346e93d330 100644 --- a/cli/testdata/coder_list_--output_json.golden +++ b/cli/testdata/coder_list_--output_json.golden @@ -1,3 +1,4 @@ +check versions error: deployment config: GET http://localhost:36329/api/v2/deployment/unprivileged: unexpected status code 404: Route not found. [ { "id": "[workspace ID]", diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden index 8d420da29b1e7..b74f809224495 100644 --- a/cli/testdata/coder_server_--help.golden +++ b/cli/testdata/coder_server_--help.golden @@ -65,7 +65,7 @@ CLIENT OPTIONS: These options change the behavior of how clients interact with the Coder. Clients include the coder cli, vs code extension, and the web UI. - --cli-upgrade-message string, $CODER_CLI_UPGRADE_MESSAGE + --cli-upgrade-message string, $CODER_CLI_UPGRADE_MESSAGE (default: download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version v0.0.0-devel') The upgrade message to display to users when a client/server mismatch is detected. By default it instructs users to update using 'curl -L https://coder.com/install.sh | sh'. diff --git a/cli/testdata/coder_users_list_--output_json.golden b/cli/testdata/coder_users_list_--output_json.golden index 1ec8f37cb5262..c817da0b7d7a4 100644 --- a/cli/testdata/coder_users_list_--output_json.golden +++ b/cli/testdata/coder_users_list_--output_json.golden @@ -1,3 +1,4 @@ +check versions error: deployment config: GET http://localhost:36329/api/v2/deployment/unprivileged: unexpected status code 404: Route not found. [ { "id": "[first user ID]", diff --git a/cli/testdata/server-config.yaml.golden b/cli/testdata/server-config.yaml.golden index 1c9372fad62dd..0c50dce4f14a6 100644 --- a/cli/testdata/server-config.yaml.golden +++ b/cli/testdata/server-config.yaml.golden @@ -436,8 +436,9 @@ client: # The upgrade message to display to users when a client/server mismatch is # detected. By default it instructs users to update using 'curl -L # https://coder.com/install.sh | sh'. - # (default: , type: string) - cliUpgradeMessage: "" + # (default: download the server version with: 'curl -L + # https://coder.com/install.sh | sh -s -- --version v0.0.0-devel', type: string) + cliUpgradeMessage: 'download the server version with: ''curl -L https://coder.com/install.sh | sh -s -- --version v0.0.0-devel''' # The renderer to use when opening a web terminal. Valid values are 'canvas', # 'webgl', or 'dom'. # (default: canvas, type: string) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index aafea3095a9f1..cd217ce41debd 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -648,31 +648,6 @@ const docTemplate = `{ } } }, - "/deployment/unprivileged": { - "get": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "General" - ], - "summary": "Unprivileged deployment config.", - "operationId": "unprivileged-deployment-config", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.UnprivilegedDeploymentConfig" - } - } - } - } - }, "/derp-map": { "get": { "security": [ @@ -8270,6 +8245,10 @@ const docTemplate = `{ "description": "ExternalURL references the current Coder version.\nFor production builds, this will link directly to a release. For development builds, this will link to a commit.", "type": "string" }, + "upgrade_message": { + "description": "UpgradeMessage is the message displayed to users when an outdated client\nis detected.", + "type": "string" + }, "version": { "description": "Version returns the semantic version of the build.", "type": "string" @@ -11498,17 +11477,6 @@ const docTemplate = `{ } } }, - "codersdk.UnprivilegedDeploymentConfig": { - "type": "object", - "properties": { - "cli_upgrade_message": { - "type": "string" - }, - "ssh_config": { - "$ref": "#/definitions/codersdk.SSHConfigResponse" - } - } - }, "codersdk.UpdateActiveTemplateVersion": { "type": "object", "required": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 4145f13f7fa44..fc1c8a909361d 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -552,27 +552,6 @@ } } }, - "/deployment/unprivileged": { - "get": { - "security": [ - { - "CoderSessionToken": [] - } - ], - "produces": ["application/json"], - "tags": ["General"], - "summary": "Unprivileged deployment config.", - "operationId": "unprivileged-deployment-config", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/codersdk.UnprivilegedDeploymentConfig" - } - } - } - } - }, "/derp-map": { "get": { "security": [ @@ -7365,6 +7344,10 @@ "description": "ExternalURL references the current Coder version.\nFor production builds, this will link directly to a release. For development builds, this will link to a commit.", "type": "string" }, + "upgrade_message": { + "description": "UpgradeMessage is the message displayed to users when an outdated client\nis detected.", + "type": "string" + }, "version": { "description": "Version returns the semantic version of the build.", "type": "string" @@ -10405,17 +10388,6 @@ } } }, - "codersdk.UnprivilegedDeploymentConfig": { - "type": "object", - "properties": { - "cli_upgrade_message": { - "type": "string" - }, - "ssh_config": { - "$ref": "#/definitions/codersdk.SSHConfigResponse" - } - } - }, "codersdk.UpdateActiveTemplateVersion": { "type": "object", "required": ["id"], diff --git a/docs/api/general.md b/docs/api/general.md index 7b4532e7ac730..1069a7d3328e5 100644 --- a/docs/api/general.md +++ b/docs/api/general.md @@ -56,6 +56,7 @@ curl -X GET http://coder-server:8080/api/v2/buildinfo \ "agent_api_version": "string", "dashboard_url": "string", "external_url": "string", + "upgrade_message": "string", "version": "string", "workspace_proxy": true } @@ -534,44 +535,6 @@ curl -X GET http://coder-server:8080/api/v2/deployment/stats \ To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Unprivileged deployment config. - -### Code samples - -```shell -# Example request using curl -curl -X GET http://coder-server:8080/api/v2/deployment/unprivileged \ - -H 'Accept: application/json' \ - -H 'Coder-Session-Token: API_KEY' -``` - -`GET /deployment/unprivileged` - -### Example responses - -> 200 Response - -```json -{ - "cli_upgrade_message": "string", - "ssh_config": { - "hostname_prefix": "string", - "ssh_config_options": { - "property1": "string", - "property2": "string" - } - } -} -``` - -### Responses - -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.UnprivilegedDeploymentConfig](schemas.md#codersdkunprivilegeddeploymentconfig) | - -To perform this operation, you must be authenticated. [Learn more](authentication.md). - ## Get enabled experiments ### Code samples diff --git a/docs/api/schemas.md b/docs/api/schemas.md index c4b8fd37c7e17..62aa77db4cb9a 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -1445,6 +1445,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "agent_api_version": "string", "dashboard_url": "string", "external_url": "string", + "upgrade_message": "string", "version": "string", "workspace_proxy": true } @@ -1457,6 +1458,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `agent_api_version` | string | false | | Agent api version is the current version of the Agent API (back versions MAY still be supported). | | `dashboard_url` | string | false | | Dashboard URL is the URL to hit the deployment's dashboard. For external workspace proxies, this is the coderd they are connected to. | | `external_url` | string | false | | External URL references the current Coder version. For production builds, this will link directly to a release. For development builds, this will link to a commit. | +| `upgrade_message` | string | false | | Upgrade message is the message displayed to users when an outdated client is detected. | | `version` | string | false | | Version returns the semantic version of the build. | | `workspace_proxy` | boolean | false | | | @@ -5333,28 +5335,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `p50` | integer | false | | | | `p95` | integer | false | | | -## codersdk.UnprivilegedDeploymentConfig - -```json -{ - "cli_upgrade_message": "string", - "ssh_config": { - "hostname_prefix": "string", - "ssh_config_options": { - "property1": "string", - "property2": "string" - } - } -} -``` - -### Properties - -| Name | Type | Required | Restrictions | Description | -| --------------------- | -------------------------------------------------------- | -------- | ------------ | ----------- | -| `cli_upgrade_message` | string | false | | | -| `ssh_config` | [codersdk.SSHConfigResponse](#codersdksshconfigresponse) | false | | | - ## codersdk.UpdateActiveTemplateVersion ```json diff --git a/docs/cli/server.md b/docs/cli/server.md index 2b649aa321847..9480207ad336a 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -75,11 +75,12 @@ Whether Coder only allows connections to workspaces via the browser. ### --cli-upgrade-message -| | | -| ----------- | --------------------------------------- | -| Type | string | -| Environment | $CODER_CLI_UPGRADE_MESSAGE | -| YAML | client.cliUpgradeMessage | +| | | +| ----------- | ----------------------------------------------------------------------------- | --------------------------------------- | +| Type | string | +| Environment | $CODER_CLI_UPGRADE_MESSAGE | +| YAML | client.cliUpgradeMessage | +| Default | download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version v0.0.0-devel' | The upgrade message to display to users when a client/server mismatch is detected. By default it instructs users to update using 'curl -L https://coder.com/install.sh | sh'. diff --git a/enterprise/cli/testdata/coder_server_--help.golden b/enterprise/cli/testdata/coder_server_--help.golden index 5129aaed52b07..cbaa525d00ca8 100644 --- a/enterprise/cli/testdata/coder_server_--help.golden +++ b/enterprise/cli/testdata/coder_server_--help.golden @@ -66,7 +66,7 @@ CLIENT OPTIONS: These options change the behavior of how clients interact with the Coder. Clients include the coder cli, vs code extension, and the web UI. - --cli-upgrade-message string, $CODER_CLI_UPGRADE_MESSAGE + --cli-upgrade-message string, $CODER_CLI_UPGRADE_MESSAGE (default: download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version v0.0.0-devel') The upgrade message to display to users when a client/server mismatch is detected. By default it instructs users to update using 'curl -L https://coder.com/install.sh | sh'. diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index b7a5a016172d9..5ddda290d6d0c 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -163,6 +163,7 @@ export interface BuildInfoResponse { readonly dashboard_url: string; readonly workspace_proxy: boolean; readonly agent_api_version: string; + readonly upgrade_message: string; } // From codersdk/insights.go From 790cfc36eaa1f6e7611c0215b32ed3db64dd0c39 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Mon, 29 Jan 2024 23:01:23 +0000 Subject: [PATCH 09/17] update golden files --- cli/root.go | 15 ++----------- cli/testdata/coder_list_--output_json.golden | 1 - .../coder_users_list_--output_json.golden | 1 - codersdk/deployment.go | 22 ------------------- 4 files changed, 2 insertions(+), 37 deletions(-) diff --git a/cli/root.go b/cli/root.go index 95f7481dc5089..20f1606190ce3 100644 --- a/cli/root.go +++ b/cli/root.go @@ -835,21 +835,10 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client, return xerrors.Errorf("build info: %w", err) } - dconfig, err := client.UnprivilegedDeploymentConfig(ctx) - if err != nil { - return xerrors.Errorf("deployment config: %w", err) - } - fmtWarningText := "version mismatch: client %s, server %s\n%s" - warn := cliui.DefaultStyles.Warn - warning := fmt.Sprintf(pretty.Sprint(warn, fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v"), info.UpgradeMessage) - - // If a custom upgrade message has been set, override the default that we - // display. - if msg := dconfig.CLIUpgradeMessage; msg != "" { - warning = fmt.Sprint(pretty.Sprint(warn, msg)) - } + fmtWarn := pretty.Sprint(cliui.DefaultStyles.Warn, fmtWarningText) + warning := fmt.Sprintf(fmtWarn, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v"), info.UpgradeMessage) if !buildinfo.VersionsMatch(clientVersion, info.Version) || forceCheck { _, _ = fmt.Fprint(i.Stderr, warning) diff --git a/cli/testdata/coder_list_--output_json.golden b/cli/testdata/coder_list_--output_json.golden index a3a346e93d330..319ac80c1554c 100644 --- a/cli/testdata/coder_list_--output_json.golden +++ b/cli/testdata/coder_list_--output_json.golden @@ -1,4 +1,3 @@ -check versions error: deployment config: GET http://localhost:36329/api/v2/deployment/unprivileged: unexpected status code 404: Route not found. [ { "id": "[workspace ID]", diff --git a/cli/testdata/coder_users_list_--output_json.golden b/cli/testdata/coder_users_list_--output_json.golden index c817da0b7d7a4..1ec8f37cb5262 100644 --- a/cli/testdata/coder_users_list_--output_json.golden +++ b/cli/testdata/coder_users_list_--output_json.golden @@ -1,4 +1,3 @@ -check versions error: deployment config: GET http://localhost:36329/api/v2/deployment/unprivileged: unexpected status code 404: Route not found. [ { "id": "[first user ID]", diff --git a/codersdk/deployment.go b/codersdk/deployment.go index f1da535ea2bc6..79e920cdad76a 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -2104,28 +2104,6 @@ func (c *Client) BuildInfo(ctx context.Context) (BuildInfoResponse, error) { return buildInfo, json.NewDecoder(res.Body).Decode(&buildInfo) } -type UnprivilegedDeploymentConfig struct { - SSHConfig SSHConfigResponse `json:"ssh_config"` - CLIUpgradeMessage string `json:"cli_upgrade_message"` -} - -// UnprivilegedDeploymentConfig returns unsensitive config values -// accessible by an ordinary, unprivileged user. -func (c *Client) UnprivilegedDeploymentConfig(ctx context.Context) (UnprivilegedDeploymentConfig, error) { - res, err := c.Request(ctx, http.MethodGet, "/api/v2/deployment/unprivileged", nil) - if err != nil { - return UnprivilegedDeploymentConfig{}, err - } - defer res.Body.Close() - - if res.StatusCode != http.StatusOK { - return UnprivilegedDeploymentConfig{}, ReadBodyAsError(res) - } - - var config UnprivilegedDeploymentConfig - return config, json.NewDecoder(res.Body).Decode(&config) -} - type Experiment string const ( From 1749686243565282eb7bd4c2f7873ee83898d9b1 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 30 Jan 2024 01:21:33 +0000 Subject: [PATCH 10/17] pr comments --- cli/login.go | 3 ++- cli/root.go | 16 +++++++--------- cli/root_internal_test.go | 39 ++++++++++++++++++++++++++------------- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/cli/login.go b/cli/login.go index 8da78c7d44040..17cb206e1ef50 100644 --- a/cli/login.go +++ b/cli/login.go @@ -18,6 +18,7 @@ import ( "github.com/coder/pretty" + "github.com/coder/coder/v2/buildinfo" "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/userpassword" @@ -175,7 +176,7 @@ func (r *RootCmd) login() *clibase.Cmd { // Try to check the version of the server prior to logging in. // It may be useful to warn the user if they are trying to login // on a very old client. - err = r.checkVersions(inv, client, false) + err = r.checkVersions(inv, client, buildinfo.Version()) if err != nil { // Checking versions isn't a fatal error so we print a warning // and proceed. diff --git a/cli/root.go b/cli/root.go index 20f1606190ce3..6be3fa88e044b 100644 --- a/cli/root.go +++ b/cli/root.go @@ -602,7 +602,7 @@ func (r *RootCmd) PrintWarnings(client *codersdk.Client) clibase.MiddlewareFunc warningErr = make(chan error) ) go func() { - versionErr <- r.checkVersions(inv, client, false) + versionErr <- r.checkVersions(inv, client, buildinfo.Version()) close(versionErr) }() @@ -817,7 +817,7 @@ func formatExamples(examples ...example) string { // is detected. forceCheck is a test flag and should always be false in production. // //nolint:revive -func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client, forceCheck bool) error { +func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client, clientVersion string) error { if r.noVersionCheck { return nil } @@ -825,8 +825,7 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client, ctx, cancel := context.WithTimeout(i.Context(), 10*time.Second) defer cancel() - clientVersion := buildinfo.Version() - info, err := client.BuildInfo(ctx) + serverInfo, err := client.BuildInfo(ctx) // Avoid printing errors that are connection-related. if isConnectionError(err) { return nil @@ -835,12 +834,11 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client, return xerrors.Errorf("build info: %w", err) } - fmtWarningText := "version mismatch: client %s, server %s\n%s" + if !buildinfo.VersionsMatch(clientVersion, serverInfo.Version) { + fmtWarningText := "version mismatch: client %s, server %s\n%s" + fmtWarn := pretty.Sprint(cliui.DefaultStyles.Warn, fmtWarningText) + warning := fmt.Sprintf(fmtWarn, clientVersion, strings.TrimPrefix(serverInfo.CanonicalVersion(), "v"), serverInfo.UpgradeMessage) - fmtWarn := pretty.Sprint(cliui.DefaultStyles.Warn, fmtWarningText) - warning := fmt.Sprintf(fmtWarn, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v"), info.UpgradeMessage) - - if !buildinfo.VersionsMatch(clientVersion, info.Version) || forceCheck { _, _ = fmt.Fprint(i.Stderr, warning) _, _ = fmt.Fprintln(i.Stderr) } diff --git a/cli/root_internal_test.go b/cli/root_internal_test.go index d6c95a82f2827..d81f0b0aa52da 100644 --- a/cli/root_internal_test.go +++ b/cli/root_internal_test.go @@ -3,6 +3,9 @@ package cli import ( "bytes" "fmt" + "net/http" + "net/http/httptest" + "net/url" "os" "runtime" "testing" @@ -10,9 +13,11 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/goleak" - "github.com/coder/coder/v2/cli/clibase" + "github.com/coder/coder/v2/buildinfo" "github.com/coder/coder/v2/cli/cliui" - "github.com/coder/coder/v2/coderd/coderdtest" + "github.com/coder/coder/v2/coderd" + "github.com/coder/coder/v2/coderd/httpapi" + "github.com/coder/coder/v2/codersdk" "github.com/coder/pretty" ) @@ -100,18 +105,25 @@ func Test_checkVersions(t *testing.T) { var ( expectedUpgradeMessage = "My custom upgrade message" - dv = coderdtest.DeploymentValues(t) ) - dv.CLIUpgradeMessage = clibase.String(expectedUpgradeMessage) - ownerClient := coderdtest.New(t, &coderdtest.Options{ - DeploymentValues: dv, - }) - owner := coderdtest.CreateFirstUser(t, ownerClient) + srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.BuildInfoResponse{ + ExternalURL: buildinfo.ExternalURL(), + // Provide a version that will not match + Version: "v1.0.0", + AgentAPIVersion: coderd.AgentAPIVersionREST, + // does not matter what the url is + DashboardURL: "https://example.com", + WorkspaceProxy: false, + UpgradeMessage: expectedUpgradeMessage, + }) + })) + defer srv.Close() + surl, err := url.Parse(srv.URL) + require.NoError(t, err) - // Create an unprivileged user to ensure the message can be printed - // to any Coder user. - memberClient, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) + client := codersdk.New(surl) r := &RootCmd{} @@ -122,10 +134,11 @@ func Test_checkVersions(t *testing.T) { inv := cmd.Invoke() inv.Stderr = &buf - err = r.checkVersions(inv, memberClient, true) + err = r.checkVersions(inv, client, "v2.0.0") require.NoError(t, err) - expectedOutput := fmt.Sprintln(pretty.Sprint(cliui.DefaultStyles.Warn, expectedUpgradeMessage)) + fmtOutput := fmt.Sprintf("version mismatch: client v2.0.0, server 1.0.0\n%s", expectedUpgradeMessage) + expectedOutput := fmt.Sprintln(pretty.Sprint(cliui.DefaultStyles.Warn, fmtOutput)) require.Equal(t, expectedOutput, buf.String()) }) } From 0531bd341148a5116f5b2b0627a0711ef996c5e0 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 30 Jan 2024 01:26:44 +0000 Subject: [PATCH 11/17] fix default value --- cli/root.go | 17 +++++++++++++++- cli/root_internal_test.go | 41 ++++++++++++++++++++++++++++++++++++++- codersdk/deployment.go | 13 ------------- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/cli/root.go b/cli/root.go index 6be3fa88e044b..16eb47f6aa8ea 100644 --- a/cli/root.go +++ b/cli/root.go @@ -835,9 +835,14 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client, } if !buildinfo.VersionsMatch(clientVersion, serverInfo.Version) { + upgradeMessage := defaultUpgradeMessage() + if serverInfo.UpgradeMessage != "" { + upgradeMessage = serverInfo.UpgradeMessage + } + fmtWarningText := "version mismatch: client %s, server %s\n%s" fmtWarn := pretty.Sprint(cliui.DefaultStyles.Warn, fmtWarningText) - warning := fmt.Sprintf(fmtWarn, clientVersion, strings.TrimPrefix(serverInfo.CanonicalVersion(), "v"), serverInfo.UpgradeMessage) + warning := fmt.Sprintf(fmtWarn, clientVersion, strings.TrimPrefix(serverInfo.CanonicalVersion(), "v"), upgradeMessage) _, _ = fmt.Fprint(i.Stderr, warning) _, _ = fmt.Fprintln(i.Stderr) @@ -1212,3 +1217,13 @@ func SlimUnsupported(w io.Writer, cmd string) { //nolint:revive os.Exit(1) } + +func defaultUpgradeMessage() string { + // Our installation script doesn't work on Windows, so instead we direct the user + // to the GitHub release page to download the latest installer. + version := buildinfo.Version() + if runtime.GOOS == "windows" { + return fmt.Sprintf("download the server version from: https://github.com/coder/coder/releases/v%s", version) + } + return fmt.Sprintf("download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version %s'", version) +} diff --git a/cli/root_internal_test.go b/cli/root_internal_test.go index d81f0b0aa52da..1355fe65ce9e1 100644 --- a/cli/root_internal_test.go +++ b/cli/root_internal_test.go @@ -100,7 +100,7 @@ func TestMain(m *testing.M) { func Test_checkVersions(t *testing.T) { t.Parallel() - t.Run("CustomInstallMessage", func(t *testing.T) { + t.Run("CustomUpgradeMessage", func(t *testing.T) { t.Parallel() var ( @@ -141,4 +141,43 @@ func Test_checkVersions(t *testing.T) { expectedOutput := fmt.Sprintln(pretty.Sprint(cliui.DefaultStyles.Warn, fmtOutput)) require.Equal(t, expectedOutput, buf.String()) }) + + t.Run("DefaultUpgradeMessage", func(t *testing.T) { + t.Parallel() + + srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.BuildInfoResponse{ + ExternalURL: buildinfo.ExternalURL(), + // Provide a version that will not match + Version: "v1.0.0", + AgentAPIVersion: coderd.AgentAPIVersionREST, + // does not matter what the url is + DashboardURL: "https://example.com", + WorkspaceProxy: false, + UpgradeMessage: "", + }) + })) + defer srv.Close() + surl, err := url.Parse(srv.URL) + require.NoError(t, err) + + client := codersdk.New(surl) + + r := &RootCmd{} + + cmd, err := r.Command(nil) + require.NoError(t, err) + + var buf bytes.Buffer + inv := cmd.Invoke() + inv.Stderr = &buf + + err = r.checkVersions(inv, client, "v2.0.0") + require.NoError(t, err) + + fmtOutput := fmt.Sprintf("version mismatch: client v2.0.0, server 1.0.0\n%s", defaultUpgradeMessage()) + expectedOutput := fmt.Sprintln(pretty.Sprint(cliui.DefaultStyles.Warn, fmtOutput)) + require.Equal(t, expectedOutput, buf.String()) + }) + } diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 79e920cdad76a..c02eea595924f 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -4,11 +4,9 @@ import ( "context" "encoding/json" "flag" - "fmt" "net/http" "os" "path/filepath" - "runtime" "strconv" "strings" "time" @@ -1791,7 +1789,6 @@ when required by your organization's security policy.`, YAML: "cliUpgradeMessage", Group: &deploymentGroupClient, Value: &c.CLIUpgradeMessage, - Default: defaultUpgradeMessage(), Hidden: false, }, { @@ -2305,13 +2302,3 @@ func (c *Client) SSHConfiguration(ctx context.Context) (SSHConfigResponse, error var sshConfig SSHConfigResponse return sshConfig, json.NewDecoder(res.Body).Decode(&sshConfig) } - -func defaultUpgradeMessage() string { - // Our installation script doesn't work on Windows, so instead we direct the user - // to the GitHub release page to download the latest installer. - version := buildinfo.Version() - if runtime.GOOS == "windows" { - return fmt.Sprintf("download the server version from: https://github.com/coder/coder/releases/v%s", version) - } - return fmt.Sprintf("download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version %s'", version) -} From c9921fc5145dcd5f725cf15515196fc88ddc0d23 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 30 Jan 2024 01:32:33 +0000 Subject: [PATCH 12/17] lint --- cli/root_internal_test.go | 1 - docs/cli/server.md | 11 +++++------ site/src/api/typesGenerated.ts | 6 ------ site/src/testHelpers/entities.ts | 1 + 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/cli/root_internal_test.go b/cli/root_internal_test.go index 1355fe65ce9e1..fa086d9690fb8 100644 --- a/cli/root_internal_test.go +++ b/cli/root_internal_test.go @@ -179,5 +179,4 @@ func Test_checkVersions(t *testing.T) { expectedOutput := fmt.Sprintln(pretty.Sprint(cliui.DefaultStyles.Warn, fmtOutput)) require.Equal(t, expectedOutput, buf.String()) }) - } diff --git a/docs/cli/server.md b/docs/cli/server.md index 9480207ad336a..2b649aa321847 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -75,12 +75,11 @@ Whether Coder only allows connections to workspaces via the browser. ### --cli-upgrade-message -| | | -| ----------- | ----------------------------------------------------------------------------- | --------------------------------------- | -| Type | string | -| Environment | $CODER_CLI_UPGRADE_MESSAGE | -| YAML | client.cliUpgradeMessage | -| Default | download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version v0.0.0-devel' | +| | | +| ----------- | --------------------------------------- | +| Type | string | +| Environment | $CODER_CLI_UPGRADE_MESSAGE | +| YAML | client.cliUpgradeMessage | The upgrade message to display to users when a client/server mismatch is detected. By default it instructs users to update using 'curl -L https://coder.com/install.sh | sh'. diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 5ddda290d6d0c..d9bfd9fa3f5e5 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1232,12 +1232,6 @@ export interface TransitionStats { readonly P95?: number; } -// From codersdk/deployment.go -export interface UnprivilegedDeploymentConfig { - readonly ssh_config: SSHConfigResponse; - readonly cli_upgrade_message: string; -} - // From codersdk/templates.go export interface UpdateActiveTemplateVersion { readonly id: string; diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index e35a44b26cfff..00dd1d1d549cb 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -199,6 +199,7 @@ export const MockBuildInfo: TypesGen.BuildInfoResponse = { version: "v99.999.9999+c9cdf14", dashboard_url: "https:///mock-url", workspace_proxy: false, + upgrade_message: "My custom upgrade message", }; export const MockSupportLinks: TypesGen.LinkConfig[] = [ From d880b9ea50dcb886be937091d9f3d6d336e32b38 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 30 Jan 2024 01:35:29 +0000 Subject: [PATCH 13/17] fmt --- cli/root_internal_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cli/root_internal_test.go b/cli/root_internal_test.go index fa086d9690fb8..d981c25fed167 100644 --- a/cli/root_internal_test.go +++ b/cli/root_internal_test.go @@ -103,9 +103,7 @@ func Test_checkVersions(t *testing.T) { t.Run("CustomUpgradeMessage", func(t *testing.T) { t.Parallel() - var ( - expectedUpgradeMessage = "My custom upgrade message" - ) + expectedUpgradeMessage := "My custom upgrade message" srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.BuildInfoResponse{ From fc2c926e298c49ce7f985c9185e7b11fe5d7a948 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 30 Jan 2024 01:43:09 +0000 Subject: [PATCH 14/17] golden --- cli/testdata/coder_server_--help.golden | 2 +- cli/testdata/server-config.yaml.golden | 5 ++--- enterprise/cli/testdata/coder_server_--help.golden | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden index b74f809224495..8d420da29b1e7 100644 --- a/cli/testdata/coder_server_--help.golden +++ b/cli/testdata/coder_server_--help.golden @@ -65,7 +65,7 @@ CLIENT OPTIONS: These options change the behavior of how clients interact with the Coder. Clients include the coder cli, vs code extension, and the web UI. - --cli-upgrade-message string, $CODER_CLI_UPGRADE_MESSAGE (default: download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version v0.0.0-devel') + --cli-upgrade-message string, $CODER_CLI_UPGRADE_MESSAGE The upgrade message to display to users when a client/server mismatch is detected. By default it instructs users to update using 'curl -L https://coder.com/install.sh | sh'. diff --git a/cli/testdata/server-config.yaml.golden b/cli/testdata/server-config.yaml.golden index 0c50dce4f14a6..1c9372fad62dd 100644 --- a/cli/testdata/server-config.yaml.golden +++ b/cli/testdata/server-config.yaml.golden @@ -436,9 +436,8 @@ client: # The upgrade message to display to users when a client/server mismatch is # detected. By default it instructs users to update using 'curl -L # https://coder.com/install.sh | sh'. - # (default: download the server version with: 'curl -L - # https://coder.com/install.sh | sh -s -- --version v0.0.0-devel', type: string) - cliUpgradeMessage: 'download the server version with: ''curl -L https://coder.com/install.sh | sh -s -- --version v0.0.0-devel''' + # (default: , type: string) + cliUpgradeMessage: "" # The renderer to use when opening a web terminal. Valid values are 'canvas', # 'webgl', or 'dom'. # (default: canvas, type: string) diff --git a/enterprise/cli/testdata/coder_server_--help.golden b/enterprise/cli/testdata/coder_server_--help.golden index cbaa525d00ca8..5129aaed52b07 100644 --- a/enterprise/cli/testdata/coder_server_--help.golden +++ b/enterprise/cli/testdata/coder_server_--help.golden @@ -66,7 +66,7 @@ CLIENT OPTIONS: These options change the behavior of how clients interact with the Coder. Clients include the coder cli, vs code extension, and the web UI. - --cli-upgrade-message string, $CODER_CLI_UPGRADE_MESSAGE (default: download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version v0.0.0-devel') + --cli-upgrade-message string, $CODER_CLI_UPGRADE_MESSAGE The upgrade message to display to users when a client/server mismatch is detected. By default it instructs users to update using 'curl -L https://coder.com/install.sh | sh'. From 7b1be4366b47ca26b1030751566204068b4a888e Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 30 Jan 2024 21:59:41 +0000 Subject: [PATCH 15/17] fix version formatting --- cli/root.go | 11 +++++------ cli/root_internal_test.go | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cli/root.go b/cli/root.go index 16eb47f6aa8ea..b665e482410db 100644 --- a/cli/root.go +++ b/cli/root.go @@ -835,14 +835,14 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client, } if !buildinfo.VersionsMatch(clientVersion, serverInfo.Version) { - upgradeMessage := defaultUpgradeMessage() + upgradeMessage := defaultUpgradeMessage(strings.TrimPrefix(serverInfo.CanonicalVersion(), "v")) if serverInfo.UpgradeMessage != "" { upgradeMessage = serverInfo.UpgradeMessage } fmtWarningText := "version mismatch: client %s, server %s\n%s" fmtWarn := pretty.Sprint(cliui.DefaultStyles.Warn, fmtWarningText) - warning := fmt.Sprintf(fmtWarn, clientVersion, strings.TrimPrefix(serverInfo.CanonicalVersion(), "v"), upgradeMessage) + warning := fmt.Sprintf(fmtWarn, clientVersion, serverInfo.Version, upgradeMessage) _, _ = fmt.Fprint(i.Stderr, warning) _, _ = fmt.Fprintln(i.Stderr) @@ -1218,12 +1218,11 @@ func SlimUnsupported(w io.Writer, cmd string) { os.Exit(1) } -func defaultUpgradeMessage() string { +func defaultUpgradeMessage(serverVersion string) string { // Our installation script doesn't work on Windows, so instead we direct the user // to the GitHub release page to download the latest installer. - version := buildinfo.Version() if runtime.GOOS == "windows" { - return fmt.Sprintf("download the server version from: https://github.com/coder/coder/releases/v%s", version) + return fmt.Sprintf("download the server version from: https://github.com/coder/coder/releases/v%s", serverVersion) } - return fmt.Sprintf("download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version %s'", version) + return fmt.Sprintf("download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version %s'", serverVersion) } diff --git a/cli/root_internal_test.go b/cli/root_internal_test.go index d981c25fed167..2061ec7c474c5 100644 --- a/cli/root_internal_test.go +++ b/cli/root_internal_test.go @@ -135,7 +135,7 @@ func Test_checkVersions(t *testing.T) { err = r.checkVersions(inv, client, "v2.0.0") require.NoError(t, err) - fmtOutput := fmt.Sprintf("version mismatch: client v2.0.0, server 1.0.0\n%s", expectedUpgradeMessage) + fmtOutput := fmt.Sprintf("version mismatch: client v2.0.0, server v1.0.0\n%s", expectedUpgradeMessage) expectedOutput := fmt.Sprintln(pretty.Sprint(cliui.DefaultStyles.Warn, fmtOutput)) require.Equal(t, expectedOutput, buf.String()) }) @@ -173,7 +173,7 @@ func Test_checkVersions(t *testing.T) { err = r.checkVersions(inv, client, "v2.0.0") require.NoError(t, err) - fmtOutput := fmt.Sprintf("version mismatch: client v2.0.0, server 1.0.0\n%s", defaultUpgradeMessage()) + fmtOutput := fmt.Sprintf("version mismatch: client v2.0.0, server v1.0.0\n%s", defaultUpgradeMessage("1.0.0")) expectedOutput := fmt.Sprintln(pretty.Sprint(cliui.DefaultStyles.Warn, fmtOutput)) require.Equal(t, expectedOutput, buf.String()) }) From 423ab8be7ce8a5f6ff581c06f13a74a890568528 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 30 Jan 2024 22:04:17 +0000 Subject: [PATCH 16/17] move trimming into helper --- cli/root.go | 9 +++++---- cli/root_internal_test.go | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cli/root.go b/cli/root.go index b665e482410db..2bf01095573ee 100644 --- a/cli/root.go +++ b/cli/root.go @@ -835,7 +835,7 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client, } if !buildinfo.VersionsMatch(clientVersion, serverInfo.Version) { - upgradeMessage := defaultUpgradeMessage(strings.TrimPrefix(serverInfo.CanonicalVersion(), "v")) + upgradeMessage := defaultUpgradeMessage(serverInfo.CanonicalVersion()) if serverInfo.UpgradeMessage != "" { upgradeMessage = serverInfo.UpgradeMessage } @@ -1218,11 +1218,12 @@ func SlimUnsupported(w io.Writer, cmd string) { os.Exit(1) } -func defaultUpgradeMessage(serverVersion string) string { +func defaultUpgradeMessage(version string) string { // Our installation script doesn't work on Windows, so instead we direct the user // to the GitHub release page to download the latest installer. + version = strings.TrimPrefix(version, "v") if runtime.GOOS == "windows" { - return fmt.Sprintf("download the server version from: https://github.com/coder/coder/releases/v%s", serverVersion) + return fmt.Sprintf("download the server version from: https://github.com/coder/coder/releases/v%s", version) } - return fmt.Sprintf("download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version %s'", serverVersion) + return fmt.Sprintf("download the server version with: 'curl -L https://coder.com/install.sh | sh -s -- --version %s'", version) } diff --git a/cli/root_internal_test.go b/cli/root_internal_test.go index 2061ec7c474c5..6d108ee554e65 100644 --- a/cli/root_internal_test.go +++ b/cli/root_internal_test.go @@ -173,7 +173,7 @@ func Test_checkVersions(t *testing.T) { err = r.checkVersions(inv, client, "v2.0.0") require.NoError(t, err) - fmtOutput := fmt.Sprintf("version mismatch: client v2.0.0, server v1.0.0\n%s", defaultUpgradeMessage("1.0.0")) + fmtOutput := fmt.Sprintf("version mismatch: client v2.0.0, server v1.0.0\n%s", defaultUpgradeMessage("v1.0.0")) expectedOutput := fmt.Sprintln(pretty.Sprint(cliui.DefaultStyles.Warn, fmtOutput)) require.Equal(t, expectedOutput, buf.String()) }) From bf2dce1597129fce6a012b3c84484115cab97521 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 30 Jan 2024 22:09:55 +0000 Subject: [PATCH 17/17] fix merge --- coderd/agentapi/servicebanner_internal_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/coderd/agentapi/servicebanner_internal_test.go b/coderd/agentapi/servicebanner_internal_test.go index 0c80896de49d1..6098d7df5f3d9 100644 --- a/coderd/agentapi/servicebanner_internal_test.go +++ b/coderd/agentapi/servicebanner_internal_test.go @@ -8,8 +8,6 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/xerrors" - "github.com/stretchr/testify/require" - agentproto "github.com/coder/coder/v2/agent/proto" "github.com/coder/coder/v2/coderd/appearance" "github.com/coder/coder/v2/codersdk"