Skip to content

Commit 263e7e5

Browse files
committed
Merge branch 'main' into 5751/deployment-dau/presleyp
2 parents 20390ce + bbb208e commit 263e7e5

Some content is hidden

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

58 files changed

+2643
-755
lines changed

.github/workflows/coder.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ jobs:
215215

216216
- name: Install sqlc
217217
run: |
218-
curl -sSL https://github.com/kyleconroy/sqlc/releases/download/v1.13.0/sqlc_1.13.0_linux_amd64.tar.gz | sudo tar -C /usr/bin -xz sqlc
218+
curl -sSL https://github.com/kyleconroy/sqlc/releases/download/v1.16.0/sqlc_1.16.0_linux_amd64.tar.gz | sudo tar -C /usr/bin -xz sqlc
219219
- name: Install protoc-gen-go
220220
run: go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
221221
- name: Install protoc-gen-go-drpc

.github/workflows/release.yaml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ jobs:
253253
retention-days: 7
254254

255255
publish-winget:
256+
name: Publish to winget-pkgs
256257
runs-on: windows-latest
257258
needs: release
258259
steps:
@@ -308,18 +309,22 @@ jobs:
308309
--submit `
309310
--version "${version}" `
310311
--urls "${installer_url}|X64" `
311-
--token "${{ secrets.CDRCI_GITHUB_TOKEN }}"
312+
--token "$env:WINGET_GH_TOKEN"
312313
313314
env:
314315
# For gh CLI:
315316
GH_TOKEN: ${{ github.token }}
317+
# For wingetcreate. We need a real token since we're pushing a commit
318+
# to GitHub and then making a PR in a different repo.
319+
WINGET_GH_TOKEN: ${{ secrets.CDRCI_GITHUB_TOKEN }}
316320

317321
- name: Comment on PR
322+
if: ${{ !inputs.dry_run }}
318323
run: |
319324
# Find the PR that wingetcreate just made.
320325
$version = "${{ needs.release.outputs.version }}".Trim('v')
321326
$pr_list = gh pr list --repo microsoft/winget-pkgs --search "author:cdrci Coder.Coder version ${version}" --limit 1 --json number | `
322-
ConvertFrom-Json`
327+
ConvertFrom-Json
323328
$pr_number = $pr_list[0].number
324329
325330
gh pr comment --repo microsoft/winget-pkgs "${pr_number}" --body "🤖 cc: @deansheather @matifali"

agent/agent_test.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,16 @@ func TestAgent_GitSSH(t *testing.T) {
133133

134134
func TestAgent_SessionTTYShell(t *testing.T) {
135135
t.Parallel()
136+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
137+
t.Cleanup(cancel)
136138
if runtime.GOOS == "windows" {
137139
// This might be our implementation, or ConPTY itself.
138140
// It's difficult to find extensive tests for it, so
139141
// it seems like it could be either.
140142
t.Skip("ConPTY appears to be inconsistent on Windows.")
141143
}
142144
session := setupSSHSession(t, codersdk.WorkspaceAgentMetadata{})
143-
command := "bash"
145+
command := "sh"
144146
if runtime.GOOS == "windows" {
145147
command = "cmd.exe"
146148
}
@@ -152,11 +154,7 @@ func TestAgent_SessionTTYShell(t *testing.T) {
152154
session.Stdin = ptty.Input()
153155
err = session.Start(command)
154156
require.NoError(t, err)
155-
caret := "$"
156-
if runtime.GOOS == "windows" {
157-
caret = ">"
158-
}
159-
ptty.ExpectMatch(caret)
157+
_ = ptty.Peek(ctx, 1) // wait for the prompt
160158
ptty.WriteLine("echo test")
161159
ptty.ExpectMatch("test")
162160
ptty.WriteLine("exit")

cli/cliui/parameter.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,56 @@ func ParameterSchema(cmd *cobra.Command, parameterSchema codersdk.ParameterSchem
6060

6161
return value, nil
6262
}
63+
64+
func RichParameter(cmd *cobra.Command, templateVersionParameter codersdk.TemplateVersionParameter) (string, error) {
65+
_, _ = fmt.Fprintln(cmd.OutOrStdout(), Styles.Bold.Render(templateVersionParameter.Name))
66+
if templateVersionParameter.Description != "" {
67+
_, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+strings.TrimSpace(strings.Join(strings.Split(templateVersionParameter.Description, "\n"), "\n "))+"\n")
68+
}
69+
70+
// TODO Implement full validation and show descriptions.
71+
var err error
72+
var value string
73+
if len(templateVersionParameter.Options) > 0 {
74+
// Move the cursor up a single line for nicer display!
75+
_, _ = fmt.Fprint(cmd.OutOrStdout(), "\033[1A")
76+
value, err = Select(cmd, SelectOptions{
77+
Options: templateVersionParameterOptionValues(templateVersionParameter),
78+
Default: templateVersionParameter.DefaultValue,
79+
HideSearch: true,
80+
})
81+
if err == nil {
82+
_, _ = fmt.Fprintln(cmd.OutOrStdout())
83+
_, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+Styles.Prompt.String()+Styles.Field.Render(value))
84+
}
85+
} else {
86+
text := "Enter a value"
87+
if templateVersionParameter.DefaultValue != "" {
88+
text += fmt.Sprintf(" (default: %q)", templateVersionParameter.DefaultValue)
89+
}
90+
text += ":"
91+
92+
value, err = Prompt(cmd, PromptOptions{
93+
Text: Styles.Bold.Render(text),
94+
})
95+
value = strings.TrimSpace(value)
96+
}
97+
if err != nil {
98+
return "", err
99+
}
100+
101+
// If they didn't specify anything, use the default value if set.
102+
if len(templateVersionParameter.Options) == 0 && value == "" {
103+
value = templateVersionParameter.DefaultValue
104+
}
105+
106+
return value, nil
107+
}
108+
109+
func templateVersionParameterOptionValues(param codersdk.TemplateVersionParameter) []string {
110+
var options []string
111+
for _, opt := range param.Options {
112+
options = append(options, opt.Value)
113+
}
114+
return options
115+
}

cli/create.go

Lines changed: 104 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ import (
1717

1818
func create() *cobra.Command {
1919
var (
20-
parameterFile string
21-
templateName string
22-
startAt string
23-
stopAfter time.Duration
24-
workspaceName string
20+
parameterFile string
21+
richParameterFile string
22+
templateName string
23+
startAt string
24+
stopAfter time.Duration
25+
workspaceName string
2526
)
2627
cmd := &cobra.Command{
2728
Annotations: workspaceCommand,
@@ -121,11 +122,12 @@ func create() *cobra.Command {
121122
schedSpec = ptr.Ref(sched.String())
122123
}
123124

124-
parameters, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{
125-
Template: template,
126-
ExistingParams: []codersdk.Parameter{},
127-
ParameterFile: parameterFile,
128-
NewWorkspaceName: workspaceName,
125+
buildParams, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{
126+
Template: template,
127+
ExistingParams: []codersdk.Parameter{},
128+
ParameterFile: parameterFile,
129+
RichParameterFile: richParameterFile,
130+
NewWorkspaceName: workspaceName,
129131
})
130132
if err != nil {
131133
return err
@@ -140,11 +142,12 @@ func create() *cobra.Command {
140142
}
141143

142144
workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.Me, codersdk.CreateWorkspaceRequest{
143-
TemplateID: template.ID,
144-
Name: workspaceName,
145-
AutostartSchedule: schedSpec,
146-
TTLMillis: ptr.Ref(stopAfter.Milliseconds()),
147-
ParameterValues: parameters,
145+
TemplateID: template.ID,
146+
Name: workspaceName,
147+
AutostartSchedule: schedSpec,
148+
TTLMillis: ptr.Ref(stopAfter.Milliseconds()),
149+
ParameterValues: buildParams.parameters,
150+
RichParameterValues: buildParams.richParameters,
148151
})
149152
if err != nil {
150153
return err
@@ -163,26 +166,40 @@ func create() *cobra.Command {
163166
cliui.AllowSkipPrompt(cmd)
164167
cliflag.StringVarP(cmd.Flags(), &templateName, "template", "t", "CODER_TEMPLATE_NAME", "", "Specify a template name.")
165168
cliflag.StringVarP(cmd.Flags(), &parameterFile, "parameter-file", "", "CODER_PARAMETER_FILE", "", "Specify a file path with parameter values.")
169+
cliflag.StringVarP(cmd.Flags(), &richParameterFile, "rich-parameter-file", "", "CODER_RICH_PARAMETER_FILE", "", "Specify a file path with values for rich parameters defined in the template.")
166170
cliflag.StringVarP(cmd.Flags(), &startAt, "start-at", "", "CODER_WORKSPACE_START_AT", "", "Specify the workspace autostart schedule. Check `coder schedule start --help` for the syntax.")
167171
cliflag.DurationVarP(cmd.Flags(), &stopAfter, "stop-after", "", "CODER_WORKSPACE_STOP_AFTER", 8*time.Hour, "Specify a duration after which the workspace should shut down (e.g. 8h).")
168172
return cmd
169173
}
170174

171175
type prepWorkspaceBuildArgs struct {
172-
Template codersdk.Template
173-
ExistingParams []codersdk.Parameter
174-
ParameterFile string
175-
NewWorkspaceName string
176+
Template codersdk.Template
177+
ExistingParams []codersdk.Parameter
178+
ParameterFile string
179+
ExistingRichParams []codersdk.WorkspaceBuildParameter
180+
RichParameterFile string
181+
NewWorkspaceName string
182+
183+
UpdateWorkspace bool
184+
}
185+
186+
type buildParameters struct {
187+
// Parameters contains legacy parameters stored in /parameters.
188+
parameters []codersdk.CreateParameterRequest
189+
// Rich parameters stores values for build parameters annotated with description, icon, type, etc.
190+
richParameters []codersdk.WorkspaceBuildParameter
176191
}
177192

178193
// prepWorkspaceBuild will ensure a workspace build will succeed on the latest template version.
179-
// Any missing params will be prompted to the user.
180-
func prepWorkspaceBuild(cmd *cobra.Command, client *codersdk.Client, args prepWorkspaceBuildArgs) ([]codersdk.CreateParameterRequest, error) {
194+
// Any missing params will be prompted to the user. It supports legacy and rich parameters.
195+
func prepWorkspaceBuild(cmd *cobra.Command, client *codersdk.Client, args prepWorkspaceBuildArgs) (*buildParameters, error) {
181196
ctx := cmd.Context()
182197
templateVersion, err := client.TemplateVersion(ctx, args.Template.ActiveVersionID)
183198
if err != nil {
184199
return nil, err
185200
}
201+
202+
// Legacy parameters
186203
parameterSchemas, err := client.TemplateVersionSchema(ctx, templateVersion.ID)
187204
if err != nil {
188205
return nil, err
@@ -200,7 +217,7 @@ func prepWorkspaceBuild(cmd *cobra.Command, client *codersdk.Client, args prepWo
200217
}
201218
}
202219
disclaimerPrinted := false
203-
parameters := make([]codersdk.CreateParameterRequest, 0)
220+
legacyParameters := make([]codersdk.CreateParameterRequest, 0)
204221
PromptParamLoop:
205222
for _, parameterSchema := range parameterSchemas {
206223
if !parameterSchema.AllowOverrideSource {
@@ -227,19 +244,76 @@ PromptParamLoop:
227244
return nil, err
228245
}
229246

230-
parameters = append(parameters, codersdk.CreateParameterRequest{
247+
legacyParameters = append(legacyParameters, codersdk.CreateParameterRequest{
231248
Name: parameterSchema.Name,
232249
SourceValue: parameterValue,
233250
SourceScheme: codersdk.ParameterSourceSchemeData,
234251
DestinationScheme: parameterSchema.DefaultDestinationScheme,
235252
})
236253
}
237-
_, _ = fmt.Fprintln(cmd.OutOrStdout())
254+
255+
if disclaimerPrinted {
256+
_, _ = fmt.Fprintln(cmd.OutOrStdout())
257+
}
258+
259+
// Rich parameters
260+
templateVersionParameters, err := client.TemplateVersionRichParameters(cmd.Context(), templateVersion.ID)
261+
if err != nil {
262+
return nil, xerrors.Errorf("get template version rich parameters: %w", err)
263+
}
264+
265+
parameterMapFromFile = map[string]string{}
266+
useParamFile = false
267+
if args.RichParameterFile != "" {
268+
useParamFile = true
269+
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Paragraph.Render("Attempting to read the variables from the rich parameter file.")+"\r\n")
270+
parameterMapFromFile, err = createParameterMapFromFile(args.RichParameterFile)
271+
if err != nil {
272+
return nil, err
273+
}
274+
}
275+
disclaimerPrinted = false
276+
richParameters := make([]codersdk.WorkspaceBuildParameter, 0)
277+
PromptRichParamLoop:
278+
for _, templateVersionParameter := range templateVersionParameters {
279+
if !disclaimerPrinted {
280+
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Paragraph.Render("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss).")+"\r\n")
281+
disclaimerPrinted = true
282+
}
283+
284+
// Param file is all or nothing
285+
if !useParamFile {
286+
for _, e := range args.ExistingRichParams {
287+
if e.Name == templateVersionParameter.Name {
288+
// If the param already exists, we do not need to prompt it again.
289+
// The workspace scope will reuse params for each build.
290+
continue PromptRichParamLoop
291+
}
292+
}
293+
}
294+
295+
if args.UpdateWorkspace && !templateVersionParameter.Mutable {
296+
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Warn.Render(fmt.Sprintf(`Parameter %q is not mutable, so can't be customized after workspace creation.`, templateVersionParameter.Name)))
297+
continue
298+
}
299+
300+
parameterValue, err := getWorkspaceBuildParameterValueFromMapOrInput(cmd, parameterMapFromFile, templateVersionParameter)
301+
if err != nil {
302+
return nil, err
303+
}
304+
305+
richParameters = append(richParameters, *parameterValue)
306+
}
307+
308+
if disclaimerPrinted {
309+
_, _ = fmt.Fprintln(cmd.OutOrStdout())
310+
}
238311

239312
// Run a dry-run with the given parameters to check correctness
240313
dryRun, err := client.CreateTemplateVersionDryRun(cmd.Context(), templateVersion.ID, codersdk.CreateTemplateVersionDryRunRequest{
241-
WorkspaceName: args.NewWorkspaceName,
242-
ParameterValues: parameters,
314+
WorkspaceName: args.NewWorkspaceName,
315+
ParameterValues: legacyParameters,
316+
RichParameterValues: richParameters,
243317
})
244318
if err != nil {
245319
return nil, xerrors.Errorf("begin workspace dry-run: %w", err)
@@ -279,5 +353,8 @@ PromptParamLoop:
279353
return nil, err
280354
}
281355

282-
return parameters, nil
356+
return &buildParameters{
357+
parameters: legacyParameters,
358+
richParameters: richParameters,
359+
}, nil
283360
}

0 commit comments

Comments
 (0)