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

feat: support custom validation errors for number-typed parameters#12224

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
mtojek merged 9 commits intomainfrom12192-number-error
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes fromall 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
46 changes: 46 additions & 0 deletionscli/create_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -556,6 +556,14 @@ func TestCreateValidateRichParameters(t *testing.T) {
{Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: ptr.Ref(int32(3)), ValidationMax: ptr.Ref(int32(10))},
}

numberCustomErrorRichParameters := []*proto.RichParameter{
{
Name: numberParameterName, Type: "number", Mutable: true,
ValidationMin: ptr.Ref(int32(3)), ValidationMax: ptr.Ref(int32(10)),
ValidationError: "These are values: {min}, {max}, and {value}.",
},
}

stringRichParameters := []*proto.RichParameter{
{Name: stringParameterName, Type: "string", Mutable: true, ValidationRegex: "^[a-z]+$", ValidationError: "this is error"},
}
Expand DownExpand Up@@ -644,6 +652,44 @@ func TestCreateValidateRichParameters(t *testing.T) {
<-doneChan
})

t.Run("ValidateNumber_CustomError", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, client)
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, prepareEchoResponses(numberCustomErrorRichParameters))
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)

template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)

inv, root := clitest.New(t, "create", "my-workspace", "--template", template.Name)
clitest.SetupConfig(t, member, root)
doneChan := make(chan struct{})
pty := ptytest.New(t).Attach(inv)
go func() {
defer close(doneChan)
err := inv.Run()
assert.NoError(t, err)
}()

matches := []string{
numberParameterName, "12",
"These are values: 3, 10, and 12.", "",
"Enter a value", "8",
"Confirm create?", "yes",
}
for i := 0; i < len(matches); i += 2 {
match := matches[i]
value := matches[i+1]
pty.ExpectMatch(match)
if value != "" {
pty.WriteLine(value)
}
}
<-doneChan
})

