Skip to content

Commit 005f12c

Browse files
committed
Merge branch 'main' into dean/server-derp-force-websockets
2 parents e3dde15 + af939d1 commit 005f12c

File tree

62 files changed

+3304
-806
lines changed

Some content is hidden

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

62 files changed

+3304
-806
lines changed

.github/workflows/ci.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ jobs:
137137
138138
# Check for any typos
139139
- name: Check for typos
140-
uses: crate-ci/typos@v1.16.4
140+
uses: crate-ci/typos@v1.16.6
141141
with:
142142
config: .github/workflows/typos.toml
143143

@@ -568,6 +568,7 @@ jobs:
568568
# https://www.chromatic.com/docs/github-actions#forked-repositories
569569
projectToken: 695c25b6cb65
570570
workingDir: "./site"
571+
storybookBaseDir: "./site"
571572
# Prevent excessive build runs on minor version changes
572573
skip: "@(renovate/**|dependabot/**)"
573574
# Run TurboSnap to trace file dependencies to related stories
@@ -593,6 +594,7 @@ jobs:
593594
buildScriptName: "storybook:build"
594595
projectToken: 695c25b6cb65
595596
workingDir: "./site"
597+
storybookBaseDir: "./site"
596598
# Run TurboSnap to trace file dependencies to related stories
597599
# and tell chromatic to only take snapshots of relevent stories
598600
onlyChanged: true

.github/workflows/contrib.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ jobs:
4646
path-to-document: "https://github.com/coder/cla/blob/main/README.md"
4747
# branch should not be protected
4848
branch: "main"
49-
allowlist: dependabot*
49+
# Some users have signed a corporate CLA with Coder so are exempt from signing our community one.
50+
allowlist: "coryb,aaronlehmann,dependabot*"
5051

