use std log export def compare-versions [version1: string, version2: string] { let v1_parts = ($version1 | split row "." | each { into int }) let v2_parts = ($version2 | split row "." | each { into int }) if ($v1_parts.0 > $v2_parts.0) { return "greater" } if ($v1_parts.0 < $v2_parts.0) { return "less" } if ($v1_parts.1 > $v2_parts.1) { return "greater" } if ($v1_parts.1 < $v2_parts.1) { return "less" } if ($v1_parts.2 > $v2_parts.2) { return "greater" } if ($v1_parts.2 < $v2_parts.2) { return "less" } "equal" } export def is-version-compatible [current: string, required: string] { let comparison = (compare-versions $current $required) $comparison == "equal" or $comparison == "greater" } export def get-system-version [] { if ($env.PROVISIONING_VERS? | is-not-empty) { return $env.PROVISIONING_VERS } let cli_path = ([$env.PROVISIONING "core" "cli" "provisioning"] | path join) if ($cli_path | path exists) { let version_line = (open $cli_path | lines | where $it =~ "^# Release:" | first) if ($version_line | is-not-empty) { return ($version_line | str replace "# Release: " "" | str trim) } } "1.0.11" } export def get-workspace-metadata-path [workspace_path: string] { $workspace_path | path join ".provisioning" | path join "metadata.yaml" } export def load-workspace-metadata [workspace_path: string] { let metadata_path = (get-workspace-metadata-path $workspace_path) if not ($metadata_path | path exists) { return { version: {provisioning: "unknown", schema: "unknown", workspace_format: "unknown"} created: "unknown" last_updated: "unknown" migration_history: [] } } open $metadata_path } export def save-workspace-metadata [workspace_path: string, metadata: record] { let metadata_path = (get-workspace-metadata-path $workspace_path) let metadata_dir = ($metadata_path | path dirname) if not ($metadata_dir | path exists) { mkdir $metadata_dir } let updated_metadata = ($metadata | upsert last_updated (date now | format date "%Y-%m-%dT%H:%M:%SZ")) $updated_metadata | to yaml | save -f $metadata_path } export def init-workspace-metadata [workspace_path: string, workspace_name: string] { let system_version = (get-system-version) let metadata = { workspace: {name: $workspace_name, path: $workspace_path} version: {provisioning: $system_version, schema: "1.0.0", workspace_format: "1.0.0"} created: (date now | format date "%Y-%m-%dT%H:%M:%SZ") last_updated: (date now | format date "%Y-%m-%dT%H:%M:%SZ") migration_history: [] compatibility: {min_provisioning_version: "1.0.0", min_schema_version: "1.0.0"} } save-workspace-metadata $workspace_path $metadata $metadata } export def check-workspace-compatibility [workspace_path: string] { let metadata = (load-workspace-metadata $workspace_path) let system_version = (get-system-version) if ($metadata.version.provisioning == "unknown") { return { compatible: false, reason: "no_metadata" message: "Workspace metadata not found or corrupted" requires_migration: true, current_system: $system_version, workspace_version: "unknown" } } let workspace_version = $metadata.version.provisioning let min_required = ($metadata.compatibility?.min_provisioning_version? | default "2.0.0") let system_compatible = (is-version-compatible $system_version $min_required) if not $system_compatible { return { compatible: false, reason: "version_too_old" message: $"Provisioning system version ($system_version) is older than required ($min_required)" requires_migration: false, requires_upgrade: true current_system: $system_version, workspace_version: $workspace_version, min_required: $min_required } } let version_comparison = (compare-versions $system_version $workspace_version) if ($version_comparison == "greater") { return { compatible: true, reason: "migration_available" message: $"Workspace can be migrated from ($workspace_version) to ($system_version)" requires_migration: true, migration_optional: true current_system: $system_version, workspace_version: $workspace_version } } if ($version_comparison == "less") { return { compatible: false, reason: "workspace_too_new" message: $"Workspace version ($workspace_version) is newer than system ($system_version)" requires_migration: false, requires_upgrade: true current_system: $system_version, workspace_version: $workspace_version } } { compatible: true, reason: "version_match" message: "Workspace and system versions match" requires_migration: false current_system: $system_version, workspace_version: $workspace_version } } export def add-migration-record [ workspace_path: string from_version: string to_version: string migration_type: string success: bool notes?: string ] { let metadata = (load-workspace-metadata $workspace_path) let migration_record = { from_version: $from_version, to_version: $to_version, migration_type: $migration_type timestamp: (date now | format date "%Y-%m-%dT%H:%M:%SZ") success: $success, notes: ($notes | default "") } let updated_metadata = ( $metadata | upsert migration_history ($metadata.migration_history | append $migration_record) | upsert version.provisioning $to_version ) save-workspace-metadata $workspace_path $updated_metadata } export def get-version-summary [workspace_path: string] { let metadata = (load-workspace-metadata $workspace_path) let system_version = (get-system-version) let compatibility = (check-workspace-compatibility $workspace_path) { system: {version: $system_version} workspace: { name: ($metadata.workspace?.name? | default "unknown") path: $workspace_path version: ($metadata.version?.provisioning? | default "unknown") schema_version: ($metadata.version?.schema? | default "unknown") format_version: ($metadata.version?.workspace_format? | default "unknown") created: ($metadata.created? | default "unknown") last_updated: ($metadata.last_updated? | default "unknown") } compatibility: $compatibility migrations: { count: ($metadata.migration_history? | default [] | length) last_migration: ($metadata.migration_history? | default [] | last | default null) } } } export def validate-workspace-structure [workspace_path: string] { mut issues = [] for dir in ["config", "infra", ".provisioning"] { let dir_path = ($workspace_path | path join $dir) if not ($dir_path | path exists) { $issues = ($issues | append { type: "missing_directory", path: $dir, severity: "error" message: $"Required directory missing: ($dir)" }) } } let config_schema_path = ($workspace_path | path join "config" | path join "provisioning.ncl") let config_yaml_path = ($workspace_path | path join "config" | path join "provisioning.yaml") if (not ($config_schema_path | path exists) and not ($config_yaml_path | path exists)) { $issues = ($issues | append { type: "missing_file" path: "config/provisioning.ncl or config/provisioning.yaml" severity: "error" message: "Main configuration file missing (provisioning.ncl or provisioning.yaml required)" }) } let metadata_path = (get-workspace-metadata-path $workspace_path) if not ($metadata_path | path exists) { $issues = ($issues | append { type: "missing_metadata", path: ".provisioning/metadata.yaml", severity: "warning" message: "Workspace metadata missing - run migration" }) } { valid: (($issues | where severity == "error" | length) == 0) issues: $issues warnings: ($issues | where severity == "warning" | length) errors: ($issues | where severity == "error" | length) } }