Skip to content

Commit a240245

Browse files
committed
Merge branch 'main' into 4-pause-1
2 parents 8f2d019 + ac6db5e commit a240245

File tree

15 files changed

+1180
-897
lines changed

15 files changed

+1180
-897
lines changed

.github/actions/setup-go/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: |
44
inputs:
55
version:
66
description: "The Go version to use."
7-
default: "1.22.4"
7+
default: "1.22.5"
88
runs:
99
using: "composite"
1010
steps:

.github/dependabot.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ updates:
3939
prefix: "chore"
4040
labels: []
4141
open-pull-requests-limit: 15
42+
groups:
43+
x:
44+
patterns:
45+
- "golang.org/x/*"
4246
ignore:
4347
# Ignore patch updates for all dependencies
4448
- dependency-name: "*"
@@ -73,6 +77,32 @@ updates:
7377
commit-message:
7478
prefix: "chore"
7579
labels: []
80+
groups:
81+
xterm:
82+
patterns:
83+
- "@xterm*"
84+
mui:
85+
patterns:
86+
- "@mui*"
87+
react:
88+
patterns:
89+
- "react*"
90+
- "@types/react*"
91+
emotion:
92+
patterns:
93+
- "@emotion*"
94+
eslint:
95+
patterns:
96+
- "eslint*"
97+
- "@typescript-eslint*"
98+
jest:
99+
patterns:
100+
- "jest*"
101+
- "@types/jest"
102+
vite:
103+
patterns:
104+
- "vite*"
105+
- "@vitejs/plugin-react"
76106
ignore:
77107
# Ignore patch updates for all dependencies
78108
- dependency-name: "*"
@@ -83,4 +113,10 @@ updates:
83113
- dependency-name: "@types/node"
84114
update-types:
85115
- version-update:semver-major
116+
# Ignore @storybook updates, run `pnpm dlx storybook@latest upgrade` to upgrade manually
117+
- dependency-name: "*storybook*" # matches @storybook/* and storybook*
118+
update-types:
119+
- version-update:semver-major
120+
- version-update:semver-minor
121+
- version-update:semver-patch
86122
open-pull-requests-limit: 15

cli/cliui/agent.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ func Agent(ctx context.Context, writer io.Writer, agentID uuid.UUID, opts AgentO
137137
stage += " (non-blocking)"
138138
}
139139
sw.Start(stage)
140+
if follow {
141+
sw.Log(time.Time{}, codersdk.LogLevelInfo, "==> ℹ︎ To connect immediately, reconnect with --wait=no or CODER_SSH_WAIT=no, see --help for more information.")
142+
}
140143