5152
release-labels:
5253
runs-on: ubuntu-latest

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ coderd/apidoc/swagger.json: $(shell find ./scripts/apidocgen $(FIND_EXCLUSIONS)
564564
./scripts/apidocgen/generate.sh
565565
pnpm run format:write:only ./docs/api ./docs/manifest.json ./coderd/apidoc/swagger.json
566566

567-
update-golden-files: cli/testdata/.gen-golden helm/coder/tests/testdata/.gen-golden helm/provisioner/tests/testdata/.gen-golden scripts/ci-report/testdata/.gen-golden enterprise/cli/testdata/.gen-golden
567+
update-golden-files: cli/testdata/.gen-golden helm/coder/tests/testdata/.gen-golden helm/provisioner/tests/testdata/.gen-golden scripts/ci-report/testdata/.gen-golden enterprise/cli/testdata/.gen-golden coderd/.gen-golden
568568
.PHONY: update-golden-files
569569

570570
cli/testdata/.gen-golden: $(wildcard cli/testdata/*.golden) $(wildcard cli/*.tpl) $(GO_SRC_FILES) $(wildcard cli/*_test.go)
@@ -583,6 +583,10 @@ helm/provisioner/tests/testdata/.gen-golden: $(wildcard helm/provisioner/tests/t
583583
go test ./helm/provisioner/tests -run=TestUpdateGoldenFiles -update
584584
touch "$@"
585585

586+
coderd/.gen-golden: $(wildcard coderd/testdata/*/*.golden) $(GO_SRC_FILES) $(wildcard coderd/*_test.go)
587+
go test ./coderd -run="Test.*Golden$$" -update
588+
touch "$@"
589+
586590
scripts/ci-report/testdata/.gen-golden: $(wildcard scripts/ci-report/testdata/*) $(wildcard scripts/ci-report/*.go)
587591
go test ./scripts/ci-report -run=TestOutputMatchesGoldenFile -update
588592
touch "$@"

cli/parameterresolver.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ next:
141141
continue // immutables should not be passed to consecutive builds
142142
}
143143

144+
if len(tvp.Options) > 0 && !isValidTemplateParameterOption(buildParameter, tvp.Options) {
145+
continue // do not propagate invalid options
146+
}
147+
144148
for i, r := range resolved {
145149
if r.Name == buildParameter.Name {
146150
resolved[i].Value = buildParameter.Value
@@ -180,10 +184,12 @@ func (pr *ParameterResolver) resolveWithInput(resolved []codersdk.WorkspaceBuild
180184
// Parameter has not been resolved yet, so CLI needs to determine if user should input it.
181185

182186
firstTimeUse := pr.isFirstTimeUse(tvp.Name)
187+
promptParameterOption := pr.isLastBuildParameterInvalidOption(tvp)
183188

184189
if (tvp.Ephemeral && pr.promptBuildOptions) ||
185190
(action == WorkspaceCreate && tvp.Required) ||
186191
(action == WorkspaceCreate && !tvp.Ephemeral) ||
192+
(action == WorkspaceUpdate && promptParameterOption) ||
187193
(action == WorkspaceUpdate && tvp.Mutable && tvp.Required) ||
188194
(action == WorkspaceUpdate && !tvp.Mutable && firstTimeUse) ||
189195
(action == WorkspaceUpdate && tvp.Mutable && !tvp.Ephemeral && pr.promptRichParameters) {
@@ -207,6 +213,19 @@ func (pr *ParameterResolver) isFirstTimeUse(parameterName string) bool {
207213
return findWorkspaceBuildParameter(parameterName, pr.lastBuildParameters) == nil
208214
}
209215

216+
func (pr *ParameterResolver) isLastBuildParameterInvalidOption(templateVersionParameter codersdk.TemplateVersionParameter) bool {
217+
if len(templateVersionParameter.Options) == 0 {
218+
return false
219+
}
220+
221+
for _, buildParameter := range pr.lastBuildParameters {
222+
if buildParameter.Name == templateVersionParameter.Name {
223+
return !isValidTemplateParameterOption(buildParameter, templateVersionParameter.Options)
224+
}
225+
}
226+
return false
227+
}
228+
210229
func findTemplateVersionParameter(workspaceBuildParameter codersdk.WorkspaceBuildParameter, templateVersionParameters []codersdk.TemplateVersionParameter) *codersdk.TemplateVersionParameter {
211230
for _, tvp := range templateVersionParameters {
212231
if tvp.Name == workspaceBuildParameter.Name {
@@ -224,3 +243,12 @@ func findWorkspaceBuildParameter(parameterName string, params []codersdk.Workspa
224243
}
225244
return nil
226245
}
246+
247+
func isValidTemplateParameterOption(buildParameter codersdk.WorkspaceBuildParameter, options []codersdk.TemplateVersionParameterOption) bool {
248+
for _, opt := range options {
249+
if opt.Value == buildParameter.Value {
250+
return true
251+
}
252+
}
253+
return false
254+
}

cli/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,8 @@ func (p *prettyErrorFormatter) format(err error) {
981981
msg = sdkError.Message
982982
if sdkError.Helper != "" {
983983
msg = msg + "\n" + sdkError.Helper
984+
} else if sdkError.Detail != "" {
985+
msg = msg + "\n" + sdkError.Detail
984986
}
985987
// The SDK error is usually good enough, and we don't want to overwhelm
986988
// the user with output.

cli/update_test.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,12 +593,138 @@ func TestUpdateValidateRichParameters(t *testing.T) {
593593
assert.NoError(t, err)
594594
}()
595595

596+
pty.ExpectMatch("Planning workspace...")
597+
<-doneChan
598+
})
599+
600+
t.Run("ParameterOptionChanged", func(t *testing.T) {
601+
t.Parallel()
602+
603+
// Create template and workspace
604+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
605+
user := coderdtest.CreateFirstUser(t, client)
606+
607+
templateParameters := []*proto.RichParameter{
608+
{Name: stringParameterName, Type: "string", Mutable: true, Required: true, Options: []*proto.RichParameterOption{
609+
{Name: "First option", Description: "This is first option", Value: "1st"},
610+
{Name: "Second option", Description: "This is second option", Value: "2nd"},
611+
{Name: "Third option", Description: "This is third option", Value: "3rd"},
612+
}},
613+
}
614+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(templateParameters))
615+
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
616+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
617+
618+
inv, root := clitest.New(t, "create", "my-workspace", "--yes", "--template", template.Name, "--parameter", fmt.Sprintf("%s=%s", stringParameterName, "2nd"))
619+
clitest.SetupConfig(t, client, root)
620+
err := inv.Run()
621+
require.NoError(t, err)
622+
623+
// Update template
624+
updatedTemplateParameters := []*proto.RichParameter{
625+
{Name: stringParameterName, Type: "string", Mutable: true, Required: true, Options: []*proto.RichParameterOption{
626+
{Name: "first_option", Description: "This is first option", Value: "1"},
627+
{Name: "second_option", Description: "This is second option", Value: "2"},
628+
{Name: "third_option", Description: "This is third option", Value: "3"},
629+
}},
630+
}
631+
632+
updatedVersion := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(updatedTemplateParameters), template.ID)
633+
coderdtest.AwaitTemplateVersionJob(t, client, updatedVersion.ID)
634+
err = client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{
635+
ID: updatedVersion.ID,
636+
})
637+
require.NoError(t, err)
638+
639+
// Update the workspace
640+
inv, root = clitest.New(t, "update", "my-workspace")
641+
clitest.SetupConfig(t, client, root)
642+
doneChan := make(chan struct{})
643+
pty := ptytest.New(t).Attach(inv)
644+
go func() {
645+
defer close(doneChan)
646+
err := inv.Run()
647+
assert.NoError(t, err)
648+
}()
649+
596650
matches := []string{
651+
stringParameterName, "second_option",
597652
"Planning workspace...", "",
598653
}
599654
for i := 0; i < len(matches); i += 2 {
600655
match := matches[i]
656+
value := matches[i+1]
601657
pty.ExpectMatch(match)
658+
659+
if value != "" {
660+
pty.WriteLine(value)
661+
}
662+
}
663+
<-doneChan
664+
})
665+
666+
t.Run("ParameterOptionDisappeared", func(t *testing.T) {
667+
t.Parallel()
668+
669+
// Create template and workspace
670+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
671+
user := coderdtest.CreateFirstUser(t, client)
672+
673+
templateParameters := []*proto.RichParameter{
674+
{Name: stringParameterName, Type: "string", Mutable: true, Required: true, Options: []*proto.RichParameterOption{
675+
{Name: "First option", Description: "This is first option", Value: "1st"},
676+
{Name: "Second option", Description: "This is second option", Value: "2nd"},
677+
{Name: "Third option", Description: "This is third option", Value: "3rd"},
678+
}},
679+
}
680+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(templateParameters))
681+
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
682+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
683+
684+
inv, root := clitest.New(t, "create", "my-workspace", "--yes", "--template", template.Name, "--parameter", fmt.Sprintf("%s=%s", stringParameterName, "2nd"))
685+
clitest.SetupConfig(t, client, root)
686+
err := inv.Run()
687+
require.NoError(t, err)
688+
689+
// Update template - 2nd option disappeared, 4th option added
690+
updatedTemplateParameters := []*proto.RichParameter{
691+
{Name: stringParameterName, Type: "string", Mutable: true, Required: true, Options: []*proto.RichParameterOption{
692+
{Name: "First option", Description: "This is first option", Value: "1st"},
693+
{Name: "Third option", Description: "This is third option", Value: "3rd"},
694+
{Name: "Fourth option", Description: "This is fourth option", Value: "4th"},
695+
}},
696+
}
697+
698+
updatedVersion := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(updatedTemplateParameters), template.ID)
699+
coderdtest.AwaitTemplateVersionJob(t, client, updatedVersion.ID)
700+
err = client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{
701+
ID: updatedVersion.ID,
702+
})
703+
require.NoError(t, err)
704+
705+
// Update the workspace
706+
inv, root = clitest.New(t, "update", "my-workspace")
707+
clitest.SetupConfig(t, client, root)
708+
doneChan := make(chan struct{})
709+
pty := ptytest.New(t).Attach(inv)
710+
go func() {
711+
defer close(doneChan)
712+
err := inv.Run()
713+
assert.NoError(t, err)
714+
}()
715+
716+
matches := []string{
717+
stringParameterName, "Third option",
718+
"Planning workspace...", "",
719+
}
720+
for i := 0; i < len(matches); i += 2 {
721+
match := matches[i]
722+
value := matches[i+1]
723+
pty.ExpectMatch(match)
724+
725+
if value != "" {
726+
pty.WriteLine(value)
727+
}
602728
}
603729
<-doneChan
604730
})

coderd/apidoc/docs.go

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 3 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderd_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package coderd_test
22

33
import (
44
"context"
5+
"flag"
56
"io"
67
"net/http"
78
"net/netip"
@@ -32,6 +33,9 @@ import (
3233
"github.com/coder/coder/v2/testutil"
3334
)
3435

36+
// updateGoldenFiles is a flag that can be set to update golden files.
37+
var updateGoldenFiles = flag.Bool("update", false, "Update golden files")
38+
3539
func TestMain(m *testing.M) {
3640
goleak.VerifyTestMain(m)
3741
}

0 commit comments

Comments
 (0)