nushell-plugins/scripts/check_upstream_changes.nu

357 lines
11 KiB
Plaintext
Raw Permalink Normal View History

feat: major repository modernization and tracking cleanup ## 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>
2025-09-20 15:18:58 +01:00
#!/usr/bin/env nu
# Check Upstream Changes Script
# Automatically checks for upstream changes and marks plugins as OK when only nu_* dependencies differ
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"
}
# Add or update git remote for upstream
def setup_upstream_remote [plugin_path: string, upstream_url: string] {
if ($upstream_url | is-empty) {
return
}
cd $plugin_path
# Check if upstream remote exists
let remotes = git remote | lines
if not ("upstream" in $remotes) {
print $"Adding upstream remote for ($plugin_path)..."
git remote add upstream $upstream_url
} else {
# Update upstream URL if it changed
let current_url = git remote get-url upstream | str trim
if $current_url != $upstream_url {
print $"Updating upstream remote URL for ($plugin_path)..."
git remote set-url upstream $upstream_url
}
}
}
# Fetch upstream changes without merging
def fetch_upstream [plugin_path: string, upstream_branch: string] {
cd $plugin_path
try {
print $"Fetching upstream changes for ($plugin_path)..."
git fetch upstream $upstream_branch
true
} catch {
print $"Failed to fetch upstream for ($plugin_path)"
false
}
}
# Get latest upstream commit hash
def get_upstream_commit [plugin_path: string, upstream_branch: string] {
cd $plugin_path
try {
git rev-parse $"upstream/($upstream_branch)" | str trim
} catch {
""
}
}
# Check if there are differences between local and upstream
def has_upstream_changes [plugin_path: string, upstream_branch: string] {
cd $plugin_path
try {
let diff_output = git diff $"HEAD..upstream/($upstream_branch)" --name-only | lines
($diff_output | length) > 0
} catch {
false
}
}
# Create temporary upstream version of Cargo.toml for comparison
def create_upstream_cargo_toml [plugin_path: string, upstream_branch: string] {
cd $plugin_path
let temp_file = "Cargo.toml.upstream"
try {
git show $"upstream/($upstream_branch):Cargo.toml" | save $temp_file
$temp_file
} catch {
""
}
}
# Check for source code changes (non-Cargo.toml)
def has_source_changes [plugin_path: string, upstream_branch: string] {
cd $plugin_path
try {
let changed_files = git diff $"HEAD..upstream/($upstream_branch)" --name-only | lines
let source_changes = $changed_files | where ($it =~ "\\.rs$") or ($it == "README.md") or ($it == "LICENSE")
($source_changes | length) > 0
} catch {
false
}
}
# Process a single plugin
def process_plugin [plugin_name: string, plugin_config: record, nu_managed_deps: list<string>, exclusions: record] {
print $"\n🔍 Checking ($plugin_name)..."
# Check if plugin is excluded
if (is_plugin_excluded $plugin_name "check" $exclusions) {
print $" 🚫 Skipping ($plugin_name) - excluded from upstream checking"
return $plugin_config
}
let plugin_path = $plugin_config.local_path
# Skip if no upstream URL
if ($plugin_config.upstream_url | is-empty) {
print $" ⏭️ Skipping ($plugin_name) - no upstream URL"
return $plugin_config
}
# Check if plugin directory exists
if not ($plugin_path | path exists) {
print $" ❌ Plugin directory not found: ($plugin_path)"
return ($plugin_config | upsert status "error")
}
# Setup upstream remote
setup_upstream_remote $plugin_path $plugin_config.upstream_url
# Fetch upstream changes
if not (fetch_upstream $plugin_path $plugin_config.upstream_branch) {
print $" ❌ Failed to fetch upstream changes"
return ($plugin_config | upsert status "error")
}
# Get latest upstream commit
let upstream_commit = get_upstream_commit $plugin_path $plugin_config.upstream_branch
if ($upstream_commit | is-empty) {
print $" ❌ Could not get upstream commit hash"
return ($plugin_config | upsert status "error")
}
# Check if commit changed since last check
if $plugin_config.last_checked_commit == $upstream_commit {
print $" ✅ No new upstream changes since last check"
return ($plugin_config | upsert last_checked_date (current_date))
}
# Check if there are any changes
if not (has_upstream_changes $plugin_path $plugin_config.upstream_branch) {
print $" ✅ Local is up to date with upstream"
return ($plugin_config
| upsert status "ok"
| upsert last_checked_commit $upstream_commit
| upsert last_checked_date (current_date))
}
print $" 📋 Changes detected, analyzing..."
# Check for source code changes
let has_source = has_source_changes $plugin_path $plugin_config.upstream_branch
if $has_source {
print $" ⚠️ Source code changes detected - requires manual review"
return ($plugin_config
| upsert status "pending"
| upsert last_checked_commit $upstream_commit
| upsert last_checked_date (current_date))
}
# Create upstream Cargo.toml for comparison
let upstream_cargo_path = create_upstream_cargo_toml $plugin_path $plugin_config.upstream_branch
if ($upstream_cargo_path | is-empty) {
print $" ❌ Could not extract upstream Cargo.toml"
return ($plugin_config | upsert status "error")
}
# Compare Cargo.toml files
let local_cargo = $"($plugin_path)/Cargo.toml"
try {
let diff_result = compare_cargo_tomls $local_cargo $"($plugin_path)/($upstream_cargo_path)"
# Clean up temporary file
rm $"($plugin_path)/($upstream_cargo_path)"
if not $diff_result.analysis.has_changes {
print $" ✅ No meaningful changes in Cargo.toml"
return ($plugin_config
| upsert status "ok"
| upsert last_checked_commit $upstream_commit
| upsert last_checked_date (current_date))
}
# Check if safe for auto-OK
if ($plugin_config.auto_ok_on_nu_deps_only) and (is_safe_for_auto_ok $diff_result $nu_managed_deps) {
print $" ✅ AUTO-OK: Only nu_* dependency changes detected"
let summary = generate_diff_summary $diff_result
print $" Changes:\n($summary | str replace --all '\n' '\n ')"
return ($plugin_config
| upsert status "ok"
| upsert last_checked_commit $upstream_commit
| upsert last_checked_date (current_date))
} else {
print $" ⚠️ PENDING: Non-nu dependency changes require manual review"
let summary = generate_diff_summary $diff_result
print $" Changes:\n($summary | str replace --all '\n' '\n ')"
return ($plugin_config
| upsert status "pending"
| upsert last_checked_commit $upstream_commit
| upsert last_checked_date (current_date))
}
} catch {|err|
print $" ❌ Error comparing Cargo.toml files: ($err.msg)"
# Clean up on error
try { rm $"($plugin_path)/($upstream_cargo_path)" } catch { }
return ($plugin_config | upsert status "error")
}
}
# Main function
def main [
--plugin (-p): string = "" # Check specific plugin only
--verbose (-v) # Verbose output
] {
# Mandatory version check before any plugin operations
version_check
print "🚀 Checking upstream changes for nushell plugins..."
# 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
# Get managed nu dependencies
let nu_managed_deps = $registry.settings.nu_managed_dependencies
# Process plugins
mut updated_registry = $registry
let plugins_to_check = if ($plugin | is-empty) {
$registry.plugins | transpose key value
} else {
if $plugin in ($registry.plugins | columns) {
[{key: $plugin, value: ($registry.plugins | get $plugin)}]
} else {
error make {msg: $"Plugin '($plugin)' not found in registry"}
}
}
for plugin_entry in $plugins_to_check {
let plugin_name = $plugin_entry.key
let plugin_config = $plugin_entry.value
let updated_config = process_plugin $plugin_name $plugin_config $nu_managed_deps $exclusions
$updated_registry = ($updated_registry | upsert $"plugins.($plugin_name)" $updated_config)
}
# Save updated registry
save_registry $updated_registry
print "\n📊 Summary:"
let status_counts = $updated_registry.plugins
| values
| group-by status
| transpose status count
| each {|entry| {status: $entry.status, count: ($entry.count | length)}}
for status in $status_counts {
let emoji = match $status.status {
"ok" => "✅",
"pending" => "⚠️",
"error" => "❌",
"local_only" => "🏠",
"unknown" => "❓",
_ => "📦"
}
print $" ($emoji) ($status.status): ($status.count) plugins"
}
print $"\n🔄 Registry updated: etc/plugin_registry.toml"
print "💡 Run 'bash scripts/run.sh plugin_status.nu' to see detailed status"
}
if ($env.NUSHELL_EXECUTION_CONTEXT? | default "" | str contains "run") {
main
}