Skip to content

Commit bc9568f

Browse files
authored
feat: Manage profiles & workspaces (#52)
* feat: Update CLI authentication to user scope * feat: Manage workspace commands * feat: Remove legacy profile * feat: Manage keys in profile with the same schema as legacy profile * fix: Change relevant team field in config when switching workspace * feat: Manage profiles * fix: Use new CLI auth for listen command * fix: Logout cmd * fix: Interactive login * refactor: Error handling * fix: Guest mode login * refactor: Change local config file flag variable name * fix: Change command descriptions * chore: Remove commented code * refactor: Change team and workspace nomenclature * feat: Remove profile management commands * feat: Remove team ID reference in workspace commands * docs: Add workspace management command docs in README
1 parent 20a3afb commit bc9568f

File tree

21 files changed

+368
-564
lines changed

21 files changed

+368
-564
lines changed

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,30 @@ Inventory Service forwarding to /webhooks/shopify/inventory
219219

220220
```
221221

222+
### Manage active workspace
223+
224+
If you are a part of many workspaces, you can switch between them using our workspace management commands.
225+
226+
```sh-session
227+
$ hookdeck workspace list
228+
My Workspace (current)
229+
Another Workspace
230+
Yet Another One
231+
232+
$ hookdeck workspace use
233+
Use the arrow keys to navigate: ↓ ↑ → ←
234+
? Select Workspace:
235+
My Workspace
236+
Another Workspace
237+
▸ Yet Another One
238+
239+
Selecting workspace Yet Another One
240+
241+
$ hookdeck whoami
242+
Using profile default
243+
Logged in as Me in workspace Yet Another One
244+
```
245+
222246
## Developing
223247

224248
Build from source by running:

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ require (
2222
)
2323

2424
require (
25+
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
2526
github.com/creack/pty v1.1.9 // indirect
2627
github.com/davecgh/go-spew v1.1.1 // indirect
2728
github.com/fatih/color v1.9.0 // indirect
@@ -34,6 +35,7 @@ require (
3435
github.com/kr/text v0.2.0 // indirect
3536
github.com/magefile/mage v1.10.0 // indirect
3637
github.com/magiconair/properties v1.8.3 // indirect
38+
github.com/manifoldco/promptui v0.9.0 // indirect
3739
github.com/mattn/go-colorable v0.1.7 // indirect
3840
github.com/mattn/go-isatty v0.0.12 // indirect
3941
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
3232
github.com/briandowns/spinner v1.11.1 h1:OixPqDEcX3juo5AjQZAnFPbeUA0jvkp2qzB5gOZJ/L0=
3333
github.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
3434
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
35+
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
36+
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
37+
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
38+
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
3539
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
3640
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
3741
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -160,6 +164,8 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
160164
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
161165
github.com/magiconair/properties v1.8.3 h1:kJSsc6EXkBLgr3SphHk9w5mtjn0bjlR4JYEXKrJ45rQ=
162166
github.com/magiconair/properties v1.8.3/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
167+
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
168+
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
163169
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
164170
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
165171
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -338,6 +344,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
338344
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
339345
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
340346
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
347+
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
341348
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
342349
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
343350
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

pkg/cmd/root.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,13 @@ func Execute() {
8989
func init() {
9090
cobra.OnInitialize(Config.InitConfig)
9191

92+
rootCmd.PersistentFlags().StringVarP(&Config.Profile.Name, "profile", "p", "", fmt.Sprintf("profile name (default \"%s\")", hookdeck.DefaultProfileName))
9293
rootCmd.PersistentFlags().StringVar(&Config.Profile.APIKey, "cli-key", "", "Your CLI key to use for the command")
9394
rootCmd.PersistentFlags().StringVar(&Config.Color, "color", "", "turn on/off color output (on, off, auto)")
94-
rootCmd.PersistentFlags().StringVar(&Config.ProfilesFile, "config", "", "config file (default is $HOME/.config/hookdeck/config.toml)")
95-
rootCmd.PersistentFlags().StringVar(&Config.Profile.DeviceName, "device-name", "", "device name")
95+
rootCmd.PersistentFlags().StringVar(&Config.LocalConfigFile, "config", "", "config file (default is $HOME/.config/hookdeck/config.toml)")
96+
rootCmd.PersistentFlags().StringVar(&Config.DeviceName, "device-name", "", "device name")
9697
rootCmd.PersistentFlags().StringVar(&Config.LogLevel, "log-level", "info", "log level (debug, info, warn, error)")
9798
rootCmd.PersistentFlags().BoolVar(&Config.Insecure, "insecure", false, "Allow invalid TLS certificates")
98-
rootCmd.PersistentFlags().StringVarP(&Config.Profile.ProfileName, "project-name", "p", "", fmt.Sprintf("the project name to read from for config (default \"%s\")", hookdeck.DefaultProfileName))
9999

100100
// Hidden configuration flags, useful for dev/debugging
101101
rootCmd.PersistentFlags().StringVar(&Config.APIBaseURL, "api-base", "", fmt.Sprintf("Sets the API base URL (default \"%s\")", hookdeck.DefaultAPIBaseURL))
@@ -111,4 +111,5 @@ func init() {
111111
rootCmd.AddCommand(newListenCmd().cmd)
112112
rootCmd.AddCommand(newCompletionCmd().cmd)
113113
rootCmd.AddCommand(newWhoamiCmd().cmd)
114+
rootCmd.AddCommand(newWorkspaceCmd().cmd)
114115
}

pkg/cmd/whoami.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,15 @@ func newWhoamiCmd() *whoamiCmd {
2929
}
3030

3131
func (lc *whoamiCmd) runWhoamiCmd(cmd *cobra.Command, args []string) error {
32-
key, err := Config.Profile.GetAPIKey()
33-
if err != nil {
34-
return err
35-
}
36-
response, err := login.ValidateKey(Config.APIBaseURL, key)
32+
color := ansi.Color(os.Stdout)
33+
34+
fmt.Printf( "Using profile %s\n", color.Bold(Config.Profile.Name))
35+
36+
response, err := login.ValidateKey(Config.APIBaseURL, Config.Profile.APIKey, Config.Profile.TeamID)
3737
if err != nil {
3838
return err
3939
}
4040

41-
color := ansi.Color(os.Stdout)
42-
4341
fmt.Printf(
4442
"Logged in as %s in workspace %s\n",
4543
color.Bold(response.UserName),

pkg/cmd/workspace.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package cmd
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
6+
"github.com/hookdeck/hookdeck-cli/pkg/validators"
7+
)
8+
9+
type workspaceCmd struct {
10+
cmd *cobra.Command
11+
}
12+
13+
func newWorkspaceCmd() *workspaceCmd {
14+
lc := &workspaceCmd{}
15+
16+
lc.cmd = &cobra.Command{
17+
Use: "workspace",
18+
Args: validators.NoArgs,
19+
Short: "Manage your workspaces",
20+
}
21+
22+
lc.cmd.AddCommand(newWorkspaceListCmd().cmd)
23+
lc.cmd.AddCommand(newWorkspaceUseCmd().cmd)
24+
25+
return lc
26+
}

pkg/cmd/workspace_list.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/spf13/cobra"
8+
9+
"github.com/hookdeck/hookdeck-cli/pkg/ansi"
10+
"github.com/hookdeck/hookdeck-cli/pkg/validators"
11+
"github.com/hookdeck/hookdeck-cli/pkg/workspace"
12+
)
13+
14+
type workspaceListCmd struct {
15+
cmd *cobra.Command
16+
}
17+
18+
func newWorkspaceListCmd() *workspaceListCmd {
19+
lc := &workspaceListCmd{}
20+
21+
lc.cmd = &cobra.Command{
22+
Use: "list",
23+
Args: validators.NoArgs,
24+
Short: "List your workspaces",
25+
RunE: lc.runWorkspaceListCmd,
26+
}
27+
28+
return lc
29+
}
30+
31+
func (lc *workspaceListCmd) runWorkspaceListCmd(cmd *cobra.Command, args []string) error {
32+
// TODO: validate API key ??
33+
34+
workspaces, err := workspace.ListWorkspaces(&Config)
35+
if err != nil {
36+
return err
37+
}
38+
39+
color := ansi.Color(os.Stdout)
40+
41+
for _, workspace := range workspaces {
42+
if workspace.Id == Config.Profile.TeamID {
43+
fmt.Printf("%s (current)\n", color.Green(workspace.Name))
44+
} else {
45+
fmt.Printf("%s\n", workspace.Name)
46+
}
47+
}
48+
49+
return nil
50+
}

pkg/cmd/workspace_use.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package cmd
2+
3+
import (
4+
"github.com/manifoldco/promptui"
5+
"github.com/spf13/cobra"
6+
7+
"github.com/hookdeck/hookdeck-cli/pkg/validators"
8+
"github.com/hookdeck/hookdeck-cli/pkg/workspace"
9+
)
10+
11+
type workspaceUseCmd struct {
12+
cmd *cobra.Command
13+
}
14+
15+
func newWorkspaceUseCmd() *workspaceUseCmd {
16+
lc := &workspaceUseCmd{}
17+
18+
lc.cmd = &cobra.Command{
19+
Use: "use",
20+
Args: validators.MaximumNArgs(1),
21+
Short: "Select your active workspace for future commands",
22+
RunE: lc.runWorkspaceUseCmd,
23+
}
24+
25+
return lc
26+
}
27+
28+
// TODO: handle case where workspace name is not unique
29+
func (lc *workspaceUseCmd) runWorkspaceUseCmd(cmd *cobra.Command, args []string) error {
30+
workspaces, err := workspace.ListWorkspaces(&Config)
31+
if err != nil {
32+
return err
33+
}
34+
35+
templates := &promptui.SelectTemplates{
36+
Active: "▸ {{ .Name | green }}",
37+
Inactive: " {{ .Name }}",
38+
Selected: "Selecting workspace {{ .Name | green }}",
39+
}
40+
41+
prompt := promptui.Select{
42+
Label: "Select Workspace",
43+
Items: workspaces,
44+
Templates: templates,
45+
}
46+
47+
i, _, err := prompt.Run()
48+
if err != nil {
49+
return err
50+
}
51+
52+
workspace := workspaces[i]
53+
return Config.UseWorkspace(workspace.Id, workspace.Mode)
54+
}

0 commit comments

Comments
 (0)