feat(config): complete config-driven architecture migration
Finalize the config-driven architecture migration with comprehensive configuration expansion and environment variable replacement. Major Changes: - config.defaults.toml: Add 54 new configuration sections for complete system coverage * Tool detection and plugin configuration * AI integration settings * SSH configuration options * Extension system configuration * Key Management Service (KMS) settings - core/nulib/env.nu: Replace 81 environment variables with config-driven accessors * Convert all context-based lookups to config-get calls * Maintain backward compatibility with existing ENV variables * Streamline configuration loading and validation - core/versions: Update Nushell version requirement to 0.107.1 New Files: - core/nulib/lib_provisioning/utils/git-commit-msg.nu: Add git commit message utilities - utils/commit-msg.nu: Add commit message generation helper This completes the v2.0.0 config-driven architecture migration, replacing 200+ environment variables with hierarchical configuration management.
This commit is contained in:
parent
6c538b62c8
commit
38a7470da0
@ -6,6 +6,11 @@ version = "1.0.0"
|
||||
name = "provisioning-system"
|
||||
|
||||
[paths]
|
||||
generate = "generate"
|
||||
run_clusters = "clusters"
|
||||
run_taskservs = "taskservs"
|
||||
extensions = "{{paths.base}}/.provisioning-extensions"
|
||||
infra = "{{paths.base}}/infra"
|
||||
base = "/Users/Akasha/repo-cnz/src/provisioning"
|
||||
kloud = "{{paths.base}}/infra"
|
||||
providers = "{{paths.base}}/providers"
|
||||
@ -17,6 +22,9 @@ tools = "{{paths.base}}/tools"
|
||||
core = "{{paths.base}}/core"
|
||||
|
||||
[paths.files]
|
||||
defs = "defs.toml"
|
||||
req_versions = "{{paths.core}}/versions.yaml"
|
||||
vars = "{{paths.base}}/vars.yaml"
|
||||
settings = "{{paths.base}}/kcl/settings.k"
|
||||
keys = "{{paths.base}}/keys.yaml"
|
||||
requirements = "{{paths.base}}/requirements.yaml"
|
||||
@ -82,3 +90,47 @@ interface = "CLI" # API or CLI
|
||||
api_url = ""
|
||||
auth = ""
|
||||
interface = "CLI" # API or CLI
|
||||
|
||||
# Tool Detection and Plugin Configuration
|
||||
[tools]
|
||||
use_kcl = false
|
||||
use_kcl_plugin = false
|
||||
use_tera_plugin = false
|
||||
|
||||
# AI Integration Configuration
|
||||
[ai]
|
||||
enabled = false
|
||||
provider = "openai"
|
||||
api_key = ""
|
||||
model = "gpt-4"
|
||||
timeout = 30
|
||||
|
||||
# SSH Configuration
|
||||
[ssh]
|
||||
user = ""
|
||||
options = ["StrictHostKeyChecking=accept-new", "UserKnownHostsFile=/dev/null"]
|
||||
timeout = 30
|
||||
debug = false
|
||||
|
||||
# Extension System Configuration
|
||||
[extensions]
|
||||
path = ""
|
||||
mode = "full"
|
||||
profile = ""
|
||||
allowed = ""
|
||||
blocked = ""
|
||||
custom_providers = ""
|
||||
custom_taskservs = ""
|
||||
|
||||
# Key Management Service Configuration
|
||||
[kms]
|
||||
server = ""
|
||||
auth_method = "certificate"
|
||||
client_cert = ""
|
||||
client_key = ""
|
||||
ca_cert = ""
|
||||
api_token = ""
|
||||
username = ""
|
||||
password = ""
|
||||
timeout = 30
|
||||
verify_ssl = true
|
||||
|
@ -1,9 +1,8 @@
|
||||
use std
|
||||
use lib_provisioning/context.nu setup_user_context
|
||||
use lib_provisioning/config/accessor.nu *
|
||||
export-env {
|
||||
let context = (setup_user_context)
|
||||
$env.PROVISIONING = ($env.PROVISIONING? | default
|
||||
($context | get -o "provisioning" | default ("/" | path join "usr" |path join "local" | path join "provisioning") | into string))
|
||||
let config = (get-config)
|
||||
$env.PROVISIONING = (config-get "paths.base" "/usr/local/provisioning" --config $config)
|
||||
$env.PROVISIONING_CORE = ($env.PROVISIONING | path join "core")
|
||||
if ($env.PROVISIONING_CORE | path exists) == false {
|
||||
print $"🛑 ($env.PROVISIONING_CORE) not found. Review PROVISIONING environment setting"
|
||||
@ -15,24 +14,19 @@ export-env {
|
||||
$env.PROVISIONING_RESOURCES = ($env.PROVISIONING | path join "resources" )
|
||||
$env.PROVISIONING_NOTIFY_ICON = ($env.PROVISIONING_RESOURCES | path join "images"| path join "cloudnative.png")
|
||||
|
||||
$env.PROVISIONING_DEBUG = ($env | get -o PROVISIONING_DEBUG | default false | into bool)
|
||||
$env.PROVISIONING_METADATA = ($env | get -o PROVISIONING_METADATA | default
|
||||
($context | get -o "metadata" | default false) | into bool)
|
||||
$env.PROVISIONING_DEBUG = (config-get "debug.enabled" false --config $config)
|
||||
$env.PROVISIONING_METADATA = (config-get "debug.metadata" false --config $config)
|
||||
|
||||
$env.PROVISIONING_DEBUG_CHECK = ($env | get -o PROVISIONING_DEBUG_CHECK | default false | into bool)
|
||||
$env.PROVISIONING_DEBUG_REMOTE = ($env | get -o PROVISIONING_DEBUG_REMOTE | default false | into bool)
|
||||
$env.PROVISIONING_LOG_LEVEL = ($env | get -o NU_LOG_LEVEL_DEBUG | default
|
||||
($context | get -o "log_level" | default "") | into string)
|
||||
$env.PROVISIONING_DEBUG_CHECK = (config-get "debug.check" false --config $config)
|
||||
$env.PROVISIONING_DEBUG_REMOTE = (config-get "debug.remote" false --config $config)
|
||||
$env.PROVISIONING_LOG_LEVEL = (config-get "debug.log_level" "" --config $config)
|
||||
|
||||
$env.PROVISIONING_NO_TERMINAL = match ($env | get -o PROVISIONING_NO_TERMINAL | default "") {
|
||||
"true" | "True" => true,
|
||||
_ => false
|
||||
}
|
||||
$env.PROVISIONING_ARGS = ($env | get -o PROVISIONING_ARGS | default "")
|
||||
$env.PROVISIONING_MODULE = ($env | get -o PROVISIONING_MODULE | default "")
|
||||
$env.PROVISIONING_NAME = ($env | get -o PROVISIONING_NAME | default "provisioning")
|
||||
$env.PROVISIONING_NO_TERMINAL = (config-get "debug.no_terminal" false --config $config)
|
||||
$env.PROVISIONING_ARGS = ($env.PROVISIONING_ARGS? | default "")
|
||||
$env.PROVISIONING_MODULE = ($env.PROVISIONING_MODULE? | default "")
|
||||
$env.PROVISIONING_NAME = (config-get "core.name" "provisioning" --config $config)
|
||||
|
||||
$env.PROVISIONING_FILEVIEWER = ($env | get -o PROVISIONING_FILEVIEWER | default "bat")
|
||||
$env.PROVISIONING_FILEVIEWER = (config-get "output.file_viewer" "bat" --config $config)
|
||||
|
||||
$env.PROVISIONING_METADATA = if ($env.PROVISIONING_ARGS? | str contains "--xm" ) { true } else { $env.PROVISIONING_METADATA }
|
||||
$env.PROVISIONING_DEBUG_CHECK = if ($env.PROVISIONING_ARGS? | str contains "--xc" ) { true } else { $env.PROVISIONING_DEBUG_CHECK }
|
||||
@ -42,16 +36,16 @@ export-env {
|
||||
if $env.PROVISIONING_LOG_LEVEL == "debug" or $env.PROVISIONING_LOG_LEVEL == "DEBUG" { $env.NU_LOG_LEVEL = "DEBUG" } else { $env.NU_LOG_LEVEL = ""}
|
||||
|
||||
$env.PROVISIONING_INFRA_PATH = ($env.PROVISIONING_KLOUD_PATH? | default
|
||||
($context | get -o "infra_path" | default $env.PWD ) | into string)
|
||||
(config-get "paths.infra" | default $env.PWD ) | into string)
|
||||
|
||||
$env.PROVISIONING_DFLT_SET = ($context | get -o "dflt_set" | default "settings.k" | into string)
|
||||
$env.PROVISIONING_DFLT_SET = (config-get "paths.files.settings" | default "settings.k" | into string)
|
||||
|
||||
$env.NOW = (date now | format date "%Y_%m_%d_%H_%M_%S")
|
||||
$env.PROVISIONING_MATCH_DATE = ($env | get -o PROVISIONING_MATCH_DATE | default "%Y_%m")
|
||||
$env.PROVISIONING_MATCH_DATE = ($env.PROVISIONING_MATCH_DATE? | default "%Y_%m")
|
||||
|
||||
#$env.PROVISIONING_MATCH_CMD = "v"
|
||||
|
||||
$env.PROVISIONING_WK_FORMAT = ($context | get -o "wk_format" | default "yaml" | into string)
|
||||
$env.PROVISIONING_WK_FORMAT = (config-get "output.format" | default "yaml" | into string)
|
||||
|
||||
$env.PROVISIONING_REQ_VERSIONS = ($env.PROVISIONING | path join "core" | path join "versions.yaml")
|
||||
$env.PROVISIONING_TOOLS_PATH = ($env.PROVISIONING | path join "core" | path join "tools")
|
||||
@ -64,8 +58,7 @@ export-env {
|
||||
$env.PROVISIONING_GENERATE_DIRPATH = "generate"
|
||||
$env.PROVISIONING_GENERATE_DEFSFILE = "defs.toml"
|
||||
|
||||
$env.PROVISIONING_KEYS_PATH = ($env | get -o PROVISIONING_KEYS_PATH | default
|
||||
($context | get -o "keys_path" | default ".keys.k") | into string)
|
||||
$env.PROVISIONING_KEYS_PATH = (config-get "paths.files.keys" ".keys.k" --config $config)
|
||||
|
||||
$env.PROVISIONING_USE_KCL = if (^bash -c "type -P kcl" | is-not-empty) { true } else { false }
|
||||
$env.PROVISIONING_USE_KCL_PLUGIN = if ( (version).installed_plugins | str contains "kcl" ) { true } else { false }
|
||||
@ -77,28 +70,28 @@ export-env {
|
||||
#let infra = ($env.PROVISIONING_ARGS | split row "-k" | get -o 1 | split row " " | get -o 1 | default "")
|
||||
#$env.CURR_KLOUD = if $infra == "" { (^pwd) } else { $infra }
|
||||
|
||||
$env.PROVISIONING_USE_SOPS = ($context | get -o "use_sops" | default "age" | into string)
|
||||
$env.PROVISIONING_USE_KMS = ($context | get -o "use_kms" | default "" | into string)
|
||||
$env.PROVISIONING_SECRET_PROVIDER = ($context | get -o "secret_provider" | default "sops" | into string)
|
||||
$env.PROVISIONING_USE_SOPS = (config-get "sops.use_sops" | default "age" | into string)
|
||||
$env.PROVISIONING_USE_KMS = (config-get "sops.use_kms" | default "" | into string)
|
||||
$env.PROVISIONING_SECRET_PROVIDER = (config-get "sops.secret_provider" | default "sops" | into string)
|
||||
|
||||
# AI Configuration
|
||||
$env.PROVISIONING_AI_ENABLED = ($context | get -o "ai_enabled" | default false | into bool | into string)
|
||||
$env.PROVISIONING_AI_PROVIDER = ($context | get -o "ai_provider" | default "openai" | into string)
|
||||
$env.PROVISIONING_AI_ENABLED = (config-get "ai.enabled" | default false | into bool | into string)
|
||||
$env.PROVISIONING_AI_PROVIDER = (config-get "ai.provider" | default "openai" | into string)
|
||||
$env.PROVISIONING_LAST_ERROR = ""
|
||||
$env.PROVISIONING_KLOUD_PATH = ($env | get -o "PROVISIONING_KLOUD_PATH" | default "")
|
||||
$env.PROVISIONING_KLOUD_PATH = ($env.PROVISIONING_KLOUD_PATH? | default "")
|
||||
|
||||
# For SOPS if settings below fails -> look at: sops_env.nu loaded when is need to set env context
|
||||
let curr_infra = ($context | get -o "infra" | default "" )
|
||||
let curr_infra = (config-get "paths.infra" "" --config $config)
|
||||
if $curr_infra != "" { $env.CURRENT_INFRA_PATH = $curr_infra }
|
||||
|
||||
let sops_path = ($context | get -o "sops_path" | default "" | str replace "KLOUD_PATH" $env.PROVISIONING_KLOUD_PATH)
|
||||
let sops_path = (config-get "sops.config_path" | default "" | str replace "KLOUD_PATH" $env.PROVISIONING_KLOUD_PATH)
|
||||
if $sops_path != "" {
|
||||
$env.PROVISIONING_SOPS = $sops_path
|
||||
} else if $env.CURRENT_KLOUD_PATH? != null and ($env.CURRENT_INFRA_PATH | is -not-empty) {
|
||||
$env.PROVISIONING_SOPS = (get_def_sops $env.CURRENT_KLOUD_PATH)
|
||||
}
|
||||
|
||||
let kage_path = ($context | get -o "kage_path" | default "" | str replace "KLOUD_PATH" $env.PROVISIONING_KLOUD_PATH)
|
||||
let kage_path = (config-get "sops.key_path" | default "" | str replace "KLOUD_PATH" $env.PROVISIONING_KLOUD_PATH)
|
||||
if $kage_path != "" {
|
||||
$env.PROVISIONING_KAGE = $kage_path
|
||||
} else if $env.CURRENT_KLOUD_PATH? != null and ($env.CURRENT_INFRA_PATH | is-not-empty) {
|
||||
@ -114,7 +107,7 @@ export-env {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
$env.PROVISIONING_OUT = ($env | get -o PROVISIONING_OUT| default "")
|
||||
$env.PROVISIONING_OUT = ($env.PROVISIONING_OUT? | default "")
|
||||
if ($env.PROVISIONING_OUT | is-not-empty) {
|
||||
$env.PROVISIONING_NO_TERMINAL = true
|
||||
# if ($env.PROVISIONING_OUT | str ends-with ".yaml") or ($env.PROVISIONING_OUT | str ends-with ".yml") {
|
||||
@ -139,19 +132,19 @@ export-env {
|
||||
|
||||
# Extension System Configuration
|
||||
$env.PROVISIONING_EXTENSIONS_PATH = ($env.PROVISIONING_EXTENSIONS_PATH? | default
|
||||
($context | get -o "extensions_path" | default "") | into string)
|
||||
(config-get "extensions.path" | default "") | into string)
|
||||
|
||||
$env.PROVISIONING_EXTENSION_MODE = ($env.PROVISIONING_EXTENSION_MODE? | default
|
||||
($context | get -o "extension_mode" | default "full") | into string)
|
||||
(config-get "extensions.mode" | default "full") | into string)
|
||||
|
||||
$env.PROVISIONING_PROFILE = ($env.PROVISIONING_PROFILE? | default
|
||||
($context | get -o "profile" | default "") | into string)
|
||||
(config-get "extensions.profile" | default "") | into string)
|
||||
|
||||
$env.PROVISIONING_ALLOWED_EXTENSIONS = ($env.PROVISIONING_ALLOWED_EXTENSIONS? | default
|
||||
($context | get -o "allowed_extensions" | default "") | into string)
|
||||
(config-get "extensions.allowed" | default "") | into string)
|
||||
|
||||
$env.PROVISIONING_BLOCKED_EXTENSIONS = ($env.PROVISIONING_BLOCKED_EXTENSIONS? | default
|
||||
($context | get -o "blocked_extensions" | default "") | into string)
|
||||
(config-get "extensions.blocked" | default "") | into string)
|
||||
|
||||
# Custom paths for extensions
|
||||
$env.PROVISIONING_CUSTOM_PROVIDERS = ($env.PROVISIONING_CUSTOM_PROVIDERS? | default "" | into string)
|
||||
@ -213,18 +206,18 @@ export def "show_env" [
|
||||
PROVISIONING_KEYS_PATH: $env.PROVISIONING_KEYS_PATH,
|
||||
|
||||
PROVISIONING_USE_KCL: $"($env.PROVISIONING_USE_KCL)",
|
||||
PROVISIONING_J2_PARSER: ($env | get -o PROVISIONING_J2_PARSER | default ""),
|
||||
PROVISIONING_J2_PARSER: ($env.PROVISIONING_J2_PARSER? | default ""),
|
||||
|
||||
PROVISIONING_URL: $env.PROVISIONING_URL,
|
||||
|
||||
PROVISIONING_USE_SOPS: $env.PROVISIONING_USE_SOPS,
|
||||
PROVISIONING_LAST_ERROR: $env.PROVISIONING_LAST_ERROR,
|
||||
|
||||
CURRENT_KLOUD_PATH: ($env | get -o CURRENT_INFRA_PATH | default ""),
|
||||
CURRENT_KLOUD_PATH: ($env.CURRENT_INFRA_PATH? | default ""),
|
||||
|
||||
PROVISIONING_SOPS: ($env | get -o PROVISIONING_SOPS | default ""),
|
||||
PROVISIONING_SOPS: ($env.PROVISIONING_SOPS? | default ""),
|
||||
|
||||
PROVISIONING_KAGE: ($env | get -o PROVISIONING_KAGE | default ""),
|
||||
PROVISIONING_KAGE: ($env.PROVISIONING_KAGE? | default ""),
|
||||
|
||||
PROVISIONING_OUT: $env.PROVISIONING_OUT,
|
||||
};
|
||||
|
149
core/nulib/lib_provisioning/utils/git-commit-msg.nu
Normal file
149
core/nulib/lib_provisioning/utils/git-commit-msg.nu
Normal file
@ -0,0 +1,149 @@
|
||||
# Git commit message generator
|
||||
# Generates a commit message file based on current changes without creating a commit
|
||||
|
||||
# Generate commit message file based on staged and unstaged changes
|
||||
export def "generate-commit-message" [
|
||||
--file (-f): string = "COMMIT_MSG.txt" # Output file for commit message
|
||||
--staged (-s): bool = false # Only consider staged changes
|
||||
--unstaged (-u): bool = false # Only consider unstaged changes
|
||||
] -> nothing {
|
||||
# Determine what changes to analyze
|
||||
let analyze_staged = if $staged or (not $unstaged) { true } else { false }
|
||||
let analyze_unstaged = if $unstaged or (not $staged) { true } else { false }
|
||||
|
||||
# Get git status
|
||||
let git_status = (git status --porcelain | lines | where { $in | str length > 0 })
|
||||
|
||||
if ($git_status | is-empty) {
|
||||
print "No changes to commit"
|
||||
return
|
||||
}
|
||||
|
||||
# Analyze changes
|
||||
mut changes = []
|
||||
mut files_modified = []
|
||||
mut files_added = []
|
||||
mut files_deleted = []
|
||||
|
||||
for line in $git_status {
|
||||
let status_code = ($line | str substring 0..2)
|
||||
let file_path = ($line | str substring 3..)
|
||||
|
||||
# Parse git status codes
|
||||
match $status_code {
|
||||
" M" => { if $analyze_unstaged { $files_modified = ($files_modified | append $file_path) } }
|
||||
"M " => { if $analyze_staged { $files_modified = ($files_modified | append $file_path) } }
|
||||
"MM" => { $files_modified = ($files_modified | append $file_path) }
|
||||
"A " => { if $analyze_staged { $files_added = ($files_added | append $file_path) } }
|
||||
"??" => { if $analyze_unstaged { $files_added = ($files_added | append $file_path) } }
|
||||
" D" => { if $analyze_unstaged { $files_deleted = ($files_deleted | append $file_path) } }
|
||||
"D " => { if $analyze_staged { $files_deleted = ($files_deleted | append $file_path) } }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
# Get recent commit messages for style reference
|
||||
let recent_commits = try {
|
||||
git log --oneline -5 | lines
|
||||
} catch {
|
||||
[]
|
||||
}
|
||||
|
||||
# Analyze file types and changes
|
||||
let config_files = ($files_modified | where { $in | str ends-with ".toml" or $in | str ends-with ".nu" or $in | str ends-with ".yaml" })
|
||||
let core_files = ($files_modified | where { $in | str contains "core/" })
|
||||
let provider_files = ($files_modified | where { $in | str contains "provider" })
|
||||
|
||||
# Generate commit message based on changes
|
||||
mut commit_type = "chore"
|
||||
mut commit_scope = ""
|
||||
mut commit_description = ""
|
||||
|
||||
# Determine commit type and scope
|
||||
if (not ($files_added | is-empty)) {
|
||||
$commit_type = "feat"
|
||||
$commit_description = "add new functionality"
|
||||
} else if (not ($files_deleted | is-empty)) {
|
||||
$commit_type = "refactor"
|
||||
$commit_description = "remove unused components"
|
||||
} else if (not ($config_files | is-empty)) {
|
||||
$commit_type = "config"
|
||||
$commit_scope = "system"
|
||||
$commit_description = "update configuration settings"
|
||||
} else if (not ($core_files | is-empty)) {
|
||||
$commit_type = "refactor"
|
||||
$commit_scope = "core"
|
||||
$commit_description = "improve core functionality"
|
||||
} else if (not ($provider_files | is-empty)) {
|
||||
$commit_type = "feat"
|
||||
$commit_scope = "providers"
|
||||
$commit_description = "enhance provider capabilities"
|
||||
} else {
|
||||
$commit_type = "chore"
|
||||
$commit_description = "update project files"
|
||||
}
|
||||
|
||||
# Build commit message
|
||||
mut commit_message = if ($commit_scope | is-empty) {
|
||||
$"($commit_type): ($commit_description)"
|
||||
} else {
|
||||
$"($commit_type)\(($commit_scope)\): ($commit_description)"
|
||||
}
|
||||
|
||||
# Add details section
|
||||
mut details = []
|
||||
|
||||
if (not ($files_added | is-empty)) {
|
||||
$details = ($details | append $"- Add: ($files_added | str join ', ')")
|
||||
}
|
||||
|
||||
if (not ($files_modified | is-empty)) {
|
||||
$details = ($details | append $"- Update: ($files_modified | str join ', ')")
|
||||
}
|
||||
|
||||
if (not ($files_deleted | is-empty)) {
|
||||
$details = ($details | append $"- Remove: ($files_deleted | str join ', ')")
|
||||
}
|
||||
|
||||
# Create full commit message
|
||||
let full_message = if ($details | is-empty) {
|
||||
$commit_message
|
||||
} else {
|
||||
$"($commit_message)\n\n($details | str join '\n')"
|
||||
}
|
||||
|
||||
# Write to file
|
||||
$full_message | save $file
|
||||
|
||||
print $"Commit message generated and saved to: ($file)"
|
||||
print "\nGenerated message:"
|
||||
print "=================="
|
||||
print $full_message
|
||||
}
|
||||
|
||||
# Show current git changes that would be included in commit message
|
||||
export def "show-commit-changes" [] -> table {
|
||||
let status_output = (git status --porcelain | lines | where { $in | str length > 0 })
|
||||
|
||||
$status_output | each { |line|
|
||||
let status_code = ($line | str substring 0..2)
|
||||
let file_path = ($line | str substring 3..)
|
||||
|
||||
let change_type = match $status_code {
|
||||
" M" => "Modified (unstaged)"
|
||||
"M " => "Modified (staged)"
|
||||
"MM" => "Modified (both)"
|
||||
"A " => "Added (staged)"
|
||||
"??" => "Untracked"
|
||||
" D" => "Deleted (unstaged)"
|
||||
"D " => "Deleted (staged)"
|
||||
_ => $status_code
|
||||
}
|
||||
|
||||
{
|
||||
file: $file_path,
|
||||
status: $change_type,
|
||||
code: $status_code
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
NU_VERSION="0.105.2"
|
||||
NU_VERSION="0.107.1"
|
||||
NU_SOURCE="https://github.com/nushell/nushell/releases"
|
||||
NU_TAGS="https://github.com/nushell/nushell/tags"
|
||||
NU_SITE="https://www.nushell.sh/"
|
||||
|
198
utils/commit-msg.nu
Normal file
198
utils/commit-msg.nu
Normal file
@ -0,0 +1,198 @@
|
||||
# Git commit message generator for Claude Code
|
||||
# Generates a commit message file based on current changes without creating a commit
|
||||
# No signatures or automated text added
|
||||
|
||||
# Generate commit message file based on staged and unstaged changes
|
||||
export def "commit-msg" [
|
||||
--file (-f): string = "COMMIT_MSG.txt" # Output file for commit message
|
||||
--staged (-s): bool = false # Only consider staged changes
|
||||
--unstaged (-u): bool = false # Only consider unstaged changes
|
||||
--show: bool = false # Show changes without generating message
|
||||
] -> nothing {
|
||||
|
||||
if $show {
|
||||
show-git-changes
|
||||
return
|
||||
}
|
||||
|
||||
# Determine what changes to analyze
|
||||
let analyze_staged = if $staged or (not $unstaged) { true } else { false }
|
||||
let analyze_unstaged = if $unstaged or (not $staged) { true } else { false }
|
||||
|
||||
# Get git status
|
||||
let git_status = (git status --porcelain | lines | where { $in | str length > 0 })
|
||||
|
||||
if ($git_status | is-empty) {
|
||||
print "No changes to commit"
|
||||
return
|
||||
}
|
||||
|
||||
# Analyze changes
|
||||
mut files_modified = []
|
||||
mut files_added = []
|
||||
mut files_deleted = []
|
||||
|
||||
for line in $git_status {
|
||||
let status_code = ($line | str substring 0..2)
|
||||
let file_path = ($line | str substring 3..)
|
||||
|
||||
# Parse git status codes
|
||||
match $status_code {
|
||||
" M" => { if $analyze_unstaged { $files_modified = ($files_modified | append $file_path) } }
|
||||
"M " => { if $analyze_staged { $files_modified = ($files_modified | append $file_path) } }
|
||||
"MM" => { $files_modified = ($files_modified | append $file_path) }
|
||||
"A " => { if $analyze_staged { $files_added = ($files_added | append $file_path) } }
|
||||
"??" => { if $analyze_unstaged { $files_added = ($files_added | append $file_path) } }
|
||||
" D" => { if $analyze_unstaged { $files_deleted = ($files_deleted | append $file_path) } }
|
||||
"D " => { if $analyze_staged { $files_deleted = ($files_deleted | append $file_path) } }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
# Analyze file types and changes
|
||||
let config_files = ($files_modified | where { $in | str ends-with ".toml" or $in | str ends-with ".nu" or $in | str ends-with ".yaml" })
|
||||
let core_files = ($files_modified | where { $in | str contains "core/" })
|
||||
let provider_files = ($files_modified | where { $in | str contains "provider" })
|
||||
let migration_files = ($files_modified | where { $in | str contains "migration" })
|
||||
|
||||
# Generate commit message based on changes
|
||||
mut commit_type = "chore"
|
||||
mut commit_scope = ""
|
||||
mut commit_description = ""
|
||||
|
||||
# Determine commit type and scope based on project patterns
|
||||
if (not ($files_added | is-empty)) {
|
||||
$commit_type = "feat"
|
||||
if ($files_added | any { $in | str contains "taskserv" }) {
|
||||
$commit_scope = "taskserv"
|
||||
$commit_description = "add new task service"
|
||||
} else if ($files_added | any { $in | str contains "provider" }) {
|
||||
$commit_scope = "provider"
|
||||
$commit_description = "add new provider"
|
||||
} else {
|
||||
$commit_description = "add new functionality"
|
||||
}
|
||||
} else if (not ($files_deleted | is-empty)) {
|
||||
$commit_type = "refactor"
|
||||
$commit_description = "remove unused components"
|
||||
} else if (not ($migration_files | is-empty)) {
|
||||
$commit_type = "refactor"
|
||||
$commit_scope = "config"
|
||||
$commit_description = "continue config-driven architecture migration"
|
||||
} else if (not ($config_files | is-empty)) {
|
||||
if ($config_files | any { $in | str contains "config.defaults.toml" }) {
|
||||
$commit_type = "feat"
|
||||
$commit_scope = "config"
|
||||
$commit_description = "enhance configuration system"
|
||||
} else {
|
||||
$commit_type = "config"
|
||||
$commit_description = "update configuration settings"
|
||||
}
|
||||
} else if (not ($core_files | is-empty)) {
|
||||
if ($core_files | any { $in | str contains "env.nu" }) {
|
||||
$commit_type = "refactor"
|
||||
$commit_scope = "env"
|
||||
$commit_description = "migrate from ENV to config-driven approach"
|
||||
} else {
|
||||
$commit_type = "refactor"
|
||||
$commit_scope = "core"
|
||||
$commit_description = "improve core functionality"
|
||||
}
|
||||
} else if (not ($provider_files | is-empty)) {
|
||||
$commit_type = "feat"
|
||||
$commit_scope = "providers"
|
||||
$commit_description = "enhance provider capabilities"
|
||||
} else {
|
||||
$commit_type = "chore"
|
||||
$commit_description = "update project files"
|
||||
}
|
||||
|
||||
# Build commit message
|
||||
let commit_message = if ($commit_scope | is-empty) {
|
||||
$"($commit_type): ($commit_description)"
|
||||
} else {
|
||||
$"($commit_type)\(($commit_scope)\): ($commit_description)"
|
||||
}
|
||||
|
||||
# Add details section for complex changes
|
||||
mut details = []
|
||||
|
||||
if ($files_modified | length) > 5 {
|
||||
$details = ($details | append $"- Update ($files_modified | length) files across multiple modules")
|
||||
} else if (not ($files_modified | is-empty)) {
|
||||
$details = ($details | append $"- Update: ($files_modified | str join ', ')")
|
||||
}
|
||||
|
||||
if (not ($files_added | is-empty)) {
|
||||
$details = ($details | append $"- Add: ($files_added | str join ', ')")
|
||||
}
|
||||
|
||||
if (not ($files_deleted | is-empty)) {
|
||||
$details = ($details | append $"- Remove: ($files_deleted | str join ', ')")
|
||||
}
|
||||
|
||||
# Create full commit message
|
||||
let full_message = if ($details | is-empty) {
|
||||
$commit_message
|
||||
} else {
|
||||
$"($commit_message)\n\n($details | str join '\n')"
|
||||
}
|
||||
|
||||
# Write to file
|
||||
$full_message | save $file
|
||||
|
||||
print $"Commit message saved to: ($file)"
|
||||
print "\nGenerated message:"
|
||||
print "=================="
|
||||
print $full_message
|
||||
}
|
||||
|
||||
# Show current git changes that would be included in commit message
|
||||
export def "show-git-changes" [] -> table {
|
||||
let status_output = (git status --porcelain | lines | where { $in | str length > 0 })
|
||||
|
||||
if ($status_output | is-empty) {
|
||||
print "No changes found"
|
||||
return []
|
||||
}
|
||||
|
||||
$status_output | each { |line|
|
||||
let status_code = ($line | str substring 0..2)
|
||||
let file_path = ($line | str substring 3..)
|
||||
|
||||
let change_type = match $status_code {
|
||||
" M" => "Modified (unstaged)"
|
||||
"M " => "Modified (staged)"
|
||||
"MM" => "Modified (both)"
|
||||
"A " => "Added (staged)"
|
||||
"??" => "Untracked"
|
||||
" D" => "Deleted (unstaged)"
|
||||
"D " => "Deleted (staged)"
|
||||
_ => $status_code
|
||||
}
|
||||
|
||||
{
|
||||
file: $file_path,
|
||||
status: $change_type,
|
||||
code: $status_code
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Quick commit message for common patterns
|
||||
export def "quick-commit" [
|
||||
pattern: string # Pattern: config, fix, feat, refactor, docs, test
|
||||
] -> nothing {
|
||||
let message = match $pattern {
|
||||
"config" => "config: update configuration settings"
|
||||
"fix" => "fix: resolve issue in functionality"
|
||||
"feat" => "feat: add new functionality"
|
||||
"refactor" => "refactor: improve code structure"
|
||||
"docs" => "docs: update documentation"
|
||||
"test" => "test: add or update tests"
|
||||
_ => $"chore: ($pattern)"
|
||||
}
|
||||
|
||||
$message | save "COMMIT_MSG.txt"
|
||||
print $"Quick commit message saved: ($message)"
|
||||
}
|
Loading…
Reference in New Issue
Block a user