
## Summary Comprehensive repository cleanup focusing on plugin dependency management, documentation improvements, and git tracking optimization. ## Key Changes ### 🔧 Core Infrastructure - Synchronized all nu-* dependencies across plugins for version consistency - Enhanced upstream tracking and automation systems - Removed nushell directory from git tracking for cleaner repository management ### 📚 Documentation - Significantly expanded README.md with comprehensive development guides - Added detailed workflow documentation and command references - Improved plugin collection overview and usage examples ### 🧹 Repository Cleanup - Removed legacy bash scripts (build-all.sh, collect-install.sh, make_plugin.sh) - Streamlined automation through unified justfile and nushell script approach - Updated .gitignore with nushell directory and archive patterns - Removed nushell directory from git tracking to prevent unwanted changes ### 🔌 Plugin Updates - **nu_plugin_image**: Major refactoring with modular architecture improvements - **nu_plugin_hashes**: Enhanced functionality and build system improvements - **nu_plugin_highlight**: Updated for new plugin API compatibility - **nu_plugin_clipboard**: Dependency synchronization - **nu_plugin_desktop_notifications**: Version alignment - **nu_plugin_port_extension & nu_plugin_qr_maker**: Consistency updates - **nu_plugin_kcl & nu_plugin_tera**: Submodule synchronization ### 🏗️ Git Tracking Optimization - Removed nushell directory from version control for cleaner repository management - Added comprehensive .gitignore patterns for build artifacts and archives ## Statistics - 2,082 files changed - 2,373 insertions, 339,936 deletions - Net reduction of 337,563 lines (primarily from removing nushell directory tracking) ## Benefits - Complete version consistency across all plugins - Cleaner repository with optimized git tracking - Improved developer experience with streamlined workflows - Enhanced documentation and automation - Reduced repository size and complexity 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
506 lines
15 KiB
Plaintext
Executable File
506 lines
15 KiB
Plaintext
Executable File
#!/usr/bin/env nu
|
|
|
|
# Safe Merge Upstream Script
|
|
# Safely merges upstream changes while preserving local nu_* dependency versions
|
|
|
|
use lib/cargo_toml_diff.nu *
|
|
|
|
# Version check - mandatory for all plugin operations
|
|
def version_check [] {
|
|
try {
|
|
nu scripts/check_version.nu --quiet | ignore
|
|
} catch {
|
|
print "❌ Nushell version mismatch detected!"
|
|
print "🔧 Run: nu scripts/check_version.nu --fix"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# Load plugin registry
|
|
def load_registry [] {
|
|
let registry_path = "etc/plugin_registry.toml"
|
|
if not ($registry_path | path exists) {
|
|
error make {msg: "Plugin registry not found. Please run from repository root directory."}
|
|
}
|
|
open $registry_path
|
|
}
|
|
|
|
# Load exclusions configuration
|
|
def load_exclusions [] {
|
|
let exclude_path = "etc/upstream_exclude.toml"
|
|
if ($exclude_path | path exists) {
|
|
let config = open $exclude_path
|
|
{
|
|
all: ($config.exclude.plugins? | default []),
|
|
check: ($config.exclude.check.plugins? | default []),
|
|
merge: ($config.exclude.merge.plugins? | default []),
|
|
patterns: ($config.exclude.patterns.plugins? | default [])
|
|
}
|
|
} else {
|
|
{all: [], check: [], merge: [], patterns: []}
|
|
}
|
|
}
|
|
|
|
# Check if plugin should be excluded
|
|
def is_plugin_excluded [plugin_name: string, operation: string, exclusions: record] {
|
|
# Check direct exclusions
|
|
if $plugin_name in $exclusions.all {
|
|
return true
|
|
}
|
|
|
|
# Check operation-specific exclusions
|
|
let op_exclusions = match $operation {
|
|
"check" => $exclusions.check,
|
|
"merge" => $exclusions.merge,
|
|
_ => []
|
|
}
|
|
|
|
if $plugin_name in $op_exclusions {
|
|
return true
|
|
}
|
|
|
|
# Check pattern exclusions
|
|
for pattern in $exclusions.patterns {
|
|
if ($plugin_name | str contains ($pattern | str replace "*" "")) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
false
|
|
}
|
|
|
|
# Save plugin registry
|
|
def save_registry [registry: record] {
|
|
$registry | to toml | save -f "etc/plugin_registry.toml"
|
|
}
|
|
|
|
# Get current date in ISO format
|
|
def current_date [] {
|
|
date now | format date "%Y-%m-%d %H:%M:%S"
|
|
}
|
|
|
|
# Create backup branch
|
|
def create_backup [plugin_path: string] {
|
|
cd $plugin_path
|
|
|
|
let timestamp = date now | format date "%Y%m%d_%H%M%S"
|
|
let backup_branch = $"backup_before_merge_($timestamp)"
|
|
|
|
try {
|
|
git checkout -b $backup_branch
|
|
git checkout - # Return to original branch
|
|
print $" 📋 Created backup branch: ($backup_branch)"
|
|
$backup_branch
|
|
} catch {
|
|
error make {msg: "Failed to create backup branch"}
|
|
}
|
|
}
|
|
|
|
# Create temporary merge branch
|
|
def create_merge_branch [plugin_path: string] {
|
|
cd $plugin_path
|
|
|
|
let timestamp = date now | format date "%Y%m%d_%H%M%S"
|
|
let merge_branch = $"temp_merge_($timestamp)"
|
|
|
|
try {
|
|
git checkout -b $merge_branch
|
|
print $" 🔀 Created merge branch: ($merge_branch)"
|
|
$merge_branch
|
|
} catch {
|
|
error make {msg: "Failed to create merge branch"}
|
|
}
|
|
}
|
|
|
|
# Extract and preserve local nu dependencies
|
|
def preserve_local_nu_deps [plugin_path: string] {
|
|
cd $plugin_path
|
|
|
|
let cargo_toml = "Cargo.toml"
|
|
if not ($cargo_toml | path exists) {
|
|
error make {msg: "Cargo.toml not found"}
|
|
}
|
|
|
|
# Parse current local dependencies
|
|
let local_cargo = parse_cargo_toml $cargo_toml
|
|
let local_nu_deps = extract_nu_dependencies $local_cargo
|
|
|
|
print $" 💾 Preserved ($local_nu_deps | columns | length) local nu_* dependencies"
|
|
$local_nu_deps
|
|
}
|
|
|
|
# Restore local nu dependencies after merge
|
|
def restore_nu_deps [plugin_path: string, local_nu_deps: record] {
|
|
cd $plugin_path
|
|
|
|
let cargo_toml = "Cargo.toml"
|
|
let content = open $cargo_toml
|
|
|
|
# Update each nu dependency with local version
|
|
mut updated_content = $content
|
|
|
|
for dep in ($local_nu_deps | transpose key value) {
|
|
let dep_name = $dep.key
|
|
let dep_value = $dep.value
|
|
|
|
# Update the dependency in the TOML structure
|
|
$updated_content = ($updated_content | upsert dependencies.($dep_name) $dep_value)
|
|
}
|
|
|
|
# Save updated Cargo.toml
|
|
$updated_content | to toml | save -f $cargo_toml
|
|
print $" 🔧 Restored ($local_nu_deps | columns | length) local nu_* dependency versions"
|
|
}
|
|
|
|
# Perform the merge
|
|
def perform_merge [plugin_path: string, upstream_branch: string] {
|
|
cd $plugin_path
|
|
|
|
try {
|
|
print $" 🔀 Merging upstream/($upstream_branch)..."
|
|
git merge $"upstream/($upstream_branch)" --no-edit
|
|
|
|
# Check if merge was successful
|
|
let merge_status = git status --porcelain | lines
|
|
if ($merge_status | length) > 0 {
|
|
# Check if there are conflict markers
|
|
let conflicts = $merge_status | where ($it | str starts-with "UU")
|
|
if ($conflicts | length) > 0 {
|
|
print $" ❌ Merge conflicts detected"
|
|
return false
|
|
}
|
|
}
|
|
|
|
print $" ✅ Merge completed successfully"
|
|
true
|
|
} catch {
|
|
print $" ❌ Merge failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test if the project compiles after merge
|
|
def test_compilation [plugin_path: string] {
|
|
cd $plugin_path
|
|
|
|
print $" 🧪 Testing compilation..."
|
|
try {
|
|
let result = cargo check --quiet
|
|
print $" ✅ Compilation successful"
|
|
true
|
|
} catch {
|
|
print $" ❌ Compilation failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Run tests if they exist
|
|
def run_tests [plugin_path: string] {
|
|
cd $plugin_path
|
|
|
|
# Check if there are tests
|
|
let test_files = glob "**/*test*.rs" | length
|
|
if $test_files == 0 {
|
|
print $" ⏭️ No tests found, skipping"
|
|
return true
|
|
}
|
|
|
|
print $" 🧪 Running tests..."
|
|
try {
|
|
cargo test --quiet
|
|
print $" ✅ All tests passed"
|
|
true
|
|
} catch {
|
|
print $" ❌ Tests failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Rollback to original state
|
|
def rollback_changes [plugin_path: string, original_branch: string, merge_branch: string] {
|
|
cd $plugin_path
|
|
|
|
print $" 🔄 Rolling back changes..."
|
|
try {
|
|
git checkout $original_branch
|
|
git branch -D $merge_branch
|
|
print $" ✅ Rollback completed"
|
|
} catch {
|
|
print $" ⚠️ Rollback may have failed - manual intervention needed"
|
|
}
|
|
}
|
|
|
|
# Apply successful merge to main branch
|
|
def apply_merge [plugin_path: string, original_branch: string, merge_branch: string] {
|
|
cd $plugin_path
|
|
|
|
print $" ✅ Applying successful merge..."
|
|
try {
|
|
git checkout $original_branch
|
|
git merge $merge_branch --no-edit
|
|
git branch -D $merge_branch
|
|
print $" ✅ Merge applied to ($original_branch)"
|
|
true
|
|
} catch {
|
|
print $" ❌ Failed to apply merge"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Process a single plugin merge
|
|
def process_plugin_merge [plugin_name: string, plugin_config: record, force: bool, exclusions: record] {
|
|
print $"\n🔀 Processing merge for ($plugin_name)..."
|
|
|
|
# Check if plugin is excluded
|
|
if (is_plugin_excluded $plugin_name "merge" $exclusions) {
|
|
print $" 🚫 Skipping ($plugin_name) - excluded from merging"
|
|
return $plugin_config
|
|
}
|
|
|
|
let plugin_path = $plugin_config.local_path
|
|
|
|
# Validation checks
|
|
if ($plugin_config.upstream_url | is-empty) {
|
|
print $" ⏭️ Skipping ($plugin_name) - no upstream URL"
|
|
return $plugin_config
|
|
}
|
|
|
|
if not ($plugin_path | path exists) {
|
|
print $" ❌ Plugin directory not found: ($plugin_path)"
|
|
return $plugin_config
|
|
}
|
|
|
|
if ($plugin_config.status == "ok") and not $force {
|
|
print $" ✅ Plugin already marked as OK, use --force to merge anyway"
|
|
return $plugin_config
|
|
}
|
|
|
|
if ($plugin_config.status == "local_only") {
|
|
print $" 🏠 Local-only plugin, no upstream to merge"
|
|
return $plugin_config
|
|
}
|
|
|
|
cd $plugin_path
|
|
|
|
# Get current branch
|
|
let original_branch = git branch --show-current | str trim
|
|
|
|
# Check for uncommitted changes
|
|
let uncommitted = git status --porcelain | lines
|
|
if ($uncommitted | length) > 0 {
|
|
print $" ⚠️ Uncommitted changes detected. Please commit or stash them first."
|
|
return $plugin_config
|
|
}
|
|
|
|
# Fetch latest upstream
|
|
try {
|
|
git fetch upstream $plugin_config.upstream_branch
|
|
} catch {
|
|
print $" ❌ Failed to fetch upstream"
|
|
return $plugin_config
|
|
}
|
|
|
|
# Check if there are actually changes to merge
|
|
let changes = git diff $"HEAD..upstream/($plugin_config.upstream_branch)" --name-only | lines
|
|
if ($changes | length) == 0 {
|
|
print $" ✅ No changes to merge"
|
|
return ($plugin_config | upsert status "ok")
|
|
}
|
|
|
|
print $" 📋 Found ($changes | length) changed files: ($changes | str join ', ')"
|
|
|
|
# Create backup branch
|
|
let backup_branch = create_backup $plugin_path
|
|
|
|
# Preserve local nu dependencies
|
|
let local_nu_deps = preserve_local_nu_deps $plugin_path
|
|
|
|
# Create merge branch
|
|
let merge_branch = create_merge_branch $plugin_path
|
|
|
|
# Perform merge
|
|
let merge_success = perform_merge $plugin_path $plugin_config.upstream_branch
|
|
|
|
if not $merge_success {
|
|
print $" ❌ Merge failed, cleaning up..."
|
|
rollback_changes $plugin_path $original_branch $merge_branch
|
|
return ($plugin_config | upsert status "conflict")
|
|
}
|
|
|
|
# Restore local nu dependencies
|
|
restore_nu_deps $plugin_path $local_nu_deps
|
|
|
|
# Test compilation
|
|
let compile_success = test_compilation $plugin_path
|
|
|
|
if not $compile_success {
|
|
print $" ❌ Compilation failed after merge, rolling back..."
|
|
rollback_changes $plugin_path $original_branch $merge_branch
|
|
return ($plugin_config | upsert status "error")
|
|
}
|
|
|
|
# Run tests
|
|
let test_success = run_tests $plugin_path
|
|
|
|
if not $test_success {
|
|
print $" ❌ Tests failed after merge, rolling back..."
|
|
rollback_changes $plugin_path $original_branch $merge_branch
|
|
return ($plugin_config | upsert status "error")
|
|
}
|
|
|
|
# Apply the successful merge
|
|
let apply_success = apply_merge $plugin_path $original_branch $merge_branch
|
|
|
|
if not $apply_success {
|
|
print $" ❌ Failed to apply merge"
|
|
return ($plugin_config | upsert status "error")
|
|
}
|
|
|
|
# Update plugin configuration
|
|
let upstream_commit = git rev-parse $"upstream/($plugin_config.upstream_branch)" | str trim
|
|
print $" ✅ Successfully merged upstream changes!"
|
|
|
|
($plugin_config
|
|
| upsert status "ok"
|
|
| upsert last_checked_commit $upstream_commit
|
|
| upsert last_checked_date (current_date))
|
|
}
|
|
|
|
# Show merge preview
|
|
def show_merge_preview [plugin_name: string, plugin_config: record] {
|
|
let plugin_path = $plugin_config.local_path
|
|
|
|
if not ($plugin_path | path exists) {
|
|
print $"Plugin directory not found: ($plugin_path)"
|
|
return
|
|
}
|
|
|
|
cd $plugin_path
|
|
|
|
print $"🔍 Merge preview for ($plugin_name):"
|
|
print "=" * 50
|
|
|
|
try {
|
|
let changes = git diff $"HEAD..upstream/($plugin_config.upstream_branch)" --name-only | lines
|
|
print $"Files that will be changed: ($changes | length)"
|
|
for file in $changes {
|
|
print $" 📄 ($file)"
|
|
}
|
|
|
|
print "\nSample diff (first 20 lines):"
|
|
git diff $"HEAD..upstream/($plugin_config.upstream_branch)" | lines | first 20 | each {|line| print $" ($line)"}
|
|
|
|
if ($changes | length) > 20 {
|
|
print " ... (output truncated)"
|
|
}
|
|
} catch {
|
|
print "Failed to generate preview"
|
|
}
|
|
}
|
|
|
|
# Main function
|
|
def main [
|
|
plugin?: string # Specific plugin to merge
|
|
--force (-f) # Force merge even if status is OK
|
|
--preview (-p) # Show merge preview only
|
|
--all (-a) # Process all pending plugins
|
|
--help (-h) # Show help
|
|
] {
|
|
# Mandatory version check before any plugin operations
|
|
version_check
|
|
|
|
if $help {
|
|
print "Safe Merge Upstream - Nushell Plugin Upstream Merger"
|
|
print ""
|
|
print "USAGE:"
|
|
print " nu safe_merge_upstream.nu [OPTIONS] [PLUGIN]"
|
|
print ""
|
|
print "OPTIONS:"
|
|
print " --force, -f Force merge even if plugin status is OK"
|
|
print " --preview, -p Show merge preview without performing merge"
|
|
print " --all, -a Process all plugins with pending status"
|
|
print " --help, -h Show this help message"
|
|
print ""
|
|
print "EXAMPLES:"
|
|
print " nu safe_merge_upstream.nu highlight # Merge specific plugin"
|
|
print " nu safe_merge_upstream.nu --preview highlight # Preview changes"
|
|
print " nu safe_merge_upstream.nu --all # Merge all pending"
|
|
print " nu safe_merge_upstream.nu --force highlight # Force merge"
|
|
return
|
|
}
|
|
|
|
# Ensure we're in the repository root directory
|
|
if not ("nu_plugin_clipboard" | path exists) {
|
|
error make {msg: "Please run this script from the nushell-plugins repository root directory"}
|
|
}
|
|
|
|
# Load registry and exclusions
|
|
let registry = load_registry
|
|
let exclusions = load_exclusions
|
|
|
|
# Determine which plugins to process
|
|
let plugins_to_process = if $all {
|
|
$registry.plugins
|
|
| transpose key value
|
|
| where $it.value.status in ["pending", "error", "conflict"]
|
|
# Filter out excluded plugins
|
|
| where not (is_plugin_excluded $it.key "merge" $exclusions)
|
|
} else if ($plugin | is-not-empty) {
|
|
if $plugin in ($registry.plugins | columns) {
|
|
[{key: $plugin, value: ($registry.plugins | get $plugin)}]
|
|
} else {
|
|
error make {msg: $"Plugin '($plugin)' not found in registry"}
|
|
}
|
|
} else {
|
|
error make {msg: "Please specify a plugin name or use --all flag"}
|
|
}
|
|
|
|
if ($plugins_to_process | length) == 0 {
|
|
print "No plugins found to process"
|
|
return
|
|
}
|
|
|
|
# Preview mode
|
|
if $preview {
|
|
for plugin_entry in $plugins_to_process {
|
|
show_merge_preview $plugin_entry.key $plugin_entry.value
|
|
print ""
|
|
}
|
|
return
|
|
}
|
|
|
|
# Confirmation for multiple plugins
|
|
if ($plugins_to_process | length) > 1 {
|
|
print $"About to process ($plugins_to_process | length) plugins:"
|
|
for plugin_entry in $plugins_to_process {
|
|
print $" - ($plugin_entry.key) (status: ($plugin_entry.value.status))"
|
|
}
|
|
print ""
|
|
let confirm = input "Continue? [y/N]: "
|
|
if ($confirm | str downcase) != "y" {
|
|
print "Aborted"
|
|
return
|
|
}
|
|
}
|
|
|
|
# Process plugins
|
|
mut updated_registry = $registry
|
|
|
|
for plugin_entry in $plugins_to_process {
|
|
let plugin_name = $plugin_entry.key
|
|
let plugin_config = $plugin_entry.value
|
|
|
|
let updated_config = process_plugin_merge $plugin_name $plugin_config $force $exclusions
|
|
$updated_registry = ($updated_registry | upsert plugins.($plugin_name) $updated_config)
|
|
}
|
|
|
|
# Save updated registry
|
|
save_registry $updated_registry
|
|
|
|
print $"\n✅ Merge process completed!"
|
|
print "📊 Run 'nu plugin_status.nu' to see updated status"
|
|
}
|
|
|
|
if ($env.NUSHELL_EXECUTION_CONTEXT? | default "" | str contains "run") {
|
|
main
|
|
} |