Skip to content

Commit

Permalink
better cli
Browse files Browse the repository at this point in the history
  • Loading branch information
YieldRay committed Feb 12, 2024
1 parent 9ac9fe6 commit 66e1a65
Show file tree
Hide file tree
Showing 22 changed files with 626 additions and 403 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 YieldRay
Copyright (c) 2024 YieldRay

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
42 changes: 24 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
# surgecli

third party [surge.sh](https://surge.sh) cli written in golang
currently, `.surgeignore` file is not fully supported
Third party [surge.sh](https://surge.sh) cli written in golang

Features:

- Single executable
- Compatible with the official CLI
- Multi-user support
- Friendly for CI environments

## usage

manage your site
Manage your site

```sh
surgecli login <username> <password> # skip this if you have already logged in
Expand All @@ -20,7 +26,7 @@ surgecli list
surgecli teardown mydomain.example.net
```

you may want to upload your site with something like Github Actions, see this
You may want to upload your site with something like Github Actions, see this

```sh
# first, fetch token from your local machine
Expand All @@ -33,27 +39,27 @@ export SURGE_TOKEN=<your_token>
surgecli upload --silent . mysite.surge.sh
```

command help
Command help

```
```sh
NAME:
surgecli - thrid party surge.sh cli

USAGE:
surgecli [global options] command [command options] [arguments...]
surgecli [global options] command [command options]

COMMANDS:
account Show account information
fetch-token Fetch token by email and password, but do not save the token like login command
list List my sites
login Login (or create new account) to surge.sh
logout Logout from surge.sh
api Print or set api host, the official host is https://surge.surge.sh
su Switch user
teardown, delete Delete site from surge.sh
upload, deploy Upload a directory (a.k.a. deploy a project) to surge.sh
whoami Show my email
help, h Shows a list of commands or help for one command
account, me Show account information
api Set or Show API base URL, the official one is https://surge.surge.sh
fetch-token, token Fetch token by email and password, but do not save the token like login command
list, ls List my sites
login Login (or create new account) to surge.sh
logout Logout from surge.sh
su Switch user
teardown, delete, rm Delete site from current account
upload, deploy Upload a directory (a.k.a. deploy a project) to surge.sh
whoami Show my email
help, h Shows a list of commands or help for one command

GLOBAL OPTIONS:
--debug toggle debug on (default: false)
Expand Down
54 changes: 33 additions & 21 deletions cli/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,40 @@ import (
"fmt"
"strings"

"github.com/charmbracelet/huh/spinner"
"github.com/urfave/cli/v2"
"github.com/yieldray/surgecli/types"
)

func (c *privateSurgeCLI) AccountCommand() *cli.Command {
return &cli.Command{
Name: "account",
Usage: "Show account information",
Action: func(cCtx *cli.Context) error {
if email := c.surgesh.Whoami(); email == "" {
fmt.Println("<YOU ARE NOT LOGGED IN>")
return fmt.Errorf("unauthorized")
}
ac, err := c.surgesh.Account()
if err != nil {
return err
}
fmt.Printf("%-6s: %s\n", "Email", ac.Email)
fmt.Printf("%-6s: %s\n", "ID", ac.ID)
fmt.Printf("%-6s: %s\n", "UUID", ac.UUID)
fmt.Printf("%-6s: %s\n", "Plan", ac.Plan.Name)
fmt.Printf("\n[FEATURES]\n%s\n", strings.Join(ac.Plan.Perks, "\n"))
return nil
},
}
func init() {
Commands = append(Commands,
&cli.Command{
Name: "account",
Aliases: []string{"me"},
Usage: "Show account information",
Action: func(cCtx *cli.Context) error {

if email := surgesh.Whoami(); email == "" {
fmt.Println("<YOU ARE NOT LOGGED IN>")
return fmt.Errorf("unauthorized")
}

var acc types.Account
var err error
spinner.New().Title("Fetching...").Action(func() {
acc, err = surgesh.Account()
}).Run()

if err != nil {
return err
}

fmt.Printf("%-6s: %s\n", "Email", acc.Email)
fmt.Printf("%-6s: %s\n", "ID", acc.ID)
fmt.Printf("%-6s: %s\n", "UUID", acc.UUID)
fmt.Printf("%-6s: %s\n", "Plan", acc.Plan.Name)
fmt.Printf("\n[FEATURES]\n%s\n", strings.Join(acc.Plan.Perks, "\n"))
return nil
},
})
}
76 changes: 51 additions & 25 deletions cli/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,59 @@ package cli

import (
"fmt"
"os"
"net/url"

"github.com/charmbracelet/huh"
"github.com/urfave/cli/v2"
surgeUtils "github.com/yieldray/surgecli/utils"
"github.com/yieldray/surgecli/utils"
)

func (c *privateSurgeCLI) ProxyCommand() *cli.Command {
return &cli.Command{
Name: "api",
Usage: "Print or set api host, the official host is https://surge.surge.sh",
ArgsUsage: "<host>",
Action: func(cCtx *cli.Context) error {
api := cCtx.Args().First()
prevApi := surgeUtils.ConfGetApi()
if len(api) == 0 {
fmt.Printf("Usage: %s api https://surge.surge.sh\n", os.Args[0])
fmt.Printf("Current api host is %s\n", prevApi)
return nil
}

if err := surgeUtils.ConfSetApi(api); err != nil {
return err
} else {
fmt.Printf("The previous api host is %s\n", prevApi)
fmt.Printf("Your api host has been set to %s\n", api)
return nil
}
},
}
func init() {
var isShow int
var isReset int

Commands = append(Commands,
&cli.Command{
Name: "api",
Usage: "Set or Show API base URL, the official one is https://surge.surge.sh",
ArgsUsage: "[<baseURL>]",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "show",
Usage: "Show current API base URL",
Count: &isShow,
}, &cli.BoolFlag{
Name: "reset",
Usage: "Reset API base URL to official one",
Count: &isReset,
}},
Action: func(cCtx *cli.Context) error {

prevApi := utils.ConfGetApi()
if isShow > 0 {
fmt.Println(prevApi)
return nil
}

api := cCtx.Args().First()

if isReset > 0 {
api = "https://surge.surge.sh"
} else if len(api) == 0 {
huh.NewInput().Title("Enter new API base").Placeholder(prevApi).
Suggestions([]string{"https://surge.surge.sh"}).
Validate(func(s string) error {
_, err := url.ParseRequestURI(s)
return err
}).Value(&api).Run()
}

if err := utils.ConfSetApi(api); err != nil {
return err
} else {
fmt.Printf("API base URL has been set to %s\n", api)
return nil
}
},
})
}
88 changes: 48 additions & 40 deletions cli/fetchToken.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,63 @@ package cli

import (
"fmt"
"os"

"github.com/charmbracelet/huh"
"github.com/charmbracelet/huh/spinner"
"github.com/urfave/cli/v2"
"github.com/yieldray/surgecli/api"
surgeUtils "github.com/yieldray/surgecli/utils"
"github.com/yieldray/surgecli/types"
"github.com/yieldray/surgecli/utils"
)

func (c *privateSurgeCLI) FetchTokenCommand() *cli.Command {
func init() {
var isLocal int

return &cli.Command{
Name: "fetch-token",
Usage: "Fetch token by email and password, but do not save the token like login command",
ArgsUsage: "<username> <password>",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "local",
Usage: "Only print token from ~/.netrc file, rather than login to server",
Count: &isLocal,
}},
Action: func(cCtx *cli.Context) error {

// print local token
if isLocal > 0 {
if _, token, err := surgeUtils.ReadNetrc(); err != nil {
Commands = append(Commands,
&cli.Command{
Name: "fetch-token",
Aliases: []string{"token"},
Usage: "Fetch token by email and password, but do not save the token like login command",
ArgsUsage: "[<username> <password>]",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "local",
Usage: "Only print token from ~/.netrc file, rather than login to server",
Count: &isLocal,
}},
Action: func(cCtx *cli.Context) error {

// print local token
if isLocal > 0 {
if _, token, err := utils.ReadNetrc(); err != nil {
return err
} else {
fmt.Println(token)
return nil
}
}

// otherwise, login to server and print token
username := cCtx.Args().Get(0)
password := cCtx.Args().Get(1)

if password == "" {
huh.NewInput().Title("Enter you username (email)").Value(&username).Run()
huh.NewInput().Title("Enter you password").Value(&password).Run()
}

var tokens types.Token
var err error
spinner.New().Title("Fetching...").Action(func() {
tokens, err = api.Token(httpClient, username, password)
}).Run()

if err != nil {
return err
} else {
fmt.Println(token)
fmt.Println(tokens.Token)
return nil
}
}

// otherwise, login to server and print token
username := cCtx.Args().Get(0)
password := cCtx.Args().Get(1)

if password == "" {
fmt.Printf("Usage: \n%s fetch-token <username> <password> \n%s fetch token --local\n",
os.Args[0], os.Args[0])
return fmt.Errorf("command failed")
}

if tokens, err := api.Token(CustomHttpClient(), username, password); err != nil {
return err
} else {
fmt.Println(tokens.Token)
return nil
}

},
}
},
})
}
Loading

0 comments on commit 66e1a65

Please sign in to comment.