Skip to content

Commit 2ad5da7

Browse files
authored
improve init UX (#2424)
1 parent 02f8127 commit 2ad5da7

File tree

5 files changed

+79
-41
lines changed

5 files changed

+79
-41
lines changed

internal/cmd/alpha/function/init.go

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,21 @@ import (
66
"os"
77
"path"
88
"path/filepath"
9+
"sort"
910
"strings"
1011

1112
"github.com/kyma-project/cli.v3/internal/clierror"
1213
"github.com/kyma-project/cli.v3/internal/cmdcommon"
13-
"github.com/kyma-project/cli.v3/internal/cmdcommon/flags"
14+
"github.com/pkg/errors"
1415
"github.com/spf13/cobra"
1516
"gopkg.in/yaml.v3"
1617
)
1718

19+
type extensionConfig struct {
20+
DefaultRuntime string `yaml:"defaultRuntime"`
21+
Runtimes map[string]runtimeConfig `yaml:"runtimes"`
22+
}
23+
1824
type runtimeConfig struct {
1925
DepsFilename string `yaml:"depsFilename"`
2026
DepsData string `yaml:"depsData"`
@@ -25,77 +31,78 @@ type runtimeConfig struct {
2531
type initConfig struct {
2632
*cmdcommon.KymaConfig
2733

28-
runtimesConfig map[string]runtimeConfig
34+
extensionConfig *extensionConfig
2935

3036
runtime string
3137
dir string
3238
}
3339

34-
func NewInitCmd(kymaConfig *cmdcommon.KymaConfig, cmdConfig interface{}) *cobra.Command {
40+
func NewInitCmd(kymaConfig *cmdcommon.KymaConfig, cmdConfig interface{}) (*cobra.Command, error) {
41+
extensionConfig, err := parseExtensionConfig(cmdConfig)
42+
if err != nil {
43+
return nil, err
44+
}
45+
3546
cfg := &initConfig{
36-
KymaConfig: kymaConfig,
47+
KymaConfig: kymaConfig,
48+
extensionConfig: extensionConfig,
3749
}
3850

3951
cmd := &cobra.Command{
4052
Use: "init",
4153
Short: "Init source and dependencies files locally",
4254
Long: "Use this command to initialize source and dependencies files for a Function.",
4355
PreRun: func(cmd *cobra.Command, _ []string) {
44-
clierror.Check(flags.Validate(cmd.Flags(), flags.MarkRequired("runtime")))
45-
clierror.Check(cfg.complete(cmdConfig))
4656
clierror.Check(cfg.validate())
4757
},
4858
Run: func(cmd *cobra.Command, _ []string) {
4959
clierror.Check(runInit(cfg, cmd.OutOrStdout()))
5060
},
5161
}
5262

53-
cmd.Flags().StringVar(&cfg.runtime, "runtime", "", "Runtime for which the files are generated")
63+
cmd.Flags().StringVar(&cfg.runtime, "runtime", cfg.extensionConfig.DefaultRuntime, fmt.Sprintf("Runtime for which the files are generated [ %s ]", sortedRuntimesString(cfg.extensionConfig.Runtimes)))
5464
cmd.Flags().StringVar(&cfg.dir, "dir", ".", "Path to the directory where files must be created")
5565

56-
return cmd
66+
return cmd, nil
5767
}
5868

59-
func (c *initConfig) complete(cmdConfig interface{}) clierror.Error {
69+
func parseExtensionConfig(cmdConfig interface{}) (*extensionConfig, error) {
6070
if cmdConfig == nil {
61-
return clierror.New("unexpected extension error, empty config")
71+
return nil, errors.New("unexpected extension error, empty config object")
6272
}
6373

6474
configBytes, err := yaml.Marshal(cmdConfig)
6575
if err != nil {
66-
return clierror.Wrap(err, clierror.New("failed to marshal config"))
76+
return nil, errors.Wrap(err, "failed to marshal config")
6777
}
6878

69-
err = yaml.Unmarshal(configBytes, &c.runtimesConfig)
79+
extCfg := extensionConfig{}
80+
err = yaml.Unmarshal(configBytes, &extCfg)
7081
if err != nil {
71-
return clierror.Wrap(err, clierror.New("failed to unmarshal config"))
82+
return nil, errors.Wrap(err, "failed to unmarshal config")
7283
}
7384

74-
return nil
85+
if extCfg.DefaultRuntime == "" || len(extCfg.Runtimes) == 0 {
86+
// simple validation
87+
return nil, errors.New("unexpected extension error, empty config data")
88+
}
89+
90+
return &extCfg, nil
7591
}
7692

7793
func (c *initConfig) validate() clierror.Error {
78-
if _, ok := c.runtimesConfig[c.runtime]; !ok {
94+
if _, ok := c.extensionConfig.Runtimes[c.runtime]; !ok {
7995
return clierror.New(
8096
fmt.Sprintf("unsupported runtime %s", c.runtime),
81-
fmt.Sprintf("use on the allowed runtimes on this cluster [ %s ]", strings.Join(mapKeys(c.runtimesConfig), " / ")),
97+
fmt.Sprintf("use on the allowed runtimes on this cluster [ %s ]", sortedRuntimesString(c.extensionConfig.Runtimes)),
8298
)
8399
}
84100

85101
return nil
86102
}
87103

88-
func mapKeys(m map[string]runtimeConfig) []string {
89-
keys := []string{}
90-
for key := range m {
91-
keys = append(keys, key)
92-
}
93-
94-
return keys
95-
}
96-
97104
func runInit(cfg *initConfig, out io.Writer) clierror.Error {
98-
runtimeCfg := cfg.runtimesConfig[cfg.runtime]
105+
runtimeCfg := cfg.extensionConfig.Runtimes[cfg.runtime]
99106

100107
handlerPath := path.Join(cfg.dir, runtimeCfg.HandlerFilename)
101108
err := os.WriteFile(handlerPath, []byte(runtimeCfg.HandlerData), os.ModePerm)
@@ -115,8 +122,20 @@ func runInit(cfg *initConfig, out io.Writer) clierror.Error {
115122
outDir = cfg.dir
116123
}
117124

118-
fmt.Fprintf(out, "Functions files initialized to dir %s\n", outDir)
119-
fmt.Fprint(out, "\nExample usage:\n")
120-
fmt.Fprintf(out, "kyma alpha function create %s --runtime %s --source %s --dependencies %s\n", cfg.runtime, cfg.runtime, handlerPath, depsPath)
125+
fmt.Fprintf(out, "Functions files of runtime %s initialized to dir %s\n", cfg.runtime, outDir)
126+
fmt.Fprint(out, "\nNext steps:\n")
127+
fmt.Fprint(out, "* update output files in your favorite IDE\n")
128+
fmt.Fprintf(out, "* create Function, for example:\n")
129+
fmt.Fprintf(out, " kyma alpha function create %s --runtime %s --source %s --dependencies %s\n", cfg.runtime, cfg.runtime, handlerPath, depsPath)
121130
return nil
122131
}
132+
133+
func sortedRuntimesString(m map[string]runtimeConfig) string {
134+
keys := []string{}
135+
for key := range m {
136+
keys = append(keys, key)
137+
}
138+
139+
sort.Strings(sort.StringSlice(keys))
140+
return strings.Join(keys, ", ")
141+
}

internal/cmd/alpha/registry/config/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type cfgConfig struct {
1717
output string
1818
}
1919

20-
func NewConfigCMD(kymaConfig *cmdcommon.KymaConfig, _ interface{}) *cobra.Command {
20+
func NewConfigCMD(kymaConfig *cmdcommon.KymaConfig, _ interface{}) (*cobra.Command, error) {
2121
cfg := cfgConfig{
2222
KymaConfig: kymaConfig,
2323
}
@@ -34,7 +34,7 @@ func NewConfigCMD(kymaConfig *cmdcommon.KymaConfig, _ interface{}) *cobra.Comman
3434
cmd.Flags().BoolVar(&cfg.externalurl, "externalurl", false, "External URL for the Kyma registry")
3535
cmd.Flags().StringVar(&cfg.output, "output", "", "Path where the output file should be saved to. NOTE: docker expects the file to be named `config.json`")
3636

37-
return cmd
37+
return cmd, nil
3838
}
3939

4040
func runConfig(cfg *cfgConfig) clierror.Error {

internal/cmd/alpha/registry/imageimport/imageimport.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type provisionConfig struct {
1616
image string
1717
}
1818

19-
func NewImportCMD(kymaConfig *cmdcommon.KymaConfig, _ interface{}) *cobra.Command {
19+
func NewImportCMD(kymaConfig *cmdcommon.KymaConfig, _ interface{}) (*cobra.Command, error) {
2020
config := provisionConfig{
2121
KymaConfig: kymaConfig,
2222
}
@@ -36,7 +36,7 @@ func NewImportCMD(kymaConfig *cmdcommon.KymaConfig, _ interface{}) *cobra.Comman
3636
},
3737
}
3838

39-
return cmd
39+
return cmd, nil
4040
}
4141

4242
func (pc *provisionConfig) validate() clierror.Error {

internal/cmdcommon/extension.go

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,17 @@ func (kec *KymaExtensionsConfig) BuildExtensions(availableTemplateCommands *Temp
7777
continue
7878
}
7979

80-
cmds = append(cmds, buildCommandFromExtension(kec.kymaConfig, extension, availableTemplateCommands, availableCoreCommands))
80+
extensionCommands, err := buildCommandFromExtension(kec.kymaConfig, extension, availableTemplateCommands, availableCoreCommands)
81+
if err != nil {
82+
kec.parseErrors = errors.Join(
83+
kec.parseErrors,
84+
fmt.Errorf("failed to build extensions from configmap '%s/%s': %s",
85+
cm.GetNamespace(), cm.GetName(), err.Error()),
86+
)
87+
continue
88+
}
89+
90+
cmds = append(cmds, extensionCommands)
8191
}
8292

8393
return cmds
@@ -203,7 +213,7 @@ func parseOptionalField[T any](cmData map[string]string, cmKey string) (T, error
203213
return data, err
204214
}
205215

206-
func buildCommandFromExtension(config *KymaConfig, extension *Extension, availableTemplateCommands *TemplateCommandsList, availableCoreCommands CoreCommandsMap) *cobra.Command {
216+
func buildCommandFromExtension(config *KymaConfig, extension *Extension, availableTemplateCommands *TemplateCommandsList, availableCoreCommands CoreCommandsMap) (*cobra.Command, error) {
207217
cmd := &cobra.Command{
208218
Use: fmt.Sprintf("%s <command> [flags]", extension.RootCommand.Name),
209219
Short: extension.RootCommand.Description,
@@ -214,9 +224,8 @@ func buildCommandFromExtension(config *KymaConfig, extension *Extension, availab
214224
addGenericCommands(cmd, config, extension, availableTemplateCommands)
215225
}
216226

217-
addCoreCommands(cmd, config, extension.CoreCommands, availableCoreCommands)
218-
219-
return cmd
227+
err := addCoreCommands(cmd, config, extension.CoreCommands, availableCoreCommands)
228+
return cmd, err
220229
}
221230

222231
func addGenericCommands(cmd *cobra.Command, config *KymaConfig, extension *Extension, availableTemplateCommands *TemplateCommandsList) {
@@ -257,16 +266,26 @@ func addGenericCommands(cmd *cobra.Command, config *KymaConfig, extension *Exten
257266
}
258267
}
259268

260-
func addCoreCommands(cmd *cobra.Command, config *KymaConfig, extensionCoreCommands []CoreCommandInfo, availableCoreCommands CoreCommandsMap) {
269+
func addCoreCommands(cmd *cobra.Command, config *KymaConfig, extensionCoreCommands []CoreCommandInfo, availableCoreCommands CoreCommandsMap) error {
270+
var cmdErr error
261271
for _, expectedCoreCommand := range extensionCoreCommands {
262272
command, ok := availableCoreCommands[expectedCoreCommand.ActionID]
263273
if !ok {
264274
// commands doesn't exist in this version of cli and we will not process it
265275
continue
266276
}
267277

268-
cmd.AddCommand(command(config, expectedCoreCommand.Config))
278+
coreCmd, err := command(config, expectedCoreCommand.Config)
279+
if err != nil {
280+
// add error and continue to check next commands
281+
cmdErr = errors.Join(cmdErr, err)
282+
continue
283+
}
284+
285+
cmd.AddCommand(coreCmd)
269286
}
287+
288+
return cmdErr
270289
}
271290

272291
// search os.Args manually to find if user pass given flag and return its value

internal/cmdcommon/extension_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const (
1717
)
1818

1919
// map of allowed core commands in format ID: FUNC
20-
type CoreCommandsMap map[string]func(*KymaConfig, interface{}) *cobra.Command
20+
type CoreCommandsMap map[string]func(*KymaConfig, interface{}) (*cobra.Command, error)
2121

2222
// allowed template commands
2323
type TemplateCommandsList struct {

0 commit comments

Comments
 (0)