Skip to content

Commit f192601

Browse files
committed
add app management capabilities
$ go run ./cli app create dex-4 ID NAME SLUG SCHEDULER 1qUVWDuO9XsaIZRuqOnGS42L3uz dex-4 dex-4-manatee kots $ go run ./cli app delete dex-4-manatee ID NAME SLUG SCHEDULER 1qUVWDuO9XsaIZRuqOnGS42L3uz dex-4 dex-4-manatee kots Delete the above listed application? There is no undo: no Error: prompt declined exit status 1 $ go run ./cli app delete dex-4-manatee ID NAME SLUG SCHEDULER 1qUVWDuO9XsaIZRuqOnGS42L3uz dex-4 dex-4-manatee kots Delete the above listed application? There is no undo: yes $ go run ./cli app ls dex- ID NAME SLUG SCHEDULER 1gpU6hFrwvXQvdU7CtG5ZTGRuy3 kots-dex-integration kots-dex-integration kots 1mIxSexfFN9SYPdEo6o4Ko1PQ5d kots-dex-2 kots-dex-2-longhorn kots 1XDWkWVtgvr4A20TREpCHEwRAun kots-dex-the third one kots-dex-2 kots $ go run ./cli app ls dex-4 ID NAME SLUG SCHEDULER
1 parent 85c1118 commit f192601

File tree

14 files changed

+466
-68
lines changed

14 files changed

+466
-68
lines changed

cli/cmd/app_create.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package cmd
2+
3+
import (
4+
"github.com/pkg/errors"
5+
"github.com/replicatedhq/replicated/cli/print"
6+
"github.com/replicatedhq/replicated/pkg/kotsclient"
7+
"github.com/replicatedhq/replicated/pkg/types"
8+
"github.com/spf13/cobra"
9+
)
10+
11+
func (r *runners) InitAppCreate(parent *cobra.Command) *cobra.Command {
12+
cmd := &cobra.Command{
13+
Use: "create NAME",
14+
Short: "create kots apps",
15+
Long: `create kots apps`,
16+
RunE: r.createApp,
17+
SilenceUsage: true,
18+
}
19+
parent.AddCommand(cmd)
20+
21+
return cmd
22+
}
23+
24+
func (r *runners) createApp(_ *cobra.Command, args []string) error {
25+
if len(args) != 1 {
26+
return errors.New("missing app name")
27+
}
28+
appName := args[0]
29+
30+
kotsRestClient := kotsclient.VendorV3Client{HTTPClient: *r.platformAPI}
31+
32+
33+
app, err := kotsRestClient.CreateKOTSApp(appName)
34+
35+
if err != nil {
36+
return errors.Wrap(err, "list apps")
37+
}
38+
39+
apps := []types.AppAndChannels{
40+
{
41+
App: &types.App{
42+
ID: app.ID,
43+
Name: app.Name,
44+
Slug: app.Slug,
45+
Scheduler: "kots",
46+
},
47+
},
48+
}
49+
50+
return print.Apps(r.w, apps)
51+
}

cli/cmd/app_delete.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package cmd
2+
3+
import (
4+
"github.com/manifoldco/promptui"
5+
"github.com/pkg/errors"
6+
"github.com/replicatedhq/replicated/cli/print"
7+
"github.com/replicatedhq/replicated/pkg/types"
8+
"github.com/spf13/cobra"
9+
"os"
10+
)
11+
12+
func (r *runners) InitAppDelete(parent *cobra.Command) *cobra.Command {
13+
cmd := &cobra.Command{
14+
Use: "delete NAME",
15+
Short: "delete kots apps",
16+
Long: `Delete a kots app. There is no undo for this operation, use with caution.`,
17+
RunE: r.deleteApp,
18+
SilenceUsage: true,
19+
}
20+
parent.AddCommand(cmd)
21+
cmd.Flags().BoolVarP(&r.args.deleteAppForceYes, "force", "f", false, "Skip confirmation prompt. There is no undo for this action.")
22+
23+
return cmd
24+
}
25+
26+
func (r *runners) deleteApp(_ *cobra.Command, args []string) error {
27+
log := print.NewLogger(r.w)
28+
if len(args) != 1 {
29+
return errors.New("missing app slug or id")
30+
}
31+
appName := args[0]
32+
33+
log.ActionWithSpinner("Fetching App")
34+
app, err := r.kotsAPI.GetApp(appName)
35+
if err != nil {
36+
log.FinishSpinnerWithError()
37+
return errors.Wrap(err, "list apps")
38+
}
39+
log.FinishSpinner()
40+
41+
apps := []types.AppAndChannels{{ App: app}}
42+
43+
err = print.Apps(r.w, apps)
44+
if err != nil {
45+
return errors.Wrap(err, "print app")
46+
}
47+
48+
if !r.args.deleteAppForceYes {
49+
answer, err := promptConfirmDelete()
50+
if err != nil {
51+
return errors.Wrap(err, "confirm deletion")
52+
}
53+
54+
if answer != "yes" {
55+
return errors.New("prompt declined")
56+
}
57+
}
58+
59+
60+
log.ActionWithSpinner("Deleting App")
61+
err = r.kotsAPI.DeleteKOTSApp(app.ID)
62+
if err != nil {
63+
log.FinishSpinnerWithError()
64+
return errors.Wrap(err, "delete app")
65+
}
66+
log.FinishSpinner()
67+
68+
return nil
69+
}
70+
71+
var templates = &promptui.PromptTemplates{
72+
Prompt: "{{ . | bold }} ",
73+
Valid: "{{ . | green }} ",
74+
Invalid: "{{ . | red }} ",
75+
Success: "{{ . | bold }} ",
76+
}
77+
78+
func promptConfirmDelete() (string, error) {
79+
80+
prompt := promptui.Prompt{
81+
Label: "Delete the above listed application? There is no undo:",
82+
Templates: templates,
83+
Default: "",
84+
Validate: func(input string) error {
85+
if input == "no" {
86+
return nil
87+
}
88+
89+
if input != "yes" {
90+
return errors.New(`only "yes" will be accepted`)
91+
}
92+
93+
return nil
94+
},
95+
}
96+
97+
for {
98+
result, err := prompt.Run()
99+
if err != nil {
100+
if err == promptui.ErrInterrupt {
101+
os.Exit(-1)
102+
}
103+
continue
104+
}
105+
106+
return result, nil
107+
}
108+
}

cli/cmd/app_ls.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package cmd
2+
3+
import (
4+
"github.com/pkg/errors"
5+
"github.com/replicatedhq/replicated/cli/print"
6+
"github.com/replicatedhq/replicated/pkg/types"
7+
"github.com/spf13/cobra"
8+
"strings"
9+
)
10+
11+
func (r *runners) InitAppList(parent *cobra.Command) *cobra.Command {
12+
cmd := &cobra.Command{
13+
Use: "ls [NAME]",
14+
Short: "list kots apps",
15+
Long: `list kots apps, or a single app by name`,
16+
RunE: r.listApps,
17+
SilenceUsage: true,
18+
}
19+
parent.AddCommand(cmd)
20+
21+
return cmd
22+
}
23+
24+
func (r *runners) listApps(_ *cobra.Command, args []string) error {
25+
26+
kotsApps, err := r.kotsAPI.ListApps()
27+
if err != nil {
28+
return errors.Wrap(err, "list apps")
29+
}
30+
31+
if len(args) == 0 {
32+
return print.Apps(r.w, kotsApps)
33+
}
34+
35+
appSearch := args[0]
36+
var apps []types.AppAndChannels
37+
for _, app := range kotsApps {
38+
if strings.Contains(app.App.ID, appSearch) || strings.Contains(app.App.Slug, appSearch) {
39+
apps = append(apps, app)
40+
}
41+
}
42+
return print.Apps(r.w, apps)
43+
}

cli/cmd/apps.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package cmd
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
)
6+
7+
func (r *runners) InitAppCommand(parent *cobra.Command) *cobra.Command {
8+
cmd := &cobra.Command{
9+
Use: "app",
10+
Short: "Manage apps",
11+
Long: `app can be used to list apps and create new apps`,
12+
}
13+
parent.AddCommand(cmd)
14+
15+
return cmd
16+
}

cli/cmd/release_create.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -409,13 +409,6 @@ func readYAMLDir(yamlDir string) (string, error) {
409409

410410
func promptForConfirm() (string, error) {
411411

412-
templates := &promptui.PromptTemplates{
413-
Prompt: "{{ . | bold }} ",
414-
Valid: "{{ . | green }} ",
415-
Invalid: "{{ . | red }} ",
416-
Success: "{{ . | bold }} ",
417-
}
418-
419412
prompt := promptui.Prompt{
420413
Label: "Create with these properties? (default Yes) [Y/n]",
421414
Templates: templates,

cli/cmd/root.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,14 @@ func Execute(rootCmd *cobra.Command, stdin io.Reader, stdout io.Writer, stderr i
192192
runCmds.InitEnterpriseInstallerRM(enterpriseInstallerCmd)
193193
runCmds.InitEnterpriseInstallerAssign(enterpriseInstallerCmd)
194194

195+
appCmd := runCmds.InitAppCommand(runCmds.rootCmd)
196+
runCmds.InitAppList(appCmd)
197+
runCmds.InitAppCreate(appCmd)
198+
runCmds.InitAppDelete(appCmd)
199+
195200
runCmds.rootCmd.SetUsageTemplate(rootCmdUsageTmpl)
196201

197-
prerunCommand := func(cmd *cobra.Command, args []string) error {
202+
preRunSetupAPIs := func(_ *cobra.Command, _ []string) error {
198203
if apiToken == "" {
199204
apiToken = os.Getenv("REPLICATED_API_TOKEN")
200205
if apiToken == "" {
@@ -218,33 +223,40 @@ func Execute(rootCmd *cobra.Command, stdin io.Reader, stdout io.Writer, stderr i
218223

219224
commonAPI := client.NewClient(platformOrigin, graphqlOrigin, apiToken, kurlDotSHOrigin)
220225
runCmds.api = commonAPI
226+
return nil
227+
}
228+
229+
prerunCommand := func(cmd *cobra.Command, args []string) error {
230+
if err := preRunSetupAPIs(cmd, args); err != nil {
231+
return errors.Wrap(err, "set up APIs")
232+
}
221233

222234
if appSlugOrID == "" {
223235
appSlugOrID = os.Getenv("REPLICATED_APP")
224236
}
225237

226-
appType, err := commonAPI.GetAppType(appSlugOrID)
238+
appType, err := runCmds.api.GetAppType(appSlugOrID)
227239
if err != nil {
228240
return err
229241
}
230242
runCmds.appType = appType
231243

232244
if appType == "platform" {
233-
app, err := platformAPI.GetApp(appSlugOrID)
245+
app, err := runCmds.platformAPI.GetApp(appSlugOrID)
234246
if err != nil {
235247
return err
236248
}
237249
runCmds.appID = app.Id
238250
runCmds.appSlug = app.Slug
239251
} else if appType == "ship" {
240-
app, err := shipAPI.GetApp(appSlugOrID)
252+
app, err := runCmds.shipAPI.GetApp(appSlugOrID)
241253
if err != nil {
242254
return err
243255
}
244256
runCmds.appID = app.ID
245257
runCmds.appSlug = app.Slug
246258
} else if appType == "kots" {
247-
app, err := kotsAPI.GetApp(appSlugOrID)
259+
app, err := runCmds.kotsAPI.GetApp(appSlugOrID)
248260
if err != nil {
249261
return err
250262
}
@@ -255,12 +267,14 @@ func Execute(rootCmd *cobra.Command, stdin io.Reader, stdout io.Writer, stderr i
255267
return nil
256268
}
257269

270+
258271
channelCmd.PersistentPreRunE = prerunCommand
259272
releaseCmd.PersistentPreRunE = prerunCommand
260273
collectorsCmd.PersistentPreRunE = prerunCommand
261274
entitlementsCmd.PersistentPreRunE = prerunCommand
262275
customersCmd.PersistentPreRunE = prerunCommand
263276
installerCmd.PersistentPreRunE = prerunCommand
277+
appCmd.PersistentPreRunE = preRunSetupAPIs
264278

265279
runCmds.rootCmd.AddCommand(Version())
266280

cli/cmd/runner.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,15 @@ type runnerArgs struct {
6161
createReleasePromoteVersion string
6262
createReleasePromoteEnsureChannel bool
6363
// Add Create Release Lint
64-
createReleaseLint bool
65-
lintReleaseYamlDir string
66-
lintReleaseFailOn string
67-
releaseOptional bool
68-
releaseNotes string
69-
releaseVersion string
70-
updateReleaseYaml string
71-
updateReleaseYamlDir string
72-
updateReleaseYamlFile string
64+
createReleaseLint bool
65+
lintReleaseYamlDir string
66+
lintReleaseFailOn string
67+
releaseOptional bool
68+
releaseNotes string
69+
releaseVersion string
70+
updateReleaseYaml string
71+
updateReleaseYamlDir string
72+
updateReleaseYamlFile string
7373

7474
entitlementsAPIServer string
7575
entitlementsVerbose bool
@@ -144,4 +144,5 @@ type runnerArgs struct {
144144
releaseDownloadDest string
145145
createInstallerAutoDefaults bool
146146
createInstallerAutoDefaultsAccept bool
147+
deleteAppForceYes bool
147148
}

cli/print/apps.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,21 @@ import (
44
"text/tabwriter"
55
"text/template"
66

7-
apps "github.com/replicatedhq/replicated/gen/go/v1"
7+
"github.com/replicatedhq/replicated/pkg/types"
88
)
99

10-
var appsTmplSrc = `ID NAME SCHEDULER
10+
var appsTmplSrc = `ID NAME SLUG SCHEDULER
1111
{{ range . -}}
12-
{{ .ID }} {{ .Name }} {{ .Scheduler }}
12+
{{ .ID }} {{ .Name }} {{ .Slug}} {{ .Scheduler }}
1313
{{ end }}`
1414

1515
var appsTmpl = template.Must(template.New("apps").Funcs(funcs).Parse(appsTmplSrc))
1616

17-
func Apps(w *tabwriter.Writer, apps []apps.AppAndChannels) error {
18-
as := make([]map[string]interface{}, len(apps))
17+
func Apps(w *tabwriter.Writer, apps []types.AppAndChannels) error {
18+
var as []*types.App
1919

20-
for i, a := range apps {
21-
as[i] = map[string]interface{}{
22-
"ID": a.App.Id,
23-
"Name": a.App.Name,
24-
"Scheduler": a.App.Scheduler,
25-
}
20+
for _, a := range apps {
21+
as = append(as, a.App)
2622
}
2723

2824
if err := appsTmpl.Execute(w, as); err != nil {

0 commit comments

Comments
 (0)