242 lines
7.9 KiB
Text
242 lines
7.9 KiB
Text
#!/usr/bin/env nu
|
|
# Main version management interface
|
|
# Completely configuration-driven, no hardcoded components
|
|
|
|
# Selective imports (ADR-025 Phase 3 Layer 2).
|
|
use domain/version/core.nu [check-version]
|
|
use domain/version/loader.nu [discover-configurations load-configuration-file]
|
|
use domain/version/formatter.nu [format-results]
|
|
use primitives/io/interface.nu [_print]
|
|
|
|
# Check versions for discovered components
|
|
export def check-versions [
|
|
--path: string = "" # Base path to search
|
|
--types: list = [] # Filter by types
|
|
--fetch-latest = false # Fetch latest versions
|
|
--respect-fixed = true # Respect fixed flag
|
|
--config-file: string = "" # Use specific config file
|
|
] {
|
|
# Load configurations
|
|
let configs = if ($config_file | is-not-empty) {
|
|
load-configuration-file $config_file
|
|
} else {
|
|
discover-configurations --base-path=$path --types=$types
|
|
}
|
|
|
|
# Check each configuration
|
|
$configs | each { |config|
|
|
check-version $config --fetch-latest=$fetch_latest --respect-fixed=$respect_fixed
|
|
}
|
|
}
|
|
|
|
# Display version status
|
|
export def show-versions [
|
|
--path: string = ""
|
|
--types: list = []
|
|
--fetch-latest = true
|
|
--group-by: string = "type"
|
|
--format: string = "table" # table, json, yaml
|
|
] {
|
|
let results = (check-versions --path=$path --types=$types --fetch-latest=$fetch_latest)
|
|
|
|
match $format {
|
|
"table" => {
|
|
format-results $results --group-by=$group_by
|
|
}
|
|
"json" => {
|
|
print ($results | to json -i 2)
|
|
}
|
|
"yaml" => {
|
|
print ($results | to yaml)
|
|
}
|
|
_ => {
|
|
format-results $results
|
|
}
|
|
}
|
|
}
|
|
|
|
# Check for available updates (does not modify configs)
|
|
export def check-available-updates [
|
|
--path: string = ""
|
|
--types: list = []
|
|
] {
|
|
let results = (check-versions --path=$path --types=$types --fetch-latest=true --respect-fixed=true)
|
|
let updates = ($results | where status == "update_available")
|
|
|
|
if ($updates | is-empty) {
|
|
_print "✅ All components are up to date"
|
|
return
|
|
}
|
|
|
|
_print "Updates available:"
|
|
_print ($updates | select id configured latest | rename id configured "latest available" | table)
|
|
|
|
# Show installation guidance for each update
|
|
for update in $updates {
|
|
let config = (discover-configurations --types=[$update.type]
|
|
| where id == $update.id
|
|
| first | default null)
|
|
|
|
if ($config | is-not-empty) {
|
|
show-installation-guidance $config $update.latest
|
|
}
|
|
}
|
|
|
|
_print $"\n💡 After installing, run 'tools apply-updates' to update configuration files"
|
|
}
|
|
|
|
# Apply updates to configuration files
|
|
export def apply-config-updates [
|
|
--path: string = ""
|
|
--types: list = []
|
|
--dry-run = false
|
|
--force = false # Update even if fixed
|
|
--auto-yes = false # Skip prompts and auto-confirm
|
|
] {
|
|
# Separate types from component ids (types are "provider", "generic"; ids are "upctl", "aws", etc.)
|
|
let all_configs = (discover-configurations --base-path=$path)
|
|
let known_types = ($all_configs | get type | uniq)
|
|
let filter_types = ($types | where { |t| $t in $known_types })
|
|
let filter_ids = ($types | where { |t| $t not-in $known_types })
|
|
|
|
# Check locally only (don't fetch latest to avoid GitHub API rate limits)
|
|
let results_local = if ($filter_types | is-empty) {
|
|
(check-versions --path=$path --fetch-latest=false --respect-fixed=(not $force))
|
|
} else {
|
|
(check-versions --path=$path --types=$filter_types --fetch-latest=false --respect-fixed=(not $force))
|
|
}
|
|
|
|
# Apply id filters if provided
|
|
let results = if ($filter_ids | length) > 0 {
|
|
$results_local | where id in $filter_ids
|
|
} else {
|
|
$results_local
|
|
}
|
|
|
|
# Find mismatches between installed and configured
|
|
let all_updates = ($results | where status in ["ahead_config", "behind_config"])
|
|
|
|
if ($all_updates | is-empty) {
|
|
_print "✅ All configurations match installed versions"
|
|
return
|
|
}
|
|
|
|
_print "Configuration updates available to match installed versions:"
|
|
_print ($all_updates | select id configured installed status | table)
|
|
|
|
if $dry_run {
|
|
_print "\n🔍 Dry run mode - no changes will be made"
|
|
return
|
|
}
|
|
|
|
if not $auto_yes {
|
|
let proceed = (input "Update configurations to match installed versions? (y/n): ")
|
|
if $proceed != "y" { return }
|
|
} else {
|
|
_print "Auto-confirming updates..."
|
|
}
|
|
|
|
# Update each component's configuration file
|
|
for update in $all_updates {
|
|
let config = (discover-configurations --types=[$update.type]
|
|
| where id == $update.id
|
|
| first | default null)
|
|
|
|
if ($config | is-not-empty) {
|
|
let source_file = $config.metadata.source_file
|
|
# Update to match installed version
|
|
update-configuration-file $source_file $update.id $update.installed
|
|
_print $"✅ Updated config ($update.id): ($update.configured) -> ($update.installed)"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Show agnostic installation guidance
|
|
export def show-installation-guidance [
|
|
config: record
|
|
version: string
|
|
] {
|
|
_print $"\n📦 To install ($config.id) ($version):"
|
|
|
|
# Show documentation/site links from configuration
|
|
if ($config.metadata.site | is-not-empty) {
|
|
_print $" • Documentation: ($config.metadata.site)"
|
|
}
|
|
|
|
# Show source repository if available
|
|
if ($config.source.type? | default "" | str contains "github") {
|
|
let repo = ($config.source.repo? | default "")
|
|
if ($repo | is-not-empty) {
|
|
_print $" • Releases: https://github.com/($repo)/releases"
|
|
}
|
|
}
|
|
|
|
# Show generic installation command if available in metadata
|
|
if ($config.metadata.install_cmd? | default "" | is-not-empty) {
|
|
_print $" • Install: ($config.metadata.install_cmd)"
|
|
}
|
|
|
|
_print $"\n🔍 Configuration updated, manual installation required"
|
|
_print $"💡 Run 'tools check ($config.id)' after installation to verify"
|
|
}
|
|
|
|
# Update configuration file
|
|
export def update-configuration-file [
|
|
file_path: string
|
|
component_id: string
|
|
new_version: string
|
|
] {
|
|
if not ($file_path | path exists) { return }
|
|
|
|
let ext = ($file_path | path parse | get extension)
|
|
|
|
match $ext {
|
|
"yaml" | "yml" => {
|
|
let data = (open $file_path)
|
|
let updated = ($data | upsert $component_id ($data | get $component_id | upsert version $new_version))
|
|
$updated | save -f $file_path
|
|
}
|
|
"json" => {
|
|
let data = (open $file_path)
|
|
let updated = ($data | upsert $component_id ($data | get $component_id | upsert version $new_version))
|
|
$updated | to json -i 2 | save -f $file_path
|
|
}
|
|
"toml" => {
|
|
# TOML update would need proper TOML writer
|
|
print $"⚠️ TOML update not implemented for ($file_path)"
|
|
}
|
|
"k" => {
|
|
# Nickel update would need Nickel parser/writer
|
|
print $"⚠️ Nickel update not implemented for ($file_path)"
|
|
}
|
|
_ => {
|
|
print $"⚠️ Unknown file type: ($ext)"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Pin/unpin component version
|
|
export def set-fixed [
|
|
component_id: string
|
|
fixed: bool
|
|
--path: string = ""
|
|
] {
|
|
let configs = (discover-configurations --base-path=$path)
|
|
let config = ($configs | where id == $component_id | first | default null)
|
|
|
|
if ($config | is-empty) {
|
|
print $"❌ Component '($component_id)' not found"
|
|
return
|
|
}
|
|
|
|
let source_file = $config.metadata.source_file
|
|
let data = (open $source_file)
|
|
let updated = ($data | upsert $component_id ($data | get $component_id | upsert fixed $fixed))
|
|
$updated | save -f $source_file
|
|
|
|
if $fixed {
|
|
print $"🔒 Pinned ($component_id) to version ($config.version)"
|
|
} else {
|
|
print $"🔓 Unpinned ($component_id)"
|
|
}
|
|
}
|