From 0340226b24353c0eab1ca019be8b6d586d6a9254 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Nov 2025 03:29:13 +0000 Subject: [PATCH 1/2] refactor: Dramatically simplify cs CLI for better usability BREAKING CHANGE: Complete rewrite for simplicity and zsh compatibility Problems with previous version: - Too complex with many features users didn't understand - Didn't work properly with zsh - Index building was complicated and error-prone - Too many commands and options New simplified version: - Only 4 commands: quick, search, list, view - Works with both bash and zsh - No complex indexing - just grep search - Clear, simple help with real examples - README reduced from 800+ lines to ~120 lines - Test suite reduced from 17 tests to 10 essential tests Commands: cs quick # Save a command cs search # Search cheatsheets cs list # List all files cs # View a cheatsheet That's it. Simple and it works. All tests passing (10/10) --- README.md | 779 ++++---------------------------------------- cs | 935 +++++------------------------------------------------ install.sh | 213 ++---------- test.sh | 181 ++--------- 4 files changed, 202 insertions(+), 1906 deletions(-) diff --git a/README.md b/README.md index 7ea5691..46ac50a 100644 --- a/README.md +++ b/README.md @@ -1,778 +1,117 @@ -# CheatSheets - Interactive Knowledge Base +# CheatSheets [![CI Tests](https://github.com/mlorentedev/cheat-sheets/workflows/CI%20Tests/badge.svg)](https://github.com/mlorentedev/cheat-sheets/actions) -[![Quality Checks](https://github.com/mlorentedev/cheat-sheets/workflows/Quality%20Checks/badge.svg)](https://github.com/mlorentedev/cheat-sheets/actions) -[![Multi-Platform](https://github.com/mlorentedev/cheat-sheets/workflows/Multi-Platform%20Tests/badge.svg)](https://github.com/mlorentedev/cheat-sheets/actions) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -Transform your scattered command knowledge into an organized, searchable personal reference system. - -A personal second brain for DevOps commands, configurations, and scripts. Built for engineers who value their time and want to capture knowledge as they discover it - in under 10 seconds. +Personal command reference for Linux, Docker, Kubernetes, Terraform, and more. ## Quick Start ```bash -# Clone the repository +# Clone git clone https://github.com/mlorentedev/cheat-sheets ~/.cheat-sheets cd ~/.cheat-sheets -# Run the installer -./install.sh - -# Start using immediately -cs docker # Search docker commands -cs -i # Interactive browser -cs quick "kubectl get pods -A" # Capture a command instantly -``` - -## The Problem - -You discover useful commands daily, but capturing them interrupts your flow. Traditional cheatsheets are static and hard to maintain. - -## The Solution - -A CLI tool (`cs`) that makes adding commands as natural as running them. If it takes more than 10 seconds to add a command, the system has failed. - -### Features - -- Quick Capture: `cs quick "command"` takes about 2 seconds -- Fast Search: Find commands in milliseconds -- Zero Friction: Add without breaking your flow -- Smart Organization: Auto-categorizes commands -- Interactive Browser: Explore with fzf integration -- Auto-Sync: Optional git sync on every change -- Track Learning: See your knowledge growth - -## Daily Usage - -### Finding Commands - -```bash -# Simple search -cs docker # All docker commands -cs "list pods" # Natural language search -cs kubectl -c tools # Search specific category - -# Interactive browser (requires fzf) -cs -i # Browse everything -cs browse # Same as -i - -# List what's available -cs list # All categories and files -cs stats # Usage statistics -``` - -Example output: -``` -docker system prune -a - → Remove all unused containers, networks, images - 📁 tools/docker.md - -docker run -d -p 8080:80 nginx - → Run nginx in background on port 8080 - 📁 tools/docker.md -``` - -### Adding Commands - -#### Quick Add (2 seconds) - -Just discovered a useful command? Save it instantly: - -```bash -cs quick "terraform state rm aws_instance.example" -cs q "git reset --hard HEAD~1" # Short alias -``` - -Commands are added to `personal/quick.md` with a timestamp. Perfect for capturing during active work. - -#### Standard Add (5 seconds) - -Add with context: - -```bash -cs add "kubectl rollout restart deploy/app" \ - --desc "Restart deployment without downtime" \ - --tags k8s,restart,deploy - -cs add "docker logs -f container 2>&1 | grep ERROR" \ - --desc "Follow container logs and filter errors" \ - --tags docker,debug \ - --cat tools/docker -``` - -#### Interactive Mode (10 seconds) - -Guided process with prompts: - -```bash -cs add -i -``` - -You'll be prompted for: -- Command (required) -- Description (optional) -- Tags (optional) -- Category (auto-detected, customizable) -- Example (optional) - -Example session: -``` -=== Interactive Command Add === - -Command: kubectl get pods -A -Description (optional): List all pods in all namespaces -Tags (comma-separated, optional): k8s,debug,pods -Category [tools/kubectl]: -Example (optional): - -Preview: -Command: kubectl get pods -A -Description: List all pods in all namespaces -Tags: k8s,debug,pods -Category: tools/kubectl - -Add this command? [Y/n]: y -✓ Added to: tools/kubectl.md -``` - -#### Capture from History - -Just ran something useful? Capture it: - -```bash -cs capture # Show last 10 commands, select to save -cs capture --last 5 # Last 5 commands -cs capture --auto # Auto-capture frequently used commands -``` - -Shell alias for instant capture: -```bash -alias csc='cs capture --last 1' -``` - -Then after running any command: -```bash -terraform plan -var-file=prod.tfvars -csc # Captures the terraform command -``` - -### Creating New Sections - -Need to organize a new tool or category? - -```bash -# Create new tool section -cs new consul # Creates tools/consul.md -cs new tool ansible # Same as above - -# Create in specific category -cs new infra/mongodb # Creates infra/mongodb.md -cs new monitoring/prometheus # Creates monitoring/prometheus.md - -# Use templates -cs new istio --template k8s # Use Kubernetes template -cs new myapp --template simple # Minimal template +# Add to PATH +echo 'export PATH="$PATH:~/.cheat-sheets"' >> ~/.bashrc +source ~/.bashrc ``` -Available templates: -- `tool` (default): Full tool documentation structure -- `k8s`: Kubernetes resource template -- `simple`: Minimal template - -### Maintenance +## Usage ```bash -# Update search index (auto-runs after adds) -cs index +# Save a command +cs quick "docker ps -a" +cs quick "kubectl get pods -A" -# Sync with git -cs sync # Pull, commit, push +# Search for something +cs search docker +cs search kubernetes -# View statistics -cs stats +# View a cheatsheet +cs docker +cs kubectl +cs git -# List all categories and files +# List everything cs list ``` -## Real-World Workflows - -### Learning a New Tool - -You're exploring Consul for the first time: - -```bash -# 1. Check if you have any consul commands -cs consul -# No results (new tool) - -# 2. Try some commands while learning -consul members -consul catalog services - -# 3. Find something useful -consul kv put config/app/db "postgresql://..." - -# 4. Capture it immediately -cs quick "consul kv put config/app/db " - -# 5. Later, organize properly -cs add "consul kv get config/app/db" \ - --desc "Retrieve key-value from Consul" \ - --tags consul,kv,config \ - --cat tools/consul - -# 6. Create dedicated section -cs new consul -``` - -After a few days, you have a personal Consul reference built from real usage. - -### Debugging Production - -Production is down at 2 AM: - -```bash -# 1. Quick search -cs "pod logs" - -# Shows: kubectl logs -f deployment/app - -# 2. Run it -kubectl logs -f deployment/myapp -n production - -# 3. Find the issue, fix it - -# 4. Found a new useful variation during debugging -kubectl logs deployment/myapp -n production --previous - -# 5. Save it for next time -cs quick "kubectl logs deployment/app --previous" -``` - -Next incident, you have the command ready. - -### Daily Knowledge Accumulation - -Throughout your day: - -```bash -# Morning - found useful docker command -cs quick "docker run --rm -v $(pwd):/app -w /app node:alpine npm test" - -# Noon - learned terraform trick -cs add "terraform fmt -recursive" --desc "Format all .tf files" --tags terraform - -# Afternoon - kubernetes discovery -cs quick "kubectl top nodes" -cs quick "kubectl describe node" - -# End of day - review what you captured -cs stats -# Personal: 8 new commands today - -# Auto-organize frequent commands -cs capture --auto -``` - -Result: After one month, you have 100+ real commands you actually use, organized automatically. - -## Configuration - -### Configuration File - -Create `.cs.config` in the repository root: - -```bash -# .cs.config - CheatSheets configuration - -# Editor for opening files -EDITOR=nvim # or code, nano, vim - -# Auto-sync with git after changes -AUTO_SYNC=true # true or false - -# Default category for new commands -DEFAULT_CATEGORY=personal - -# Where quick adds go -QUICK_ADD_FILE="${PERSONAL_DIR}/quick.md" - -# Threshold for auto-capture -CAPTURE_THRESHOLD=3 # Capture commands used 3+ times -``` - -### Shell Aliases (Recommended) +That's it! Just 4 commands. -Add to your `~/.bashrc` or `~/.zshrc`: +## What's Inside -```bash -# CheatSheets aliases for maximum speed -alias csa='cs add' -alias csq='cs quick' -alias csc='cs capture --last 1' -alias csi='cs -i' -alias css='cs search' -alias csn='cs new' - -# Integration with your workflow -alias csl='cs list' -alias csync='cs sync' -``` +- **linux/** - grep, sed, awk, find, tar, cron, etc. +- **tools/** - docker, kubectl, terraform, helm, git, etc. +- **infra/** - mysql, postgresql, sqlite, zfs +- **misc/** - http codes, dns, smtp codes +- **windows/** - powershell, chocolatey +- **personal/** - your own commands (gitignored) -With aliases, adding a command becomes: -```bash -csq "docker system df" # 2 seconds total -``` +## Examples -### Environment Variables +### Save commands as you discover them ```bash -# Set custom root directory -export CS_ROOT="$HOME/my-cheatsheets" - -# Enable auto-sync -export CS_AUTO_SYNC=true - -# Set capture threshold -export CS_CAPTURE_THRESHOLD=5 -``` - -## Repository Structure - -``` -cheat-sheets/ -├── README.md # This file -├── LICENSE # MIT License -├── install.sh # One-line installer -├── cs # Main CLI tool (executable) -├── .cs.config # Your configuration (optional) -├── .gitignore # Ignores personal/ directory -│ -├── linux/ # Linux system commands -│ ├── grep.md -│ ├── find.md -│ ├── sed.md -│ └── ... -│ -├── tools/ # DevOps tools -│ ├── docker.md -│ ├── kubectl.md -│ ├── terraform.md -│ ├── git.md -│ ├── helm.md -│ └── ... -│ -├── infra/ # Infrastructure & databases -│ ├── mysql.md -│ ├── postgresql.md -│ ├── zfs.md -│ └── ... -│ -├── misc/ # Protocols and references -│ ├── http-status-codes.md -│ ├── dns.md -│ └── ... -│ -├── windows/ # Windows tools -│ ├── powershell.md -│ └── ... -│ -├── personal/ # Your additions (gitignored) -│ ├── quick.md # Quick captures -│ ├── commands.md # Organized personal commands -│ └── work.md # Work-specific commands -│ -└── templates/ # Templates for new sections - ├── tool.md - ├── k8s.md - └── simple.md -``` - -### What Gets Committed - -**Tracked** (committed to git): -- All category directories (linux/, tools/, infra/, etc.) -- Shared/public cheatsheets -- README, LICENSE, install.sh, cs tool - -**Ignored** (not committed): -- `personal/` directory - your private commands -- `.cs.config` - your personal configuration -- `.cs_index` - search index (rebuilt automatically) -- `.cs_cache/` - temporary cache - -This lets you: -- Pull updates from upstream -- Keep your private commands separate -- Share your additions via export - -## Tips - -### Instant Capture Workflow - -```bash -# Run command -docker run -d -p 8080:80 --name web nginx - -# Works! Save it immediately -csq "docker run -d -p 8080:80 --name web nginx" -``` - -Time: about 3 seconds including typing. - -### Build a Daily Habit - -End of each day: - -```bash -cs stats # Review what you added -cs capture --auto # Capture frequently used -cs sync # Backup to git -``` - -### Category Auto-Detection - -The tool auto-detects categories from command prefixes: - -- `docker ...` → `tools/docker` -- `kubectl ...` → `tools/kubectl` -- `git ...` → `tools/git` -- `terraform ...` → `tools/terraform` -- `helm ...` → `tools/helm` -- Everything else → `personal` - -Override with `--cat`: -```bash -cs add "aws s3 ls" --cat tools/aws -``` - -### Search Shortcuts - -```bash -# Search is smart - just type keywords -cs docker prune # Finds docker system prune commands -cs k8s logs # Finds kubectl logs -cs "restart deployment" # Natural language - -# Search specific category -cs nginx -c tools -``` - -### Quick Reference Export - -```bash -# Export recent additions for sharing -cs capture --auto > team-snippets.md - -# Or manually export category -cat tools/docker.md | grep '|' > docker-ref.txt +# Just ran a useful command? Save it: +docker run -d -p 8080:80 nginx +cs quick "docker run -d -p 8080:80 nginx" ``` -### Shell Integration +### Find commands you forgot -Add to your shell prompt: ```bash -# Show CS stats in prompt -PROMPT_COMMAND='__cs_count=$(find ~/.cheat-sheets/personal -name "*.md" -exec cat {} \; | grep -c "```bash" 2>/dev/null || echo 0)' -PS1='[${__cs_count} cmds] $ ' -``` - -## Track Your Learning +# What was that kubernetes command? +cs search pods -```bash -# View statistics -cs stats - -# Example output: -# CheatSheets Statistics -# -# Repository: -# Files: 42 -# Categories: 5 -# Total commands: 487 -# -# Personal: -# Commands: 67 -# -# Recent Activity: -# Quick captures today: 5 +# Show me all docker commands +cs docker ``` -## Advanced Usage - -### Import from Other Sources +### View cheatsheets ```bash -# Import from another cheatsheet format -cat external-cheatsheet.md | while read line; do - cs quick "$line" -done - -# Bulk import from history -history | tail -100 | cut -d' ' -f4- | while read cmd; do - echo "Import: $cmd [Y/n]?" - read confirm - [[ "$confirm" == "Y" ]] && cs quick "$cmd" -done -``` - -### Integration with Other Tools +# Open docker cheatsheet +cs docker -```bash -# With tldr -tldr docker | grep -E '^\s*-' | while read line; do - cmd=$(echo "$line" | sed 's/^- //') - cs quick "$cmd" -done - -# With your notes -grep '```bash' notes.md | sed 's/```bash//' | while read cmd; do - cs quick "$cmd" -done +# List all available cheatsheets +cs list ``` -### Backup and Restore - -```bash -# Backup personal commands -tar -czf cs-backup-$(date +%Y%m%d).tar.gz personal/ - -# Restore -tar -xzf cs-backup-20250101.tar.gz -``` +## Your Quick Commands -### Multi-Machine Sync +Your saved commands go to `personal/quick.md` - edit it anytime: ```bash -# Machine 1: Enable auto-sync -echo "AUTO_SYNC=true" >> .cs.config - -# Every change syncs to git automatically -cs quick "new command" -# Added to quick captures -# Syncing with git... -# Changes committed - -# Machine 2: Pull updates -cd ~/.cheat-sheets -git pull -cs index # Rebuild index with new content +vim personal/quick.md +# or +code personal/quick.md ``` -## Contributing - -Found a useful command? Share it. +## Manual Additions -### Adding to Public Categories +Just add to the markdown files: ```bash -# Add to a public category (will be committed) -cs add "terraform state list | grep aws_instance" \ - --desc "List all AWS instances in state" \ - --tags terraform,aws \ - --cat tools/terraform - -# Sync to create commit -cs sync -git push +vim tools/myapp.md ``` -### Sharing Your Discoveries - -```bash -# Export your personal additions -cd personal/ -cat quick.md commands.md > ../my-contributions.md - -# Create a PR with the additions -``` - -## Command Format in Files - -When manually editing `.md` files, use this format: - -### Table Format (Recommended) - +Format: ```markdown -## Category Name +# My App + +## Commands | COMMAND | DESCRIPTION | | --- | --- | -| `command --flag arg` | What it does [Tags: tag1,tag2] | -| `another command` | Description here | -``` - -### Code Block Format - -```markdown -## Command Name - -```bash -# Description of what this does -command --flag argument - -# Example with output -command --verbose -# Expected output: ... -``` -``` - -Both formats are indexed and searchable. - -## Command Reference - -```bash -cs [COMMAND] [OPTIONS] - -QUICK COMMANDS: - cs quick "command" Add command instantly - cs "search term" Search for commands - cs add "cmd" --desc "..." Add with description - cs add -i Interactive add mode - cs capture Capture from history - cs new Create new section - -SEARCH & BROWSE: - cs search Search all commands - cs browse Interactive browser - cs -i Interactive browser (same) - cs list List all categories - -CONTENT MANAGEMENT: - cs add "command" [OPTIONS] Add command with metadata - --desc "description" Add description - --tags "tag1,tag2" Add tags - --cat "category" Specify category - --example "example" Add example - - cs new section Create new section - --template Use template (tool, k8s, simple) - - cs capture [OPTIONS] Capture from history - --last N Show last N commands - --auto Auto-capture frequent commands - -MAINTENANCE: - cs index Rebuild search index - cs sync Git sync (pull, commit, push) - cs stats Show statistics - cs list List all categories - cs help Show this help - cs version Show version -``` - -## Troubleshooting - -### Search not finding commands - -```bash -# Rebuild the index -cs index -``` - -### Want to use fzf for better browsing - -```bash -# Install fzf (Ubuntu/Debian) -sudo apt install fzf - -# Install fzf (macOS) -brew install fzf - -# Install fzf (manual) -git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf -~/.fzf/install +| `myapp start` | Start the app | +| `myapp stop` | Stop the app | ``` -### Commands not syncing to git - -```bash -# Check git status -git status - -# Manual sync -git add . -git commit -m "Update cheatsheets" -git push - -# Or use cs sync -cs sync -``` - -### Lost personal commands - -```bash -# Check if they exist -ls -la personal/ - -# Restore from git (if previously synced) -git checkout personal/ - -# Restore from backup -tar -xzf cs-backup-*.tar.gz -``` - -## Getting Started - -1. Install the tool: `./install.sh` -2. Try quick add: `cs quick "ls -la"` -3. Search: `cs "list files"` -4. Browse: `cs -i` - -### Example Daily Workflow - -```bash -# Morning: Review what's new -cs stats - -# During work: Capture as you discover -cs quick "useful command 1" -cs quick "useful command 2" - -# When you have 2 minutes: Organize -cs add -i # Go through quick captures - -# End of day: Sync -cs sync -``` - -### Building Your Library - -Week 1: Quick capture everything -- Focus on `cs quick` only -- Capture 5-10 commands/day -- Don't worry about organization - -Week 2: Start organizing -- Use `cs add -i` for important commands -- Add descriptions and tags -- Create 2-3 new sections - -Week 3: Optimize your workflow -- Set up aliases -- Enable auto-sync -- Use capture from history - -Month 2+: Your knowledge base grows naturally -- 100+ commands captured -- Organized by real usage patterns -- Your go-to reference - ## License -MIT License - see [LICENSE](LICENSE) file for details. - -## Related Projects - -- [Dotfiles](https://github.com/mlorentedev/dotfiles) - My personal dotfiles for Linux -- [Boilerplates](https://github.com/mlorentedev/boilerplates) - Docker, Kubernetes, and more - -## Acknowledgments +MIT - See [LICENSE](LICENSE) -Built for DevOps engineers who value their time. Inspired by the need to capture knowledge without breaking flow. +## More -If you find this useful, star the repo. -Found a bug? [Open an issue](https://github.com/mlorentedev/cheat-sheets/issues) -Have an idea? [Start a discussion](https://github.com/mlorentedev/cheat-sheets/discussions) +- [Dotfiles](https://github.com/mlorentedev/dotfiles) +- [Boilerplates](https://github.com/mlorentedev/boilerplates) diff --git a/cs b/cs index a6ff40a..047fcef 100755 --- a/cs +++ b/cs @@ -1,890 +1,115 @@ -#!/bin/bash +#!/usr/bin/env bash -# CheatSheets (cs) - Interactive CLI for managing your personal knowledge base -# Version: 1.0.0 -# Focus: Adding commands in < 10 seconds +# CheatSheets (cs) - Simple command lookup tool -set -euo pipefail - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -MAGENTA='\033[0;35m' -CYAN='\033[0;36m' -NC='\033[0m' # No Color -BOLD='\033[1m' +set -e # Script directory -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)" CS_ROOT="${CS_ROOT:-$SCRIPT_DIR}" -CONFIG_FILE="${CS_ROOT}/.cs.config" PERSONAL_DIR="${CS_ROOT}/personal" -INDEX_FILE="${CS_ROOT}/.cs_index" -CACHE_DIR="${CS_ROOT}/.cs_cache" - -# Default configuration -DEFAULT_EDITOR="${EDITOR:-nano}" -DEFAULT_CATEGORY="personal" -QUICK_ADD_FILE="${PERSONAL_DIR}/quick.md" -AUTO_SYNC=${CS_AUTO_SYNC:-false} -CAPTURE_THRESHOLD=${CS_CAPTURE_THRESHOLD:-3} - -# Load configuration if exists -if [[ -f "$CONFIG_FILE" ]]; then - source "$CONFIG_FILE" -fi - -# Ensure directories exist -mkdir -p "$PERSONAL_DIR" "$CACHE_DIR" - -#============================================================================== -# UTILITY FUNCTIONS -#============================================================================== - -print_success() { - echo -e "${GREEN}✓${NC} $*" -} - -print_error() { - echo -e "${RED}✗${NC} $*" >&2 -} - -print_info() { - echo -e "${BLUE}ℹ${NC} $*" -} - -print_warning() { - echo -e "${YELLOW}⚠${NC} $*" -} - -print_header() { - echo -e "${BOLD}${CYAN}$*${NC}" -} - -# Check if command exists -has_command() { - command -v "$1" >/dev/null 2>&1 -} - -# Get timestamp -timestamp() { - date +"%Y-%m-%d %H:%M:%S" -} - -#============================================================================== -# CORE FUNCTIONS -#============================================================================== - -# Initialize index -init_index() { - print_info "Building search index..." - - # Create empty index - : > "$INDEX_FILE" - - # Create a simple indexer script to avoid escaping issues - local indexer="${CACHE_DIR}/indexer.sh" - mkdir -p "$CACHE_DIR" - - cat > "$indexer" <<'INDEXER_EOF' -#!/bin/sh -mdfile="$1" -index="$2" -root="$3" -relpath="${mdfile#$root/}" - -# Extract table rows with backticks - use awk for single pass -awk -F'|' -v file="$relpath" ' -/\|.*`.*\|/ { - cmd = $2 - desc = $3 - gsub(/`/, "", cmd) - gsub(/^[[:space:]]+|[[:space:]]+$/, "", cmd) - gsub(/^[[:space:]]+|[[:space:]]+$/, "", desc) - if (cmd != "" && cmd != "COMMAND" && cmd != "---") { - print cmd "|" desc "|" file - } -} -' "$mdfile" >> "$index" 2>/dev/null - -# Extract code blocks -awk -v file="$relpath" ' -/```bash/,/```/ { - if (!/```/ && !/^#/ && NF>0) { - print $0 "||" file - } -} -' "$mdfile" >> "$index" 2>/dev/null -INDEXER_EOF - - chmod +x "$indexer" - - # Process each markdown file - find "$CS_ROOT" -name "*.md" -type f \ - ! -path "*/.git/*" \ - ! -path "*/node_modules/*" \ - ! -path "*/personal/*" \ - 2>/dev/null \ - -exec "$indexer" {} "$INDEX_FILE" "$CS_ROOT" \; - - # Cleanup - rm -f "$indexer" - - local count=$(wc -l < "$INDEX_FILE" 2>/dev/null || echo "0") - print_success "Index built with $count entries" - return 0 -} - -# Search commands -search_commands() { - local query="$1" - local category="${2:-}" - local use_fzf="${3:-true}" - - # Ensure index exists - [[ ! -f "$INDEX_FILE" ]] && init_index - - local results - if [[ -n "$category" ]]; then - results=$(grep -i "$query" "$INDEX_FILE" | grep "$category") - else - results=$(grep -i "$query" "$INDEX_FILE") - fi +QUICK_FILE="${PERSONAL_DIR}/quick.md" - if [[ -z "$results" ]]; then - print_warning "No results found for: $query" - return 1 - fi +mkdir -p "$PERSONAL_DIR" - # Use fzf for interactive selection if available - if $use_fzf && has_command fzf; then - echo "$results" | fzf --delimiter='|' \ - --preview 'cat {3}' \ - --preview-window=right:60%:wrap \ - --header="Search: $query" \ - --bind 'enter:execute(bat {3} 2>/dev/null || cat {3})+abort' \ - --with-nth=1,2 - else - echo "$results" | while IFS='|' read -r cmd desc file; do - echo -e "${GREEN}${cmd}${NC}" - [[ -n "$desc" ]] && echo -e " ${CYAN}→${NC} ${desc}" - echo -e " ${YELLOW}📁${NC} ${file}" - echo - done - fi -} +# Colors +G='\033[0;32m' +B='\033[0;34m' +NC='\033[0m' -# Quick add - fastest way to add a command +# Quick add quick_add() { - local cmd="$1" - local timestamp=$(date +"%Y-%m-%d %H:%M") - - # Ensure personal directory and quick file exist - mkdir -p "$PERSONAL_DIR" + [ -z "$*" ] && echo "Usage: cs quick " && exit 1 - if [[ ! -f "$QUICK_ADD_FILE" ]]; then - cat > "$QUICK_ADD_FILE" < "$QUICK_FILE" fi - # Add command to quick file - cat >> "$QUICK_ADD_FILE" </dev/null 2>&1 || true - - # Auto-sync if enabled - [[ "$AUTO_SYNC" == "true" ]] && git_sync || true - - return 0 + printf "\n\`\`\`bash\n%s\n\`\`\`\n" "$*" >> "$QUICK_FILE" + printf "${G}✓${NC} Saved to %s\n" "$QUICK_FILE" } -# Standard add with metadata -standard_add() { - local cmd="$1" - local desc="${2:-}" - local tags="${3:-}" - local category="${4:-$DEFAULT_CATEGORY}" - local example="${5:-}" - - # Determine file based on category - local file - if [[ "$category" == "personal" ]]; then - file="${PERSONAL_DIR}/commands.md" - mkdir -p "$PERSONAL_DIR" - else - # Parse category (e.g., "tools/docker" or "docker") - if [[ "$category" == */* ]]; then - local dir="${category%/*}" - local name="${category##*/}" - file="${CS_ROOT}/${dir}/${name}.md" - else - # Try to find existing file - local found=$(find "$CS_ROOT" -name "${category}.md" -type f ! -path "*/personal/*" | head -1) - if [[ -n "$found" ]]; then - file="$found" - else - file="${CS_ROOT}/tools/${category}.md" - fi +# Search +search_commands() { + [ -z "$*" ] && echo "Usage: cs search " && exit 1 + + printf "${B}Searching for: %s${NC}\n\n" "$*" + find "$CS_ROOT" -name "*.md" -type f ! -path "*/.git/*" 2>/dev/null | while read -r file; do + if grep -i -q "$*" "$file" 2>/dev/null; then + printf "${G}%s${NC}\n" "${file#$CS_ROOT/}" + grep -i -C 1 "$*" "$file" 2>/dev/null | head -5 + echo "" fi - fi - - # Create file if doesn't exist - if [[ ! -f "$file" ]]; then - local title=$(basename "$file" .md) - title="$(echo "$title" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1')" - cat > "$file" <> "$file" - - # Add example if provided - if [[ -n "$example" ]]; then - cat >> "$file" </dev/null 2>&1 || true - - # Auto-sync if enabled - [[ "$AUTO_SYNC" == "true" ]] && git_sync || true - - return 0 -} - -# Interactive add -interactive_add() { - echo -e "${BOLD}=== Interactive Command Add ===${NC}\n" - - # Get command - read -p "Command: " cmd - [[ -z "$cmd" ]] && print_error "Command cannot be empty" && return 1 - - # Get description - read -p "Description (optional): " desc - - # Get tags - read -p "Tags (comma-separated, optional): " tags - - # Detect category from command - local detected_category="" - case "$cmd" in - docker*) detected_category="tools/docker" ;; - kubectl*|k8s*) detected_category="tools/kubectl" ;; - git*) detected_category="tools/git" ;; - terraform*) detected_category="tools/terraform" ;; - helm*) detected_category="tools/helm" ;; - mysql*) detected_category="infra/mysql" ;; - psql*|postgres*) detected_category="infra/postgresql" ;; - *) detected_category="personal" ;; - esac - - read -p "Category [$detected_category]: " category - category="${category:-$detected_category}" - - # Get example - read -p "Example (optional, press Enter to skip): " example - - # Confirm - echo -e "\n${BOLD}Preview:${NC}" - echo -e "Command: ${GREEN}$cmd${NC}" - [[ -n "$desc" ]] && echo -e "Description: $desc" - [[ -n "$tags" ]] && echo -e "Tags: $tags" - echo -e "Category: $category" - [[ -n "$example" ]] && echo -e "Example: $example" - - read -p $'\n'"Add this command? [Y/n]: " confirm - confirm="${confirm:-Y}" - - if [[ "$confirm" =~ ^[Yy]$ ]]; then - standard_add "$cmd" "$desc" "$tags" "$category" "$example" - else - print_info "Cancelled" - fi + done } -# Capture from history -capture_from_history() { - local limit="${1:-10}" - local auto_mode="${2:-false}" - - if ! has_command fzf; then - print_error "fzf is required for history capture. Install it first." - return 1 - fi - - # Get history file - local hist_file="${HISTFILE:-$HOME/.bash_history}" - if [[ -f "$HOME/.zsh_history" ]]; then - hist_file="$HOME/.zsh_history" - fi - - if [[ ! -f "$hist_file" ]]; then - print_error "History file not found" - return 1 - fi - - if $auto_mode; then - print_info "Auto-capture mode: finding frequently used commands..." - # Find commands used more than threshold times - tail -1000 "$hist_file" | sed 's/^: [0-9]*:[0-9]*;//' | \ - sort | uniq -c | sort -rn | head -20 | \ - awk -v thresh="$CAPTURE_THRESHOLD" '$1 >= thresh {$1=""; print substr($0,2)}' - else - # Interactive selection - local selected - selected=$(tail -500 "$hist_file" | sed 's/^: [0-9]*:[0-9]*;//' | \ - grep -v '^cs ' | \ - awk '!seen[$0]++' | \ - tail -"$limit" | \ - fzf --multi --reverse --header="Select commands to save (TAB for multi-select)") - - if [[ -n "$selected" ]]; then - while IFS= read -r cmd; do - echo -e "\n${BOLD}Capture:${NC} ${GREEN}$cmd${NC}" - read -p "Add this command? [Y/n/q]: " confirm - confirm="${confirm:-Y}" - - case "$confirm" in - [Qq]*) break ;; - [Yy]*) - read -p "Description (optional): " desc - read -p "Tags (optional): " tags - standard_add "$cmd" "$desc" "$tags" "personal" - ;; - *) continue ;; - esac - done <<< "$selected" - fi - fi +# List +list_all() { + printf "${B}Available cheatsheets:${NC}\n\n" + for dir in linux tools infra misc windows personal; do + [ ! -d "$CS_ROOT/$dir" ] && continue + printf "${G}%s/${NC}\n" "$dir" + find "$CS_ROOT/$dir" -name "*.md" -type f 2>/dev/null | while read -r f; do + printf " - %s\n" "$(basename "$f" .md)" + done + echo "" + done } -# Create new section -create_section() { - local name="$1" - local template="${2:-default}" - - # Determine directory and filename - local file - if [[ "$name" == */* ]]; then - local dir="${name%/*}" - local section="${name##*/}" - mkdir -p "${CS_ROOT}/${dir}" - file="${CS_ROOT}/${dir}/${section}.md" - else - # Default to tools - file="${CS_ROOT}/tools/${name}.md" - fi - - if [[ -f "$file" ]]; then - print_warning "File already exists: $file" - return 1 - fi - - # Create from template - local title=$(basename "$file" .md) - title="$(echo "$title" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1')" - - case "$template" in - tool|default) - cat > "$file" < "$file" <\` | Show detailed information | - -## Create/Update - -| COMMAND | DESCRIPTION | -| --- | --- | -| \`kubectl apply -f \` | Create/update from file | -| \`kubectl create $name \` | Create new resource | - -## Delete - -| COMMAND | DESCRIPTION | -| --- | --- | -| \`kubectl delete $name \` | Delete resource | - -## Debugging - -| COMMAND | DESCRIPTION | -| --- | --- | -| \`kubectl logs $name/\` | View logs | -| \`kubectl exec -it $name/ -- /bin/bash\` | Access shell | -EOF - ;; - simple) - cat > "$file" </dev/null 2>&1 || true - - return 0 -} + done -# Git sync -git_sync() { - if ! git -C "$CS_ROOT" rev-parse --git-dir > /dev/null 2>&1; then - print_warning "Not a git repository" - return 1 + if [ -z "$file" ]; then + echo "Not found: $1" + echo "Try: cs list" + exit 1 fi - print_info "Syncing with git..." - - # Pull latest - git -C "$CS_ROOT" pull --quiet 2>/dev/null || true - - # Check if there are changes - if git -C "$CS_ROOT" diff-index --quiet HEAD --; then - print_info "No changes to commit" + if command -v less >/dev/null 2>&1; then + less "$file" else - # Add all changes - git -C "$CS_ROOT" add . - - # Commit - local msg="chore: auto-update cheatsheets [$(date +%Y-%m-%d)]" - git -C "$CS_ROOT" commit -m "$msg" --quiet - - print_success "Changes committed" + cat "$file" fi } -# Show statistics -show_stats() { - local total_files=$(find "$CS_ROOT" -name "*.md" -type f ! -path "*/.git/*" | wc -l) - local total_commands=$(grep -c '|' "$INDEX_FILE" 2>/dev/null || echo "0") - local categories=$(find "$CS_ROOT" -mindepth 1 -maxdepth 1 -type d ! -name ".*" ! -name "personal" | wc -l) - local personal_commands=$(find "$PERSONAL_DIR" -name "*.md" -type f 2>/dev/null | xargs cat 2>/dev/null | grep -c '```bash' || echo "0") - - print_header "📊 CheatSheets Statistics" - echo - echo -e "${BOLD}Repository:${NC}" - echo -e " Files: $total_files" - echo -e " Categories: $categories" - echo -e " Total commands: $total_commands" - echo - echo -e "${BOLD}Personal:${NC}" - echo -e " Commands: $personal_commands" - echo - - # Most recent additions - if [[ -f "$QUICK_ADD_FILE" ]]; then - local recent=$(tail -5 "$QUICK_ADD_FILE" | grep '^## Added:' | wc -l) - echo -e "${BOLD}Recent Activity:${NC}" - echo -e " Quick captures today: $recent" - fi - - return 0 -} - -# List all categories -list_categories() { - print_header "📂 Available Categories" - echo - - for dir in "$CS_ROOT"/{linux,tools,infra,misc,windows,personal}; do - if [[ -d "$dir" ]]; then - local category=$(basename "$dir") - local count=$(find "$dir" -name "*.md" -type f | wc -l) - echo -e "${CYAN}$category${NC} ($count files)" - find "$dir" -name "*.md" -type f | while read -r file; do - local name=$(basename "$file" .md) - echo -e " • $name" - done || true - echo - fi - done - - return 0 -} - -# Browse with fzf -browse() { - if ! has_command fzf; then - print_error "fzf is required for browsing. Install it first." - return 1 - fi - - # Ensure index exists - [[ ! -f "$INDEX_FILE" ]] && init_index - - # Interactive browser (don't fail if user cancels) - cat "$INDEX_FILE" | fzf --delimiter='|' \ - --preview 'bat --color=always --style=numbers {3} 2>/dev/null || cat {3}' \ - --preview-window=right:60%:wrap \ - --header="Browse all commands (Ctrl-C to exit)" \ - --with-nth=1,2 \ - --bind 'enter:execute(less {3})+abort' || true - - return 0 -} - -# Show help +# Help show_help() { - cat < Create new section - -${BOLD}SEARCH & BROWSE:${NC} - cs search Search all commands - cs search -c Search in specific category - cs browse, cs -i Interactive browser (requires fzf) - cs list List all categories - -${BOLD}CONTENT MANAGEMENT:${NC} - cs add "command" [OPTIONS] Add command with metadata - --desc "description" Add description - --tags "tag1,tag2" Add tags - --cat "category" Specify category - --example "example" Add example - cs new section Create new section - --template Use template (tool, k8s, simple) - cs capture Capture from history - --last N Show last N commands - --auto Auto-capture frequent commands - -${BOLD}MAINTENANCE:${NC} - cs index Rebuild search index - cs sync Git sync (pull, commit, push) - cs stats Show statistics - cs validate Validate all commands - cs backup Backup personal additions - -${BOLD}EXAMPLES:${NC} - # Quick capture - cs quick "docker system prune -a" - - # Add with metadata - cs add "kubectl get pods -A" --desc "List all pods" --tags k8s,debug - - # Interactive add - cs add -i - - # Search + cat <<'EOF' +cs - Simple CheatSheets + +USAGE: + cs quick Save a command + cs search Search cheatsheets + cs list List all files + cs View cheatsheet (e.g., cs docker) + cs help Show this help + +EXAMPLES: + cs quick "docker ps -a" + cs search kubernetes cs docker - cs "list pods" + cs list - # Browse interactively - cs -i - - # Create new section - cs new consul --template tool - cs new monitoring/prometheus - -${BOLD}CONFIGURATION:${NC} - Config file: ${CONFIG_FILE} - Personal dir: ${PERSONAL_DIR} - Index file: ${INDEX_FILE} - -${BOLD}ENVIRONMENT VARIABLES:${NC} - CS_ROOT CheatSheets root directory - CS_AUTO_SYNC Auto-sync with git (true/false) - CS_CAPTURE_THRESHOLD Threshold for auto-capture - -For more info: https://github.com/mlorentedev/cheat-sheets EOF } -#============================================================================== -# MAIN COMMAND DISPATCHER -#============================================================================== - -main() { - # No arguments - show help - if [[ $# -eq 0 ]]; then - show_help - exit 0 - fi - - local cmd="$1" - shift - - case "$cmd" in - # Quick add - quick|q) - [[ $# -eq 0 ]] && print_error "Usage: cs quick " && exit 1 - quick_add "$*" - ;; - - # Standard add - add|a) - if [[ "$1" == "-i" ]] || [[ "$1" == "--interactive" ]]; then - interactive_add - else - local command="" - local desc="" - local tags="" - local category="$DEFAULT_CATEGORY" - local example="" - - # Parse arguments - while [[ $# -gt 0 ]]; do - case "$1" in - --desc|--description|-d) - desc="$2" - shift 2 - ;; - --tags|--tag|-t) - tags="$2" - shift 2 - ;; - --cat|--category|-c) - category="$2" - shift 2 - ;; - --example|-e) - example="$2" - shift 2 - ;; - *) - command="$1" - shift - ;; - esac - done - - [[ -z "$command" ]] && print_error "Usage: cs add [--desc DESC] [--tags TAGS]" && exit 1 - standard_add "$command" "$desc" "$tags" "$category" "$example" - fi - ;; - - # Search - search|s|find|f) - [[ $# -eq 0 ]] && print_error "Usage: cs search " && exit 1 - local query="$1" - local category="" - shift - - # Parse options - while [[ $# -gt 0 ]]; do - case "$1" in - -c|--category|--cat) - category="$2" - shift 2 - ;; - *) - shift - ;; - esac - done - - search_commands "$query" "$category" - ;; - - # Browse - browse|b|-i|--interactive) - browse - ;; - - # Capture - capture|cap) - local limit=10 - local auto=false - - while [[ $# -gt 0 ]]; do - case "$1" in - --last|-n) - limit="$2" - shift 2 - ;; - --auto|-a) - auto=true - shift - ;; - *) - shift - ;; - esac - done - - capture_from_history "$limit" "$auto" - ;; - - # New section - new|n|create) - [[ $# -eq 0 ]] && print_error "Usage: cs new " && exit 1 - local type="$1" - shift - - case "$type" in - section|s|tool|t) - local name="$1" - local template="tool" - shift - - while [[ $# -gt 0 ]]; do - case "$1" in - --template|-t) - template="$2" - shift 2 - ;; - *) - shift - ;; - esac - done - - create_section "$name" "$template" - ;; - category|cat) - local name="$1" - mkdir -p "${CS_ROOT}/${name}" - print_success "Created category: ${CS_ROOT}/${name}" - ;; - *) - # Assume it's a name without type - create_section "$type" "tool" - ;; - esac - ;; - - # Index - index|idx|rebuild) - init_index - ;; - - # Sync - sync) - git_sync - ;; - - # Stats - stats|statistics|info) - show_stats - ;; - - # List - list|ls|categories) - list_categories - ;; - - # Help - help|h|-h|--help) - show_help - ;; - - # Version - version|v|-v|--version) - echo "cs version 1.0.0" - ;; - - # Default: treat as search query - *) - search_commands "$cmd $*" - ;; - esac -} +# Main +if [ $# -eq 0 ]; then + show_help + exit 0 +fi -# Run main -main "$@" +case "$1" in + quick|q) shift; quick_add "$@" ;; + search|s) shift; search_commands "$@" ;; + list|ls) list_all ;; + help|h|-h|--help) show_help ;; + *) view_file "$1" ;; +esac diff --git a/install.sh b/install.sh index 80f5061..684e69f 100755 --- a/install.sh +++ b/install.sh @@ -1,202 +1,53 @@ #!/bin/bash -# CheatSheets Installation Script -# Simple, clear installer with no magic - -set -e - -# Colors -GREEN='\033[0;32m' -BLUE='\033[0;34m' -YELLOW='\033[1;33m' -RED='\033[0;31m' -NC='\033[0m' - -print_step() { - echo -e "${BLUE}==>${NC} $*" -} - -print_success() { - echo -e "${GREEN}✓${NC} $*" -} - -print_warning() { - echo -e "${YELLOW}!${NC} $*" -} - -print_error() { - echo -e "${RED}✗${NC} $*" >&2 -} - -# Detect shell -detect_shell() { - if [ -n "$ZSH_VERSION" ]; then - echo "zsh" - elif [ -n "$BASH_VERSION" ]; then - echo "bash" - else - echo "unknown" - fi -} - -# Get shell RC file -get_shell_rc() { - local shell_type=$(detect_shell) - case "$shell_type" in - zsh) - echo "$HOME/.zshrc" - ;; - bash) - if [ -f "$HOME/.bashrc" ]; then - echo "$HOME/.bashrc" - else - echo "$HOME/.bash_profile" - fi - ;; - *) - echo "" - ;; - esac -} +# Simple CheatSheets installer -echo "" -echo "CheatSheets Installation" -echo "========================" +echo "Installing CheatSheets..." echo "" -# Get installation directory SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CS_ROOT="${CS_ROOT:-$SCRIPT_DIR}" - -print_step "Installation directory: $CS_ROOT" # Make cs executable -print_step "Making cs executable..." -chmod +x "$CS_ROOT/cs" -print_success "Done" +chmod +x "$SCRIPT_DIR/cs" +echo "✓ Made cs executable" -# Create necessary directories -print_step "Creating directories..." -mkdir -p "$CS_ROOT/personal" -mkdir -p "$CS_ROOT/templates" -print_success "Created personal/ and templates/ directories" +# Create personal directory +mkdir -p "$SCRIPT_DIR/personal" +echo "✓ Created personal directory" -# Check if already in PATH -if echo "$PATH" | grep -q "$CS_ROOT"; then - print_success "Already in PATH" +# Detect shell +if [ -n "$ZSH_VERSION" ]; then + SHELL_RC="$HOME/.zshrc" +elif [ -n "$BASH_VERSION" ]; then + SHELL_RC="$HOME/.bashrc" else - # Add to PATH - SHELL_RC=$(get_shell_rc) - - if [ -n "$SHELL_RC" ]; then - print_step "Adding to PATH in $SHELL_RC..." - - # Check if already added - if grep -q "cheat-sheets" "$SHELL_RC" 2>/dev/null; then - print_warning "PATH entry already exists in $SHELL_RC" - else - cat >> "$SHELL_RC" </dev/null; then + echo "" >> "$SHELL_RC" + echo "# CheatSheets" >> "$SHELL_RC" + echo "export PATH=\"\$PATH:$SCRIPT_DIR\"" >> "$SHELL_RC" + echo "✓ Added to $SHELL_RC" echo "" - echo " export PATH=\"\$PATH:$CS_ROOT\"" - echo " export CS_ROOT=\"$CS_ROOT\"" + echo "Run: source $SHELL_RC" + else + echo "✓ Already in PATH" fi -fi - -# Check for dependencies -echo "" -print_step "Checking dependencies..." - -# Check for fzf -if command -v fzf >/dev/null 2>&1; then - print_success "fzf is installed (for interactive browsing)" -else - print_warning "fzf not found (optional, but recommended)" - echo "" - echo "Install fzf for better browsing experience:" - echo " Ubuntu/Debian: sudo apt install fzf" - echo " macOS: brew install fzf" - echo " Manual: git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && ~/.fzf/install" -fi - -# Check for bat (optional) -if command -v bat >/dev/null 2>&1; then - print_success "bat is installed (for syntax highlighting)" else - print_warning "bat not found (optional, for better previews)" + echo "⚠ Could not detect shell" + echo " Add to your PATH manually:" + echo " export PATH=\"\$PATH:$SCRIPT_DIR\"" fi -# Build initial index echo "" -print_step "Building search index..." -"$CS_ROOT/cs" index -print_success "Index created" - -# Create example config -if [ ! -f "$CS_ROOT/.cs.config" ]; then - print_step "Creating example configuration..." - cat > "$CS_ROOT/.cs.config.example" </dev/null || true - rm -f .cs_index 2>/dev/null || true - rm -rf .cs_cache/ 2>/dev/null || true rm -f tools/test-tool.md 2>/dev/null || true - git checkout tools/docker.md 2>/dev/null || true - git checkout tools/terraform.md 2>/dev/null || true } -# Trap exit to cleanup (but don't fail on cleanup errors) trap 'cleanup || true' EXIT -echo "" echo "=========================================" echo "CheatSheets Test Suite" echo "=========================================" echo "" -# Test 1: Shell script syntax -print_test "Validating shell script syntax..." -if bash -n cs && bash -n install.sh; then - print_pass "Shell scripts have valid syntax" -else - print_fail "Shell script syntax validation failed" -fi - -# Test 2: cs executable -print_test "Checking cs is executable..." +# Test 1: cs is executable if [ -x cs ]; then print_pass "cs is executable" else print_fail "cs is not executable" - chmod +x cs -fi - -# Test 3: install.sh executable -print_test "Checking install.sh is executable..." -if [ -x install.sh ]; then - print_pass "install.sh is executable" -else - print_fail "install.sh is not executable" - chmod +x install.sh fi -# Test 4: cs help -print_test "Testing cs help command..." -if ./cs help > /dev/null 2>&1; then +# Test 2: cs help works +if ./cs help >/dev/null 2>&1; then print_pass "cs help works" else print_fail "cs help failed" fi -# Test 5: cs index -print_test "Testing cs index command..." -if ./cs index > /dev/null 2>&1; then - if [ -f .cs_index ]; then - print_pass "cs index created index file" - else - print_fail "cs index did not create index file" - fi -else - print_fail "cs index failed" -fi - -# Test 6: cs quick -print_test "Testing cs quick command..." -if ./cs quick "test command for suite" > /dev/null 2>&1; then - if [ -f personal/quick.md ] && grep -q "test command for suite" personal/quick.md; then +# Test 3: cs quick works +if ./cs quick "test command" >/dev/null 2>&1; then + if [ -f personal/quick.md ] && grep -q "test command" personal/quick.md; then print_pass "cs quick works" else - print_fail "cs quick did not add command" + print_fail "cs quick did not save command" fi else print_fail "cs quick failed" fi -# Test 7: cs add -print_test "Testing cs add command..." -if ./cs add "docker ps -a" --desc "List all containers" --tags docker --cat tools/docker > /dev/null 2>&1; then - if grep -q "docker ps -a" tools/docker.md; then - print_pass "cs add works" - else - print_fail "cs add did not add command" - fi -else - print_fail "cs add failed" -fi - -# Test 8: cs search -print_test "Testing cs search command..." -if ./cs search docker > /dev/null 2>&1; then +# Test 4: cs search works +if ./cs search docker >/dev/null 2>&1; then print_pass "cs search works" else print_fail "cs search failed" fi -# Test 9: cs list -print_test "Testing cs list command..." -if ./cs list > /dev/null 2>&1; then +# Test 5: cs list works +if ./cs list >/dev/null 2>&1; then print_pass "cs list works" else print_fail "cs list failed" fi -# Test 10: cs stats -print_test "Testing cs stats command..." -if ./cs stats > /dev/null 2>&1; then - print_pass "cs stats works" +# Test 6: install.sh is executable +if [ -x install.sh ]; then + print_pass "install.sh is executable" else - print_fail "cs stats failed" + print_fail "install.sh is not executable" fi -# Test 11: cs new -print_test "Testing cs new command..." -if echo "" | ./cs new test-tool --template tool > /dev/null 2>&1; then - if [ -f tools/test-tool.md ]; then - print_pass "cs new works" - else - print_fail "cs new did not create file" - fi +# Test 7: README exists +if [ -f README.md ] && [ -s README.md ]; then + print_pass "README.md exists" else - print_fail "cs new failed" + print_fail "README.md missing" fi -# Test 12: Templates exist -print_test "Checking templates exist..." -all_templates_exist=true -for template in tool k8s simple; do - if [ ! -f "templates/${template}.md" ]; then - all_templates_exist=false - break - fi -done - -if $all_templates_exist; then - print_pass "All templates exist" +# Test 8: .gitignore has personal/ +if grep -q "personal/" .gitignore; then + print_pass ".gitignore has personal/" else - print_fail "Some templates missing" + print_fail ".gitignore missing personal/" fi -# Test 13: Required directories -print_test "Checking required directories..." +# Test 9: Required directories exist all_dirs_exist=true -for dir in linux tools infra misc templates; do +for dir in linux tools infra misc; do if [ ! -d "$dir" ]; then all_dirs_exist=false break @@ -192,47 +106,14 @@ for dir in linux tools infra misc templates; do done if $all_dirs_exist; then - print_pass "All required directories exist" + print_pass "Required directories exist" else print_fail "Some directories missing" fi -# Test 14: Configuration example -print_test "Checking configuration example..." -if [ -f .cs.config.example ] && bash -n .cs.config.example 2>/dev/null; then - print_pass "Configuration example is valid" -else - print_fail "Configuration example invalid or missing" -fi - -# Test 15: .gitignore -print_test "Checking .gitignore..." -all_patterns_exist=true -for pattern in "personal/" ".cs.config" ".cs_index"; do - if ! grep -q "$pattern" .gitignore; then - all_patterns_exist=false - break - fi -done - -if $all_patterns_exist; then - print_pass ".gitignore has required patterns" -else - print_fail ".gitignore missing patterns" -fi - -# Test 16: README exists and has content -print_test "Checking README.md..." -if [ -f README.md ] && [ -s README.md ] && grep -q "CheatSheets" README.md; then - print_pass "README.md exists and has content" -else - print_fail "README.md missing or empty" -fi - -# Test 17: Markdown files are not empty -print_test "Checking markdown files are not empty..." +# Test 10: Markdown files are not empty empty_files=0 -find . -name "*.md" -type f ! -path "*/.*" ! -path "*/personal/*" | while read -r file; do +find . -name "*.md" -type f ! -path "*/.*" ! -path "*/personal/*" 2>/dev/null | while read -r file; do if [ ! -s "$file" ]; then ((empty_files++)) fi @@ -241,7 +122,7 @@ done if [ $empty_files -eq 0 ]; then print_pass "No empty markdown files" else - print_fail "Found $empty_files empty markdown files" + print_fail "Found empty markdown files" fi # Summary From 10b3d0fdfa1f9387a78cb4ebf75a9c287fc29a3b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Nov 2025 03:43:01 +0000 Subject: [PATCH 2/2] ci: Simplify CI workflow to match simplified CLI tool --- .github/workflows/ci.yml | 116 ++------------------------------------- 1 file changed, 6 insertions(+), 110 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a9f65c..3fe8a95 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,16 +18,10 @@ jobs: - name: Set up environment run: | echo "CS_ROOT=$GITHUB_WORKSPACE" >> $GITHUB_ENV - chmod +x cs install.sh + chmod +x cs install.sh test.sh - - name: Install dependencies + - name: Install shellcheck run: | - # Install fzf for interactive features - git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf - ~/.fzf/install --all --no-update-rc --no-bash --no-zsh - export PATH="$HOME/.fzf/bin:$PATH" - - # Install shellcheck for shell script validation sudo apt-get update sudo apt-get install -y shellcheck @@ -52,19 +46,6 @@ jobs: ./cs help echo "✓ Help command works" - - name: Test cs index command - run: | - echo "Testing cs index..." - ./cs index - echo "✓ Index built successfully" - - # Verify index was created - if [ ! -f .cs_index ]; then - echo "✗ Index file not created" - exit 1 - fi - echo "✓ Index file created" - - name: Test cs quick command run: | echo "Testing cs quick..." @@ -90,19 +71,6 @@ jobs: echo "✓ Quick add works" - - name: Test cs add command - run: | - echo "Testing cs add with metadata..." - ./cs add "docker ps -a" --desc "List all containers" --tags docker,containers --cat tools/docker - - # Verify command was added to docker.md - if ! grep -q "docker ps -a" tools/docker.md; then - echo "✗ Command not added to docker.md" - exit 1 - fi - - echo "✓ Standard add works" - - name: Test cs search command run: | echo "Testing cs search..." @@ -115,39 +83,6 @@ jobs: ./cs list echo "✓ List command works" - - name: Test cs stats command - run: | - echo "Testing cs stats..." - ./cs stats - echo "✓ Stats command works" - - - name: Test cs new command - run: | - echo "Testing cs new with tool template..." - ./cs new test-tool --template tool < /dev/null || true - - # Verify file was created - if [ ! -f tools/test-tool.md ]; then - echo "✗ New section not created" - exit 1 - fi - - echo "✓ New section creation works" - - - name: Test template files - run: | - echo "Validating templates..." - - # Check templates exist - for template in tool k8s simple; do - if [ ! -f "templates/${template}.md" ]; then - echo "✗ Template ${template}.md not found" - exit 1 - fi - done - - echo "✓ All templates present" - - name: Validate markdown files run: | echo "Checking markdown files..." @@ -167,43 +102,10 @@ jobs: echo "✓ Markdown files validated" - - name: Test search index content + - name: Run test suite run: | - echo "Validating search index..." - - # Rebuild index - ./cs index - - # Check index has content - if [ ! -s .cs_index ]; then - echo "✗ Index is empty" - exit 1 - fi - - line_count=$(wc -l < .cs_index) - echo "Index contains $line_count entries" - - if [ "$line_count" -lt 10 ]; then - echo "✗ Index has too few entries" - exit 1 - fi - - echo "✓ Search index validated" - - - name: Test configuration file - run: | - echo "Testing configuration..." - - # Check example config exists - if [ ! -f .cs.config.example ]; then - echo "✗ Example config not found" - exit 1 - fi - - # Verify it's valid bash - bash -n .cs.config.example - - echo "✓ Configuration file validated" + echo "Running full test suite..." + ./test.sh - name: Summary run: | @@ -216,15 +118,9 @@ jobs: echo " ✓ Installation script" echo " ✓ Shell script syntax" echo " ✓ cs help" - echo " ✓ cs index" echo " ✓ cs quick" - echo " ✓ cs add" echo " ✓ cs search" echo " ✓ cs list" - echo " ✓ cs stats" - echo " ✓ cs new" - echo " ✓ Templates" echo " ✓ Markdown files" - echo " ✓ Search index" - echo " ✓ Configuration" + echo " ✓ Full test suite (10 tests)" echo ""