Skip to content

Commit 2737aba

Browse files
ramil-bitriseclaude
andcommitted
drop bitrise-codespaces proto dependency, hand-roll JSON types
The CLI talks to the codespaces gRPC-gateway over HTTP/JSON, so the generated proto types were only being used as JSON-serializable structs. Replace them with plain Go structs in internal/codespaces/types.go (json tags match protojson's lowerCamelCase + symbolic-name-enum defaults), and drop the bitrise-codespaces / google.golang.org/protobuf / genproto chain entirely. This is the last private module pinning the CLI, so the repo can now go public — which is required for `go run github.com/bitrise-io/ ai-qa-agent-cli@latest mcp` from the QA Agent template's warmup.sh to resolve from inside the session VM. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 44a71f1 commit 2737aba

10 files changed

Lines changed: 299 additions & 175 deletions

File tree

cmd/session.go

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"time"
1313

1414
"github.com/bitrise-io/ai-qa-agent-cli/internal/codespaces"
15-
codespacesv1 "github.com/bitrise-io/bitrise-codespaces/backend/proto/codespaces/v1"
1615
"github.com/spf13/cobra"
1716
)
1817

@@ -199,11 +198,11 @@ func runSessionCreate(cmd *cobra.Command, _ []string) error {
199198
}
200199
inputs = ensureQAAgentInputs(inputs, createDeviceType, createIOSVersion, createXcodeVersion, createUploadDestination, createWatchTimeout, createWatchPoll)
201200

