Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit57bf997

Browse files
authored
feat: support custom validation errors for number-typed parameters (#12224)
1 parent6414b7a commit57bf997

File tree

7 files changed

+156
-9
lines changed

7 files changed

+156
-9
lines changed

‎cli/create_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,14 @@ func TestCreateValidateRichParameters(t *testing.T) {
556556
{Name:numberParameterName,Type:"number",Mutable:true,ValidationMin:ptr.Ref(int32(3)),ValidationMax:ptr.Ref(int32(10))},
557557
}
558558

559+
numberCustomErrorRichParameters:= []*proto.RichParameter{
560+
{
561+
Name:numberParameterName,Type:"number",Mutable:true,
562+
ValidationMin:ptr.Ref(int32(3)),ValidationMax:ptr.Ref(int32(10)),
563+
ValidationError:"These are values: {min}, {max}, and {value}.",
564+
},
565+
}
566+
559567
stringRichParameters:= []*proto.RichParameter{
560568
{Name:stringParameterName,Type:"string",Mutable:true,ValidationRegex:"^[a-z]+$",ValidationError:"this is error"},
561569
}
@@ -644,6 +652,44 @@ func TestCreateValidateRichParameters(t *testing.T) {
644652
<-doneChan
645653
})
646654

655+
t.Run("ValidateNumber_CustomError",func(t*testing.T) {
656+
t.Parallel()
657+
658+
client:=coderdtest.New(t,&coderdtest.Options{IncludeProvisionerDaemon:true})
659+
owner:=coderdtest.CreateFirstUser(t,client)
660+
member,_:=coderdtest.CreateAnotherUser(t,client,owner.OrganizationID)
661+
version:=coderdtest.CreateTemplateVersion(t,client,owner.OrganizationID,prepareEchoResponses(numberCustomErrorRichParameters))
662+
coderdtest.AwaitTemplateVersionJobCompleted(t,client,version.ID)
663+
664+
template:=coderdtest.CreateTemplate(t,client,owner.OrganizationID,version.ID)
665+
666+
inv,root:=clitest.New(t,"create","my-workspace","--template",template.Name)
667+
clitest.SetupConfig(t,member,root)
668+
doneChan:=make(chanstruct{})
669+
pty:=ptytest.New(t).Attach(inv)
670+
gofunc() {
671+
deferclose(doneChan)
672+
err:=inv.Run()
673+
assert.NoError(t,err)
674+
}()
675+
676+
matches:= []string{
677+
numberParameterName,"12",
678+
"These are values: 3, 10, and 12.","",
679+
"Enter a value","8",
680+
"Confirm create?","yes",
681+
}
682+
fori:=0;i<len(matches);i+=2 {
683+
match:=matches[i]
684+
value:=matches[i+1]
685+
pty.ExpectMatch(match)
686+
ifvalue!="" {
687+
pty.WriteLine(value)
688+
}
689+
}
690+
<-doneChan
691+
})
692+
647693
t.Run("ValidateBool",func(t*testing.T) {
648694
t.Parallel()
649695

‎codersdk/richparameters_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,24 @@ func TestParameterResolver_ValidateResolve_Ephemeral_UseEmptyDefault(t *testing.
376376
require.NoError(t,err)
377377
require.Equal(t,"",v)
378378
}
379+
380+
funcTestParameterResolver_ValidateResolve_Number_CustomError(t*testing.T) {
381+
t.Parallel()
382+
uut:= codersdk.ParameterResolver{}
383+
p:= codersdk.TemplateVersionParameter{
384+
Name:"n",
385+
Type:"number",
386+
Mutable:true,
387+
DefaultValue:"5",
388+
389+
ValidationMin:ptr.Ref(int32(4)),
390+
ValidationMax:ptr.Ref(int32(6)),
391+
ValidationError:"These are values for testing purposes: {min}, {max}, and {value}.",
392+
}
393+
_,err:=uut.ValidateResolve(p,&codersdk.WorkspaceBuildParameter{
394+
Name:"n",
395+
Value:"8",
396+
})
397+
require.Error(t,err)
398+
require.Contains(t,err.Error(),"These are values for testing purposes: 4, 6, and 8.")
399+
}

‎docs/templates/parameters.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,23 @@ data "coder_parameter" "instances" {
249249
}
250250
```
251251

252+
It is possible to override the default`error` message for a`number` parameter,
253+
along with its associated`min` and/or`max` properties. The following message
254+
placeholders are available`{min}`,`{max}`, and`{value}`.
255+
256+
```hcl
257+
data "coder_parameter" "instances" {
258+
name = "Instances"
259+
type = "number"
260+
description = "Number of compute instances"
261+
validation {
262+
min = 1
263+
max = 4
264+
error = "Sorry, we can't provision too many instances - maximum limit: {max}, wanted: {value}."
265+
}
266+
}
267+
```
268+
252269
###String
253270

254271
You can validate a`string` parameter to match a regular expression. The`regex`

‎go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ require (
9696
github.com/coder/flogv1.1.0
9797
github.com/coder/prettyv0.0.0-20230908205945-e89ba86370e0
9898
github.com/coder/retryv1.5.1
99-
github.com/coder/terraform-provider-coderv0.17.0
99+
github.com/coder/terraform-provider-coderv0.18.0
100100
github.com/coder/wgtunnelv0.1.13-0.20231127054351-578bfff9b92a
101101
github.com/coreos/go-oidc/v3v3.9.0
102102
github.com/coreos/go-systemdv0.0.0-20191104093116-d3cd4ed1dbcf

‎go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ github.com/coder/ssh v0.0.0-20231128192721-70855dedb788 h1:YoUSJ19E8AtuUFVYBpXuO
204204
github.com/coder/sshv0.0.0-20231128192721-70855dedb788/go.mod h1:aGQbuCLyhRLMzZF067xc84Lh7JDs1FKwCmF1Crl9dxQ=
205205
github.com/coder/tailscalev1.1.1-0.20240214140224-3788ab894ba1 h1:A7dZHNidAVH6Kxn5D3hTEH+iRO8slnM0aRer6/cxlyE=
206206
github.com/coder/tailscalev1.1.1-0.20240214140224-3788ab894ba1/go.mod h1:L8tPrwSi31RAMEMV8rjb0vYTGs7rXt8rAHbqY/p41j4=
207-
github.com/coder/terraform-provider-coderv0.17.0 h1:qwdLSbh6vPN+QDDvw1WNSYYEFlFwJFwzzP9vrvwr/ks=
208-
github.com/coder/terraform-provider-coderv0.17.0/go.mod h1:pACHRoXSHBGyY696mLeQ1hR/Ag1G2wFk5bw0mT5Zp2g=
207+
github.com/coder/terraform-provider-coderv0.18.0 h1:JWSBsOuzyiCev3C2Aj8Y1dvJkm5JMysIrIylMJtzPAY=
208+
github.com/coder/terraform-provider-coderv0.18.0/go.mod h1:pACHRoXSHBGyY696mLeQ1hR/Ag1G2wFk5bw0mT5Zp2g=
209209
github.com/coder/wgtunnelv0.1.13-0.20231127054351-578bfff9b92a h1:KhR9LUVllMZ+e9lhubZ1HNrtJDgH5YLoTvpKwmrGag4=
210210
github.com/coder/wgtunnelv0.1.13-0.20231127054351-578bfff9b92a/go.mod h1:QzfptVUdEO+XbkzMKx1kw13i9wwpJlfI1RrZ6SNZ0hA=
211211
github.com/coder/wireguard-gov0.0.0-20230807234434-d825b45ccbf5 h1:eDk/42Kj4xN4yfE504LsvcFEo3dWUiCOaBiWJ2uIH2A=

‎site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import { rest } from "msw";
2525
constnameLabelText="Workspace Name";
2626
constcreateWorkspaceText="Create Workspace";
2727
constvalidationNumberNotInRangeText="Value must be between 1 and 3.";
28-
constvalidationPatternNotMatched=`${MockTemplateVersionParameter3.validation_error} (value does not match the pattern ^[a-z]{3}$)`;
2928

3029
constrenderCreateWorkspacePage=()=>{
3130
returnrenderWithAuth(<CreateWorkspacePage/>,{
@@ -152,7 +151,36 @@ describe("CreateWorkspacePage", () => {
152151
fireEvent.submit(thirdParameterField);
153152

154153
constvalidationError=awaitscreen.findByText(
155-
validationPatternNotMatched,
154+
MockTemplateVersionParameter3.validation_errorasstring,
155+
);
156+
expect(validationError).toBeInTheDocument();
157+
});
158+
159+
it("rich parameter: number validation fails with custom error",async()=>{
160+
jest.spyOn(API,"getTemplateVersionRichParameters").mockResolvedValueOnce([
161+
MockTemplateVersionParameter1,
162+
{
163+
...MockTemplateVersionParameter2,
164+
validation_error:"These are values: {min}, {max}, and {value}.",
165+
validation_monotonic:undefined,// only needs min-max rules
166+
},
167+
]);
168+
169+
renderCreateWorkspacePage();
170+
awaitwaitForLoaderToBeRemoved();
171+
172+
constsecondParameterField=awaitscreen.findByLabelText(
173+
MockTemplateVersionParameter2.name,
174+
{exact:false},
175+
);
176+
expect(secondParameterField).toBeDefined();
177+
fireEvent.change(secondParameterField,{
178+
target:{value:"4"},
179+
});
180+
fireEvent.submit(secondParameterField);
181+
182+
constvalidationError=awaitscreen.findByText(
183+
"These are values: 1, 3, and 4.",
156184
);
157185
expect(validationError).toBeInTheDocument();
158186
});

‎site/src/utils/richParameters.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ export const useValidationSchemaForRichParameters = (
7979
if(Number(val)<templateParameter.validation_min){
8080
returnctx.createError({
8181
path:ctx.path,
82-
message:`Value must be greater than${templateParameter.validation_min}.`,
82+
message:
83+
parameterError(templateParameter,val)??
84+
`Value must be greater than${templateParameter.validation_min}.`,
8385
});
8486
}
8587
}elseif(
@@ -89,7 +91,9 @@ export const useValidationSchemaForRichParameters = (
8991
if(templateParameter.validation_max<Number(val)){
9092
returnctx.createError({
9193
path:ctx.path,
92-
message:`Value must be less than${templateParameter.validation_max}.`,
94+
message:
95+
parameterError(templateParameter,val)??
96+
`Value must be less than${templateParameter.validation_max}.`,
9397
});
9498
}
9599
}elseif(
@@ -102,7 +106,9 @@ export const useValidationSchemaForRichParameters = (
102106
){
103107
returnctx.createError({
104108
path:ctx.path,
105-
message:`Value must be between${templateParameter.validation_min} and${templateParameter.validation_max}.`,
109+
message:
110+
parameterError(templateParameter,val)??
111+
`Value must be between${templateParameter.validation_min} and${templateParameter.validation_max}.`,
106112
});
107113
}
108114
}
@@ -149,7 +155,7 @@ export const useValidationSchemaForRichParameters = (
149155
if(val&&!regex.test(val)){
150156
returnctx.createError({
151157
path:ctx.path,
152-
message:`${templateParameter.validation_error} (value does not match the pattern${templateParameter.validation_regex})`,
158+
message:parameterError(templateParameter,val),
153159
});
154160
}
155161
}
@@ -162,3 +168,32 @@ export const useValidationSchemaForRichParameters = (
162168
)
163169
.required();
164170
};
171+
172+
constparameterError=(
173+
parameter:TemplateVersionParameter,
174+
value?:string,
175+
):string|undefined=>{
176+
if(!parameter.validation_error||!value){
177+
return;
178+
}
179+
180+
constr=newMap<string,string>([
181+
[
182+
"{min}",
183+
parameter.validation_min!==undefined
184+
?parameter.validation_min.toString()
185+
:"",
186+
],
187+
[
188+
"{max}",
189+
parameter.validation_max!==undefined
190+
?parameter.validation_max.toString()
191+
:"",
192+
],
193+
["{value}",value],
194+
]);
195+
returnparameter.validation_error.replace(
196+
/{min}|{max}|{value}/g,
197+
(match)=>r.get(match)||"",
198+
);
199+
};

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp