Claude
Skills
Sign in
Back

pre-release-validation

Included with Lifetime
$97 forever

Validate release readiness for any project type with comprehensive checks

General

What this skill does


# Pre-Release Validation

## Purpose

Performs comprehensive validation checks before finalizing a release for any project type. Validates version files, changelog, git state, and runs project-specific and custom validation checks. Returns both blocking errors (must be fixed) and non-blocking warnings (can proceed with caution).

## Input Context

Requires:
- **Project Configuration**: Output from `detect-project-type` skill
- **New Version**: Version to be released (e.g., "1.2.0")
- **Changelog Path**: Path to changelog file
- **Modified Files**: List of files that will be committed

## Workflow

### 1. Load Configuration

Use configuration from `detect-project-type`:
- `project_type` - Determines project-specific checks
- `version_files` - Files to validate
- `tag_pattern` - For checking tag conflicts
- `custom_validations` - Custom validation scripts
- `skip_validations` - Validations to skip

### 2. Version Tag Conflict Check

Check if a git tag already exists for this version:

```bash
# Build tag name from pattern
tag_pattern="v{version}"  # from config
tag_name="${tag_pattern//\{version\}/$new_version}"

# Check if tag exists
if git tag -l "$tag_name" | grep -q "$tag_name"; then
  error="Version $new_version already released (tag $tag_name exists)"
  suggestion="Choose a different version or delete existing tag with: git tag -d $tag_name"
fi
```

**Can skip with:** `skip_validations: ["version-tag-conflict"]`

### 3. Version Format Validation

Validate the version string follows semantic versioning:

```bash
# Semantic version pattern: X.Y.Z
if ! echo "$new_version" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
  error="Invalid version format: $new_version (expected X.Y.Z)"
  suggestion="Use semantic versioning format like 1.2.3"
fi
```

**Can skip with:** `skip_validations: ["version-format"]`

### 4. Version Progression Check

Compare new version to current version:

```bash
# Parse versions
IFS='.' read -r curr_major curr_minor curr_patch <<< "$current_version"
IFS='.' read -r new_major new_minor new_patch <<< "$new_version"

# Check if new > current
is_greater=false

if [ $new_major -gt $curr_major ]; then
  is_greater=true
elif [ $new_major -eq $curr_major ] && [ $new_minor -gt $curr_minor ]; then
  is_greater=true
elif [ $new_major -eq $curr_major ] && [ $new_minor -eq $curr_minor ] && [ $new_patch -gt $curr_patch ]; then
  is_greater=true
fi

if [ "$is_greater" = false ]; then
  error="New version $new_version must be greater than current version $current_version"
  suggestion="Increment version appropriately"
fi
```

**Can skip with:** `skip_validations: ["version-progression"]`

### 5. Required Files Existence

Check that all version files and required project files exist:

```bash
required_files=()

# Add version files
for version_file in "${version_files[@]}"; do
  required_files+=("$version_file")
done

# Add changelog
required_files+=("$changelog_file")

# Project-specific required files
case "$project_type" in
  "nodejs")
    required_files+=("package.json")
    ;;
  "python")
    # pyproject.toml or setup.py required
    if [ ! -f "pyproject.toml" ] && [ ! -f "setup.py" ]; then
      error="Python project requires pyproject.toml or setup.py"
    fi
    ;;
  "rust")
    required_files+=("Cargo.toml")
    ;;
  "go")
    required_files+=("go.mod")
    ;;
  "java")
    # build.gradle or pom.xml required
    if [ ! -f "build.gradle" ] && [ ! -f "gradle.properties" ] && [ ! -f "pom.xml" ]; then
      error="Java project requires build.gradle, gradle.properties, or pom.xml"
    fi
    ;;
esac

# Check each required file
for file in "${required_files[@]}"; do
  if [ ! -f "$file" ]; then
    error="Required file not found: $file"
    suggestion="Create the file before releasing"
  fi
done
```

**Can skip with:** `skip_validations: ["required-files"]`

### 6. Version File Validity

Validate each version file can be parsed and read:

