Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit36c7e20

Browse files
committed
feat(cli): addcoder open vscode
Fixes#7667
1 parentfd43985 commit36c7e20

File tree

6 files changed

+225
-2
lines changed

6 files changed

+225
-2
lines changed

‎cli/open.go‎

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
"strings"
8+
9+
"github.com/skratchdot/open-golang/open"
10+
"golang.org/x/xerrors"
11+
12+
"github.com/coder/coder/v2/cli/clibase"
13+
"github.com/coder/coder/v2/cli/cliui"
14+
"github.com/coder/coder/v2/codersdk"
15+
)
16+
17+
func (r*RootCmd)open()*clibase.Cmd {
18+
cmd:=&clibase.Cmd{
19+
Use:"open",
20+
Short:"Open a workspace",
21+
Handler:func(inv*clibase.Invocation)error {
22+
returninv.Command.HelpHandler(inv)
23+
},
24+
Children: []*clibase.Cmd{
25+
r.openVSCode(),
26+
},
27+
}
28+
returncmd
29+
}
30+
31+
func (r*RootCmd)openVSCode()*clibase.Cmd {
32+
vartestNoOpenbool
33+
34+
client:=new(codersdk.Client)
35+
cmd:=&clibase.Cmd{
36+
Annotations:workspaceCommand,
37+
Use:"vscode <workspace> [<directory in workspace>]",
38+
Short:"Open a workspace in Visual Studio Code",
39+
Middleware:clibase.Chain(
40+
clibase.RequireRangeArgs(1,-1),
41+
r.InitClient(client),
42+
),
43+
Handler:func(inv*clibase.Invocation)error {
44+
ctx,cancel:=context.WithCancel(inv.Context())
45+
defercancel()
46+
47+
// Prepare an API key. This is for automagical configuration of
48+
// VS Code, however, we could try to probe VS Code settings to see
49+
// if the current configuration is valid. Future improvement idea.
50+
apiKey,err:=client.CreateAPIKey(ctx,codersdk.Me)
51+
iferr!=nil {
52+
returnxerrors.Errorf("create API key: %w",err)
53+
}
54+
55+
// We need a started workspace to figure out e.g. expanded directory.
56+
// Pehraps the vscode-coder extension could handle this by accepting
57+
// default_directory=true, then probing the agent. Then we wouldn't
58+
// need to wait for the agent to start.
59+
workspaceName:=inv.Args[0]
60+
autostart:=true
61+
workspace,workspaceAgent,err:=getWorkspaceAndAgent(ctx,inv,client,autostart,codersdk.Me,workspaceName)
62+
iferr!=nil {
63+
returnxerrors.Errorf("get workspace and agent: %w",err)
64+
}
65+
66+
// We could optionally add a flag to skip wait, like with SSH.
67+
wait:=false
68+
for_,script:=rangeworkspaceAgent.Scripts {
69+
ifscript.StartBlocksLogin {
70+
wait=true
71+
break
72+
}
73+
}
74+
err=cliui.Agent(ctx,inv.Stderr,workspaceAgent.ID, cliui.AgentOptions{
75+
Fetch:client.WorkspaceAgent,
76+
FetchLogs:client.WorkspaceAgentLogsAfter,
77+
Wait:wait,
78+
})
79+
iferr!=nil {
80+
ifxerrors.Is(err,context.Canceled) {
81+
returncliui.Canceled
82+
}
83+
returnxerrors.Errorf("agent: %w",err)
84+
}
85+
86+
// If the ExpandedDirectory was initially missing, it could mean
87+
// that the agent hadn't reported it in yet. Retry once.
88+
ifworkspaceAgent.ExpandedDirectory=="" {
89+
autostart=false// Don't retry autostart.
90+
workspace,workspaceAgent,err=getWorkspaceAndAgent(ctx,inv,client,autostart,codersdk.Me,workspaceName)
91+
iferr!=nil {
92+
returnxerrors.Errorf("get workspace and agent retry: %w",err)
93+
}
94+
}
95+
96+
varfolderstring
97+
switch {
98+
caselen(inv.Args)>1:
99+
folder=inv.Args[1]
100+
// Perhaps we could SSH in to expand the directory?
101+
ifstrings.HasPrefix(folder,"~") {
102+
returnxerrors.Errorf("folder path %q not supported, use an absolute path instead",folder)
103+
}
104+
caseworkspaceAgent.ExpandedDirectory!="":
105+
folder=workspaceAgent.ExpandedDirectory
106+
}
107+
108+
qp:= url.Values{}
109+
110+
qp.Add("url",client.URL.String())
111+
qp.Add("token",apiKey.Key)
112+
qp.Add("owner",workspace.OwnerName)
113+
qp.Add("workspace",workspace.Name)
114+
qp.Add("agent",workspaceAgent.Name)
115+
iffolder!="" {
116+
qp.Add("folder",folder)
117+
}
118+
119+
uri:=fmt.Sprintf("vscode://coder.coder-remote/open?%s",qp.Encode())
120+
_,_=fmt.Fprintf(inv.Stdout,"Opening %s\n",strings.ReplaceAll(uri,apiKey.Key,"<REDACTED>"))
121+
122+
iftestNoOpen {
123+
returnnil
124+
}
125+
126+
err=open.Run(uri)
127+
iferr!=nil {
128+
returnxerrors.Errorf("open: %w",err)
129+
}
130+
131+
returnnil
132+
},
133+
}
134+
135+
cmd.Options= clibase.OptionSet{
136+
{
137+
Flag:"test.no-open",
138+
Description:"Don't run the open command.",
139+
Value:clibase.BoolOf(&testNoOpen),
140+
Hidden:true,// This is for testing!
141+
},
142+
}
143+
144+
returncmd
145+
}

