-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The objective was to play out the use of cobra without any inits. This work was heavily inspired from stripe-cli.
- Loading branch information
Showing
13 changed files
with
1,647 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
package ansi | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os" | ||
"runtime" | ||
"time" | ||
|
||
"github.com/briandowns/spinner" | ||
"github.com/logrusorgru/aurora" | ||
"github.com/tidwall/pretty" | ||
"golang.org/x/crypto/ssh/terminal" | ||
) | ||
|
||
var darkTerminalStyle = &pretty.Style{ | ||
Key: [2]string{"\x1B[34m", "\x1B[0m"}, | ||
String: [2]string{"\x1B[30m", "\x1B[0m"}, | ||
Number: [2]string{"\x1B[94m", "\x1B[0m"}, | ||
True: [2]string{"\x1B[35m", "\x1B[0m"}, | ||
False: [2]string{"\x1B[35m", "\x1B[0m"}, | ||
Null: [2]string{"\x1B[31m", "\x1B[0m"}, | ||
} | ||
|
||
// ForceColors forces the use of colors and other ANSI sequences. | ||
var ForceColors = false | ||
|
||
// DisableColors disables all colors and other ANSI sequences. | ||
var DisableColors = false | ||
|
||
// EnvironmentOverrideColors overs coloring based on `CLICOLOR` and | ||
// `CLICOLOR_FORCE`. Cf. https://bixense.com/clicolors/ | ||
var EnvironmentOverrideColors = true | ||
|
||
// Bold returns bolded text if the writer supports colors | ||
func Bold(text string) string { | ||
color := Color(os.Stdout) | ||
return color.Sprintf(color.Bold(text)) | ||
} | ||
|
||
// Color returns an aurora.Aurora instance with colors enabled or disabled | ||
// depending on whether the writer supports colors. | ||
func Color(w io.Writer) aurora.Aurora { | ||
return aurora.NewAurora(shouldUseColors(w)) | ||
} | ||
|
||
// ColorizeJSON returns a colorized version of the input JSON, if the writer | ||
// supports colors. | ||
func ColorizeJSON(json string, darkStyle bool, w io.Writer) string { | ||
if !shouldUseColors(w) { | ||
return json | ||
} | ||
|
||
style := (*pretty.Style)(nil) | ||
if darkStyle { | ||
style = darkTerminalStyle | ||
} | ||
|
||
return string(pretty.Color([]byte(json), style)) | ||
} | ||
|
||
// ColorizeStatus returns a colorized number for HTTP status code | ||
func ColorizeStatus(status int) aurora.Value { | ||
color := Color(os.Stdout) | ||
|
||
switch { | ||
case status >= 500: | ||
return color.Red(status).Bold() | ||
case status >= 300: | ||
return color.Yellow(status).Bold() | ||
default: | ||
return color.Green(status).Bold() | ||
} | ||
} | ||
|
||
// Faint returns slightly offset color text if the writer supports it | ||
func Faint(text string) string { | ||
color := Color(os.Stdout) | ||
return color.Sprintf(color.Faint(text)) | ||
} | ||
|
||
// Italic returns italicized text if the writer supports it. | ||
func Italic(text string) string { | ||
color := Color(os.Stdout) | ||
return color.Sprintf(color.Italic(text)) | ||
} | ||
|
||
// Linkify returns an ANSI escape sequence with an hyperlink, if the writer | ||
// supports colors. | ||
func Linkify(text, url string, w io.Writer) string { | ||
if !shouldUseColors(w) { | ||
return text | ||
} | ||
|
||
// See https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda | ||
// for more information about this escape sequence. | ||
return fmt.Sprintf("\x1b]8;;%s\x1b\\%s\x1b]8;;\x1b\\", url, text) | ||
} | ||
|
||
type charset = []string | ||
|
||
func getCharset() charset { | ||
// See https://github.com/briandowns/spinner#available-character-sets for | ||
// list of available charsets | ||
if runtime.GOOS == "windows" { | ||
// Less fancy, but uses ASCII characters so works with Windows default | ||
// console. | ||
return spinner.CharSets[8] | ||
} | ||
return spinner.CharSets[11] | ||
} | ||
|
||
const duration = time.Duration(100) * time.Millisecond | ||
|
||
// StartNewSpinner starts a new spinner with the given message. If the writer is not | ||
// a terminal or doesn't support colors, it simply prints the message. | ||
func StartNewSpinner(msg string, w io.Writer) *spinner.Spinner { | ||
if !isTerminal(w) || !shouldUseColors(w) { | ||
fmt.Fprintln(w, msg) | ||
return nil | ||
} | ||
|
||
s := spinner.New(getCharset(), duration) | ||
s.Writer = w | ||
|
||
if msg != "" { | ||
s.Suffix = " " + msg | ||
} | ||
|
||
s.Start() | ||
|
||
return s | ||
} | ||
|
||
// StartSpinner updates an existing spinner's message, and starts it if it was stopped | ||
func StartSpinner(s *spinner.Spinner, msg string, w io.Writer) { | ||
if s == nil { | ||
fmt.Fprintln(w, msg) | ||
return | ||
} | ||
if msg != "" { | ||
s.Suffix = " " + msg | ||
} | ||
if !s.Active() { | ||
s.Start() | ||
} | ||
} | ||
|
||
// StopSpinner stops a spinner with the given message. If the writer is not | ||
// a terminal or doesn't support colors, it simply prints the message. | ||
func StopSpinner(s *spinner.Spinner, msg string, w io.Writer) { | ||
if !isTerminal(w) || !shouldUseColors(w) { | ||
fmt.Fprintln(w, msg) | ||
return | ||
} | ||
|
||
if msg != "" { | ||
s.FinalMSG = "> " + msg + "\n" | ||
} | ||
|
||
s.Stop() | ||
} | ||
|
||
// StrikeThrough returns struck though text if the writer supports colors | ||
func StrikeThrough(text string) string { | ||
color := Color(os.Stdout) | ||
return color.Sprintf(color.StrikeThrough(text)) | ||
} | ||
|
||
func isTerminal(w io.Writer) bool { | ||
switch v := w.(type) { | ||
case *os.File: | ||
return terminal.IsTerminal(int(v.Fd())) | ||
default: | ||
return false | ||
} | ||
} | ||
|
||
func shouldUseColors(w io.Writer) bool { | ||
useColors := ForceColors || isTerminal(w) | ||
|
||
if EnvironmentOverrideColors { | ||
force, ok := os.LookupEnv("CLICOLOR_FORCE") | ||
|
||
switch { | ||
case ok && force != "0": | ||
useColors = true | ||
case ok && force == "0": | ||
useColors = false | ||
case os.Getenv("CLICOLOR") == "0": | ||
useColors = false | ||
} | ||
} | ||
|
||
return useColors && !DisableColors | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/auth0/auth0-cli/internal/config" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func actionsCmd(cfg *config.Config) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "actions", | ||
Short: "manage resources for actions.", | ||
} | ||
|
||
cmd.SetUsageTemplate(resourceUsageTemplate()) | ||
cmd.AddCommand(listActionsCmd(cfg)) | ||
cmd.AddCommand(createActionCmd(cfg)) | ||
cmd.AddCommand(renameActionCmd(cfg)) | ||
cmd.AddCommand(deleteActionCmd(cfg)) | ||
cmd.AddCommand(deployActionCmd(cfg)) | ||
|
||
return cmd | ||
} | ||
|
||
func listActionsCmd(cfg *config.Config) *cobra.Command { | ||
var flags struct { | ||
trigger string | ||
} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "list", | ||
Short: "List existing actions", | ||
Long: `List all actions within a tenant.`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
fmt.Println("list called") | ||
return nil | ||
}, | ||
} | ||
|
||
cmd.Flags().StringVarP(&flags.trigger, | ||
"trigger", "t", "", "Only list actions within this trigger.", | ||
) | ||
|
||
return cmd | ||
} | ||
|
||
func createActionCmd(cfg *config.Config) *cobra.Command { | ||
var flags struct { | ||
trigger string | ||
} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "create <name>", | ||
Short: "Create an action.", | ||
Long: `Creates an action, and generates a few files for working with actions: | ||
- code.js - function signature. | ||
- testdata.json - sample payload for testing the action. | ||
`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
fmt.Println("create called") | ||
return nil | ||
}, | ||
} | ||
|
||
cmd.Flags().StringVarP(&flags.trigger, | ||
"trigger", "t", "", "Supported trigger for the action.", | ||
) | ||
|
||
return cmd | ||
} | ||
|
||
func deployActionCmd(cfg *config.Config) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "deploy <name>", | ||
Short: "Deploy an action.", | ||
Long: `Deploy an action. This creates a new version. | ||
The deploy lifecycle is as follows: | ||
1. Build the code artifact. Produces a new version. | ||
2. Route production traffic at it. | ||
3. Bind it to the associated trigger (if not already bound). | ||
`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
fmt.Println("deploy called") | ||
return nil | ||
}, | ||
} | ||
|
||
return cmd | ||
} | ||
|
||
func renameActionCmd(cfg *config.Config) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "rename <name>", | ||
Short: "Rename an existing action.", | ||
Long: `Renames an action. If any generated files are found those files are also renamed.: | ||
The following generated files will be moved: | ||
- code.js | ||
- testdata.json | ||
`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
fmt.Println("rename called") | ||
return nil | ||
}, | ||
} | ||
|
||
return cmd | ||
} | ||
|
||
func deleteActionCmd(cfg *config.Config) *cobra.Command { | ||
var flags struct { | ||
confirm string | ||
} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "delete <name>", | ||
Short: "Delete an existing action.", | ||
Long: `Deletes an existing action. Only actions not bound to triggers can be deleted. | ||
To delete an action already bound, you have to: | ||
1. Remove it from the trigger. | ||
2. Delete the action after. | ||
Note that all code artifacts will also be deleted. | ||
`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
fmt.Println("delete called") | ||
return nil | ||
}, | ||
} | ||
|
||
cmd.Flags().StringVarP(&flags.confirm, | ||
"confirm", "c", "", "Confirm the action name to be deleted.", | ||
) | ||
|
||
return cmd | ||
} |
Oops, something went wrong.