Merge pull request #35 from outis1one/claude/read-repo-wA3y1
Claude/read repo w a3y1
This commit is contained in:
Executable
+440
@@ -0,0 +1,440 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# bump-version.sh — Universal version bump tool
|
||||
#
|
||||
# Finds version strings in any project, shows what will change,
|
||||
# asks for confirmation, and updates them. Supports undo.
|
||||
#
|
||||
# Supported patterns:
|
||||
# JSON: "version": "1.2.3"
|
||||
# TOML: version = "1.2.3"
|
||||
# YAML: version: 1.2.3
|
||||
# Python: __version__ = "1.2.3" or version = "1.2.3"
|
||||
# PHP: Version: 1.2.3 (WordPress plugin/theme headers)
|
||||
# Shell: VERSION="1.2.3"
|
||||
# HTML/JS: v1.2.3
|
||||
# setup.cfg: version = 1.2.3
|
||||
#
|
||||
# Usage:
|
||||
# ./bump-version.sh # interactive
|
||||
# ./bump-version.sh patch # bump patch: 0.9.0 → 0.9.1
|
||||
# ./bump-version.sh minor # bump minor: 0.9.0 → 0.10.0
|
||||
# ./bump-version.sh major # bump major: 0.9.0 → 1.0.0
|
||||
# ./bump-version.sh 1.2.3 # set all to 1.2.3
|
||||
# ./bump-version.sh undo # revert last bump
|
||||
# ./bump-version.sh --help # show help
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
UNDO_FILE="$SCRIPT_DIR/.version-bump-undo"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
RED='\033[0;31m'
|
||||
DIM='\033[2m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Directories to skip
|
||||
SKIP_DIRS="node_modules|dist|build|\.git|__pycache__|\.venv|venv|\.egg-info|vendor"
|
||||
|
||||
# --- Help ---
|
||||
show_help() {
|
||||
cat << 'HELPEOF'
|
||||
bump-version.sh — Universal version bump tool
|
||||
|
||||
USAGE:
|
||||
./bump-version.sh Interactive mode
|
||||
./bump-version.sh patch Bump patch: 0.9.0 → 0.9.1
|
||||
./bump-version.sh minor Bump minor: 0.9.0 → 0.10.0
|
||||
./bump-version.sh major Bump major: 0.9.0 → 1.0.0
|
||||
./bump-version.sh 1.2.3 Set to exact version
|
||||
./bump-version.sh undo Revert last version bump
|
||||
./bump-version.sh --help Show this help
|
||||
|
||||
HOW IT WORKS:
|
||||
1. Scans all text files for version-like patterns
|
||||
2. Groups files by version number (the "version profile")
|
||||
3. Only updates files matching the most common version
|
||||
4. Shows a preview of all changes before applying
|
||||
5. Asks for confirmation (unless --yes flag is used)
|
||||
6. Saves undo information for easy rollback
|
||||
|
||||
SUPPORTED PATTERNS:
|
||||
"version": "1.2.3" JSON (package.json, manifest.json, etc.)
|
||||
version = "1.2.3" TOML, Python (pyproject.toml, setup.py)
|
||||
version: 1.2.3 YAML (helm charts, GitHub Actions)
|
||||
__version__ = "1.2.3" Python packages
|
||||
Version: 1.2.3 PHP/WordPress plugin/theme headers
|
||||
VERSION="1.2.3" Shell scripts
|
||||
v1.2.3 HTML footers, display strings
|
||||
|
||||
SAFETY:
|
||||
- Only updates files matching the current version (ignores unrelated X.Y.Z)
|
||||
- Shows all changes before applying and asks for confirmation
|
||||
- Saves undo info so you can revert with ./bump-version.sh undo
|
||||
- Skips node_modules, dist, build, .git, __pycache__, venv, vendor
|
||||
- Skips binary files and files over 500KB
|
||||
- Skips itself (won't match examples in this help text)
|
||||
|
||||
EXAMPLES:
|
||||
./bump-version.sh # shows versions, pick what to do
|
||||
./bump-version.sh patch # quick patch bump, still confirms
|
||||
./bump-version.sh 1.0.0 --yes # set to 1.0.0 without confirmation
|
||||
./bump-version.sh undo # oops, go back
|
||||
HELPEOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# --- Find version files ---
|
||||
find_version_files() {
|
||||
while IFS= read -r file; do
|
||||
[ -z "$file" ] && continue
|
||||
[ ! -f "$file" ] && continue
|
||||
local size=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null || echo 0)
|
||||
[ "$size" -gt 500000 ] && continue
|
||||
echo "$file"
|
||||
done < <(find . -type f \( \
|
||||
-name "*.json" -o -name "*.toml" -o -name "*.yaml" -o -name "*.yml" \
|
||||
-o -name "*.py" -o -name "*.php" -o -name "*.sh" -o -name "*.bash" \
|
||||
-o -name "*.html" -o -name "*.js" -o -name "*.css" -o -name "*.cfg" \
|
||||
-o -name "*.ini" -o -name "*.txt" -o -name "*.xml" -o -name "*.plist" \
|
||||
-o -name "*.gradle" -o -name "*.gemspec" -o -name "*.podspec" \
|
||||
-o -name "*.csproj" -o -name "*.props" -o -name "*.md" \
|
||||
-o -name "Makefile" -o -name "Dockerfile" -o -name "Cargo.toml" \
|
||||
-o -name "setup.py" -o -name "setup.cfg" -o -name "pyproject.toml" \
|
||||
-o -name "package.json" -o -name "composer.json" -o -name "Gemfile" \
|
||||
\) 2>/dev/null | grep -Ev "$SKIP_DIRS" | grep -v "bump-version")
|
||||
}
|
||||
|
||||
# --- Extract version from file ---
|
||||
# Only matches version DECLARATIONS, not arbitrary X.Y.Z in text.
|
||||
# Each pattern requires a keyword context (version, VERSION, __version__, etc.)
|
||||
get_version_from_file() {
|
||||
local file="$1"
|
||||
local ver=""
|
||||
|
||||
# JSON: "version": "X.Y.Z"
|
||||
ver=$(grep -oP '"version"\s*:\s*"\K[0-9]+\.[0-9]+\.[0-9]+' "$file" 2>/dev/null | head -1)
|
||||
[ -n "$ver" ] && echo "$ver" && return
|
||||
|
||||
# TOML/Python: version = "X.Y.Z" or __version__ = "X.Y.Z"
|
||||
ver=$(grep -oP '(?:__)?version\s*=\s*["\x27]\K[0-9]+\.[0-9]+\.[0-9]+' "$file" 2>/dev/null | head -1)
|
||||
[ -n "$ver" ] && echo "$ver" && return
|
||||
|
||||
# YAML: version: X.Y.Z (must be at start of line)
|
||||
ver=$(grep -oP '^version:\s*["\x27]?\K[0-9]+\.[0-9]+\.[0-9]+' "$file" 2>/dev/null | head -1)
|
||||
[ -n "$ver" ] && echo "$ver" && return
|
||||
|
||||
# PHP/WordPress: Version: X.Y.Z
|
||||
ver=$(grep -oP 'Version:\s*\K[0-9]+\.[0-9]+\.[0-9]+' "$file" 2>/dev/null | head -1)
|
||||
[ -n "$ver" ] && echo "$ver" && return
|
||||
|
||||
# Shell: VERSION="X.Y.Z"
|
||||
ver=$(grep -oP 'VERSION\s*=\s*["\x27]?\K[0-9]+\.[0-9]+\.[0-9]+' "$file" 2>/dev/null | head -1)
|
||||
[ -n "$ver" ] && echo "$ver" && return
|
||||
|
||||
# HTML display: " vX.Y.Z" or ">vX.Y.Z" (requires v prefix — not bare numbers)
|
||||
ver=$(grep -oP '[ >]v\K[0-9]+\.[0-9]+\.[0-9]+' "$file" 2>/dev/null | head -1)
|
||||
[ -n "$ver" ] && echo "$ver" && return
|
||||
}
|
||||
|
||||
# --- Get current version (most common across files) ---
|
||||
get_current_version() {
|
||||
local versions=""
|
||||
while IFS= read -r file; do
|
||||
[ -z "$file" ] && continue
|
||||
local ver=$(get_version_from_file "$file")
|
||||
[ -n "$ver" ] && versions="$versions $ver"
|
||||
done <<< "$(find_version_files)"
|
||||
|
||||
echo "$versions" | tr ' ' '\n' | grep -v '^$' | sort | uniq -c | sort -rn | head -1 | awk '{print $2}'
|
||||
}
|
||||
|
||||
# --- Show all version occurrences grouped by version ---
|
||||
show_versions() {
|
||||
local current="$1"
|
||||
local files_list=""
|
||||
|
||||
echo -e "${CYAN}Version profile:${NC}"
|
||||
echo ""
|
||||
|
||||
# Collect all versions
|
||||
declare -A version_files
|
||||
while IFS= read -r file; do
|
||||
[ -z "$file" ] && continue
|
||||
local ver=$(get_version_from_file "$file")
|
||||
if [ -n "$ver" ]; then
|
||||
local rel="${file#./}"
|
||||
if [ -z "${version_files[$ver]+x}" ]; then
|
||||
version_files[$ver]="$rel"
|
||||
else
|
||||
version_files[$ver]="${version_files[$ver]}|$rel"
|
||||
fi
|
||||
fi
|
||||
done <<< "$(find_version_files)"
|
||||
|
||||
# Show grouped by version
|
||||
for ver in $(echo "${!version_files[@]}" | tr ' ' '\n' | sort -V); do
|
||||
if [ "$ver" = "$current" ]; then
|
||||
echo -e " ${GREEN}$ver${NC} ${BOLD}(current — will be updated)${NC}"
|
||||
else
|
||||
echo -e " ${DIM}$ver (different — will NOT be changed)${NC}"
|
||||
fi
|
||||
IFS='|' read -ra files <<< "${version_files[$ver]}"
|
||||
for f in "${files[@]}"; do
|
||||
if [ "$ver" = "$current" ]; then
|
||||
echo -e " ${GREEN}✓${NC} $f"
|
||||
else
|
||||
echo -e " ${DIM}· $f${NC}"
|
||||
fi
|
||||
done
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
# --- Preview changes ---
|
||||
preview_changes() {
|
||||
local old="$1"
|
||||
local new="$2"
|
||||
|
||||
echo -e "${YELLOW}Changes to be made:${NC}"
|
||||
echo ""
|
||||
|
||||
local count=0
|
||||
while IFS= read -r file; do
|
||||
[ -z "$file" ] && continue
|
||||
local ver=$(get_version_from_file "$file")
|
||||
if [ "$ver" = "$old" ]; then
|
||||
local rel="${file#./}"
|
||||
# Show the actual line that will change
|
||||
local line=$(grep -n "$old" "$file" 2>/dev/null | head -1)
|
||||
local linenum=$(echo "$line" | cut -d: -f1)
|
||||
local content=$(echo "$line" | cut -d: -f2-)
|
||||
local newcontent=$(echo "$content" | sed "s/$old/$new/g")
|
||||
echo -e " ${BOLD}$rel${NC} (line $linenum)"
|
||||
echo -e " ${RED}- $content${NC}"
|
||||
echo -e " ${GREEN}+ $newcontent${NC}"
|
||||
echo ""
|
||||
count=$((count + 1))
|
||||
fi
|
||||
done <<< "$(find_version_files)"
|
||||
|
||||
echo -e " ${CYAN}$count file(s) will be modified${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# --- Apply changes ---
|
||||
replace_version() {
|
||||
local old="$1"
|
||||
local new="$2"
|
||||
local escaped_old=$(echo "$old" | sed 's/\./\\./g')
|
||||
|
||||
# Save undo info
|
||||
echo "$new $old" > "$UNDO_FILE"
|
||||
local undo_files=""
|
||||
|
||||
while IFS= read -r file; do
|
||||
[ -z "$file" ] && continue
|
||||
local ver=$(get_version_from_file "$file")
|
||||
if [ "$ver" = "$old" ]; then
|
||||
# JSON: "version": "X.Y.Z"
|
||||
sed -i "s/\(\"version\"\s*:\s*\"\)$escaped_old\"/\1$new\"/g" "$file" 2>/dev/null
|
||||
# TOML/Python: version = "X.Y.Z" or __version__ = "X.Y.Z"
|
||||
sed -i "s/\(\(__\)\?version\s*=\s*[\"']\)$escaped_old/\1$new/g" "$file" 2>/dev/null
|
||||
# YAML: version: X.Y.Z
|
||||
sed -i "s/\(^version:\s*[\"']\?\)$escaped_old/\1$new/g" "$file" 2>/dev/null
|
||||
# PHP/WordPress: Version: X.Y.Z
|
||||
sed -i "s/\(Version:\s*\)$escaped_old/\1$new/g" "$file" 2>/dev/null
|
||||
# Shell: VERSION="X.Y.Z"
|
||||
sed -i "s/\(VERSION\s*=\s*[\"']\?\)$escaped_old/\1$new/g" "$file" 2>/dev/null
|
||||
# HTML display: vX.Y.Z
|
||||
sed -i "s/\([ >]v\)$escaped_old/\1$new/g" "$file" 2>/dev/null
|
||||
|
||||
local rel="${file#./}"
|
||||
echo -e " ${GREEN}✓${NC} $rel"
|
||||
undo_files="$undo_files $rel"
|
||||
fi
|
||||
done <<< "$(find_version_files)"
|
||||
|
||||
# Append file list to undo
|
||||
echo "$undo_files" >> "$UNDO_FILE"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Done! $old → $new${NC}"
|
||||
echo -e "${DIM}Run ./bump-version.sh undo to revert${NC}"
|
||||
}
|
||||
|
||||
# --- Undo ---
|
||||
do_undo() {
|
||||
if [ ! -f "$UNDO_FILE" ]; then
|
||||
echo -e "${RED}No undo information found. Nothing to revert.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local versions=$(head -1 "$UNDO_FILE")
|
||||
local current=$(echo "$versions" | awk '{print $1}')
|
||||
local previous=$(echo "$versions" | awk '{print $2}')
|
||||
|
||||
echo -e "${YELLOW}Undo: $current → $previous${NC}"
|
||||
echo ""
|
||||
|
||||
# Just do a version replace in the other direction
|
||||
local escaped_current=$(echo "$current" | sed 's/\./\\./g')
|
||||
|
||||
while IFS= read -r file; do
|
||||
[ -z "$file" ] && continue
|
||||
local ver=$(get_version_from_file "$file")
|
||||
if [ "$ver" = "$current" ]; then
|
||||
sed -i "s/\(\"version\"\s*:\s*\"\)$escaped_current\"/\1$previous\"/g" "$file" 2>/dev/null
|
||||
sed -i "s/\(\(__\)\?version\s*=\s*[\"']\)$escaped_current/\1$previous/g" "$file" 2>/dev/null
|
||||
sed -i "s/\(^version:\s*[\"']\?\)$escaped_current/\1$previous/g" "$file" 2>/dev/null
|
||||
sed -i "s/\(Version:\s*\)$escaped_current/\1$previous/g" "$file" 2>/dev/null
|
||||
sed -i "s/\(VERSION\s*=\s*[\"']\?\)$escaped_current/\1$previous/g" "$file" 2>/dev/null
|
||||
sed -i "s/\([ >]v\)$escaped_current/\1$previous/g" "$file" 2>/dev/null
|
||||
|
||||
local rel="${file#./}"
|
||||
echo -e " ${GREEN}✓${NC} $rel"
|
||||
fi
|
||||
done <<< "$(find_version_files)"
|
||||
|
||||
rm -f "$UNDO_FILE"
|
||||
echo ""
|
||||
echo -e "${GREEN}Reverted to $previous${NC}"
|
||||
}
|
||||
|
||||
# --- Bump version component ---
|
||||
bump_version() {
|
||||
local ver="$1"
|
||||
local part="$2"
|
||||
IFS='.' read -r major minor patch <<< "$ver"
|
||||
case "$part" in
|
||||
major) echo "$((major + 1)).0.0" ;;
|
||||
minor) echo "$major.$((minor + 1)).0" ;;
|
||||
patch) echo "$major.$minor.$((patch + 1))" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- Confirm ---
|
||||
confirm() {
|
||||
local msg="$1"
|
||||
read -p "$msg [y/N] " answer
|
||||
case "$answer" in
|
||||
y|Y|yes|YES) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
|
||||
# Parse flags
|
||||
YES_FLAG=false
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--help|-h) show_help ;;
|
||||
--yes|-y) YES_FLAG=true ;;
|
||||
undo) do_undo; exit 0 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Get first non-flag argument
|
||||
ACTION=""
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--*|-*) continue ;;
|
||||
undo) continue ;;
|
||||
*) ACTION="$arg"; break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
CURRENT=$(get_current_version)
|
||||
|
||||
if [ -z "$CURRENT" ]; then
|
||||
echo -e "${RED}No version declarations found in the project.${NC}"
|
||||
echo -e "${DIM}Looking for patterns like \"version\": \"X.Y.Z\" or VERSION=\"X.Y.Z\"${NC}"
|
||||
echo -e "${DIM}Run ./bump-version.sh --help for supported formats${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Handle command-line argument
|
||||
if [ -n "$ACTION" ]; then
|
||||
case "$ACTION" in
|
||||
patch|minor|major)
|
||||
NEW=$(bump_version "$CURRENT" "$ACTION")
|
||||
;;
|
||||
[0-9]*)
|
||||
if ! [[ "$ACTION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo -e "${RED}Invalid version format. Use X.Y.Z (e.g. 1.0.0)${NC}"
|
||||
exit 1
|
||||
fi
|
||||
NEW="$ACTION"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unknown action: $ACTION${NC}"
|
||||
echo "Usage: $0 [patch|minor|major|X.Y.Z|undo|--help]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
show_versions "$CURRENT"
|
||||
preview_changes "$CURRENT" "$NEW"
|
||||
|
||||
if [ "$YES_FLAG" = false ]; then
|
||||
if ! confirm "Apply these changes?"; then
|
||||
echo "Cancelled."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
replace_version "$CURRENT" "$NEW"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Interactive mode
|
||||
show_versions "$CURRENT"
|
||||
|
||||
echo -e "Current version: ${GREEN}${BOLD}$CURRENT${NC}"
|
||||
echo ""
|
||||
echo " [1] Bump patch: $CURRENT → $(bump_version "$CURRENT" patch)"
|
||||
echo " [2] Bump minor: $CURRENT → $(bump_version "$CURRENT" minor)"
|
||||
echo " [3] Bump major: $CURRENT → $(bump_version "$CURRENT" major)"
|
||||
echo " [4] Enter custom version"
|
||||
if [ -f "$UNDO_FILE" ]; then
|
||||
prev=$(head -1 "$UNDO_FILE" | awk '{print $2}')
|
||||
echo " [u] Undo last bump (revert to $prev)"
|
||||
fi
|
||||
echo " [q] Quit"
|
||||
echo ""
|
||||
read -p "Choice: " choice
|
||||
|
||||
case "$choice" in
|
||||
1) NEW=$(bump_version "$CURRENT" patch) ;;
|
||||
2) NEW=$(bump_version "$CURRENT" minor) ;;
|
||||
3) NEW=$(bump_version "$CURRENT" major) ;;
|
||||
4)
|
||||
read -p "Enter version (X.Y.Z): " NEW
|
||||
if ! [[ "$NEW" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo -e "${RED}Invalid version format. Use X.Y.Z${NC}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
u|U) do_undo; exit 0 ;;
|
||||
q|Q|"") echo "Cancelled."; exit 0 ;;
|
||||
*) echo -e "${RED}Invalid choice.${NC}"; exit 1 ;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
preview_changes "$CURRENT" "$NEW"
|
||||
|
||||
if ! confirm "Apply these changes?"; then
|
||||
echo "Cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
replace_version "$CURRENT" "$NEW"
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Silent Send",
|
||||
"version": "2.0.14",
|
||||
"version": "0.9.0",
|
||||
"description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Silent Send",
|
||||
"version": "2.0.14",
|
||||
"version": "0.9.0",
|
||||
"description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.",
|
||||
"permissions": [
|
||||
"storage",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "silent-send",
|
||||
"version": "2.0.14",
|
||||
"version": "0.9.0",
|
||||
"private": true,
|
||||
"license": "BSL-1.1",
|
||||
"description": "Browser extension that substitutes personal data before sending to AI services",
|
||||
|
||||
@@ -610,7 +610,7 @@
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<p>Silent Send v2.0.14</p>
|
||||
<p>Silent Send v0.9.0</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user