141144
err = func() error { // Use func because of defer in for loop.
142145
logStream, logsCloser, err := opts.FetchLogs(ctx, agent.ID, 0, follow)

cli/cliui/agent_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ func TestAgent(t *testing.T) {
226226
},
227227
want: []string{
228228
"⧗ Running workspace agent startup scripts",
229+
"ℹ︎ To connect immediately, reconnect with --wait=no or CODER_SSH_WAIT=no, see --help for more information.",
229230
"testing: Hello world",
230231
"Bye now",
231232
"✔ Running workspace agent startup scripts",
@@ -255,6 +256,7 @@ func TestAgent(t *testing.T) {
255256
},
256257
want: []string{
257258
"⧗ Running workspace agent startup scripts",
259+
"ℹ︎ To connect immediately, reconnect with --wait=no or CODER_SSH_WAIT=no, see --help for more information.",
258260
"Hello world",
259261
"✘ Running workspace agent startup scripts",
260262
"Warning: A startup script exited with an error and your workspace may be incomplete.",
@@ -306,6 +308,7 @@ func TestAgent(t *testing.T) {
306308
},
307309
want: []string{
308310
"⧗ Running workspace agent startup scripts",
311+
"ℹ︎ To connect immediately, reconnect with --wait=no or CODER_SSH_WAIT=no, see --help for more information.",
309312
"Hello world",
310313
"✔ Running workspace agent startup scripts",
311314
},

cli/configssh.go

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type sshConfigOptions struct {
5454
disableAutostart bool
5555
header []string
5656
headerCommand string
57+
removedKeys map[string]bool
5758
}
5859

5960
// addOptions expects options in the form of "option=value" or "option value".
@@ -74,30 +75,20 @@ func (o *sshConfigOptions) addOption(option string) error {
7475
if err != nil {
7576
return err
7677
}
77-
for i, existing := range o.sshOptions {
78-
// Override existing option if they share the same key.
79-
// This is case-insensitive. Parsing each time might be a little slow,
80-
// but it is ok.
81-
existingKey, _, err := codersdk.ParseSSHConfigOption(existing)
82-
if err != nil {
83-
// Don't mess with original values if there is an error.
84-
// This could have come from the user's manual edits.
85-
continue
86-
}
87-
if strings.EqualFold(existingKey, key) {
88-
if value == "" {
89-
// Delete existing option.
90-
o.sshOptions = append(o.sshOptions[:i], o.sshOptions[i+1:]...)
91-
} else {
92-
// Override existing option.
93-
o.sshOptions[i] = option
94-
}
95-
return nil
96-
}
78+
lowerKey := strings.ToLower(key)
79+
if o.removedKeys != nil && o.removedKeys[lowerKey] {
80+
// Key marked as removed, skip.
81+
return nil
9782
}
98-
// Only append the option if it is not empty.
83+
// Only append the option if it is not empty
84+
// (we interpret empty as removal).
9985
if value != "" {
10086
o.sshOptions = append(o.sshOptions, option)
87+
} else {
88+
if o.removedKeys == nil {
89+
o.removedKeys = make(map[string]bool)
90+
}
91+
o.removedKeys[lowerKey] = true
10192
}
10293
return nil
10394
}
@@ -245,6 +236,8 @@ func (r *RootCmd) configSSH() *serpent.Command {
245236
r.InitClient(client),
246237
),
247238
Handler: func(inv *serpent.Invocation) error {
239+
ctx := inv.Context()
240+
248241
if sshConfigOpts.waitEnum != "auto" && skipProxyCommand {
249242
// The wait option is applied to the ProxyCommand. If the user
250243
// specifies skip-proxy-command, then wait cannot be applied.
@@ -253,7 +246,14 @@ func (r *RootCmd) configSSH() *serpent.Command {
253246
sshConfigOpts.header = r.header
254247
sshConfigOpts.headerCommand = r.headerCommand
255248

256-
recvWorkspaceConfigs := sshPrepareWorkspaceConfigs(inv.Context(), client)
249+
// Talk to the API early to prevent the version mismatch
250+
// warning from being printed in the middle of a prompt.
251+
// This is needed because the asynchronous requests issued
252+
// by sshPrepareWorkspaceConfigs may otherwise trigger the
253+
// warning at any time.
254+
_, _ = client.BuildInfo(ctx)
255+
256+
recvWorkspaceConfigs := sshPrepareWorkspaceConfigs(ctx, client)
257257

258258
out := inv.Stdout
259259
if dryRun {
@@ -375,7 +375,7 @@ func (r *RootCmd) configSSH() *serpent.Command {
375375
return xerrors.Errorf("fetch workspace configs failed: %w", err)
376376
}
377377

378-
coderdConfig, err := client.SSHConfiguration(inv.Context())
378+
coderdConfig, err := client.SSHConfiguration(ctx)
379379
if err != nil {
380380
// If the error is 404, this deployment does not support
381381
// this endpoint yet. Do not error, just assume defaults.
@@ -440,26 +440,29 @@ func (r *RootCmd) configSSH() *serpent.Command {
440440
configOptions := sshConfigOpts
441441
configOptions.sshOptions = nil
442442

443-
// Add standard options.
444-
err := configOptions.addOptions(defaultOptions...)
445-
if err != nil {
446-
return err
443+
// User options first (SSH only uses the first
444+
// option unless it can be given multiple times)
445+
for _, opt := range sshConfigOpts.sshOptions {
446+
err := configOptions.addOptions(opt)
447+
if err != nil {
448+
return xerrors.Errorf("add flag config option %q: %w", opt, err)
449+
}
447450
}
448451

449-
// Override with deployment options
452+
// Deployment options second, allow them to
453+
// override standard options.
450454
for k, v := range coderdConfig.SSHConfigOptions {
451455
opt := fmt.Sprintf("%s %s", k, v)
452456
err := configOptions.addOptions(opt)
453457
if err != nil {
454458
return xerrors.Errorf("add coderd config option %q: %w", opt, err)
455459
}
456460
}
457-
// Override with flag options
458-
for _, opt := range sshConfigOpts.sshOptions {
459-
err := configOptions.addOptions(opt)
460-
if err != nil {
461-
return xerrors.Errorf("add flag config option %q: %w", opt, err)
462-
}
461+
462+
// Finally, add the standard options.
463+
err := configOptions.addOptions(defaultOptions...)
464+
if err != nil {
465+
return err
463466
}
464467

465468
hostBlock := []string{

cli/configssh_internal_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,32 +272,32 @@ func Test_sshConfigOptions_addOption(t *testing.T) {
272272
},
273273
},
274274
{
275-
Name: "Replace",
275+
Name: "AddTwo",
276276
Start: []string{
277277
"foo bar",
278278
},
279279
Add: []string{"Foo baz"},
280280
Expect: []string{
281+
"foo bar",
281282
"Foo baz",
282283
},
283284
},
284285
{
285-
Name: "AddAndReplace",
286+
Name: "AddAndRemove",
286287
Start: []string{
287-
"a b",
288288
"foo bar",
289289
"buzz bazz",
290290
},
291291
Add: []string{
292292
"b c",
293+
"a ", // Empty value, means remove all following entries that start with "a", i.e. next line.
293294
"A hello",
294295
"hello world",
295296
},
296297
Expect: []string{
297298
"foo bar",
298299
"buzz bazz",
299300
"b c",
300-
"A hello",
301301
"hello world",
302302
},
303303
},

cli/configssh_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func TestConfigSSH(t *testing.T) {
6565

6666
const hostname = "test-coder."
6767
const expectedKey = "ConnectionAttempts"
68-
const removeKey = "ConnectionTimeout"
68+
const removeKey = "ConnectTimeout"
6969
client, db := coderdtest.NewWithDatabase(t, &coderdtest.Options{
7070
ConfigSSH: codersdk.SSHConfigResponse{
7171
HostnamePrefix: hostname,
@@ -620,6 +620,19 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
620620
regexMatch: `ProxyCommand .* --header-command "printf h1=v1 h2='v2'" ssh`,
621621
},
622622
},
623+
{
624+
name: "Multiple remote forwards",
625+
args: []string{
626+
"--yes",
627+
"--ssh-option", "RemoteForward 2222 192.168.11.1:2222",
628+
"--ssh-option", "RemoteForward 2223 192.168.11.1:2223",
629+
},
630+
wantErr: false,
631+
hasAgent: true,
632+
wantConfig: wantConfig{
633+
regexMatch: "RemoteForward 2222 192.168.11.1:2222.*\n.*RemoteForward 2223 192.168.11.1:2223",
634+
},
635+
},
623636
}
624637
for _, tt := range tests {
625638
tt := tt

0 commit comments

Comments
 (0)