Add prompt validation (required fields, types, constraints) #24

Closed
opened 2026-01-03 23:39:49 +00:00 by KofTwentyTwo · 1 comment
KofTwentyTwo commented 2026-01-03 23:39:49 +00:00 (Migrated from github.com)

Part of #12

User Story

As a qctl user, I want my input validated against prompt rules so that I get immediate feedback on invalid values before template rendering fails.

Design

Validation Rules in Manifest

prompts:
  - name: packageName
    message: "Java package"
    type: string
    required: true
    validation:
      pattern: "^[a-z][a-z0-9]*(\\.[a-z][a-z0-9]*)*$"
      message: "Must be a valid Java package name (e.g., com.example.myapp)"
      
  - name: port
    message: "Server port"
    type: integer
    validation:
      min: 1024
      max: 65535
      message: "Port must be between 1024 and 65535"
      
  - name: appName
    message: "Application name"
    type: string
    required: true
    validation:
      minLength: 2
      maxLength: 50
      pattern: "^[a-zA-Z][a-zA-Z0-9]*$"

Validation Types

Type Rules Available
string pattern, minLength, maxLength, enum
integer min, max
boolean (no additional validation)
choice Value must match one of choices

Interactive Retry

When validation fails, re-prompt with error message:

? Java package [com.example.myapp]: 123invalid
  ✗ Must be a valid Java package name (e.g., com.example.myapp)
? Java package [com.example.myapp]: com.acme.orders
  ✓ 

CLI Override Validation

--var overrides are also validated:

$ qctl qqq init qqq-web-api myapp --var packageName=123
Error: Invalid value for 'packageName': Must be a valid Java package name

Files to Create/Modify

File Action Description
PromptValidation.java Create Validation rule record
PromptValidator.java Create Validates values against rules
ConsoleUI.java Modify Re-prompt on validation failure
InitCommand.java Modify Validate --var overrides
TemplateManifest.java Modify Add validation to Prompt record

Implementation Tasks

  • Create PromptValidation record with all rule fields
  • Add validation field to Prompt record
  • Create PromptValidator class
  • Implement pattern validation (regex)
  • Implement minLength/maxLength validation
  • Implement min/max validation for integers
  • Implement enum validation (value in list)
  • Implement required field validation
  • Update PromptRunner to retry on validation failure
  • Add validation for --var command-line overrides
  • Show clear error messages with examples
  • Add unit tests for all validation types - 20 tests in PromptValidatorTest
  • Test edge cases (empty values, whitespace)

Acceptance Criteria

  • Invalid input triggers re-prompt with error message
  • Pattern validation works with regex
  • Length validation works for strings
  • Range validation works for integers
  • Required fields cannot be skipped
  • --var overrides are validated (falls back to interactive prompt if invalid)
  • Error messages are helpful with examples
  • All prompt types validate correctly
