Skip to content

Commit

Permalink
Merge pull request #1 from aztekas/test/cli
Browse files Browse the repository at this point in the history
Restructure repository, add aux commands
  • Loading branch information
zaikinlv committed Mar 18, 2024
2 parents 4daa544 + 638e4a1 commit 73f0195
Show file tree
Hide file tree
Showing 18 changed files with 984 additions and 424 deletions.
444 changes: 22 additions & 422 deletions cmd/cleura/cleura.go

Large diffs are not rendered by default.

152 changes: 152 additions & 0 deletions cmd/cleura/configcmd/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package configcmd

import (
"bytes"
"errors"
"fmt"
"slices"

"github.com/aztekas/cleura-client-go/cmd/cleura/utils"
"github.com/spf13/viper"
"github.com/urfave/cli/v2"
"golang.org/x/exp/maps"
"gopkg.in/yaml.v2"
)

type Config struct {
ActiveConfig string `mapstructure:"active_configuration" yaml:"active_configuration"`
Configurations map[string]Configuration `mapstructure:"configurations"`
location string
}
type Configuration struct {
Username string `mapstructure:"username" yaml:"username"`
Token string `mapstructure:"token" yaml:"token"`
DefaultDomainID string `mapstructure:"domain-id" yaml:"domain-id"`
DefaultRegion string `mapstructure:"region" yaml:"region"`
DefaultProjectID string `mapstructure:"project-id" yaml:"project-id"`
//APIHost string `mapstructure:"api-host" yaml:"api-host"`
}

func (c *Config) SetActive(name string) error {
viper.SetConfigFile(c.location)
viper.SetConfigType("yaml")

_, ok := c.Configurations[name]
if !ok {
return errors.New("error: specified configuration name is not present in configuration file")
}
c.ActiveConfig = name
configByte, err := yaml.Marshal(c)
if err != nil {
return err
}
err = viper.ReadConfig(bytes.NewBuffer(configByte))
if err != nil {
return err
}
err = viper.WriteConfig()
if err != nil {
return err
}
return nil
}

func (c *Config) UpdateConfiguration(key string, value string) error {

_, ok := c.Configurations[c.ActiveConfig]
if !ok {
return errors.New("error: no active configuration in configuration file")
}
viper.SetConfigFile(c.location)
viper.SetConfigType("yaml")
err := viper.ReadInConfig()
if err != nil {
return err
}
viper.Set("configurations."+c.ActiveConfig+"."+key, value)
err = viper.WriteConfig()
if err != nil {
return err
}
return nil
}

func (c *Config) PrintConfigurations() {
if len(c.Configurations) > 0 {
fmt.Printf("Available configurations: (in %s)\n", c.location)
for i, conf := range maps.Keys(c.Configurations) {
if conf == c.ActiveConfig {
conf = conf + " (active)"
}
fmt.Printf("%d. %s\n", i, conf)
}
} else {
fmt.Printf("no configurations found in configuration file: %s\n", c.location)
}
}

func LoadConfiguration(path string) (*Config, error) {
var config Config
path, err := utils.ChoosePath(path)
if err != nil {
return nil, err
}
viper.SetConfigFile(path)
viper.SetConfigType("yaml")
err = viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
return nil, fmt.Errorf("loadConfiguration: error reading config file: %w", err)
}
err = viper.Unmarshal(&config)
if err != nil {
return nil, err
}
config.location = path
return &config, nil
}

// Get available configuration settings from supplied or default configuration file
func TrySetConfigFromFile(c *cli.Context) error {
var config *Config
//ignore api-host as it always has default value
//ignore path as it always has default value (%HOME/.config/cleura/config)
var ignoreFlags = []string{"help", "api-host", "path"}
config, err := LoadConfiguration(c.String("path"))
if err != nil {
fmt.Printf("Failed to read configuration file: %s, proceed with explicit configuration via flags and environment variables\n", err)
return nil
}
activeConfig := config.ActiveConfig
if activeConfig == "" {
fmt.Printf("No active configuration found in %s, proceed with explicit configuration via flags and environment variables\n", config.location)
return nil
}
// Get a map put of struct fields with yaml tag
configFromFile, err := utils.ToMap(config.Configurations[activeConfig], "yaml")
if err != nil {
return err
}

//Iterate over all defined flags (set and unset)
for _, flag := range c.Command.Flags {
ok := c.IsSet(flag.Names()[0])
// Only set flags that are not already set directly of via environment variables
if !ok && !slices.Contains(ignoreFlags, flag.Names()[0]) {
c.Set(flag.Names()[0], configFromFile[flag.Names()[0]].(string))
}
}
//return fmt.Errorf("error: expected error")
return nil
}

func Command() *cli.Command {
return &cli.Command{
Name: "config",
Description: "Command used for preparing cleura cli credentials and setting default parameter values",
Subcommands: []*cli.Command{
setCommand(),
listCommand(),
showActiveCommand(),
},
}
}
27 changes: 27 additions & 0 deletions cmd/cleura/configcmd/listcmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package configcmd

