dev: automated commit - 2025-05-31 16:03:53
This commit is contained in:
commit
0e0bebab30
7 changed files with 944 additions and 0 deletions
377
run
Executable file
377
run
Executable file
|
@ -0,0 +1,377 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔧 SETUP
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ENV_FILE="$SCRIPT_DIR/.env"
|
||||
RUNS_DIR="$SCRIPT_DIR/runs"
|
||||
LOGS_DIR="$SCRIPT_DIR/logs"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🛠️ HELPERS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
log() { echo -e "${GREEN}[RUN]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔍 DEPENDENCY VALIDATION
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
check_dependencies() {
|
||||
local missing=()
|
||||
|
||||
# Required tools
|
||||
local required_tools=("git" "find" "grep")
|
||||
|
||||
# Optional but recommended tools
|
||||
local optional_tools=("gitleaks")
|
||||
|
||||
log "Checking dependencies..."
|
||||
|
||||
# Check required tools
|
||||
for tool in "${required_tools[@]}"; do
|
||||
if ! command -v "$tool" &>/dev/null; then
|
||||
missing+=("$tool")
|
||||
fi
|
||||
done
|
||||
|
||||
# Check optional tools
|
||||
for tool in "${optional_tools[@]}"; do
|
||||
if ! command -v "$tool" &>/dev/null; then
|
||||
warn "Optional tool missing: $tool (recommended for security scanning)"
|
||||
else
|
||||
log "✓ Found: $tool"
|
||||
fi
|
||||
done
|
||||
|
||||
# Report missing required tools
|
||||
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||
error "Missing required tools: ${missing[*]}"
|
||||
error "Please install missing dependencies"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "✓ All required dependencies found"
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔒 SECURITY SCANNING
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
run_security_scan() {
|
||||
log "Running security scan..."
|
||||
|
||||
if command -v gitleaks &>/dev/null; then
|
||||
log "Using GitLeaks for secret detection..."
|
||||
if gitleaks detect --verbose --exit-code 1; then
|
||||
log "✅ No secrets detected"
|
||||
return 0
|
||||
else
|
||||
error "❌ Secrets detected! Review before pushing."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
warn "GitLeaks not installed - skipping security scan"
|
||||
warn "Install with: paru -S gitleaks"
|
||||
echo
|
||||
read -p "Continue without security scan? (y/N): " -r answer
|
||||
if [[ ! "$answer" =~ ^[Yy]$ ]]; then
|
||||
error "Push cancelled for security"
|
||||
exit 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 📤 PUSH COMMAND
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
handle_push() {
|
||||
log "Preparing to push repository..."
|
||||
|
||||
# Check if we're in a git repository
|
||||
if ! git rev-parse --git-dir &>/dev/null; then
|
||||
error "Not in a git repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for uncommitted changes
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
warn "You have uncommitted changes"
|
||||
echo
|
||||
git status --short
|
||||
echo
|
||||
|
||||
# Generate default commit message
|
||||
local default_msg="dev: automated commit - $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
|
||||
read -p "Commit all changes? (Y/n): " -r answer
|
||||
if [[ ! "$answer" =~ ^[Nn]$ ]]; then
|
||||
echo
|
||||
echo "Default: $default_msg"
|
||||
read -p "Custom commit message (or press Enter for default): " -r commit_msg
|
||||
|
||||
# Use default if empty
|
||||
if [[ -z "$commit_msg" ]]; then
|
||||
commit_msg="$default_msg"
|
||||
fi
|
||||
|
||||
git add .
|
||||
git commit -m "$commit_msg"
|
||||
log "✓ Changes committed: $commit_msg"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run security scan
|
||||
if ! run_security_scan; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get current branch
|
||||
local current_branch
|
||||
current_branch=$(git branch --show-current)
|
||||
|
||||
# Push to origin
|
||||
log "Pushing branch '$current_branch' to origin..."
|
||||
if git push origin "$current_branch"; then
|
||||
log "✅ Successfully pushed to origin/$current_branch"
|
||||
else
|
||||
error "❌ Push failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
show_help() {
|
||||
cat <<EOF
|
||||
Usage: $0 [OPTIONS] [COMMAND|FILTERS...]
|
||||
|
||||
COMMANDS:
|
||||
push Commit, scan for secrets, and push to git origin
|
||||
deps, check Check for required dependencies
|
||||
help Show this help message
|
||||
|
||||
SCRIPT EXECUTION:
|
||||
[FILTERS...] Run scripts matching filters from runs/ directory
|
||||
|
||||
OPTIONS:
|
||||
--dry Show what would run without executing
|
||||
--verbose Show detailed output during execution
|
||||
|
||||
EXAMPLES:
|
||||
$0 deps # Check dependencies
|
||||
$0 push # Secure git push with secret scanning
|
||||
$0 docker # Run scripts containing 'docker'
|
||||
$0 --dry base # Show what base scripts would run
|
||||
$0 --verbose all # Run all scripts with detailed output
|
||||
|
||||
SECURITY:
|
||||
The push command automatically scans for secrets using GitLeaks
|
||||
before pushing to prevent accidental credential exposure.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
get_description() {
|
||||
local script="$1"
|
||||
grep '^# NAME:' "$script" 2>/dev/null | cut -d: -f2- | sed 's/^ *//' || echo "No description"
|
||||
}
|
||||
|
||||
matches_filters() {
|
||||
local script_name="$1"
|
||||
shift
|
||||
local filters=("$@")
|
||||
|
||||
[[ ${#filters[@]} -eq 0 ]] && return 0
|
||||
|
||||
for filter in "${filters[@]}"; do
|
||||
if [[ "$script_name" == *"$filter"* ]] || [[ "${script_name,,}" == *"${filter,,}"* ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🚦 INITIALIZATION
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Create runs directory if missing
|
||||
if [[ ! -d "$RUNS_DIR" ]]; then
|
||||
log "Creating runs directory at: $RUNS_DIR"
|
||||
mkdir -p "$RUNS_DIR"
|
||||
|
||||
# Create example script
|
||||
cat >"$RUNS_DIR/example.sh" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# NAME: Example script
|
||||
echo "Hello from runs/example.sh!"
|
||||
echo "Edit this script or add your own to $RUNS_DIR"
|
||||
EOF
|
||||
chmod +x "$RUNS_DIR/example.sh"
|
||||
|
||||
log "✅ Created runs/ directory with example script"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create logs directory
|
||||
mkdir -p "$LOGS_DIR"
|
||||
|
||||
# Load environment
|
||||
[[ -f "$ENV_FILE" ]] && source "$ENV_FILE"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 📝 PARSE ARGUMENTS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
DRY_RUN=0
|
||||
VERBOSE=0
|
||||
FILTERS=()
|
||||
COMMAND=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dry) DRY_RUN=1 ;;
|
||||
--verbose) VERBOSE=1 ;;
|
||||
--help | help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
push) COMMAND="push" ;;
|
||||
deps | check) COMMAND="deps" ;;
|
||||
-*)
|
||||
error "Unknown option: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
*) FILTERS+=("$1") ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🚦 HANDLE COMMANDS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Handle special commands first
|
||||
case "$COMMAND" in
|
||||
"push")
|
||||
handle_push
|
||||
exit 0
|
||||
;;
|
||||
"deps")
|
||||
check_dependencies
|
||||
exit 0
|
||||
;;
|
||||
"")
|
||||
# No command, continue with script execution
|
||||
;;
|
||||
*)
|
||||
error "Unknown command: $COMMAND"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔍 FIND SCRIPTS TO RUN
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
mapfile -t ALL_SCRIPTS < <(find "$RUNS_DIR" -type f -executable | sort)
|
||||
|
||||
if [[ ${#ALL_SCRIPTS[@]} -eq 0 ]]; then
|
||||
warn "No executable scripts found in $RUNS_DIR"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SCRIPTS_TO_RUN=()
|
||||
for script in "${ALL_SCRIPTS[@]}"; do
|
||||
script_name="$(basename "$script")"
|
||||
if matches_filters "$script_name" "${FILTERS[@]}"; then
|
||||
SCRIPTS_TO_RUN+=("$script")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#SCRIPTS_TO_RUN[@]} -eq 0 ]]; then
|
||||
warn "No scripts match the given filters: ${FILTERS[*]}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# ⚠️ CONFIRMATION FOR RUNNING ALL SCRIPTS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
if [[ ${#FILTERS[@]} -eq 0 && $DRY_RUN -eq 0 ]]; then
|
||||
echo -e "${RED}⚠️ About to run ALL scripts:${NC}"
|
||||
for script in "${SCRIPTS_TO_RUN[@]}"; do
|
||||
name="$(basename "$script")"
|
||||
desc="$(get_description "$script")"
|
||||
echo " • $name - $desc"
|
||||
done
|
||||
echo
|
||||
read -p "Continue? (y/N): " -r answer
|
||||
if [[ ! "$answer" =~ ^[Yy]$ ]]; then
|
||||
echo "Cancelled"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🚀 EXECUTE SCRIPTS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
EXECUTED=()
|
||||
FAILED=()
|
||||
|
||||
for script in "${SCRIPTS_TO_RUN[@]}"; do
|
||||
name="$(basename "$script")"
|
||||
desc="$(get_description "$script")"
|
||||
log_file="$LOGS_DIR/${name%.*}.log"
|
||||
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
echo -e "${BLUE}[DRY]${NC} Would run: $name - $desc"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo -e "\n${BLUE}▶${NC} Running: $name"
|
||||
[[ "$desc" != "No description" ]] && echo " $desc"
|
||||
|
||||
if [[ $VERBOSE -eq 1 ]]; then
|
||||
if "$script" 2>&1 | tee "$log_file"; then
|
||||
log "✅ $name completed"
|
||||
EXECUTED+=("$name")
|
||||
else
|
||||
error "❌ $name failed (see $log_file)"
|
||||
FAILED+=("$name")
|
||||
fi
|
||||
else
|
||||
if "$script" &>"$log_file"; then
|
||||
log "✅ $name completed"
|
||||
EXECUTED+=("$name")
|
||||
else
|
||||
error "❌ $name failed (see $log_file)"
|
||||
FAILED+=("$name")
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 📊 SUMMARY
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
if [[ $DRY_RUN -eq 0 ]]; then
|
||||
echo -e "\n${BLUE}═══ SUMMARY ═══${NC}"
|
||||
echo "✅ Completed: ${#EXECUTED[@]}"
|
||||
[[ ${#FAILED[@]} -gt 0 ]] && echo "❌ Failed: ${#FAILED[@]}"
|
||||
|
||||
if [[ ${#FAILED[@]} -gt 0 ]]; then
|
||||
echo -e "\n${RED}Failed scripts:${NC}"
|
||||
for failed in "${FAILED[@]}"; do
|
||||
echo " • $failed"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
Loading…
Add table
Add a link
Reference in a new issue