Files
jaganpro__sf-skills/scripts/create-release.sh
T

289 lines
7.9 KiB
Bash
Raw Normal View History

1 feat(hooks): implement session-start auto-update system for marketplace users 2 3 PROBLEM: 4 - Marketplace users' sf-skills clone at ~/.claude/plugins/marketplaces/sf-skills/ 5 doesn't auto-update, leading to stale plugins 6 - Project-level hooks.json uses relative paths; marketplace users don't get 7 global hooks without manual setup 8 - No mechanism to check for or apply updates automatically 9 10 SOLUTION: 11 Session-start auto-update system with global hooks installation: 12 13 NEW FILES: 14 - shared/hooks/scripts/session-update-check.py 15 - SessionStart hook that checks GitHub releases (24h cache) 16 - 5-second total timeout, graceful offline fallback 17 - Silent output except on successful update 18 - Uses rsync/shutil to sync hooks to ~/.claude/sf-skills-hooks/ 19 20 - scripts/migrate-to-global-hooks.py 21 - Migrates from settings.json to global hooks.json 22 - Creates backups at ~/.claude/backups/migration-{timestamp}/ 23 - Copies shared/hooks/ → ~/.claude/sf-skills-hooks/ 24 - Merges with existing user hooks (preserves non-sf-skills hooks) 25 - Cleans orphan cache files 26 - Options: --dry-run, --verbose 27 28 - scripts/create-release.sh 29 - Validates semver format (v*.*.*) 30 - Updates marketplace.json and skills-registry.json versions 31 - Creates annotated git tag with changelog 32 - Pushes tag to trigger GitHub Actions 33 34 - .github/workflows/release.yml 35 - Triggers on v*.*.* tag push 36 - Generates categorized changelog (features, fixes, docs, chores) 37 - Creates GitHub release with installation instructions 38 39 MODIFIED FILES: 40 - scripts/install-hooks.py 41 - Added --global flag: installs to ~/.claude/sf-skills-hooks/ 42 - Added --to-hooks-json flag: writes to hooks.json instead of settings.json 43 - Added get_global_hooks_config() for absolute path generation 44 - Added copy_hooks_to_global() and write_version_file() helpers 45 - Added session-update-check.py to HOOK_DESCRIPTIONS and verify list 46 47 ARCHITECTURE: 48 ~/.claude/ 49 ├── hooks.json # Global hooks (absolute paths) 50 ├── sf-skills-hooks/ # Stable hooks location 51 │ ├── VERSION # Current version (e.g., "v1.2.0") 52 │ ├── .last-update-check # 24-hour cache timestamp 53 │ ├── scripts/ # All hook scripts 54 │ └── skills-registry.json # Skills configuration 55 └── plugins/marketplaces/sf-skills/ # Git clone (source) 56 57 DATA FLOW: 58 Session Start → Cache fresh? → Yes: Exit (0ms) 59 → No: Fetch GitHub API (3s timeout) 60 → Offline: Update cache, exit 61 → Outdated: git fetch → rsync → update VERSION 62 → Output: "✅ sf-skills updated v1.0.0 → v1.1.0" 63 64 Jag Valaiyapathy
2026-01-31 10:25:02 -05:00
#!/usr/bin/env bash
#
# sf-skills Release Helper Script
# ================================
#
# Creates a new release of sf-skills by:
# 1. Validating version format (v*.*.*)
# 2. Updating version in skills-registry.json
# 3. Creating annotated git tag
# 4. Pushing tag to origin (triggers GitHub Actions release workflow)
1 feat(hooks): implement session-start auto-update system for marketplace users 2 3 PROBLEM: 4 - Marketplace users' sf-skills clone at ~/.claude/plugins/marketplaces/sf-skills/ 5 doesn't auto-update, leading to stale plugins 6 - Project-level hooks.json uses relative paths; marketplace users don't get 7 global hooks without manual setup 8 - No mechanism to check for or apply updates automatically 9 10 SOLUTION: 11 Session-start auto-update system with global hooks installation: 12 13 NEW FILES: 14 - shared/hooks/scripts/session-update-check.py 15 - SessionStart hook that checks GitHub releases (24h cache) 16 - 5-second total timeout, graceful offline fallback 17 - Silent output except on successful update 18 - Uses rsync/shutil to sync hooks to ~/.claude/sf-skills-hooks/ 19 20 - scripts/migrate-to-global-hooks.py 21 - Migrates from settings.json to global hooks.json 22 - Creates backups at ~/.claude/backups/migration-{timestamp}/ 23 - Copies shared/hooks/ → ~/.claude/sf-skills-hooks/ 24 - Merges with existing user hooks (preserves non-sf-skills hooks) 25 - Cleans orphan cache files 26 - Options: --dry-run, --verbose 27 28 - scripts/create-release.sh 29 - Validates semver format (v*.*.*) 30 - Updates marketplace.json and skills-registry.json versions 31 - Creates annotated git tag with changelog 32 - Pushes tag to trigger GitHub Actions 33 34 - .github/workflows/release.yml 35 - Triggers on v*.*.* tag push 36 - Generates categorized changelog (features, fixes, docs, chores) 37 - Creates GitHub release with installation instructions 38 39 MODIFIED FILES: 40 - scripts/install-hooks.py 41 - Added --global flag: installs to ~/.claude/sf-skills-hooks/ 42 - Added --to-hooks-json flag: writes to hooks.json instead of settings.json 43 - Added get_global_hooks_config() for absolute path generation 44 - Added copy_hooks_to_global() and write_version_file() helpers 45 - Added session-update-check.py to HOOK_DESCRIPTIONS and verify list 46 47 ARCHITECTURE: 48 ~/.claude/ 49 ├── hooks.json # Global hooks (absolute paths) 50 ├── sf-skills-hooks/ # Stable hooks location 51 │ ├── VERSION # Current version (e.g., "v1.2.0") 52 │ ├── .last-update-check # 24-hour cache timestamp 53 │ ├── scripts/ # All hook scripts 54 │ └── skills-registry.json # Skills configuration 55 └── plugins/marketplaces/sf-skills/ # Git clone (source) 56 57 DATA FLOW: 58 Session Start → Cache fresh? → Yes: Exit (0ms) 59 → No: Fetch GitHub API (3s timeout) 60 → Offline: Update cache, exit 61 → Outdated: git fetch → rsync → update VERSION 62 → Output: "✅ sf-skills updated v1.0.0 → v1.1.0" 63 64 Jag Valaiyapathy
2026-01-31 10:25:02 -05:00
#
# Usage:
# ./scripts/create-release.sh v1.2.0
#
# Requirements:
# - jq (for JSON manipulation)
# - git
# - Clean working directory (no uncommitted changes)
#
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
# Files to update
REGISTRY_JSON="$REPO_ROOT/shared/hooks/skills-registry.json"
# ============================================================================
# HELPER FUNCTIONS
# ============================================================================
print_banner() {
echo ""
echo -e "${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║ sf-skills Release Helper ║${NC}"
echo -e "${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}"
echo ""
}
print_success() {
echo -e " ${GREEN}${NC} $1"
}
print_info() {
echo -e " ${BLUE} ${NC} $1"
}
print_warning() {
echo -e " ${YELLOW}⚠️ ${NC} $1"
}
print_error() {
echo -e " ${RED}${NC} $1"
}
print_step() {
echo ""
echo -e "${BOLD}Step $1: $2${NC}"
echo "──────────────────────────────────────────────────────"
}
# ============================================================================
# VALIDATION FUNCTIONS
# ============================================================================
check_dependencies() {
local missing=()
if ! command -v jq &> /dev/null; then
missing+=("jq")
fi
if ! command -v git &> /dev/null; then
missing+=("git")
fi
if [ ${#missing[@]} -gt 0 ]; then
print_error "Missing required dependencies: ${missing[*]}"
echo " Install with: brew install ${missing[*]}"
exit 1
fi
}
validate_version_format() {
local version="$1"
# Must match v followed by semver (v1.0.0, v1.2.3, etc.)
if [[ ! "$version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
print_error "Invalid version format: $version"
echo " Expected format: v1.2.3 (semantic versioning with 'v' prefix)"
exit 1
fi
}
check_clean_working_directory() {
if ! git diff --quiet || ! git diff --staged --quiet; then
print_error "Working directory has uncommitted changes"
echo " Please commit or stash changes before creating a release"
git status --short
exit 1
fi
}
check_tag_not_exists() {
local version="$1"
if git tag -l "$version" | grep -q "$version"; then
print_error "Tag $version already exists"
echo " Use a different version or delete the existing tag first"
exit 1
fi
}
get_current_version() {
if [ -f "$REGISTRY_JSON" ]; then
jq -r '.version // "0.0.0"' "$REGISTRY_JSON"
else
echo "0.0.0"
fi
}
# ============================================================================
# UPDATE FUNCTIONS
# ============================================================================
update_registry_json() {
local version="$1"
local version_no_v="${version#v}" # Remove 'v' prefix
if [ ! -f "$REGISTRY_JSON" ]; then
print_warning "skills-registry.json not found, skipping"
return 0
fi
local temp_file
temp_file=$(mktemp)
jq --arg v "$version_no_v" '.version = $v' "$REGISTRY_JSON" > "$temp_file"
mv "$temp_file" "$REGISTRY_JSON"
print_success "Updated skills-registry.json to v$version_no_v"
}
create_git_tag() {
local version="$1"
local current_version="$2"
# Get commit count since last tag for the message
local commit_count
if git describe --tags --abbrev=0 &>/dev/null; then
local last_tag
last_tag=$(git describe --tags --abbrev=0)
commit_count=$(git rev-list "$last_tag"..HEAD --count)
else
commit_count=$(git rev-list HEAD --count)
fi
# Create annotated tag with message
local tag_message="Release $version
Changes since v$current_version:
- $commit_count commits
Created by: scripts/create-release.sh
Date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
git tag -a "$version" -m "$tag_message"
print_success "Created annotated tag: $version"
}
push_tag() {
local version="$1"
print_info "Pushing tag to origin..."
git push origin "$version"
print_success "Pushed tag $version to origin"
}
commit_version_updates() {
local version="$1"
# Stage version file changes
git add "$REGISTRY_JSON" 2>/dev/null || true
1 feat(hooks): implement session-start auto-update system for marketplace users 2 3 PROBLEM: 4 - Marketplace users' sf-skills clone at ~/.claude/plugins/marketplaces/sf-skills/ 5 doesn't auto-update, leading to stale plugins 6 - Project-level hooks.json uses relative paths; marketplace users don't get 7 global hooks without manual setup 8 - No mechanism to check for or apply updates automatically 9 10 SOLUTION: 11 Session-start auto-update system with global hooks installation: 12 13 NEW FILES: 14 - shared/hooks/scripts/session-update-check.py 15 - SessionStart hook that checks GitHub releases (24h cache) 16 - 5-second total timeout, graceful offline fallback 17 - Silent output except on successful update 18 - Uses rsync/shutil to sync hooks to ~/.claude/sf-skills-hooks/ 19 20 - scripts/migrate-to-global-hooks.py 21 - Migrates from settings.json to global hooks.json 22 - Creates backups at ~/.claude/backups/migration-{timestamp}/ 23 - Copies shared/hooks/ → ~/.claude/sf-skills-hooks/ 24 - Merges with existing user hooks (preserves non-sf-skills hooks) 25 - Cleans orphan cache files 26 - Options: --dry-run, --verbose 27 28 - scripts/create-release.sh 29 - Validates semver format (v*.*.*) 30 - Updates marketplace.json and skills-registry.json versions 31 - Creates annotated git tag with changelog 32 - Pushes tag to trigger GitHub Actions 33 34 - .github/workflows/release.yml 35 - Triggers on v*.*.* tag push 36 - Generates categorized changelog (features, fixes, docs, chores) 37 - Creates GitHub release with installation instructions 38 39 MODIFIED FILES: 40 - scripts/install-hooks.py 41 - Added --global flag: installs to ~/.claude/sf-skills-hooks/ 42 - Added --to-hooks-json flag: writes to hooks.json instead of settings.json 43 - Added get_global_hooks_config() for absolute path generation 44 - Added copy_hooks_to_global() and write_version_file() helpers 45 - Added session-update-check.py to HOOK_DESCRIPTIONS and verify list 46 47 ARCHITECTURE: 48 ~/.claude/ 49 ├── hooks.json # Global hooks (absolute paths) 50 ├── sf-skills-hooks/ # Stable hooks location 51 │ ├── VERSION # Current version (e.g., "v1.2.0") 52 │ ├── .last-update-check # 24-hour cache timestamp 53 │ ├── scripts/ # All hook scripts 54 │ └── skills-registry.json # Skills configuration 55 └── plugins/marketplaces/sf-skills/ # Git clone (source) 56 57 DATA FLOW: 58 Session Start → Cache fresh? → Yes: Exit (0ms) 59 → No: Fetch GitHub API (3s timeout) 60 → Offline: Update cache, exit 61 → Outdated: git fetch → rsync → update VERSION 62 → Output: "✅ sf-skills updated v1.0.0 → v1.1.0" 63 64 Jag Valaiyapathy
2026-01-31 10:25:02 -05:00
# Check if there are changes to commit
if git diff --staged --quiet; then
print_info "No version file changes to commit"
return 0
fi
git commit -m "chore: bump version to $version
Updated:
- shared/hooks/skills-registry.json
[automated by scripts/create-release.sh]"
print_success "Committed version updates"
}
# ============================================================================
# MAIN
# ============================================================================
main() {
print_banner
# Check arguments
if [ $# -lt 1 ]; then
echo "Usage: $0 <version>"
echo ""
echo "Examples:"
echo " $0 v1.0.0"
echo " $0 v1.2.3"
echo ""
exit 1
fi
local new_version="$1"
# Step 1: Check dependencies
print_step 1 "Checking dependencies"
check_dependencies
print_success "All dependencies available"
# Step 2: Validate version format
print_step 2 "Validating version"
validate_version_format "$new_version"
print_success "Version format valid: $new_version"
# Get current version for comparison
local current_version
current_version=$(get_current_version)
print_info "Current version: v$current_version"
# Step 3: Check working directory
print_step 3 "Checking git status"
cd "$REPO_ROOT"
check_clean_working_directory
print_success "Working directory is clean"
# Step 4: Check tag doesn't exist
check_tag_not_exists "$new_version"
print_success "Tag $new_version does not exist yet"
# Step 5: Update version files
print_step 4 "Updating version files"
update_registry_json "$new_version"
# Step 6: Commit version changes
print_step 5 "Committing changes"
commit_version_updates "$new_version"
# Step 7: Create tag
print_step 6 "Creating git tag"
create_git_tag "$new_version" "$current_version"
# Step 8: Push tag (triggers GitHub Actions)
print_step 7 "Pushing to remote"
push_tag "$new_version"
# Summary
echo ""
echo -e "${BOLD}═══════════════════════════════════════════════════════════════${NC}"
echo -e "${GREEN}✅ RELEASE CREATED SUCCESSFULLY!${NC}"
echo ""
echo " Version: $new_version"
echo " Previous: v$current_version"
echo ""
echo " GitHub Actions will now:"
echo " 1. Generate changelog from commits"
echo " 2. Create GitHub Release with notes"
echo ""
echo " View release at:"
echo " https://github.com/Jaganpro/sf-skills/releases/tag/$new_version"
1 feat(hooks): implement session-start auto-update system for marketplace users 2 3 PROBLEM: 4 - Marketplace users' sf-skills clone at ~/.claude/plugins/marketplaces/sf-skills/ 5 doesn't auto-update, leading to stale plugins 6 - Project-level hooks.json uses relative paths; marketplace users don't get 7 global hooks without manual setup 8 - No mechanism to check for or apply updates automatically 9 10 SOLUTION: 11 Session-start auto-update system with global hooks installation: 12 13 NEW FILES: 14 - shared/hooks/scripts/session-update-check.py 15 - SessionStart hook that checks GitHub releases (24h cache) 16 - 5-second total timeout, graceful offline fallback 17 - Silent output except on successful update 18 - Uses rsync/shutil to sync hooks to ~/.claude/sf-skills-hooks/ 19 20 - scripts/migrate-to-global-hooks.py 21 - Migrates from settings.json to global hooks.json 22 - Creates backups at ~/.claude/backups/migration-{timestamp}/ 23 - Copies shared/hooks/ → ~/.claude/sf-skills-hooks/ 24 - Merges with existing user hooks (preserves non-sf-skills hooks) 25 - Cleans orphan cache files 26 - Options: --dry-run, --verbose 27 28 - scripts/create-release.sh 29 - Validates semver format (v*.*.*) 30 - Updates marketplace.json and skills-registry.json versions 31 - Creates annotated git tag with changelog 32 - Pushes tag to trigger GitHub Actions 33 34 - .github/workflows/release.yml 35 - Triggers on v*.*.* tag push 36 - Generates categorized changelog (features, fixes, docs, chores) 37 - Creates GitHub release with installation instructions 38 39 MODIFIED FILES: 40 - scripts/install-hooks.py 41 - Added --global flag: installs to ~/.claude/sf-skills-hooks/ 42 - Added --to-hooks-json flag: writes to hooks.json instead of settings.json 43 - Added get_global_hooks_config() for absolute path generation 44 - Added copy_hooks_to_global() and write_version_file() helpers 45 - Added session-update-check.py to HOOK_DESCRIPTIONS and verify list 46 47 ARCHITECTURE: 48 ~/.claude/ 49 ├── hooks.json # Global hooks (absolute paths) 50 ├── sf-skills-hooks/ # Stable hooks location 51 │ ├── VERSION # Current version (e.g., "v1.2.0") 52 │ ├── .last-update-check # 24-hour cache timestamp 53 │ ├── scripts/ # All hook scripts 54 │ └── skills-registry.json # Skills configuration 55 └── plugins/marketplaces/sf-skills/ # Git clone (source) 56 57 DATA FLOW: 58 Session Start → Cache fresh? → Yes: Exit (0ms) 59 → No: Fetch GitHub API (3s timeout) 60 → Offline: Update cache, exit 61 → Outdated: git fetch → rsync → update VERSION 62 → Output: "✅ sf-skills updated v1.0.0 → v1.1.0" 63 64 Jag Valaiyapathy
2026-01-31 10:25:02 -05:00
echo ""
}
main "$@"