import "github.com/urfave/cli/v2"

func listCommand() *cli.Command {
return &cli.Command{
Name: "list",
Description: "List available configurations",
Usage: "List available configurations defined in configuration file",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Usage: "Path to configuration file. $HOME/.config/cleura/config if not set",
},
},
Action: func(ctx *cli.Context) error {
var config *Config
config, err := LoadConfiguration(ctx.String("path"))
if err != nil {
return err
}
config.PrintConfigurations()
return nil
},
}
}
38 changes: 38 additions & 0 deletions cmd/cleura/configcmd/setcmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package configcmd

import "github.com/urfave/cli/v2"

func setCommand() *cli.Command {
return &cli.Command{
Name: "set",
Description: "Set active configuration from the list of configurations defined in the configuration file",
Usage: "Set active configuration from the list of configurations defined in the configuration file",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Required: true,
Aliases: []string{"n"},
Usage: "Configuration name",
},
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Usage: "Path to configuration file. $HOME/.config/cleura/config if not set",
},
},
Action: func(ctx *cli.Context) error {
var config *Config
config, err := LoadConfiguration(ctx.String("path"))
if err != nil {
return err
}
err = config.SetActive(ctx.String("name"))
if err != nil {
return err
}

return nil

},
}
}
36 changes: 36 additions & 0 deletions cmd/cleura/configcmd/showactivecmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package configcmd

import (
"fmt"

"github.com/urfave/cli/v2"
)

func showActiveCommand() *cli.Command {
return &cli.Command{
Name: "show-active",
Description: "Show currently active configuration",
Usage: "Show currently active configuration",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Usage: "Path to configuration file. $HOME/.config/cleura/config if not set",
},
},
Action: func(ctx *cli.Context) error {
var config *Config
config, err := LoadConfiguration(ctx.String("path"))
if err != nil {
return err
}
activeConf := config.ActiveConfig
if activeConf == "" {
fmt.Println("Active configuration is not set, try setting with `cleura config set --name <configuration_name>`")
} else {
fmt.Printf("Active configuration: `%s` (in %s)\n", activeConf, config.location)
}
return nil
},
}
}
13 changes: 13 additions & 0 deletions cmd/cleura/domaincmd/domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package domaincmd

import "github.com/urfave/cli/v2"

func Command() *cli.Command {
return &cli.Command{
Name: "domain",
Description: "Command used to list available domains",
Subcommands: []*cli.Command{
listCommand(),
},
}
}
79 changes: 79 additions & 0 deletions cmd/cleura/domaincmd/listcmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package domaincmd

import (
"fmt"
"strconv"

"github.com/aztekas/cleura-client-go/cmd/cleura/configcmd"
"github.com/aztekas/cleura-client-go/pkg/api/cleura"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
"github.com/urfave/cli/v2"
)

func listCommand() *cli.Command {
return &cli.Command{
Name: "list",
Description: "List available domains",
Usage: "List domains available to current user",
Before: configcmd.TrySetConfigFromFile,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "token",
Aliases: []string{"t"},
Usage: "Token to validate",
EnvVars: []string{"CLEURA_API_TOKEN"},
},
&cli.StringFlag{
Name: "username",
Aliases: []string{"u"},
Usage: "Username token belongs to",
EnvVars: []string{"CLEURA_API_USERNAME"},
},
&cli.StringFlag{
Name: "api-host",
Aliases: []string{"host"},
Usage: "Cleura API host",
Value: "https://rest.cleura.cloud",
EnvVars: []string{"CLEURA_API_HOST"},
},
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Usage: "Path to configuration file. $HOME/.config/cleura/config if not set",
},
},
Action: func(ctx *cli.Context) error {
token := ctx.String("token")
username := ctx.String("username")
host := ctx.String("api-host")
client, err := cleura.NewClientNoPassword(&host, &username, &token)
if err != nil {
return err
}
domains, err := client.ListDomains()
if err != nil {
re, ok := err.(*cleura.RequestAPIError)
if ok {
if re.StatusCode == 403 {
return fmt.Errorf("error: invalid token")
}
}
return err
}
t := table.NewWriter()
t.SetAutoIndex(true)
t.Style().Format.Header = text.FormatTitle
t.AppendHeader(table.Row{"Name", "Domain Id", "Regions"})
for _, domain := range *domains {
var regs string
for _, region := range domain.Area.Regions {
regs += fmt.Sprintf("%s:%s\n", region.Region, region.Status)
}
t.AppendRow(table.Row{fmt.Sprintf("%s(enabled:%s,status:%s)", domain.Name, strconv.FormatBool(domain.Enabled), domain.Status), domain.Id, regs})
}
fmt.Println(t.Render())
return nil
},
}
}
Loading

0 comments on commit 73f0195

Please sign in to comment.