diff --git a/.github/workflows/fish-syntax.yml b/.github/workflows/fish-syntax.yml new file mode 100644 index 0000000..8b3a427 --- /dev/null +++ b/.github/workflows/fish-syntax.yml @@ -0,0 +1,153 @@ +name: Fish Shell Syntax & Functionality Check + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +jobs: + fish-syntax: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Fish shell (Ubuntu) + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y fish + fish --version + + - name: Install Fish shell (macOS) + if: matrix.os == 'macos-latest' + run: | + brew install fish + fish --version + + - name: Verify Fish installation and version + run: | + echo "Testing Fish shell installation..." + fish --version + echo "Current Fish version:" + fish -c "echo $version" + echo "Fish version compatibility test passed" + + - name: Check Fish syntax + run: | + # Check syntax for all .fish files + for file in *.fish; do + if [ -f "$file" ]; then + echo "Checking syntax for $file..." + fish -c "source $file" || { + echo "❌ Syntax error in $file" + exit 1 + } + echo "✅ $file syntax OK" + fi + done + + - name: Test function loading + run: | + # Test that functions can be loaded without errors + fish -c " + # Test nvm function definition + source nvm.fish + functions -t nvm + echo '✅ nvm function loaded successfully' + + # Test helper functions + if functions -q __nvm_handle_nvmrc_file + echo '✅ Helper functions available' + end + " || { + echo "❌ Function loading test failed" + exit 1 + } + + - name: Validate PKGBUILD + if: matrix.os == 'ubuntu-latest' + run: | + # Check if PKGBUILD is valid bash + bash -n PKGBUILD + echo "✅ PKGBUILD syntax OK" + + - name: Check file permissions + run: | + # Ensure fish files are executable + chmod +x *.fish 2>/dev/null || true + echo "✅ File permissions set" + + - name: Run CI test script + run: | + # Run our comprehensive test suite + fish test_ci.fish + echo "✅ CI tests passed" + + code-quality: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check for common issues + run: | + echo "🔍 Checking code quality..." + + # Check for deprecated syntax + if grep -q 'test.*[[:space:]]-a[[:space:]]' *.fish; then + echo "❌ Found deprecated '-a' operator in test commands" + exit 1 + fi + echo "✅ No deprecated syntax found" + + # Check for proper error handling + if grep -q "echo.*error" *.fish | grep -v ">"; then + echo "⚠️ Consider redirecting error messages to stderr" + fi + echo "✅ Error handling check completed" + + # Check file sizes + for file in *.fish; do + if [ -f "$file" ]; then + lines=$(wc -l < "$file") + if [ "$lines" -gt 500 ]; then + echo "⚠️ $file is large ($lines lines), consider refactoring" + fi + fi + done + echo "✅ File size check completed" + + security-scan: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Security check + run: | + echo "🔒 Running security checks..." + + # Check for potential security issues + if grep -q "rm -rf" *.fish *.sh 2>/dev/null; then + echo "⚠️ Found 'rm -rf' usage - review for security" + fi + + # Check for eval usage + if grep -q "eval" *.fish *.sh 2>/dev/null; then + echo "⚠️ Found 'eval' usage - review for security" + fi + + # Check for hardcoded paths + if grep -q "/home/" *.fish *.sh 2>/dev/null | grep -v "#"; then + echo "⚠️ Found hardcoded paths - consider using variables" + fi + + echo "✅ Security scan completed" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 113cdb5..c891300 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ nvm-official-readme.md # Test and backup files *.backup* -test_* backup_* # Fish shell cache @@ -39,4 +38,5 @@ Thumbs.db # custom aur-push.sh -CLAUDE.md \ No newline at end of file +CLAUDE.md +.claude/ \ No newline at end of file diff --git a/aur-sync.sh b/aur-sync.sh new file mode 100755 index 0000000..6231095 --- /dev/null +++ b/aur-sync.sh @@ -0,0 +1,240 @@ +#!/bin/bash + +# AUR 同步脚本 +# 自动将开发仓库的更改同步到 AUR 本地仓库 + +set -e # 遇到错误立即退出 + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 脚本配置 +DEV_REPO="/home/chhsich/Git/Mine/NVM-Fish/nvm-fish-aur" +AUR_REPO="/home/chhsich/Git/Mine/NVM-Fish/nvm-fish-aurpush" + +# 打印带颜色的消息 +print_message() { + local color=$1 + local message=$2 + echo -e "${color}[$(date '+%Y-%m-%d %H:%M:%S')] ${message}${NC}" +} + +# 检查仓库是否存在 +check_repos() { + print_message "$BLUE" "检查仓库状态..." + + if [ ! -d "$DEV_REPO" ]; then + print_message "$RED" "错误: 开发仓库不存在: $DEV_REPO" + exit 1 + fi + + if [ ! -d "$AUR_REPO" ]; then + print_message "$RED" "错误: AUR 仓库不存在: $AUR_REPO" + exit 1 + fi + + print_message "$GREEN" "仓库检查通过" +} + +# 获取当前版本号 +get_current_version() { + local pkgbuild_path="$DEV_REPO/PKGBUILD" + if [ ! -f "$pkgbuild_path" ]; then + print_message "$RED" "错误: 找不到 PKGBUILD 文件: $pkgbuild_path" + exit 1 + fi + + # 提取版本号 + local version=$(grep "^pkgver=" "$pkgbuild_path" | cut -d'=' -f2) + echo "$version" +} + +# 检查是否需要更新 +check_if_update_needed() { + local dev_version="$1" + local aur_pkgbuild="$AUR_REPO/PKGBUILD" + + if [ ! -f "$aur_pkgbuild" ]; then + print_message "$YELLOW" "AUR 仓库中找不到 PKGBUILD,需要更新" + return 0 + fi + + local aur_version=$(grep "^pkgver=" "$aur_pkgbuild" | cut -d'=' -f2) + + if [ "$dev_version" = "$aur_version" ]; then + print_message "$YELLOW" "版本号相同 (v$dev_version),无需更新" + return 1 + else + print_message "$GREEN" "检测到版本更新: v$aur_version -> v$dev_version" + return 0 + fi +} + +# 复制文件到 AUR 仓库 +copy_files_to_aur() { + local version="$1" + print_message "$BLUE" "复制文件到 AUR 仓库..." + + # 复制核心文件 + cp "$DEV_REPO/PKGBUILD" "$AUR_REPO/" + cp "$DEV_REPO/nvm-fish.install" "$AUR_REPO/" + + # 复制 Fish 函数文件 + cp "$DEV_REPO/"*.fish "$AUR_REPO/" + + # 生成 .SRCINFO + cd "$AUR_REPO" + makepkg --printsrcinfo > .SRCINFO + + print_message "$GREEN" "文件复制完成" +} + +# 显示更改摘要 +show_changes_summary() { + local version="$1" + print_message "$BLUE" "=== 更改摘要 ===" + print_message "$GREEN" "版本: v$version" + print_message "$BLUE" "更新的文件:" + + cd "$AUR_REPO" + git status --porcelain + + print_message "$BLUE" "=== 详细更改 ===" + git diff --stat +} + +# 显示下一步操作指南 +show_next_steps() { + local version="$1" + cat << EOF + +${GREEN}=== 同步完成!下一步操作指南 ===${NC} + +${YELLOW}1. 检查更改:${NC} + cd "$AUR_REPO" + git status + git diff + +${YELLOW}2. 如果一切正常,提交更改:${NC} + cd "$AUR_REPO" + git add . + git commit -m "Update nvm-fish to v$version" + +${YELLOW}3. 推送到 AUR 远程仓库:${NC} + git push origin master + +${YELLOW}4. 验证 AUR 包:${NC} + # 在本地测试构建 + makepkg --check + + # 检查 AUR 网站 + # https://aur.archlinux.org/packages/nvm-fish + +${YELLOW}常见问题:${NC} +- 如果推送失败,请检查 SSH 密钥配置 +- 如果构建失败,请检查 PKGBUILD 语法 +- 如果版本号有问题,请手动编辑 PKGBUILD + +${BLUE}提示: 运行以下命令快速提交并推送${NC} + cd "$AUR_REPO" && git add . && git commit -m "Update nvm-fish to v$version" && git push origin master + +EOF +} + +# 显示使用说明 +show_usage() { + cat << EOF +AUR 同步脚本 + +用法: $(basename "$0") [选项] + +选项: + -h, --help 显示此帮助信息 + -f, --force 强制更新,即使版本号相同也执行 + -v, --version 显示当前版本号 + -s, --summary 只显示更改摘要,不执行同步 + +示例: + $(basename "$0") # 正常同步流程 + $(basename "$0") --force # 强制更新 + $(basename "$0") --version # 显示版本号 + $(basename "$0") --summary # 显示更改摘要 + +EOF +} + +# 主函数 +main() { + local force=false + local summary_only=false + + # 解析命令行参数 + while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_usage + exit 0 + ;; + -f|--force) + force=true + shift + ;; + -v|--version) + echo "v$(get_current_version)" + exit 0 + ;; + -s|--summary) + summary_only=true + shift + ;; + *) + print_message "$RED" "未知选项: $1" + show_usage + exit 1 + ;; + esac + done + + print_message "$GREEN" "=== AUR 同步脚本启动 ===" + + # 1. 检查仓库 + check_repos + + # 2. 获取当前版本 + local current_version=$(get_current_version) + print_message "$BLUE" "当前开发仓库版本: v$current_version" + + # 3. 检查是否需要更新 + if ! $force && ! check_if_update_needed "$current_version"; then + if $summary_only; then + show_changes_summary "$current_version" + fi + print_message "$YELLOW" "使用 --force 强制更新" + exit 0 + fi + + if $summary_only; then + show_changes_summary "$current_version" + exit 0 + fi + + # 4. 复制文件 + copy_files_to_aur "$current_version" + + # 5. 显示更改摘要 + show_changes_summary "$current_version" + + # 6. 显示下一步操作指南 + show_next_steps "$current_version" + + print_message "$GREEN" "=== AUR 同步完成 ===" +} + +# 脚本入口点 +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi \ No newline at end of file diff --git a/load_nvm.fish b/load_nvm.fish index 8fc3af2..40e5a46 100644 --- a/load_nvm.fish +++ b/load_nvm.fish @@ -28,7 +28,7 @@ function load_nvm --on-variable="PWD" --description 'Automatically switch Node.j set -l current_dir "$PWD" # Search up the directory tree for .nvmrc - while test -z "$nvmrc_path" -a "$current_dir" != "/" + while test -z "$nvmrc_path"; and test "$current_dir" != "/" if test -f "$current_dir/.nvmrc" set nvmrc_path "$current_dir/.nvmrc" else @@ -36,7 +36,7 @@ function load_nvm --on-variable="PWD" --description 'Automatically switch Node.j end end - if test -n "$nvmrc_path" -a -f "$nvmrc_path" + if test -n "$nvmrc_path"; and test -f "$nvmrc_path" # Only call nvm if there's actually a .nvmrc file set -l nvmrc_content (cat "$nvmrc_path" 2>/dev/null | string trim) if test -n "$nvmrc_content" @@ -69,7 +69,7 @@ function load_nvm --on-variable="PWD" --description 'Automatically switch Node.j else # Only revert to default if we're not already on default # This avoids calling nvm on every directory without .nvmrc - if test -n "$NVM_BIN" -a "$NVM_BIN" != "$HOME/.nvm/versions/node/$(nvm version default 2>/dev/null)/bin" + if test -n "$NVM_BIN"; and test "$NVM_BIN" != "$HOME/.nvm/versions/node/$(nvm version default 2>/dev/null)/bin" # Use direct bass call to avoid .nvmrc management prompts and output set -lx NVM_AUTO 1 bass source ~/.nvm/nvm.sh --no-use ';' nvm use default diff --git a/test_ci.fish b/test_ci.fish new file mode 100755 index 0000000..d8dd7ae --- /dev/null +++ b/test_ci.fish @@ -0,0 +1,171 @@ +#!/usr/bin/env fish + +# CI test script for nvm-fish +# This script runs automated tests to verify nvm-fish functionality + +set -g TEST_ROOT (mktemp -d /tmp/nvm-fish-test.XXXXXX) +set -g ORIGINAL_PWD $PWD + +# Cleanup function +function cleanup + cd $ORIGINAL_PWD + rm -rf $TEST_ROOT + echo "🧹 Test directory cleaned up" +end + +# Register cleanup +function __trap_exit --on-event fish_exit + cleanup +end + +echo "🧪 Starting nvm-fish CI tests..." +echo "📁 Test directory: $TEST_ROOT" + +# Test 1: Syntax validation +echo "" +echo "📋 Test 1: Syntax validation" +set -l test_files (string match '*.fish' -- * | string match -v 'test_ci.fish') +if test (count $test_files) -eq 0 + echo " ⚠️ No .fish files found to test" +else + for file in $test_files + if test -f "$file" + echo " Checking $file..." + if not fish -c "source \"$file\"" + echo "❌ Syntax error in $file" + exit 1 + end + echo " ✅ $file" + end + end +end + +# Test 2: Function definitions +echo "" +echo "📋 Test 2: Function definitions" +fish -c " + source \"$ORIGINAL_PWD/nvm.fish\" + + # Check main function exists + if functions -q nvm + echo ' ✅ nvm function defined' + else + echo ' ❌ nvm function not found' + exit 1 + end + + # Check helper functions exist + set -l helper_functions __nvm_write_nvmrc_file __nvm_handle_nvmrc_file __nvm_create_nvmrc __nvm_prompt_override_nvmrc __nvm_backup_nvmrc + for func in $helper_functions + if functions -q $func + echo " ✅ $func function defined" + else + echo " ❌ $func function not found" + exit 1 + end + end +" + +# Test 3: Basic functionality +echo "" +echo "📋 Test 3: Basic functionality simulation" +cd $TEST_ROOT + +# Test version extraction regex +fish -c " + set test_output 'Now using node v18.17.0 (npm v9.6.7)' + set extracted_version (string match -rg 'Now using node v([0-9]+\.[0-9]+\.[0-9]+)' "$test_output") + + if test \"$extracted_version\" = \"18.17.0\" + echo ' ✅ Version extraction works correctly' + else + echo ' ❌ Version extraction failed: got \"$extracted_version\", expected \"18.17.0\"' + exit 1 + end +" + +# Test cross-platform compatibility +echo " 🔄 Testing cross-platform compatibility..." +fish -c " + # Test path handling + set test_path '/tmp/test/path' + if test (dirname \"$test_path\") = '/tmp/test' + echo ' ✅ Path handling works correctly' + else + echo ' ❌ Path handling failed' + exit 1 + end + + # Test string operations + set test_string 'v18.17.0' + if test (string replace 'v' '' \"$test_string\") = '18.17.0' + echo ' ✅ String operations work correctly' + else + echo ' ❌ String operations failed' + exit 1 + end +" + +# Test 4: File operations +echo "" +echo "📋 Test 4: File operations" +cd $TEST_ROOT + +# Test .nvmrc writing +fish -c " + source "$ORIGINAL_PWD/nvm.fish" + + # Test .nvmrc file creation + if __nvm_write_nvmrc_file '18.17.0' + echo ' ✅ .nvmrc file creation works' + + # Verify file content + if test -f .nvmrc + set content (cat .nvmrc) + if test \"$content\" = \"18.17.0\" + echo ' ✅ .nvmrc content correct' + else + echo ' ❌ .nvmrc content incorrect: $content' + exit 1 + end + end + else + echo ' ❌ .nvmrc file creation failed' + exit 1 + end +" + +# Test 5: Backup functionality +echo "" +echo "📋 Test 5: Backup functionality" +cd $TEST_ROOT + +# Create test .nvmrc +echo "16.20.2" > .nvmrc + +fish -c " + source "$ORIGINAL_PWD/nvm.fish" + + # Test backup function + if __nvm_backup_nvmrc + echo ' ✅ Backup function works' + + # Check backup was created + if test -d .nvm + set backup_files (count .nvm/.nvmrc_* 2>/dev/null) + if test $backup_files -gt 0 + echo ' ✅ Backup file created' + else + echo ' ❌ No backup files found' + exit 1 + end + end + else + echo ' ❌ Backup function failed' + exit 1 + end +" + +echo "" +echo "🎉 All CI tests passed!" +echo "✅ nvm-fish is ready for release" \ No newline at end of file