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
3 changes: 3 additions & 0 deletions cmd/api_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ var apiKeyCmd = &cobra.Command{
return err
}

if isJSONOutput() {
return printJSON(result)
}
fmt.Printf("Valid API key for team: %s\n", result.TeamName)
return nil
},
Expand Down
3 changes: 3 additions & 0 deletions cmd/login.go → cmd/auth_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ var loginCmd = &cobra.Command{
return err
}

if isJSONOutput() {
return printJSON(Result{Success: true, Message: fmt.Sprintf("Authenticated as team: %s", result.TeamName)})
}
fmt.Printf("API key saved. Authenticated as team: %s\n", result.TeamName)
return nil
},
Expand Down
3 changes: 3 additions & 0 deletions cmd/logout.go → cmd/auth_logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ var logoutCmd = &cobra.Command{
if err := config.Delete(); err != nil {
return err
}
if isJSONOutput() {
return printJSON(Result{Success: true})
}
fmt.Println("Logged out.")
return nil
},
Expand Down
10 changes: 4 additions & 6 deletions cmd/debug.go → cmd/auth_status.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package cmd

import (
"encoding/json"
"fmt"
"os"

"github.com/loops-so/cli/internal/config"
"github.com/spf13/cobra"
Expand All @@ -18,12 +16,12 @@ var statusCmd = &cobra.Command{
return err
}

out, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return err
if isJSONOutput() {
return printJSON(cfg)
}

fmt.Fprintln(os.Stdout, string(out))
fmt.Printf("API Key: %s\n", cfg.APIKey)
fmt.Printf("Endpoint: %s\n", cfg.EndpointURL)
return nil
},
}
Expand Down
37 changes: 37 additions & 0 deletions cmd/output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package cmd

import (
"encoding/json"
"fmt"
"os"
)

type outputFlag string

func (o *outputFlag) Set(s string) error {
switch s {
case "text", "json":
*o = outputFlag(s)
return nil
default:
return fmt.Errorf("must be \"text\" or \"json\"")
}
}

func (o *outputFlag) String() string { return string(*o) }
func (o *outputFlag) Type() string { return "format" }

type Result struct {
Success bool `json:"success"`
Message string `json:"message,omitempty"`
}

func isJSONOutput() bool {
return outputFormat == "json"
}

func printJSON(v any) error {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(v)
}
22 changes: 22 additions & 0 deletions cmd/output_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cmd

import "testing"

func TestOutputFlagSet(t *testing.T) {
for _, valid := range []string{"text", "json"} {
var f outputFlag
if err := f.Set(valid); err != nil {
t.Errorf("Set(%q) unexpected error: %v", valid, err)
}
if string(f) != valid {
t.Errorf("Set(%q) got %q", valid, f)
}
}

for _, invalid := range []string{"yaml", "csv", ""} {
var f outputFlag
if err := f.Set(invalid); err == nil {
t.Errorf("Set(%q) expected error, got nil", invalid)
}
}
}
21 changes: 14 additions & 7 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,32 @@ Copyright © 2026 NAME HERE <EMAIL ADDRESS>
package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

var outputFormat outputFlag = "text"

var rootCmd = &cobra.Command{
Use: "loops",
Short: "The official CLI for Loops (https://loops.so)",
Long: "The official CLI for Loops (https://loops.so)",
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
Use: "loops",
Short: "The official CLI for Loops (https://loops.so)",
Long: "The official CLI for Loops (https://loops.so)",
SilenceErrors: true,
SilenceUsage: true,
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
if isJSONOutput() {
printJSON(Result{Success: false, Message: err.Error()})
} else {
fmt.Fprintln(os.Stderr, "Error:", err)
}
os.Exit(1)
}
}
Expand All @@ -36,5 +43,5 @@ func init() {

// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
rootCmd.PersistentFlags().VarP(&outputFormat, "output", "o", "Output format (text, json)")
}
10 changes: 10 additions & 0 deletions cmd/transactional.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ var transactionalListCmd = &cobra.Command{
return err
}

if isJSONOutput() {
if emails == nil {
emails = []api.TransactionalEmail{}
}
return printJSON(emails)
}

if len(emails) == 0 {
fmt.Println("No transactional emails found.")
return nil
Expand Down Expand Up @@ -133,6 +140,9 @@ var transactionalSendCmd = &cobra.Command{
return err
}

if isJSONOutput() {
return printJSON(Result{Success: true})
}
fmt.Println("Sent.")
return nil
},
Expand Down
Loading