Skip to content

chore: remove coder/preview dependency from codersdk #17939

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/parameterresolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func (pr *ParameterResolver) resolveWithInput(resolved []codersdk.WorkspaceBuild
if p != nil {
continue
}
// Parameter has not been resolved yet, so CLI needs to determine if user should input it.
// PreviewParameter has not been resolved yet, so CLI needs to determine if user should input it.

firstTimeUse := pr.isFirstTimeUse(tvp.Name)
promptParameterOption := pr.isLastBuildParameterInvalidOption(tvp)
Expand Down
82 changes: 82 additions & 0 deletions coderd/database/db2sdk/db2sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"github.com/google/uuid"
"github.com/hashicorp/hcl/v2"
"golang.org/x/xerrors"
"tailscale.com/tailcfg"

Expand All @@ -24,6 +25,7 @@ import (
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/provisionersdk/proto"
"github.com/coder/coder/v2/tailnet"
previewtypes "github.com/coder/preview/types"
)

// List is a helper function to reduce boilerplate when converting slices of
Expand Down Expand Up @@ -764,3 +766,83 @@ func Chat(chat database.Chat) codersdk.Chat {
func Chats(chats []database.Chat) []codersdk.Chat {
return List(chats, Chat)
}

func PreviewParameter(param previewtypes.Parameter) codersdk.PreviewParameter {
return codersdk.PreviewParameter{
PreviewParameterData: codersdk.PreviewParameterData{
Name: param.Name,
DisplayName: param.DisplayName,
Description: param.Description,
Type: codersdk.OptionType(param.Type),
FormType: codersdk.ParameterFormType(param.FormType),
Styling: codersdk.PreviewParameterStyling{
Placeholder: param.Styling.Placeholder,
Disabled: param.Styling.Disabled,
Label: param.Styling.Label,
},
Mutable: param.Mutable,
DefaultValue: PreviewHCLString(param.DefaultValue),
Icon: param.Icon,
Options: List(param.Options, PreviewParameterOption),
Validations: List(param.Validations, PreviewParameterValidation),
Required: param.Required,
Order: param.Order,
Ephemeral: param.Ephemeral,
},
Value: PreviewHCLString(param.Value),
Diagnostics: PreviewDiagnostics(param.Diagnostics),
}
}

func HCLDiagnostics(d hcl.Diagnostics) []codersdk.FriendlyDiagnostic {
return PreviewDiagnostics(previewtypes.Diagnostics(d))
}

func PreviewDiagnostics(d previewtypes.Diagnostics) []codersdk.FriendlyDiagnostic {
f := d.FriendlyDiagnostics()
return List(f, func(f previewtypes.FriendlyDiagnostic) codersdk.FriendlyDiagnostic {
return codersdk.FriendlyDiagnostic{
Severity: codersdk.DiagnosticSeverityString(f.Severity),
Summary: f.Summary,
Detail: f.Detail,
Extra: codersdk.DiagnosticExtra{
Code: f.Extra.Code,
},
}
})
}

func PreviewHCLString(h previewtypes.HCLString) codersdk.NullHCLString {
n := h.NullHCLString()
return codersdk.NullHCLString{
Value: n.Value,
Valid: n.Valid,
}
}

func PreviewParameterOption(o *previewtypes.ParameterOption) codersdk.PreviewParameterOption {
if o == nil {
// This should never be sent
return codersdk.PreviewParameterOption{}
}
return codersdk.PreviewParameterOption{
Name: o.Name,
Description: o.Description,
Value: PreviewHCLString(o.Value),
Icon: o.Icon,
}
}

func PreviewParameterValidation(v *previewtypes.ParameterValidation) codersdk.PreviewParameterValidation {
if v == nil {
// This should never be sent
return codersdk.PreviewParameterValidation{}
}
return codersdk.PreviewParameterValidation{
Error: v.Error,
Regex: v.Regex,
Min: v.Min,
Max: v.Max,
Monotonic: v.Monotonic,
}
}
9 changes: 5 additions & 4 deletions coderd/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/coder/coder/v2/apiversion"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/db2sdk"
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/files"
"github.com/coder/coder/v2/coderd/httpapi"
Expand Down Expand Up @@ -289,10 +290,10 @@ func (api *API) handleParameterWebsocket(rw http.ResponseWriter, r *http.Request
result, diagnostics := render(ctx, map[string]string{})
response := codersdk.DynamicParametersResponse{
ID: -1, // Always start with -1.
Diagnostics: previewtypes.Diagnostics(diagnostics),
Diagnostics: db2sdk.HCLDiagnostics(diagnostics),
}
if result != nil {
response.Parameters = result.Parameters
response.Parameters = db2sdk.List(result.Parameters, db2sdk.PreviewParameter)
}
err = stream.Send(response)
if err != nil {
Expand All @@ -317,10 +318,10 @@ func (api *API) handleParameterWebsocket(rw http.ResponseWriter, r *http.Request
result, diagnostics := render(ctx, update.Inputs)
response := codersdk.DynamicParametersResponse{
ID: update.ID,
Diagnostics: previewtypes.Diagnostics(diagnostics),
Diagnostics: db2sdk.HCLDiagnostics(diagnostics),
}
if result != nil {
response.Parameters = result.Parameters
response.Parameters = db2sdk.List(result.Parameters, db2sdk.PreviewParameter)
}
err = stream.Send(response)
if err != nil {
Expand Down
16 changes: 8 additions & 8 deletions coderd/parameters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ func TestDynamicParametersOwnerSSHPublicKey(t *testing.T) {
require.Equal(t, -1, preview.ID)
require.Empty(t, preview.Diagnostics)
require.Equal(t, "public_key", preview.Parameters[0].Name)
require.True(t, preview.Parameters[0].Value.Valid())
require.Equal(t, sshKey.PublicKey, preview.Parameters[0].Value.Value.AsString())
require.True(t, preview.Parameters[0].Value.Valid)
require.Equal(t, sshKey.PublicKey, preview.Parameters[0].Value.Value)
}

func TestDynamicParametersWithTerraformValues(t *testing.T) {
Expand Down Expand Up @@ -103,8 +103,8 @@ func TestDynamicParametersWithTerraformValues(t *testing.T) {

require.Len(t, preview.Parameters, 1)
require.Equal(t, "jetbrains_ide", preview.Parameters[0].Name)
require.True(t, preview.Parameters[0].Value.Valid())
require.Equal(t, "CL", preview.Parameters[0].Value.AsString())
require.True(t, preview.Parameters[0].Value.Valid)
require.Equal(t, "CL", preview.Parameters[0].Value.Value)
})

// OldProvisioners use the static parameters in the dynamic param flow
Expand Down Expand Up @@ -154,8 +154,8 @@ func TestDynamicParametersWithTerraformValues(t *testing.T) {
require.Contains(t, preview.Diagnostics[0].Summary, "required metadata to support dynamic parameters")
require.Len(t, preview.Parameters, 1)
require.Equal(t, "jetbrains_ide", preview.Parameters[0].Name)
require.True(t, preview.Parameters[0].Value.Valid())
require.Equal(t, defaultValue, preview.Parameters[0].Value.AsString())
require.True(t, preview.Parameters[0].Value.Valid)
require.Equal(t, defaultValue, preview.Parameters[0].Value.Value)

// Test some inputs
for _, exp := range []string{defaultValue, "GO", "Invalid", defaultValue} {
Expand All @@ -182,8 +182,8 @@ func TestDynamicParametersWithTerraformValues(t *testing.T) {
require.Len(t, preview.Parameters[0].Diagnostics, 0)
}
require.Equal(t, "jetbrains_ide", preview.Parameters[0].Name)
require.True(t, preview.Parameters[0].Value.Valid())
require.Equal(t, exp, preview.Parameters[0].Value.AsString())
require.True(t, preview.Parameters[0].Value.Valid)
require.Equal(t, exp, preview.Parameters[0].Value.Value)
}
})

Expand Down
118 changes: 111 additions & 7 deletions codersdk/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,121 @@ import (
"github.com/google/uuid"

"github.com/coder/coder/v2/codersdk/wsjson"
previewtypes "github.com/coder/preview/types"
"github.com/coder/websocket"
)

// FriendlyDiagnostic is included to guarantee it is generated in the output
// types. This is used as the type override for `previewtypes.Diagnostic`.
type FriendlyDiagnostic = previewtypes.FriendlyDiagnostic
type ParameterFormType string

// NullHCLString is included to guarantee it is generated in the output
// types. This is used as the type override for `previewtypes.HCLString`.
type NullHCLString = previewtypes.NullHCLString
const (
ParameterFormTypeDefault ParameterFormType = ""
ParameterFormTypeRadio ParameterFormType = "radio"
ParameterFormTypeSlider ParameterFormType = "slider"
ParameterFormTypeInput ParameterFormType = "input"
ParameterFormTypeDropdown ParameterFormType = "dropdown"
ParameterFormTypeCheckbox ParameterFormType = "checkbox"
ParameterFormTypeSwitch ParameterFormType = "switch"
ParameterFormTypeMultiSelect ParameterFormType = "multi-select"
ParameterFormTypeTagSelect ParameterFormType = "tag-select"
ParameterFormTypeTextArea ParameterFormType = "textarea"
ParameterFormTypeError ParameterFormType = "error"
)

type OptionType string

const (
OptionTypeString OptionType = "string"
OptionTypeNumber OptionType = "number"
OptionTypeBoolean OptionType = "bool"
OptionTypeListString OptionType = "list(string)"
)

type DiagnosticSeverityString string

const (
DiagnosticSeverityError DiagnosticSeverityString = "error"
DiagnosticSeverityWarning DiagnosticSeverityString = "warning"
)

// FriendlyDiagnostic == previewtypes.FriendlyDiagnostic
// Copied to avoid import deps
type FriendlyDiagnostic struct {
Severity DiagnosticSeverityString `json:"severity"`
Summary string `json:"summary"`
Detail string `json:"detail"`

Extra DiagnosticExtra `json:"extra"`
}

type DiagnosticExtra struct {
Code string `json:"code"`
}

// NullHCLString == `previewtypes.NullHCLString`.
type NullHCLString struct {
Value string `json:"value"`
Valid bool `json:"valid"`
}

type PreviewParameter struct {
PreviewParameterData
Value NullHCLString `json:"value"`
Diagnostics []FriendlyDiagnostic `json:"diagnostics"`
}

type PreviewParameterData struct {
Name string `json:"name"`
DisplayName string `json:"display_name"`
Description string `json:"description"`
Type OptionType `json:"type"`
FormType ParameterFormType `json:"form_type"`
Styling PreviewParameterStyling `json:"styling"`
Mutable bool `json:"mutable"`
DefaultValue NullHCLString `json:"default_value"`
Icon string `json:"icon"`
Options []PreviewParameterOption `json:"options"`
Validations []PreviewParameterValidation `json:"validations"`
Required bool `json:"required"`
// legacy_variable_name was removed (= 14)
Order int64 `json:"order"`
Ephemeral bool `json:"ephemeral"`
}

type PreviewParameterStyling struct {
Placeholder *string `json:"placeholder,omitempty"`
Disabled *bool `json:"disabled,omitempty"`
Label *string `json:"label,omitempty"`
}

type PreviewParameterOption struct {
Name string `json:"name"`
Description string `json:"description"`
Value NullHCLString `json:"value"`
Icon string `json:"icon"`
}

type PreviewParameterValidation struct {
Error string `json:"validation_error"`

// All validation attributes are optional.
Regex *string `json:"validation_regex"`
Min *int64 `json:"validation_min"`
Max *int64 `json:"validation_max"`
Monotonic *string `json:"validation_monotonic"`
}

type DynamicParametersRequest struct {
// ID identifies the request. The response contains the same
// ID so that the client can match it to the request.
ID int `json:"id"`
Inputs map[string]string `json:"inputs"`
}

type DynamicParametersResponse struct {
ID int `json:"id"`
Diagnostics []FriendlyDiagnostic `json:"diagnostics"`
Parameters []PreviewParameter `json:"parameters"`
// TODO: Workspace tags
}

func (c *Client) TemplateVersionDynamicParameters(ctx context.Context, userID, version uuid.UUID) (*wsjson.Stream[DynamicParametersResponse, DynamicParametersRequest], error) {
conn, err := c.Dial(ctx, fmt.Sprintf("/api/v2/users/%s/templateversions/%s/parameters", userID, version), nil)
Expand Down
16 changes: 0 additions & 16 deletions codersdk/templateversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import (
"time"

"github.com/google/uuid"

previewtypes "github.com/coder/preview/types"
)

type TemplateVersionWarning string
Expand Down Expand Up @@ -125,20 +123,6 @@ func (c *Client) CancelTemplateVersion(ctx context.Context, version uuid.UUID) e
return nil
}

type DynamicParametersRequest struct {
// ID identifies the request. The response contains the same
// ID so that the client can match it to the request.
ID int `json:"id"`
Inputs map[string]string `json:"inputs"`
}

type DynamicParametersResponse struct {
ID int `json:"id"`
Diagnostics previewtypes.Diagnostics `json:"diagnostics"`
Parameters []previewtypes.Parameter `json:"parameters"`
// TODO: Workspace tags
}

// TemplateVersionParameters returns parameters a template version exposes.
func (c *Client) TemplateVersionRichParameters(ctx context.Context, version uuid.UUID) ([]TemplateVersionParameter, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/rich-parameters", version), nil)
Expand Down
12 changes: 6 additions & 6 deletions enterprise/coderd/parameters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ func TestDynamicParametersOwnerGroups(t *testing.T) {
require.Equal(t, -1, preview.ID)
require.Empty(t, preview.Diagnostics)
require.Equal(t, "group", preview.Parameters[0].Name)
require.True(t, preview.Parameters[0].Value.Valid())
require.Equal(t, database.EveryoneGroup, preview.Parameters[0].Value.Value.AsString())
require.True(t, preview.Parameters[0].Value.Valid)
require.Equal(t, database.EveryoneGroup, preview.Parameters[0].Value.Value)

// Send a new value, and see it reflected
err = stream.Send(codersdk.DynamicParametersRequest{
Expand All @@ -83,8 +83,8 @@ func TestDynamicParametersOwnerGroups(t *testing.T) {
require.Equal(t, 1, preview.ID)
require.Empty(t, preview.Diagnostics)
require.Equal(t, "group", preview.Parameters[0].Name)
require.True(t, preview.Parameters[0].Value.Valid())
require.Equal(t, group.Name, preview.Parameters[0].Value.Value.AsString())
require.True(t, preview.Parameters[0].Value.Valid)
require.Equal(t, group.Name, preview.Parameters[0].Value.Value)

// Back to default
err = stream.Send(codersdk.DynamicParametersRequest{
Expand All @@ -96,6 +96,6 @@ func TestDynamicParametersOwnerGroups(t *testing.T) {
require.Equal(t, 3, preview.ID)
require.Empty(t, preview.Diagnostics)
require.Equal(t, "group", preview.Parameters[0].Name)
require.True(t, preview.Parameters[0].Value.Valid())
require.Equal(t, database.EveryoneGroup, preview.Parameters[0].Value.Value.AsString())
require.True(t, preview.Parameters[0].Value.Valid)
require.Equal(t, database.EveryoneGroup, preview.Parameters[0].Value.Value)
}
Loading
Loading