Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/godon/credential.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import std/[httpclient, json, strutils, uri, tables]
import std/[httpclient, json, uri, tables]
import yaml
import client, types

Expand Down
199 changes: 124 additions & 75 deletions src/godon_cli.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import std/[parseopt, strutils, os, json]
import yaml, yaml/presenter, yaml/dumping
import godon/[client, breeder, credential, types]

type
OutputFormat* = enum
Text = "text"
Json = "json"
Yaml = "yaml"

proc writeHelp() =
echo """Godon CLI - Command line interface for Godon API

Expand All @@ -23,8 +30,9 @@ Global Options:
--hostname, -h <host> Godon hostname (default: localhost)
--port, -p <port> Godon port (default: 8080)
--api-version, -v <ver> API version (default: v0)
--output, -o <format> Output format: text, json, or yaml (default: text)
--insecure Skip SSL certificate verification (HTTPS only)
--help, -h Show this help message
--help Show this help message

Examples:
godon_cli breeder list
Expand All @@ -40,12 +48,13 @@ proc writeError(message: string) =
stderr.writeLine("Error: " & message)
quit(1)

proc parseArgs(): (string, string, int, string, bool, seq[string]) =
proc parseArgs(): (string, string, int, string, bool, OutputFormat, seq[string]) =
var command = ""
var hostname = "localhost"
var port = 8080
var apiVersion = "v0"
var insecure = false
var outputFormat = OutputFormat.Text
var args: seq[string] = @[]

var p = initOptParser(commandLineParams())
Expand Down Expand Up @@ -82,7 +91,19 @@ proc parseArgs(): (string, string, int, string, bool, seq[string]) =
args.add("--id=" & val)
of "insecure":
insecure = true
of "help", "h":
of "output", "o":
if val.len == 0:
writeError("Output option requires a value (text, json, or yaml)")
case val.normalize()
of "text":
outputFormat = OutputFormat.Text
of "json":
outputFormat = OutputFormat.Json
of "yaml":
outputFormat = OutputFormat.Yaml
else:
writeError("Unknown output format: " & val & ". Use text, json, or yaml")
of "help":
writeHelp()
quit(0)
else:
Expand All @@ -95,23 +116,39 @@ proc parseArgs(): (string, string, int, string, bool, seq[string]) =
writeHelp()
quit(0)

(command, hostname, port, apiVersion, insecure, args)
(command, hostname, port, apiVersion, insecure, outputFormat, args)

proc formatOutput*[T](data: T, outputFormat: OutputFormat) =
## Format data according to output format preference
case outputFormat
of OutputFormat.Text:
# Text mode is handled by caller with custom formatting
discard
of OutputFormat.Json:
echo pretty(%*data)
of OutputFormat.Yaml:
# Convert to YAML by dumping JSON as text and transforming it
let jsonString = pretty(%*data)
var dumper = blockOnlyDumper()
echo dumper.transform(jsonString)

proc handleBreederCommand(client: GodonClient, command: string, args: seq[string]) =
proc handleBreederCommand(client: GodonClient, command: string, args: seq[string], outputFormat: OutputFormat) =
let subCommand = if args.len > 0: args[0] else: ""

case subCommand:
of "list":
echo "Listing breeders..."
let response = client.listBreeders()
if response.success:
echo "Breeders:"
for breeder in response.data:
echo " ID: ", breeder.id
echo " Name: ", breeder.name
echo " Status: ", breeder.status
echo " Created: ", breeder.createdAt
echo " ---"
if outputFormat == OutputFormat.Text:
echo "Breeders:"
for breeder in response.data:
echo " ID: ", breeder.id
echo " Name: ", breeder.name
echo " Status: ", breeder.status
echo " Created: ", breeder.createdAt
echo " ---"
else:
formatOutput(response.data, outputFormat)
else:
writeError(response.error)

Expand All @@ -133,14 +170,16 @@ proc handleBreederCommand(client: GodonClient, command: string, args: seq[string
if not fileExists(file):
writeError("File not found: " & file)

echo "Creating breeder '", name, "' from file: ", file
let content = readFile(file)
let response = client.createBreederFromYamlWithName(content, name)
if response.success:
echo "Breeder created successfully:"
echo " ID: ", response.data.id
echo " Name: ", response.data.name
echo " Status: ", response.data.status
if outputFormat == OutputFormat.Text:
echo "Breeder created successfully:"
echo " ID: ", response.data.id
echo " Name: ", response.data.name
echo " Status: ", response.data.status
else:
formatOutput(response.data, outputFormat)
else:
writeError(response.error)

Expand All @@ -153,16 +192,18 @@ proc handleBreederCommand(client: GodonClient, command: string, args: seq[string

if id.len == 0:
writeError("breeder show requires --id <id>")

echo "Getting breeder details for ID: ", id

let response = client.getBreeder(id)
if response.success:
echo "Breeder Details:"
echo " ID: ", response.data.id
echo " Name: ", response.data.name
echo " Status: ", response.data.status
echo " Config: ", pretty(response.data.config)
echo " Created: ", response.data.createdAt
if outputFormat == OutputFormat.Text:
echo "Breeder Details:"
echo " ID: ", response.data.id
echo " Name: ", response.data.name
echo " Status: ", response.data.status
echo " Config: ", pretty(response.data.config)
echo " Created: ", response.data.createdAt
else:
formatOutput(response.data, outputFormat)
else:
writeError(response.error)

Expand All @@ -178,15 +219,17 @@ proc handleBreederCommand(client: GodonClient, command: string, args: seq[string

if not fileExists(file):
writeError("File not found: " & file)

echo "Updating breeder from file: ", file

let content = readFile(file)
let response = client.updateBreederFromYaml(content)
if response.success:
echo "Breeder updated successfully:"
echo " ID: ", response.data.id
echo " Name: ", response.data.name
echo " Status: ", response.data.status
if outputFormat == OutputFormat.Text:
echo "Breeder updated successfully:"
echo " ID: ", response.data.id
echo " Name: ", response.data.name
echo " Status: ", response.data.status
else:
formatOutput(response.data, outputFormat)
else:
writeError(response.error)

Expand All @@ -199,36 +242,38 @@ proc handleBreederCommand(client: GodonClient, command: string, args: seq[string

if id.len == 0:
writeError("breeder purge requires --id <id>")

echo "Deleting breeder with ID: ", id

let response = client.deleteBreeder(id)
if response.success:
echo "Breeder deleted successfully"
if response.data != nil:
echo "Response: ", pretty(response.data)
if outputFormat == OutputFormat.Text:
echo "Breeder deleted successfully: ", id
else:
formatOutput(response.data, outputFormat)
else:
writeError(response.error)

else:
writeError("Unknown breeder command: " & subCommand)

proc handleCredentialCommand(client: GodonClient, command: string, args: seq[string]) =
proc handleCredentialCommand(client: GodonClient, command: string, args: seq[string], outputFormat: OutputFormat) =
let subCommand = if args.len > 0: args[0] else: ""

case subCommand:
of "list":
echo "Listing credentials..."
let response = client.listCredentials()
if response.success:
echo "Credentials:"
for credential in response.data:
echo " ID: ", credential.id
echo " Name: ", credential.name
echo " Type: ", credential.credentialType
echo " Description: ", credential.description
echo " Windmill Variable: ", credential.windmillVariable
echo " Created: ", credential.createdAt
echo " ---"
if outputFormat == OutputFormat.Text:
echo "Credentials:"
for credential in response.data:
echo " ID: ", credential.id
echo " Name: ", credential.name
echo " Type: ", credential.credentialType
echo " Description: ", credential.description
echo " windmillVariable: ", credential.windmillVariable
echo " Created: ", credential.createdAt
echo " ---"
else:
formatOutput(response.data, outputFormat)
else:
writeError(response.error)

Expand All @@ -244,16 +289,18 @@ proc handleCredentialCommand(client: GodonClient, command: string, args: seq[str

if not fileExists(file):
writeError("File not found: " & file)

echo "Creating credential from file: ", file

let content = readFile(file)
let response = client.createCredentialFromYaml(content)
if response.success:
echo "Credential created successfully:"
echo " ID: ", response.data.id
echo " Name: ", response.data.name
echo " Type: ", response.data.credentialType
echo " Windmill Variable: ", response.data.windmillVariable
if outputFormat == OutputFormat.Text:
echo "Credential created successfully:"
echo " ID: ", response.data.id
echo " Name: ", response.data.name
echo " Type: ", response.data.credentialType
echo " windmillVariable: ", response.data.windmillVariable
else:
formatOutput(response.data, outputFormat)
else:
writeError(response.error)

Expand All @@ -266,20 +313,22 @@ proc handleCredentialCommand(client: GodonClient, command: string, args: seq[str

if id.len == 0:
writeError("credential show requires --id <id>")

echo "Getting credential details for ID: ", id

let response = client.getCredential(id)
if response.success:
echo "Credential Details:"
echo " ID: ", response.data.id
echo " Name: ", response.data.name
echo " Type: ", response.data.credentialType
echo " Description: ", response.data.description
echo " Windmill Variable: ", response.data.windmillVariable
echo " Created: ", response.data.createdAt
echo " Last Used: ", response.data.lastUsedAt
echo " Content:"
echo " ", response.data.content # Show actual credential content
if outputFormat == OutputFormat.Text:
echo "Credential Details:"
echo " ID: ", response.data.id
echo " Name: ", response.data.name
echo " Type: ", response.data.credentialType
echo " Description: ", response.data.description
echo " windmillVariable: ", response.data.windmillVariable
echo " Created: ", response.data.createdAt
echo " Last Used: ", response.data.lastUsedAt
echo " Content:"
echo " ", response.data.content
else:
formatOutput(response.data, outputFormat)
else:
writeError(response.error)

Expand All @@ -292,33 +341,33 @@ proc handleCredentialCommand(client: GodonClient, command: string, args: seq[str

if id.len == 0:
writeError("credential delete requires --id <id>")

echo "Deleting credential with ID: ", id

let response = client.deleteCredential(id)
if response.success:
echo "Credential deleted successfully"
if response.data != nil:
echo "Response: ", pretty(response.data)
if outputFormat == OutputFormat.Text:
echo "Credential deleted successfully: ", id
else:
formatOutput(response.data, outputFormat)
else:
writeError(response.error)

else:
writeError("Unknown credential command: " & subCommand)

let (command, hostname, port, apiVersion, insecure, args) = parseArgs()
let (command, hostname, port, apiVersion, insecure, outputFormat, args) = parseArgs()

let godonClient = newGodonClient(hostname, port, apiVersion, insecure)

case command:
of "breeder":
if args.len == 0:
writeError("breeder command requires a subcommand (list, create, show, update, purge)")
handleBreederCommand(godonClient, command, args)
handleBreederCommand(godonClient, command, args, outputFormat)

of "credential":
if args.len == 0:
writeError("credential command requires a subcommand (list, create, show, delete)")
handleCredentialCommand(godonClient, command, args)
handleCredentialCommand(godonClient, command, args, outputFormat)

else:
writeError("Unknown command: " & command)