Part of #12 ## User Story As a **qctl user**, I want my input validated against prompt rules so that I get immediate feedback on invalid values before template rendering fails. ## Design ### Validation Rules in Manifest ```yaml prompts: - name: packageName message: "Java package" type: string required: true validation: pattern: "^[a-z][a-z0-9]*(\\.[a-z][a-z0-9]*)*$" message: "Must be a valid Java package name (e.g., com.example.myapp)" - name: port message: "Server port" type: integer validation: min: 1024 max: 65535 message: "Port must be between 1024 and 65535" - name: appName message: "Application name" type: string required: true validation: minLength: 2 maxLength: 50 pattern: "^[a-zA-Z][a-zA-Z0-9]*$" ``` ### Validation Types | Type | Rules Available | |------|-----------------| | `string` | `pattern`, `minLength`, `maxLength`, `enum` | | `integer` | `min`, `max` | | `boolean` | (no additional validation) | | `choice` | Value must match one of `choices` | ### Interactive Retry When validation fails, re-prompt with error message: ``` ? Java package [com.example.myapp]: 123invalid ✗ Must be a valid Java package name (e.g., com.example.myapp) ? Java package [com.example.myapp]: com.acme.orders ✓ ``` ### CLI Override Validation `--var` overrides are also validated: ```bash $ qctl qqq init qqq-web-api myapp --var packageName=123 Error: Invalid value for 'packageName': Must be a valid Java package name ``` ## Files to Create/Modify | File | Action | Description | |------|--------|-------------| | `PromptValidation.java` | Create | Validation rule record | | `PromptValidator.java` | Create | Validates values against rules | | `ConsoleUI.java` | Modify | Re-prompt on validation failure | | `InitCommand.java` | Modify | Validate --var overrides | | `TemplateManifest.java` | Modify | Add validation to Prompt record | ## Implementation Tasks - [x] Create `PromptValidation` record with all rule fields - [x] Add `validation` field to `Prompt` record - [x] Create `PromptValidator` class - [x] Implement pattern validation (regex) - [x] Implement minLength/maxLength validation - [x] Implement min/max validation for integers - [x] Implement enum validation (value in list) - [x] Implement required field validation - [x] Update `PromptRunner` to retry on validation failure - [x] Add validation for `--var` command-line overrides - [x] Show clear error messages with examples - [x] Add unit tests for all validation types - 20 tests in PromptValidatorTest - [x] Test edge cases (empty values, whitespace) ## Acceptance Criteria - [x] Invalid input triggers re-prompt with error message - [x] Pattern validation works with regex - [x] Length validation works for strings - [x] Range validation works for integers - [x] Required fields cannot be skipped - [x] `--var` overrides are validated (falls back to interactive prompt if invalid) - [x] Error messages are helpful with examples - [x] All prompt types validate correctly
KofTwentyTwo commented 2026-01-04 03:01:38 +00:00 (Migrated from github.com)

Implementation Complete

Files Created

  • PromptValidation.java - Record for validation rules (pattern, minLength, maxLength, min, max, values, message)
  • PromptValidator.java - Validates values against prompt rules with ValidationResult record
  • PromptValidatorTest.java - 20 unit tests covering all validation types

Files Modified

  • TemplateManifest.java - Added validation field (PromptValidation) to Prompt record, added isRequired() helper
  • PromptRunner.java - Integrated validator with retry loop, validates --var overrides
  • ConsoleUI.java - Added validationError(), validationSuccess(), warning() methods

Validation Types Supported

Type Rules
string pattern, minLength, maxLength, values (enum)
integer/number min, max
required applies to all types

User Experience

? Java package [com.example.myapp]: 123invalid
  ✗ Must be a valid Java package name
? Java package [com.example.myapp]: com.acme.orders
  ✓

CLI Override Validation

Invalid --var values trigger interactive re-prompt with warning.

Commit: a2e85f7

## Implementation Complete ### Files Created - `PromptValidation.java` - Record for validation rules (pattern, minLength, maxLength, min, max, values, message) - `PromptValidator.java` - Validates values against prompt rules with ValidationResult record - `PromptValidatorTest.java` - 20 unit tests covering all validation types ### Files Modified - `TemplateManifest.java` - Added `validation` field (PromptValidation) to Prompt record, added `isRequired()` helper - `PromptRunner.java` - Integrated validator with retry loop, validates --var overrides - `ConsoleUI.java` - Added `validationError()`, `validationSuccess()`, `warning()` methods ### Validation Types Supported | Type | Rules | |------|-------| | string | pattern, minLength, maxLength, values (enum) | | integer/number | min, max | | required | applies to all types | ### User Experience ``` ? Java package [com.example.myapp]: 123invalid ✗ Must be a valid Java package name ? Java package [com.example.myapp]: com.acme.orders ✓ ``` ### CLI Override Validation Invalid `--var` values trigger interactive re-prompt with warning. Commit: a2e85f7
Sign in to join this conversation.