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

Commit2bd6d29

Browse files
authored
feat: convert entire CLI to clibase (#6491)
I'm sorry.
1 parentb71b8da commit2bd6d29

File tree

345 files changed

+9977
-9094
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

345 files changed

+9977
-9094
lines changed

‎.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ jobs:
302302
echo "cover=false" >> $GITHUB_OUTPUT
303303
fi
304304
305-
gotestsum --junitfile="gotests.xml" --packages="./..." -- -parallel=8 -timeout=5m -short -failfast $COVERAGE_FLAGS
305+
gotestsum --junitfile="gotests.xml" --packages="./..." -- -parallel=8 -timeout=7m -short -failfast $COVERAGE_FLAGS
306306
307307
-uses:actions/upload-artifact@v3
308308
if:success() || failure()

‎Makefile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -501,8 +501,6 @@ docs/admin/prometheus.md: scripts/metricsdocgen/main.go scripts/metricsdocgen/me
501501
yarn run format:write:only ../docs/admin/prometheus.md
502502

503503
docs/cli.md: scripts/clidocgen/main.go$(GO_SRC_FILES) docs/manifest.json
504-
# TODO(@ammario): re-enable server.md once we finish clibase migration.
505-
ls ./docs/cli/*.md| grep -vP"\/coder_server"| xargs rm
506504
BASE_PATH="." go run ./scripts/clidocgen
507505
cd site
508506
yarn run format:write:only ../docs/cli.md ../docs/cli/*.md ../docs/manifest.json
@@ -519,7 +517,7 @@ coderd/apidoc/swagger.json: $(shell find ./scripts/apidocgen $(FIND_EXCLUSIONS)
519517
update-golden-files: cli/testdata/.gen-golden helm/tests/testdata/.gen-golden
520518
.PHONY: update-golden-files
521519

522-
cli/testdata/.gen-golden:$(wildcard cli/testdata/*.golden)$(GO_SRC_FILES)
520+
cli/testdata/.gen-golden:$(wildcard cli/testdata/*.golden)$(wildcard cli/*.tpl)$(GO_SRC_FILES)
523521
gotest ./cli -run=TestCommandHelp -update
524522
touch"$@"
525523

‎cli/agent.go

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"time"
1717

1818
"cloud.google.com/go/compute/metadata"
19-
"github.com/spf13/cobra"
2019
"golang.org/x/xerrors"
2120
"gopkg.in/natefinch/lumberjack.v2"
2221

@@ -25,34 +24,27 @@ import (
2524
"github.com/coder/coder/agent"
2625
"github.com/coder/coder/agent/reaper"
2726
"github.com/coder/coder/buildinfo"
28-
"github.com/coder/coder/cli/cliflag"
27+
"github.com/coder/coder/cli/clibase"
2928
"github.com/coder/coder/codersdk/agentsdk"
3029
)
3130

32-
funcworkspaceAgent()*cobra.Command {
31+
func(r*RootCmd)workspaceAgent()*clibase.Cmd {
3332
var (
3433
authstring
3534
logDirstring
3635
pprofAddressstring
3736
noReapbool
3837
sshMaxTimeout time.Duration
3938
)
40-
cmd:=&cobra.Command{
41-
Use:"agent",
39+
cmd:=&clibase.Cmd{
40+
Use:"agent",
41+
Short:`Starts the Coder workspace agent.`,
4242
// This command isn't useful to manually execute.
4343
Hidden:true,
44-
RunE:func(cmd*cobra.Command,_ []string)error {
45-
ctx,cancel:=context.WithCancel(cmd.Context())
44+
Handler:func(inv*clibase.Invocation)error {
45+
ctx,cancel:=context.WithCancel(inv.Context())
4646
defercancel()
4747

48-
rawURL,err:=cmd.Flags().GetString(varAgentURL)
49-
iferr!=nil {
50-
returnxerrors.Errorf("CODER_AGENT_URL must be set: %w",err)
51-
}
52-
coderURL,err:=url.Parse(rawURL)
53-
iferr!=nil {
54-
returnxerrors.Errorf("parse %q: %w",rawURL,err)
55-
}
5648
agentPorts:=map[int]string{}
5749

5850
isLinux:=runtime.GOOS=="linux"
@@ -65,7 +57,7 @@ func workspaceAgent() *cobra.Command {
6557
MaxSize:5,// MB
6658
}
6759
deferlogWriter.Close()
68-
logger:=slog.Make(sloghuman.Sink(cmd.ErrOrStderr()),sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug)
60+
logger:=slog.Make(sloghuman.Sink(inv.Stderr),sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug)
6961

7062
logger.Info(ctx,"spawning reaper process")
7163
// Do not start a reaper on the child process. It's important
@@ -107,15 +99,15 @@ func workspaceAgent() *cobra.Command {
10799
logWriter:=&closeWriter{w:ljLogger}
108100
deferlogWriter.Close()
109101

110-
logger:=slog.Make(sloghuman.Sink(cmd.ErrOrStderr()),sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug)
102+
logger:=slog.Make(sloghuman.Sink(inv.Stderr),sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug)
111103

112104
version:=buildinfo.Version()
113105
logger.Info(ctx,"starting agent",
114-
slog.F("url",coderURL),
106+
slog.F("url",r.agentURL),
115107
slog.F("auth",auth),
116108
slog.F("version",version),
117109
)
118-
client:=agentsdk.New(coderURL)
110+
client:=agentsdk.New(r.agentURL)
119111
client.SDK.Logger=logger
120112
// Set a reasonable timeout so requests can't hang forever!
121113
// The timeout needs to be reasonably long, because requests
@@ -139,7 +131,7 @@ func workspaceAgent() *cobra.Command {
139131
varexchangeTokenfunc(context.Context) (agentsdk.AuthenticateResponse,error)
140132
switchauth {
141133
case"token":
142-
token,err:=cmd.Flags().GetString(varAgentToken)
134+
token,err:=inv.ParsedFlags().GetString(varAgentToken)
143135
iferr!=nil {
144136
returnxerrors.Errorf("CODER_AGENT_TOKEN must be set for token auth: %w",err)
145137
}
@@ -220,11 +212,44 @@ func workspaceAgent() *cobra.Command {
220212
},
221213
}
222214

223-
cliflag.StringVarP(cmd.Flags(),&auth,"auth","","CODER_AGENT_AUTH","token","Specify the authentication type to use for the agent")
224-
cliflag.StringVarP(cmd.Flags(),&logDir,"log-dir","","CODER_AGENT_LOG_DIR",os.TempDir(),"Specify the location for the agent log files")
225-
cliflag.StringVarP(cmd.Flags(),&pprofAddress,"pprof-address","","CODER_AGENT_PPROF_ADDRESS","127.0.0.1:6060","The address to serve pprof.")
226-
cliflag.BoolVarP(cmd.Flags(),&noReap,"no-reap","","",false,"Do not start a process reaper.")
227-
cliflag.DurationVarP(cmd.Flags(),&sshMaxTimeout,"ssh-max-timeout","","CODER_AGENT_SSH_MAX_TIMEOUT",time.Duration(0),"Specify the max timeout for a SSH connection")
215+
cmd.Options= clibase.OptionSet{
216+
{
217+
Flag:"auth",
218+
Default:"token",
219+
Description:"Specify the authentication type to use for the agent.",
220+
Env:"CODER_AGENT_AUTH",
221+
Value:clibase.StringOf(&auth),
222+
},
223+
{
224+
Flag:"log-dir",
225+
Default:os.TempDir(),
226+
Description:"Specify the location for the agent log files.",
227+
Env:"CODER_AGENT_LOG_DIR",
228+
Value:clibase.StringOf(&logDir),
229+
},
230+
{
231+
Flag:"pprof-address",
232+
Default:"127.0.0.1:6060",
233+
Env:"CODER_AGENT_PPROF_ADDRESS",
234+
Value:clibase.StringOf(&pprofAddress),
235+
Description:"The address to serve pprof.",
236+
},
237+
{
238+
Flag:"no-reap",
239+
240+
Env:"",
241+
Description:"Do not start a process reaper.",
242+
Value:clibase.BoolOf(&noReap),
243+
},
244+
{
245+
Flag:"ssh-max-timeout",
246+
Default:"0",
247+
Env:"CODER_AGENT_SSH_MAX_TIMEOUT",
248+
Description:"Specify the max timeout for a SSH connection.",
249+
Value:clibase.DurationOf(&sshMaxTimeout),
250+
},
251+
}
252+
228253
returncmd
229254
}
230255

‎cli/agent_test.go

Lines changed: 35 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
"github.com/coder/coder/coderd/coderdtest"
1717
"github.com/coder/coder/provisioner/echo"
1818
"github.com/coder/coder/provisionersdk/proto"
19-
"github.com/coder/coder/testutil"
19+
"github.com/coder/coder/pty/ptytest"
2020
)
2121

2222
funcTestWorkspaceAgent(t*testing.T) {
@@ -40,24 +40,20 @@ func TestWorkspaceAgent(t *testing.T) {
4040
coderdtest.AwaitWorkspaceBuildJob(t,client,workspace.LatestBuild.ID)
4141

4242
logDir:=t.TempDir()
43-
cmd,_:=clitest.New(t,
43+
inv,_:=clitest.New(t,
4444
"agent",
4545
"--auth","token",
4646
"--agent-token",authToken,
4747
"--agent-url",client.URL.String(),
4848
"--log-dir",logDir,
4949
)
50-
ctx,cancel:=context.WithTimeout(context.Background(),testutil.WaitMedium)
51-
defercancel()
52-
errC:=make(chanerror,1)
53-
gofunc() {
54-
errC<-cmd.ExecuteContext(ctx)
55-
}()
56-
coderdtest.AwaitWorkspaceAgents(t,client,workspace.ID)
5750

58-
cancel()
59-
err:=<-errC
60-
require.NoError(t,err)
51+
pty:=ptytest.New(t).Attach(inv)
52+
53+
clitest.Start(t,inv)
54+
pty.ExpectMatch("starting agent")
55+
56+
coderdtest.AwaitWorkspaceAgents(t,client,workspace.ID)
6157

6258
info,err:=os.Stat(filepath.Join(logDir,"coder-agent.log"))
6359
require.NoError(t,err)
@@ -96,16 +92,14 @@ func TestWorkspaceAgent(t *testing.T) {
9692
workspace:=coderdtest.CreateWorkspace(t,client,user.OrganizationID,template.ID)
9793
coderdtest.AwaitWorkspaceBuildJob(t,client,workspace.LatestBuild.ID)
9894

99-
cmd,_:=clitest.New(t,"agent","--auth","azure-instance-identity","--agent-url",client.URL.String())
95+
inv,_:=clitest.New(t,"agent","--auth","azure-instance-identity","--agent-url",client.URL.String())
96+
inv=inv.WithContext(
97+
//nolint:revive,staticcheck
98+
context.WithValue(inv.Context(),"azure-client",metadataClient),
99+
)
100100
ctx,cancelFunc:=context.WithCancel(context.Background())
101101
defercancelFunc()
102-
errC:=make(chanerror)
103-
gofunc() {
104-
// A linting error occurs for weakly typing the context value here.
105-
//nolint // The above seems reasonable for a one-off test.
106-
ctx:=context.WithValue(ctx,"azure-client",metadataClient)
107-
errC<-cmd.ExecuteContext(ctx)
108-
}()
102+
clitest.Start(t,inv)
109103
coderdtest.AwaitWorkspaceAgents(t,client,workspace.ID)
110104
workspace,err:=client.Workspace(ctx,workspace.ID)
111105
require.NoError(t,err)
@@ -117,9 +111,6 @@ func TestWorkspaceAgent(t *testing.T) {
117111
require.NoError(t,err)
118112
deferdialer.Close()
119113
require.True(t,dialer.AwaitReachable(context.Background()))
120-
cancelFunc()
121-
err=<-errC
122-
require.NoError(t,err)
123114
})
124115

125116
t.Run("AWS",func(t*testing.T) {
@@ -154,36 +145,29 @@ func TestWorkspaceAgent(t *testing.T) {
154145
workspace:=coderdtest.CreateWorkspace(t,client,user.OrganizationID,template.ID)
155146
coderdtest.AwaitWorkspaceBuildJob(t,client,workspace.LatestBuild.ID)
156147

157-
cmd,_:=clitest.New(t,"agent","--auth","aws-instance-identity","--agent-url",client.URL.String())
158-
ctx,cancelFunc:=context.WithCancel(context.Background())
159-
defercancelFunc()
160-
errC:=make(chanerror)
161-
gofunc() {
162-
// A linting error occurs for weakly typing the context value here.
163-
//nolint // The above seems reasonable for a one-off test.
164-
ctx:=context.WithValue(ctx,"aws-client",metadataClient)
165-
errC<-cmd.ExecuteContext(ctx)
166-
}()
148+
inv,_:=clitest.New(t,"agent","--auth","aws-instance-identity","--agent-url",client.URL.String())
149+
inv=inv.WithContext(
150+
//nolint:revive,staticcheck
151+
context.WithValue(inv.Context(),"aws-client",metadataClient),
152+
)
153+
clitest.Start(t,inv)
167154
coderdtest.AwaitWorkspaceAgents(t,client,workspace.ID)
168-
workspace,err:=client.Workspace(ctx,workspace.ID)
155+
workspace,err:=client.Workspace(inv.Context(),workspace.ID)
169156
require.NoError(t,err)
170157
resources:=workspace.LatestBuild.Resources
171158
ifassert.NotEmpty(t,resources)&&assert.NotEmpty(t,resources[0].Agents) {
172159
assert.NotEmpty(t,resources[0].Agents[0].Version)
173160
}
174-
dialer,err:=client.DialWorkspaceAgent(ctx,resources[0].Agents[0].ID,nil)
161+
dialer,err:=client.DialWorkspaceAgent(inv.Context(),resources[0].Agents[0].ID,nil)
175162
require.NoError(t,err)
176163
deferdialer.Close()
177164
require.True(t,dialer.AwaitReachable(context.Background()))
178-
cancelFunc()
179-
err=<-errC
180-
require.NoError(t,err)
181165
})
182166

183167
t.Run("GoogleCloud",func(t*testing.T) {
184168
t.Parallel()
185169
instanceID:="instanceidentifier"
186-
validator,metadata:=coderdtest.NewGoogleInstanceIdentity(t,instanceID,false)
170+
validator,metadataClient:=coderdtest.NewGoogleInstanceIdentity(t,instanceID,false)
187171
client:=coderdtest.New(t,&coderdtest.Options{
188172
GoogleTokenValidator:validator,
189173
IncludeProvisionerDaemon:true,
@@ -212,16 +196,18 @@ func TestWorkspaceAgent(t *testing.T) {
212196
workspace:=coderdtest.CreateWorkspace(t,client,user.OrganizationID,template.ID)
213197
coderdtest.AwaitWorkspaceBuildJob(t,client,workspace.LatestBuild.ID)
214198

215-
cmd,_:=clitest.New(t,"agent","--auth","google-instance-identity","--agent-url",client.URL.String())
216-
ctx,cancelFunc:=context.WithCancel(context.Background())
217-
defercancelFunc()
218-
errC:=make(chanerror)
219-
gofunc() {
220-
// A linting error occurs for weakly typing the context value here.
221-
//nolint // The above seems reasonable for a one-off test.
222-
ctx:=context.WithValue(ctx,"gcp-client",metadata)
223-
errC<-cmd.ExecuteContext(ctx)
224-
}()
199+
inv,cfg:=clitest.New(t,"agent","--auth","google-instance-identity","--agent-url",client.URL.String())
200+
ptytest.New(t).Attach(inv)
201+
clitest.SetupConfig(t,client,cfg)
202+
clitest.Start(t,
203+
inv.WithContext(
204+
//nolint:revive,staticcheck
205+
context.WithValue(context.Background(),"gcp-client",metadataClient),
206+
),
207+
)
208+
209+
ctx:=inv.Context()
210+
225211
coderdtest.AwaitWorkspaceAgents(t,client,workspace.ID)
226212
workspace,err:=client.Workspace(ctx,workspace.ID)
227213
require.NoError(t,err)
@@ -248,9 +234,5 @@ func TestWorkspaceAgent(t *testing.T) {
248234
require.NoError(t,err)
249235
_,err=uuid.Parse(strings.TrimSpace(string(token)))
250236
require.NoError(t,err)
251-
252-
cancelFunc()
253-
err=<-errC
254-
require.NoError(t,err)
255237
})
256238
}

‎cli/clibase/clibase.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
// Package clibase offers an all-in-one solution for a highly configurable CLI
2-
// application. Within Coder, we use it for our `server` subcommand, which
3-
// demands more functionality than cobra/viper can offer.
4-
//
5-
// We will extend its usage to the rest of our application, completely replacing
6-
// cobra/viper. It's also a candidate to be broken out into its own open-source
7-
// library, so we avoid deep coupling with Coder concepts.
2+
// application. Within Coder, we use it for all of our subcommands, which
3+
// demands more functionality than cobra/viber offers.
84
//
95
// The Command interface is loosely based on the chi middleware pattern and
106
// http.Handler/HandlerFunc.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp