Documentation
¶
Overview ¶
Package validation provides input validation and pre-flight checks for Hitch operations.
Overview ¶
This package implements validation logic that ensures operations are safe to execute before any Git modifications occur. It provides helper functions for checking repository state, validating user input, and generating helpful error messages.
Purpose ¶
Validation serves as a critical safety layer:
- Verify repository state before operations
- Check for uncommitted changes
- Validate branch names and environment names
- Generate user-friendly error messages
- Prevent operations that would fail or corrupt state
Core Functions ¶
CheckUnstagedChanges:
func CheckUnstagedChanges(repo *git.Repo, operation, context string) error
Validates that the repository has no uncommitted changes before proceeding with an operation. This prevents data loss and ensures clean operation state.
Usage:
err := validation.CheckUnstagedChanges(repo, "promote", "feature/login to dev")
if err != nil {
return err
}
If changes are detected, returns a detailed error with resolution steps.
FormatUnstagedChangesMessage:
func FormatUnstagedChangesMessage(operation, context string) string
Generates user-friendly error messages for unstaged changes, including:
- Clear explanation of the problem
- Step-by-step resolution instructions
- Example commands to fix the issue
- Context about what operation was blocked
Error Messages ¶
The package generates helpful, actionable error messages:
🚫 SAFETY CHECK FAILED
Cannot promote with uncommitted changes.
Hitch refuses to operate on repositories with uncommitted changes to prevent data loss.
To proceed:
1. Commit your changes:
git add .
git commit -m "Save work before hitch operation"
2. Stash your changes:
git stash push -m "Temporary stash before hitch operation"
After resolving changes, run: hitch promote feature/login to dev
✓ Repository state preserved
Unstaged Changes Detection ¶
CheckUnstagedChanges performs comprehensive checks:
- Modified files
- New files (untracked)
- Deleted files
- Staged but uncommitted changes
Any of these conditions will block the operation.
Usage in Commands ¶
All commands that modify repository state use validation:
Promote Command:
import "github.com/DoomedRamen/hitch/internal/validation"
func runPromote(cmd *cobra.Command, args []string) error {
// Parse arguments
branch, env := parsePromoteArgs(args)
// Open repository
repo, err := git.OpenRepo(".")
if err != nil {
return err
}
// VALIDATION: Check for unstaged changes
err = validation.CheckUnstagedChanges(repo, "promote",
fmt.Sprintf("%s to %s", branch, env))
if err != nil {
return err
}
// Safe to proceed with promote
// ...
}
Rebuild Command:
err := validation.CheckUnstagedChanges(repo, "rebuild", environment)
if err != nil {
return err
}
Release Command:
err := validation.CheckUnstagedChanges(repo, "release",
fmt.Sprintf("%s to %s", environment, baseBranch))
if err != nil {
return err
}
Command Helpers ¶
The package also provides command-specific helper functions in command_helpers.go for parsing and validating command arguments.
Validation Flow ¶
Typical validation flow in a command:
Parse and validate arguments ├─ Check argument count ├─ Validate syntax (e.g., "to", "from" keywords) └─ Extract branch and environment names
Open repository ├─ Verify .git directory exists ├─ Check repository is valid └─ Load repository state
Check for unstaged changes ├─ Run git status equivalent ├─ Detect any modifications └─ Block if changes found
Validate metadata exists ├─ Check hitch-metadata branch exists ├─ Verify hitch.json is valid └─ Load metadata
Validate operation-specific requirements ├─ Check branch exists ├─ Verify environment exists ├─ Check for conflicts └─ Validate permissions
Proceed with operation └─ All validations passed
Why Validation Matters ¶
Without validation, operations could:
- Overwrite uncommitted work (data loss)
- Corrupt repository state (broken git state)
- Leave repository in inconsistent state
- Lose track of what changes belong to what operation
Validation prevents all these issues by catching problems early.
Error Message Design ¶
Error messages follow these principles:
- Clear Problem Statement: Explain what's wrong
- Why It Matters: Explain why operation is blocked
- How to Fix: Provide step-by-step resolution
- Next Steps: Show exact command to run after fixing
- Reassurance: Confirm no data was lost
Example breakdown:
🚫 SAFETY CHECK FAILED [1. Problem]
Cannot promote with uncommitted changes.
Hitch refuses to operate on repositories [2. Why]
with uncommitted changes to prevent data loss.
To proceed: [3. How to Fix]
1. Commit your changes:
git add .
git commit -m "..."
2. Stash your changes:
git stash push -m "..."
After resolving changes, run: [4. Next Steps]
hitch promote feature/login to dev
✓ Repository state preserved [5. Reassurance]
Integration with Safety System ¶
Validation is the first layer in Hitch's safety system:
Layer 1: Validation (this package) ↓ Check for unstaged changes ↓ Validate repository state ↓ Check basic requirements ↓ Layer 2: Safe Testing (safety package) ↓ Test in temporary branch ↓ Verify merge succeeds ↓ Run hooks ↓ Layer 3: Lock Management (metadata package) ↓ Acquire environment lock ↓ Prevent concurrent modifications ↓ Layer 4: Actual Operation ↓ Modify repository ↓ Update metadata ↓ Layer 5: Cleanup └─ Release locks └─ Cleanup temp branches
Custom Validators ¶
Extend validation for custom needs:
func ValidateCustomRequirement(repo *git.Repo) error {
// Custom validation logic
if !customCheck(repo) {
return fmt.Errorf("custom requirement not met")
}
return nil
}
// In command
if err := ValidateCustomRequirement(repo); err != nil {
return err
}
Testing ¶
Validation functions are easy to test:
func TestCheckUnstagedChanges(t *testing.T) {
testRepo := testutil.NewTestRepo(t)
defer testRepo.Cleanup()
// Repository is clean - should pass
err := validation.CheckUnstagedChanges(testRepo.Repo, "test", "context")
if err != nil {
t.Errorf("Clean repository should pass: %v", err)
}
// Add uncommitted change
testRepo.WriteFile("test.txt", "content")
// Should now fail
err = validation.CheckUnstagedChanges(testRepo.Repo, "test", "context")
if err == nil {
t.Error("Should fail with uncommitted changes")
}
}
Performance ¶
Validation is fast:
- Uses git library calls (no shell execution)
- Minimal overhead (< 10ms typically)
- Doesn't slow down operations noticeably
Best Practices ¶
- Always validate before operations
- Provide clear error messages
- Include resolution steps
- Don't swallow validation errors
- Test validation logic thoroughly
- Keep validation fast
Future Enhancements ¶
Potential additions:
- Validate branch naming conventions
- Check for merge conflicts before operation
- Verify environment configuration
- Validate user permissions
- Check disk space availability
Example: Complete Validation Pattern ¶
func SafeOperation(repo *git.Repo, branch, env string) error {
// 1. Validate repository state
err := validation.CheckUnstagedChanges(repo, "promote",
fmt.Sprintf("%s to %s", branch, env))
if err != nil {
return err
}
// 2. Validate branch exists
if !repo.BranchExists(branch) {
return fmt.Errorf("branch %s not found", branch)
}
// 3. Validate metadata
reader := metadata.NewReader(repo)
if !reader.Exists() {
return errors.New("hitch not initialized")
}
meta, err := reader.Read()
if err != nil {
return fmt.Errorf("failed to read metadata: %w", err)
}
// 4. Validate environment exists
if _, exists := meta.Environments[env]; !exists {
return fmt.Errorf("environment %s not found", env)
}
// All validations passed - safe to proceed
return performOperation(repo, meta, branch, env)
}
This package ensures that Hitch operations are safe, predictable, and user-friendly by catching issues early and providing clear guidance for resolution.
Index ¶
- func CheckBranchAlreadyInEnvironment(env metadata.Environment, branchName, envName string) error
- func CheckUnstagedChanges(repo *hitchgit.Repo, operation, context string) error
- func FormatBranchNotFoundError(branchName string) string
- func FormatEnvironmentNotFoundError(envName string, environments map[string]metadata.Environment) string
- func FormatRepositoryValidationError(validationResult hitchgit.ValidationResult, operation string) string
- func FormatUnstagedChangesMessage(operation, context string) string
- func InitializeRepositoryAndMetadata() (*hitchgit.Repo, *metadata.Metadata, error)
- func SetupBranchRestoration(repo *hitchgit.Repo) string
- func ValidateBranchExists(repo *hitchgit.Repo, branchName string) error
- func ValidateEnvironmentExists(meta *metadata.Metadata, envName string) (metadata.Environment, error)
- func ValidateGitUserInfo(repo *hitchgit.Repo) (string, string, error)
- func ValidateRepositoryState(repo *hitchgit.Repo, operation string) error
- type CommonValidator
- type ErrorType
- type ValidationAdapter
- type ValidationChain
- type ValidationResult
- type ValidationRule
- type ValidatorConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CheckBranchAlreadyInEnvironment ¶
func CheckBranchAlreadyInEnvironment(env metadata.Environment, branchName, envName string) error
CheckBranchAlreadyInEnvironment checks if branch is already in the target environment
func CheckUnstagedChanges ¶
CheckUnstagedChanges validates that the repository has no uncommitted changes
func FormatBranchNotFoundError ¶
FormatBranchNotFoundError generates the error message for missing branches
func FormatEnvironmentNotFoundError ¶
func FormatEnvironmentNotFoundError(envName string, environments map[string]metadata.Environment) string
FormatEnvironmentNotFoundError generates the error message for missing environments
func FormatRepositoryValidationError ¶
func FormatRepositoryValidationError(validationResult hitchgit.ValidationResult, operation string) string
FormatRepositoryValidationError generates the error message for repository validation failures
func FormatUnstagedChangesMessage ¶
FormatUnstagedChangesMessage generates the error message for unstaged changes
func InitializeRepositoryAndMetadata ¶
InitializeRepositoryAndMetadata performs common repository initialization steps
func SetupBranchRestoration ¶
SetupBranchRestoration saves current branch for later restoration
func ValidateBranchExists ¶
ValidateBranchExists validates that a branch exists in the repository
func ValidateEnvironmentExists ¶
func ValidateEnvironmentExists(meta *metadata.Metadata, envName string) (metadata.Environment, error)
ValidateEnvironmentExists validates that an environment exists in metadata
func ValidateGitUserInfo ¶
ValidateGitUserInfo validates that git user information is configured
Types ¶
type CommonValidator ¶ added in v1.1.8
type CommonValidator struct {
// contains filtered or unexported fields
}
CommonValidator provides reusable validation patterns
func BranchNameValidator ¶ added in v1.1.8
func BranchNameValidator() *CommonValidator
BranchNameValidator creates a validator for git branch names
func CommitMessageValidator ¶ added in v1.1.8
func CommitMessageValidator() *CommonValidator
CommitMessageValidator creates a validator for commit messages
func EnvironmentNameValidator ¶ added in v1.1.8
func EnvironmentNameValidator() *CommonValidator
EnvironmentNameValidator creates a validator for environment names
func NewCommonValidator ¶ added in v1.1.8
func NewCommonValidator(config ValidatorConfig, rules ...ValidationRule) *CommonValidator
NewCommonValidator creates a new common validator with the given rules
func RemoteNameValidator ¶ added in v1.1.8
func RemoteNameValidator() *CommonValidator
RemoteNameValidator creates a validator for git remote names
func (*CommonValidator) Validate ¶ added in v1.1.8
func (cv *CommonValidator) Validate(value string) ValidationResult
Validate performs validation on the given value
type ErrorType ¶ added in v1.1.8
type ErrorType int
ErrorType represents the type of validation error to create
const ( // ErrorTypeBranch creates branch validation errors ErrorTypeBranch ErrorType = iota // ErrorTypeEnvironment creates environment validation errors ErrorTypeEnvironment // ErrorTypeCommit creates commit validation errors ErrorTypeCommit // ErrorTypeRemote creates remote validation errors ErrorTypeRemote // ErrorTypeGeneric creates generic validation errors ErrorTypeGeneric )
type ValidationAdapter ¶ added in v1.1.8
type ValidationAdapter struct {
// contains filtered or unexported fields
}
ValidationAdapter adapts the common validation framework to work with the Hitch error system
func BranchValidationAdapter ¶ added in v1.1.8
func BranchValidationAdapter() *ValidationAdapter
BranchValidationAdapter creates a pre-configured branch validation adapter
func CommitValidationAdapter ¶ added in v1.1.8
func CommitValidationAdapter() *ValidationAdapter
CommitValidationAdapter creates a pre-configured commit message validation adapter
func EnvironmentValidationAdapter ¶ added in v1.1.8
func EnvironmentValidationAdapter() *ValidationAdapter
EnvironmentValidationAdapter creates a pre-configured environment validation adapter
func NewValidationAdapter ¶ added in v1.1.8
func NewValidationAdapter(validator *CommonValidator, errorType ErrorType) *ValidationAdapter
NewValidationAdapter creates a new validation adapter
func RemoteValidationAdapter ¶ added in v1.1.8
func RemoteValidationAdapter() *ValidationAdapter
RemoteValidationAdapter creates a pre-configured remote name validation adapter
func (*ValidationAdapter) ValidateMultiple ¶ added in v1.1.8
func (va *ValidationAdapter) ValidateMultiple(fields map[string]string) error
ValidateMultiple validates multiple fields and combines errors
func (*ValidationAdapter) ValidateWithErrors ¶ added in v1.1.8
func (va *ValidationAdapter) ValidateWithErrors(value string, fieldName string) error
ValidateWithErrors performs validation and returns Hitch-specific errors
type ValidationChain ¶ added in v1.1.8
type ValidationChain struct {
// contains filtered or unexported fields
}
ValidationChain allows chaining multiple validators for a single field
func NewValidationChain ¶ added in v1.1.8
func NewValidationChain() *ValidationChain
NewValidationChain creates a new validation chain
func (*ValidationChain) Add ¶ added in v1.1.8
func (vc *ValidationChain) Add(validator *CommonValidator, errorType ErrorType) *ValidationChain
Add adds a validator to the chain
func (*ValidationChain) Validate ¶ added in v1.1.8
func (vc *ValidationChain) Validate(value string, fieldName string) error
Validate runs all validators in the chain and returns the first error
func (*ValidationChain) ValidateAll ¶ added in v1.1.8
func (vc *ValidationChain) ValidateAll(value string, fieldName string) error
ValidateAll runs all validators in the chain and returns all errors
type ValidationResult ¶ added in v1.1.8
ValidationResult represents the result of validation
type ValidationRule ¶ added in v1.1.8
ValidationRule represents a single validation rule
func EnvironmentNameRule ¶ added in v1.1.8
func EnvironmentNameRule() ValidationRule
EnvironmentNameRule implements environment name specific validation
func GitBranchNameRule ¶ added in v1.1.8
func GitBranchNameRule() ValidationRule
GitBranchNameRule implements git branch name specific validation
func NoCommandInjectionRule ¶ added in v1.1.8
func NoCommandInjectionRule() ValidationRule
NoCommandInjectionRule prevents command injection attacks
func NoControlCharactersRule ¶ added in v1.1.8
func NoControlCharactersRule() ValidationRule
NoControlCharactersRule prevents control characters
func NoPathTraversalRule ¶ added in v1.1.8
func NoPathTraversalRule() ValidationRule
NoPathTraversalRule prevents path traversal attacks
func NoSuspiciousUnicodeRule ¶ added in v1.1.8
func NoSuspiciousUnicodeRule() ValidationRule
NoSuspiciousUnicodeRule prevents suspicious unicode characters