enhance: Add intelligent workflow guidance and error handling

- Command suggestions for typos and alternatives
- Workflow state analysis with next steps
- Enhanced error messages with examples
- Progress indicators throughout workflow
- Automated guidance for feature development
This commit is contained in:
2025-09-23 17:40:07 -04:00
parent d85d9bf63a
commit a99fb3e9c9
+602
View File
@@ -0,0 +1,602 @@
#!/bin/bash
# NFOGuard Dual-Repo Development Sync Script
# Manages Gitea (private) + GitHub (public) workflow with AI attribution prevention
# CONFIDENTIAL: Stays in .local/ directory only
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
GITEA_REMOTE="origin" # gitea@192.168.253.221:sbcrumb/nfoguard.git
GITHUB_REMOTE="github" # git@github.com:sbcrumb/nfoguard.git
VERSION_FILE="VERSION"
# Helper functions
log_info() { echo -e "${BLUE}$1${NC}"; }
log_success() { echo -e "${GREEN}$1${NC}"; }
log_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; }
log_error() { echo -e "${RED}$1${NC}"; }
# Help with common mistakes and suggestions
suggest_command() {
local input="$1"
local suggestions=()
# Common typos and alternatives
case "$input" in
"create"|"new"|"begin"|"init")
suggestions+=("start")
;;
"merge"|"pr"|"pullrequest"|"pull-request")
suggestions+=("github-pr")
;;
"clean"|"cleanup"|"remove"|"delete")
suggestions+=("cleanup-github-pr")
;;
"check"|"info"|"show")
suggestions+=("status")
;;
"push"|"deploy"|"publish")
suggestions+=("release")
;;
"dev"|"develop"|"development")
suggestions+=("test")
;;
"help"|"--help"|"-h")
suggestions+=("(see help below)")
;;
"ver"|"version")
suggestions+=("version")
;;
*)
# Fuzzy matching for close commands
local commands=("start" "test" "release" "github-pr" "cleanup-github-pr" "sync" "version" "status")
for cmd in "${commands[@]}"; do
# Simple character similarity check
if [[ ${#input} -gt 2 && "$cmd" == *"$input"* ]]; then
suggestions+=("$cmd")
fi
done
;;
esac
if [[ ${#suggestions[@]} -gt 0 ]]; then
log_warning "Unknown command: '$input'"
echo ""
echo "Did you mean:"
for suggestion in "${suggestions[@]}"; do
echo " $0 $suggestion"
done
echo ""
fi
}
# Check if feature branch exists and suggest next steps
check_feature_status() {
local feature_name="$1"
local branch_name="feature/$feature_name"
# Check if feature branch exists locally
if git branch | grep -q " $branch_name$"; then
log_info "Feature branch '$branch_name' exists locally"
# Check if it's been tested (merged to dev)
if git branch -r | grep -q "$GITEA_REMOTE/dev"; then
git fetch "$GITEA_REMOTE" dev >/dev/null 2>&1
if git merge-base --is-ancestor "$branch_name" "$GITEA_REMOTE/dev" 2>/dev/null; then
log_success "Feature has been tested on dev branch"
log_info "Next step: $0 release $feature_name [patch|minor|major]"
else
log_warning "Feature not yet tested on dev branch"
log_info "Next step: $0 test $feature_name"
fi
fi
# Check if it's been released (merged to main)
if git branch -r | grep -q "$GITEA_REMOTE/main"; then
git fetch "$GITEA_REMOTE" main >/dev/null 2>&1
if git merge-base --is-ancestor "$branch_name" "$GITEA_REMOTE/main" 2>/dev/null; then
log_success "Feature has been released to Gitea main"
log_info "Next step: $0 github-pr $feature_name"
fi
fi
else
log_warning "Feature branch '$branch_name' does not exist"
log_info "Start with: $0 start $feature_name"
fi
}
# Show current workflow state and suggest next action
show_workflow_guidance() {
log_info "🔄 Current Workflow State Analysis"
echo ""
# Check for existing feature branches
local feature_branches=($(git branch | grep "feature/" | sed 's/^[* ]*//' | sed 's/feature\///'))
if [[ ${#feature_branches[@]} -eq 0 ]]; then
log_info "No active feature branches found"
log_info "Start a new feature: $0 start <feature-name>"
echo ""
echo "Example: $0 start user-dashboard"
return
fi
log_info "Active feature branches:"
for feature in "${feature_branches[@]}"; do
echo " 📝 $feature"
check_feature_status "$feature"
echo ""
done
log_info "Quick reference:"
echo " $0 test <name> # Test feature on Gitea dev"
echo " $0 release <name> # Release to Gitea main"
echo " $0 github-pr <name> # Create GitHub PR workflow"
}
# Get current version
get_version() {
if [[ -f "$VERSION_FILE" ]]; then
cat "$VERSION_FILE" | tr -d '\n'
else
echo "1.0.0"
fi
}
# Bump version
bump_version() {
local current_version=$(get_version)
local version_type=$1
IFS='.' read -ra VERSION_PARTS <<< "$current_version"
local major=${VERSION_PARTS[0]}
local minor=${VERSION_PARTS[1]}
local patch=${VERSION_PARTS[2]}
case $version_type in
"patch"|"p")
patch=$((patch + 1))
;;
"minor"|"m")
minor=$((minor + 1))
patch=0
;;
"major"|"M")
major=$((major + 1))
minor=0
patch=0
;;
*)
log_error "Invalid version type. Use: patch|p, minor|m, major|M"
exit 1
;;
esac
local new_version="$major.$minor.$patch"
echo "$new_version" > "$VERSION_FILE"
log_success "Version bumped: $current_version$new_version"
echo "$new_version"
}
# Check if working directory is clean
check_clean() {
if [[ -n $(git status --porcelain) ]]; then
log_error "Working directory not clean. Commit or stash changes first."
exit 1
fi
}
# Ensure we're on the right branch
ensure_branch() {
local target_branch=$1
local current_branch=$(git branch --show-current)
if [[ "$current_branch" != "$target_branch" ]]; then
log_info "Switching to $target_branch"
git checkout "$target_branch"
fi
}
# Sync all branches to match a source
sync_all_branches() {
local source_remote=$1
local source_branch=$2
log_info "Syncing all branches to match $source_remote/$source_branch"
# Fetch all remotes
git fetch "$GITEA_REMOTE"
git fetch "$GITHUB_REMOTE"
# Reset local main to source
ensure_branch main
git reset --hard "$source_remote/$source_branch"
# Push to Gitea (includes .local and .gitea)
log_info "Pushing to Gitea main and dev..."
git push "$GITEA_REMOTE" main --force-with-lease
git push "$GITEA_REMOTE" main:dev --force-with-lease
# For GitHub: create clean branch without .local and .gitea AND without AI attribution
log_info "Creating GitHub-safe branch (excluding .local, .gitea, and AI attribution)..."
local temp_branch="github-sync-temp"
git checkout -b "$temp_branch"
# Remove private directories if they exist
if [[ -d ".local" ]]; then
git rm -rf .local --cached 2>/dev/null || true
fi
if [[ -d ".gitea" ]]; then
git rm -rf .gitea --cached 2>/dev/null || true
fi
# Commit the clean version for GitHub
if [[ -n $(git status --porcelain) ]]; then
git add .
git commit -m "sync: Clean version for GitHub (excludes private dev files)"
fi
# Strip AI attribution AND fix author names from the entire branch history
log_info "Removing AI attribution and fixing author names..."
git filter-branch -f --env-filter '
# Fix author name/email for any commits by jskala or Claude
if [ "$GIT_AUTHOR_NAME" = "jskala" ] || [ "$GIT_AUTHOR_EMAIL" = "jskala@gmail.com" ] ||
[ "$GIT_AUTHOR_NAME" = "Claude" ] || [ "$GIT_AUTHOR_EMAIL" = "noreply@anthropic.com" ]; then
export GIT_AUTHOR_NAME="SBCrumb"
export GIT_AUTHOR_EMAIL="sbcrumb@kickthetree.com"
fi
# Fix committer name/email for any commits by jskala or Claude
if [ "$GIT_COMMITTER_NAME" = "jskala" ] || [ "$GIT_COMMITTER_EMAIL" = "jskala@gmail.com" ] ||
[ "$GIT_COMMITTER_NAME" = "Claude" ] || [ "$GIT_COMMITTER_EMAIL" = "noreply@anthropic.com" ]; then
export GIT_COMMITTER_NAME="SBCrumb"
export GIT_COMMITTER_EMAIL="sbcrumb@kickthetree.com"
fi
' --msg-filter '
# Remove Claude co-authorship lines from commit messages
sed "/Co-Authored-By: Claude/d" |
sed "/Generated with.*Claude/d" |
sed "/🤖 Generated with.*Claude/d" |
# Remove any other AI references
sed "/noreply@anthropic.com/d"
' -- "$temp_branch" 2>/dev/null || log_warning "Filter-branch may not be needed"
log_info "Pushing to GitHub main and dev..."
git push "$GITHUB_REMOTE" "$temp_branch:main" --force-with-lease
git push "$GITHUB_REMOTE" "$temp_branch:dev" --force-with-lease
# Clean up temp branch and return to main
git checkout main
git branch -D "$temp_branch"
log_success "All branches synchronized with privacy respected!"
log_warning "Note: .local and .gitea stay on Gitea only (as intended)"
}
# Start feature development
start_feature() {
local feature_name=$1
if [[ -z "$feature_name" ]]; then
log_error "Feature name required"
echo ""
echo "Usage: $0 start <feature-name>"
echo ""
echo "Examples:"
echo " $0 start user-dashboard # Creates feature/user-dashboard"
echo " $0 start api-improvements # Creates feature/api-improvements"
echo " $0 start bug-fix-login # Creates feature/bug-fix-login"
echo ""
log_info "💡 Use descriptive names with hyphens (no spaces)"
exit 1
fi
check_clean
ensure_branch main
# Create feature branch
local branch_name="feature/$feature_name"
log_info "Creating feature branch: $branch_name"
git checkout -b "$branch_name"
log_success "Feature branch '$branch_name' created. Start coding!"
echo ""
log_info "🔄 Next steps in workflow:"
echo " 1. Make your changes and commit them"
echo " 2. When ready for testing: $0 test $feature_name"
echo " 3. After testing: $0 release $feature_name [patch|minor|major]"
echo " 4. For GitHub PR: $0 github-pr $feature_name"
}
# Test feature (merge to dev)
test_feature() {
local feature_name=$1
if [[ -z "$feature_name" ]]; then
log_error "Feature name required"
echo "Usage: $0 test <feature-name>"
exit 1
fi
check_clean
local branch_name="feature/$feature_name"
# Merge to Gitea dev for testing
ensure_branch dev
git fetch "$GITEA_REMOTE"
git reset --hard "$GITEA_REMOTE/dev"
log_info "Merging $branch_name to dev for testing"
git merge "$branch_name" --no-ff -m "test: Merge $feature_name for local testing"
git push "$GITEA_REMOTE" dev
log_success "Feature merged to Gitea dev for testing"
echo ""
log_info "🧪 Testing Phase:"
echo " • Test your changes thoroughly on the dev environment"
echo " • Check logs, functionality, and integration"
echo " • When satisfied: $0 release $feature_name [patch|minor|major]"
echo ""
log_warning "💡 Remember: Once released to main, it goes to GitHub PR workflow"
}
# Release feature (merge to Gitea main, then create GitHub PR workflow)
release_feature() {
local feature_name=$1
local version_type=${2:-"patch"}
if [[ -z "$feature_name" ]]; then
log_error "Feature name required"
echo "Usage: $0 release <feature-name> [patch|minor|major]"
exit 1
fi
check_clean
# Bump version
local new_version=$(bump_version "$version_type")
# Merge to Gitea main
ensure_branch main
git fetch "$GITEA_REMOTE"
git reset --hard "$GITEA_REMOTE/main"
local branch_name="feature/$feature_name"
log_info "Merging $branch_name to Gitea main"
git merge "$branch_name" --no-ff -m "feat: $feature_name (v$new_version)"
# Push to Gitea main
git push "$GITEA_REMOTE" main
log_success "Feature '$feature_name' merged to Gitea main as v$new_version"
echo ""
log_info "🚀 Ready for GitHub PR Workflow!"
echo " Phase 1 (Gitea) Complete ✅"
echo ""
log_info "📋 Next steps:"
echo " 1. $0 github-pr $feature_name"
echo " 2. Go to GitHub → Create PR: github-feature/$feature_name → dev"
echo " 3. Test on GitHub dev environment"
echo " 4. Create PR: dev → main"
echo " 5. $0 cleanup-github-pr $feature_name"
echo ""
log_warning "💡 The github-pr command will automatically exclude .local/.gitea files"
}
# Create GitHub PR workflow branch
github_pr() {
local feature_name=$1
if [[ -z "$feature_name" ]]; then
log_error "Feature name required"
echo "Usage: $0 github-pr <feature-name>"
exit 1
fi
check_clean
# Create clean GitHub feature branch from current Gitea main
log_info "Creating GitHub PR workflow for feature: $feature_name"
ensure_branch main
git fetch "$GITEA_REMOTE"
git reset --hard "$GITEA_REMOTE/main"
# Create GitHub-safe feature branch
local github_branch="github-feature/$feature_name"
git checkout -b "$github_branch"
# Remove private directories for GitHub
if [[ -d ".local" ]]; then
git rm -rf .local --cached 2>/dev/null || true
fi
if [[ -d ".gitea" ]]; then
git rm -rf .gitea --cached 2>/dev/null || true
fi
# Commit clean version if changes exist
if [[ -n $(git status --porcelain) ]]; then
git add .
git commit -m "github: Clean feature branch for $feature_name PR workflow"
fi
# Apply privacy filters
log_info "Applying privacy filters..."
git filter-branch -f --env-filter '
if [ "$GIT_AUTHOR_NAME" = "jskala" ] || [ "$GIT_AUTHOR_EMAIL" = "jskala@gmail.com" ] ||
[ "$GIT_AUTHOR_NAME" = "Claude" ] || [ "$GIT_AUTHOR_EMAIL" = "noreply@anthropic.com" ]; then
export GIT_AUTHOR_NAME="SBCrumb"
export GIT_AUTHOR_EMAIL="sbcrumb@kickthetree.com"
fi
if [ "$GIT_COMMITTER_NAME" = "jskala" ] || [ "$GIT_COMMITTER_EMAIL" = "jskala@gmail.com" ] ||
[ "$GIT_COMMITTER_NAME" = "Claude" ] || [ "$GIT_COMMITTER_EMAIL" = "noreply@anthropic.com" ]; then
export GIT_COMMITTER_NAME="SBCrumb"
export GIT_COMMITTER_EMAIL="sbcrumb@kickthetree.com"
fi
' --msg-filter '
sed "/Co-Authored-By: Claude/d" |
sed "/Generated with.*Claude/d" |
sed "/🤖 Generated with.*Claude/d" |
sed "/noreply@anthropic.com/d"
' -- "$github_branch" 2>/dev/null || log_warning "Filter-branch may not be needed"
# Push feature branch to GitHub
git push "$GITHUB_REMOTE" "$github_branch" --force-with-lease
# Also update GitHub dev branch
git push "$GITHUB_REMOTE" "$github_branch:dev" --force-with-lease
log_success "GitHub feature branch created: $github_branch"
log_info "Next steps:"
log_info " 1. Go to GitHub and create PR: $github_branch → dev"
log_info " 2. Test the changes on github-dev"
log_info " 3. Create PR: dev → main"
log_info " 4. Run: $0 cleanup-github-pr $feature_name"
# Return to main and cleanup
git checkout main
git branch -D "$github_branch"
}
# Cleanup after GitHub PR workflow
cleanup_github_pr() {
local feature_name=$1
if [[ -z "$feature_name" ]]; then
log_error "Feature name required"
echo "Usage: $0 cleanup-github-pr <feature-name>"
exit 1
fi
# Cleanup local feature branch
local branch_name="feature/$feature_name"
git branch -d "$branch_name" 2>/dev/null || true
# Cleanup remote branches
git push "$GITEA_REMOTE" --delete "$branch_name" 2>/dev/null || true
git push "$GITHUB_REMOTE" --delete "github-feature/$feature_name" 2>/dev/null || true
log_success "Cleaned up feature branches for: $feature_name"
}
# Show status
show_status() {
log_info "Current Repository Status"
echo ""
# Current branch and version
local current_branch=$(git branch --show-current)
local current_version=$(get_version)
echo "📍 Current Branch: $current_branch"
echo "🔢 Current Version: $current_version"
echo ""
# Remote status
git fetch "$GITEA_REMOTE" >/dev/null 2>&1
git fetch "$GITHUB_REMOTE" >/dev/null 2>&1
echo "🔄 Branch Status:"
echo " Local main: $(git rev-parse --short main)"
echo " Gitea main: $(git rev-parse --short $GITEA_REMOTE/main)"
echo " Gitea dev: $(git rev-parse --short $GITEA_REMOTE/dev)"
echo " GitHub main: $(git rev-parse --short $GITHUB_REMOTE/main)"
echo " GitHub dev: $(git rev-parse --short $GITHUB_REMOTE/dev)"
echo ""
# Check if synchronized
local gitea_main=$(git rev-parse $GITEA_REMOTE/main)
local gitea_dev=$(git rev-parse $GITEA_REMOTE/dev)
local github_main=$(git rev-parse $GITHUB_REMOTE/main)
local github_dev=$(git rev-parse $GITHUB_REMOTE/dev)
if [[ "$gitea_main" == "$gitea_dev" && "$gitea_main" == "$github_main" && "$gitea_main" == "$github_dev" ]]; then
log_success "All branches are synchronized! ✨"
else
log_warning "Branches are not synchronized"
echo " Run: $0 sync to synchronize all branches"
fi
echo ""
show_workflow_guidance
}
# Main script logic
case "${1:-status}" in
"start")
start_feature "$2"
;;
"test")
test_feature "$2"
;;
"release")
release_feature "$2" "$3"
;;
"github-pr")
github_pr "$2"
;;
"cleanup-github-pr")
cleanup_github_pr "$2"
;;
"sync")
sync_all_branches "$GITEA_REMOTE" main
;;
"version")
if [[ -n "$2" ]]; then
bump_version "$2"
else
echo "Current version: $(get_version)"
fi
;;
"status"|"")
show_status
;;
*)
# Check if it's a typo or unknown command and suggest alternatives
suggest_command "$1"
echo "NFOGuard Development Sync Script"
echo ""
echo "Usage: $0 <command> [options]"
echo ""
log_info "Available Commands:"
echo " start <name> Create new feature branch"
echo " test <name> Merge feature to dev for testing"
echo " release <name> [type] Merge to Gitea main (patch|minor|major)"
echo " github-pr <name> Create GitHub PR workflow branch"
echo " cleanup-github-pr <name> Cleanup after GitHub PR workflow"
echo " sync Sync all branches to Gitea main"
echo " version [type] Show or bump version"
echo " status Show repository status (default)"
echo ""
log_info "Professional Git Workflow:"
echo " # 🔧 Gitea Development (Private)"
echo " $0 start user-auth # Create feature branch"
echo " # ... develop feature ..."
echo " $0 test user-auth # Test on Gitea dev"
echo " $0 release user-auth minor # Merge to Gitea main"
echo ""
echo " # 🚀 GitHub PR Workflow (Public)"
echo " $0 github-pr user-auth # Create clean GitHub branch"
echo " # Create PR: github-feature/user-auth → github-dev"
echo " # Test, then create PR: github-dev → github-main"
echo " $0 cleanup-github-pr user-auth # Cleanup branches"
echo ""
log_info "Common Aliases:"
echo " create, new, init → start"
echo " merge, pr, pull-request → github-pr"
echo " clean, cleanup, remove → cleanup-github-pr"
echo " check, info, show → status"
echo " push, deploy, publish → release"
echo " dev, develop → test"
echo ""
log_warning "💡 Tip: Run '$0 status' to see your current workflow state and next steps"
;;
esac