# Workspace Documentation Generator # Generates deployment, configuration, and troubleshooting guides from Jinja2 templates # Uses workspace metadata to populate guide variables use tools/nickel/process.nu [ncl-eval] def extract-workspace-metadata [workspace_path: string] { { workspace_path: $workspace_path, config_path: $"($workspace_path)/config/config.ncl", } } def extract-workspace-name [metadata: record] { ncl-eval ($metadata.workspace_path | path join "config/config.ncl") [$metadata.workspace_path] | get workspace.name } def extract-provider-config [metadata: record] { let config = (ncl-eval ($metadata.workspace_path | path join "config/config.ncl") [$metadata.workspace_path]) let providers = $config.providers let provider_names = ($providers | columns) let provider_list = ( $provider_names | each { |name| { name: $name, enabled: (($providers | get $name).enabled) } } ) let first_enabled_provider = ( $provider_list | where enabled == true | first | get name ) { name: $first_enabled_provider, enabled: true } } def extract-infrastructures [workspace_path: string] { let infra_dir = $"($workspace_path)/infra" if ($infra_dir | path exists) { ls $infra_dir | where type == dir | get name | each { |path| $path | path basename } } else { [] } } def extract-servers [workspace_path: string, infra: string] { let servers_file = $"($workspace_path)/infra/($infra)/servers.ncl" if ($servers_file | path exists) { let exported = (ncl-eval $servers_file [$workspace_path]) $exported.servers } else { [] } } def extract-taskservs [workspace_path: string, infra: string] { let taskservs_dir = $"($workspace_path)/infra/($infra)/taskservs" if ($taskservs_dir | path exists) { ls $taskservs_dir | where name ends-with .ncl | get name | each { |path| $path | path basename | str replace --regex '\.ncl$' '' } } else { [] } } def generate-guide [template_path: string, output_path: string, variables: record] { let output_dir = ($output_path | path dirname) if not ($output_dir | path exists) { mkdir $output_dir } let rendered = (tera-render $template_path $variables) $rendered | save --force $output_path } export def generate-all-guides [workspace_path: string, template_dir: string, output_dir: string] { let metadata = (extract-workspace-metadata $workspace_path) let workspace_name = (extract-workspace-name $metadata) let provider_info = (extract-provider-config $metadata) let all_infra = (extract-infrastructures $workspace_path) # Filter out library/technical directories let infrastructures = ($all_infra | where $it != "lib") let default_infra = if ($infrastructures | is-empty) { "default" } else { $infrastructures | first } let extracted_servers = (extract-servers $workspace_path $default_infra) let taskservs = (extract-taskservs $workspace_path $default_infra) # Map server fields to template-friendly names let servers = ( $extracted_servers | each { |srv| let stg = if (($srv.storages | length) > 0) { ($srv.storages | get 0).total } else { 0 } { name: $srv.hostname, plan: $srv.plan, storage: $stg, provider: $srv.provider, zone: $srv.zone } } ) let variables = { workspace_name: $workspace_name, workspace_path: $workspace_path, workspace_description: "Workspace infrastructure deployment", primary_provider: $provider_info.name, primary_zone: "es-mad1", alternate_zone: "nl-ams1", default_infra: $default_infra, providers: [$provider_info.name], infrastructures: $infrastructures, servers: $servers, taskservs: $taskservs, pricing_estimate: "€30-40/month", provider_url: "https://hub.upcloud.com", provider_api_url: "https://upcloud.com/api/", provider_api_host: "api.upcloud.com", provider_status_url: "https://status.upcloud.com", provider_env_vars: { "UPCLOUD_USER": "username", "UPCLOUD_PASSWORD": "password", }, provider_defaults: { "api_timeout": "30", }, provider_zone_defaults: { "zone": "es-mad1", "plan": "2xCPU-4GB", }, infrastructure_purposes: { "wuji": "Kubernetes cluster for production workloads", "sgoyol": "Development and testing environment", }, server_plans: [ "1xCPU-1GB", "1xCPU-2GB", "2xCPU-4GB", "2xCPU-8GB", "4xCPU-8GB", "4xCPU-16GB", ], available_zones: [ "us-east-1", "us-west-1", "nl-ams1", "es-mad1", "fi-hel1", ], provider_config_example: { "username": "your-username", "password": "your-password", "default-zone": "es-mad1", }, } print $"Generating guides for workspace: ($workspace_name)" let guides = [ { template: "deployment-guide.md.j2", output: "deployment-guide.md", }, { template: "configuration-guide.md.j2", output: "configuration-guide.md", }, { template: "troubleshooting.md.j2", output: "troubleshooting.md", }, { template: "README.md.j2", output: "README.md", }, ] $guides | each { |guide| let template_path = $"($template_dir)/($guide.template)" let output_path = $"($output_dir)/($guide.output)" print $" Generating ($guide.output)..." generate-guide $template_path $output_path $variables } print "Documentation generation complete!" } def main [workspace_path: string] { # Get absolute paths - resolve from project root let current_dir = (pwd) let abs_workspace_path = (($workspace_path | path expand) | if (($in | path type) == relative) { ($"($current_dir)/($in)") } else { $in }) let template_dir = ($"($current_dir)/provisioning/templates/docs" | path expand) let output_dir = ($"($abs_workspace_path)/docs" | path expand) if not ($template_dir | path exists) { print $"Template directory not found at ($template_dir)" } else { generate-all-guides $abs_workspace_path $template_dir $output_dir } }