Skip to content

Commit 90a40e0

Browse files
committed
Merge branch 'main' into 12508-experiments
2 parents 22bed46 + fad97a1 commit 90a40e0

Some content is hidden

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

50 files changed

+1442
-306
lines changed

.github/workflows/ci.yaml

+27-23
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,15 @@ jobs:
432432
needs: changes
433433
if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ts == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main'
434434
timeout-minutes: 20
435+
strategy:
436+
fail-fast: false
437+
matrix:
438+
variant:
439+
- enterprise: false
440+
name: test-e2e
441+
- enterprise: true
442+
name: test-e2e-enterprise
443+
name: ${{ matrix.variant.name }}
435444
steps:
436445
- name: Checkout
437446
uses: actions/checkout@v4
@@ -444,39 +453,34 @@ jobs:
444453
- name: Setup Go
445454
uses: ./.github/actions/setup-go
446455

447-
- name: Setup Terraform
448-
uses: ./.github/actions/setup-tf
449-
450-
- name: go install tools
451-
run: |
452-
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.30
453-
go install storj.io/drpc/cmd/protoc-gen-go-drpc@v0.0.33
454-
go install golang.org/x/tools/cmd/goimports@latest
455-
go install github.com/mikefarah/yq/v4@v4.30.6
456-
go install go.uber.org/mock/mockgen@v0.4.0
457-
458-
- name: Install Protoc
459-
run: |
460-
mkdir -p /tmp/proto
461-
pushd /tmp/proto
462-
curl -L -o protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v23.3/protoc-23.3-linux-x86_64.zip
463-
unzip protoc.zip
464-
cp -r ./bin/* /usr/local/bin
465-
cp -r ./include /usr/local/bin/include
466-
popd
456+
# Assume that the checked-in versions are up-to-date
457+
- run: make gen/mark-fresh
458+
name: make gen
467459

468-
- name: Build
469-
run: |
470-
make -B site/out/index.html
460+
- run: pnpm build
461+
working-directory: site
471462

472463
- run: pnpm playwright:install
473464
working-directory: site
474465

475466
# Run tests that don't require an enterprise license without an enterprise license
476467
- run: pnpm playwright:test --forbid-only --workers 1
468+
if: ${{ !matrix.variant.enterprise }}
469+
env:
470+
DEBUG: pw:api
471+
working-directory: site
472+
473+
# Run all of the tests with an enterprise license
474+
- run: pnpm playwright:test --forbid-only --workers 1
475+
if: ${{ matrix.variant.enterprise }}
477476
env:
478477
DEBUG: pw:api
478+
CODER_E2E_ENTERPRISE_LICENSE: ${{ secrets.CODER_E2E_ENTERPRISE_LICENSE }}
479+
CODER_E2E_REQUIRE_ENTERPRISE_TESTS: "1"
479480
working-directory: site
481+
# Temporarily allow these to fail so that I can gather data about which
482+
# tests are failing.
483+
continue-on-error: true
480484

481485
- name: Upload Playwright Failed Tests
482486
if: always() && github.actor != 'dependabot[bot]' && runner.os == 'Linux' && !github.event.pull_request.head.repo.fork

cli/support.go

+33-23
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"text/tabwriter"
1414
"time"
1515

16+
"github.com/google/uuid"
1617
"golang.org/x/xerrors"
1718

1819
"cdr.dev/slog"
@@ -114,31 +115,40 @@ func (r *RootCmd) supportBundle() *serpent.Command {
114115
client.URL = u
115116
}
116117

117-
if len(inv.Args) == 0 {
118-
return xerrors.Errorf("must specify workspace name")
119-
}
120-
ws, err := namedWorkspace(inv.Context(), client, inv.Args[0])
121-
if err != nil {
122-
return xerrors.Errorf("invalid workspace: %w", err)
123-
}
124-
cliLog.Debug(inv.Context(), "found workspace",
125-
slog.F("workspace_name", ws.Name),
126-
slog.F("workspace_id", ws.ID),
118+
var (
119+
wsID uuid.UUID
120+
agtID uuid.UUID
127121
)
128122

129-
agentName := ""
130-
if len(inv.Args) > 1 {
131-
agentName = inv.Args[1]
132-
}
123+
if len(inv.Args) == 0 {
124+
cliLog.Warn(inv.Context(), "no workspace specified")
125+
_, _ = fmt.Fprintln(inv.Stderr, "Warning: no workspace specified. This will result in incomplete information.")
126+
} else {
127+
ws, err := namedWorkspace(inv.Context(), client, inv.Args[0])
128+
if err != nil {
129+
return xerrors.Errorf("invalid workspace: %w", err)
130+
}
131+
cliLog.Debug(inv.Context(), "found workspace",
132+
slog.F("workspace_name", ws.Name),
133+
slog.F("workspace_id", ws.ID),
134+
)
135+
wsID = ws.ID
136+
agentName := ""
137+
if len(inv.Args) > 1 {
138+
agentName = inv.Args[1]
139+
}
133140

134-
agt, found := findAgent(agentName, ws.LatestBuild.Resources)
135-
if !found {
136-
return xerrors.Errorf("could not find agent named %q for workspace", agentName)
141+
agt, found := findAgent(agentName, ws.LatestBuild.Resources)
142+
if !found {
143+
cliLog.Warn(inv.Context(), "could not find agent in workspace", slog.F("agent_name", agentName))
144+
} else {
145+
cliLog.Debug(inv.Context(), "found workspace agent",
146+
slog.F("agent_name", agt.Name),
147+
slog.F("agent_id", agt.ID),
148+
)
149+
agtID = agt.ID
150+
}
137151
}
138-
cliLog.Debug(inv.Context(), "found workspace agent",
139-
slog.F("agent_name", agt.Name),
140-
slog.F("agent_id", agt.ID),
141-
)
142152

143153
if outputPath == "" {
144154
cwd, err := filepath.Abs(".")
@@ -165,8 +175,8 @@ func (r *RootCmd) supportBundle() *serpent.Command {
165175
Client: client,
166176
// Support adds a sink so we don't need to supply one ourselves.
167177
Log: clientLog,
168-
WorkspaceID: ws.ID,
169-
AgentID: agt.ID,
178+
WorkspaceID: wsID,
179+
AgentID: agtID,
170180
}
171181

172182
bun, err := support.Run(inv.Context(), &deps)

cli/support_test.go

+109-23
Original file line numberDiff line numberDiff line change
@@ -95,33 +95,50 @@ func TestSupportBundle(t *testing.T) {
9595
clitest.SetupConfig(t, client, root)
9696
err = inv.Run()
9797
require.NoError(t, err)
98-
assertBundleContents(t, path, secretValue)
98+
assertBundleContents(t, path, true, true, []string{secretValue})
9999
})
100100

101101
t.Run("NoWorkspace", func(t *testing.T) {
102102
t.Parallel()
103-
client := coderdtest.New(t, nil)
103+
var dc codersdk.DeploymentConfig
104+
secretValue := uuid.NewString()
105+
seedSecretDeploymentOptions(t, &dc, secretValue)
106+
client := coderdtest.New(t, &coderdtest.Options{
107+
DeploymentValues: dc.Values,
108+
})
104109
_ = coderdtest.CreateFirstUser(t, client)
105-
inv, root := clitest.New(t, "support", "bundle", "--yes")
110+
111+
d := t.TempDir()
112+
path := filepath.Join(d, "bundle.zip")
113+
inv, root := clitest.New(t, "support", "bundle", "--output-file", path, "--yes")
106114
//nolint: gocritic // requires owner privilege
107115
clitest.SetupConfig(t, client, root)
108116
err := inv.Run()
109-
require.ErrorContains(t, err, "must specify workspace name")
117+
require.NoError(t, err)
118+
assertBundleContents(t, path, false, false, []string{secretValue})
110119
})
111120

112121
t.Run("NoAgent", func(t *testing.T) {
113122
t.Parallel()
114-
client, db := coderdtest.NewWithDatabase(t, nil)
123+
var dc codersdk.DeploymentConfig
124+
secretValue := uuid.NewString()
125+
seedSecretDeploymentOptions(t, &dc, secretValue)
126+
client, db := coderdtest.NewWithDatabase(t, &coderdtest.Options{
127+
DeploymentValues: dc.Values,
128+
})
115129
admin := coderdtest.CreateFirstUser(t, client)
116130
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
117131
OrganizationID: admin.OrganizationID,
118132
OwnerID: admin.UserID,
119133
}).Do() // without agent!
120-
inv, root := clitest.New(t, "support", "bundle", r.Workspace.Name, "--yes")
134+
d := t.TempDir()
135+
path := filepath.Join(d, "bundle.zip")
136+
inv, root := clitest.New(t, "support", "bundle", r.Workspace.Name, "--output-file", path, "--yes")
121137
//nolint: gocritic // requires owner privilege
122138
clitest.SetupConfig(t, client, root)
123139
err := inv.Run()
124-
require.ErrorContains(t, err, "could not find agent")
140+
require.NoError(t, err)
141+
assertBundleContents(t, path, true, false, []string{secretValue})
125142
})
126143

127144
t.Run("NoPrivilege", func(t *testing.T) {
@@ -140,7 +157,8 @@ func TestSupportBundle(t *testing.T) {
140157
})
141158
}
142159

143-
func assertBundleContents(t *testing.T, path string, badValues ...string) {
160+
// nolint:revive // It's a control flag, but this is just a test.
161+
func assertBundleContents(t *testing.T, path string, wantWorkspace bool, wantAgent bool, badValues []string) {
144162
t.Helper()
145163
r, err := zip.OpenReader(path)
146164
require.NoError(t, err, "open zip file")
@@ -173,64 +191,132 @@ func assertBundleContents(t *testing.T, path string, badValues ...string) {
173191
case "network/netcheck.json":
174192
var v workspacesdk.AgentConnectionInfo
175193
decodeJSONFromZip(t, f, &v)
194+
if !wantAgent || !wantWorkspace {
195+
require.Empty(t, v, "expected connection info to be empty")
196+
continue
197+
}
176198
require.NotEmpty(t, v, "connection info should not be empty")
177199
case "workspace/workspace.json":
178200
var v codersdk.Workspace
179201
decodeJSONFromZip(t, f, &v)
202+
if !wantWorkspace {
203+
require.Empty(t, v, "expected workspace to be empty")
204+
continue
205+
}
180206
require.NotEmpty(t, v, "workspace should not be empty")
181207
case "workspace/build_logs.txt":
182208
bs := readBytesFromZip(t, f)
209+
if !wantWorkspace || !wantAgent {
210+
require.Empty(t, bs, "expected workspace build logs to be empty")
211+
continue
212+
}
183213
require.Contains(t, string(bs), "provision done")
214+
case "workspace/template.json":
215+
var v codersdk.Template
216+
decodeJSONFromZip(t, f, &v)
217+
if !wantWorkspace {
218+
require.Empty(t, v, "expected workspace template to be empty")
219+
continue
220+
}
221+
require.NotEmpty(t, v, "workspace template should not be empty")
222+
case "workspace/template_version.json":
223+
var v codersdk.TemplateVersion
224+
decodeJSONFromZip(t, f, &v)
225+
if !wantWorkspace {
226+
require.Empty(t, v, "expected workspace template version to be empty")
227+
continue
228+
}
229+
require.NotEmpty(t, v, "workspace template version should not be empty")
230+
case "workspace/parameters.json":
231+
var v []codersdk.WorkspaceBuildParameter
232+
decodeJSONFromZip(t, f, &v)
233+
if !wantWorkspace {
234+
require.Empty(t, v, "expected workspace parameters to be empty")
235+
continue
236+
}
237+
require.NotNil(t, v, "workspace parameters should not be nil")
238+
case "workspace/template_file.zip":
239+
bs := readBytesFromZip(t, f)
240+
if !wantWorkspace {
241+
require.Empty(t, bs, "expected template file to be empty")
242+
continue
243+
}
244+
require.NotNil(t, bs, "template file should not be nil")
184245
case "agent/agent.json":
185246
var v codersdk.WorkspaceAgent
186247
decodeJSONFromZip(t, f, &v)
248+
if !wantAgent {
249+
require.Empty(t, v, "expected agent to be empty")
250+
continue
251+
}
187252
require.NotEmpty(t, v, "agent should not be empty")
188253
case "agent/listening_ports.json":
189254
var v codersdk.WorkspaceAgentListeningPortsResponse
190255
decodeJSONFromZip(t, f, &v)
256+
if !wantAgent {
257+
require.Empty(t, v, "expected agent listening ports to be empty")
258+
continue
259+
}
191260
require.NotEmpty(t, v, "agent listening ports should not be empty")
192261
case "agent/logs.txt":
193262
bs := readBytesFromZip(t, f)
263+
if !wantAgent {
264+
require.Empty(t, bs, "expected agent logs to be empty")
265+
continue
266+
}
194267
require.NotEmpty(t, bs, "logs should not be empty")
195268
case "agent/agent_magicsock.html":
196269
bs := readBytesFromZip(t, f)
270+
if !wantAgent {
271+
require.Empty(t, bs, "expected agent magicsock to be empty")
272+
continue
273+
}
197274
require.NotEmpty(t, bs, "agent magicsock should not be empty")
198275
case "agent/client_magicsock.html":
199276
bs := readBytesFromZip(t, f)
277+
if !wantAgent {
278+
require.Empty(t, bs, "expected client magicsock to be empty")
279+
continue
280+
}
200281
require.NotEmpty(t, bs, "client magicsock should not be empty")
201282
case "agent/manifest.json":
202283
var v agentsdk.Manifest
203284
decodeJSONFromZip(t, f, &v)
285+
if !wantAgent {
286+
require.Empty(t, v, "expected agent manifest to be empty")
287+
continue
288+
}
204289
require.NotEmpty(t, v, "agent manifest should not be empty")
205290
case "agent/peer_diagnostics.json":
206291
var v *tailnet.PeerDiagnostics
207292
decodeJSONFromZip(t, f, &v)
293+
if !wantAgent {
294+
require.Empty(t, v, "expected peer diagnostics to be empty")
295+
continue
296+
}
208297
require.NotEmpty(t, v, "peer diagnostics should not be empty")
209298
case "agent/ping_result.json":
210299
var v *ipnstate.PingResult
211300
decodeJSONFromZip(t, f, &v)
301+
if !wantAgent {
302+
require.Empty(t, v, "expected ping result to be empty")
303+
continue
304+
}
212305
require.NotEmpty(t, v, "ping result should not be empty")
213306
case "agent/prometheus.txt":
214307
bs := readBytesFromZip(t, f)
308+
if !wantAgent {
309+
require.Empty(t, bs, "expected agent prometheus metrics to be empty")
310+
continue
311+
}
215312
require.NotEmpty(t, bs, "agent prometheus metrics should not be empty")
216313
case "agent/startup_logs.txt":
217314
bs := readBytesFromZip(t, f)
315+
if !wantAgent {
316+
require.Empty(t, bs, "expected agent startup logs to be empty")
317+
continue
318+
}
218319
require.Contains(t, string(bs), "started up")
219-
case "workspace/template.json":
220-
var v codersdk.Template
221-
decodeJSONFromZip(t, f, &v)
222-
require.NotEmpty(t, v, "workspace template should not be empty")
223-
case "workspace/template_version.json":
224-
var v codersdk.TemplateVersion
225-
decodeJSONFromZip(t, f, &v)
226-
require.NotEmpty(t, v, "workspace template version should not be empty")
227-
case "workspace/parameters.json":
228-
var v []codersdk.WorkspaceBuildParameter
229-
decodeJSONFromZip(t, f, &v)
230-
require.NotNil(t, v, "workspace parameters should not be nil")
231-
case "workspace/template_file.zip":
232-
bs := readBytesFromZip(t, f)
233-
require.NotNil(t, bs, "template file should not be nil")
234320
case "logs.txt":
235321
bs := readBytesFromZip(t, f)
236322
require.NotEmpty(t, bs, "logs should not be empty")

0 commit comments

Comments
 (0)