‎cli/open_test.go‎

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package cli_test
2+
3+
import (
4+
"context"
5+
"net/url"
6+
"strings"
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
12+
"github.com/coder/coder/v2/agent/agenttest"
13+
"github.com/coder/coder/v2/cli/clitest"
14+
"github.com/coder/coder/v2/coderd/coderdtest"
15+
"github.com/coder/coder/v2/codersdk"
16+
"github.com/coder/coder/v2/provisionersdk/proto"
17+
"github.com/coder/coder/v2/pty/ptytest"
18+
"github.com/coder/coder/v2/testutil"
19+
)
20+
21+
funcTestOpen(t*testing.T) {
22+
t.Parallel()
23+
24+
t.Run("VSCode",func(t*testing.T) {
25+
t.Parallel()
26+
27+
client,workspace,agentToken:=setupWorkspaceForAgent(t,func(agents []*proto.Agent) []*proto.Agent {
28+
agents[0].Directory="/tmp"
29+
agents[0].Name="agent1"
30+
returnagents
31+
})
32+
33+
inv,root:=clitest.New(t,"open","vscode","--test.no-open",workspace.Name)
34+
clitest.SetupConfig(t,client,root)
35+
pty:=ptytest.New(t)
36+
inv.Stdin=pty.Input()
37+
inv.Stderr=pty.Output()
38+
inv.Stdout=pty.Output()
39+
40+
_=agenttest.New(t,client.URL,agentToken)
41+
_=coderdtest.AwaitWorkspaceAgents(t,client,workspace.ID)
42+
43+
ctx,cancel:=context.WithTimeout(context.Background(),testutil.WaitLong)
44+
defercancel()
45+
46+
cmdDone:=tGo(t,func() {
47+
err:=inv.WithContext(ctx).Run()
48+
assert.NoError(t,err)
49+
})
50+
51+
me,err:=client.User(ctx,codersdk.Me)
52+
require.NoError(t,err)
53+
54+
line:=pty.ReadLine(ctx)
55+
56+
// Opening vscode://coder.coder-remote/open?...
57+
parts:=strings.Split(line," ")
58+
require.Len(t,parts,2)
59+
require.Contains(t,parts[1],"vscode://")
60+
u,err:=url.ParseRequestURI(parts[1])
61+
require.NoError(t,err)
62+
63+
qp:=u.Query()
64+
assert.Equal(t,client.URL.String(),qp.Get("url"))
65+
assert.Equal(t,me.Username,qp.Get("owner"))
66+
assert.Equal(t,workspace.Name,qp.Get("workspace"))
67+
assert.Equal(t,"agent1",qp.Get("agent"))
68+
assert.Equal(t,"/tmp",qp.Get("folder"))
69+
70+
cancel()
71+
<-cmdDone
72+
})
73+
}

‎cli/root.go‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,18 @@ func (r *RootCmd) Core() []*clibase.Cmd {
101101
r.create(),
102102
r.deleteWorkspace(),
103103
r.list(),
104+
r.open(),
104105
r.ping(),
105106
r.rename(),
107+
r.restart(),
106108
r.schedules(),
107109
r.show(),
108110
r.speedtest(),
109111
r.ssh(),
110112
r.start(),
113+
r.stat(),
111114
r.stop(),
112115
r.update(),
113-
r.restart(),
114-
r.stat(),
115116

116117
// Hidden
117118
r.gitssh(),

‎cli/ssh.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ func (r *RootCmd) ssh() *clibase.Cmd {
205205
ifxerrors.Is(err,context.Canceled) {
206206
returncliui.Canceled
207207
}
208+
returnerr
208209
}
209210

210211
ifr.disableDirect {

‎go.mod‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ require (
160160
github.com/prometheus/commonv0.45.0
161161
github.com/quasilyte/go-ruleguard/dslv0.3.21
162162
github.com/robfig/cron/v3v3.0.1
163+
github.com/skratchdot/open-golangv0.0.0-20200116055534-eef842397966
163164
github.com/spf13/aferov1.10.0
164165
github.com/spf13/pflagv1.0.5
165166
github.com/sqlc-dev/pqtypev0.3.0

‎go.sum‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,8 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
817817
github.com/sirupsen/logrusv1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
818818
github.com/sirupsen/logrusv1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
819819
github.com/sirupsen/logrusv1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
820+
github.com/skratchdot/open-golangv0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
821+
github.com/skratchdot/open-golangv0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
820822
github.com/spaolacci/murmur3v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
821823
github.com/spaolacci/murmur3v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
822824
github.com/spf13/aferov1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp