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
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 ¶
This section is empty.