```bash
for version_file_config in "${version_files[@]}"; do
  file_path="${version_file_config[path]}"
  adapter="${version_file_config[adapter]}"

  case "$adapter" in
    "json")
      # Validate JSON
      if ! jq empty "$file_path" 2>/dev/null; then
        error="Invalid JSON in $file_path"
        suggestion="Fix JSON syntax errors"
      fi

      # Check version field exists
      if ! jq -e '.version' "$file_path" >/dev/null 2>&1; then
        error="Missing 'version' field in $file_path"
      fi
      ;;

    "toml")
      # Validate TOML syntax (basic check)
      if ! grep -q '^version = ' "$file_path"; then
        error="No version field found in $file_path"
      fi
      ;;

    "python-file")
      # Validate Python syntax
      if ! python -c "import ast; ast.parse(open('$file_path').read())" 2>/dev/null; then
        error="Invalid Python syntax in $file_path"
      fi

      # Check __version__ is defined
      if ! grep -q '^__version__ = ' "$file_path"; then
        error="Missing __version__ in $file_path"
      fi
      ;;

    "text")
      # Check file is not empty
      if [ ! -s "$file_path" ]; then
        error="Version file $file_path is empty"
      fi
      ;;
  esac
done
```

**Can skip with:** `skip_validations: ["json-validity"]` or `skip_validations: ["version-file-validity"]`

### 7. Changelog Entry Verification

Read changelog file and verify entry exists for new version:

```bash
if [ ! -f "$changelog_file" ]; then
  warning="Changelog file $changelog_file does not exist (will be created)"
else
  # Look for version entry in changelog
  version_pattern="## Version $new_version"

  if ! grep -q "$version_pattern" "$changelog_file"; then
    error="Changelog entry for version $new_version not found in $changelog_file"
    suggestion="Run changelog-update skill to generate entry"
  else
    # Check if entry has content (not just header)
    # Get lines after version header until next version or EOF
    entry_lines=$(sed -n "/^## Version $new_version/,/^## Version/p" "$changelog_file" | wc -l)

    if [ $entry_lines -lt 3 ]; then
      warning="Changelog entry for $new_version appears to be empty"
    fi
  fi
fi
```

**Can skip with:** `skip_validations: ["changelog-entry"]`

### 8. Git Remote Configuration

Check if git remote is configured:

```bash
if ! git remote -v | grep -q 'origin'; then
  warning="No git remote 'origin' configured - push will fail"
  suggestion="Add remote with: git remote add origin <url>"
fi
```

**Can skip with:** `skip_validations: ["git-remote"]`

### 9. Uncommitted Changes Check

Check for unexpected uncommitted changes:

```bash
# Get all uncommitted files
uncommitted=$(git status --porcelain | grep -v '^??' | cut -c 4-)

# Filter out expected release files
expected_files=(
  "$changelog_file"
  "${version_files[@]}"
  "${modified_files[@]}"
)

unexpected_changes=()

while IFS= read -r file; do
  is_expected=false

  for expected in "${expected_files[@]}"; do
    if [ "$file" = "$expected" ]; then
      is_expected=true
      break
    fi
  done

  if [ "$is_expected" = false ]; then
    unexpected_changes+=("$file")
  fi
done <<< "$uncommitted"

if [ ${#unexpected_changes[@]} -gt 0 ]; then
  warning="Unexpected uncommitted changes found:"
  for file in "${unexpected_changes[@]}"; do
    warning+=" - $file"
  done
  suggestion="Commit or stash unrelated changes before release"
fi
```

### 10. Branch Validation

Check current branch matches expected:

```bash
current_branch=$(git branch --show-current)
expected_branches=("master" "main")

is_valid_branch=false
for branch in "${expected_branches[@]}"; do
  if [ "$current_branch" = "$branch" ]; then
    is_valid_branch=true
    break
  fi
done

if [ "$is_valid_branch" = false ]; then
  warning="Not on master/main branch (currently on $current_branch)"
  suggestion="Releases are typically done from master/main branch"
fi
```

### 11. Project-Specific Validations

Run validations specific to project type:

**Node.js:**
```bash
if [ "$project_type" = "nodejs" ]; then
  # Check if node_modules exis

Related in General