202-
req := &codespacesv1.CreateSessionRequest{
201+
req := &codespaces.CreateSessionRequest{
203202
Name: createName,
204203
Description: createDescription,
205-
TemplateId: createTemplate,
206-
WorkspaceId: createWorkspace,
204+
TemplateID: createTemplate,
205+
WorkspaceID: createWorkspace,
207206
SessionInputs: inputs,
208207
EnabledFeatureFlagNames: createFeatureFlags,
209208
Cluster: createCluster,
@@ -227,40 +226,40 @@ func runSessionCreate(cmd *cobra.Command, _ []string) error {
227226
if err != nil {
228227
return fmt.Errorf("CreateSession: %w", err)
229228
}
230-
fmt.Fprintf(os.Stderr, "created session %s (status: %s)\n", session.GetId(), session.GetStatus())
229+
fmt.Fprintf(os.Stderr, "created session %s (status: %s)\n", session.ID, session.Status)
231230

232231
if createWait {
233-
session, err = client.WaitForRunning(ctx, session.GetId(), createWorkspace, createPollInterval, func(s codespacesv1.SessionStatus) {
232+
session, err = client.WaitForRunning(ctx, session.ID, createWorkspace, createPollInterval, func(s codespaces.SessionStatus) {
234233
fmt.Fprintf(os.Stderr, " status: %s\n", s)
235234
})
236235
if err != nil {
237236
return err
238237
}
239238
}
240239

241-
if createUpload != "" && session.GetStatus() == codespacesv1.SessionStatus_SESSION_STATUS_RUNNING {
242-
actualPath, err := client.UploadFile(ctx, session.GetId(), createWorkspace, createUpload, createUploadDestination)
240+
if createUpload != "" && session.Status == codespaces.SessionStatusRunning {
241+
actualPath, err := client.UploadFile(ctx, session.ID, createWorkspace, createUpload, createUploadDestination)
243242
if err != nil {
244243
return fmt.Errorf("upload %s: %w", createUpload, err)
245244
}
246245
fmt.Fprintf(os.Stderr, "uploaded %s -> %s\n", createUpload, actualPath)
247246
}
248247

249-
if createOpenRemoteAccess && session.GetStatus() == codespacesv1.SessionStatus_SESSION_STATUS_RUNNING {
250-
session, err = client.OpenRemoteAccess(ctx, session.GetId(), createWorkspace)
248+
if createOpenRemoteAccess && session.Status == codespaces.SessionStatusRunning {
249+
session, err = client.OpenRemoteAccess(ctx, session.ID, createWorkspace)
251250
if err != nil {
252251
return fmt.Errorf("OpenRemoteAccess: %w", err)
253252
}
254-
fmt.Fprintf(os.Stderr, "ssh: %s (password: %s)\n", session.GetSshAddress(), session.GetSshPassword())
255-
fmt.Fprintf(os.Stderr, "vnc: %s (user: %s, password: %s)\n", session.GetVncAddress(), session.GetVncUsername(), session.GetVncPassword())
253+
fmt.Fprintf(os.Stderr, "ssh: %s (password: %s)\n", session.SSHAddress, session.SSHPassword)
254+
fmt.Fprintf(os.Stderr, "vnc: %s (user: %s, password: %s)\n", session.VNCAddress, session.VNCUsername, session.VNCPassword)
256255
}
257256

258-
fmt.Println(session.GetId())
257+
fmt.Println(session.ID)
259258
if createUpload != "" {
260259
fmt.Fprintf(os.Stderr,
261260
"\nWhen the QA run finishes, collect results + stop the VM with:\n"+
262261
" ai-qa-agent-cli session collect %s --workspace %s\n",
263-
session.GetId(), createWorkspace)
262+
session.ID, createWorkspace)
264263
}
265264
return nil
266265
}
@@ -303,16 +302,16 @@ func resolveUploadAndPrompt(uploadLocal, uploadDest, prompt string, isDefault bo
303302
// injectQAPrompt appends the resolved QA prompt as a QA_PROMPT session input.
304303
// Errors if the caller already supplied QA_PROMPT via --input / --secret-input
305304
// / --saved-input — the dedicated --qa-prompt flag is the supported entry point.
306-
func injectQAPrompt(inputs []*codespacesv1.SessionInputValue, prompt string) ([]*codespacesv1.SessionInputValue, error) {
305+
func injectQAPrompt(inputs []*codespaces.SessionInputValue, prompt string) ([]*codespaces.SessionInputValue, error) {
307306
if prompt == "" {
308307
return inputs, nil
309308
}
310309
for _, in := range inputs {
311-
if in.GetKey() == qaPromptInputKey {
310+
if in.Key == qaPromptInputKey {
312311
return nil, fmt.Errorf("%s already supplied via --input/--secret-input/--saved-input; use --qa-prompt only", qaPromptInputKey)
313312
}
314313
}
315-
return append(inputs, &codespacesv1.SessionInputValue{Key: qaPromptInputKey, Value: prompt}), nil
314+
return append(inputs, &codespaces.SessionInputValue{Key: qaPromptInputKey, Value: prompt}), nil
316315
}
317316

318317
// ensureQAAgentInputs forwards the QA Agent template's optional session
@@ -322,13 +321,13 @@ func injectQAPrompt(inputs []*codespacesv1.SessionInputValue, prompt string) ([]
322321
// are skipped so the template's own defaults apply. Already-supplied inputs
323322
// (via --input / --secret-input / --saved-input) win.
324323
func ensureQAAgentInputs(
325-
inputs []*codespacesv1.SessionInputValue,
324+
inputs []*codespaces.SessionInputValue,
326325
deviceType, iosVersion, xcodeVersion, watchDir string,
327326
watchTimeout, watchPoll time.Duration,
328-
) []*codespacesv1.SessionInputValue {
327+
) []*codespaces.SessionInputValue {
329328
have := func(key string) bool {
330329
for _, in := range inputs {
331-
if in.GetKey() == key {
330+
if in.Key == key {
332331
return true
333332
}
334333
}
@@ -338,7 +337,7 @@ func ensureQAAgentInputs(
338337
if val == "" || have(key) {
339338
return
340339
}
341-
inputs = append(inputs, &codespacesv1.SessionInputValue{Key: key, Value: val})
340+
inputs = append(inputs, &codespaces.SessionInputValue{Key: key, Value: val})
342341
}
343342
add(deviceTypeInputKey, deviceType)
344343
add(iosVersionInputKey, iosVersion)
@@ -353,29 +352,29 @@ func ensureQAAgentInputs(
353352
return inputs
354353
}
355354

356-
func buildSessionInputs(plain, secret, saved []string) ([]*codespacesv1.SessionInputValue, error) {
357-
out := make([]*codespacesv1.SessionInputValue, 0, len(plain)+len(secret)+len(saved))
355+
func buildSessionInputs(plain, secret, saved []string) ([]*codespaces.SessionInputValue, error) {
356+
out := make([]*codespaces.SessionInputValue, 0, len(plain)+len(secret)+len(saved))
358357

359358
for _, kv := range plain {
360359
k, v, ok := strings.Cut(kv, "=")
361360
if !ok {
362361
return nil, fmt.Errorf("--input %q: expected key=value", kv)
363362
}
364-
out = append(out, &codespacesv1.SessionInputValue{Key: k, Value: v})
363+
out = append(out, &codespaces.SessionInputValue{Key: k, Value: v})
365364
}
366365
for _, kv := range secret {
367366
k, v, ok := strings.Cut(kv, "=")
368367
if !ok {
369368
return nil, fmt.Errorf("--secret-input %q: expected key=value", kv)
370369
}
371-
out = append(out, &codespacesv1.SessionInputValue{Key: k, Value: v, IsSecret: true})
370+
out = append(out, &codespaces.SessionInputValue{Key: k, Value: v, IsSecret: true})
372371
}
373372
for _, kv := range saved {
374373
k, id, ok := strings.Cut(kv, "=")
375374
if !ok {
376375
return nil, fmt.Errorf("--saved-input %q: expected key=savedInputID", kv)
377376
}
378-
out = append(out, &codespacesv1.SessionInputValue{Key: k, SavedInputId: id})
377+
out = append(out, &codespaces.SessionInputValue{Key: k, SavedInputID: id})
379378
}
380379
return out, nil
381380
}

cmd/session_collect.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"time"
99

1010
"github.com/bitrise-io/ai-qa-agent-cli/internal/codespaces"
11-
codespacesv1 "github.com/bitrise-io/bitrise-codespaces/backend/proto/codespaces/v1"
1211
"github.com/spf13/cobra"
1312
)
1413

@@ -83,7 +82,7 @@ func runSessionCollect(cmd *cobra.Command, args []string) error {
8382

8483
if !collectNoWait {
8584
fmt.Fprintln(os.Stderr, "waiting for QA agent to reach IDLE...")
86-
_, err := client.WaitForAgentIdle(ctx, sessionID, collectWorkspace, collectPollInterval, func(s codespacesv1.AgentSessionStatus) {
85+
_, err := client.WaitForAgentIdle(ctx, sessionID, collectWorkspace, collectPollInterval, func(s codespaces.AgentSessionStatus) {
8786
fmt.Fprintf(os.Stderr, " agent_session_status: %s\n", s)
8887
})
8988
if err != nil {
@@ -109,7 +108,7 @@ func runSessionCollect(cmd *cobra.Command, args []string) error {
109108
if err != nil {
110109
return fmt.Errorf("stop session: %w", err)
111110
}
112-
fmt.Fprintf(os.Stderr, " status: %s\n", stopped.GetStatus())
111+
fmt.Fprintf(os.Stderr, " status: %s\n", stopped.Status)
113112
}
114113

115114
fmt.Println(destDir)

go.mod

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,25 @@ module github.com/bitrise-io/ai-qa-agent-cli
33
go 1.26.2
44

55
require (
6-
github.com/bitrise-io/bitrise-codespaces/backend v0.0.0-20260504130057-ba324a92da8c
76
github.com/mark3labs/mcp-go v0.43.0
87
github.com/spf13/cobra v1.10.2
9-
google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348
10-
google.golang.org/protobuf v1.36.11
118
)
129

1310
require (
1411
github.com/bahlo/generic-list-go v0.2.0 // indirect
1512
github.com/buger/jsonparser v1.1.1 // indirect
13+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
14+
github.com/google/go-cmp v0.7.0 // indirect
1615
github.com/google/uuid v1.6.0 // indirect
17-
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
1816
github.com/inconshreveable/mousetrap v1.1.0 // indirect
1917
github.com/invopop/jsonschema v0.13.0 // indirect
2018
github.com/mailru/easyjson v0.7.7 // indirect
19+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
2120
github.com/spf13/cast v1.7.1 // indirect
2221
github.com/spf13/pflag v1.0.10 // indirect
22+
github.com/stretchr/testify v1.11.1 // indirect
2323
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
2424
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
25-
golang.org/x/net v0.53.0 // indirect
26-
golang.org/x/sys v0.43.0 // indirect
27-
golang.org/x/text v0.36.0 // indirect
28-
google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348 // indirect
29-
google.golang.org/grpc v1.81.0 // indirect
25+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
3026
gopkg.in/yaml.v3 v3.0.1 // indirect
3127
)

go.sum

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,26 @@
11
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
22
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
3-
github.com/bitrise-io/bitrise-codespaces/backend v0.0.0-20260504130057-ba324a92da8c h1:dsZNyHDhMWH176kWGwCNH7/bZ/r3CT9Cd0oQavvp7fo=
4-
github.com/bitrise-io/bitrise-codespaces/backend v0.0.0-20260504130057-ba324a92da8c/go.mod h1:byAJeoz+TQErjY2M2k3+BdtVTbI7cB7rDJ3/JV8uAYw=
53
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
64
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
7-
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
8-
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
95
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
106
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
117
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
128
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
139
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
14-
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
15-
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
16-
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
17-
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
18-
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
19-
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
2010
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
2111
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
2212
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
2313
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
24-
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
25-
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
2614
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
2715
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
2816
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
2917
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
3018
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
19+
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
3120
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
3221
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
22+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
23+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
3324
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
3425
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
3526
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@@ -54,35 +45,7 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/
5445
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
5546
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
5647
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
57-
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
58-
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
59-
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
60-
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
61-
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
62-
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
63-
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
64-
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
65-
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
66-
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
67-
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
68-
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
6948
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
70-
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
71-
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
72-
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
73-
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
74-
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
75-
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
76-
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
77-
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
78-
google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348 h1:U8orV30l6KpDsi9dxU0CoJZGbjS8EEpw+6ba+XwGPQA=
79-
google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348/go.mod h1:Yzdzr5OOZFgSsEV2D/Xi9NL3bszpXFAg0hFJiRohcD8=
80-
google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 h1:pfIbyB44sWzHiCpRqIen67ZQnVXSfIxWrqUMk1qwODE=
81-
google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
82-
google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw=
83-
google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
84-
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
85-
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
8649
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
8750
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
8851
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

internal/codespaces/client.go

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,22 @@ package codespaces
33
import (
44
"bytes"
55
"context"
6+
"encoding/json"
67
"fmt"
78
"io"
89
"net/http"
910
"net/url"
1011
"strings"
1112
"time"
12-
13-
"google.golang.org/protobuf/encoding/protojson"
14-
"google.golang.org/protobuf/proto"
1513
)
1614

1715
// Client is a thin HTTP wrapper around the bitrise-codespaces gRPC-gateway.
18-
// Requests and responses are still proto messages; protojson handles the
19-
// JSON wire format that the gateway speaks.
16+
// Requests and responses are plain Go structs with json tags that match
17+
// protojson's lowerCamelCase wire format — see types.go.
2018
type Client struct {
2119
baseURL string
2220
pat string
2321
http *http.Client
24-
25-
// jsonOpts mirrors what bitrise-codespaces/backend's gateway sends:
26-
// lowerCamelCase fields, enums as numeric strings or names — protojson's
27-
// defaults match.
28-
marshal protojson.MarshalOptions
29-
unmarshal protojson.UnmarshalOptions
3022
}
3123

3224
// NewClient constructs a Client. baseURL must be an absolute URL with scheme
@@ -43,10 +35,9 @@ func NewClient(baseURL, pat string) (*Client, error) {
4335
return nil, fmt.Errorf("invalid base URL %q (need scheme://host[:port])", baseURL)
4436
}
4537
return &Client{
46-
baseURL: strings.TrimRight(baseURL, "/"),
47-
pat: pat,
48-
http: &http.Client{Timeout: 10 * time.Minute},
49-
unmarshal: protojson.UnmarshalOptions{DiscardUnknown: true},
38+
baseURL: strings.TrimRight(baseURL, "/"),
39+
pat: pat,
40+
http: &http.Client{Timeout: 10 * time.Minute},
5041
}, nil
5142
}
5243

@@ -55,12 +46,12 @@ func NewClient(baseURL, pat string) (*Client, error) {
5546
func (c *Client) Close() error { return nil }
5647

5748
// do issues a JSON request to a path relative to the base URL. body and resp
58-
// are optional proto messages; pass nil to skip either side. Non-2xx
59-
// responses are wrapped in *httpError so FormatError can expand them.
60-
func (c *Client) do(ctx context.Context, method, relPath string, body, resp proto.Message) error {
49+
// are optional; pass nil to skip either side. Non-2xx responses are wrapped
50+
// in *httpError so FormatError can expand them.
51+
func (c *Client) do(ctx context.Context, method, relPath string, body, resp any) error {
6152
var rdr io.Reader
6253
if body != nil {
63-
raw, err := c.marshal.Marshal(body)
54+
raw, err := json.Marshal(body)
6455
if err != nil {
6556
return fmt.Errorf("marshal %s body: %w", relPath, err)
6657
}
@@ -97,7 +88,7 @@ func (c *Client) do(ctx context.Context, method, relPath string, body, resp prot
9788
}
9889
}
9990
if resp != nil && len(raw) > 0 {
100-
if err := c.unmarshal.Unmarshal(raw, resp); err != nil {
91+
if err := json.Unmarshal(raw, resp); err != nil {
10192
return fmt.Errorf("%s %s: unmarshal response: %w", method, fullURL, err)
10293
}
10394
}

internal/codespaces/download.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import (
1313
"path/filepath"
1414
"slices"
1515
"strings"
16-
17-
codespacesv1 "github.com/bitrise-io/bitrise-codespaces/backend/proto/codespaces/v1"
1816
)
1917

2018
// DownloadDir asks the codespaces backend to tar+gzip sourcePath on the VM
@@ -44,20 +42,20 @@ func (c *Client) DownloadDir(
4442
return nil, fmt.Errorf("create %s: %w", destDir, err)
4543
}
4644

47-
req := &codespacesv1.SessionDownloadRequest{
48-
SessionId: sessionID,
49-
WorkspaceId: workspaceID,
45+
req := &SessionDownloadRequest{
46+
SessionID: sessionID,
47+
WorkspaceID: workspaceID,
5048
SourcePath: sourcePath,
5149
OnlyContentsOfFolder: onlyContents,
5250
}
53-
var resp codespacesv1.SessionDownloadResponse
51+
var resp SessionDownloadResponse
5452
p := fmt.Sprintf("/v1/workspaces/%s/sessions/%s/download",
5553
url.PathEscape(workspaceID), url.PathEscape(sessionID))
5654
if err := c.do(ctx, http.MethodPost, p, req, &resp); err != nil {
5755
return nil, fmt.Errorf("SessionDownload: %w", err)
5856
}
5957

60-
signedURL := resp.GetSignedUrl()
58+
signedURL := resp.SignedURL
6159
if signedURL == "" {
6260
return nil, fmt.Errorf("SessionDownload returned an empty signed URL")
6361
}

0 commit comments

Comments
 (0)