t.Run("ValidateBool", func(t *testing.T) {
t.Parallel()

Expand Down
21 changes: 21 additions & 0 deletionscodersdk/richparameters_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -376,3 +376,24 @@ func TestParameterResolver_ValidateResolve_Ephemeral_UseEmptyDefault(t *testing.
require.NoError(t, err)
require.Equal(t, "", v)
}

func TestParameterResolver_ValidateResolve_Number_CustomError(t *testing.T) {
t.Parallel()
uut := codersdk.ParameterResolver{}
p := codersdk.TemplateVersionParameter{
Name: "n",
Type: "number",
Mutable: true,
DefaultValue: "5",

ValidationMin: ptr.Ref(int32(4)),
ValidationMax: ptr.Ref(int32(6)),
ValidationError: "These are values for testing purposes: {min}, {max}, and {value}.",
}
_, err := uut.ValidateResolve(p, &codersdk.WorkspaceBuildParameter{
Name: "n",
Value: "8",
})
require.Error(t, err)
require.Contains(t, err.Error(), "These are values for testing purposes: 4, 6, and 8.")
}
17 changes: 17 additions & 0 deletionsdocs/templates/parameters.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -249,6 +249,23 @@ data "coder_parameter" "instances" {
}
```

It is possible to override the default `error` message for a `number` parameter,
along with its associated `min` and/or `max` properties. The following message
placeholders are available `{min}`, `{max}`, and `{value}`.

```hcl
data "coder_parameter" "instances" {
name = "Instances"
type = "number"
description = "Number of compute instances"
validation {
min = 1
max = 4
error = "Sorry, we can't provision too many instances - maximum limit: {max}, wanted: {value}."
}
}
```

### String

You can validate a `string` parameter to match a regular expression. The `regex`
Expand Down
2 changes: 1 addition & 1 deletiongo.mod
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -96,7 +96,7 @@ require (
github.com/coder/flog v1.1.0
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0
github.com/coder/retry v1.5.1
github.com/coder/terraform-provider-coder v0.17.0
github.com/coder/terraform-provider-coder v0.18.0
github.com/coder/wgtunnel v0.1.13-0.20231127054351-578bfff9b92a
github.com/coreos/go-oidc/v3 v3.9.0
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
Expand Down
4 changes: 2 additions & 2 deletionsgo.sum
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -204,8 +204,8 @@ github.com/coder/ssh v0.0.0-20231128192721-70855dedb788 h1:YoUSJ19E8AtuUFVYBpXuO
github.com/coder/ssh v0.0.0-20231128192721-70855dedb788/go.mod h1:aGQbuCLyhRLMzZF067xc84Lh7JDs1FKwCmF1Crl9dxQ=
github.com/coder/tailscale v1.1.1-0.20240214140224-3788ab894ba1 h1:A7dZHNidAVH6Kxn5D3hTEH+iRO8slnM0aRer6/cxlyE=
github.com/coder/tailscale v1.1.1-0.20240214140224-3788ab894ba1/go.mod h1:L8tPrwSi31RAMEMV8rjb0vYTGs7rXt8rAHbqY/p41j4=
github.com/coder/terraform-provider-coder v0.17.0 h1:qwdLSbh6vPN+QDDvw1WNSYYEFlFwJFwzzP9vrvwr/ks=
github.com/coder/terraform-provider-coder v0.17.0/go.mod h1:pACHRoXSHBGyY696mLeQ1hR/Ag1G2wFk5bw0mT5Zp2g=
github.com/coder/terraform-provider-coder v0.18.0 h1:JWSBsOuzyiCev3C2Aj8Y1dvJkm5JMysIrIylMJtzPAY=
github.com/coder/terraform-provider-coder v0.18.0/go.mod h1:pACHRoXSHBGyY696mLeQ1hR/Ag1G2wFk5bw0mT5Zp2g=
github.com/coder/wgtunnel v0.1.13-0.20231127054351-578bfff9b92a h1:KhR9LUVllMZ+e9lhubZ1HNrtJDgH5YLoTvpKwmrGag4=
github.com/coder/wgtunnel v0.1.13-0.20231127054351-578bfff9b92a/go.mod h1:QzfptVUdEO+XbkzMKx1kw13i9wwpJlfI1RrZ6SNZ0hA=
github.com/coder/wireguard-go v0.0.0-20230807234434-d825b45ccbf5 h1:eDk/42Kj4xN4yfE504LsvcFEo3dWUiCOaBiWJ2uIH2A=
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,7 +25,6 @@ import { rest } from "msw";
const nameLabelText = "Workspace Name";
const createWorkspaceText = "Create Workspace";
const validationNumberNotInRangeText = "Value must be between 1 and 3.";
const validationPatternNotMatched = `${MockTemplateVersionParameter3.validation_error} (value does not match the pattern ^[a-z]{3}$)`;

const renderCreateWorkspacePage = () => {
return renderWithAuth(<CreateWorkspacePage />, {
Expand DownExpand Up@@ -152,7 +151,36 @@ describe("CreateWorkspacePage", () => {
fireEvent.submit(thirdParameterField);

const validationError = await screen.findByText(
validationPatternNotMatched,
MockTemplateVersionParameter3.validation_error as string,
);
expect(validationError).toBeInTheDocument();
});

it("rich parameter: number validation fails with custom error", async () => {
jest.spyOn(API, "getTemplateVersionRichParameters").mockResolvedValueOnce([
MockTemplateVersionParameter1,
{
...MockTemplateVersionParameter2,
validation_error: "These are values: {min}, {max}, and {value}.",
validation_monotonic: undefined, // only needs min-max rules
},
]);

renderCreateWorkspacePage();
await waitForLoaderToBeRemoved();

const secondParameterField = await screen.findByLabelText(
MockTemplateVersionParameter2.name,
{ exact: false },
);
expect(secondParameterField).toBeDefined();
fireEvent.change(secondParameterField, {
target: { value: "4" },
});
fireEvent.submit(secondParameterField);

const validationError = await screen.findByText(
"These are values: 1, 3, and 4.",
);
expect(validationError).toBeInTheDocument();
});
Expand Down
43 changes: 39 additions & 4 deletionssite/src/utils/richParameters.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -79,7 +79,9 @@ export const useValidationSchemaForRichParameters = (
if (Number(val) < templateParameter.validation_min) {
return ctx.createError({
path: ctx.path,
message: `Value must be greater than ${templateParameter.validation_min}.`,
message:
parameterError(templateParameter, val) ??
`Value must be greater than ${templateParameter.validation_min}.`,
});
}
} else if (
Expand All@@ -89,7 +91,9 @@ export const useValidationSchemaForRichParameters = (
if (templateParameter.validation_max < Number(val)) {
return ctx.createError({
path: ctx.path,
message: `Value must be less than ${templateParameter.validation_max}.`,
message:
parameterError(templateParameter, val) ??
`Value must be less than ${templateParameter.validation_max}.`,
});
}
} else if (
Expand All@@ -102,7 +106,9 @@ export const useValidationSchemaForRichParameters = (
) {
return ctx.createError({
path: ctx.path,
message: `Value must be between ${templateParameter.validation_min} and ${templateParameter.validation_max}.`,
message:
parameterError(templateParameter, val) ??
`Value must be between ${templateParameter.validation_min} and ${templateParameter.validation_max}.`,
});
}
}
Expand DownExpand Up@@ -149,7 +155,7 @@ export const useValidationSchemaForRichParameters = (
if (val && !regex.test(val)) {
return ctx.createError({
path: ctx.path,
message:`${templateParameter.validation_error} (value does not match the pattern ${templateParameter.validation_regex})`,
message:parameterError(templateParameter, val),
});
}
}
Expand All@@ -162,3 +168,32 @@ export const useValidationSchemaForRichParameters = (
)
.required();
};

const parameterError = (
parameter: TemplateVersionParameter,
value?: string,
): string | undefined => {
if (!parameter.validation_error || !value) {
return;
}

const r = new Map<string, string>([
[
"{min}",
parameter.validation_min !== undefined
? parameter.validation_min.toString()
: "",
],
[
"{max}",
parameter.validation_max !== undefined
? parameter.validation_max.toString()
: "",
],
["{value}", value],
]);
return parameter.validation_error.replace(
/{min}|{max}|{value}/g,
(match) => r.get(match) || "",
);
};

[8]ページ先頭

©2009-2025 Movatter.jp