Files
nfoguard/.local/sync-script.sh
T
sbcrumb a99fb3e9c9 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
2025-09-23 17:40:07 -04:00

602 lines
20 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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