From release-automation
Validate release readiness for any project type with comprehensive checks
npx claudepluginhub jayteealao/agent-skills --plugin release-automationThis skill uses the workspace's default tool permissions.
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).
Verifies tests pass on completed feature branch, presents options to merge locally, create GitHub PR, keep as-is or discard; executes choice and cleans up worktree.
Guides root cause investigation for bugs, test failures, unexpected behavior, performance issues, and build failures before proposing fixes.
Writes implementation plans from specs for multi-step tasks, mapping files and breaking into TDD bite-sized steps before coding.
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).
Requires:
detect-project-type skillUse configuration from detect-project-type:
project_type - Determines project-specific checksversion_files - Files to validatetag_pattern - For checking tag conflictscustom_validations - Custom validation scriptsskip_validations - Validations to skipCheck if a git tag already exists for this version:
# 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"]
Validate the version string follows semantic versioning:
# 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"]
Compare new version to current version:
# 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"]
Check that all version files and required project files exist:
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"]
Validate each version file can be parsed and read:
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"]
Read changelog file and verify entry exists for new version:
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"]
Check if git remote is configured:
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"]
Check for unexpected uncommitted changes:
# 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
Check current branch matches expected:
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
Run validations specific to project type:
Node.js:
if [ "$project_type" = "nodejs" ]; then
# Check if node_modules exists (dependencies installed)
if [ ! -d "node_modules" ]; then
warning="node_modules not found - dependencies may not be installed"
suggestion="Run: npm install"
fi
# Check for package-lock.json or yarn.lock consistency
if [ -f "package-lock.json" ]; then
# Verify lockfile is in sync (would need npm ci to fully validate)
if ! npm ls >/dev/null 2>&1; then
warning="Dependency tree has issues - check with npm ls"
fi
fi
fi
Python:
if [ "$project_type" = "python" ]; then
# Check if pyproject.toml is valid
if [ -f "pyproject.toml" ]; then
# Try to build (dry-run)
if command -v python >/dev/null 2>&1; then
if ! python -c "import tomli; tomli.load(open('pyproject.toml', 'rb'))" 2>/dev/null; then
warning="pyproject.toml may have syntax errors"
fi
fi
fi
# Check if dist/ directory exists from previous builds
if [ -d "dist" ]; then
warning="dist/ directory exists from previous build"
suggestion="Consider cleaning with: rm -rf dist/"
fi
fi
Rust:
if [ "$project_type" = "rust" ]; then
# Check if Cargo.lock is in sync
if [ -f "Cargo.lock" ]; then
if ! cargo check --quiet 2>/dev/null; then
warning="Cargo check failed - dependencies may have issues"
fi
fi
fi
Go:
if [ "$project_type" = "go" ]; then
# Verify go.mod is valid
if ! go mod verify 2>/dev/null; then
warning="go.mod verification failed"
fi
# Check for go.sum
if [ ! -f "go.sum" ]; then
warning="go.sum not found"
suggestion="Run: go mod tidy"
fi
fi
Run custom validation scripts from configuration:
if [ ${#custom_validations[@]} -gt 0 ]; then
for script in "${custom_validations[@]}"; do
echo "Running custom validation: $script"
if [ -x "$script" ]; then
# Run script and capture output
if ! output=$($script 2>&1); then
error="Custom validation failed: $script"
error+="Output: $output"
fi
else
warning="Custom validation script not executable: $script"
fi
done
fi
If preReleaseHook is configured, validate it exists and is executable:
if [ -n "$pre_release_hook" ]; then
if [ ! -f "$pre_release_hook" ]; then
warning="Pre-release hook not found: $pre_release_hook"
elif [ ! -x "$pre_release_hook" ]; then
warning="Pre-release hook not executable: $pre_release_hook"
suggestion="Run: chmod +x $pre_release_hook"
fi
fi
Return validation results:
{
"valid": true,
"errors": [],
"warnings": [
{
"level": "WARNING",
"check": "branch_validation",
"message": "Not on master branch (currently on develop)",
"suggestion": "Switch to master with: git checkout master"
}
],
"checks_passed": 12,
"checks_total": 13,
"checks_skipped": ["git-remote"],
"project_specific_checks": {
"nodejs": ["dependencies_installed", "lockfile_valid"]
}
}
Input:
nodejs1.2.01.1.0Output:
{
"valid": true,
"errors": [],
"warnings": [],
"checks_passed": 13,
"checks_total": 13,
"project_specific_checks": {
"nodejs": ["dependencies_installed", "lockfile_valid"]
}
}
Input:
1.0.0v1.0.0 existsOutput:
{
"valid": false,
"errors": [
{
"level": "BLOCKING",
"check": "version_tag_conflict",
"message": "Version 1.0.0 already released (tag v1.0.0 exists)",
"suggestion": "Choose version 1.0.1 or 1.1.0 instead"
}
],
"warnings": [],
"checks_passed": 12,
"checks_total": 13
}
Input:
python2.0.0Output:
{
"valid": false,
"errors": [
{
"level": "BLOCKING",
"check": "changelog_entry",
"message": "Changelog entry for version 2.0.0 not found in CHANGELOG.md",
"suggestion": "Add changelog entry before releasing"
}
],
"warnings": [],
"checks_passed": 12,
"checks_total": 13
}
Input:
rustfeature-branchOutput:
{
"valid": true,
"errors": [],
"warnings": [
{
"level": "WARNING",
"check": "branch_validation",
"message": "Not on master/main branch (currently on feature-branch)",
"suggestion": "Switch to master before releasing"
},
{
"level": "WARNING",
"check": "git_remote",
"message": "No git remote configured - push will fail",
"suggestion": "Add remote with: git remote add origin <url>"
},
{
"level": "WARNING",
"check": "rust_cargo_check",
"message": "Cargo check reported warnings",
"suggestion": "Fix warnings before releasing"
}
],
"checks_passed": 10,
"checks_total": 13
}
Input:
./scripts/validate-docs.shOutput:
{
"valid": false,
"errors": [
{
"level": "BLOCKING",
"check": "custom_validation",
"message": "Custom validation failed: ./scripts/validate-docs.sh",
"output": "Error: Missing API documentation for new endpoints"
}
],
"checks_passed": 12,
"checks_total": 13
}
Input:
skip_validations: ["git-remote", "branch-validation"]Output:
{
"valid": true,
"errors": [],
"warnings": [],
"checks_passed": 11,
"checks_total": 13,
"checks_skipped": ["git-remote", "branch-validation"]
}
Git command failures:
{
"valid": false,
"errors": [
{
"check": "git_state",
"message": "Git command failed: not a git repository",
"suggestion": "Ensure you're in a git repository"
}
]
}
File read errors:
{
"valid": false,
"errors": [
{
"check": "file_access",
"message": "Cannot read version file: package.json",
"suggestion": "Check file permissions"
}
]
}
For certain errors, provide auto-fix options:
Version conflict:
1.2.11.3.0Missing changelog:
changelog-update skillInvalid JSON:
jqThis skill is invoked by the /release command in Phase 5. The command will:
valid: false