Skip to content

Commit 39f2cda

Browse files
authored
ZEA-2480: Implement list/delete domain (#73)
* feat(cmd/domain): Implement list domain cmd Signed-off-by: hackerchai <i@hackerchai.com> * feat(cmd/domain): Optimize domain create prompt Signed-off-by: hackerchai <i@hackerchai.com> * feat(cmd/domain): Implement domain delete cmd Signed-off-by: hackerchai <i@hackerchai.com> --------- Signed-off-by: hackerchai <i@hackerchai.com>
1 parent 5d88758 commit 39f2cda

File tree

7 files changed

+255
-4
lines changed

7 files changed

+255
-4
lines changed

internal/cmd/domain/create/create.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func NewCmdCreateDomain(f *cmdutil.Factory) *cobra.Command {
2626
cmd := &cobra.Command{
2727
Use: "create",
2828
Short: "create a domain",
29+
Long: `Create a domain for a service`,
2930
PreRunE: util.RunEChain(
3031
util.NeedProjectContextWhenNonInteractive(f),
3132
util.DefaultIDNameByContext(zctx.GetService(), &opts.id, &opts.name),
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package delete
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/briandowns/spinner"
8+
"github.com/spf13/cobra"
9+
10+
"github.com/zeabur/cli/internal/cmdutil"
11+
"github.com/zeabur/cli/internal/util"
12+
)
13+
14+
type Options struct {
15+
id string
16+
name string
17+
environmentID string
18+
domainName string
19+
skipConfirm bool
20+
}
21+
22+
func NewCmdDeleteDomain(f *cmdutil.Factory) *cobra.Command {
23+
opts := &Options{}
24+
zctx := f.Config.GetContext()
25+
26+
cmd := &cobra.Command{
27+
Use: "delete",
28+
Short: "Delete domain",
29+
Long: `Delete domain of a service`,
30+
Aliases: []string{"del"},
31+
PreRunE: util.RunEChain(
32+
util.NeedProjectContextWhenNonInteractive(f),
33+
util.DefaultIDNameByContext(zctx.GetService(), &opts.id, &opts.name),
34+
util.DefaultIDByContext(zctx.GetEnvironment(), &opts.environmentID),
35+
),
36+
RunE: func(cmd *cobra.Command, args []string) error {
37+
return runDeleteDomain(f, opts)
38+
},
39+
}
40+
41+
util.AddServiceParam(cmd, &opts.id, &opts.name)
42+
util.AddEnvOfServiceParam(cmd, &opts.environmentID)
43+
cmd.Flags().BoolVarP(&opts.skipConfirm, "yes", "y", false, "Skip confirmation")
44+
cmd.Flags().StringVar(&opts.domainName, "domain", "", "Domain name")
45+
46+
return cmd
47+
}
48+
49+
func runDeleteDomain(f *cmdutil.Factory, opts *Options) error {
50+
if f.Interactive {
51+
return runDeleteDomainInteractive(f, opts)
52+
} else {
53+
return runDeleteDomainNonInteractive(f, opts)
54+
}
55+
}
56+
57+
func runDeleteDomainInteractive(f *cmdutil.Factory, opts *Options) error {
58+
zctx := f.Config.GetContext()
59+
60+
if _, err := f.ParamFiller.ServiceByNameWithEnvironment(zctx, &opts.id, &opts.name, &opts.environmentID); err != nil {
61+
return err
62+
}
63+
64+
s := spinner.New(cmdutil.SpinnerCharSet, cmdutil.SpinnerInterval,
65+
spinner.WithColor(cmdutil.SpinnerColor),
66+
spinner.WithSuffix(fmt.Sprintf(" Fetching domains of service %s ...", opts.name)),
67+
)
68+
s.Start()
69+
domainList, err := f.ApiClient.ListDomains(context.Background(), opts.id, opts.environmentID)
70+
if err != nil {
71+
return err
72+
}
73+
s.Stop()
74+
75+
if len(domainList) == 0 {
76+
f.Log.Infof("No domains found")
77+
return nil
78+
}
79+
80+
domainNameList := make([]string, len(domainList))
81+
for i, domain := range domainList {
82+
domainNameList[i] = domain.Domain
83+
}
84+
deleteDomainSelection, err := f.Prompter.Select("Select domain to delete", "", domainNameList)
85+
if err != nil {
86+
return err
87+
}
88+
opts.domainName = domainNameList[deleteDomainSelection]
89+
90+
if opts.skipConfirm {
91+
return runDeleteDomainNonInteractive(f, opts)
92+
}
93+
94+
deleteConfirm, err := f.Prompter.Confirm(fmt.Sprintf("Are you sure to delete domain %s", opts.domainName), false)
95+
if err != nil {
96+
return err
97+
}
98+
99+
if !deleteConfirm {
100+
f.Log.Infof("Delete domain %s canceled", opts.domainName)
101+
return nil
102+
}
103+
104+
return runDeleteDomainNonInteractive(f, opts)
105+
}
106+
107+
func runDeleteDomainNonInteractive(f *cmdutil.Factory, opts *Options) error {
108+
zctx := f.Config.GetContext()
109+
110+
if _, err := f.ParamFiller.ServiceByNameWithEnvironment(zctx, &opts.id, &opts.name, &opts.environmentID); err != nil {
111+
return err
112+
}
113+
114+
s := spinner.New(cmdutil.SpinnerCharSet, cmdutil.SpinnerInterval,
115+
spinner.WithColor(cmdutil.SpinnerColor),
116+
spinner.WithSuffix(fmt.Sprintf(" Deleting selected domain: %s ...", opts.domainName)))
117+
s.Start()
118+
deleteResult, err := f.ApiClient.RemoveDomain(context.Background(), opts.domainName)
119+
if err != nil {
120+
return err
121+
}
122+
s.Stop()
123+
124+
if !deleteResult {
125+
f.Log.Warnf("Delete domain %s failed", opts.domainName)
126+
return nil
127+
}
128+
129+
f.Log.Infof("Delete domain %s success", opts.domainName)
130+
131+
return nil
132+
}

internal/cmd/domain/domain.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package domain
22

33
import (
44
"github.com/spf13/cobra"
5-
5+
66
domainCreateCmd "github.com/zeabur/cli/internal/cmd/domain/create"
7+
domainDeleteCmd "github.com/zeabur/cli/internal/cmd/domain/delete"
8+
domainListCmd "github.com/zeabur/cli/internal/cmd/domain/list"
79
"github.com/zeabur/cli/internal/cmdutil"
810
)
911

@@ -16,6 +18,8 @@ func NewCmdDomain(f *cmdutil.Factory) *cobra.Command {
1618
}
1719

1820
cmd.AddCommand(domainCreateCmd.NewCmdCreateDomain(f))
21+
cmd.AddCommand(domainListCmd.NewCmdListDomains(f))
22+
cmd.AddCommand(domainDeleteCmd.NewCmdDeleteDomain(f))
1923

2024
return cmd
2125
}

internal/cmd/domain/list/list.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package list
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/briandowns/spinner"
8+
"github.com/spf13/cobra"
9+
10+
"github.com/zeabur/cli/internal/cmdutil"
11+
"github.com/zeabur/cli/internal/util"
12+
)
13+
14+
type Options struct {
15+
id string
16+
name string
17+
environmentID string
18+
}
19+
20+
func NewCmdListDomains(f *cmdutil.Factory) *cobra.Command {
21+
opts := &Options{}
22+
zctx := f.Config.GetContext()
23+
24+
cmd := &cobra.Command{
25+
Use: "list",
26+
Short: "list domains",
27+
Long: `List domains of a service`,
28+
Args: cobra.NoArgs,
29+
Aliases: []string{"ls"},
30+
PreRunE: util.RunEChain(
31+
util.NeedProjectContextWhenNonInteractive(f),
32+
util.DefaultIDNameByContext(zctx.GetService(), &opts.id, &opts.name),
33+
util.DefaultIDByContext(zctx.GetEnvironment(), &opts.environmentID),
34+
),
35+
RunE: func(cmd *cobra.Command, args []string) error {
36+
return runListDomains(f, opts)
37+
},
38+
}
39+
40+
util.AddServiceParam(cmd, &opts.id, &opts.name)
41+
util.AddEnvOfServiceParam(cmd, &opts.environmentID)
42+
43+
return cmd
44+
}
45+
46+
func runListDomains(f *cmdutil.Factory, opts *Options) error {
47+
if f.Interactive {
48+
return runListDomainsInteractive(f, opts)
49+
} else {
50+
return runListDomainsNonInteractive(f, opts)
51+
}
52+
}
53+
54+
func runListDomainsInteractive(f *cmdutil.Factory, opts *Options) error {
55+
zctx := f.Config.GetContext()
56+
57+
if _, err := f.ParamFiller.ServiceByNameWithEnvironment(zctx, &opts.id, &opts.name, &opts.environmentID); err != nil {
58+
return err
59+
}
60+
61+
return runListDomainsNonInteractive(f, opts)
62+
}
63+
64+
func runListDomainsNonInteractive(f *cmdutil.Factory, opts *Options) error {
65+
zctx := f.Config.GetContext()
66+
67+
if _, err := f.ParamFiller.ServiceByNameWithEnvironment(zctx, &opts.id, &opts.name, &opts.environmentID); err != nil {
68+
return err
69+
}
70+
71+
s := spinner.New(cmdutil.SpinnerCharSet, cmdutil.SpinnerInterval,
72+
spinner.WithColor(cmdutil.SpinnerColor),
73+
spinner.WithSuffix(fmt.Sprintf(" Fetching domains of service %s ...", opts.name)),
74+
)
75+
s.Start()
76+
domainList, err := f.ApiClient.ListDomains(context.Background(), opts.id, opts.environmentID)
77+
if err != nil {
78+
return err
79+
}
80+
s.Stop()
81+
82+
if len(domainList) == 0 {
83+
f.Log.Infof("No domains found")
84+
return nil
85+
}
86+
87+
f.Printer.Table(domainList.Header(), domainList.Rows())
88+
89+
return nil
90+
}

pkg/api/domain.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (c *client) AddDomain(ctx context.Context, serviceID string, environmentID
5151
return &mutation.AddDomain.Domain, nil
5252
}
5353

54-
func (c *client) ListDomains(ctx context.Context, serviceID string, environmentID string) ([]*model.Domain, error) {
54+
func (c *client) ListDomains(ctx context.Context, serviceID string, environmentID string) (model.Domains, error) {
5555
var query struct {
5656
Service struct {
5757
Domains model.Domains `graphql:"domains(environmentID: $environmentID)"`

pkg/api/interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type (
6363

6464
DomainAPI interface {
6565
AddDomain(ctx context.Context, serviceID string, environmentID string, isGenerated bool, domain string, options ...string) (*string, error)
66-
ListDomains(ctx context.Context, serviceID string, environmentID string) ([]*model.Domain, error)
66+
ListDomains(ctx context.Context, serviceID string, environmentID string) (model.Domains, error)
6767
RemoveDomain(ctx context.Context, domain string) (bool, error)
6868
CheckDomainAvailable(ctx context.Context, domain string, isGenerated bool) (bool, string, error)
6969
}

pkg/model/domain.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package model
22

3-
import "time"
3+
import (
4+
"strconv"
5+
"time"
6+
)
47

58
type Domain struct {
69
ID string `json:"id" graphql:"_id"`
@@ -16,3 +19,24 @@ type Domain struct {
1619
}
1720

1821
type Domains []*Domain
22+
23+
func (d Domains) Header() []string {
24+
return []string{"ID", "Domain", "RedirectTo", "Status", "IsGenerated", "CreatedAt"}
25+
}
26+
27+
func (d Domains) Rows() [][]string {
28+
rows := make([][]string, 0, len(d))
29+
headerLen := len(d.Header())
30+
for _, domain := range d {
31+
row := make([]string, 0, headerLen)
32+
row = append(row, domain.ID)
33+
row = append(row, domain.Domain)
34+
row = append(row, domain.RedirectTo)
35+
row = append(row, domain.Status)
36+
row = append(row, strconv.FormatBool(domain.IsGenerated))
37+
row = append(row, domain.CreatedAt.Format(time.RFC3339))
38+
39+
rows = append(rows, row)
40+
}
41+
return rows
42+
}

0 commit comments

Comments
 (0)