mirror of
https://codeberg.org/muon/home.git
synced 2026-07-04 07:59:33 +00:00
Fix hr call
This commit is contained in:
parent
d049d7de3e
commit
6c344e061f
1 changed files with 157 additions and 27 deletions
|
|
@ -1,4 +1,18 @@
|
|||
# HR - Hefring work tooling for nushell
|
||||
#
|
||||
# This module provides commands for working with Hefring Cloud Run services and Cloud Functions.
|
||||
#
|
||||
# Key features:
|
||||
# - Shell-style argument passing: -key value supports dot notation for nested structures
|
||||
# Example: hr call service -items.0.type "trip" -items.0.id "123"
|
||||
#
|
||||
# - Nushell record syntax with --data flag for complex payloads:
|
||||
# Example: hr call service --data {company_id: "abc", items: [{type: "trip"}]}
|
||||
#
|
||||
# - Automatic type detection: numbers, booleans, and JSON are parsed automatically
|
||||
# Example: -count "42" → number, -active "true" → boolean
|
||||
#
|
||||
# - Pretty display: Payloads are shown as Nushell tables before sending
|
||||
|
||||
def _hr_usage [] {
|
||||
print "Usage: hr <command>"
|
||||
|
|
@ -181,29 +195,89 @@ def _hr_init_base [name: string, write_files: closure, ignores: list<string>] {
|
|||
direnv allow
|
||||
}
|
||||
|
||||
def _hr_setpath [data: any, path: list, value: any] {
|
||||
# Recursively build nested structure, similar to jq's setpath
|
||||
if ($path | is-empty) {
|
||||
$value
|
||||
} else if ($path | length) == 1 {
|
||||
$data | upsert ($path | first) $value
|
||||
} else {
|
||||
let key = ($path | first)
|
||||
let rest = ($path | skip 1)
|
||||
let next_key = ($rest | first)
|
||||
|
||||
# Check if key exists in data and get intermediate value
|
||||
let key_type = ($key | describe)
|
||||
let data_type = ($data | describe)
|
||||
let is_list = ($data_type | str starts-with "list") or ($data_type | str starts-with "table")
|
||||
|
||||
# Determine if key exists and get intermediate structure
|
||||
let intermediate = if $key_type == "int" and $is_list {
|
||||
# Array index
|
||||
if $key < ($data | length) {
|
||||
$data | get $key
|
||||
} else {
|
||||
# Index doesn't exist, create structure based on next key
|
||||
if ($next_key | describe) == "int" { [] } else { {} }
|
||||
}
|
||||
} else if $key_type != "int" {
|
||||
# Object key
|
||||
if $key in $data {
|
||||
$data | get $key
|
||||
} else {
|
||||
# Key doesn't exist, create structure based on next key
|
||||
if ($next_key | describe) == "int" { [] } else { {} }
|
||||
}
|
||||
} else {
|
||||
# Data is not a list but key is int - create array
|
||||
if ($next_key | describe) == "int" { [] } else { {} }
|
||||
}
|
||||
|
||||
# Recursively set the rest of the path
|
||||
let updated_intermediate = (_hr_setpath $intermediate $rest $value)
|
||||
|
||||
# Update data with the new intermediate value
|
||||
$data | upsert $key $updated_intermediate
|
||||
}
|
||||
}
|
||||
|
||||
def _hr_add_json_field [json: string, key: string, value: string] {
|
||||
# Determine if value should be parsed as raw JSON or treated as a string
|
||||
let is_bool = ($value == "true" or $value == "false")
|
||||
let is_number = ($value =~ '^-?(0|[1-9][0-9]*)(\.[0-9]+)?$')
|
||||
let is_json_container = ($value =~ '^\[' or $value =~ '^\{')
|
||||
|
||||
if $is_bool or $is_number {
|
||||
$json | from json | upsert $key ($value | from json) | to json
|
||||
# Parse the value into the appropriate type
|
||||
let parsed_value = if $is_bool or $is_number {
|
||||
$value | from json
|
||||
} else if $is_json_container {
|
||||
let parsed = (do { $value | from json } | complete)
|
||||
if $parsed.exit_code == 0 {
|
||||
$json | from json | upsert $key ($value | from json) | to json
|
||||
$value | from json
|
||||
} else {
|
||||
print $"Warning: Value for '($key)' looks like JSON but is invalid. Treating as string." --stderr
|
||||
$json | from json | upsert $key $value | to json
|
||||
$value
|
||||
}
|
||||
} else {
|
||||
$json | from json | upsert $key $value | to json
|
||||
$value
|
||||
}
|
||||
|
||||
# Convert key path (e.g., "items.0.type") to a list of path segments
|
||||
# Numbers are converted to integers for array indexing
|
||||
let path_segments = ($key | split row "." | each { |segment|
|
||||
if ($segment =~ '^[0-9]+$') {
|
||||
$segment | into int
|
||||
} else {
|
||||
$segment
|
||||
}
|
||||
})
|
||||
|
||||
let data = ($json | from json)
|
||||
_hr_setpath $data $path_segments $parsed_value | to json
|
||||
}
|
||||
|
||||
def _hr_parse_flags [args: list<string>] {
|
||||
mut payload = {}
|
||||
mut json_str = "{}"
|
||||
mut i = 0
|
||||
while $i < ($args | length) {
|
||||
let arg = ($args | get $i)
|
||||
|
|
@ -217,16 +291,28 @@ def _hr_parse_flags [args: list<string>] {
|
|||
if ($next | str starts-with "-") {
|
||||
error make { msg: $"Error: Missing value for option ($key)" }
|
||||
}
|
||||
$payload = ($payload | upsert $key $next)
|
||||
$json_str = (_hr_add_json_field $json_str $key $next)
|
||||
$i = $i + 2
|
||||
} else {
|
||||
error make { msg: $"Error: Unexpected argument '($arg)'" }
|
||||
}
|
||||
}
|
||||
$payload
|
||||
$json_str | from json
|
||||
}
|
||||
|
||||
def _hr_call [route_arg: string, ...rest: string] {
|
||||
def _hr_call [args: list<string>] {
|
||||
if ($args | is-empty) {
|
||||
print "Usage: hr call <route-name>[/path] [OPTIONS]"
|
||||
print ""
|
||||
print "Options:"
|
||||
print " -key value Set JSON field (supports dot notation, e.g., -items.0.type \"trip\")"
|
||||
print " --data <record> Pass structured data as a Nushell record"
|
||||
return
|
||||
}
|
||||
|
||||
let route_arg = ($args | first)
|
||||
let rest = ($args | skip 1)
|
||||
|
||||
let parts = if ($route_arg | str contains "/") {
|
||||
let service = ($route_arg | split row "/" | first)
|
||||
let path = "/" + ($route_arg | split row "/" | skip 1 | str join "/")
|
||||
|
|
@ -241,29 +327,81 @@ def _hr_call [route_arg: string, ...rest: string] {
|
|||
"322048751601"
|
||||
}
|
||||
|
||||
let payload = (_hr_parse_flags $rest | to json)
|
||||
# Check if --data flag is present
|
||||
let data_idx = ($rest | enumerate | where item == "--data" | get index.0? | default (-1))
|
||||
|
||||
let payload_record = if $data_idx >= 0 {
|
||||
# Use --data record
|
||||
if ($data_idx + 1) >= ($rest | length) {
|
||||
error make { msg: "Error: --data requires a record argument" }
|
||||
}
|
||||
let data_str = ($rest | get ($data_idx + 1))
|
||||
# Try to parse as Nushell code to get a record
|
||||
try {
|
||||
nu -c $data_str
|
||||
} catch {
|
||||
error make { msg: $"Error: --data argument must be a valid Nushell record, got: ($data_str)" }
|
||||
}
|
||||
} else {
|
||||
# Use -key value pairs
|
||||
_hr_parse_flags $rest
|
||||
}
|
||||
|
||||
let payload = ($payload_record | to json -r)
|
||||
let url = $"https://($parts.service)-($project_number).europe-west1.run.app($parts.path)"
|
||||
|
||||
print $"Calling ($url)..."
|
||||
print $payload
|
||||
print ($payload | from json)
|
||||
|
||||
let token = (gcloud auth print-identity-token)
|
||||
http post $url $payload --content-type "application/json" --headers { Authorization: $"bearer ($token)" }
|
||||
^curl -s -S -L $url -H $"Authorization: Bearer ($token)" -H "Content-Type: application/json" -d $payload
|
||||
}
|
||||
|
||||
def _hr_cf [function_name: string, ...rest: string] {
|
||||
let payload = (_hr_parse_flags $rest | to json)
|
||||
def _hr_cf [args: list<string>] {
|
||||
if ($args | is-empty) {
|
||||
print "Usage: hr cf <function-name> [OPTIONS]"
|
||||
print ""
|
||||
print "Options:"
|
||||
print " -key value Set JSON field (supports dot notation, e.g., -items.0.type \"trip\")"
|
||||
print " --data <record> Pass structured data as a Nushell record"
|
||||
return
|
||||
}
|
||||
|
||||
let function_name = ($args | first)
|
||||
let rest = ($args | skip 1)
|
||||
|
||||
# Check if --data flag is present
|
||||
let data_idx = ($rest | enumerate | where item == "--data" | get index.0? | default (-1))
|
||||
|
||||
let payload_record = if $data_idx >= 0 {
|
||||
# Use --data record
|
||||
if ($data_idx + 1) >= ($rest | length) {
|
||||
error make { msg: "Error: --data requires a record argument" }
|
||||
}
|
||||
let data_str = ($rest | get ($data_idx + 1))
|
||||
# Try to parse as Nushell code to get a record
|
||||
try {
|
||||
nu -c $data_str
|
||||
} catch {
|
||||
error make { msg: $"Error: --data argument must be a valid Nushell record, got: ($data_str)" }
|
||||
}
|
||||
} else {
|
||||
# Use -key value pairs
|
||||
_hr_parse_flags $rest
|
||||
}
|
||||
|
||||
let payload = ($payload_record | to json -r)
|
||||
let url = $"https://europe-west1-($env.PROJECT_ID).cloudfunctions.net/($function_name)"
|
||||
|
||||
print $"Calling ($url)..."
|
||||
print $payload
|
||||
print ($payload | from json)
|
||||
|
||||
let token = (gcloud auth print-identity-token)
|
||||
http post $url $payload --content-type "application/json" --headers { Authorization: $"bearer ($token)" }
|
||||
^curl -s -S -L $url -H $"Authorization: Bearer ($token)" -H "Content-Type: application/json" -d $payload
|
||||
}
|
||||
|
||||
# HR - Hefring work tooling
|
||||
export def --env hr [...args: string] {
|
||||
export def --env --wrapped hr [...args: string] {
|
||||
if ($args | is-empty) {
|
||||
_hr_usage
|
||||
return
|
||||
|
|
@ -326,18 +464,10 @@ export def --env hr [...args: string] {
|
|||
uv pip freeze --exclude-editable | save --append requirements.txt
|
||||
}
|
||||
"call" => {
|
||||
if ($rest | is-empty) {
|
||||
print "Usage: hr call <route-name>[/path] <options>"
|
||||
return
|
||||
}
|
||||
_hr_call ($rest | first) ...($rest | skip 1)
|
||||
_hr_call $rest
|
||||
}
|
||||
"cf" => {
|
||||
if ($rest | is-empty) {
|
||||
print "Usage: hr cf <function-name> <options>"
|
||||
return
|
||||
}
|
||||
_hr_cf ($rest | first) ...($rest | skip 1)
|
||||
_hr_cf $rest
|
||||
}
|
||||
_ => { _hr_usage }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue